Newsgroup: comp.sources.misc


Path: icdoc!inmos!inmos-c!col!hp-lsd!hpldola!hpfcso!hplabs!hp-pcd!hp-sdd!ucsdhub!ucsd!usc!brutus.cs.uiuc.edu!uakari.primate.wisc.edu!aplcen!uunet!allbery
From: dds@cc.ic.ac.uk (Diomidis Spinellis)
Newsgroups: comp.sources.misc
Subject: v10i082: Stat(1)
Message-ID: <79983@uunet.UU.NET>
Date: 27 Feb 90 02:49:35 GMT
Sender: allbery@uunet.UU.NET
Lines: 1143
Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Content-Length: 30133
Posting-number: Volume 10, Issue 82
Submitted-by: dds@cc.ic.ac.uk (Diomidis Spinellis)
Archive-name: stat

Stat is a program that brings all the power of the stat(2) system call
to the shell programer.  It can be used to print various
characteristics of a file such as its size, permissions, dates, type
etc. in a variety of user specified formats.  The output can be easily
manipulated with tools such as awk, sed and sort to provide complex
file selection and printing mechanisms.  Obvious applications are
novice-user-friendly versions of ls(1) and getting the mode of a file
in a way that can be later used by chmod(1).  It has been tested under 
4.3 BSD, AIX, HP/UX, SunOS, and Ultrix.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	Makefile
#	stat.1
#	stat.c
# This archive created: Wed Feb 21 21:21:02 1990
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(1374 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
X
XStat is a program that brings all the power of the stat(2) system call
Xto the shell programer.  It can be used to print various
Xcharacteristics of a file such as its size, permissions, dates, type
Xetc. in a variety of user specified formats.  The output can be easily
Xmanipulated with tools such as awk, sed and sort to provide complex
Xfile selection and printing mechanisms.  Obvious applications are
Xnovice-user-friendly versions of ls(1) and getting the mode of a file
Xin a way that can be later used by chmod(1).  It has been tested under 
X4.3 BSD, AIX, HP/UX, SunOS, and Ultrix.
X
XThe output format is specified at three different levels in a
Xprintf(3S) like way.  A global output format string specifies the
Xitems which are printed.  The way the different time values are printed
Xis specified by other format strings.  Finaly the way each individual
Xfield is printed (number base, justification, padding) can be specified
Xusing the normal printf specifications.
X
XComments and additions can be sent to the author:
X
X	Diomidis Spinellis
X	Myrsinis 1
X	GR-145 62 Kifissia
X	GREECE
X
X--
XDiomidis Spinellis                  Internet:                 dds@cc.ic.ac.uk
XDepartment of Computing             UUCP:                    ...!ukc!iccc!dds
XImperial College                    JANET:                    dds@uk.ac.ic.cc
XLondon SW7 2BZ                      #include "/dev/tty"
SHAR_EOF
if test 1374 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 1374 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(464 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X# Makefile for stat
X#
X
X# Binary destination
Xbin = /usr/local/bin
X
X# Unformated manual page destination
Xmansrc = /usr/local/man/man1
X
XCC = cc
XCFLAGS = -O
XLINTFLAGS = -chabx
X
Xall: stat
X
Xstat: stat.c
X	$(CC) $(CFLAGS) stat.c -o stat
X
Xinstall: stat stat.1
X	install stat $(bin)
X	install stat.1 $(mansrc)
X
Xclean:
X	rm -f stat.o 
X
Xclobber:
X	rm -f stat.o stat core
X
Xlint:
X	lint $(LINTFLAGS) stat.c >stat.lint
X
Xshar:
X	shar -cv -p X README Makefile stat.1 stat.c >stat.shar
SHAR_EOF
if test 464 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 464 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'stat.1'" '(8549 characters)'
if test -f 'stat.1'
then
	echo shar: will not over-write existing file "'stat.1'"
else
sed 's/^X//' << \SHAR_EOF > 'stat.1'
X.\"
X.\" (C) Copyright 1989 Diomidis D. Spinellis.  All rights reserved.
X.\"
X.\" Redistribution and use in source and formated forms are permitted
X.\" provided that the above copyright notice and this paragraph are
X.\" duplicated in all such forms and that any documentation,
X.\" advertising materials, and other materials related to such
X.\" distribution and use acknowledge that the software was developed
X.\" by Diomidis D. Spinellis.
X.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X.\"
X.TH STAT 1 
X.SH NAME
Xstat \- print file status information
X.SH SYNOPSIS
X.B stat
X[
X.BI \-g
X]
X[
X.BI \-l
X]
X[
X.BI \-e
X]
X[
X.BI \-f " format"
X]
X[
X.BI \-t " time_format"
X]
X[
X.BI \-m " time_format"
X]
X[
X.BI \-a " time_format"
X]
X[
X.BI \-c " time_format"
X]
X[
X.BI \-q " mode_names"
X]
X[
X.BI \-y " type_names"
X]
Xfile ...
X.SH DESCRIPTION
X.I Stat
Xprints status information for each of the files specified.  If a
Xfile name is `\-', then status information about the standard input
Xis displayed.
X.PP
XThe output can be specified by means of
X.I printf
Xlike format specifications.  If no format specifications are given, then
X.I ``ls -l''
Xlike output is produced.  
X.SH OPTIONS
X.TP
X.B \-g
XList time fields in UTC (GMT) instead of local time.
X.TP
X.B \-l
XFor symbolic links list the status of the the file it points to instead of
Xthe status of the link (i.e. follow symbolic links).
X.TP
X.B \-e
XExit immediately with an error when stat can not be performed on a file.  If 
Xthis
Xflag is not given then error messages are printed, but the program continues
Xto go through the list of files.
X.TP
X.BI \-f " output format"
XSpecify the output format.
X.TP
X.BI \-a " time format"
XSpecify the output format for the file access time field.
X.TP
X.BI \-m " time format"
XSpecify the output format for the file modification time field.
X.TP
X.BI \-c " time format"
XSpecify the output format for the file status change time field.
X.TP
X.BI \-t " time format"
XSpecify the output format for the current time field.
X.TP
X.BI \-q " mode names"
XSpecify the English description of the file mode giving a list of 24 strings.
XThe strings are separated by an arbitrary character and the list should start
Xand end with that character.  
XThe first three strings 
Xdescribe the set user id, set group id and sticky modes.  
XAfter that, nine strings, the descriptions for read 
Xpermission, write permission and execute permission, first for the owner,
Xthen for the group and then for others must be given.
XAnother set
Xof 12 strings must follow describing the semantics of the above in
Xthe case of directories.
X.TP
X.BI \-y " type names"
XSpecify the English description of the file type giving a list of seven strings.
XThe list is given as in the
X.I -q
Xoption and the strings are the descriptions to be used for directories,
Xblock special files, character special files, symbolic links, named pipes, 
Xsockets and regular files.  All types must be given, even if not supported
Xon a system.
X.PP
XFive format specifications can be given: one for
Xthe whole output and four for the output format of different time values.  
XThe format specification
Xis a string.  All characters in the format specification are printed except
Xfor characters following a `%' sign.  If the first character after a `%' sign
Xis an open bracket `(' then the characters up to the matching closing bracket
Xare taken as a
X.I printf
Xformat specification that will be used to print the item specified.
XA `%' sign in the printf format specification is not needed.
XNote that some systems may not support some of the options.
X.PP
XCharacters following a `%' sign are
Xconverted in the global output specification as follows:
X.RS
X.PD 0
X.TP 5
X.B v
Xdevice the file resides on in decimal
X.TP 5
X.B i
Xthe file's inode number in decimal
X.TP 5
X.B p
Xthe file's protection in octal
X.TP 5
X.B P
Xthe file's protection in an
X.I ls -l
Xlike fashion
X.TP 5
X.B q
Xthe file's protection as a series of nine 0 or 1 digits.  The default format
Xspecification for printf is `%s' and applies to each individual digit
X.TP 5
X.B Q
Xthe file's protection using an English description.  The description can be
Xoptionaly specified using the
X.I .q
Xoption.  If the file is a symbolic link and the
X.I -l
Xoption has not been given, nothing is printed
X.TP 5
X.B l
Xthe number of links the file has in decimal
X.TP 5
X.B u
Xthe user id of the owner of the file in decimal
X.TP 5
X.B U
Xthe user id of the owner of the file as a string
X.TP 5
X.B g
Xthe group id of the owner of the file in decimal
X.TP 5
X.B G
Xthe group id of the owner of the file as a string
X.TP 5
X.B r
Xthe device identifier (only for special files)
X.TP 5
X.B s
Xtotal byte size of the file in decimal 
X.TP 5
X.B a
Xlast access time of file in seconds since 1970
X.TP 5
X.B m
Xlast modification time of file in seconds since 1970
X.TP 5
X.B c
Xlast status change time of file in seconds since 1970
X.TP 5
X.B t
Xcurrent time in seconds since 1970
X.TP 5
X.B A
Xlast access time of file as the string specified by the access time format
X.TP 5
X.B M
Xlast modification time of file as the string specified by the modification time 
Xformat
X.TP 5
X.B C
Xlast status change time of file as the string specified by the change 
Xtime format
X.TP 5
X.B T
Xcurrent time as the string specified by the current time format
X.TP 5
X.B z
Xpreferred blocksize for file I/O
X.TP 5
X.B b
Xactual number of blocks allocated
X.TP 5
X.B n
Xthe name of the file
X.TP 5
X.B f
Xa `/' for directories, `@' for symbolic links, `=' for AF_UNIX domain sockets
Xand `*' for executable files.  If the name of a symbolic link or an arrow is
Xprinted as a result of %L or %- then the `@' is not printed.
X.TP 5
X.B F
XThe type of the file is printed as one of the symbols S_IFIDR, S_IFBLK,
XS_IFCHAR, S_IFLNK, S_IFIFO, S_IFSOCK, S_IFREG for directories, block
Xspecial files, character special files, symbolic links, FIFO special files,
XAF_UNIX domain sockets and regular files.
X.TP 5
X.B Y
XThe type of the file using an English description, optionaly specified using
Xthe
X.I -y
Xoption
X.TP 5
X.B L
Xif the file is a symbolic link, the contents of the link
X.TP 5
X.B -
Xif the file is a symbolic link, the character sequence ` -> '
X.PD
X.RE
X.PP
XThe default time format specification produces
X.I `ls -l'
Xlike time output.
XCharacters following a `%' sign are
Xconverted in the time output specification as follows:
X.RS
X.PD 0
X.TP 5
X.B m
Xthe month number in decimal (1-12)
X.TP 5
X.B d
Xthe day of month number in decimal (1-31)
X.TP 5
X.B y
Xthe year in decimal (1900-...)
X.TP 5
X.B Y
Xthe year in decimal printed only if the time is more that half a year older
Xthan the current time.
X.TP 5
X.B H
Xthe hour of the day in decimal (0-23)
X.TP 5
X.B M
Xminutes in decimal (0-59)
X.TP 5
X.B S
Xseconds in decimal (0-59)
X.TP 5
X.B T
Xhours and minutes as 00:00 printed only if time is less than half a
Xyear older than the current time.  (A note for pedants: If the time
Xis exactly equal to the current time minus half a year than hours and
Xminutes are printed.)
X.TP 5
X.B j
Xthe day of the year in decimal (0-365)
X.TP 5
X.B w
Xthe day of the week in decimal (Sunday is 0)
X.TP 5
X.B a
Xthe three letter abbreviation of the day of the week
X.TP 5
X.B h
Xthe three letter abbreviation of the month
X.TP 5
X.B z
Xthe offset of the time from UTC (GMT) in seconds
X.TP 5
X.B Z
Xabbreviation of the timezone name
X.TP 5
X.B D
Xthe letters DST if daylight savings time is in effect
X.TP 5
X.B t
XThe time in the form mmddhhmmyy.  This form can be used as an argument
Xof the System V touch command.
X.PD
X.RE
X.PP
X.SH EXAMPLES
X.PP
XList all files in a directory in a
X.I `ls -F'
Xlike fashion (the default time format is `%h %(2d)d %T%(5d)Y'):
X.nf
X	stat -f '%P%(3d)l %(-8s)U %(8ld)s %M %n%-%L%F' *
X.fi
X.PP
XMake depend in a makefile without modifying the permissions of Makefile
X(Makefile can be read only from a version control system).
X.nf
X	PERMS=`stat -f %p Makefile` ;\\
X	chmod 600 Makefile ;\\
X	mkdep $(FILES) ;\\
X	chmod $$PERMS Makefile
X.fi
X.PP
XAn extremely verbose version of ls:
X.nf
X#!/bin/sh
XT='%a %d %h %y %H:%M:%S'
Xstat -a "$T" -c "$T" -m "$T" -f '
XFile:		%n
XType:		%Y
XDevice:		%v(0x%(x)v)
XInode:		%i(0x%(x)i)
XPotection:	%Q
XUser:		%U(%u)
XGroup:		%G(%g)
XFile size:	%s byte(s) %b block(s)
XLast access:	%A
XLast change:	%M
XStatus change:	%C
X ' -y '
XDirectory
XBlock device
XCharacter device
XSymbolic link
XNamed pipe
XSocket
XNormal file
X ' $*
X.fi
X
X.SH AUTHOR
X(C) Copyright 1989 Diomidis D. Spinellis (dds@cc.ic.ac.uk).  All rights reserved.
X.SH SEE ALSO
Xls(1), find(1), printf(3S)
X.SH BUGS
X.PP
XNot quite as many options as ls.
SHAR_EOF
if test 8549 -ne "`wc -c < 'stat.1'`"
then
	echo shar: error transmitting "'stat.1'" '(should have been 8549 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'stat.c'" '(14832 characters)'
if test -f 'stat.c'
then
	echo shar: will not over-write existing file "'stat.c'"
else
sed 's/^X//' << \SHAR_EOF > 'stat.c'
X/*
X * stat - List the status information of a list of files
X *
X * (C) Copyright 1989 Diomidis D. Spinellis.  All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Diomidis D. Spinellis.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * $Header: stat.c,v 1.9 89/11/03 22:53:12 dds Rel $
X *
X */
X
X#include <stdio.h>
X#include <string.h>
X#include <varargs.h>
X#include <pwd.h>
X#include <grp.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <sys/param.h>
X
X#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
X
X#ifndef lint
Xstatic char RCSid[] = "$Header: stat.c,v 1.9 89/11/03 22:53:12 dds Rel $";
X#endif
X
Xint debug = 0;
Xint lflag = 0;					/* Follow links */
Xint gflag = 0;					/* Use GMT */
Xint eflag = 0;					/* Exit on error */
Xchar *progname;					/* Base name of the program */
X/* Output format string */
Xchar *format = "%P%(3d)l %(-8s)U %(8ld)s %M %n%-%L";
Xchar *ttformat = "%h %(2d)d %T%(5d)Y";		/* Current time format */
Xchar *tcformat = "%h %(2d)d %T%(5d)Y";		/* Creation time format */
Xchar *taformat = "%h %(2d)d %T%(5d)Y";		/* Access time format */
Xchar *tmformat = "%h %(2d)d %T%(5d)Y";		/* Modification time format */
Xchar *typename[];				/* File type english names */
Xchar *modename[];				/* File mode english names */
Xstruct tm currtime;				/* Current time structure */
Xlong currclock, halfyearago;			/* ... in seconds */
X
Xextern void error(), exit();
Xextern struct tm *localtime(), *gmtime();
X
Xstatic void parsenames();
X
X/*
X * main - parse arguments and handle options
X */
Xmain(argc, argv)
X	int argc;
X	char *argv[];
X{
X	int c;
X	int errflg = 0;
X	extern int optind;
X	extern char *optarg;
X	extern char *mkprogname();
X	void process();
X	struct timeval time;
X	struct timezone zone;
X
X	progname = mkprogname(argv[0]);
X
X	while ((c = getopt(argc, argv, "dglf:t:a:m:c:q:y:")) != EOF)
X		switch (c) {
X#ifndef NDEBUG
X		case 'd':	/* Debugging. */
X			debug++;
X			break;
X#endif
X		case 'e':
X			eflag++;
X			break;
X		case 'g':
X			gflag++;
X			break;
X		case 'l':
X			lflag++;
X			break;
X		case 'c':	/* Format for current time specification */
X			tcformat = optarg;
X			break;
X		case 'a':	/* Format for current time specification */
X			taformat = optarg;
X			break;
X		case 'm':	/* Format for current time specification */
X			tmformat = optarg;
X			break;
X		case 't':	/* Format for current time specification */
X			ttformat = optarg;
X			break;
X		case 'f':	/* Format specification */
X			format = optarg;
X			break;
X		case 'q':	/* Names for english file mode descriptions */
X			parsenames(optarg, modename, 24, "mode");
X			break;
X		case 'y':	/* Names for file type descriptions */
X			parsenames(optarg, typename, 7, "type");
X			break;
X		case '?':
X		default:
X			errflg++;
X			break;
X		}
X	if (errflg || optind >= argc) {
X		fprintf(stderr, "usage: %s [-f format] [-t date_format]file ...\n", progname);
X		exit(2);
X	}
X
X	gettimeofday(&time, &zone);
X	currclock = time.tv_sec;
X	halfyearago = currclock - 365L * 24L * 60L * 60L / 2L;
X	if (gflag)
X		currtime = *gmtime(&time.tv_sec);
X	else
X		currtime = *localtime(&time.tv_sec);
X	for (; optind < argc; optind++)
X		process(argv[optind]);
X	exit(0);
X}
X
X/*
X * List the mode of a file a la ls
X */
X#ifdef __GCC__
Xinline
X#endif
Xstatic void
Xlsmode(mode)
X	unsigned short mode;
X{
X	if ((mode & S_IFMT) == S_IFDIR)
X		putchar('d');
X	else if ((mode & S_IFMT) == S_IFBLK)
X		putchar('b');
X	else if ((mode & S_IFMT) == S_IFCHR)
X		putchar('c');
X#ifdef S_IFLNK
X	else if ((mode & S_IFMT) == S_IFLNK)
X		putchar('l');
X#endif
X#ifdef S_IFIFO
X	else if ((mode & S_IFMT) == S_IFIFO)
X		putchar('p');
X#endif
X#ifdef S_IFSOCK
X	else if ((mode & S_IFMT) == S_IFSOCK)
X		putchar('s');
X#endif
X	else
X		putchar('-');
X	putchar((mode & (S_IREAD >> 0)) ? 'r' : '-');
X	putchar((mode & (S_IWRITE >> 0)) ? 'w' : '-');
X	if (mode & S_ISUID)
X		putchar((mode & (S_IEXEC >> 0)) ? 's' : 'S');
X	else
X		putchar((mode & (S_IEXEC >> 0)) ? 'x' : '-');
X	putchar((mode & (S_IREAD >> 3)) ? 'r' : '-');
X	putchar((mode & (S_IWRITE >> 3)) ? 'w' : '-');
X	if (mode & S_ISGID)
X		putchar((mode & (S_IEXEC >> 3)) ? 's' : 'S');
X	else
X		putchar((mode & (S_IEXEC >> 3)) ? 'x' : '-');
X	putchar((mode & (S_IREAD >> 6)) ? 'r' : '-');
X	putchar((mode & (S_IWRITE >> 6)) ? 'w' : '-');
X	if (mode & S_ISVTX)
X		putchar((mode & (S_IEXEC >> 3)) ? 't' : 'T');
X	else
X		putchar((mode & (S_IEXEC >> 3)) ? 'x' : '-');
X}
X
X#define optform(x) (form[1]?form:(x))
Xstatic char form[512] = "%";
X
X/*
X * Print time using the time format
X */
Xstatic
Xtimef(clock, format)
X	long clock;
X	char *format;
X{
X	struct tm *t;
X	char c, *p, *fp;
X	static char *weekday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
X	static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
X
X	if (gflag)
X		t = gmtime(&clock);
X	else
X		t = localtime(&clock);
X	for (p = format; *p; p++) {
X		c = *p;
X		if (c != '%')
X			putchar(c);
X		else {
X			fp = form + 1;
X			p++;
X			if (*p == '(') {
X				p++;
X				while (*p && *p != ')')
X					*fp++ = *p++;
X				if (*p)
X					p++;
X			}
X			*fp = 0;
X			switch (*p) {
X			case 'm':
X				printf(optform("%d"), t->tm_mon + 1);
X				break;
X			case 'd':
X				printf(optform("%d"), t->tm_mday);
X				break;
X			case 'y':
X				printf(optform("%d"), t->tm_year+1900);
X				break;
X			case 'Y':
X				if (clock < halfyearago)
X					printf(optform("%d"), t->tm_year+1900);
X				break;
X			case 'H':
X				printf(optform("%d"), t->tm_hour);
X				break;
X			case 'M':
X				printf(optform("%d"), t->tm_min);
X				break;
X			case 'T':
X				if (clock >= halfyearago)
X					printf("%02d:%02d", t->tm_hour, t->tm_min);
X				break;
X			case 'S':
X				printf(optform("%d"), t->tm_sec);
X				break;
X			case 'j':
X				printf(optform("%d"), t->tm_yday);
X				break;
X			case 'w':
X				printf(optform("%d"), t->tm_wday);
X				break;
X			case 'a':
X				printf(optform("%s"), weekday[t->tm_wday]);
X				break;
X			case 'h':
X				printf(optform("%s"), month[t->tm_mon]);
X				break;
X#ifdef sun
X			case 'z':
X				printf(optform("%s"), t->tm_gmtoff);
X				break;
X			case 'Z':
X				printf(optform("%s"), t->tm_zone);
X				break;
X#endif
X			case 'D':
X				printf(optform("%s"), t->tm_isdst ? "DST" : "");
X				break;
X			case 't':
X				printf("%02d%02d%02d%02d%02d", t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_year);
X				break;
X			default :
X				putchar(*p);
X				break;
X			}
X		}
X	}
X}
X
X/*
X * process - process input file
X */
Xstatic void
Xprocess(inname)
X	char *inname;
X{
X	struct stat statbuf;
X	struct group *grp, *getgrgid();
X	struct passwd *pwd, *getpwuid();
X	int uid = -10, gid = -10;			/* Cached */
X	char *pw_name, *gr_name;
X	char *p, c, *fp, *ctime();
X	int i, j;
X	int Lprinted = 0;
X
X	if (STREQ(inname, "-")) {
X		if (fstat(0, &statbuf) < 0) {
X			error("can't fstat `%s'", inname);
X			return;
X		}
X	} else {
X		if (lflag) {
X			if (stat(inname, &statbuf) < 0) {
X				error("can't stat `%s'", inname);
X				return;
X			}
X		} else {
X			if (lstat(inname, &statbuf) < 0) {
X				error("can't lstat `%s'", inname);
X				return;
X			}
X		}
X	}
X
X	for (p = format; *p; p++) {
X		c = *p;
X		if (c != '%')
X			putchar(c);
X		else {
X			fp = form + 1;
X			p++;
X			if (*p == '(') {
X				p++;
X				while (*p && *p != ')')
X					*fp++ = *p++;
X				if (*p)
X					p++;
X			}
X			*fp = 0;
X			switch (*p) {
X			case 'v':
X				printf(optform("%d"), statbuf.st_dev);
X				break;
X			case 'i':
X				printf(optform("%lu"), statbuf.st_ino);
X				break;
X			case 'p':
X				printf(optform("%o"), statbuf.st_mode);
X				break;
X			case 'P':
X				lsmode(statbuf.st_mode);
X				break;
X			case 'l':
X				printf(optform("%d"), statbuf.st_nlink);
X				break;
X			case 'u':
X				printf(optform("%d"), statbuf.st_uid);
X				break;
X			case 'g':
X				printf(optform("%d"), statbuf.st_gid);
X				break;
X			case 'U':
X				if (uid != statbuf.st_uid) {
X					if (pwd = getpwuid(statbuf.st_uid))
X						pw_name = pwd->pw_name;
X					else
X						pw_name = "[UNKOWN]";
X				}
X				printf(optform("%s"), pw_name);
X				break;
X			case 'G':
X				if (gid != statbuf.st_gid) {
X					if (grp = getgrgid(statbuf.st_gid))
X						gr_name = grp->gr_name;
X					else
X						gr_name = "[UNKOWN]";
X				}
X				printf(optform("%s"), gr_name);
X				break;
X			case 'r':
X				printf(optform("%d"), statbuf.st_rdev);
X				break;
X			case 's':
X				printf(optform("%ld"), statbuf.st_size);
X				break;
X			case 'a':
X				printf(optform("%ld"), statbuf.st_atime);
X				break;
X			case 'm':
X				printf(optform("%ld"), statbuf.st_mtime);
X				break;
X			case 'c':
X				printf(optform("%ld"), statbuf.st_ctime);
X				break;
X			case 't':
X				printf(optform("%ld"), currclock);
X				break;
X			case 'A':
X				timef(statbuf.st_atime, taformat);
X				break;
X			case 'M':
X				timef(statbuf.st_mtime, tmformat);
X				break;
X			case 'C':
X				timef(statbuf.st_ctime, tcformat);
X				break;
X			case 'T':
X				timef(currclock, ttformat);
X				break;
X#ifndef AIX
X			case 'z':
X				printf(optform("%ld"), statbuf.st_blksize);
X				break;
X			case 'b':
X				printf(optform("%ld"), statbuf.st_blocks);
X				break;
X#endif
X			case 'n':
X				printf(optform("%s"), inname);
X				break;
X			case 'f':
X#ifdef S_IFLNK
X				if ((statbuf.st_mode & S_IFMT) == S_IFLNK && Lprinted)
X					break;
X#endif
X				if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
X					putchar('/');
X#ifdef S_IFLNK
X				else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
X					putchar('@');
X#endif
X#ifdef S_IFSOCK
X				else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
X					putchar('=');
X#endif
X				else if (statbuf.st_mode & (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6)))
X					putchar('*');
X				else
X					putchar(' ');
X				break;
X			case 'F':
X				if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
X					printf(optform("%s"), "S_IFDIR");
X				else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
X					printf(optform("%s"), "S_IFBLK");
X				else if ((statbuf.st_mode & S_IFMT) == S_IFCHR)
X					printf(optform("%s"), "S_IFCHR");
X#ifdef S_IFLNK
X				else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
X					printf(optform("%s"), "S_IFLNK");
X#endif
X#ifdef S_IFIFO
X				else if ((statbuf.st_mode & S_IFMT) == S_IFIFO)
X					printf(optform("%s"), "S_IFIFO");
X#endif
X#ifdef S_IFSOCK
X				else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
X					printf(optform("%s"), "S_IFSOCK");
X#endif
X				else if ((statbuf.st_mode & S_IFMT) == S_IFREG)
X					printf(optform("%s"), "S_IFREG");
X				else
X					printf(optform("%s"), "");
X				break;
X			case 'Y':
X				if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
X					printf(optform("%s"), typename[0]);
X				else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
X					printf(optform("%s"), typename[1]);
X				else if ((statbuf.st_mode & S_IFMT) == S_IFCHR)
X					printf(optform("%s"), typename[2]);
X#ifdef S_IFLNK
X				else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
X					printf(optform("%s"), typename[3]);
X#endif
X#ifdef S_IFIFO
X				else if ((statbuf.st_mode & S_IFMT) == S_IFIFO)
X					printf(optform("%s"), typename[4]);
X#endif
X#ifdef S_IFSOCK
X				else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
X					printf(optform("%s"), typename[5]);
X#endif
X				else if ((statbuf.st_mode & S_IFMT) == S_IFREG)
X					printf(optform("%s"), typename[6]);
X				else
X					printf(optform("%s"), "");
X				break;
X			case 'q':
X				for (i = 0400; i; i >>= 1)
X					if (statbuf.st_mode & i)
X						printf(optform("%s"), "1");
X					else
X						printf(optform("%s"), "0");
X				break;
X			case 'Q':
X#ifdef S_IFLNK
X				if ((statbuf.st_mode & S_IFMT) == S_IFLNK && ! lflag)
X					break;
X#endif
X				if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
X					j = 12;
X				else
X					j = 0;
X				for (i = 04000; i; i >>= 1, j++)
X					if (statbuf.st_mode & i)
X						printf(optform("%s"), modename[j]);
X				break;
X#ifdef S_IFLNK
X			case 'L':
X				if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
X					int len;
X					char buf[MAXPATHLEN];
X
X					if ((len = readlink(inname, buf, MAXPATHLEN)) == -1) {
X						error("can't readlink `%s'", inname);
X						break;
X					}
X					buf[len] = 0;
X					printf(optform("%s"), buf);
X					Lprinted = 1;
X				} else 
X					printf(optform("%s"), "");
X				break;
X			case '-':
X				if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
X					fputs(" -> ", stdout);
X					Lprinted = 1;
X				}
X				break;
X#endif
X			default :
X				putchar(c);
X				break;
X			}
X		}
X	}
X	putchar('\n');
X}
X
X/*
X * error - report trouble
X */
Xstatic void				/* does not return */
Xerror(s1, s2)
X	char *s1, *s2;
X{
X	extern int sys_nerr, errno;
X	extern char *sys_errlist[];
X
X	fprintf(stderr, "%s: ", progname);
X	fprintf(stderr, s1, s2);
X	if( errno && errno <= sys_nerr )
X		fprintf(stderr, " (%s)", sys_errlist[errno]);
X	putc('\n', stderr);
X	if (eflag)
X		exit(1);
X}
X
X/*
X * mkprogname - convert string to a meaningful program name
X * May change the string
X */
Xchar *
Xmkprogname(s)
X	char *s;
X{
X	char *p, *p2;
X	char *unkown="[unkown]";
X
X	if (!s || !*s)
X		return unkown;
X	p = s;
X	if ((p2 = strrchr(s, '/')) > p)		/* Check for path */
X		p = p2+1;
X#ifdef MSDOS
X	if ((p2 = strrchr(s, '\\')) > p)	/* Check for backslash path */
X		p = p2+1;
X	if ((p2 = strrchr(s, ':')) > p)		/* Check for drive spec */
X		p = p2+1;
X	if ((p2 = strrchr(s, '.')) > p)		/* Check for extension */
X		*p2=0;
X	for (p2=p; *p2; p2++)			/* Make it lowercase */
X		if (isascii(*p2) && isupper(*p2))
X			*p2 = tolower(*p2);
X#endif
X	if (*p)
X		return p;
X	else
X		return unkown;
X}
X
Xchar *modename[] = {				/* File mode english names */
X	"run with id of the owner ",
X	"run with id of the group ",
X	"stay in swap space on termination ",
X	"owner can read ",
X	"owner can change ",
X	"owner can execute ",
X	"group can read ",
X	"group can change ",
X	"group can execute ",
X	"anyone can read ",
X	"anyone can change ",
X	"anyone can execute ",
X	"",
X	"files inherit group ",
X	"only owners can delete files ",
X	"owner can read ",
X	"owner can change ",
X	"owner can access ",
X	"group can read ",
X	"group can change ",
X	"group can access ",
X	"anyone can read ",
X	"anyone can change ",
X	"anyone can access ",
X};
X
X/* File type english names */
Xchar *typename[] = {
X	"Directory",
X	"Block special",
X	"Character special",
X	"Symbolic link",
X	"Named pipe",
X	"Socket",
X	"Regular file",
X};
X
X/*
X * Convert a separator terminated list of strings starting with the
X * terminator to an array.  The strings should be exactly number else
X * an error is printed.
X */
Xstatic void
Xparsenames(names, array, number, errname)
X	char *names, *errname;
X	char *array[];
X	int number;
X{
X	char term = *names;
X	char *p, *p2;
X	int count = 0;
X
X	for (p = p2 = names + 1; *p ; p++)
X		if (*p == term) {
X			array[count++] = p2;
X			*p++ = 0;
X			p2 = p;
X			if (count > number)
X				break;
X		}
X	if (count != number) {
X		fprintf(stderr, "%s: expected %d arguments to specify file %s, got %d\n", progname, number, errname, count);
X		exit(1);
X	}
X}
SHAR_EOF
if test 14832 -ne "`wc -c < 'stat.c'`"
then
	echo shar: error transmitting "'stat.c'" '(should have been 14832 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
--
Diomidis Spinellis                  Internet:                 dds@cc.ic.ac.uk
Department of Computing             UUCP:                    ...!ukc!iccc!dds
Imperial College                    JANET:                    dds@uk.ac.ic.cc
London SW7 2BZ                      #include "/dev/tty"



Newsgroup comp.sources.misc contents
Newsgroup list
Diomidis Spinellis home page

Creative Commons License Unless otherwise expressly stated, all original material on this page created by Diomidis Spinellis is licensed under a Creative Commons Attribution-Share Alike 3.0 Greece License.