From owner-freebsd-standards Sun Feb 17 19:15:42 2002 Delivered-To: freebsd-standards@freebsd.org Received: from descent.robbins.dropbear.id.au (252.b.007.mel.iprimus.net.au [210.50.81.252]) by hub.freebsd.org (Postfix) with ESMTP id 6E87337B402 for ; Sun, 17 Feb 2002 19:15:30 -0800 (PST) Received: (from tim@localhost) by descent.robbins.dropbear.id.au (8.11.6/8.11.6) id g1I3EF533231 for freebsd-standards@FreeBSD.ORG; Mon, 18 Feb 2002 14:14:15 +1100 (EST) (envelope-from tim) Date: Mon, 18 Feb 2002 14:14:15 +1100 From: Tim Robbins To: freebsd-standards@FreeBSD.ORG Subject: unexpand -t option Message-ID: <20020218141415.A33138@descent.robbins.dropbear.id.au> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5.1i Sender: owner-freebsd-standards@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG This patch adds the -t option to unexpand, makes it use getopt instead of rolling its own option parser, and just generally cleans it up and simplifies it. Now that it no longer buffers output itself, it should be trivial to convert to support multibyte encoding: make `ch' in tabify() a rune_t, use fgetrune() and fputrune() instead of getchar()/putchar(). Should I make this change? (The standard suggests it should handle multibyte encodings when LC_CTYPE specifies one) Comments? Index: unexpand/unexpand.c =================================================================== RCS file: /home/ncvs/src/usr.bin/unexpand/unexpand.c,v retrieving revision 1.7 diff -u -r1.7 unexpand.c --- unexpand/unexpand.c 2001/12/11 23:18:25 1.7 +++ unexpand/unexpand.c 2002/02/18 03:07:21 @@ -52,13 +52,16 @@ #include #include #include +#include +#include -char genbuf[BUFSIZ]; -char linebuf[BUFSIZ]; int all; +int nstops; +int tabstops[100]; +static void getstops __P((char *)); static void usage __P((void)); -void tabify __P((char)); +void tabify __P((void)); int main(argc, argv) @@ -66,28 +69,34 @@ char *argv[]; { register char *cp; + int ch; - argc--, argv++; - if (argc > 0 && argv[0][0] == '-') { - if (strcmp(argv[0], "-a") != 0) + nstops = 1; + tabstops[0] = 8; + while ((ch = getopt(argc, argv, "at:")) != -1) { + switch (ch) { + case 'a': + all = 1; + break; + case 't': + getstops(optarg); + all = 1; + break; + default: usage(); - all++; - argc--, argv++; + /*NOTREACHED*/ + } } + argc -= optind; + argv += optind; + do { if (argc > 0) { if (freopen(argv[0], "r", stdin) == NULL) - err(1, "%s", argv[0]); + err(EX_NOINPUT, "%s", argv[0]); argc--, argv++; } - while (fgets(genbuf, BUFSIZ, stdin) != NULL) { - for (cp = linebuf; *cp; cp++) - continue; - if (cp > linebuf) - cp[-1] = 0; - tabify(all); - printf("%s", linebuf); - } + tabify(); } while (argc > 0); exit(0); } @@ -95,52 +104,98 @@ static void usage() { - fprintf(stderr, "usage: unexpand [-a] file ...\n"); - exit(1); + fprintf(stderr, "usage: unexpand [-a] [-t tablist] [file ...]\n"); + exit(EX_USAGE); } void -tabify(c) - char c; +tabify() { - register char *cp, *dp; register int dcol; - int ocol; + int ch, n, ocol; ocol = 0; dcol = 0; - cp = genbuf, dp = linebuf; - for (;;) { - switch (*cp) { - + while ((ch = getchar()) != EOF) { +top: switch (ch) { + case EOF: + return; + case '\n': + putchar('\n'); + ocol = dcol = 0; + break; case ' ': dcol++; break; - case '\t': dcol += 8; dcol &= ~07; break; - + case '\b': + if (dcol > 0) + dcol--; + /*FALLTHROUGH*/ default: - while (((ocol + 8) &~ 07) <= dcol) { - if (ocol + 1 == dcol) - break; - *dp++ = '\t'; - ocol += 8; - ocol &= ~07; + if (nstops == 1) { + while (((ocol + tabstops[0]) / tabstops[0]) + <= (dcol / tabstops[0])) { + if (dcol - ocol < 2) + break; + putchar('\t'); + ocol = (1 + ocol / tabstops[0]) * + tabstops[0]; + } + } else { + for (n = 0; n < nstops; n++) + if (tabstops[n] > ocol) + break; + for (; n != nstops && tabstops[n] <= dcol; + n++) { + putchar('\t'); + if (n == 0) + ocol = tabstops[n]; + else + ocol = tabstops[n] + + (ocol - tabstops[n - 1]); + } } while (ocol < dcol) { - *dp++ = ' '; + putchar(' '); ocol++; } - if (*cp == 0 || c == 0) { - strcpy(dp, cp); - return; + putchar(ch); + if (!all) { + while ((ch = getchar()) != EOF && ch != '\n') + putchar(ch); + goto top; } - *dp++ = *cp; ocol++, dcol++; } + } +} + +static void +getstops(cp) + register char *cp; +{ + register int i; + + nstops = 0; + for (;;) { + i = 0; + while (*cp >= '0' && *cp <= '9') + i = i * 10 + *cp++ - '0'; + if (i <= 0) + errx(1, "bad tab stop spec"); + if (nstops > 0 && i <= tabstops[nstops-1]) + errx(1, "bad tab stop spec"); + if (nstops == sizeof(tabstops) / sizeof(*tabstops)) + errx(1, "too many tabstops"); + tabstops[nstops++] = i; + if (*cp == 0) + break; + if (*cp != ',' && *cp != ' ') + errx(1, "bad tab stop spec"); cp++; } } Ugh! The expand(1) and unexpand(1) manual pages are stuck together. Index: expand/expand.1 =================================================================== RCS file: /home/ncvs/src/usr.bin/expand/expand.1,v retrieving revision 1.7 diff -u -r1.7 expand.1 --- expand/expand.1 2001/07/10 14:15:57 1.7 +++ expand/expand.1 2002/02/18 02:16:14 @@ -51,6 +51,12 @@ .Op Ar .Nm unexpand .Op Fl a +.Oo +.Fl t +.Sm off +.Ar tab1 , tab2 , ... , tabn +.Sm on +.Oc .Op Ar .Sh DESCRIPTION .Nm Expand @@ -91,3 +97,10 @@ .Nm command appeared in .Bx 3.0 . +.Pp +The +.Nm expand +and +.Nm unexpand +utilities are expected to conform to +.St -p1003.1-2001 . To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-standards" in the body of the message