diff options
Diffstat (limited to 'usr/src/lib/libcmd/common')
52 files changed, 2392 insertions, 666 deletions
diff --git a/usr/src/lib/libcmd/common/RELEASE b/usr/src/lib/libcmd/common/RELEASE index 6300890d12..ebda670177 100644 --- a/usr/src/lib/libcmd/common/RELEASE +++ b/usr/src/lib/libcmd/common/RELEASE @@ -1,3 +1,34 @@ +09-09-09 fds.c: add --unit=fd +09-08-25 tail.c: initialize Tail_t.fifo=0 !! +09-08-15 tail.c: fix fifo logic +09-08-11 wc.c: add setlocale(LC_CTYPE,"C") cleanup, add utf8 optimzations +09-08-10 uniq.c: replace -c 1..9999 sfsprintf() with inline conversion +09-08-01 join.c: fix empty field null pointer deref +09-07-23 pathchk.c: add -P,--path and -a,--all +09-07-02 chgrp.c,chmod.c,cksum.c: fts_flags() default only if not --recursive +09-06-19 cmd.h,cmdinit.c: add ERROR_CALLBACK for ERROR_NOTIFY main() callback +09-06-19 mktemp.c: --unsafe now checks and prints path but does create +09-06-19 tee.c: add ERROR_CALLBACK for tee_cleanup() sfio discipline pop +09-06-18 rm.c: handle interrupts during interactive query +09-06-18 cp.c: handle interrupts during interactive query +09-05-25 tail.c: fix old style option logic to handle --invalid-long-option +09-05-24 tail.c: -r == +1r +09-05-01 mktemp.c: handle foo/prefix, add -p dir and -u +09-03-31 cat.c: handle --no* options +09-03-15 tail.c: fix --timeout termination logic +09-03-03 tee.c: clean up sfio disciplines on error +09-03-03 cat.c: fix -v|-e|-n|-B interaction bugs +09-02-14 tail.c: fix VSC failures +09-02-14 join.c: fix VSC failure +09-02-02 uniq.c: document -number == -fnumber, +number == -snumber +09-02-02 tail.c: fix usage[] for negative offsets, add sun -b +09-02-02 mktemp.c: add +09-02-02 features/utsname: UWIN _UNAME_os_DEFAULT => UWIN +09-01-31 dirname.c: add experimental { -f -r -x } for pathpath(3) +09-01-05 cmp.c: fix EOF diagnostic to conform to posix +09-01-03 mkfifo.c: fix --mode=mode logic +08-12-07 date.c: add %[_][EO]K for [space pad] [full|long] iso docs +08-11-10 stty.c: check for -t grouping so -tostop != -t -ostop 08-10-15 rm.c: handle 'rm -f x x' => exit 0 08-09-08 stty.c: #ifdef guard TAB[012] -- freebsd: damn the posix, full speed ahead 08-06-17 shcmd.h: move to libast @@ -169,7 +200,7 @@ 00-10-31 mkdir: handle races by checking EEXIST 00-09-20 cp: copy argv to stack before modifying in place 00-05-18 add setlocale(LC_ALL,"") -00-04-30 join: drop wierd opt_info.argv reference +00-04-30 join: drop weird opt_info.argv reference 00-03-17 expr: add == operator -- duh cp,ln,mv: delay pathcanon() on destination to verify `cp a b/.' getconf: use astgetconf for proper message control diff --git a/usr/src/lib/libcmd/common/basename.c b/usr/src/lib/libcmd/common/basename.c index c5c86aa154..2b59030483 100644 --- a/usr/src/lib/libcmd/common/basename.c +++ b/usr/src/lib/libcmd/common/basename.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/cat.c b/usr/src/lib/libcmd/common/cat.c index 76af2f2765..e451998cc2 100644 --- a/usr/src/lib/libcmd/common/cat.c +++ b/usr/src/lib/libcmd/common/cat.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -31,7 +31,7 @@ #include <fcntl.h> static const char usage[] = -"[-?\n@(#)$Id: cat (AT&T Research) 2007-07-17 $\n]" +"[-?\n@(#)$Id: cat (AT&T Research) 2009-03-31 $\n]" USAGE_LICENSE "[+NAME?cat - concatenate files]" "[+DESCRIPTION?\bcat\b copies each \afile\a in sequence to the standard" @@ -62,6 +62,7 @@ USAGE_LICENSE "[D:dos-output?Output files are opened in \atext\amode which inserts carriage" " returns in front of new-lines on some systems.]" "[E:show-ends?Causes a \b$\b to be inserted before each new-line.]" +"[R:regress?Regression test defaults: \b-v\b buffer size 4.]" "[S:silent?\bcat\b is silent about non-existent files.]" "[T:show-blank?Causes tabs to be copied as \b^I\b and formfeeds as \b^L\b.]" @@ -87,146 +88,306 @@ USAGE_LICENSE #define d_FLAG (1<<9) /* character types */ -#define T_ENDBUF 1 -#define T_CONTROL 2 -#define T_NEWLINE 3 -#define T_EIGHTBIT 4 -#define T_CNTL8BIT 5 +#define T_ERROR 1 +#define T_EOF 2 +#define T_ENDBUF 3 +#define T_NEWLINE 4 +#define T_CONTROL 5 +#define T_EIGHTBIT 6 +#define T_CNTL8BIT 7 #define printof(c) ((c)^0100) +typedef void* (*Reserve_f)(Sfio_t*, ssize_t, int); + +#ifndef sfvalue +#define sfvalue(f) ((f)->_val) +#endif + +static void* +regress(Sfio_t* sp, ssize_t n, int f) +{ + void* r; + + if (!(r = sfreserve(sp, 4, f))) + r = sfreserve(sp, n, f); + else if (sfvalue(sp) > 4) + sfvalue(sp) = 4; + return r; +} + /* * called for any special output processing */ static int -vcat(register char* states, Sfio_t *fdin, Sfio_t *fdout, int flags) +vcat(register char* states, Sfio_t* ip, Sfio_t* op, Reserve_f reserve, int flags) { register unsigned char* cp; - register unsigned char* cpold; + register unsigned char* pp; + unsigned char* cur; + unsigned char* end; + unsigned char* buf; + unsigned char* nxt; register int n; - register int m; - register int line = 1; - register unsigned char* endbuff; - unsigned char* inbuff; - int printdefer = (flags&(B_FLAG|N_FLAG)); - int lastchar; - int lastline; + register int line; + register int raw; + int last; + int c; + int m; + int any; + int header; unsigned char meta[4]; + unsigned char tmp[32]; meta[0] = 'M'; meta[1] = '-'; + last = -1; + *(cp = buf = end = tmp) = 0; + any = 0; + header = flags & (B_FLAG|N_FLAG); + line = 1; + states[0] = T_ENDBUF; + raw = !mbwide(); for (;;) { - /* read in a buffer full */ - if (!(inbuff = (unsigned char*)sfreserve(fdin, SF_UNBOUND, 0))) - return sfvalue(fdin) ? -1 : 0; - if ((n = sfvalue(fdin)) <= 0) - return n; - cp = inbuff; - lastchar = *(endbuff = cp + --n); - *endbuff = 0; - if (printdefer) + cur = cp; + if (raw) + while (!(n = states[*cp++])); + else + for (;;) + { + while (!(n = states[*cp++])); + if (n < T_CONTROL) + break; + if ((m = mbsize(pp = cp - 1)) > 1) + cp += m - 1; + else + { + if (m <= 0) + { + if (cur == pp) + { + if (last > 0) + { + *end = last; + last = -1; + c = end - pp + 1; + if ((m = mbsize(pp)) == c) + { + any = 1; + if (header) + { + header = 0; + sfprintf(op, "%6d\t", line); + } + sfwrite(op, cur, m); + *(cp = cur = end) = 0; + } + else + { + memcpy(tmp, pp, c); + if (!(nxt = (unsigned char*)(*reserve)(ip, SF_UNBOUND, 0))) + { + states[0] = sfvalue(ip) ? T_ERROR : T_EOF; + *(cp = end = tmp + sizeof(tmp) - 1) = 0; + last = -1; + } + else if ((n = sfvalue(ip)) <= 0) + { + states[0] = n ? T_ERROR : T_EOF; + *(cp = end = tmp + sizeof(tmp) - 1) = 0; + last = -1; + } + else + { + cp = buf = nxt; + end = buf + n - 1; + last = *end; + *end = 0; + } + mb: + if ((n = end - cp + 1) >= (sizeof(tmp) - c)) + n = sizeof(tmp) - c - 1; + memcpy(tmp + c, cp, n); + if ((m = mbsize(tmp)) >= c) + { + any = 1; + if (header) + { + header = 0; + sfprintf(op, "%6d\t", line); + } + sfwrite(op, tmp, m); + cur = cp += m - c; + } + } + continue; + } + } + else + { + cp = pp + 1; + n = 0; + } + } + break; + } + } + c = *--cp; + if ((m = cp - cur) || n >= T_CONTROL) { - if (states[*cp]!=T_NEWLINE || !(flags&B_FLAG)) - sfprintf(fdout,"%6d\t",line); - printdefer = 0; + flush: + any = 1; + if (header) + { + header = 0; + sfprintf(op, "%6d\t", line); + } + if (m) + sfwrite(op, cur, m); } - while (endbuff) + special: + switch (n) { - cpold = cp; - /* skip over printable characters */ - if (mbwide()) - while ((n = (m = mbsize(cp)) < 2 ? states[*cp++] : (cp += m, states['a'])) == 0); + case T_ERROR: + if (cp != end) + { + n = T_CONTROL; + goto flush; + } + return -1; + case T_EOF: + if (cp != end) + { + n = T_CONTROL; + goto flush; + } + return 0; + case T_ENDBUF: + if (cp != end) + { + n = T_CONTROL; + goto flush; + } + c = last; + if (!(nxt = (unsigned char*)(*reserve)(ip, SF_UNBOUND, 0))) + { + *(cp = end = tmp) = 0; + states[0] = sfvalue(ip) ? T_ERROR : T_EOF; + last = -1; + } + else if ((m = sfvalue(ip)) <= 0) + { + *(cp = end = tmp) = 0; + states[0] = m ? T_ERROR : T_EOF; + last = -1; + } else - while ((n = states[*cp++]) == 0); - if (n==T_ENDBUF) { - if (cp>endbuff) + buf = nxt; + end = buf + m - 1; + last = *end; + *end = 0; + cp = buf; + } + if (c >= 0) + { + if (!(n = states[c])) { - if (!(n = states[lastchar])) - { - *endbuff = lastchar; - cp++; - } - else - { - if (--cp > cpold) - sfwrite(fdout,(char*)cpold,cp-cpold); - if (endbuff==inbuff) - *++endbuff = 0; - cp = cpold = endbuff; - cp[-1] = lastchar; - if (n==T_ENDBUF) - n = T_CONTROL; - - } - endbuff = 0; + *(cur = tmp) = c; + m = 1; + goto flush; } - else n = T_CONTROL; + if (raw || n < T_CONTROL) + { + cp--; + goto special; + } + tmp[0] = c; + c = 1; + goto mb; } - if (--cp>cpold) - sfwrite(fdout,(char*)cpold,cp-cpold); - switch(n) + break; + case T_CONTROL: + do { - case T_CNTL8BIT: - meta[2] = '^'; - do - { - n = (*cp++)&~0200; - meta[3] = printof(n); - sfwrite(fdout,(char*)meta,4); - } - while ((n=states[*cp])==T_CNTL8BIT); - break; - case T_EIGHTBIT: - do - { - meta[2] = (*cp++)&~0200; - sfwrite(fdout,(char*)meta,3); - } - while ((n=states[*cp])==T_EIGHTBIT); - break; - case T_CONTROL: - do + sfputc(op, '^'); + sfputc(op, printof(c)); + } while (states[c = *++cp] == T_CONTROL); + break; + case T_CNTL8BIT: + meta[2] = '^'; + do + { + n = c & ~0200; + meta[3] = printof(n); + sfwrite(op, (char*)meta, 4); + } while (states[c = *++cp] == T_CNTL8BIT && raw); + break; + case T_EIGHTBIT: + do + { + meta[2] = c & ~0200; + sfwrite(op, (char*)meta, 3); + } while (states[c = *++cp] == T_EIGHTBIT && raw); + break; + case T_NEWLINE: + if (header && !(flags & B_FLAG)) + sfprintf(op, "%6d\t", line); + if (flags & E_FLAG) + sfputc(op, '$'); + sfputc(op, '\n'); + if (!header || !(flags & B_FLAG)) + line++; + header = !(flags & S_FLAG); + for (;;) + { + if ((n = states[*++cp]) == T_ENDBUF) + { + if (cp != end || last != '\n') + break; + if (!(nxt = (unsigned char*)(*reserve)(ip, SF_UNBOUND, 0))) { - n = *cp++; - sfputc(fdout,'^'); - sfputc(fdout,printof(n)); + states[0] = sfvalue(ip) ? T_ERROR : T_EOF; + cp = end = tmp; + *cp-- = 0; + last = -1; } - while ((n=states[*cp])==T_CONTROL); - break; - case T_NEWLINE: - lastline = line; - if (flags&S_FLAG) + else if ((n = sfvalue(ip)) <= 0) { - while (states[*++cp]==T_NEWLINE) - line++; - cp--; + states[0] = n ? T_ERROR : T_EOF; + cp = end = tmp; + *cp-- = 0; + last = -1; } - do + else { - cp++; - if (flags&E_FLAG) - sfputc(fdout,'$'); - sfputc(fdout,'\n'); - if(line > lastline) - { - if (flags&E_FLAG) - sfputc(fdout,'$'); - sfputc(fdout,'\n'); - } - if (!(flags&(N_FLAG|B_FLAG))) - continue; - line++; - if (cp < endbuff) - sfprintf(fdout,"%6d\t",line); - else printdefer = 1; + buf = nxt; + end = buf + n - 1; + last = *end; + *end = 0; + cp = buf - 1; } - while (states[*cp]==T_NEWLINE); + } + else if (n != T_NEWLINE) break; + if (!(flags & S_FLAG) || any || header) + { + any = 0; + header = 0; + if ((flags & (B_FLAG|N_FLAG)) == N_FLAG) + sfprintf(op, "%6d\t", line); + if (flags & E_FLAG) + sfputc(op, '$'); + sfputc(op, '\n'); + } + if (!(flags & B_FLAG)) + line++; } + header = flags & (B_FLAG|N_FLAG); + break; } } } @@ -239,60 +400,65 @@ b_cat(int argc, char** argv, void* context) register char* cp; register Sfio_t* fp; char* mode; + Reserve_f reserve = sfreserve; int att; - int dovcat=0; + int dovcat = 0; char states[UCHAR_MAX+1]; - NoP(argc); cmdinit(argc, argv, context, ERROR_CATALOG, 0); + setlocale(LC_ALL, ""); att = !strcmp(astconf("UNIVERSE", NiL, NiL), "att"); mode = "r"; for (;;) { + n = 0; switch (optget(argv, usage)) { case 'A': - flags |= T_FLAG|E_FLAG|V_FLAG; - continue; + n = T_FLAG|E_FLAG|V_FLAG; + break; case 'B': - flags |= S_FLAG; - continue; + n = S_FLAG; + break; case 'b': - flags |= B_FLAG; + n = B_FLAG; + break; + case 'd': + mode = opt_info.num ? "rt" : "r"; continue; + case 'D': + n = d_FLAG; + break; case 'E': - flags |= E_FLAG; - continue; + n = E_FLAG; + break; case 'e': - flags |= E_FLAG|V_FLAG; - continue; + n = E_FLAG|V_FLAG; + break; case 'n': - flags |= N_FLAG; + n = N_FLAG; + break; + case 'R': + reserve = opt_info.num ? regress : sfreserve; continue; case 's': - flags |= att ? F_FLAG : S_FLAG; - continue; + n = att ? F_FLAG : S_FLAG; + break; case 'S': - flags |= F_FLAG; - continue; + n = F_FLAG; + break; case 'T': - flags |= T_FLAG; - continue; + n = T_FLAG; + break; case 't': - flags |= T_FLAG|V_FLAG; - continue; + n = T_FLAG|V_FLAG; + break; case 'u': - flags |= U_FLAG; - continue; + n = U_FLAG; + break; case 'v': - flags |= V_FLAG; - continue; - case 'd': - mode = "rt"; - continue; - case 'D': - flags |= d_FLAG; - continue; + n = V_FLAG; + break; case ':': error(2, "%s", opt_info.arg); break; @@ -300,7 +466,12 @@ b_cat(int argc, char** argv, void* context) error(ERROR_usage(2), "%s", opt_info.arg); break; } - break; + if (!n) + break; + if (opt_info.num) + flags |= n; + else + flags &= ~n; } argv += opt_info.index; if (error_info.errors) @@ -340,15 +511,13 @@ b_cat(int argc, char** argv, void* context) states['\n'] = T_NEWLINE; dovcat = 1; } - if (flags&B_FLAG) - flags |= S_FLAG; if (flags&d_FLAG) sfopen(sfstdout, NiL, "wt"); if (cp = *argv) argv++; do { - if (!cp || streq(cp,"-")) + if (!cp || streq(cp, "-")) { fp = sfstdin; if (flags&D_FLAG) @@ -364,7 +533,7 @@ b_cat(int argc, char** argv, void* context) if (flags&U_FLAG) sfsetbuf(fp, (void*)fp, -1); if (dovcat) - n = vcat(states, fp, sfstdout, flags); + n = vcat(states, fp, sfstdout, reserve, flags); else if (sfmove(fp, sfstdout, SF_UNBOUND, -1) >= 0 && sfeof(fp)) n = 0; else diff --git a/usr/src/lib/libcmd/common/chgrp.c b/usr/src/lib/libcmd/common/chgrp.c index 5525157070..3295f3ab24 100644 --- a/usr/src/lib/libcmd/common/chgrp.c +++ b/usr/src/lib/libcmd/common/chgrp.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -28,7 +28,7 @@ */ static const char usage_1[] = -"[-?@(#)$Id: chgrp (AT&T Research) 2008-03-28 $\n]" +"[-?@(#)$Id: chgrp (AT&T Research) 2009-07-02 $\n]" USAGE_LICENSE ; @@ -221,6 +221,7 @@ b_chgrp(int argc, char** argv, void* context) register FTSENT*ent; register int i; Dt_t* map = 0; + int logical = 1; int flags; int uid; int gid; @@ -297,16 +298,20 @@ b_chgrp(int argc, char** argv, void* context) continue; case 'H': flags |= FTS_META|FTS_PHYSICAL; + logical = 0; continue; case 'L': flags &= ~(FTS_META|FTS_PHYSICAL); + logical = 0; continue; case 'P': flags &= ~FTS_META; flags |= FTS_PHYSICAL; + logical = 0; continue; case 'R': flags &= ~FTS_TOP; + logical = 0; continue; case 'X': options |= OPT_TEST; @@ -325,6 +330,8 @@ b_chgrp(int argc, char** argv, void* context) if (error_info.errors || argc < 2) error(ERROR_usage(2), "%s", optusage(NiL)); s = *argv; + if (logical) + flags &= ~(FTS_META|FTS_PHYSICAL); if (map) { if (streq(s, "-")) diff --git a/usr/src/lib/libcmd/common/chmod.c b/usr/src/lib/libcmd/common/chmod.c index f8fc03226a..4247446859 100644 --- a/usr/src/lib/libcmd/common/chmod.c +++ b/usr/src/lib/libcmd/common/chmod.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -28,7 +28,7 @@ */ static const char usage[] = -"[-?\n@(#)$Id: chmod (AT&T Research) 2007-09-10 $\n]" +"[-?\n@(#)$Id: chmod (AT&T Research) 2009-07-02 $\n]" USAGE_LICENSE "[+NAME?chmod - change the access permissions of files]" "[+DESCRIPTION?\bchmod\b changes the permission of each file " @@ -158,6 +158,7 @@ b_chmod(int argc, char** argv, void* context) register FTSENT*ent; char* last; int (*chmodf)(const char*, mode_t); + int logical = 1; int notify = 0; int ignore = 0; int show = 0; @@ -206,16 +207,20 @@ b_chmod(int argc, char** argv, void* context) continue; case 'H': flags |= FTS_META|FTS_PHYSICAL; + logical = 0; continue; case 'L': flags &= ~(FTS_META|FTS_PHYSICAL); + logical = 0; continue; case 'P': flags &= ~FTS_META; flags |= FTS_PHYSICAL; + logical = 0; continue; case 'R': flags &= ~FTS_TOP; + logical = 0; continue; case '?': error(ERROR_usage(2), "%s", opt_info.arg); @@ -226,6 +231,8 @@ b_chmod(int argc, char** argv, void* context) argv += opt_info.index; if (error_info.errors || !*argv || !amode && !*(argv + 1)) error(ERROR_usage(2), "%s", optusage(NiL)); + if (logical) + flags &= ~(FTS_META|FTS_PHYSICAL); if (ignore) ignore = umask(0); if (amode) diff --git a/usr/src/lib/libcmd/common/chown.c b/usr/src/lib/libcmd/common/chown.c index 83340c346a..cc80ba516f 100644 --- a/usr/src/lib/libcmd/common/chown.c +++ b/usr/src/lib/libcmd/common/chown.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/cksum.c b/usr/src/lib/libcmd/common/cksum.c index 56a80131a6..2be23e4a93 100644 --- a/usr/src/lib/libcmd/common/cksum.c +++ b/usr/src/lib/libcmd/common/cksum.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -27,7 +27,7 @@ */ static const char usage[] = -"[-?\n@(#)$Id: sum (AT&T Research) 2007-11-27 $\n]" +"[-?\n@(#)$Id: sum (AT&T Research) 2009-07-02 $\n]" USAGE_LICENSE "[+NAME?cksum,md5sum,sum - print file checksum and block count]" "[+DESCRIPTION?\bsum\b lists the checksum, and for most methods the block" @@ -447,6 +447,7 @@ b_cksum(int argc, register char** argv, void* context) Sfio_t* sp; FTS* fts; FTSENT* ent; + int logical; Optdisc_t optdisc; State_t state; @@ -456,6 +457,7 @@ b_cksum(int argc, register char** argv, void* context) flags = fts_flags() | FTS_TOP | FTS_NOPOSTORDER | FTS_NOSEEDOTDIR; state.flags = SUM_SIZE; state.warn = 1; + logical = 1; method = 0; optinit(&optdisc, optinfo); for (;;) @@ -493,6 +495,7 @@ b_cksum(int argc, register char** argv, void* context) flags &= ~FTS_TOP; state.recursive = 1; state.sort = order; + logical = 0; continue; case 's': method = "sys5"; @@ -511,13 +514,16 @@ b_cksum(int argc, register char** argv, void* context) continue; case 'H': flags |= FTS_META|FTS_PHYSICAL; + logical = 0; continue; case 'L': flags &= ~(FTS_META|FTS_PHYSICAL); + logical = 0; continue; case 'P': flags &= ~FTS_META; flags |= FTS_PHYSICAL; + logical = 0; continue; case 'T': state.text = 1; @@ -548,6 +554,8 @@ b_cksum(int argc, register char** argv, void* context) * do it */ + if (logical) + flags &= ~(FTS_META|FTS_PHYSICAL); if (state.permissions) { state.uid = geteuid(); diff --git a/usr/src/lib/libcmd/common/cmd.h b/usr/src/lib/libcmd/common/cmd.h index 8fe4094d78..3b054da7dd 100644 --- a/usr/src/lib/libcmd/common/cmd.h +++ b/usr/src/lib/libcmd/common/cmd.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -35,6 +35,8 @@ #define cmdinit _cmd_init +#define ERROR_CALLBACK ERROR_SET + #if _BLD_cmd && defined(__EXPORT__) #define extern __EXPORT__ #endif @@ -86,7 +88,7 @@ cmdinit(int argc, register char** argv, void* context, const char* catalog, int error_info.catalog = (char*)catalog; opt_info.index = 0; if (context) - error_info.flags |= flags; + error_info.flags |= flags & ~(ERROR_CALLBACK|ERROR_NOTIFY); return 0; } diff --git a/usr/src/lib/libcmd/common/cmdinit.c b/usr/src/lib/libcmd/common/cmdinit.c index bd450ebf47..e0bdfe511e 100644 --- a/usr/src/lib/libcmd/common/cmdinit.c +++ b/usr/src/lib/libcmd/common/cmdinit.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -24,14 +24,29 @@ */ #include <cmd.h> +#include <shcmd.h> int _cmd_init(int argc, char** argv, void* context, const char* catalog, int flags) { register char* cp; - if (argc < 0) + if (argc <= 0) return -1; + if (context) + { + if (flags & ERROR_CALLBACK) + { + flags &= ~ERROR_CALLBACK; + flags |= ERROR_NOTIFY; + } + else if (flags & ERROR_NOTIFY) + { + ((Shbltin_t*)(context))->notify = 1; + flags &= ~ERROR_NOTIFY; + } + error_info.flags |= flags; + } if (cp = strrchr(argv[0], '/')) cp++; else @@ -40,8 +55,6 @@ _cmd_init(int argc, char** argv, void* context, const char* catalog, int flags) if (!error_info.catalog) error_info.catalog = catalog; opt_info.index = 0; - if (context) - error_info.flags |= flags; return 0; } diff --git a/usr/src/lib/libcmd/common/cmp.c b/usr/src/lib/libcmd/common/cmp.c index 06223f5695..12b69ee23b 100644 --- a/usr/src/lib/libcmd/common/cmp.c +++ b/usr/src/lib/libcmd/common/cmp.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -28,7 +28,7 @@ */ static const char usage[] = -"[-?\n@(#)$Id: cmp (AT&T Research) 2004-12-01 $\n]" +"[-?\n@(#)$Id: cmp (AT&T Research) 2009-01-05 $\n]" USAGE_LICENSE "[+NAME?cmp - compare two files]" "[+DESCRIPTION?\bcmp\b compares two files \afile1\a and \afile2\a. " @@ -119,7 +119,7 @@ cmp(const char* file1, Sfio_t* f1, const char* file2, Sfio_t* f2, int flags) { ret = 1; if (!(flags & CMP_SILENT)) - error(ERROR_exit(1), "%s: EOF", file1); + error(ERROR_exit(1), "EOF on %s", file1); } return(ret); } @@ -130,7 +130,7 @@ cmp(const char* file1, Sfio_t* f1, const char* file2, Sfio_t* f2, int flags) if (!(p2 = (unsigned char*)sfreserve(f2, SF_UNBOUND, 0)) || (c2 = sfvalue(f2)) <= 0) { if (!(flags & CMP_SILENT)) - error(ERROR_exit(1), "%s: EOF", file2); + error(ERROR_exit(1), "EOF on %s", file2); return(1); } e2 = p2 + c2; @@ -263,14 +263,14 @@ b_cmp(int argc, register char** argv, void* context) if (o1 && sfseek(f1, o1, SEEK_SET) != o1) { if (!(flags & CMP_SILENT)) - error(ERROR_exit(0), "%s: EOF", file1); + error(ERROR_exit(0), "EOF on %s", file1); n = 1; goto done; } if (o2 && sfseek(f2, o2, SEEK_SET) != o2) { if (!(flags & CMP_SILENT)) - error(ERROR_exit(0), "%s: EOF", file2); + error(ERROR_exit(0), "EOF on %s", file2); n = 1; goto done; } @@ -280,7 +280,8 @@ b_cmp(int argc, register char** argv, void* context) error(ERROR_system(0), "%s: cannot stat", file1); else if (s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev && o1 == o2) n = 0; - else n = ((flags & CMP_SILENT) && S_ISREG(s1.st_mode) && S_ISREG(s2.st_mode) && (s1.st_size - o1) != (s2.st_size - o2)) ? 1 : cmp(file1, f1, file2, f2, flags); + else + n = ((flags & CMP_SILENT) && S_ISREG(s1.st_mode) && S_ISREG(s2.st_mode) && (s1.st_size - o1) != (s2.st_size - o2)) ? 1 : cmp(file1, f1, file2, f2, flags); done: if (f1 && f1 != sfstdin) sfclose(f1); if (f2 && f2 != sfstdin) sfclose(f2); diff --git a/usr/src/lib/libcmd/common/comm.c b/usr/src/lib/libcmd/common/comm.c index 347867d656..f3fee9ef09 100644 --- a/usr/src/lib/libcmd/common/comm.c +++ b/usr/src/lib/libcmd/common/comm.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/cp.c b/usr/src/lib/libcmd/common/cp.c index c3484b0cb0..bff4430830 100644 --- a/usr/src/lib/libcmd/common/cp.c +++ b/usr/src/lib/libcmd/common/cp.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -27,7 +27,7 @@ */ static const char usage_head[] = -"[-?@(#)$Id: cp (AT&T Research) 2007-12-13 $\n]" +"[-?@(#)$Id: cp (AT&T Research) 2009-06-18 $\n]" USAGE_LICENSE ; @@ -142,6 +142,7 @@ static const char usage_tail[] = typedef struct State_s /* program state */ { + void* context; /* builtin context */ int backup; /* BAK_* type */ int directory; /* destination is directory */ int flags; /* FTS_* flags */ @@ -438,7 +439,7 @@ visit(State_t* state, register FTSENT* ent) /* ok */; else if (state->interactive) { - if (astquery(-1, "%s %s? ", state->opname, state->path)) + if (astquery(-1, "%s %s? ", state->opname, state->path) < 0 || sh_checksig(state->context)) return 0; } else if (state->op == LN) @@ -459,7 +460,7 @@ visit(State_t* state, register FTSENT* ent) fmtmode(st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO), 0) + 1; if (state->interactive) { - if (astquery(-1, "override protection %s for %s? ", protection, state->path)) + if (astquery(-1, "override protection %s for %s? ", protection, state->path) < 0 || sh_checksig(state->context)) return 0; rm = 1; } @@ -659,7 +660,7 @@ b_cp(int argc, register char** argv, void* context) char** v; char* backup_type; FTS* fts; - FTSENT* ent; + FTSENT* ent; const char* usage; int path_resolve; int standard; @@ -677,6 +678,7 @@ b_cp(int argc, register char** argv, void* context) } else memset(state, 0, offsetof(State_t, INITSTATE)); + state->context = context; state->presiz = -1; backup_type = 0; state->flags = FTS_NOCHDIR|FTS_NOSEEDOTDIR; diff --git a/usr/src/lib/libcmd/common/cut.c b/usr/src/lib/libcmd/common/cut.c index 305ebdaf9d..2be03c3183 100644 --- a/usr/src/lib/libcmd/common/cut.c +++ b/usr/src/lib/libcmd/common/cut.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/date.c b/usr/src/lib/libcmd/common/date.c index 1984570b2d..d7895b02d4 100644 --- a/usr/src/lib/libcmd/common/date.c +++ b/usr/src/lib/libcmd/common/date.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -27,7 +27,7 @@ */ static const char usage[] = -"[-?\n@(#)$Id: date (AT&T Research) 2007-05-21 $\n]" +"[-?\n@(#)$Id: date (AT&T Research) 2009-03-03 $\n]" USAGE_LICENSE "[+NAME?date - set/list/convert dates]" "[+DESCRIPTION?\bdate\b sets the current date and time (with appropriate" @@ -106,7 +106,7 @@ USAGE_LICENSE " [+j?1-offset Julian date]" " [+J?0-offset Julian date]" " [+k?\bdate\b(1) style date]" -" [+K?all numeric date; equivalent to \b%Y-%m-%d+%H:%M:%S\b]" +" [+K?all numeric date; equivalent to \b%Y-%m-%d+%H:%M:%S\b; \b%_[EO]]K\b for space separator, %OK adds \b.%N\b, \b%EK\b adds \b%.N%z\b, \b%_EK\b adds \b.%N %z\b]" " [+l?\bls\b(1) \b-l\b date; equivalent to \b%Q/%g/%G/\b]" " [+L?locale default date format]" " [+m?month number]" @@ -212,7 +212,7 @@ settime(void* context, const char* cmd, Time_t now, int adjust, int network) char* s; char** argv; char* args[5]; - char buf[128]; + char buf[1024]; if (!adjust && !network) return tmxsettime(now); @@ -276,7 +276,7 @@ b_date(int argc, register char** argv, void* context) Time_t ts; Time_t te; Time_t e; - char buf[128]; + char buf[1024]; Fmt_t* fmts; Fmt_t fmt; struct stat st; diff --git a/usr/src/lib/libcmd/common/dirname.c b/usr/src/lib/libcmd/common/dirname.c index 71e69d8594..cd6076240b 100644 --- a/usr/src/lib/libcmd/common/dirname.c +++ b/usr/src/lib/libcmd/common/dirname.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -29,7 +29,7 @@ */ static const char usage[] = -"[-?\n@(#)$Id: dirname (AT&T Research) 2000-03-07 $\n]" +"[-?\n@(#)$Id: dirname (AT&T Research) 2009-01-31 $\n]" USAGE_LICENSE "[+NAME?dirname - return directory portion of file name]" "[+DESCRIPTION?\bdirname\b treats \astring\a as a file name and returns " @@ -48,14 +48,17 @@ USAGE_LICENSE "as \b/\b characters as described above. Otherwise, all " "trailing slashes are removed and the output will be this string " "unless this string is empty. If empty the output will be \b.\b.]" +"[f:file?Print the \b$PATH\b relative regular file path for \astring\a.]" +"[r:relative?Print the \b$PATH\b relative readable file path for \astring\a.]" +"[x:executable?Print the \b$PATH\b relative executable file path for \astring\a.]" "\n" -"\n string\n" +"\nstring\n" "\n" "[+EXIT STATUS?]{" "[+0?Successful Completion.]" "[+>0?An error occurred.]" "}" -"[+SEE ALSO?\bbasename\b(1), \bgetconf\b(1), \bdirname\b(3)]" +"[+SEE ALSO?\bbasename\b(1), \bgetconf\b(1), \bdirname\b(3), \bpathname\b(3)]" ; #include <cmd.h> @@ -96,10 +99,22 @@ int b_dirname(int argc,register char *argv[], void* context) { register int n; + int mode = 0; + char buf[PATH_MAX]; cmdinit(argc, argv, context, ERROR_CATALOG, 0); while (n = optget(argv, usage)) switch (n) { + case 'f': + mode |= PATH_REGULAR; + break; + case 'r': + mode &= ~PATH_REGULAR; + mode |= PATH_READ; + break; + case 'x': + mode |= PATH_EXECUTE; + break; case ':': error(2, "%s", opt_info.arg); break; @@ -111,6 +126,11 @@ b_dirname(int argc,register char *argv[], void* context) argc -= opt_info.index; if(error_info.errors || argc != 1) error(ERROR_usage(2),"%s", optusage(NiL)); - l_dirname(sfstdout,argv[0]); + if(!mode) + l_dirname(sfstdout,argv[0]); + else if(pathpath(buf, argv[0], "", mode)) + sfputr(sfstdout, buf, '\n'); + else + error(1|ERROR_WARNING, "%s: relative path not found", argv[0]); return(0); } diff --git a/usr/src/lib/libcmd/common/expr.c b/usr/src/lib/libcmd/common/expr.c index ff5d45e039..78749d25ce 100644 --- a/usr/src/lib/libcmd/common/expr.c +++ b/usr/src/lib/libcmd/common/expr.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/fds.c b/usr/src/lib/libcmd/common/fds.c index bafa2c09f7..cca4fd22c3 100644 --- a/usr/src/lib/libcmd/common/fds.c +++ b/usr/src/lib/libcmd/common/fds.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -21,7 +21,7 @@ #pragma prototyped static const char usage[] = -"[-?\n@(#)$Id: fds (AT&T Research) 2008-08-26 $\n]" +"[-?\n@(#)$Id: fds (AT&T Research) 2009-09-09 $\n]" USAGE_LICENSE "[+NAME?fds - list open file descriptor status]" "[+DESCRIPTION?\bfds\b lists the status for each open file descriptor. " @@ -29,6 +29,7 @@ USAGE_LICENSE "calling shell, otherwise it lists the file descriptors passed across " "\bexec\b(2).]" "[l:long?List file descriptor details.]" +"[u:unit?Write output to \afd\a.]#[fd]" "[+SEE ALSO?\blogname\b(1), \bwho\b(1), \bgetgroups\b(2), \bgetsockname\b(2), \bgetsockopts\b(2)]" ; @@ -164,6 +165,8 @@ b_fds(int argc, char** argv, void* context) int flags; int details; int open_max; + int unit; + Sfio_t* sp; struct stat st; #ifdef S_IFSOCK struct sockaddr_in addr; @@ -175,13 +178,16 @@ b_fds(int argc, char** argv, void* context) int type; int port; int prot; - char nam[256]; char num[64]; char fam[64]; +#ifdef INET6_ADDRSTRLEN + char nam[256]; +#endif #endif cmdinit(argc, argv, context, ERROR_CATALOG, 0); details = 0; + unit = 1; for (;;) { switch (optget(argv, usage)) @@ -189,6 +195,9 @@ b_fds(int argc, char** argv, void* context) case 'l': details = opt_info.num; continue; + case 'u': + unit = opt_info.num; + continue; case '?': error(ERROR_USAGE|4, "%s", opt_info.arg); continue; @@ -203,6 +212,10 @@ b_fds(int argc, char** argv, void* context) error(ERROR_USAGE|4, "%s", optusage(NiL)); if ((open_max = getconf("OPEN_MAX")) <= 0) open_max = OPEN_MAX; + if (unit == 1) + sp = sfstdout; + else if (fstat(unit, &st) || !(sp = sfnew(NiL, NiL, SF_UNBOUND, unit, SF_WRITE))) + error(ERROR_SYSTEM|3, "%d: cannot write to file descriptor"); for (i = 0; i <= open_max; i++) { if (fstat(i, &st)) @@ -212,7 +225,7 @@ b_fds(int argc, char** argv, void* context) } if (!details) { - sfprintf(sfstdout, "%d\n", i); + sfprintf(sp, "%d\n", i); continue; } if ((flags = fcntl(i, F_GETFL, (char*)0)) == -1) @@ -236,7 +249,7 @@ b_fds(int argc, char** argv, void* context) x = (fcntl(i, F_GETFD, (char*)0) > 0) ? "x" : "-"; if (isatty(i) && (s = ttyname(i))) { - sfprintf(sfstdout, "%02d %s%s %s %s\n", i, m, x, fmtmode(st.st_mode, 0), s); + sfprintf(sp, "%02d %s%s %s %s\n", i, m, x, fmtmode(st.st_mode, 0), s); continue; } #ifdef S_IFSOCK @@ -330,13 +343,18 @@ b_fds(int argc, char** argv, void* context) a = a == fam ? "0" : fam + 1; } if (port) - sfprintf(sfstdout, "%02d %s%s %s /dev/%s/%s/%d\n", i, m, x, fmtmode(st.st_mode, 0), s, a, port); + sfprintf(sp, "%02d %s%s %s /dev/%s/%s/%d\n", i, m, x, fmtmode(st.st_mode, 0), s, a, port); else - sfprintf(sfstdout, "%02d %s%s %s /dev/%s/%s\n", i, m, x, fmtmode(st.st_mode, 0), s, a); + sfprintf(sp, "%02d %s%s %s /dev/%s/%s\n", i, m, x, fmtmode(st.st_mode, 0), s, a); continue; } #endif - sfprintf(sfstdout, "%02d %s%s %s /dev/inode/%u/%u\n", i, m, x, fmtmode(st.st_mode, 0), st.st_dev, st.st_ino); + sfprintf(sp, "%02d %s%s %s /dev/inode/%u/%u\n", i, m, x, fmtmode(st.st_mode, 0), st.st_dev, st.st_ino); + } + if (sp != sfstdout) + { + sfsetfd(sp, -1); + sfclose(sp); } return 0; } diff --git a/usr/src/lib/libcmd/common/features/utsname b/usr/src/lib/libcmd/common/features/utsname index 5b746ce7ad..7254867181 100644 --- a/usr/src/lib/libcmd/common/features/utsname +++ b/usr/src/lib/libcmd/common/features/utsname @@ -6,6 +6,9 @@ sys syscall,systeminfo,syssgi tst cross{ u=`/bin/uname -o 2>/dev/null` case $u in + UWIN-*) u=UWIN ;; + esac + case $u in '') ;; *) echo "#define _UNAME_os_DEFAULT \"$u\" /* default os name */" ;; esac diff --git a/usr/src/lib/libcmd/common/fmt.c b/usr/src/lib/libcmd/common/fmt.c index 95f5fd4528..ab0db310ea 100644 --- a/usr/src/lib/libcmd/common/fmt.c +++ b/usr/src/lib/libcmd/common/fmt.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/fold.c b/usr/src/lib/libcmd/common/fold.c index 6541da8035..01a2cadfb1 100644 --- a/usr/src/lib/libcmd/common/fold.c +++ b/usr/src/lib/libcmd/common/fold.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/getconf.c b/usr/src/lib/libcmd/common/getconf.c index bceae0e167..a4509437ab 100644 --- a/usr/src/lib/libcmd/common/getconf.c +++ b/usr/src/lib/libcmd/common/getconf.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/grep.c b/usr/src/lib/libcmd/common/grep.c new file mode 100644 index 0000000000..1e857f087c --- /dev/null +++ b/usr/src/lib/libcmd/common/grep.c @@ -0,0 +1,876 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1995-2009 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> * +* * +***********************************************************************/ +#pragma prototyped + +static const char usage[] = +"[-?\n@(#)$Id: grep (AT&T Research) 2006-06-14 $\n]" +USAGE_LICENSE +"[+NAME?grep - search lines in files for matching patterns]" +"[+DESCRIPTION?The \bgrep\b commands search the named input files" +" for lines containing a match for the given \apatterns\a." +" Matching lines are printed by default. The standard input is searched" +" if no files are given or when the file \b-\b is specified.]" +"[+?There are six variants of \bgrep\b, each one using a different form of" +" \apattern\a, controlled either by option or the command path" +" base name. Details of each variant may be found in \bregex\b(3).]" +" {" +" [+grep?The default basic regular expressions (no alternations.)]" +" [+egrep?Extended regular expressions (alternations, one or more.)]" +" [+pgrep?\bperl\b(1) regular expressions (lenient extended.)]" +" [+xgrep?Augmented regular expressions (conjunction, negation.)]" +" [+fgrep?Fixed string expressions.]" +" [+agrep?Approximate regular expressions (not implemented.)]" +" }" +"[G:basic-regexp?\bgrep\b mode (default): basic regular expression \apatterns\a.]" +"[E:extended-regexp?\begrep\b mode: extended regular expression \apatterns\a.]" +"[X:augmented-regexp?\bxgrep\b mode: augmented regular expression \apatterns\a.]" +"[P:perl-regexp?\bpgrep\b mode: \bperl\b(1) regular expression \apatterns\a.]" +"[F:fixed-string?\bfgrep\b mode: fixed string \apatterns\a.]" +"[A:approximate-regexp?\bagrep\b mode: approximate regular expression \apatterns\a (not implemented.)]" + +"[C:context?Set the matched line context \abefore\a and \aafter\a count." +" By default only matched lines are printed.]:?" +" [before[,after]]:=2,2]" +"[c:count?Only print a matching line count for each file.]" +"[e:expression|pattern|regexp?Specify a matching \apattern\a. More than one" +" \apattern\a implies alternation. If this option is specified" +" then the command line \apattern\a must be omitted.]:" +" [pattern]" +"[f:file?Each line in \apattern-file\a is a \apattern\a, placed into a single" +" alternating expression.]:" +" [pattern-file]" +"[H:filename|with-filename?Prefix each matched line with the containing file name.]" +"[h:no-filename?Suppress containing file name prefix for each matched line.]" +"[i:ignore-case?Ignore case when matching.]" +"[l:files-with-matches?Only print file names with at least one match.]" +"[L:files-without-matches?Only print file names with no matches.]" +"[b:highlight?Highlight matches using the ansi terminal bold sequence.]" +"[v:invert-match|revert-match?Invert the \apattern\a match sense.]" +"[m:label?All patterns must be of the form \alabel\a:\apattern\a. Match and" +" count output will be prefixed by the corresponding \alabel\a:.]" +"[O:lenient?Enable lenient \apattern\a interpretation. This is the default.]" +"[x:line-match|line-regexp?Force \apatterns\a to match complete lines.]" +"[n:number|line-number?Prefix each matched line with its line number.]" +"[N:name?Set the standard input file name prefix to" +" \aname\a.]:[name:=empty]" +"[q:quiet|silent?Do not print matching lines.]" +"[S:strict?Enable strict \apattern\a interpretation with diagnostics.]" +"[s:suppress|no-messages?Suppress error and warning messages.]" +"[t:total?Only print a single matching line count for all files.]" +"[T:test?Enable implementation specific tests.]:" +" [test]" +"[w:word-match|word-regexp?Force \apatterns\a to match complete words.]" +"[a?Ignored for GNU compatibility.]" +"\n" +"\n[ pattern ] [ file ... ]\n" +"\n" +"[+DIAGNOSTICS?Exit status 0 if matches were found, 1 if no matches were found," +" where \b-v\b invertes the exit status. Exit status 2 for other" +" errors that are accompanied by a message on the standard error.]" +"[+SEE ALSO?\bed\b(1), \bsed\b(1), \bperl\b(1), \bregex\b(3)]" +"[+CAVEATS?Some expressions of necessity require exponential space" +" and/or time.]" +"[+BUGS?Some expressions may use sub-optimal algorithms. For example," +" don't use this implementation to compute primes.]" +; + +#include <ast.h> +#include <ctype.h> +#include <ccode.h> +#include <error.h> +#include <regex.h> + +#ifndef EISDIR +#define EISDIR (-1) +#endif + +/* + * snarfed from Doug McElroy's C++ version + * + * this grep is based on the Posix re package. + * unfortunately it has to have a nonstandard interface. + * 1. fgrep does not have usual operators. REG_LITERAL + * caters for this. + * 2. grep allows null expressions, hence REG_NULL. + * 3. it may be possible to combine the multiple + * patterns of grep into single patterns. important + * special cases are handled by regcomb(). + * 4. anchoring by -x has to be done separately from + * compilation (remember that fgrep has no ^ or $ operator), + * hence REG_LEFT|REG_RIGHT. (An honest, but slow alternative: + * run regexec with REG_NOSUB off and nmatch=1 and check + * whether the match is full length) + */ + +typedef struct Item_s /* list item - sue me for waste */ +{ + struct Item_s* next; /* next in list */ + regex_t re; /* compiled re */ + Sfulong_t hits; /* labeled pattern matches */ + Sfulong_t total; /* total hits */ + char string[1]; /* string value */ +} Item_t; + +typedef struct List_s /* generic list */ +{ + Item_t* head; /* list head */ + Item_t* tail; /* list tail */ +} List_t; + +typedef struct State_s /* program state */ +{ + struct + { + char* base; /* sfsetbuf buffer */ + size_t size; /* sfsetbuf size */ + int noshare; /* turn off SF_SHARE */ + } buffer; + + List_t file; /* pattern file list */ + List_t pattern; /* pattern list */ + List_t re; /* re list */ + + regmatch_t posvec[1]; /* match position vector */ + regmatch_t* pos; /* match position pointer */ + int posnum; /* number of match positions */ + + int any; /* if any pattern hit */ + int list; /* list files with hits */ + int notfound; /* some input file not found */ + int options; /* regex options */ + + Sfulong_t hits; /* total matched pattern count */ + + unsigned char byline; /* multiple pattern line by line*/ + unsigned char count; /* count number of hits */ + unsigned char label; /* all patterns labeled */ + unsigned char match; /* match sense */ + unsigned char query; /* return status but no output */ + unsigned char number; /* line numbers */ + unsigned char prefix; /* print file prefix */ + unsigned char suppress; /* no unopenable file messages */ + unsigned char words; /* word matches only */ +} State_s; + +static void +addre(State_s *state, List_t* p, char* s) +{ + int c; + char* b; + Item_t* x; + Sfio_t* t; + + b = s; + if (state->label) + { + if (!(s = strchr(s, ':'))) + error(3, "%s: label:pattern expected", b); + c = s - b; + s++; + } + else + c = 0; + if (!(x = newof(0, Item_t, 1, c))) + error(ERROR_SYSTEM|3, "out of space (pattern `%s')", b); + if (c) + memcpy(x->string, b, c); + if (state->words) + { + if (!(t = sfstropen())) + error(ERROR_SYSTEM|3, "out of space (word pattern `%s')", s); + if (!(state->options & REG_AUGMENTED)) + sfputc(t, '\\'); + sfputc(t, '<'); + sfputr(t, s, -1); + if (!(state->options & REG_AUGMENTED)) + sfputc(t, '\\'); + sfputc(t, '>'); + if (!(s = sfstruse(t))) + error(ERROR_SYSTEM|3, "out of space"); + } + else + t = 0; + if (c = regcomp(&x->re, s, state->options|REG_MULTIPLE)) + regfatal(&x->re, 3, c); + if (t) + sfstrclose(t); + if (!p->head) + { + p->head = p->tail = x; + if (state->number || !regrecord(&x->re)) + state->byline = 1; + } + else if (state->label || regcomb(&p->tail->re, &x->re)) + { + p->tail = p->tail->next = x; + if (!state->byline && (state->number || !state->label || !regrecord(&x->re))) + state->byline = 1; + } + else + free(x); +} + +static void +addstring(State_s *state, List_t* p, char* s) +{ + Item_t* x; + + if (!(x = newof(0, Item_t, 1, strlen(s)))) + error(ERROR_SYSTEM|3, "out of space (string `%s')", s); + strcpy(x->string, s); + if (p->head) + p->tail->next = x; + else + p->head = x; + p->tail = x; +} + +static void +compile(State_s *state) +{ + int line; + size_t n; + char* s; + char* t; + char* file; + Item_t* x; + Sfio_t* f; + + for (x = state->pattern.head; x; x = x->next) + addre(state, &state->re, x->string); + for (x = state->file.head; x; x = x->next) + { + s = x->string; + if (!(f = sfopen(NiL, s, "r"))) + error(ERROR_SYSTEM|4, "%s: cannot open", s); + else + { + file = error_info.file; + error_info.file = s; + line = error_info.line; + error_info.line = 0; + while (s = (char*)sfreserve(f, SF_UNBOUND, SF_LOCKR)) + { + if (!(n = sfvalue(f))) + break; + if (s[n - 1] != '\n') + { + for (t = s + n; t > s && *--t != '\n'; t--); + if (t == s) + { + sfread(f, s, 0); + break; + } + n = t - s + 1; + } + s[n - 1] = 0; + addre(state, &state->re, s); + s[n - 1] = '\n'; + sfread(f, s, n); + } + while ((s = sfgetr(f, '\n', 1)) || (s = sfgetr(f, '\n', -1))) + { + error_info.line++; + addre(state, &state->re, s); + } + error_info.file = file; + error_info.line = line; + sfclose(f); + } + } + if (!state->re.head) + error(3, "no pattern"); +} + +static void +highlight(Sfio_t* sp, const char* s, int n, int so, int eo) +{ + static const char bold[] = {CC_esc,'[','1','m'}; + static const char normal[] = {CC_esc,'[','0','m'}; + + sfwrite(sp, s, so); + sfwrite(sp, bold, sizeof(bold)); + sfwrite(sp, s + so, eo - so); + sfwrite(sp, normal, sizeof(normal)); + sfwrite(sp, s + eo, n - eo); +} + +typedef struct +{ + State_s *state; + Item_t *item; +} record_handle; + +static int +record(void* handle, const char* s, size_t len) +{ + record_handle *r_x = (record_handle *)handle; + State_s *state = r_x->state; + Item_t *item = r_x->item; + + item->hits++; + if (state->query || state->list) + return -1; + if (!state->count) + { + if (state->prefix) + sfprintf(sfstdout, "%s:", error_info.file); + if (state->label) + sfprintf(sfstdout, "%s:", item->string); + if (state->pos) + highlight(sfstdout, s, len + 1, state->pos[0].rm_so, state->pos[0].rm_eo); + else + sfwrite(sfstdout, s, len + 1); + } + return 0; +} + +static void +execute(State_s *state, Sfio_t* input, char* name) +{ + register char* s; + char* file; + Item_t* x; + size_t len; + int result; + int line; + + Sfulong_t hits = 0; + + if (state->buffer.noshare) + sfset(input, SF_SHARE, 0); + if (state->buffer.size) + sfsetbuf(input, state->buffer.base, state->buffer.size); + if (!name) + name = "/dev/stdin"; + file = error_info.file; + error_info.file = name; + line = error_info.line; + error_info.line = 0; + if (state->byline) + { + for (;;) + { + error_info.line++; + if (s = sfgetr(input, '\n', 0)) + len = sfvalue(input) - 1; + else if (s = sfgetr(input, '\n', -1)) + { + len = sfvalue(input); + s[len] = '\n'; +#if _you_like_the_noise + error(1, "newline appended"); +#endif + } + else + { + if (sferror(input) && errno != EISDIR) + error(ERROR_SYSTEM|2, "read error"); + break; + } + x = state->re.head; + do + { + if (!(result = regnexec(&x->re, s, len, state->posnum, state->pos, 0))) + { + if (!state->label) + break; + x->hits++; + if (state->query || state->list) + goto done; + if (!state->count) + { + if (state->prefix) + sfprintf(sfstdout, "%s:", name); + if (state->number) + sfprintf(sfstdout, "%d:", error_info.line); + sfprintf(sfstdout, "%s:", x->string); + if (state->pos) + highlight(sfstdout, s, len + 1, state->pos[0].rm_so, state->pos[0].rm_eo); + else + sfwrite(sfstdout, s, len + 1); + } + } + else if (result != REG_NOMATCH) + regfatal(&x->re, 3, result); + } while (x = x->next); + if (!state->label && (x != 0) == state->match) + { + hits++; + if (state->query || state->list) + break; + if (!state->count) + { + if (state->prefix) + sfprintf(sfstdout, "%s:", name); + if (state->number) + sfprintf(sfstdout, "%d:", error_info.line); + if (state->pos) + highlight(sfstdout, s, len + 1, state->pos[0].rm_so, state->pos[0].rm_eo); + else + sfwrite(sfstdout, s, len + 1); + } + } + } + } + else + { + register char* e; + register char* t; + char* r; + + static char* span = 0; + static size_t spansize = 0; + + s = e = 0; + for (;;) + { + if (s < e) + { + t = span; + for (;;) + { + len = 2 * (e - s) + t - span + 1; + len = roundof(len, SF_BUFSIZE); + if (spansize < len) + { + spansize = len; + len = t - span; + if (!(span = newof(span, char, spansize, 0))) + error(ERROR_SYSTEM|3, "%s: line longer than %lu characters", name, len + e - s); + t = span + len; + } + len = e - s; + memcpy(t, s, len); + t += len; + if (!(s = sfreserve(input, SF_UNBOUND, 0)) || (len = sfvalue(input)) <= 0) + { + if ((sfvalue(input) || sferror(input)) && errno != EISDIR) + error(ERROR_SYSTEM|2, "%s: read error", name); + break; + } + else if (!(e = memchr(s, '\n', len))) + e = s + len; + else + { + r = s + len; + len = (e - s) + t - span; + len = roundof(len, SF_BUFSIZE); + if (spansize < len) + { + spansize = len; + len = t - span; + if (!(span = newof(span, char, spansize, 0))) + error(ERROR_SYSTEM|3, "%s: line longer than %lu characters", name, len + e - s); + t = span + len; + } + len = e - s; + memcpy(t, s, len); + t += len; + s += len + 1; + e = r; + break; + } + } + *t = '\n'; + x = state->re.head; + do + { + record_handle r_x = { state, x }; + if ((result = regrexec(&x->re, span, t - span, state->posnum, state->pos, state->options, '\n', (void*)&r_x, record)) < 0) + goto done; + if (result && result != REG_NOMATCH) + regfatal(&x->re, 3, result); + } while (x = x->next); + if (!s) + break; + } + else + { + if (!(s = sfreserve(input, SF_UNBOUND, 0))) + { + if ((sfvalue(input) || sferror(input)) && errno != EISDIR) + error(ERROR_SYSTEM|2, "%s: read error", name); + break; + } + if ((len = sfvalue(input)) <= 0) + break; + e = s + len; + } + t = e; + while (t > s) + if (*--t == '\n') + { + x = state->re.head; + do + { + record_handle r_x = { state, x }; + if ((result = regrexec(&x->re, s, t - s, state->posnum, state->pos, state->options, '\n', (void*)&r_x, record)) < 0) + goto done; + if (result && result != REG_NOMATCH) + regfatal(&x->re, 3, result); + } while (x = x->next); + s = t + 1; + break; + } + } + } + done: + error_info.file = file; + error_info.line = line; + if (state->byline && !state->label) + { + if (hits && state->list >= 0) + state->any = 1; + if (!state->query) + { + if (!state->list) + { + if (state->count) + { + if (state->count & 2) + state->hits += hits; + else + { + if (state->prefix) + sfprintf(sfstdout, "%s:", name); + sfprintf(sfstdout, "%I*u\n", sizeof(hits), hits); + } + } + } + else if ((hits != 0) == (state->list > 0)) + { + if (state->list < 0) + state->any = 1; + sfprintf(sfstdout, "%s\n", name); + } + } + } + else + { + x = state->re.head; + do + { + if (x->hits && state->list >= 0) + { + state->any = 1; + if (state->query) + break; + } + if (!state->query) + { + if (!state->list) + { + if (state->count) + { + if (state->count & 2) + { + x->total += x->hits; + state->hits += x->hits; + } + else + { + if (state->prefix) + sfprintf(sfstdout, "%s:", name); + if (state->label) + sfprintf(sfstdout, "%s:", x->string); + sfprintf(sfstdout, "%I*u\n", sizeof(x->hits), x->hits); + } + } + } + else if ((x->hits != 0) == (state->list > 0)) + { + if (state->list < 0) + state->any = 1; + if (state->label) + sfprintf(sfstdout, "%s:%s\n", name, x->string); + else + sfprintf(sfstdout, "%s\n", name); + } + } + x->hits = 0; + } while (x = x->next); + } +} + + +static +int grep_main(int argc, char** argv, void *context) +{ + int c; + char* s; + char* h; + Sfio_t* f; + State_s state; + memset(&state, 0, sizeof(state)); + + NoP(argc); + state.match = 1; + state.options = REG_FIRST|REG_NOSUB|REG_NULL; + h = 0; + if (strcmp(astconf("CONFORMANCE", NiL, NiL), "standard")) + state.options |= REG_LENIENT; + if (s = strrchr(argv[0], '/')) + s++; + else + s = argv[0]; + switch (*s) + { + case 'e': + case 'E': + s = "egrep"; + state.options |= REG_EXTENDED; + break; + case 'f': + case 'F': + s = "fgrep"; + state.options |= REG_LITERAL; + break; + case 'p': + case 'P': + s = "pgrep"; + state.options |= REG_EXTENDED|REG_LENIENT; + break; + case 'x': + case 'X': + s = "xgrep"; + state.options |= REG_AUGMENTED; + break; + default: + s = "grep"; + break; + } + error_info.id = s; + while (c = optget(argv, usage)) + switch (c) + { + case 'E': + state.options |= REG_EXTENDED; + break; + case 'F': + state.options |= REG_LITERAL; + break; + case 'G': + state.options &= ~(REG_AUGMENTED|REG_EXTENDED); + break; + case 'H': + state.prefix = opt_info.num; + break; + case 'L': + state.list = -opt_info.num; + break; + case 'N': + h = opt_info.arg; + break; + case 'O': + state.options |= REG_LENIENT; + break; + case 'P': + state.options |= REG_EXTENDED|REG_LENIENT; + break; + case 'S': + state.options &= ~REG_LENIENT; + break; + case 'T': + s = opt_info.arg; + switch (*s) + { + case 'b': + case 'm': + c = *s++; + state.buffer.size = strton(s, &s, NiL, 1); + if (c == 'b' && !(state.buffer.base = newof(0, char, state.buffer.size, 0))) + error(ERROR_SYSTEM|3, "out of space [test buffer]"); + if (*s) + error(3, "%s: invalid characters after test", s); + break; + case 'f': + state.options |= REG_FIRST; + break; + case 'l': + state.options |= REG_LEFT; + break; + case 'n': + state.buffer.noshare = 1; + break; + case 'r': + state.options |= REG_RIGHT; + break; + default: + error(3, "%s: unknown test", s); + break; + } + break; + case 'X': + state.options |= REG_AUGMENTED; + break; + case 'a': + break; + case 'b': + state.options &= ~(REG_FIRST|REG_NOSUB); + break; + case 'c': + state.count |= 1; + break; + case 'e': + addstring(&state, &state.pattern, opt_info.arg); + break; + case 'f': + addstring(&state, &state.file, opt_info.arg); + break; + case 'h': + state.prefix = 2; + break; + case 'i': + state.options |= REG_ICASE; + break; + case 'l': + state.list = opt_info.num; + break; + case 'm': + state.label = 1; + break; + case 'n': + state.number = 1; + break; + case 'q': + state.query = 1; + break; + case 's': + state.suppress = opt_info.num; + break; + case 't': + state.count |= 2; + break; + case 'v': + if (state.match = !opt_info.num) + state.options &= ~REG_INVERT; + else + state.options |= REG_INVERT; + break; + case 'w': + state.words = 1; + break; + case 'x': + state.options |= REG_LEFT|REG_RIGHT; + break; + case '?': + error(ERROR_USAGE|4, "%s", opt_info.arg); + break; + case ':': + error(2, "%s", opt_info.arg); + break; + default: + error(3, "%s: not implemented", opt_info.name); + break; + } + argv += opt_info.index; + if ((state.options & REG_LITERAL) && (state.options & (REG_AUGMENTED|REG_EXTENDED))) + error(3, "-F and -A or -P or -X are incompatible"); + if ((state.options & REG_LITERAL) && state.words) + error(ERROR_SYSTEM|3, "-F and -w are incompatible"); + if (!state.file.head && !state.pattern.head) + { + if (!argv[0]) + error(3, "no pattern"); + addstring(&state, &state.pattern, *argv++); + } + if (!(state.options & (REG_FIRST|REG_NOSUB))) + { + if (state.count || state.list || state.query || (state.options & REG_INVERT)) + state.options |= REG_FIRST|REG_NOSUB; + else + { + state.pos = state.posvec; + state.posnum = elementsof(state.posvec); + } + } + compile(&state); + if (!argv[0]) + { + state.prefix = h ? 1 : 0; + execute(&state, sfstdin, h); + } + else + { + if (state.prefix > 1) + state.prefix = 0; + else if (argv[1]) + state.prefix = 1; + while (s = *argv++) + { + if (f = sfopen(NiL, s, "r")) + { + execute(&state, f, s); + sfclose(f); + if (state.query && state.any) + break; + } + else + { + state.notfound = 1; + if (!state.suppress) + error(ERROR_SYSTEM|2, "%s: cannot open", s); + } + } + } + if ((state.count & 2) && !state.query && !state.list) + { + if (state.label) + { + Item_t* x; + + x = state.re.head; + do + { + sfprintf(sfstdout, "%s:%I*u\n", x->string, sizeof(x->total), x->total); + } while (x = x->next); + } + else + sfprintf(sfstdout, "%I*u\n", sizeof(state.hits), state.hits); + } + return (state.notfound && !state.query) ? 2 : !state.any; +} + + +int b_egrep(int argc, char** argv, void *context) +{ + return grep_main(argc, argv, context); +} + +int b_grep(int argc, char** argv, void *context) +{ + return grep_main(argc, argv, context); +} + +int b_fgrep(int argc, char** argv, void *context) +{ + return grep_main(argc, argv, context); +} + +int b_pgrep(int argc, char** argv, void *context) +{ + return grep_main(argc, argv, context); +} + +int b_xgrep(int argc, char** argv, void *context) +{ + return grep_main(argc, argv, context); +} diff --git a/usr/src/lib/libcmd/common/head.c b/usr/src/lib/libcmd/common/head.c index cee683e81a..98f7df8e8f 100644 --- a/usr/src/lib/libcmd/common/head.c +++ b/usr/src/lib/libcmd/common/head.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/id.c b/usr/src/lib/libcmd/common/id.c index a1820e3bf7..53d8cad830 100644 --- a/usr/src/lib/libcmd/common/id.c +++ b/usr/src/lib/libcmd/common/id.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/join.c b/usr/src/lib/libcmd/common/join.c index 12b40bc31b..909a8e8a29 100644 --- a/usr/src/lib/libcmd/common/join.c +++ b/usr/src/lib/libcmd/common/join.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -28,7 +28,7 @@ */ static const char usage[] = -"[-?\n@(#)$Id: join (AT&T Research) 2006-10-31 $\n]" +"[-?\n@(#)$Id: join (AT&T Research) 2009-08-01 $\n]" USAGE_LICENSE "[+NAME?join - relational database operator]" "[+DESCRIPTION?\bjoin\b performs an \aequality join\a on the files \afile1\a " @@ -351,7 +351,7 @@ outfield(Join_t* jp, int index, register int n, int last) cp = 0; if ((n=jp->delim)<=0) { - if (fp->spaces) + if (cp && fp->spaces) { /*eliminate leading spaces */ while (jp->state[*(unsigned char*)cp++]==S_SPACE); @@ -365,7 +365,7 @@ outfield(Join_t* jp, int index, register int n, int last) size = cpmax-cp; else size = 0; - if (size==0) + if (size<=1) { if (!jp->nullfield) sfputc(iop,n); @@ -800,7 +800,7 @@ b_join(int argc, char** argv, void* context) if (jp->buffered) { sfsetbuf(jp->file[0].iop, jp->file[0].iop, SF_UNBOUND); - sfsetbuf(jp->file[1].iop, jp->file[0].iop, SF_UNBOUND); + sfsetbuf(jp->file[1].iop, jp->file[1].iop, SF_UNBOUND); } jp->state['\n'] = S_NL; jp->outfile = sfstdout; diff --git a/usr/src/lib/libcmd/common/ln.c b/usr/src/lib/libcmd/common/ln.c index 90a6190504..94da7be389 100644 --- a/usr/src/lib/libcmd/common/ln.c +++ b/usr/src/lib/libcmd/common/ln.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/logname.c b/usr/src/lib/libcmd/common/logname.c index a142653345..6ca5b02e0b 100644 --- a/usr/src/lib/libcmd/common/logname.c +++ b/usr/src/lib/libcmd/common/logname.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/md5sum.c b/usr/src/lib/libcmd/common/md5sum.c index f4f7e6ad9b..c4cafa98c7 100644 --- a/usr/src/lib/libcmd/common/md5sum.c +++ b/usr/src/lib/libcmd/common/md5sum.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/mkdir.c b/usr/src/lib/libcmd/common/mkdir.c index 596ef2b6b8..5ccce98221 100644 --- a/usr/src/lib/libcmd/common/mkdir.c +++ b/usr/src/lib/libcmd/common/mkdir.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -73,22 +73,28 @@ b_mkdir(int argc, char** argv, void* context) struct stat st; cmdinit(argc, argv, context, ERROR_CATALOG, 0); - while (n = optget(argv, usage)) switch (n) + for (;;) { - case 'p': - pflag = 1; - break; - case 'm': - mflag = 1; - mode = strperm(arg = opt_info.arg, &opt_info.arg, mode); - if (*opt_info.arg) - error(ERROR_exit(0), "%s: invalid mode", arg); - break; - case ':': - error(2, "%s", opt_info.arg); - break; - case '?': - error(ERROR_usage(2), "%s", opt_info.arg); + switch (optget(argv, usage)) + { + case 0: + break; + case 'p': + pflag = 1; + continue; + case 'm': + mflag = 1; + mode = strperm(arg = opt_info.arg, &opt_info.arg, mode); + if (*opt_info.arg) + error(ERROR_exit(0), "%s: invalid mode", arg); + continue; + case ':': + error(2, "%s", opt_info.arg); + continue; + case '?': + error(ERROR_usage(2), "%s", opt_info.arg); + continue; + } break; } argv += opt_info.index; diff --git a/usr/src/lib/libcmd/common/mkfifo.c b/usr/src/lib/libcmd/common/mkfifo.c index 7bc56747f7..8692c0702d 100644 --- a/usr/src/lib/libcmd/common/mkfifo.c +++ b/usr/src/lib/libcmd/common/mkfifo.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -26,9 +26,8 @@ * mkfifo */ - static const char usage[] = -"[-?\n@(#)$Id: mkfifo (AT&T Research) 1999-04-20 $\n]" +"[-?\n@(#)$Id: mkfifo (AT&T Research) 2009-01-02 $\n]" USAGE_LICENSE "[+NAME?mkfifo - make FIFOs (named pipes)]" "[+DESCRIPTION?\bmkfifo\b creates one or more FIFO's. By " @@ -50,40 +49,50 @@ USAGE_LICENSE #include <cmd.h> #include <ls.h> -#define RWALL (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) - int b_mkfifo(int argc, char *argv[], void* context) { - register char *arg; - register mode_t mode=RWALL, mask=0; - register int n; + register char* arg; + register mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; + register mode_t mask = 0; + register int mflag = 0; cmdinit(argc, argv, context, ERROR_CATALOG, 0); - while (n = optget(argv, usage)) switch (n) + for (;;) { - case 'm': - mode = strperm(arg=opt_info.arg,&opt_info.arg,mode); - if(*opt_info.arg) - error(ERROR_exit(0),"%s: invalid mode",arg); - break; - case ':': - error(2, "%s",opt_info.arg); - break; - case '?': - error(ERROR_usage(2), "%s",opt_info.arg); + switch (optget(argv, usage)) + { + case 0: + break; + case 'm': + mflag = 1; + mode = strperm(arg = opt_info.arg, &opt_info.arg, mode); + if (*opt_info.arg) + error(ERROR_exit(0), "%s: invalid mode", arg); + continue; + case ':': + error(2, "%s", opt_info.arg); + continue; + case '?': + error(ERROR_usage(2), "%s", opt_info.arg); + continue; + } break; } argv += opt_info.index; - if(error_info.errors || !*argv) - error(ERROR_usage(2),"%s",optusage(NiL)); - while(arg = *argv++) + if (error_info.errors || !*argv) + error(ERROR_usage(2), "%s", optusage(NiL)); + mask = umask(0); + if (!mflag) { - if(mkfifo(arg,mode) < 0) - error(ERROR_system(0),"%s:",arg); + mode &= ~mask; + umask(mask); + mask = 0; } - if(mask) + while (arg = *argv++) + if (mkfifo(arg, mode) < 0) + error(ERROR_system(0), "%s:", arg); + if (mask) umask(mask); - return(error_info.errors!=0); + return error_info.errors != 0; } - diff --git a/usr/src/lib/libcmd/common/mktemp.c b/usr/src/lib/libcmd/common/mktemp.c new file mode 100644 index 0000000000..2936a56e22 --- /dev/null +++ b/usr/src/lib/libcmd/common/mktemp.c @@ -0,0 +1,164 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1992-2009 AT&T Intellectual Property * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* 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: mktemp (AT&T Research) 2009-06-19 $\n]" +USAGE_LICENSE +"[+NAME?mktemp - make temporary file or directory]" +"[+DESCRIPTION?\bmktemp\b creates a temporary file with optional base " + "name prefix \aprefix\a. If \aprefix\a is omitted then \btmp_\b is used " + "and \b--tmp\b is implied. If \aprefix\a contains a directory prefix " + "then that directory overrides any of the directories described below. A " + "temporary file will have mode \brw-------\b and a temporary directory " + "will have mode \brwx------\b, subject to \bumask\b(1). Generated paths " + "have these attributes:]" + "{" + "[+*?Lower case to avoid clashes on case ignorant filesystems.]" + "[+*?Pseudo-random part to deter denial of service attacks.]" + "[+*?Pseudo-random part is \a3-chars\a.\a3-chars\a to accomodate " + "8.3 filesystems.]" + "}" +"[+?A consecutive sequence of \bX\b's in \aprefix\a is replaced by the " + "pseudo-random part. If there are no \bX\b's then the pseudo-random part " + "is appended to the prefix.]" +"[d:directory?Create a directory instead of a regular file.]" +"[m:mode]:[mode?Set the mode of the created temporary to \amode\a. " + "\amode\a is symbolic or octal mode as in \bchmod\b(1). Relative modes " + "assume an initial mode of \bu=rwx\b.]" +"[p:default?Use \adirectory\a if the \bTMPDIR\b environment variable is " + "not defined. Implies \b--tmp\b.]:[directory]" +"[q:quiet?Suppress file and directory error diagnostics.]" +"[t:tmp|temporary-directory?Create a path rooted in a temporary " + "directory.]" +"[u:unsafe|dry-run?Check for file/directory existence but do not create. " + "Who would want to do that.]" +"\n" +"\n[ prefix ]\n" +"\n" +"[+SEE ALSO?\bmkdir\b(1), \bpathtemp\b(3), \bmktemp\b(3)]" +; + +#include <cmd.h> +#include <ls.h> + +int +b_mktemp(int argc, char** argv, void* context) +{ + mode_t mode = 0; + mode_t mask; + int fd; + int i; + int quiet = 0; + int unsafe = 0; + int* fdp = &fd; + char* dir = ""; + char* pfx; + char* t; + char path[PATH_MAX]; + + cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY); + for (;;) + { + switch (optget(argv, usage)) + { + case 0: + break; + case 'd': + fdp = 0; + continue; + case 'm': + mode = strperm(pfx = opt_info.arg, &opt_info.arg, S_IRWXU); + if (*opt_info.arg) + error(ERROR_exit(0), "%s: invalid mode", pfx); + continue; + case 'p': + if ((t = getenv("TMPDIR")) && *t) + dir = 0; + else + dir = opt_info.arg; + continue; + case 'q': + quiet = 1; + continue; + case 't': + dir = 0; + continue; + case 'u': + unsafe = 1; + fdp = 0; + continue; + case ':': + error(2, "%s", opt_info.arg); + continue; + case '?': + error(ERROR_usage(2), "%s", opt_info.arg); + continue; + } + break; + } + argv += opt_info.index; + if (error_info.errors || (pfx = *argv++) && *argv) + error(ERROR_usage(2), "%s", optusage(NiL)); + mask = umask(0); + if (!mode) + mode = (fdp ? (S_IRUSR|S_IWUSR) : S_IRWXU) & ~mask; + umask(~mode & (S_IRWXU|S_IRWXG|S_IRWXO)); + if (!pfx) + { + pfx = "tmp_"; + if (dir && !*dir) + dir = 0; + } + if (t = strrchr(pfx, '/')) + { + i = ++t - pfx; + dir = fmtbuf(i); + memcpy(dir, pfx, i); + dir[i] = 0; + pfx = t; + } + for (;;) + { + if (!pathtemp(path, sizeof(path), dir, pfx, fdp)) + { + if (quiet) + error_info.errors++; + else + error(ERROR_SYSTEM|2, "cannot create temporary path"); + break; + } + if (fdp || unsafe || !mkdir(path, mode)) + { + if (fdp) + close(*fdp); + sfputr(sfstdout, path, '\n'); + break; + } + if (sh_checksig(context)) + { + error_info.errors++; + break; + } + } + umask(mask); + return error_info.errors != 0; +} diff --git a/usr/src/lib/libcmd/common/mv.c b/usr/src/lib/libcmd/common/mv.c index ec08bea2e4..c84c1092bd 100644 --- a/usr/src/lib/libcmd/common/mv.c +++ b/usr/src/lib/libcmd/common/mv.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/paste.c b/usr/src/lib/libcmd/common/paste.c index ce1dcef087..71da3f472a 100644 --- a/usr/src/lib/libcmd/common/paste.c +++ b/usr/src/lib/libcmd/common/paste.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/pathchk.c b/usr/src/lib/libcmd/common/pathchk.c index 7b0151d69c..ef27bd2788 100644 --- a/usr/src/lib/libcmd/common/pathchk.c +++ b/usr/src/lib/libcmd/common/pathchk.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -26,44 +26,50 @@ */ static const char usage[] = -"[-?\n@(#)$Id: pathchk (AT&T Research) 2006-09-19 $\n]" +"[-?\n@(#)$Id: pathchk (AT&T Research) 2009-07-24 $\n]" USAGE_LICENSE "[+NAME?pathchk - check pathnames for portability]" -"[+DESCRIPTION?\bpathchk\b checks each \apathname\a to see if it " - "is valid and/or portable. A \apathname\a is valid if it " - "can be used to access or create a file without causing syntax " - "errors. A file is portable, if no truncation will result on " - "any conforming POSIX.1 implementation.]" +"[+DESCRIPTION?\bpathchk\b checks each \apathname\a to see if it is " + "valid and/or portable. A \apathname\a is valid if it can be used to " + "access or create a file without causing syntax errors. A file is " + "portable if no truncation will result on any conforming POSIX.1 " + "implementation.]" "[+?By default \bpathchk\b checks each component of each \apathname\a " - "based on the underlying file system. A diagnostic is written " - "to standard error for each pathname that:]{" - "[+-?Is longer than \b$(getconf PATH_MAX)\b bytes.]" - "[+-?Contains any component longer than \b$(getconf NAME_MAX)\b bytes.]" - "[+-?Contains any directory component in a directory that is " - "not searchable.]" - "[+-?Contains any character in any component that is not valid in " - "its containing directory.]" - "[+-?Is empty.]" - "}" -"[p:portability?Instead of performing length checks on the underlying " - "file system, write a diagnostic for each pathname operand that:]{" - "[+-?Is longer than \b$(getconf _POSIX_PATH_MAX)\b bytes.]" - "[+-?Contains any component longer than " - "\b$(getconf _POSIX_NAME_MAX)\b bytes.]" + "based on the underlying file system. A diagnostic is written to " + "standard error for each pathname that:]" + "{" + "[+-?Is longer than \b$(getconf PATH_MAX)\b bytes.]" + "[+-?Contains any component longer than \b$(getconf NAME_MAX)\b " + "bytes.]" + "[+-?Contains any directory component in a directory that is not " + "searchable.]" + "[+-?Contains any character in any component that is not valid " + "in its containing directory.]" + "[+-?Is empty.]" + "}" +"[p:components?Instead of performing length checks on the underlying " + "file system, write a diagnostic for each pathname operand that:]" + "{" + "[+-?Is longer than \b$(getconf _POSIX_PATH_MAX)\b bytes.]" + "[+-?Contains any component longer than \b$(getconf " + "_POSIX_NAME_MAX)\b bytes.]" "[+-?Contains any character in any component that is not in the " - "portable filename character set.]" -#if 0 - "[+-?Contains any component with \b-\b as the first character.]" -#endif - "[+-?Is empty.]" - "}" + "portable filename character set.]" + "}" +"[P:path?Write a diagnostic for each pathname operand that:]" + "{" + "[+-?Contains any component with \b-\b as the first character.]" + "[+-?Is empty.]" + "}" +"[a:all|portability?Equivalent to \b--components\b \b--path\b.]" "\n" "\npathname ...\n" "\n" -"[+EXIT STATUS?]{" +"[+EXIT STATUS?]" + "{" "[+0?All \apathname\a operands passed all of the checks.]" "[+>0?An error occurred.]" -"}" + "}" "[+SEE ALSO?\bgetconf\b(1), \bcreat\b(2), \bpathchk\b(2)]" ; @@ -71,6 +77,9 @@ USAGE_LICENSE #include <cmd.h> #include <ls.h> +#define COMPONENTS 0x1 +#define PATH 0x2 + #define isport(c) (((c)>='a' && (c)<='z') || ((c)>='A' && (c)<='Z') || ((c)>='0' && (c)<='9') || (strchr("._-",(c))!=0) ) /* @@ -82,10 +91,10 @@ static long mypathconf(const char *path, int op) static const char* const ops[] = { "NAME_MAX", "PATH_MAX" }; - errno=0; - if((r=strtol(astconf(ops[op], path, NiL), NiL, 0))<0 && errno==0) - return(LONG_MAX); - return(r); + errno = 0; + if ((r = strtol(astconf(ops[op], path, NiL), NiL, 0)) < 0 && !errno) + return LONG_MAX; + return r; } /* @@ -100,10 +109,11 @@ static int pathchk(char* path, int mode) if(!*path) { - error(2,"path is empty"); - return(0); + if (mode & PATH) + error(2,"path is empty"); + return -1; } - if(mode) + if(mode & COMPONENTS) { name_max = _POSIX_NAME_MAX; path_max = _POSIX_PATH_MAX; @@ -177,7 +187,7 @@ static int pathchk(char* path, int mode) else if(errno==ENAMETOOLONG) { error(2,"%s: pathname too long",path); - return(0); + return -1; } #endif /*ENAMETOOLONG*/ else @@ -186,18 +196,18 @@ static int pathchk(char* path, int mode) } while(*(cpold=cp)) { - if(mode && *cp == '-') + if((mode & PATH) && *cp == '-') { error(2,"%s: path component begins with '-'",path,fmtquote(buf, NiL, "'", 1, 0)); - return(0); + return -1; } while((c= *cp++) && c!='/') - if(mode && !isport(c)) + if((mode & COMPONENTS) && !isport(c)) { buf[0] = c; buf[1] = 0; error(2,"%s: '%s' not in portable character set",path,fmtquote(buf, NiL, "'", 1, 0)); - return(0); + return -1; } if((cp-cpold) > name_max) goto err; @@ -208,41 +218,51 @@ static int pathchk(char* path, int mode) } if((cp-path) >= path_max) { - error(2,"%s: pathname too long",path); - return(0); + error(2, "%s: pathname too long", path); + return -1; } - return(1); -err: - error(2,"%s: component name %.*s too long",path,cp-cpold-1,cpold); - return(0); + return 0; + err: + error(2, "%s: component name %.*s too long", path, cp-cpold-1, cpold); + return -1; } int b_pathchk(int argc, char** argv, void* context) { - register int n, mode=0; - register char *cp; + register int n; + register int mode = 0; + register char* s; cmdinit(argc, argv, context, ERROR_CATALOG, 0); - while (n = optget(argv, usage)) switch (n) + for (;;) { - case 'p': - mode = 1; - break; - case ':': - error(2, "%s", opt_info.arg); - break; - case '?': - error(ERROR_usage(2), "%s", opt_info.arg); + switch (optget(argv, usage)) + { + case 0: + break; + case 'a': + mode |= COMPONENTS|PATH; + continue; + case 'p': + mode |= COMPONENTS; + continue; + case 'P': + mode |= PATH; + continue; + case ':': + error(2, "%s", opt_info.arg); + continue; + case '?': + error(ERROR_usage(2), "%s", opt_info.arg); + continue; + } break; } argv += opt_info.index; - if(*argv==0 || error_info.errors) - error(ERROR_usage(2),"%s", optusage((char*)0)); - while(cp = *argv++) - { - if(!pathchk(cp,mode)) - error_info.errors=1; - } - return(error_info.errors); + if (!*argv || error_info.errors) + error(ERROR_usage(2),"%s", optusage(NiL)); + while (s = *argv++) + pathchk(s, mode); + return error_info.errors != 0; } diff --git a/usr/src/lib/libcmd/common/pids.c b/usr/src/lib/libcmd/common/pids.c index ca419850c1..432b46f345 100644 --- a/usr/src/lib/libcmd/common/pids.c +++ b/usr/src/lib/libcmd/common/pids.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/rev.c b/usr/src/lib/libcmd/common/rev.c index 3c63840bdb..c67a6a4c9f 100644 --- a/usr/src/lib/libcmd/common/rev.c +++ b/usr/src/lib/libcmd/common/rev.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/rev.h b/usr/src/lib/libcmd/common/rev.h index c23ffb381e..c35fbc4ead 100644 --- a/usr/src/lib/libcmd/common/rev.h +++ b/usr/src/lib/libcmd/common/rev.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/revlib.c b/usr/src/lib/libcmd/common/revlib.c index d95bbf0c80..a2407f122b 100644 --- a/usr/src/lib/libcmd/common/revlib.c +++ b/usr/src/lib/libcmd/common/revlib.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/rm.c b/usr/src/lib/libcmd/common/rm.c index d64d209b9d..fbd21583fb 100644 --- a/usr/src/lib/libcmd/common/rm.c +++ b/usr/src/lib/libcmd/common/rm.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -27,7 +27,7 @@ */ static const char usage[] = -"[-?\n@(#)$Id: rm (AT&T Research) 2008-10-15 $\n]" +"[-?\n@(#)$Id: rm (AT&T Research) 2009-06-18 $\n]" USAGE_LICENSE "[+NAME?rm - remove files]" "[+DESCRIPTION?\brm\b removes the named \afile\a arguments. By default it" @@ -81,6 +81,7 @@ USAGE_LICENSE typedef struct State_s /* program state */ { + void* context; /* builtin context */ int clobber; /* clear out file data first */ int directory; /* remove(dir) not rmdir(dir) */ int force; /* force actions */ @@ -179,7 +180,7 @@ rm(State_t* state, register FTSENT* ent) { if (state->interactive) { - if ((v = astquery(-1, "remove directory %s? ", ent->fts_path)) < 0) + if ((v = astquery(-1, "remove directory %s? ", ent->fts_path)) < 0 || sh_checksig(state->context)) return -1; if (v > 0) { @@ -253,7 +254,7 @@ rm(State_t* state, register FTSENT* ent) sfputr(sfstdout, ent->fts_path, '\n'); if (state->interactive) { - if ((v = astquery(-1, "remove %s? ", ent->fts_path)) < 0) + if ((v = astquery(-1, "remove %s? ", ent->fts_path)) < 0 || sh_checksig(state->context)) return -1; if (v > 0) { @@ -277,7 +278,8 @@ rm(State_t* state, register FTSENT* ent) errno == ETXTBSY ? "``running program''" : #endif ent->fts_statp->st_uid != state->uid ? "``not owner''" : - fmtmode(ent->fts_statp->st_mode & S_IPERM, 0) + 1, ent->fts_path)) < 0) + fmtmode(ent->fts_statp->st_mode & S_IPERM, 0) + 1, ent->fts_path)) < 0 || + sh_checksig(state->context)) return -1; if (v > 0) { @@ -343,6 +345,7 @@ b_rm(int argc, register char** argv, void* context) cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY); memset(&state, 0, sizeof(state)); + state.context = context; state.fs3d = fs3d(FS3D_TEST); state.terminal = isatty(0); for (;;) diff --git a/usr/src/lib/libcmd/common/rmdir.c b/usr/src/lib/libcmd/common/rmdir.c index e6c370c436..c7acb197f9 100644 --- a/usr/src/lib/libcmd/common/rmdir.c +++ b/usr/src/lib/libcmd/common/rmdir.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/shcmd.h b/usr/src/lib/libcmd/common/shcmd.h deleted file mode 100644 index d355c7fd75..0000000000 --- a/usr/src/lib/libcmd/common/shcmd.h +++ /dev/null @@ -1,80 +0,0 @@ -/*********************************************************************** -* * -* This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * -* and is licensed under the * -* Common Public License, Version 1.0 * -* by AT&T Intellectual Property * -* * -* 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 - -/* - * ksh builtin command api - */ - -#ifndef _SHCMD_H -#define _SHCMD_H 1 - -#ifndef SH_VERSION -# define Shell_t void -#endif -#ifndef NV_DEFAULT -# define Namval_t void -#endif -#ifndef ERROR_NOTIFY -# define ERROR_NOTIFY 1 -#endif - -typedef int (*Shbltin_f)(int, char**, void*); - -#undef Shbltin_t -typedef struct Shbltin_s -{ - Shell_t *shp; - void *ptr; - int version; - int (*shrun)(int, char**); - int (*shtrap)(const char*, int); - void (*shexit)(int); - Namval_t *(*shbltin)(const char*, Shbltin_f, void*); - unsigned char notify; - unsigned char sigset; - unsigned char nosfio; - Namval_t *bnode; - Namval_t *vnode; - char *data; - int flags; -} Shbltin_t; - -#if defined(SH_VERSION) || defined(_SH_PRIVATE) -# undef Shell_t -# undef Namval_t -#else -# define sh_run(c, ac, av) ((c)?(*((Shbltin_t*)(c))->shrun)(ac,av):-1) -# define sh_system(c,str) ((c)?(*((Shbltin_t*)(c))->shtrap)(str,0):system(str)) -# define sh_exit(c,n) ((c)?(*((Shbltin_t*)(c))->shexit)(n):exit(n)) -# define sh_checksig(c) ((c) && ((Shbltin_t*)(c))->sigset) -# if defined(SFIO_VERSION) || defined(_AST_H) -# define LIB_INIT(c) -# else -# define LIB_INIT(c) ((c) && (((Shbltin_t*)(c))->nosfio = 1)) -# endif -# ifndef _CMD_H -# define cmdinit(ac,av,c,cat,flg) do { if((ac)<=0) return(0); \ - (((Shbltin_t*)(c))->notify = ((flg)&ERROR_NOTIFY)?1:0);} while(0) -# endif -#endif - -#endif diff --git a/usr/src/lib/libcmd/common/stty.c b/usr/src/lib/libcmd/common/stty.c index 6868d3f326..a7754f447c 100644 --- a/usr/src/lib/libcmd/common/stty.c +++ b/usr/src/lib/libcmd/common/stty.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -26,7 +26,7 @@ */ static const char usage[] = -"[-?@(#)$Id: stty (AT&T Research) 2008-04-01 $\n]" +"[-?@(#)$Id: stty (AT&T Research) 2008-11-10 $\n]" USAGE_LICENSE "[+NAME?stty - set or get terminal modes]" "[+DESCRIPTION?\bstty\b sets certain terminal I/O modes for the device " @@ -913,11 +913,9 @@ b_stty(int argc, char** argv, void* context) { switch (n = optget(argv, usage)) { - case 't': - flags |= T_FLAG; - continue; case 'a': case 'g': + case 't': if (!opt_info.offset || !argv[opt_info.index][opt_info.offset]) { switch (n) @@ -928,6 +926,9 @@ b_stty(int argc, char** argv, void* context) case 'g': flags |= G_FLAG; break; + case 't': + flags |= T_FLAG; + break; } continue; } diff --git a/usr/src/lib/libcmd/common/sum.c b/usr/src/lib/libcmd/common/sum.c index da6dc6fa2a..8b16197863 100644 --- a/usr/src/lib/libcmd/common/sum.c +++ b/usr/src/lib/libcmd/common/sum.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/sync.c b/usr/src/lib/libcmd/common/sync.c index 8ddc855783..863211c225 100644 --- a/usr/src/lib/libcmd/common/sync.c +++ b/usr/src/lib/libcmd/common/sync.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/tail.c b/usr/src/lib/libcmd/common/tail.c index 7eb012af7f..ca128f2938 100644 --- a/usr/src/lib/libcmd/common/tail.c +++ b/usr/src/lib/libcmd/common/tail.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -28,7 +28,7 @@ */ static const char usage[] = -"+[-?\n@(#)$Id: tail (AT&T Research) 2006-10-18 $\n]" +"+[-?\n@(#)$Id: tail (AT&T Research) 2009-08-25 $\n]" USAGE_LICENSE "[+NAME?tail - output trailing portion of one or more files ]" "[+DESCRIPTION?\btail\b copies one or more input files to standard output " @@ -44,21 +44,25 @@ USAGE_LICENSE "followed by one of the following characters to specify a different " "unit other than a single byte:]{" "[+b?512 bytes.]" - "[+k?1-kilobyte.]" - "[+m?1-megabyte.]" + "[+k?1 KiB.]" + "[+m?1 MiB.]" + "[+g?1 GiB.]" "}" "[+?For backwards compatibility, \b-\b\anumber\a is equivalent to " "\b-n\b \anumber\a and \b+\b\anumber\a is equivalent to " - "\b-n -\b\anumber\a.]" + "\b-n -\b\anumber\a. \anumber\a may also have these option " + "suffixes: \bb c f g k l m r\b.]" "[n:lines]:[lines:=10?Copy \alines\a lines from each file. A negative value " - "for \alines\a indicates an offset from the start of the file.]" + "for \alines\a indicates an offset from the end of the file.]" +"[b:blocks?Copy units of 512 bytes.]" "[c:bytes]:?[chars?Copy \achars\a bytes from each file. A negative value " - "for \achars\a indicates an offset from the start of the file.]" + "for \achars\a indicates an offset from the end of the file.]" "[f:forever|follow?Loop forever trying to read more characters as the " "end of each file to copy new data. Ignored if reading from a pipe " "or fifo.]" "[h!:headers?Output filename headers.]" +"[l:lines?Copy units of lines. This is the default.]" "[L:log?When a \b--forever\b file times out via \b--timeout\b, verify that " "the curent file has not been renamed and replaced by another file " "of the same name (a common log file practice) before giving up on " @@ -83,9 +87,11 @@ USAGE_LICENSE "[+S?scores]" "}" "[v:verbose?Always ouput filename headers.]" + "\n" "\n[file ...]\n" "\n" + "[+EXIT STATUS?]{" "[+0?All files copied successfully.]" "[+>0?One or more files did not copy.]" @@ -103,17 +109,18 @@ USAGE_LICENSE #define ERROR (1<<1) #define FOLLOW (1<<2) #define HEADERS (1<<3) -#define LOG (1<<4) -#define NEGATIVE (1<<5) -#define POSITIVE (1<<6) -#define REVERSE (1<<7) -#define SILENT (1<<8) -#define TIMEOUT (1<<9) -#define VERBOSE (1<<10) +#define LINES (1<<4) +#define LOG (1<<5) +#define NEGATIVE (1<<6) +#define POSITIVE (1<<7) +#define REVERSE (1<<8) +#define SILENT (1<<9) +#define TIMEOUT (1<<10) +#define VERBOSE (1<<11) #define NOW (unsigned long)time(NiL) -#define LINES 10 +#define DEFAULT 10 #ifdef S_ISSOCK #define FIFO(m) (S_ISFIFO(m)||S_ISSOCK(m)) @@ -132,8 +139,11 @@ struct Tail_s unsigned long expire; long dev; long ino; + int fifo; }; +static const char header_fmt[] = "\n==> %s <==\n"; + /* * if file is seekable, position file to tail location and return offset * otherwise, return -1 @@ -159,10 +169,10 @@ tailpos(register Sfio_t* fp, register Sfoff_t number, int delim) return first; return offset; } - if ((offset = last - SF_BUFSIZE) < first) - offset = first; for (;;) { + if ((offset = last - SF_BUFSIZE) < first) + offset = first; sfseek(fp, offset, SEEK_SET); n = last - offset; if (!(s = sfreserve(fp, n, SF_LOCKR))) @@ -178,8 +188,6 @@ tailpos(register Sfio_t* fp, register Sfoff_t number, int delim) if (offset == first) break; last = offset; - if ((offset = last - SF_BUFSIZE) < first) - offset = first; } return first; } @@ -245,11 +253,13 @@ pipetail(Sfio_t* infile, Sfio_t* outfile, Sfoff_t number, int delim) */ static int -init(Tail_t* tp, Sfoff_t number, int delim, int flags) +init(Tail_t* tp, Sfoff_t number, int delim, int flags, const char** format) { Sfoff_t offset; + Sfio_t* op; struct stat st; + tp->fifo = 0; if (tp->sp) { offset = 0; @@ -273,12 +283,46 @@ init(Tail_t* tp, Sfoff_t number, int delim, int flags) sfset(tp->sp, SF_SHARE, 0); if (offset) { - if ((offset = tailpos(tp->sp, number, delim)) < 0) + if (number < 0 || !number && (flags & POSITIVE)) + { + sfset(tp->sp, SF_SHARE, !(flags & FOLLOW)); + if (number < -1) + { + sfmove(tp->sp, NiL, -number - 1, delim); + offset = sfseek(tp->sp, (Sfoff_t)0, SEEK_CUR); + } + else + offset = 0; + } + else if ((offset = tailpos(tp->sp, number, delim)) >= 0) + sfseek(tp->sp, offset, SEEK_SET); + else if (fstat(sffileno(tp->sp), &st)) + { + error(ERROR_system(0), "%s: cannot stat", tp->name); + goto bad; + } + else if (!FIFO(st.st_mode)) { error(ERROR_SYSTEM|2, "%s: cannot position file to tail", tp->name); goto bad; } - sfseek(tp->sp, offset, SEEK_SET); + else + { + tp->fifo = 1; + if (flags & (HEADERS|VERBOSE)) + { + sfprintf(sfstdout, *format, tp->name); + *format = header_fmt; + } + op = (flags & REVERSE) ? sftmp(4*SF_BUFSIZE) : sfstdout; + pipetail(tp->sp ? tp->sp : sfstdin, op, number, delim); + if (flags & REVERSE) + { + sfseek(op, (Sfoff_t)0, SEEK_SET); + rev_line(op, sfstdout, (Sfoff_t)0); + sfclose(op); + } + } } tp->last = offset; if (flags & LOG) @@ -325,10 +369,8 @@ num(register const char* s, char** e, int* f, int o) s++; errno = 0; number = strtonll(s, &t, NiL, 0); - if (!o && t > s && *(t - 1) == 'l') - t--; if (t == s) - number = LINES; + number = DEFAULT; if (o && *t) { number = 0; @@ -346,6 +388,8 @@ num(register const char* s, char** e, int* f, int o) else { *f |= COUNT; + if (t > s && isalpha(*(t - 1))) + *f &= ~LINES; if (c == '-') number = -number; } @@ -357,24 +401,23 @@ num(register const char* s, char** e, int* f, int o) int b_tail(int argc, char** argv, void* context) { - static const char header_fmt[] = "\n==> %s <==\n"; - register Sfio_t* ip; register int n; register int i; - register int delim = '\n'; - int flags = HEADERS; + int delim; + int flags = HEADERS|LINES; + int blocks = 0; char* s; char* t; char* r; char* e; char* file; Sfoff_t offset; - Sfoff_t number = LINES; + Sfoff_t number = DEFAULT; unsigned long timeout = 0; struct stat st; const char* format = header_fmt+1; - size_t z; + ssize_t z; Sfio_t* op; register Tail_t* fp; register Tail_t* pp; @@ -386,13 +429,38 @@ b_tail(int argc, char** argv, void* context) { switch (n = optget(argv, usage)) { - case 'c': - delim = -1; - if (opt_info.arg && *opt_info.arg=='f' && !*(opt_info.arg+1)) + case 0: + if (!(flags & FOLLOW) && argv[opt_info.index] && (argv[opt_info.index][0] == '-' || argv[opt_info.index][0] == '+') && !argv[opt_info.index][1]) { - flags |= FOLLOW; + number = argv[opt_info.index][0] == '-' ? 10 : -10; + flags |= LINES; + opt_info.index++; continue; } + break; + case 'b': + blocks = 512; + flags &= ~LINES; + if (opt_info.option[0] == '+') + number = -number; + continue; + case 'c': + flags &= ~LINES; + if (opt_info.arg == argv[opt_info.index - 1]) + { + strtol(opt_info.arg, &s, 10); + if (*s) + { + opt_info.index--; + t = ""; + goto suffix; + } + } + else if (opt_info.arg && isalpha(*opt_info.arg)) + { + t = opt_info.arg; + goto suffix; + } /*FALLTHROUGH*/ case 'n': flags |= COUNT; @@ -400,14 +468,14 @@ b_tail(int argc, char** argv, void* context) number = num(s, &s, &flags, n); else { - number = LINES; + number = DEFAULT; flags &= ~(ERROR|NEGATIVE|POSITIVE); s = ""; } - if (n=='c' && *s=='f') + if (n != 'n' && s && isalpha(*s)) { - s++; - flags |= FOLLOW; + t = s; + goto suffix; } if (flags & ERROR) continue; @@ -425,6 +493,11 @@ b_tail(int argc, char** argv, void* context) else flags &= ~HEADERS; continue; + case 'l': + flags |= LINES; + if (opt_info.option[0] == '+') + number = -number; + continue; case 'L': flags |= LOG; continue; @@ -448,32 +521,46 @@ b_tail(int argc, char** argv, void* context) continue; case ':': /* handle old style arguments */ - r = s = argv[opt_info.index]; - number = num(s, &t, &flags, 0); + if (!(r = argv[opt_info.index]) || !opt_info.offset) + { + error(2, "%s", opt_info.arg); + break; + } + s = r + opt_info.offset - 1; + if (i = *(s - 1) == '-' || *(s - 1) == '+') + s--; + if ((number = num(s, &t, &flags, 0)) && i) + number = -number; + goto compatibility; + suffix: + r = 0; + if (opt_info.option[0] == '+') + number = -number; + compatibility: for (;;) { switch (*t++) { case 0: - opt_info.offset = t - r - 1; - if (number) - number = -number; + if (r) + opt_info.offset = t - r - 1; break; case 'c': - delim = -1; + flags &= ~LINES; continue; case 'f': flags |= FOLLOW; continue; case 'l': - delim = '\n'; + flags |= LINES; continue; case 'r': flags |= REVERSE; continue; default: error(2, "%s: invalid suffix", t - 1); - opt_info.offset = strlen(r); + if (r) + opt_info.offset = strlen(r); break; } break; @@ -496,12 +583,15 @@ b_tail(int argc, char** argv, void* context) } else if (!*(argv + 1)) flags &= ~HEADERS; + delim = (flags & LINES) ? '\n' : -1; + if (blocks) + number *= blocks; if (flags & REVERSE) { if (delim < 0) error(2, "--reverse requires line mode"); - else if (!(flags & COUNT)) - number = 0; + if (!(flags & COUNT)) + number = -1; flags &= ~FOLLOW; } if ((flags & (FOLLOW|TIMEOUT)) == TIMEOUT) @@ -527,7 +617,7 @@ b_tail(int argc, char** argv, void* context) { fp->name = s; fp->sp = 0; - if (!init(fp, number, delim, flags)) + if (!init(fp, number, delim, flags, &format)) { fp->expire = timeout ? (NOW + timeout + 1) : 0; if (files) @@ -542,27 +632,35 @@ b_tail(int argc, char** argv, void* context) return error_info.errors != 0; pp->next = 0; hp = 0; - for (;;) + while (fp = files) { if (sfsync(sfstdout)) error(ERROR_system(1), "write error"); +#if 0 sleep(1); +#else + { + struct timespec rqt = { 0L, 1000000000L/4L }; + (void)nanosleep(&rqt, NULL); + } +#endif n = 0; pp = 0; - fp = files; while (fp) { if (fstat(sffileno(fp->sp), &st)) error(ERROR_system(0), "%s: cannot stat", fp->name); - else if (st.st_size > fp->last) + else if (st.st_size > fp->last || fp->fifo) { n = 1; if (timeout) fp->expire = NOW + timeout; - z = st.st_size - fp->last; + z = fp->fifo ? SF_UNBOUND : st.st_size - fp->last; i = 0; if ((s = sfreserve(fp->sp, z, SF_LOCKR)) || (z = sfvalue(fp->sp)) && (s = sfreserve(fp->sp, z, SF_LOCKR)) && (i = 1)) { + if (fp->fifo) + z = sfvalue(fp->sp); r = 0; for (e = (t = s) + z; t < e; t++) if (*t == '\n') @@ -594,7 +692,7 @@ b_tail(int argc, char** argv, void* context) i = 3; while (--i && stat(fp->name, &st)) sleep(1); - if (i && (fp->dev != st.st_dev || fp->ino != st.st_ino) && !init(fp, 0, 0, flags)) + if (i && (fp->dev != st.st_dev || fp->ino != st.st_ino) && !init(fp, 0, 0, flags, &format)) { if (!(flags & SILENT)) error(ERROR_warn(0), "%s: log file change", fp->name); @@ -636,11 +734,13 @@ b_tail(int argc, char** argv, void* context) continue; } if (flags & (HEADERS|VERBOSE)) + { sfprintf(sfstdout, format, file); - format = header_fmt; + format = header_fmt; + } if (number < 0 || !number && (flags & POSITIVE)) { - sfset(ip, SF_SHARE, !(flags & FOLLOW)); + sfset(ip, SF_SHARE, 1); if (number < -1) sfmove(ip, NiL, -number - 1, delim); if (flags & REVERSE) diff --git a/usr/src/lib/libcmd/common/tee.c b/usr/src/lib/libcmd/common/tee.c index c1189bade7..246b5af9c3 100644 --- a/usr/src/lib/libcmd/common/tee.c +++ b/usr/src/lib/libcmd/common/tee.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -27,7 +27,7 @@ */ static const char usage[] = -"[-?\n@(#)$Id: tee (AT&T Research) 2007-11-11 $\n]" +"[-?\n@(#)$Id: tee (AT&T Research) 2009-06-19 $\n]" USAGE_LICENSE "[+NAME?tee - duplicate standard input]" "[+DESCRIPTION?\btee\b copies standard input to standard output " @@ -52,7 +52,6 @@ USAGE_LICENSE "[+SEE ALSO?\bcat\b(1), \bsignal\b(3)]" ; - #include <cmd.h> #include <ls.h> #include <sig.h> @@ -60,6 +59,7 @@ USAGE_LICENSE typedef struct Tee_s { Sfdisc_t disc; + int line; int fd[1]; } Tee_t; @@ -67,7 +67,8 @@ typedef struct Tee_s * This discipline writes to each file in the list given in handle */ -static ssize_t tee_write(Sfio_t* fp, const void* buf, size_t n, Sfdisc_t* handle) +static ssize_t +tee_write(Sfio_t* fp, const void* buf, size_t n, Sfdisc_t* handle) { register const char* bp; register const char* ep; @@ -82,11 +83,27 @@ static ssize_t tee_write(Sfio_t* fp, const void* buf, size_t n, Sfdisc_t* handle while (bp < ep) { if ((r = write(fd, bp, ep - bp)) <= 0) - return(-1); + return -1; bp += r; } } while ((fd = *hp++) >= 0); - return(n); + return n; +} + +static void +tee_cleanup(register Tee_t* tp) +{ + register int* hp; + register int n; + + if (tp) + { + sfdisc(sfstdout, NiL); + if (tp->line >= 0) + sfset(sfstdout, SF_LINE, tp->line); + for (hp = tp->fd; (n = *hp) >= 0; hp++) + close(n); + } } int @@ -100,32 +117,45 @@ b_tee(int argc, register char** argv, void* context) int line; Sfdisc_t tee_disc; - cmdinit(argc, argv, context, ERROR_CATALOG, 0); + if (argc <= 0) + { + if (context && (tp = (Tee_t*)sh_context(context)->data)) + { + sh_context(context)->data = 0; + tee_cleanup(tp); + } + return 0; + } + cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_CALLBACK); line = -1; - while (n = optget(argv, usage)) switch (n) + for (;;) { - case 'a': - oflag &= ~O_TRUNC; - oflag |= O_APPEND; - break; - case 'i': - signal(SIGINT, SIG_IGN); - break; - case 'l': - line = sfset(sfstdout, 0, 0) & SF_LINE; - if ((line == 0) == (opt_info.num == 0)) - line = -1; - else - sfset(sfstdout, SF_LINE, !!opt_info.num); - break; - case ':': - error(2, "%s", opt_info.arg); - break; - case '?': - error(ERROR_usage(2), "%s", opt_info.arg); + switch (optget(argv, usage)) + { + case 'a': + oflag &= ~O_TRUNC; + oflag |= O_APPEND; + continue; + case 'i': + signal(SIGINT, SIG_IGN); + continue; + case 'l': + line = sfset(sfstdout, 0, 0) & SF_LINE; + if ((line == 0) == (opt_info.num == 0)) + line = -1; + else + sfset(sfstdout, SF_LINE, !!opt_info.num); + continue; + case ':': + error(2, "%s", opt_info.arg); + break; + case '?': + error(ERROR_usage(2), "%s", opt_info.arg); + break; + } break; } - if(error_info.errors) + if (error_info.errors) error(ERROR_usage(2), "%s", optusage(NiL)); argv += opt_info.index; argc -= opt_info.index; @@ -139,40 +169,36 @@ b_tee(int argc, register char** argv, void* context) #endif if (argc > 0) { - if (!(tp = (Tee_t*)stakalloc(sizeof(Tee_t) + argc * sizeof(int)))) - error(ERROR_exit(1), "no space"); - memset(&tee_disc, 0, sizeof(tee_disc)); - tee_disc.writef = tee_write; - tp->disc = tee_disc; - hp = tp->fd; - while (cp = *argv++) + if (tp = (Tee_t*)stakalloc(sizeof(Tee_t) + argc * sizeof(int))) { - if ((*hp = open(cp, oflag, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) - error(ERROR_system(0), "%s: cannot create", cp); - else hp++; + memset(&tp->disc, 0, sizeof(tp->disc)); + tp->disc.writef = tee_write; + if (context) + sh_context(context)->data = (void*)tp; + tp->line = line; + hp = tp->fd; + while (cp = *argv++) + { + if ((*hp = open(cp, oflag, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) + error(ERROR_system(0), "%s: cannot create", cp); + else + hp++; + } + if (hp == tp->fd) + tp = 0; + else + { + *hp = -1; + sfdisc(sfstdout, &tp->disc); + } } - if (hp == tp->fd) - tp = 0; else - { - *hp = -1; - sfdisc(sfstdout, &tp->disc); - } - } - if (sfmove(sfstdin, sfstdout, SF_UNBOUND, -1) < 0 || !sfeof(sfstdin) || sfsync(sfstdout)) - error(ERROR_system(1), "cannot copy"); - - /* - * close files and free resources - */ - - if (tp) - { - sfdisc(sfstdout, NiL); - if (line >= 0) - sfset(sfstdout, SF_LINE, line); - for(hp = tp->fd; (n = *hp) >= 0; hp++) - close(n); + error(ERROR_exit(0), "out of space"); } - return(error_info.errors); + if ((sfmove(sfstdin, sfstdout, SF_UNBOUND, -1) < 0 || !sfeof(sfstdin)) && errno != EPIPE) + error(ERROR_system(0), "read error"); + if (sfsync(sfstdout)) + error(ERROR_system(0), "write error"); + tee_cleanup(tp); + return error_info.errors; } diff --git a/usr/src/lib/libcmd/common/tty.c b/usr/src/lib/libcmd/common/tty.c index 4db11b9185..b257290e50 100644 --- a/usr/src/lib/libcmd/common/tty.c +++ b/usr/src/lib/libcmd/common/tty.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * diff --git a/usr/src/lib/libcmd/common/uname.c b/usr/src/lib/libcmd/common/uname.c index 72605200be..74cbd39ebe 100644 --- a/usr/src/lib/libcmd/common/uname.c +++ b/usr/src/lib/libcmd/common/uname.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -104,7 +104,7 @@ __STDPP__directive pragma pp:nohide getdomainname gethostid gethostname sethostn extern int getdomainname(char*, size_t); #endif #if _lib_gethostid -extern int gethostid(void); +extern long gethostid(void); #endif #if _lib_gethostname extern int gethostname(char*, size_t); diff --git a/usr/src/lib/libcmd/common/uniq.c b/usr/src/lib/libcmd/common/uniq.c index d49954a710..bf87a2a15a 100644 --- a/usr/src/lib/libcmd/common/uniq.c +++ b/usr/src/lib/libcmd/common/uniq.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -26,17 +26,17 @@ */ static const char usage[] = -"[-n?\n@(#)$Id: uniq (AT&T Research) 2008-04-24 $\n]" +"[-n?\n@(#)$Id: uniq (AT&T Research) 2009-08-10 $\n]" USAGE_LICENSE "[+NAME?uniq - Report or filter out repeated lines in a file]" -"[+DESCRIPTION?\buniq\b reads an input, comparing adjacent lines, and " - "writing one copy of each input line on the output. The second " +"[+DESCRIPTION?\buniq\b reads the input, compares adjacent lines, and " + "writes one copy of each input line on the output. The second " "and succeeding copies of the repeated adjacent lines are not " "written.]" "[+?If the output file, \aoutfile\a, is not specified, \buniq\b writes " "to standard output. If no \ainfile\a is given, or if the \ainfile\a " - "is \b-\b, \buniq\b reads from standard input with the start of " - "the file is defined as the current offset.]" + "is \b-\b, \buniq\b reads from standard input with the start of " + "the file defined as the current offset.]" "[c:count?Output the number of times each line occurred along with " "the line.]" "[d:repeated|duplicates?Output the first of each duplicate line.]" @@ -49,13 +49,15 @@ USAGE_LICENSE "}" "[f:skip-fields]#[fields?\afields\a is the number of fields to skip over " "before checking for uniqueness. A field is the minimal string matching " - "the BRE \b[[:blank:]]]]*[^[:blank:]]]]*\b.]" + "the BRE \b[[:blank:]]]]*[^[:blank:]]]]*\b. -\anumber\a is equivalent to " + "\b--skip-fields\b=\anumber\a.]" "[i:ignore-case?Ignore case in comparisons.]" "[s:skip-chars]#[chars?\achars\a is the number of characters to skip over " "before checking for uniqueness. If specified along with \b-f\b, " "the first \achars\a after the first \afields\a are ignored. If " "the \achars\a specifies more characters than are on the line, " - "an empty string will be used for comparison.]" + "an empty string will be used for comparison. +\anumber\a is " + "equivalent to \b--skip-chars\b=\anumber\a.]" "[u:unique?Output unique lines.]" "[w:check-chars]#[chars?\achars\a is the number of characters to compare " "after skipping any specified fields and characters.]" @@ -145,11 +147,25 @@ static int uniq(Sfio_t *fdin, Sfio_t *fdout, int fields, int chars, int width, i { if(cwidth) { - outp[CWIDTH] = ' '; - if(count<MAXCNT) + if(count<9) { - sfsprintf(outp,cwidth,"%*d",CWIDTH,count+1); - outp[CWIDTH] = ' '; + f = 0; + while(f < CWIDTH-1) + outp[f++] = ' '; + outp[f++] = '0' + count + 1; + outp[f] = ' '; + } + else if(count<MAXCNT) + { + count++; + f = CWIDTH; + outp[f--] = ' '; + do + { + outp[f--] = '0' + (count % 10); + } while (count /= 10); + while (f >= 0) + outp[f--] = ' '; } else { diff --git a/usr/src/lib/libcmd/common/wc.c b/usr/src/lib/libcmd/common/wc.c index 763090fc02..4203fffd3a 100644 --- a/usr/src/lib/libcmd/common/wc.c +++ b/usr/src/lib/libcmd/common/wc.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -27,7 +27,7 @@ */ static const char usage[] = -"[-?\n@(#)$Id: wc (AT&T Research) 2006-08-25 $\n]" +"[-?\n@(#)$Id: wc (AT&T Research) 2000-08-11 $\n]" USAGE_LICENSE "[+NAME?wc - print the number of bytes, words, and lines in files]" "[+DESCRIPTION?\bwc\b reads one or more input files and, by default, " @@ -50,7 +50,10 @@ USAGE_LICENSE "[c:bytes|chars:chars?List the byte counts.]" "[m|C:multibyte-chars?List the character counts.]" "[q:quiet?Suppress invalid multibyte character warnings.]" -"[L:longest-line|max-line-length?List the longest line length.]" +"[L:longest-line|max-line-length?List the longest line length; the newline," + "if any, is not counted in the length.]" +"[N!:utf8?For \bUTF-8\b locales \b--noutf8\b disables \bUTF-8\b " + "optimzations and relies on the native \bmbtowc\b(3).]" "\n" "\n[file ...]\n" "\n" @@ -70,15 +73,15 @@ USAGE_LICENSE static void printout(register Wc_t *wp, register char *name,register int mode) { - if(mode&WC_LINES) + if (mode&WC_LINES) sfprintf(sfstdout," %7I*d",sizeof(wp->lines),wp->lines); - if(mode&WC_WORDS) + if (mode&WC_WORDS) sfprintf(sfstdout," %7I*d",sizeof(wp->words),wp->words); - if(mode&WC_CHARS) + if (mode&WC_CHARS) sfprintf(sfstdout," %7I*d",sizeof(wp->chars),wp->chars); - if(mode&WC_LONGEST) + if (mode&WC_LONGEST) sfprintf(sfstdout," %7I*d",sizeof(wp->chars),wp->longest); - if(name) + if (name) sfprintf(sfstdout," %s",name); sfputc(sfstdout,'\n'); } @@ -94,71 +97,72 @@ b_wc(int argc,register char **argv, void* context) struct stat statb; cmdinit(argc, argv, context, ERROR_CATALOG, 0); - while (n = optget(argv,usage)) switch (n) + for (;;) { - case 'c': - mode |= WC_CHARS; - break; - case 'l': - mode |= WC_LINES; - break; - case 'L': - mode |= WC_LONGEST; - break; - case 'm': - case 'C': - mode |= WC_MBYTE; - break; - case 'q': - mode |= WC_QUIET; - break; - case 'w': - mode |= WC_WORDS; - break; - case ':': - error(2, "%s", opt_info.arg); - break; - case '?': - error(ERROR_usage(2), "%s", opt_info.arg); + switch (optget(argv, usage)) + { + case 'c': + mode |= WC_CHARS; + continue; + case 'l': + mode |= WC_LINES; + continue; + case 'L': + mode |= WC_LONGEST; + continue; + case 'N': + if (!opt_info.num) + mode |= WC_NOUTF8; + continue; + case 'm': + case 'C': + mode |= WC_MBYTE; + continue; + case 'q': + mode |= WC_QUIET; + continue; + case 'w': + mode |= WC_WORDS; + continue; + case ':': + error(2, "%s", opt_info.arg); + break; + case '?': + error(ERROR_usage(2), "%s", opt_info.arg); + break; + } break; } argv += opt_info.index; if (error_info.errors) error(ERROR_usage(2), "%s", optusage(NiL)); - if(mode&WC_MBYTE) + if (mode&WC_MBYTE) { - if(mode&WC_CHARS) + if (mode&WC_CHARS) error(2, "-c and -C are mutually exclusive"); - mode |= WC_CHARS; - if(!mbwide()) - { + if (!mbwide()) mode &= ~WC_MBYTE; - setlocale(LC_CTYPE, "C"); - } + mode |= WC_CHARS; } - if(!(mode&(WC_WORDS|WC_CHARS|WC_LINES|WC_MBYTE|WC_LONGEST))) + if (!(mode&(WC_WORDS|WC_CHARS|WC_LINES|WC_MBYTE|WC_LONGEST))) mode |= (WC_WORDS|WC_CHARS|WC_LINES); - if(!(wp = wc_init(mode))) + if (!(wp = wc_init(mode))) error(3,"internal error"); - if(!(mode&WC_WORDS)) - { - memzero(wp->space, (1<<CHAR_BIT)); - wp->space['\n'] = -1; - } - if(cp = *argv) + if (cp = *argv) argv++; + n = 0; do { - if(!cp || streq(cp,"-")) + if (!cp || streq(cp,"-")) fp = sfstdin; - else if(!(fp = sfopen(NiL,cp,"r"))) + else if (!(fp = sfopen(NiL,cp,"r"))) { error(ERROR_system(0),"%s: cannot open",cp); continue; } - if(cp) + if (cp) n++; - if(!(mode&(WC_WORDS|WC_LINES|WC_MBYTE|WC_LONGEST)) && fstat(sffileno(fp),&statb)>=0 + if (!(mode&(WC_WORDS|WC_LINES|WC_MBYTE|WC_LONGEST)) && fstat(sffileno(fp),&statb)>=0 && S_ISREG(statb.st_mode)) { wp->chars = statb.st_size - lseek(sffileno(fp),0L,1); @@ -166,21 +170,19 @@ b_wc(int argc,register char **argv, void* context) } else wc_count(wp, fp, cp); - if(fp!=sfstdin) + if (fp!=sfstdin) sfclose(fp); tchars += wp->chars; twords += wp->words; tlines += wp->lines; printout(wp,cp,mode); - } - while(cp= *argv++); - if(n>1) + } while (cp= *argv++); + if (n > 1) { wp->lines = tlines; wp->chars = tchars; wp->words = twords; printout(wp,"total",mode); } - return(error_info.errors<ERRORMAX?error_info.errors:ERRORMAX); + return error_info.errors<ERRORMAX?error_info.errors:ERRORMAX; } - diff --git a/usr/src/lib/libcmd/common/wc.h b/usr/src/lib/libcmd/common/wc.h index 2752af36a3..e23a1ec2c4 100644 --- a/usr/src/lib/libcmd/common/wc.h +++ b/usr/src/lib/libcmd/common/wc.h @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -37,15 +37,17 @@ #define WC_MBYTE 0x08 #define WC_LONGEST 0x10 #define WC_QUIET 0x20 +#define WC_NOUTF8 0x40 typedef struct { - signed char space[1<<CHAR_BIT]; + char type[1<<CHAR_BIT]; Sfoff_t words; Sfoff_t lines; Sfoff_t chars; Sfoff_t longest; int mode; + int mb; } Wc_t; #define wc_count _cmd_wccount diff --git a/usr/src/lib/libcmd/common/wclib.c b/usr/src/lib/libcmd/common/wclib.c index 67adb5fe15..c7ce5a338a 100644 --- a/usr/src/lib/libcmd/common/wclib.c +++ b/usr/src/lib/libcmd/common/wclib.c @@ -1,7 +1,7 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1992-2008 AT&T Intellectual Property * +* Copyright (c) 1992-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * @@ -34,6 +34,7 @@ #include <wchar.h> #include <wctype.h> +#include <lc.h> #else @@ -43,80 +44,197 @@ #endif -#define endline(c) (((signed char)-1)<0?(c)<0:(c)==((char)-1)) -#define mbok(p,n) (((n)<1)?0:mbwide()?((*ast.mb_towc)(NiL,(char*)(p),n)>=0):1) +#define WC_SP 0x08 +#define WC_NL 0x10 +#define WC_MB 0x20 +#define WC_ERR 0x40 -Wc_t *wc_init(int mode) +#define eol(c) ((c)&WC_NL) +#define mbc(c) ((c)&WC_MB) +#define spc(c) ((c)&WC_SP) +#define mbwc(w,p,n) (*ast.mb_towc)(&w,(char*)p,n) + +Wc_t* wc_init(int mode) { register int n; register int w; Wc_t* wp; - if(!(wp = (Wc_t*)stakalloc(sizeof(Wc_t)))) - return(0); - wp->mode = mode; + if (!(wp = (Wc_t*)stakalloc(sizeof(Wc_t)))) + return 0; + if (!mbwide()) + wp->mb = 0; +#if _hdr_wchar && _hdr_wctype && _lib_iswctype + else if (!(mode & WC_NOUTF8) && (lcinfo(LC_CTYPE)->lc->flags & LC_utf8)) + wp->mb = 1; +#endif + else + wp->mb = -1; w = mode & WC_WORDS; - for(n=(1<<CHAR_BIT);--n >=0;) - wp->space[n] = w ? !!isspace(n) : 0; - wp->space['\n'] = -1; - return(wp); + for (n = (1<<CHAR_BIT); --n >= 0;) + wp->type[n] = (w && isspace(n)) ? WC_SP : 0; + wp->type['\n'] = WC_SP|WC_NL; + if ((mode & (WC_MBYTE|WC_WORDS)) && wp->mb > 0) + { + for (n = 0; n < 64; n++) + { + wp->type[0x80+n] |= WC_MB; + if (n<32) + wp->type[0xc0+n] |= WC_MB+1; + else if (n<48) + wp->type[0xc0+n] |= WC_MB+2; + else if (n<56) + wp->type[0xc0+n] |= WC_MB+3; + else if (n<60) + wp->type[0xc0+n] |= WC_MB+4; + else if (n<62) + wp->type[0xc0+n] |= WC_MB+5; + } + wp->type[0xc0] = WC_MB|WC_ERR; + wp->type[0xc1] = WC_MB|WC_ERR; + wp->type[0xfe] = WC_MB|WC_ERR; + wp->type[0xff] = WC_MB|WC_ERR; + } + wp->mode = mode; + return wp; +} + +static int invalid(const char *file, int nlines) +{ + error_info.file = (char*)file; + error_info.line = nlines; + error(ERROR_SYSTEM|1, "invalid multibyte character"); + error_info.file = 0; + error_info.line = 0; + return nlines; +} + +/* + * handle utf space characters + */ + +static int chkstate(int state, register unsigned int c) +{ + switch(state) + { + case 1: + state = (c==0x9a?4:0); + break; + case 2: + state = ((c==0x80||c==0x81)?6+(c&1):0); + break; + case 3: + state = (c==0x80?5:0); + break; + case 4: + state = (c==0x80?10:0); + break; + case 5: + state = (c==0x80?10:0); + break; + case 6: + state = 0; + if(c==0xa0 || c==0xa1) + return(10); + else if((c&0xf0)== 0x80) + { + if((c&=0xf)==7) + return(iswspace(0x2007)?10:0); + if(c<=0xb) + return(10); + } + else if(c==0xaf && iswspace(0x202f)) + return(10); + break; + case 7: + state = (c==0x9f?10:0); + break; + case 8: + return (iswspace(c)?10:0); + } + return state; } /* * compute the line, word, and character count for file <fd> */ + int wc_count(Wc_t *wp, Sfio_t *fd, const char* file) { - register signed char *space = wp->space; - register unsigned char *cp; + register char* type = wp->type; + register unsigned char* cp; register Sfoff_t nchars; register Sfoff_t nwords; register Sfoff_t nlines; - register Sfoff_t eline; - register Sfoff_t longest; + register Sfoff_t eline = -1; + register Sfoff_t longest = 0; register ssize_t c; - register unsigned char *endbuff; - register int lasttype = 1; + register unsigned char* endbuff; + register int lasttype = WC_SP; unsigned int lastchar; - unsigned char *buff; + ssize_t n; + ssize_t o; + unsigned char* buff; wchar_t x; + unsigned char side[32]; sfset(fd,SF_WRITE,1); nlines = nwords = nchars = 0; wp->longest = 0; - if (wp->mode & (WC_LONGEST|WC_MBYTE)) + if (wp->mb < 0 && (wp->mode & (WC_MBYTE|WC_WORDS))) { - longest = 0; - eline = -1; cp = buff = endbuff = 0; for (;;) { - if (!mbok(cp, endbuff-cp)) - { - if (buff) - sfread(fd, buff, cp-buff); - if (!(buff = (unsigned char*)sfreserve(fd, SF_UNBOUND, SF_LOCKR))) - break; - endbuff = (cp = buff) + sfvalue(fd); - } - nchars++; - x = mbchar(cp); - if (x == -1) + if (cp >= endbuff || (n = mbwc(x, cp, endbuff-cp)) < 0) { - if (eline != nlines && !(wp->mode & WC_QUIET)) + if ((o = endbuff-cp) < sizeof(side)) + { + if (buff) + { + if (o) + memcpy(side, cp, o); + mbinit(); + } + else + o = 0; + cp = side + o; + if (!(buff = (unsigned char*)sfreserve(fd, SF_UNBOUND, 0)) || (n = sfvalue(fd)) <= 0) + { + if ((nchars - longest) > wp->longest) + wp->longest = nchars - longest; + break; + } + if ((c = sizeof(side) - o) > n) + c = n; + if (c) + memcpy(cp, buff, c); + endbuff = buff + n; + cp = side; + x = mbchar(cp); + if ((cp-side) < o) + { + cp = buff; + nchars += (cp-side) - 1; + } + else + cp = buff + (cp-side) - o; + } + else { - error_info.file = (char*)file; - error_info.line = eline = nlines; - error(ERROR_SYSTEM|1, "invalid multibyte character"); - error_info.file = 0; - error_info.line = 0; + cp++; + x = -1; } + if (x == -1 && eline != nlines && !(wp->mode & WC_QUIET)) + eline = invalid(file, nlines); } - else if (x == '\n') + else + cp += n ? n : 1; + if (x == '\n') { if ((nchars - longest) > wp->longest) wp->longest = nchars - longest; - longest = nchars; + longest = nchars + 1; nlines++; lasttype = 1; } @@ -127,71 +245,253 @@ int wc_count(Wc_t *wp, Sfio_t *fd, const char* file) lasttype = 0; nwords++; } + nchars++; + } + } + else if (!wp->mb && !(wp->mode & WC_LONGEST) || wp->mb > 0 && !(wp->mode & (WC_MBYTE|WC_WORDS|WC_LONGEST))) + { + if (!(wp->mode & (WC_MBYTE|WC_WORDS|WC_LONGEST))) + { + while ((cp = (unsigned char*)sfreserve(fd, SF_UNBOUND, 0)) && (c = sfvalue(fd)) > 0) + { + nchars += c; + endbuff = cp + c; + if (*--endbuff == '\n') + nlines++; + else + *endbuff = '\n'; + for (;;) + if (*cp++ == '\n') + { + if (cp > endbuff) + break; + nlines++; + } + } + } + else + { + while ((cp = buff = (unsigned char*)sfreserve(fd, SF_UNBOUND, 0)) && (c = sfvalue(fd)) > 0) + { + nchars += c; + /* check to see whether first character terminates word */ + if (c==1) + { + if (eol(lasttype)) + nlines++; + if ((c = type[*cp]) && !lasttype) + nwords++; + lasttype = c; + continue; + } + if (!lasttype && type[*cp]) + nwords++; + lastchar = cp[--c]; + *(endbuff = cp+c) = '\n'; + c = lasttype; + /* process each buffer */ + for (;;) + { + /* process spaces and new-lines */ + do + { + if (eol(c)) + for (;;) + { + /* check for end of buffer */ + if (cp > endbuff) + goto beob; + nlines++; + if (*cp != '\n') + break; + cp++; + } + } while (c = type[*cp++]); + /* skip over word characters */ + while (!(c = type[*cp++])); + nwords++; + } + beob: + if ((cp -= 2) >= buff) + c = type[*cp]; + else + c = lasttype; + lasttype = type[lastchar]; + /* see if was in word */ + if (!c && !lasttype) + nwords--; + } + if (eol(lasttype)) + nlines++; + else if (!lasttype) + nwords++; } } else { - for (;;) + int lineoff=0; + int skip=0; + int adjust=0; + int state=0; + int oldc; + int xspace; + int wasspace = 1; + unsigned char* start; + + lastchar = 0; + start = (endbuff = side) + 1; + xspace = iswspace(0xa0) || iswspace(0x85); + while ((cp = buff = (unsigned char*)sfreserve(fd, SF_UNBOUND, 0)) && (c = sfvalue(fd)) > 0) { - /* fill next buffer and check for end-of-file */ - if (!(buff = (unsigned char*)sfreserve(fd, 0, 0)) || (c = sfvalue(fd)) <= 0) - break; - sfread(fd,(char*)(cp=buff),c); nchars += c; + start = cp-lineoff; /* check to see whether first character terminates word */ if(c==1) { - if(endline(lasttype)) + if(eol(lasttype)) nlines++; - if((c = space[*cp]) && !lasttype) + if((c = type[*cp]) && !lasttype) nwords++; lasttype = c; + endbuff = start; continue; } - if(!lasttype && space[*cp]) - nwords++; lastchar = cp[--c]; - cp[c] = '\n'; endbuff = cp+c; + cp[c] = '\n'; + if(mbc(lasttype)) + { + c = lasttype; + goto mbyte; + } + if(!lasttype && spc(type[*cp])) + nwords++; c = lasttype; /* process each buffer */ for (;;) { /* process spaces and new-lines */ - do if (endline(c)) + spaces: + do { - for (;;) + if (eol(c)) { /* check for end of buffer */ if (cp > endbuff) goto eob; + if(wp->mode&WC_LONGEST) + { + if((cp-start)-adjust > longest) + longest = (cp-start)-adjust-1; + start = cp; + } nlines++; - if (*cp != '\n') + nchars -= adjust; + adjust = 0; + } + } while (spc(c = type[*cp++])); + wasspace=1; + if(mbc(c)) + { + mbyte: + do + { + if(c&WC_ERR) + goto err; + if(skip && (c&7)) break; - cp++; + if(!skip) + { + if(!(c&7)) + { + skip=1; + break; + } + skip = (c&7); + adjust += skip; + state = 0; + if(skip==2 && (cp[-1]&0xc)==0 && (state=(cp[-1]&0x3))) + oldc = *cp; + else if(xspace && cp[-1]==0xc2) + { + state = 8; + oldc = *cp; + } + } + else + { + skip--; + if(state && (state=chkstate(state,oldc))) + { + if(state==10) + { + if(!wasspace) + nwords++; + wasspace = 1; + state=0; + goto spaces; + } + oldc = *cp; + } + } + } while (mbc(c = type[*cp++])); + wasspace = 0; + if(skip) + { + if(eol(c) && (cp > endbuff)) + goto eob; + err: + skip = 0; + state = 0; + if(eline!=nlines && !(wp->mode & WC_QUIET)) + eline = invalid(file, nlines); + while(mbc(c) && ((c|WC_ERR) || (c&7)==0)) + c=type[*cp++]; + if(eol(c) && (cp > endbuff)) + { + c = WC_MB|WC_ERR; + goto eob; + } + if(mbc(c)) + goto mbyte; + else if(c&WC_SP) + goto spaces; + } + if(spc(c)) + { + nwords++; + continue; } - } while (c = space[*cp++]); + } /* skip over word characters */ - while(!(c = space[*cp++])); + while(!(c = type[*cp++])); + if(mbc(c)) + goto mbyte; nwords++; } eob: + lineoff = cp-start; if((cp -= 2) >= buff) - c = space[*cp]; + c = type[*cp]; else - c = lasttype; - lasttype = space[lastchar]; + c = lasttype; + lasttype = type[lastchar]; /* see if was in word */ if(!c && !lasttype) nwords--; } - if(endline(lasttype)) + if ((wp->mode&WC_LONGEST) && ((endbuff + 1 - start) - adjust - (lastchar == '\n')) > longest) + longest = (endbuff + 1 - start) - adjust - (lastchar == '\n'); + wp->longest = longest; + if (eol(lasttype)) nlines++; - else if(!lasttype) + else if (!lasttype) nwords++; + nchars -= adjust; } wp->chars = nchars; wp->words = nwords; wp->lines = nlines; - return(0); + return 0; } + |