From owner-freebsd-bugs@FreeBSD.ORG Mon Aug 28 15:40:24 2006 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id B947516A4DA for ; Mon, 28 Aug 2006 15:40:24 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 03C2443D72 for ; Mon, 28 Aug 2006 15:40:18 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id k7SFeIYp026366 for ; Mon, 28 Aug 2006 15:40:18 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id k7SFeIOS026363; Mon, 28 Aug 2006 15:40:18 GMT (envelope-from gnats) Resent-Date: Mon, 28 Aug 2006 15:40:18 GMT Resent-Message-Id: <200608281540.k7SFeIOS026363@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Oliver Fromme Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 8218F16A4E1 for ; Mon, 28 Aug 2006 15:34:25 +0000 (UTC) (envelope-from olli@lurza.secnetix.de) Received: from lurza.secnetix.de (lurza.secnetix.de [83.120.8.8]) by mx1.FreeBSD.org (Postfix) with ESMTP id C069A43D45 for ; Mon, 28 Aug 2006 15:34:24 +0000 (GMT) (envelope-from olli@lurza.secnetix.de) Received: from lurza.secnetix.de (ronkdq@localhost [127.0.0.1]) by lurza.secnetix.de (8.13.4/8.13.4) with ESMTP id k7SFYHLp062781; Mon, 28 Aug 2006 17:34:22 +0200 (CEST) (envelope-from oliver.fromme@secnetix.de) Received: (from olli@localhost) by lurza.secnetix.de (8.13.4/8.13.1/Submit) id k7SFYHh0062780; Mon, 28 Aug 2006 17:34:17 +0200 (CEST) (envelope-from olli) Message-Id: <200608281534.k7SFYHh0062780@lurza.secnetix.de> Date: Mon, 28 Aug 2006 17:34:17 +0200 (CEST) From: Oliver Fromme To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Oliver Fromme Subject: bin/102609: [PATCH] Add filtering capability to date(1) X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Oliver Fromme List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Aug 2006 15:40:24 -0000 >Number: 102609 >Category: bin >Synopsis: [PATCH] Add filtering capability to date(1) >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Mon Aug 28 15:40:18 GMT 2006 >Closed-Date: >Last-Modified: >Originator: Oliver Fromme >Release: FreeBSD 6.1-STABLE i386 >Organization: secnetix GmbH & Co. KG http://www.secnetix.de/bsd >Environment: The patch below is against src/bin/date.c rev. 1.47 which is the current revision in 7-current and 6-stable. The patch also applies cleanly in 5-stable and works fine. (I haven't tested 4-stable, but it should work there, too.) A proposed patch for the date(1) manpage is also included. It is against the 6-stable version of the manpage. (Note that I'm not a native English speaker, so the patch might require some review.) >Description: Julian Elischer started a thread in the -current mailing list, proposing an addition to date(1) that turns it into a filter, reading lines from stdin, adding a time stamp, and writing it to stdout. This is Julian's mail that started the thread: http://lists.freebsd.org/pipermail/freebsd-current/2006-August/065003.html This PR contains a somewhat different approach to the problem. It has the same capability as Julian's patch, but it doesn't require a new command line option letter. It also provides better control over the placement of the time stamps, and it handles arbitrarily long lines. A description can be found here: http://lists.freebsd.org/pipermail/freebsd-current/2006-August/065424.html Basically, it implements a new conversion specification "%*" (it can be escaped with a double percent "%%*" sign as usual). If it occurs in the format string, filter mode is enabled: A loop is entered, reading lines from stdin and writing to stdout. For each line, the format string is expanded as usual, and the line read from stdin is inserted in the place of the "%*" character seqeuence. The result is written to stdout. >How-To-Repeat: n/a >Fix: --- src/bin/date/date.c.orig Mon Jan 10 09:39:21 2005 +++ src/bin/date/date.c Mon Aug 28 16:20:15 2006 @@ -66,6 +66,8 @@ int retval; static void setthetime(const char *, const char *, int, int); +static char *strndup(const char *, int); +static int parseformat(const char *, const char **, const char **); static void badformat(void); static void usage(void); @@ -76,6 +78,10 @@ int ch, rflag; int jflag, nflag; const char *format; + const char *format2; /* Format part to right of "%*", if any. */ + int filtermode; /* True if "%*" occured. */ + size_t linelen; + char *line; char buf[1024]; char *endptr, *fmt; char *tmp; @@ -144,10 +150,13 @@ err(1, "time"); format = "%+"; + format2 = ""; + line = NULL; + filtermode = 0; /* allow the operands in any order */ if (*argv && **argv == '+') { - format = *argv + 1; + filtermode = parseformat(*argv + 1, &format, &format2); ++argv; } @@ -158,22 +167,75 @@ usage(); if (*argv && **argv == '+') - format = *argv + 1; + filtermode = parseformat(*argv + 1, &format, &format2); - lt = *localtime(&tval); - badv = vary_apply(v, <); - if (badv) { - fprintf(stderr, "%s: Cannot apply date adjustment\n", - badv->arg); - vary_destroy(v); - usage(); - } - vary_destroy(v); - (void)strftime(buf, sizeof(buf), format, <); - (void)printf("%s\n", buf); - if (fflush(stdout)) - err(1, "stdout"); + do { + if (filtermode) { + if ((line = fgetln(stdin, &linelen)) == NULL) + break; + if (linelen != 0 && line[linelen - 1] == '\n') + linelen--; + if (!rflag) + tval = time(NULL); + } + lt = *localtime(&tval); + badv = vary_apply(v, <); + if (badv) { + fprintf(stderr, "%s: Cannot apply date adjustment\n", + badv->arg); + vary_destroy(v); + usage(); + } + if (*format) { + strftime(buf, sizeof(buf), format, <); + printf("%s", buf); + } + if (filtermode) { + fwrite(line, linelen, 1, stdout); + if (*format2) { + strftime(buf, sizeof(buf), format2, <); + printf("%s", buf); + } + } + printf("\n"); + if (fflush(stdout)) + err(1, "stdout"); + } while (filtermode); exit(retval); +} + +static char * +strndup(const char *src, int num) +{ + char *dst; + + if ((dst = malloc(num + 1)) == NULL) + return (NULL); + dst[num] = '\0'; + return (strncpy(dst, src, num)); +} + +static int +parseformat(const char *src, const char **prefix, const char **suffix) +{ + const char *fptr; + int percent; + + percent = 0; + for (fptr = src; *fptr; fptr++) { /* Scan string for "%*". */ + if (*fptr == '%') + percent = !percent; + else if (*fptr == '*' && percent) { + if ((*prefix = strndup(src, fptr - src - 1)) == NULL + || (*suffix = strdup(fptr + 1)) == NULL) + err(1, "malloc"); + return (1); /* filtermode on */ + } + else + percent = 0; + } + *prefix = src; + return (0); /* filtermode off */ } #define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0')) --- src/bin/date/date.1.orig Sun Feb 13 23:25:09 2005 +++ src/bin/date/date.1 Mon Aug 28 17:31:10 2006 @@ -253,6 +253,17 @@ The format string for the default display is .Dq +%+ . .Pp +As a special extension, if the format string contains the specification +.Dq %* , +.Nm +enters filter mode. +In that mode, lines are read from stdin. For each line, +a current time stamp is created according to the format string, +the line read from stdin is inserted in place of the specification +.Dq %* , +and the result is written to stdout. +This feature can be used to add time stamps to log files on the fly. +.Pp If an operand does not have a leading plus sign, it is interpreted as a value for setting the system's notion of the current date and time. The canonical representation for setting the date and time is: >Release-Note: >Audit-Trail: >Unformatted: