openenvutils/commandshell/shell/src/modules/stat.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // stat.c - stat builtin interface to system call
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1996-1997 Peter Stephenson
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Peter Stephenson or the Zsh Development Group be liable
       
    18  * to any party for direct, indirect, special, incidental, or consequential
       
    19  * damages arising out of the use of this software and its documentation,
       
    20  * even if Peter Stephenson and the Zsh Development Group have been advised of
       
    21  * the possibility of such damage.
       
    22  *
       
    23  * Peter Stephenson and the Zsh Development Group specifically disclaim any
       
    24  * warranties, including, but not limited to, the implied warranties of
       
    25  * merchantability and fitness for a particular purpose.  The software
       
    26  * provided hereunder is on an "as is" basis, and Peter Stephenson and the
       
    27  * Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 #include "stat.mdh"
       
    32 #include "stat.pro"
       
    33 
       
    34 #ifdef __SYMBIAN32__
       
    35 #ifdef __WINSCW__
       
    36 #pragma warn_unusedarg off
       
    37 #endif//__WINSCW__
       
    38 #endif//__SYMBIAN32__
       
    39 
       
    40 enum statnum { ST_DEV, ST_INO, ST_MODE, ST_NLINK, ST_UID, ST_GID,
       
    41 		   ST_RDEV, ST_SIZE, ST_ATIM, ST_MTIM, ST_CTIM,
       
    42 		   ST_BLKSIZE, ST_BLOCKS, ST_READLINK, ST_COUNT };
       
    43 enum statflags { STF_NAME = 1,  STF_FILE = 2, STF_STRING = 4, STF_RAW = 8,
       
    44 		     STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64,
       
    45 		     STF_HASH = 128, STF_OCTAL = 256 };
       
    46 static char *statelts[] = { "device", "inode", "mode", "nlink",
       
    47 				"uid", "gid", "rdev", "size", "atime",
       
    48 				"mtime", "ctime", "blksize", "blocks",
       
    49 				"link", NULL };
       
    50 #define HNAMEKEY "name"
       
    51 
       
    52 /**/
       
    53 static void
       
    54 statmodeprint(mode_t mode, char *outbuf, int flags)
       
    55 {
       
    56     if (flags & STF_RAW) {
       
    57 	sprintf(outbuf, (flags & STF_OCTAL) ? "0%lo" : "%lu",
       
    58 		(unsigned long)mode);
       
    59 	if (flags & STF_STRING)
       
    60 	    strcat(outbuf, " (");
       
    61     }
       
    62     if (flags & STF_STRING) {
       
    63 	static const char *modes = "?rwxrwxrwx";
       
    64 #ifdef __CYGWIN__
       
    65 	static mode_t mflags[9] = { 0 };
       
    66 #else
       
    67 	static const mode_t mflags[9] = {
       
    68 	    S_IRUSR, S_IWUSR, S_IXUSR,
       
    69 	    S_IRGRP, S_IWGRP, S_IXGRP,
       
    70 	    S_IROTH, S_IWOTH, S_IXOTH
       
    71 	};
       
    72 #endif
       
    73 	const mode_t *mfp = mflags;
       
    74 	char pm[11];
       
    75 	int i;
       
    76 
       
    77 #ifdef __CYGWIN__
       
    78 	if (mflags[0] == 0) {
       
    79 	    mflags[0] = S_IRUSR;
       
    80 	    mflags[1] = S_IWUSR;
       
    81 	    mflags[2] = S_IXUSR;
       
    82 	    mflags[3] = S_IRGRP;
       
    83 	    mflags[4] = S_IWGRP;
       
    84 	    mflags[5] = S_IXGRP;
       
    85 	    mflags[6] = S_IROTH;
       
    86 	    mflags[7] = S_IWOTH;
       
    87 	    mflags[8] = S_IXOTH;
       
    88 	}
       
    89 #endif
       
    90 
       
    91 	if (S_ISBLK(mode))
       
    92 	    *pm = 'b';
       
    93 	else if (S_ISCHR(mode))
       
    94 	    *pm = 'c';
       
    95 	else if (S_ISDIR(mode))
       
    96 	    *pm = 'd';
       
    97 	else if (S_ISDOOR(mode))
       
    98 	    *pm = 'D';
       
    99 	else if (S_ISFIFO(mode))
       
   100 	    *pm = 'p';
       
   101 	else if (S_ISLNK(mode))
       
   102 	    *pm = 'l';
       
   103 	else if (S_ISMPC(mode))
       
   104 	    *pm = 'm';
       
   105 	else if (S_ISNWK(mode))
       
   106 	    *pm = 'n';
       
   107 	else if (S_ISOFD(mode))
       
   108 	    *pm = 'M';
       
   109 	else if (S_ISOFL(mode))
       
   110 	    *pm = 'M';
       
   111 	else if (S_ISREG(mode))
       
   112 	    *pm = '-';
       
   113 	else if (S_ISSOCK(mode))
       
   114 	    *pm = 's';
       
   115 	else
       
   116 	    *pm = '?';
       
   117 
       
   118 	for (i = 1; i <= 9; i++)
       
   119 	    pm[i] = (mode & *mfp++) ? modes[i] : '-';
       
   120 	pm[10] = '\0';
       
   121 
       
   122 	if (mode & S_ISUID)
       
   123 	    pm[3] = (mode & S_IXUSR) ? 's' : 'S';
       
   124 	if (mode & S_ISGID)
       
   125 	    pm[6] = (mode & S_IXGRP) ? 's' : 'S';
       
   126 	if (mode & S_ISVTX)
       
   127 	    pm[9] = (mode & S_IXOTH) ? 't' : 'T';
       
   128 
       
   129 	pm[10] = 0;
       
   130 	strcat(outbuf, pm);
       
   131 	if (flags & STF_RAW)
       
   132 	    strcat(outbuf, ")");
       
   133     }
       
   134 }
       
   135 
       
   136 
       
   137 /**/
       
   138 static void
       
   139 statuidprint(uid_t uid, char *outbuf, int flags)
       
   140 {
       
   141     if (flags & STF_RAW) {
       
   142 	sprintf(outbuf, "%lu", (unsigned long)uid);
       
   143 	if (flags & STF_STRING)
       
   144 	    strcat(outbuf, " (");
       
   145     }
       
   146     if (flags & STF_STRING) {
       
   147 #ifdef HAVE_GETPWUID
       
   148 	struct passwd *pwd;
       
   149 	pwd = getpwuid(uid);
       
   150 	strcat(outbuf, pwd ? pwd->pw_name : "???");
       
   151 #else /* !HAVE_GETPWUID */
       
   152 	strcat(outbuf, "???");
       
   153 #endif /* !HAVE_GETPWUID */
       
   154 	if (flags & STF_RAW)
       
   155 	    strcat(outbuf, ")");
       
   156     }
       
   157 }
       
   158 
       
   159 
       
   160 /**/
       
   161 static void
       
   162 statgidprint(gid_t gid, char *outbuf, int flags)
       
   163 {
       
   164     if (flags & STF_RAW) {
       
   165 	sprintf(outbuf, "%lu", (unsigned long)gid);
       
   166 	if (flags & STF_STRING)
       
   167 	    strcat(outbuf, " (");
       
   168     }
       
   169     if (flags & STF_STRING) {
       
   170 #ifdef HAVE_GETGRGID
       
   171 	struct group *gr;
       
   172 	gr = getgrgid(gid);
       
   173 	strcat(outbuf, gr ? gr->gr_name : "???");
       
   174 #else /* !HAVE_GETGRGID */
       
   175 	strcat(outbuf, "???");
       
   176 #endif /* !HAVE_GETGRGID */
       
   177 	if (flags & STF_RAW)
       
   178 	    strcat(outbuf, ")");
       
   179     }
       
   180 }
       
   181 
       
   182 static char *timefmt;
       
   183 
       
   184 /**/
       
   185 static void
       
   186 stattimeprint(time_t tim, char *outbuf, int flags)
       
   187 {
       
   188     if (flags & STF_RAW) {
       
   189 	sprintf(outbuf, "%ld", (unsigned long)tim);
       
   190 	if (flags & STF_STRING)
       
   191 	    strcat(outbuf, " (");
       
   192     }
       
   193     if (flags & STF_STRING) {
       
   194 	char *oend = outbuf + strlen(outbuf);
       
   195 	ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) :
       
   196 		 localtime(&tim));
       
   197 	if (flags & STF_RAW)
       
   198 	    strcat(outbuf, ")");
       
   199     }
       
   200 }
       
   201 
       
   202 
       
   203 /**/
       
   204 static void
       
   205 statulprint(unsigned long num, char *outbuf)
       
   206 {
       
   207     sprintf(outbuf, "%lu", num);
       
   208 }
       
   209 
       
   210 
       
   211 /**/
       
   212 static void
       
   213 statlinkprint(struct stat *sbuf, char *outbuf, char *fname)
       
   214 {
       
   215     int num;
       
   216 
       
   217     /* fname is NULL if we are looking at an fd */
       
   218     if (fname && S_ISLNK(sbuf->st_mode) &&
       
   219  	(num = readlink(fname, outbuf, PATH_MAX)) > 0) {
       
   220 	/* readlink doesn't terminate the buffer itself */
       
   221 	outbuf[num] = '\0';
       
   222     }
       
   223 }
       
   224 
       
   225 
       
   226 /**/
       
   227 static void
       
   228 statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
       
   229 {
       
   230     char *optr = outbuf;
       
   231 
       
   232     if (flags & STF_NAME) {
       
   233 	sprintf(outbuf, (flags & (STF_PICK|STF_ARRAY)) ?
       
   234 		"%s " : "%-8s", statelts[iwhich]);
       
   235 	optr += strlen(outbuf);
       
   236     }
       
   237     *optr = '\0';
       
   238 
       
   239     /* cast values to unsigned long as safest bet */
       
   240     switch (iwhich) {
       
   241     case ST_DEV:
       
   242 	statulprint((unsigned long)sbuf->st_dev, optr);
       
   243 	break;
       
   244 
       
   245     case ST_INO:
       
   246 #ifdef INO_T_IS_64_BIT
       
   247 	convbase(optr, sbuf->st_ino, 0);
       
   248 #else
       
   249 	DPUTS(sizeof(sbuf->st_ino) > 4,
       
   250 	      "Shell compiled with wrong ino_t size");
       
   251 	statulprint((unsigned long)sbuf->st_ino, optr);
       
   252 #endif
       
   253 	break;
       
   254 
       
   255     case ST_MODE:
       
   256 	statmodeprint(sbuf->st_mode, optr, flags);
       
   257 	break;
       
   258 
       
   259     case ST_NLINK:
       
   260 	statulprint((unsigned long)sbuf->st_nlink, optr);
       
   261 	break;
       
   262 
       
   263     case ST_UID:
       
   264 	statuidprint(sbuf->st_uid, optr, flags);
       
   265 	break;
       
   266 
       
   267     case ST_GID:
       
   268 	statgidprint(sbuf->st_gid, optr, flags);
       
   269 	break;
       
   270 
       
   271     case ST_RDEV:
       
   272 	statulprint((unsigned long)sbuf->st_rdev, optr);
       
   273 	break;
       
   274 
       
   275     case ST_SIZE:
       
   276 #ifdef OFF_T_IS_64_BIT
       
   277 	convbase(optr, sbuf->st_size, 0);
       
   278 #else
       
   279 	DPUTS(sizeof(sbuf->st_size) > 4,
       
   280 	      "Shell compiled with wrong off_t size");
       
   281 	statulprint((unsigned long)sbuf->st_size, optr);
       
   282 #endif
       
   283 	break;
       
   284 
       
   285     case ST_ATIM:
       
   286 	stattimeprint(sbuf->st_atime, optr, flags);
       
   287 	break;
       
   288 
       
   289     case ST_MTIM:
       
   290 	stattimeprint(sbuf->st_mtime, optr, flags);
       
   291 	break;
       
   292 
       
   293     case ST_CTIM:
       
   294 	stattimeprint(sbuf->st_ctime, optr, flags);
       
   295 	break;
       
   296 
       
   297     case ST_BLKSIZE:
       
   298 	statulprint((unsigned long)sbuf->st_blksize, optr);
       
   299 	break;
       
   300 
       
   301     case ST_BLOCKS:
       
   302 	statulprint((unsigned long)sbuf->st_blocks, optr);
       
   303 	break;
       
   304 
       
   305     case ST_READLINK:
       
   306 	statlinkprint(sbuf, optr, fname);
       
   307 	break;
       
   308 
       
   309     case ST_COUNT:			/* keep some compilers happy */
       
   310 	break;
       
   311     }
       
   312 }
       
   313 
       
   314 
       
   315 /*
       
   316  *
       
   317  * Options:
       
   318  *  -f fd:   stat fd instead of file
       
   319  *  -g:   use GMT rather than local time for time strings (forces -s on).
       
   320  *  -n:   always print file name of file being statted
       
   321  *  -N:   never print file name
       
   322  *  -l:   list stat types
       
   323  *  -L:   do lstat (else links are implicitly dereferenced by stat)
       
   324  *  -t:   always print name of stat type
       
   325  *  -T:   never print name of stat type
       
   326  *  -r:   print raw alongside string data
       
   327  *  -s:   string, print mode, times, uid, gid as appropriate strings:
       
   328  *        harmless but unnecessary when combined with -r.
       
   329  *  -A array:  assign results to given array, one stat result per element.
       
   330  *        File names and type names are only added if explicitly requested:
       
   331  *        file names are returned as a separate array element, type names as
       
   332  *        prefix to element.  Note the formatting deliberately contains
       
   333  *        fewer frills when -A is used.
       
   334  *  -H hash:  as for -A array, but returns a hash with the keys being those
       
   335  *        from stat -l
       
   336  *  -F fmt: specify a $TIME-like format for printing times; the default
       
   337  *        is the (CTIME-like) "%a %b %e %k:%M:%S".  This option implies
       
   338  *        -s as it is not useful for numerical times.
       
   339  *
       
   340  *  +type selects just element type of stat buffer (-l gives list):
       
   341  *        type can be shortened to unambiguous string.  only one type is
       
   342  *        allowed.  The extra type, +link, reads the target of a symbolic
       
   343  *        link; it is empty if the stat was not an lstat or if 
       
   344  *        a file descriptor was stat'd, if the stat'd file is
       
   345  *        not a symbolic link, or if symbolic links are not
       
   346  *        supported.  If +link is explicitly requested, the -L (lstat)
       
   347  *        option is set automatically.
       
   348  */
       
   349 /**/
       
   350 static int
       
   351 bin_stat(char *name, char **args, Options ops, UNUSED(int func))
       
   352 {
       
   353     char **aptr, *arrnam = NULL, **array = NULL, **arrptr = NULL;
       
   354     char *hashnam = NULL, **hash = NULL, **hashptr = NULL;
       
   355     int len, iwhich = -1, ret = 0, flags = 0, arrsize = 0, fd = 0;
       
   356     struct stat statbuf;
       
   357     int found = 0, nargs;
       
   358 
       
   359     timefmt = "%a %b %e %k:%M:%S";
       
   360 
       
   361     for (; *args && (**args == '+' || **args == '-'); args++) {
       
   362 	char *arg = *args+1;
       
   363 	if (!*arg || *arg == '-' || *arg == '+') {
       
   364 	    args++;
       
   365 	    break;
       
   366 	}
       
   367 
       
   368 	if (**args == '+') {
       
   369 	    if (found)
       
   370 		break;
       
   371 	    len = strlen(arg);
       
   372 	    for (aptr = statelts; *aptr; aptr++)
       
   373 		if (!strncmp(*aptr, arg, len)) {
       
   374 		    found++;
       
   375 		    iwhich = aptr - statelts;
       
   376 		}
       
   377 	    if (found > 1) {
       
   378 		zwarnnam(name, "%s: ambiguous stat element", arg, 0);
       
   379 		return 1;
       
   380 	    } else if (found == 0) {
       
   381 		zwarnnam(name, "%s: no such stat element", arg, 0);
       
   382 		return 1;
       
   383 	    }
       
   384 	    /* if name of link requested, turn on lstat */
       
   385 	    if (iwhich == ST_READLINK)
       
   386 		ops->ind['L'] = 1;
       
   387 	    flags |= STF_PICK;
       
   388 	} else {
       
   389 	    for (; *arg; arg++) {
       
   390 		if (strchr("glLnNorstT", *arg))
       
   391 		    ops->ind[STOUC(*arg)] = 1;
       
   392 		else if (*arg == 'A') {
       
   393 		    if (arg[1]) {
       
   394 			arrnam = arg+1;
       
   395 		    } else if (!(arrnam = *++args)) {
       
   396 			zwarnnam(name, "missing parameter name",
       
   397 				NULL, 0);
       
   398 			return 1;
       
   399 		    }
       
   400 		    flags |= STF_ARRAY;
       
   401 		    break;
       
   402 		} else if (*arg == 'H') {
       
   403 		    if (arg[1]) {
       
   404 			hashnam = arg+1;
       
   405 		    } else if (!(hashnam = *++args)) {
       
   406 			zwarnnam(name, "missing parameter name",
       
   407 				NULL, 0);
       
   408 			return 1;
       
   409 		    }
       
   410 		    flags |= STF_HASH;
       
   411 		    break;
       
   412 		} else if (*arg == 'f') {
       
   413 		    char *sfd;
       
   414 		    ops->ind['f'] = 1;
       
   415 		    if (arg[1]) {
       
   416 			sfd = arg+1;
       
   417 		    } else if (!(sfd = *++args)) {
       
   418 			zwarnnam(name, "missing file descriptor", NULL, 0);
       
   419 			return 1;
       
   420 		    }
       
   421 		    fd = zstrtol(sfd, &sfd, 10);
       
   422 		    if (*sfd) {
       
   423 			zwarnnam(name, "bad file descriptor", NULL, 0);
       
   424 			return 1;
       
   425 		    }
       
   426 		    break;
       
   427 		} else if (*arg == 'F') {
       
   428 		    if (arg[1]) {
       
   429 			timefmt = arg+1;
       
   430 		    } else if (!(timefmt = *++args)) {
       
   431 			zwarnnam(name, "missing time format", NULL, 0);
       
   432 			return 1;
       
   433 		    }
       
   434 		    /* force string format in order to use time format */
       
   435 		    ops->ind['s'] = 1;
       
   436 		    break;
       
   437 		} else {
       
   438 		    zwarnnam(name, "bad option: -%c", NULL, *arg);
       
   439 		    return 1;
       
   440 		}
       
   441 	    }
       
   442 	}
       
   443     }
       
   444 
       
   445     if ((flags & STF_ARRAY) && (flags & STF_HASH)) {
       
   446     	/* We don't implement setting multiple variables at once */
       
   447 	zwarnnam(name, "both array and hash requested", NULL, 0);
       
   448 	return 1;
       
   449 	/* Alternate method would be to make -H blank arrnam etc etc *
       
   450 	 * and so get 'silent loss' of earlier choice, which would   *
       
   451 	 * be similar to stat -A foo -A bar filename                 */
       
   452     }
       
   453 
       
   454     if (OPT_ISSET(ops,'l')) {
       
   455 	/* list types and return:  can also list to array */
       
   456 	if (arrnam) {
       
   457 	    arrptr = array = (char **)zalloc((ST_COUNT+1)*sizeof(char *));
       
   458 	    array[ST_COUNT] = NULL;
       
   459 	}
       
   460 	for (aptr = statelts; *aptr; aptr++) {
       
   461 	    if (arrnam) {
       
   462 		*arrptr++ = ztrdup(*aptr);
       
   463 	    } else {
       
   464 		printf("%s", *aptr);
       
   465 		if (aptr[1])
       
   466 		    putchar(' ');
       
   467 	    }
       
   468 	}
       
   469 	if (arrnam) {
       
   470 	    setaparam(arrnam, array);
       
   471 	    if (errflag)
       
   472 		return 1;
       
   473 	} else
       
   474 	    putchar('\n');
       
   475 	return 0;
       
   476     }
       
   477 
       
   478     if (!*args && !OPT_ISSET(ops,'f')) {
       
   479 	zwarnnam(name, "no files given", NULL, 0);
       
   480 	return 1;
       
   481     } else if (*args && OPT_ISSET(ops,'f')) {
       
   482 	zwarnnam(name, "no files allowed with -f", NULL, 0);
       
   483 	return 1;
       
   484     }
       
   485 
       
   486     nargs = 0;
       
   487     if (OPT_ISSET(ops,'f'))
       
   488 	nargs = 1;
       
   489     else
       
   490 	for (aptr = args; *aptr; aptr++)
       
   491 	    nargs++;
       
   492 
       
   493     if (OPT_ISSET(ops,'g')) {
       
   494 	flags |= STF_GMT;
       
   495 	ops->ind['s'] = 1;
       
   496     }
       
   497     if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'r'))
       
   498 	flags |= STF_STRING;
       
   499     if (OPT_ISSET(ops,'r') || !OPT_ISSET(ops,'s'))
       
   500 	flags |= STF_RAW;
       
   501     if (OPT_ISSET(ops,'n'))
       
   502 	flags |= STF_FILE;
       
   503     if (OPT_ISSET(ops,'o'))
       
   504 	flags |= STF_OCTAL;
       
   505     if (OPT_ISSET(ops,'t'))
       
   506 	flags |= STF_NAME;
       
   507 
       
   508     if (!(arrnam || hashnam)) {
       
   509 	if (nargs > 1)
       
   510 	    flags |= STF_FILE;
       
   511 	if (!(flags & STF_PICK))
       
   512 	    flags |= STF_NAME;
       
   513     }
       
   514 
       
   515     if (OPT_ISSET(ops,'N') || OPT_ISSET(ops,'f'))
       
   516 	flags &= ~STF_FILE;
       
   517     if (OPT_ISSET(ops,'T') || OPT_ISSET(ops,'H'))
       
   518 	flags &= ~STF_NAME;
       
   519 
       
   520     if (hashnam) {
       
   521     	if (nargs > 1) {
       
   522 	    zwarnnam(name, "only one file allowed with -H", NULL, 0);
       
   523 	    return 1;
       
   524 	}
       
   525 	arrsize = (flags & STF_PICK) ? 1 : ST_COUNT;
       
   526 	if (flags & STF_FILE)
       
   527 	    arrsize++;
       
   528 	hashptr = hash = (char **)zshcalloc((arrsize+1)*2*sizeof(char *));
       
   529     }
       
   530 
       
   531     if (arrnam) {
       
   532 	arrsize = (flags & STF_PICK) ? 1 : ST_COUNT;
       
   533 	if (flags & STF_FILE)
       
   534 	    arrsize++;
       
   535 	arrsize *= nargs;
       
   536 	arrptr = array = (char **)zshcalloc((arrsize+1)*sizeof(char *));
       
   537     }
       
   538 
       
   539     for (; OPT_ISSET(ops,'f') || *args; args++) {
       
   540 	char outbuf[PATH_MAX + 9]; /* "link   " + link name + NULL */
       
   541 	int rval = OPT_ISSET(ops,'f') ? fstat(fd, &statbuf) :
       
   542 	    OPT_ISSET(ops,'L') ? lstat(*args, &statbuf) :
       
   543 	    stat(*args, &statbuf);
       
   544 	if (rval) {
       
   545 	    if (OPT_ISSET(ops,'f'))
       
   546 		sprintf(outbuf, "%d", fd);
       
   547 	    zwarnnam(name, "%s: %e", OPT_ISSET(ops,'f') ? outbuf : *args,
       
   548 		     errno);
       
   549 	    ret = 1;
       
   550 	    if (OPT_ISSET(ops,'f') || arrnam)
       
   551 		break;
       
   552 	    else
       
   553 		continue;
       
   554 	}
       
   555 
       
   556 	if (flags & STF_FILE) {
       
   557 	    if (arrnam)
       
   558 		*arrptr++ = ztrdup(*args);
       
   559 	    else if (hashnam) {
       
   560 	    	*hashptr++ = ztrdup(HNAMEKEY);
       
   561 		*hashptr++ = ztrdup(*args);
       
   562 	    } else
       
   563 		printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n");
       
   564 	}
       
   565 	if (iwhich > -1) {
       
   566 	    statprint(&statbuf, outbuf, *args, iwhich, flags);
       
   567 	    if (arrnam)
       
   568 		*arrptr++ = ztrdup(outbuf);
       
   569 	    else if (hashnam) {
       
   570 		/* STF_NAME explicitly turned off for ops.ind['H'] above */
       
   571 	    	*hashptr++ = ztrdup(statelts[iwhich]);
       
   572 		*hashptr++ = ztrdup(outbuf);
       
   573 	    } else
       
   574 		printf("%s\n", outbuf);
       
   575 	} else {
       
   576 	    int i;
       
   577 	    for (i = 0; i < ST_COUNT; i++) {
       
   578 		statprint(&statbuf, outbuf, *args, i, flags);
       
   579 		if (arrnam)
       
   580 		    *arrptr++= ztrdup(outbuf);
       
   581 		else if (hashnam) {
       
   582 		    /* STF_NAME explicitly turned off for ops.ind['H'] above */
       
   583 		    *hashptr++ = ztrdup(statelts[i]);
       
   584 		    *hashptr++ = ztrdup(outbuf);
       
   585 		} else
       
   586 		    printf("%s\n", outbuf);
       
   587 	    }
       
   588 	}
       
   589 	if (OPT_ISSET(ops,'f'))
       
   590 	    break;
       
   591 
       
   592 	if (!arrnam && !hashnam && args[1] && !(flags & STF_PICK))
       
   593 	    putchar('\n');
       
   594     }
       
   595 
       
   596     if (arrnam) {
       
   597 	if (ret)
       
   598 	    freearray(array);
       
   599 	else {
       
   600 	    setaparam(arrnam, array);
       
   601 	    if (errflag)
       
   602 		return 1;
       
   603 	}
       
   604     }
       
   605 
       
   606     if (hashnam) {
       
   607     	if (ret)
       
   608 	    freearray(hash);
       
   609 	else {
       
   610 	    sethparam(hashnam, hash);
       
   611 	    if (errflag)
       
   612 		return 1;
       
   613 	}
       
   614     }
       
   615 
       
   616     return ret;
       
   617 }
       
   618 
       
   619 static struct builtin bintab[] = {
       
   620     BUILTIN("stat", 0, bin_stat, 0, -1, 0, NULL, NULL),
       
   621 };
       
   622 
       
   623 /**/
       
   624 int
       
   625 setup_(UNUSED(Module m))
       
   626 {
       
   627     return 0;
       
   628 }
       
   629 
       
   630 /**/
       
   631 int
       
   632 boot_(Module m)
       
   633 {
       
   634     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
   635 }
       
   636 
       
   637 /**/
       
   638 int
       
   639 cleanup_(Module m)
       
   640 {
       
   641     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
   642     return 0;
       
   643 }
       
   644 
       
   645 /**/
       
   646 int
       
   647 finish_(UNUSED(Module m))
       
   648 {
       
   649     return 0;
       
   650 }