summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Doc/Zsh/mod_stat.yo30
-rw-r--r--Src/Modules/stat.c148
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;
+}