diff --git a/usr.bin/expand/expand.1 b/usr.bin/expand/expand.1 index 246f21a61e04..99d89a0a3af6 100644 --- a/usr.bin/expand/expand.1 +++ b/usr.bin/expand/expand.1 @@ -32,7 +32,7 @@ .\" @(#)expand.1 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd June 9, 1993 +.Dd April 21, 2002 .Dt EXPAND 1 .Os .Sh NAME @@ -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 The @@ -89,6 +95,13 @@ are reconverted to maximal strings of tabs. If the option is given, then tabs are inserted whenever they would compress the resultant file by replacing two or more characters. .El +.Sh STANDARDS +The +.Nm expand +and +.Nm unexpand +utilities conform to +.St -p1003.1-2001 . .Sh HISTORY The .Nm diff --git a/usr.bin/unexpand/unexpand.c b/usr.bin/unexpand/unexpand.c index 51b8d3b866ec..1df6c460f195 100644 --- a/usr.bin/unexpand/unexpand.c +++ b/usr.bin/unexpand/unexpand.c @@ -49,45 +49,53 @@ static const char sccsid[] = "@(#)unexpand.c 8.1 (Berkeley) 6/6/93"; * unexpand - put tabs into a file replacing blanks */ #include +#include #include #include #include +#include -char genbuf[BUFSIZ]; -char linebuf[BUFSIZ]; int all; +int nstops; +int tabstops[100]; +static void getstops(const char *); static void usage(void); -void tabify(char); +static void tabify(void); int main(argc, argv) int argc; 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': /* Un-expand all spaces, not just leading. */ + all = 1; + break; + case 't': /* Specify tab list, implies -a. */ + 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]); 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 +103,111 @@ main(argc, argv) static void usage() { - fprintf(stderr, "usage: unexpand [-a] file ...\n"); + fprintf(stderr, "usage: unexpand [-a] [-t tablist] [file ...]\n"); exit(1); } -void -tabify(c) - char c; +static void +tabify() { - register char *cp, *dp; - register int dcol; - int ocol; + int ch, dcol, doneline, limit, n, ocol; - ocol = 0; - dcol = 0; - cp = genbuf, dp = linebuf; - for (;;) { - switch (*cp) { + limit = nstops == 1 ? INT_MAX : tabstops[nstops - 1] - 1; - case ' ': - dcol++; - break; + doneline = ocol = dcol = 0; + while ((ch = getchar()) != EOF) { + if (ch == '\n') { + putchar('\n'); + doneline = ocol = dcol = 0; + continue; + } else if (ch == ' ' && !doneline) { + if (++dcol >= limit) + doneline = 1; + continue; + } else if (ch == '\b' && dcol > 0) { + dcol--; + } else if (ch == '\t') { + if (nstops == 1) { + dcol = (1 + dcol / tabstops[0]) * + tabstops[0]; + continue; + } else { + for (n = 0; tabstops[n] - 1 < dcol && + n < nstops; n++) + ; + if (n < nstops - 1 && tabstops[n] - 1 < limit) { + dcol = tabstops[n]; + continue; + } + doneline = 1; + } + } - case '\t': - dcol += 8; - dcol &= ~07; - break; - - default: - while (((ocol + 8) &~ 07) <= dcol) { - if (ocol + 1 == dcol) + /* Output maximal number of tabs. */ + if (nstops == 1) { + while (((ocol + tabstops[0]) / tabstops[0]) + <= (dcol / tabstops[0])) { + if (dcol - ocol < 2) break; - *dp++ = '\t'; - ocol += 8; - ocol &= ~07; + putchar('\t'); + ocol = (1 + ocol / tabstops[0]) * + tabstops[0]; } - while (ocol < dcol) { - *dp++ = ' '; - ocol++; + } else { + for (n = 0; tabstops[n] - 1 < ocol && n < nstops; n++) + ; + while (ocol < dcol && n < nstops && ocol < limit) { + putchar('\t'); + ocol = tabstops[n++]; } - if (*cp == 0 || c == 0) { - strcpy(dp, cp); - return; - } - *dp++ = *cp; + } + + /* Then spaces. */ + while (ocol < dcol && ocol < limit) { + putchar(' '); + ocol++; + } + + if (ch != ' ' || dcol > limit) { + putchar(ch); ocol++, dcol++; } + + /* + * Only processing leading blanks or we've gone past the + * last tab stop. Emit remainder of this line unchanged. + */ + if (!all || dcol >= limit) { + while ((ch = getchar()) != '\n' && ch != EOF) + putchar(ch); + if (ch == '\n') + ungetc(ch, stdin); + } + } +} + +static void +getstops(cp) + const char *cp; +{ + 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 tab stops"); + tabstops[nstops++] = i; + if (*cp == 0) + break; + if (*cp != ',' && *cp != ' ') + errx(1, "bad tab stop spec"); cp++; } }