Date: Mon, 18 Feb 2002 14:14:15 +1100 From: Tim Robbins <tim@robbins.dropbear.id.au> To: freebsd-standards@FreeBSD.ORG Subject: unexpand -t option Message-ID: <20020218141415.A33138@descent.robbins.dropbear.id.au>
next in thread | raw e-mail | index | archive | help
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 <stdio.h> #include <stdlib.h> #include <string.h> +#include <sysexits.h> +#include <unistd.h> -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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020218141415.A33138>