diff options
author | chin <none@none> | 2007-08-17 12:01:52 -0700 |
---|---|---|
committer | chin <none@none> | 2007-08-17 12:01:52 -0700 |
commit | da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch) | |
tree | 5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libcmd/common/fmt.c | |
parent | 073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff) | |
download | illumos-joyent-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz |
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93
PSARC/2006/550 Korn Shell 93 Integration
PSARC/2006/587 /etc/ksh.kshrc for ksh93
PSARC/2007/035 ksh93 Amendments
Contributed by Roland Mainz <roland.mainz@nrubsig.org>
--HG--
rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers
rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libcmd/common/fmt.c')
-rw-r--r-- | usr/src/lib/libcmd/common/fmt.c | 632 |
1 files changed, 632 insertions, 0 deletions
diff --git a/usr/src/lib/libcmd/common/fmt.c b/usr/src/lib/libcmd/common/fmt.c new file mode 100644 index 0000000000..2cbcc9c8ea --- /dev/null +++ b/usr/src/lib/libcmd/common/fmt.c @@ -0,0 +1,632 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1992-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped + +static const char usage[] = +"[-?\n@(#)$Id: fmt (AT&T Research) 2007-01-02 $\n]" +USAGE_LICENSE +"[+NAME?fmt - simple text formatter]" +"[+DESCRIPTION?\bfmt\b reads the input files and left justifies space " + "separated words into lines \awidth\a characters or less in length and " + "writes the lines to the standard output. The standard input is read if " + "\b-\b or no files are specified. Blank lines and interword spacing are " + "preserved in the output. Indentation is preserved, and lines with " + "identical indentation are joined and justified.]" +"[+?\bfmt\b is meant to format mail messages prior to sending, but may " + "also be useful for other simple tasks. For example, in \bvi\b(1) the " + "command \b:!}fmt\b will justify the lines in the current paragraph.]" +"[c:crown-margin?Preserve the indentation of the first two lines within " + "a paragraph, and align the left margin of each subsequent line with " + "that of the second line.]" +"[o:optget?Format concatenated \boptget\b(3) usage strings.]" +"[s:split-only?Split lines only; do not join short lines to form longer " + "ones.]" +"[u:uniform-spacing?One space between words, two after sentences.]" +"[w:width?Set the output line width to \acolumns\a.]#[columns:=72]" + "\n\n" +"[ file ... ]" + "\n\n" +"[+SEE ALSO?\bmailx\b(1), \bnroff\b(1), \btroff\b(1), \bvi\b(1), " + "\boptget\b(3)]" +; + +#include <cmd.h> +#include <ctype.h> + +typedef struct Fmt_s +{ + long flags; + char* outp; + char* outbuf; + char* endbuf; + Sfio_t* in; + Sfio_t* out; + int indent; + int nextdent; + int nwords; + int prefix; + int quote; + int retain; + int section; +} Fmt_t; + +#define INDENT 4 +#define TABSZ 8 + +#define isoption(fp,c) ((fp)->flags&(1L<<((c)-'a'))) +#define setoption(fp,c) ((fp)->flags|=(1L<<((c)-'a'))) +#define clroption(fp,c) ((fp)->flags&=~(1L<<((c)-'a'))) + +static void +outline(Fmt_t* fp) +{ + register char* cp = fp->outbuf; + int n = 0; + int c; + int d; + + if (!fp->outp) + return; + while (fp->outp[-1] == ' ') + fp->outp--; + *fp->outp = 0; + while (*cp++ == ' ') + n++; + if (n >= TABSZ) + { + n /= TABSZ; + cp = &fp->outbuf[TABSZ*n]; + while (n--) + *--cp = '\t'; + } + else + cp = fp->outbuf; + fp->nwords = 0; + if (!isoption(fp, 'o')) + sfputr(fp->out, cp, '\n'); + else if (*cp) + { + n = fp->indent; + if (*cp != '[') + { + if (*cp == ' ') + cp++; + n += INDENT; + } + while (n--) + sfputc(fp->out, ' '); + if (fp->quote) + { + if ((d = (fp->outp - cp)) <= 0) + c = 0; + else if ((c = fp->outp[-1]) == 'n' && d > 1 && fp->outp[-2] == '\\') + c = '}'; + sfprintf(fp->out, "\"%s%s\"\n", cp, c == ']' || c == '{' || c == '}' ? "" : " "); + } + else + sfputr(fp->out, cp, '\n'); + if (fp->nextdent) + { + fp->indent += fp->nextdent; + fp->endbuf -= fp->nextdent; + fp->nextdent = 0; + } + } + fp->outp = 0; +} + +static void +split(Fmt_t* fp, char* buf, int splice) +{ + register char* cp; + register char* ep; + register char* qp; + register int c = 1; + register int q = 0; + register int n; + int prefix; + + for (ep = buf; *ep == ' '; ep++); + prefix = ep - buf; + + /* + * preserve blank lines + */ + + if ((*ep == 0 || *buf == '.') && !isoption(fp, 'o')) + { + if (*ep) + prefix = strlen(buf); + outline(fp); + strcpy(fp->outbuf, buf); + fp->outp = fp->outbuf+prefix; + outline(fp); + return; + } + if (fp->prefix < prefix && !isoption(fp, 'c')) + outline(fp); + if (!fp->outp || prefix < fp->prefix) + fp->prefix = prefix; + while (c) + { + cp = ep; + while (*ep == ' ') + ep++; + if (cp != ep && isoption(fp, 'u')) + cp = ep-1; + while (c = *ep) + { + if (c == ' ') + break; + ep++; + + /* + * skip over \space + */ + + if (c == '\\' && *ep) + ep++; + } + n = (ep-cp); + if (n && isoption(fp, 'o')) + { + for (qp = cp; qp < ep; qp++) + if (*qp == '\\') + qp++; + else if (*qp == '"') + q = !q; + if (*(ep-1) == '"') + goto skip; + } + if (fp->nwords > 0 && &fp->outp[n] >= fp->endbuf && !fp->retain && !q) + outline(fp); + skip: + if (fp->nwords == 0) + { + if (fp->prefix) + memset(fp->outbuf, ' ', fp->prefix); + fp->outp = &fp->outbuf[fp->prefix]; + while (*cp == ' ') + cp++; + n = (ep-cp); + } + memcpy(fp->outp, cp, n); + fp->outp += n; + fp->nwords++; + } + if (isoption(fp, 's') || *buf == 0) + outline(fp); + else if (fp->outp) + { + /* + * two spaces at ends of sentences + */ + + if (!isoption(fp, 'o') && strchr(".:!?", fp->outp[-1])) + *fp->outp++ = ' '; + if (!splice && !fp->retain && (!fp->quote || (fp->outp - fp->outbuf) < 2 || fp->outp[-2] != '\\' || fp->outp[-1] != 'n' && fp->outp[-1] != 't' && fp->outp[-1] != ' ')) + *fp->outp++ = ' '; + } +} + +static int +dofmt(Fmt_t* fp) +{ + register int c; + int b; + int x; + int splice; + char* cp; + char* dp; + char* ep; + char* lp; + char* tp; + char buf[8192]; + + cp = 0; + while (cp || (cp = sfgetr(fp->in, '\n', 0)) && !(splice = 0) && (lp = cp + sfvalue(fp->in) - 1) || (cp = sfgetr(fp->in, '\n', SF_LASTR)) && (splice = 1) && (lp = cp + sfvalue(fp->in))) + { + if (isoption(fp, 'o')) + { + if (!isoption(fp, 'i')) + { + setoption(fp, 'i'); + b = 0; + while (cp < lp) + { + if (*cp == ' ') + b += 1; + else if (*cp == '\t') + b += INDENT; + else + break; + cp++; + } + fp->indent = roundof(b, INDENT); + } + else + while (cp < lp && (*cp == ' ' || *cp == '\t')) + cp++; + if (!isoption(fp, 'q') && cp < lp) + { + setoption(fp, 'q'); + if (*cp == '"') + { + ep = lp; + while (--ep > cp) + if (*ep == '"') + { + fp->quote = 1; + break; + } + else if (*ep != ' ' && *ep != '\t') + break; + } + } + } + again: + dp = buf; + ep = 0; + for (b = 1;; b = 0) + { + if (cp >= lp) + { + cp = 0; + break; + } + c = *cp++; + if (isoption(fp, 'o')) + { + if (c == '\\') + { + x = 0; + c = ' '; + cp--; + while (cp < lp) + { + if (*cp == '\\') + { + cp++; + if ((lp - cp) < 1) + { + c = '\\'; + break; + } + if (*cp == 'n') + { + cp++; + c = '\n'; + if ((lp - cp) > 2) + { + if (*cp == ']' || *cp == '@' && *(cp + 1) == '(') + { + *dp++ = '\\'; + *dp++ = 'n'; + c = *cp++; + break; + } + if (*cp == '\\' && *(cp + 1) == 'n') + { + cp += 2; + *dp++ = '\n'; + break; + } + } + } + else if (*cp == 't' || *cp == ' ') + { + cp++; + x = 1; + c = ' '; + } + else + { + if (x && dp != buf && *(dp - 1) != ' ') + *dp++ = ' '; + *dp++ = '\\'; + c = *cp++; + break; + } + } + else if (*cp == ' ' || *cp == '\t') + { + cp++; + c = ' '; + x = 1; + } + else + { + if (x && c != '\n' && dp != buf && *(dp - 1) != ' ') + *dp++ = ' '; + break; + } + } + if (c == '\n') + { + c = 0; + goto flush; + } + if (c == ' ' && (dp == buf || *(dp - 1) == ' ')) + continue; + } + else if (c == '"') + { + if (b || cp >= lp) + { + if (fp->quote) + continue; + fp->section = 0; + } + } + else if (c == '\a') + { + *dp++ = '\\'; + c = 'a'; + } + else if (c == '\b') + { + *dp++ = '\\'; + c = 'b'; + } + else if (c == '\f') + { + *dp++ = '\\'; + c = 'f'; + } + else if (c == '\v') + { + *dp++ = '\\'; + c = 'v'; + } + else if (c == ']' && (cp >= lp || *cp != ':' && *cp != '#' && *cp != '!')) + { + if (cp < lp && *cp == ']') + { + cp++; + *dp++ = c; + } + else + { + fp->section = 1; + fp->retain = 0; + flush: + *dp++ = c; + *dp = 0; + split(fp, buf, 0); + outline(fp); + goto again; + } + } + else if (fp->section) + { + if (c == '[') + { + if (b) + fp->retain = 1; + else + { + cp--; + c = 0; + goto flush; + } + fp->section = 0; + } + else if (c == '{') + { + x = 1; + for (tp = cp; tp < lp; tp++) + { + if (*tp == '[' || *tp == '\n') + break; + if (*tp == ' ' || *tp == '\t' || *tp == '"') + continue; + if (*tp == '\\' && (lp - tp) > 1) + { + if (*++tp == 'n') + break; + if (*tp == 't' || *tp == '\n') + continue; + } + x = 0; + break; + } + if (x) + { + if (fp->endbuf > (fp->outbuf + fp->indent + 2*INDENT)) + fp->nextdent = 2*INDENT; + goto flush; + } + else + fp->section = 0; + } + else if (c == '}') + { + if (fp->indent && (b || *(cp - 2) != 'f')) + { + if (b) + { + fp->indent -= 2*INDENT; + fp->endbuf += 2*INDENT; + } + else + { + cp--; + c = 0; + } + goto flush; + } + else + fp->section = 0; + } + else if (c == ' ' || c == '\t') + continue; + else + fp->section = 0; + } + else if (c == '?' && (cp >= lp || *cp != '?')) + { + if (fp->retain) + { + cp--; + while (cp < lp && *cp != ' ' && *cp != '\t' && *cp != ']' && dp < &buf[sizeof(buf)-3]) + *dp++ = *cp++; + if (cp < lp && (*cp == ' ' || *cp == '\t')) + *dp++ = *cp++; + *dp = 0; + split(fp, buf, 0); + dp = buf; + ep = 0; + fp->retain = 0; + if (fp->outp >= fp->endbuf) + outline(fp); + continue; + } + } + else if (c == ' ' || c == '\t') + for (c = ' '; *cp == ' ' || *cp == '\t'; cp++); + } + else if (c == '\b') + { + if (dp > buf) + { + dp--; + if (ep) + ep--; + } + continue; + } + else if (c == '\t') + { + /* + * expand tabs + */ + + if (!ep) + ep = dp; + c = isoption(fp, 'o') ? 1 : TABSZ - (dp - buf) % TABSZ; + if (dp >= &buf[sizeof(buf) - c - 3]) + { + cp--; + break; + } + while (c-- > 0) + *dp++ = ' '; + continue; + } + else if (!isprint(c)) + continue; + if (dp >= &buf[sizeof(buf) - 3]) + { + tp = dp; + while (--tp > buf) + if (isspace(*tp)) + { + cp -= dp - tp; + dp = tp; + break; + } + ep = 0; + break; + } + if (c != ' ') + ep = 0; + else if (!ep) + ep = dp; + *dp++ = c; + } + if (ep) + *ep = 0; + else + *dp = 0; + split(fp, buf, splice); + } + return 0; +} + +int +b_fmt(int argc, char** argv, void *context) +{ + register int n; + char* cp; + Fmt_t fmt; + char outbuf[8 * 1024]; + + fmt.flags = 0; + fmt.out = sfstdout; + fmt.outbuf = outbuf; + fmt.outp = 0; + fmt.endbuf = &outbuf[72]; + fmt.indent = 0; + fmt.nextdent = 0; + fmt.nwords = 0; + fmt.prefix = 0; + fmt.quote = 0; + fmt.retain = 0; + fmt.section = 1; + cmdinit(argc, argv, context, ERROR_CATALOG, 0); + while (n = optget(argv, usage)) + switch (n) + { + case 'c': + case 'o': + case 's': + case 'u': + setoption(&fmt, n); + break; + case 'w': + if (opt_info.num < TABSZ || opt_info.num>= sizeof(outbuf)) + error(2, "width out of range"); + fmt.endbuf = &outbuf[opt_info.num]; + break; + case ':': + error(2, "%s", opt_info.arg); + break; + case '?': + error(ERROR_usage(2), "%s", opt_info.arg); + break; + } + argv += opt_info.index; + if (error_info.errors) + error(ERROR_usage(2), "%s", optusage(NiL)); + if (isoption(&fmt, 'o')) + setoption(&fmt, 'c'); + if (isoption(&fmt, 's')) + clroption(&fmt, 'u'); + if (cp = *argv) + argv++; + do { + if (!cp || streq(cp, "-")) + fmt.in = sfstdin; + else if (!(fmt.in = sfopen(NiL, cp, "r"))) + { + error(ERROR_system(0), "%s: cannot open", cp); + error_info.errors = 1; + continue; + } + dofmt(&fmt); + if (fmt.in != sfstdin) + sfclose(fmt.in); + } while (cp = *argv++); + outline(&fmt); + if (sfsync(sfstdout)) + error(ERROR_system(0), "write error"); + return error_info.errors != 0; +} |