diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | Doc/Zsh/mod_stat.yo | 30 | ||||
-rw-r--r-- | Src/Modules/stat.c | 148 |
3 files changed, 144 insertions, 39 deletions
diff --git a/ChangeLog b/ChangeLog index 4b710e109..d2e5a6ee3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2000-04-07 Peter Stephenson <pws@pwstephenson.fsnet.co.uk> + + * 10584: Doc/Zsh/mod_stat.yo, Src/Modules/stat.c: -o shows + numeric file modes in octal. + 2000-04-07 Bart Schaefer <schaefer@zsh.org> * 10582: Src/exec.c: Apply STTY only to process group leaders. diff --git a/Doc/Zsh/mod_stat.yo b/Doc/Zsh/mod_stat.yo index 22fbe2a73..0354196ad 100644 --- a/Doc/Zsh/mod_stat.yo +++ b/Doc/Zsh/mod_stat.yo @@ -1,12 +1,14 @@ -texinode(The stat Module)(The zle Module)(The sched Module)(Zsh Modules) -sect(The stat Module) -The tt(stat) module makes available one builtin command: +COMMENT(!MOD!zsh/stat +A builtin command interface to the tt(stat) system call. +!MOD!) +The tt(zsh/stat) module makes available one builtin command: startitem() findex(stat) cindex(files, listing) cindex(files, examining) -item(tt(stat) [ tt(-gnNlLtTrs) ] [ tt(-f) var(fd) ] [ tt(-A) var(array) ] \ +item(tt(stat) [ tt(-gnNolLtTrs) ] [ tt(-f) var(fd) ] \ + [ tt(-H) var(hash) ] [ tt(-A) var(array) ] \ [ tt(-F) var(fmt) ] [ tt(PLUS())var(element) ] [ var(file) ... ])( The command acts as a front end to the tt(stat) system call (see manref(stat)(2)). @@ -84,13 +86,18 @@ item(tt(-A) var(array))( Instead of displaying the results on standard output, assign them to an var(array), one tt(struct stat) element per array element for each file in order. In this case neither the name -of the element nor the name of the files is provided unless the -tt(-t) or tt(-n) options are provided, respectively. In the -former case the element name appears as a prefix to the -appropriate array element and in the latter case the file name +of the element nor the name of the files appears in var(array) unless the +tt(-t) or tt(-n) options were given, respectively. If tt(-t) is given, +the element name appears as a prefix to the +appropriate array element; if tt(-n) is given, the file name appears as a separate array element preceding all the others. Other formatting options are respected. ) +item(tt(-H) var(hash))( +Similar to tt(-A), but instead assign the values to var(hash). The keys +are the elements listed above. If the tt(-n) option is provided then the +name of the file is included in the hash with key tt(name). +) item(tt(-f) var(fd))( Use the file on file descriptor var(fd) instead of named files; no list of file names is allowed in this case. @@ -122,6 +129,13 @@ than one file in the list. item(tt(-N))( Never show the names of files. ) +item(tt(-o))( +If a raw file mode is printed, show it in octal, which is more useful for +human consumption than the default of decimal. A leading zero will be +printed in this case. Note that this does not affect whether a raw or +formatted file mode is shown, which is controlled by the tt(-r) and tt(-s) +options, nor whether a mode is shown at all. +) item(tt(-r))( Print raw data (the default format) alongside string data (the tt(-s) format); the string data appears in parentheses diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c index 09245b52f..d0f80829c 100644 --- a/Src/Modules/stat.c +++ b/Src/Modules/stat.c @@ -34,18 +34,21 @@ enum statnum { ST_DEV, ST_INO, ST_MODE, ST_NLINK, ST_UID, ST_GID, ST_RDEV, ST_SIZE, ST_ATIM, ST_MTIM, ST_CTIM, ST_BLKSIZE, ST_BLOCKS, ST_READLINK, ST_COUNT }; enum statflags { STF_NAME = 1, STF_FILE = 2, STF_STRING = 4, STF_RAW = 8, - STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64 }; + STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64, + STF_HASH = 128, STF_OCTAL = 256 }; static char *statelts[] = { "device", "inode", "mode", "nlink", "uid", "gid", "rdev", "size", "atime", "mtime", "ctime", "blksize", "blocks", "link", NULL }; +#define HNAMEKEY "name" /**/ static void statmodeprint(mode_t mode, char *outbuf, int flags) { if (flags & STF_RAW) { - sprintf(outbuf, "%lu", (unsigned long)mode); + sprintf(outbuf, (flags & STF_OCTAL) ? "0%lo" : "%lu", + (unsigned long)mode); if (flags & STF_STRING) strcat(outbuf, " ("); } @@ -64,6 +67,8 @@ statmodeprint(mode_t mode, char *outbuf, int flags) *pm = 'c'; else if (S_ISDIR(mode)) *pm = 'd'; + else if (S_ISDOOR(mode)) + *pm = 'D'; else if (S_ISFIFO(mode)) *pm = 'p'; else if (S_ISLNK(mode)) @@ -85,6 +90,7 @@ statmodeprint(mode_t mode, char *outbuf, int flags) for (i = 1; i <= 9; i++) pm[i] = (mode & *mfp++) ? modes[i] : '-'; + pm[10] = '\0'; if (mode & S_ISUID) pm[3] = (mode & S_IXUSR) ? 's' : 'S'; @@ -210,7 +216,13 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags) break; case ST_INO: +#ifdef INO_T_IS_64_BIT + convbase(optr, sbuf->st_ino, 0); +#else + DPUTS(sizeof(sbuf->st_ino) > 4, + "Shell compiled with wrong ino_t size"); statulprint((unsigned long)sbuf->st_ino, optr); +#endif break; case ST_MODE: @@ -234,7 +246,13 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags) break; case ST_SIZE: +#ifdef OFF_T_IS_64_BIT + convbase(optr, sbuf->st_size, 0); +#else + DPUTS(sizeof(sbuf->st_size) > 4, + "Shell compiled with wrong off_t size"); statulprint((unsigned long)sbuf->st_size, optr); +#endif break; case ST_ATIM: @@ -286,6 +304,8 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags) * file names are returned as a separate array element, type names as * prefix to element. Note the formatting deliberately contains * fewer frills when -A is used. + * -H hash: as for -A array, but returns a hash with the keys being those + * from stat -l * -F fmt: specify a $TIME-like format for printing times; the default * is the (CTIME-like) "%a %b %e %k:%M:%S". This option implies * -s as it is not useful for numerical times. @@ -304,6 +324,7 @@ static int bin_stat(char *name, char **args, char *ops, int func) { char **aptr, *arrnam = NULL, **array = NULL, **arrptr = NULL; + char *hashnam = NULL, **hash = NULL, **hashptr = NULL; int len, iwhich = -1, ret = 0, flags = 0, arrsize = 0, fd = 0; struct stat statbuf; int found = 0, nargs; @@ -327,10 +348,10 @@ bin_stat(char *name, char **args, char *ops, int func) iwhich = aptr - statelts; } if (found > 1) { - zerrnam(name, "%s: ambiguous stat element", arg, 0); + zwarnnam(name, "%s: ambiguous stat element", arg, 0); return 1; } else if (found == 0) { - zerrnam(name, "%s: no such stat element", arg, 0); + zwarnnam(name, "%s: no such stat element", arg, 0); return 1; } /* if name of link requested, turn on lstat */ @@ -339,30 +360,40 @@ bin_stat(char *name, char **args, char *ops, int func) flags |= STF_PICK; } else { for (; *arg; arg++) { - if (strchr("glLnNrstT", *arg)) - ops[*arg] = 1; + if (strchr("glLnNorstT", *arg)) + ops[STOUC(*arg)] = 1; else if (*arg == 'A') { if (arg[1]) { arrnam = arg+1; } else if (!(arrnam = *++args)) { - zerrnam(name, "missing parameter name\n", + zwarnnam(name, "missing parameter name", NULL, 0); return 1; } flags |= STF_ARRAY; break; + } else if (*arg == 'H') { + if (arg[1]) { + hashnam = arg+1; + } else if (!(hashnam = *++args)) { + zwarnnam(name, "missing parameter name", + NULL, 0); + return 1; + } + flags |= STF_HASH; + break; } else if (*arg == 'f') { char *sfd; ops['f'] = 1; if (arg[1]) { sfd = arg+1; } else if (!(sfd = *++args)) { - zerrnam(name, "missing file descriptor\n", NULL, 0); + zwarnnam(name, "missing file descriptor", NULL, 0); return 1; } fd = zstrtol(sfd, &sfd, 10); if (*sfd) { - zerrnam(name, "bad file descriptor\n", NULL, 0); + zwarnnam(name, "bad file descriptor", NULL, 0); return 1; } break; @@ -370,20 +401,29 @@ bin_stat(char *name, char **args, char *ops, int func) if (arg[1]) { timefmt = arg+1; } else if (!(timefmt = *++args)) { - zerrnam(name, "missing time format\n", NULL, 0); + zwarnnam(name, "missing time format", NULL, 0); return 1; } /* force string format in order to use time format */ ops['s'] = 1; break; } else { - zerrnam(name, "bad option: -%c", NULL, *arg); + zwarnnam(name, "bad option: -%c", NULL, *arg); return 1; } } } } + if ((flags & STF_ARRAY) && (flags & STF_HASH)) { + /* We don't implement setting multiple variables at once */ + zwarnnam(name, "both array and hash requested", NULL, 0); + return 1; + /* Alternate method would be to make -H blank arrnam etc etc * + * and so get 'silent loss' of earlier choice, which would * + * be similar to stat -A foo -A bar filename */ + } + if (ops['l']) { /* list types and return: can also list to array */ if (arrnam) { @@ -423,18 +463,22 @@ bin_stat(char *name, char **args, char *ops, int func) for (aptr = args; *aptr; aptr++) nargs++; + if (ops['g']) { + flags |= STF_GMT; + ops['s'] = 1; + } if (ops['s'] || ops['r']) flags |= STF_STRING; if (ops['r'] || !ops['s']) flags |= STF_RAW; if (ops['n']) flags |= STF_FILE; + if (ops['o']) + flags |= STF_OCTAL; if (ops['t']) flags |= STF_NAME; - if (ops['g']) - flags |= STF_GMT; - if (!arrnam) { + if (!(arrnam || hashnam)) { if (nargs > 1) flags |= STF_FILE; if (!(flags & STF_PICK)) @@ -443,9 +487,20 @@ bin_stat(char *name, char **args, char *ops, int func) if (ops['N'] || ops['f']) flags &= ~STF_FILE; - if (ops['T']) + if (ops['T'] || ops['H']) flags &= ~STF_NAME; + if (hashnam) { + if (nargs > 1) { + zwarnnam(name, "only one file allowed with -H", NULL, 0); + return 1; + } + arrsize = (flags & STF_PICK) ? 1 : ST_COUNT; + if (flags & STF_FILE) + arrsize++; + hashptr = hash = (char **)zcalloc((arrsize+1)*2*sizeof(char *)); + } + if (arrnam) { arrsize = (flags & STF_PICK) ? 1 : ST_COUNT; if (flags & STF_FILE) @@ -469,16 +524,24 @@ bin_stat(char *name, char **args, char *ops, int func) continue; } - if (flags & STF_FILE) + if (flags & STF_FILE) { if (arrnam) *arrptr++ = ztrdup(*args); - else + else if (hashnam) { + *hashptr++ = ztrdup(HNAMEKEY); + *hashptr++ = ztrdup(*args); + } else printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n"); + } if (iwhich > -1) { statprint(&statbuf, outbuf, *args, iwhich, flags); if (arrnam) *arrptr++ = ztrdup(outbuf); - else + else if (hashnam) { + /* STF_NAME explicitly turned off for ops['H'] above */ + *hashptr++ = ztrdup(statelts[iwhich]); + *hashptr++ = ztrdup(outbuf); + } else printf("%s\n", outbuf); } else { int i; @@ -486,27 +549,40 @@ bin_stat(char *name, char **args, char *ops, int func) statprint(&statbuf, outbuf, *args, i, flags); if (arrnam) *arrptr++= ztrdup(outbuf); - else + else if (hashnam) { + /* STF_NAME explicitly turned off for ops['H'] above */ + *hashptr++ = ztrdup(statelts[i]); + *hashptr++ = ztrdup(outbuf); + } else printf("%s\n", outbuf); } } if (ops['f']) break; - if (!arrnam && args[1] && !(flags & STF_PICK)) + if (!arrnam && !hashnam && args[1] && !(flags & STF_PICK)) putchar('\n'); } - if (arrnam) - if (ret) { - for (aptr = array; *aptr; aptr++) - zsfree(*aptr); - zfree(array, arrsize+1); - } else { + if (arrnam) { + if (ret) + freearray(array); + else { setaparam(arrnam, array); if (errflag) return 1; } + } + + if (hashnam) { + if (ret) + freearray(hash); + else { + sethparam(hashnam, hash); + if (errflag) + return 1; + } + } return ret; } @@ -517,19 +593,29 @@ static struct builtin bintab[] = { /**/ int -boot_stat(Module m) +setup_(Module m) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } -#ifdef MODULE +/**/ +int +boot_(Module m) +{ + return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); +} /**/ int -cleanup_stat(Module m) +cleanup_(Module m) { deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); return 0; } -#endif +/**/ +int +finish_(Module m) +{ + return 0; +} |