From decwrl!elroy.jpl.nasa.gov!usc!zaphod.mps.ohio-state.edu!uakari.primate.wisc.edu!aplcen!uunet!allbery Tue Mar  6 16:44:09 PST 1990
Article 1369 of comp.sources.misc:
Path: decwrl!elroy.jpl.nasa.gov!usc!zaphod.mps.ohio-state.edu!uakari.primate.wisc.edu!aplcen!uunet!allbery
From: rsk@oldfield.CS.ColoState.Edu (Rich Kulawiec)
Newsgroups: comp.sources.misc
Subject: v10i097: Another (two more!) version(s) of stat(1)
Message-ID: <80574@uunet.UU.NET>
Date: 6 Mar 90 23:39:15 GMT
Sender: allbery@uunet.UU.NET
Lines: 960
Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)

Posting-number: Volume 10, Issue 97
Submitted-by: rsk@oldfield.CS.ColoState.Edu (Rich Kulawiec)
Archive-name: two-stats/part01

Sure bears an amazing similarity to the enclosed...which includes
two versions of stat.  The first was a rewrite by me of an old version
written at Purdue around 1980 by either Phil Hochstetler or Craig Strickland;
it's unclear which -- which is why neither name appears on the code.
Neither has ever claimed responsibility :-) (I've asked them)
so I don't think they care.  Anyway, this version includes credit for
those who contributed fixes and enhancements.  It was first posted sometime
around 1985.

Also enclosed is a second version, which I received in response to my
posting on Usenet; it's by Richard Hellier, and includes command-line
flags to control the formatting of the output.  It was also posted in 1985.

I found the recently-posted version of stat greatly resembled Hellier's;
although a straight "diff" of the code doesn't look that close, a
careful read-through show large sections which seem very much the
same to me.

---Rsk

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./stat.c`
then
echo "writing ./stat.c"
cat > ./stat.c << '\End\Of\Shar\'

#ifndef lint
static char *rcsid = "$Header: $";
#endif lint

/*
 *	Stat.c		Dump out inode info in nice form.
 *			Original version by someone at Purdue in the days of v6;
 *			this one by Rsk for modern times.
 *
 *			Various enhancements and bugs fixes to this version
 *			by Bill Stoll, Stan Barber, William J. Bogstad,
 *			Michael MacKenzie.
 *
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>

#define	FAIL	-1		/* Failure return code from call */	
#define OKAY	0		/* Success return code from call */

struct 	stat	Sbuf;		/* for return values from stat() call */
char	*ctime();		/* Time conversion	*/
struct	passwd	*getpwuid();	/* User entry */
struct	passwd	*pwent;		/* User structure */
struct	group	*getgrgid();	/* Group entry */
struct	group	*grent;		/* Group structure */

char	Mode[10];	/* File protection mode */

#define	LBUFSIZ	256	/* Length for symbolic link translation buffer */
char	Lbuf[LBUFSIZ];	/* Symbolic link translation buffer */

int
main(argc, argv)
int argc;
char *argv[];
{
	register int i;

	i = 1;

	if(argc == 1) {
		(void) fprintf(stderr,"Usage: stat file1 [file2 ...]\n");
		exit(1);
	}

	do {
		(void) stat_it(argv[i]);

		if(  (argc > 1) && (i < (argc-1)) )
			(void) printf("\n");
	}
	while(++i < argc);

	exit(0);
}

/*
 * stat_it() - Actually stat and format results from file.
 *		exit -    OKAY if no problems encountered
 *			  FAIL if couldn't open or other nastiness
 *
 */
stat_it(filename)
char	*filename;
{
	register int count;

#ifdef S_IFLNK
	if( lstat(filename,&Sbuf) == FAIL) {
		(void) fprintf(stderr,"Can't lstat %s\n",filename); 
		return(FAIL);
	}
#else S_IFLNK
	if( stat(filename,&Sbuf) == FAIL) {
		(void) fprintf(stderr,"Can't stat %s\n",filename); 
		return(FAIL);
	}
#endif S_IFLNK

#ifdef S_IFLNK
	if( (Sbuf.st_mode & S_IFMT) == S_IFLNK) {
		if( (count = readlink(filename,Lbuf,LBUFSIZ)) == FAIL) {
			(void) fprintf(stderr,"Can't readlink %s\n", filename);
			return(FAIL);
		}
		if( count < LBUFSIZ)
			Lbuf[count] = '\0';
		(void) printf("    Name: \"%s\" -> \"%s\"\n",filename,Lbuf);
	} else {
#endif S_IFLNK
		(void) printf("     Name: \"%s\"\n", filename);

		(void) printf("     Size: %-10ld\n", Sbuf.st_size);

#ifdef S_IFLNK
		(void) printf("   Blocks: %-10ld\n", Sbuf.st_blocks);
#endif S_IFLNK
	}

	print_type();

	print_mode();

	print_ug();


	(void) printf("Major/Minor   Device: %2d,%-2d\n", major(Sbuf.st_dev), minor(Sbuf.st_dev));
	(void) printf("    Inode: %-10d\n", Sbuf.st_ino);
	(void) printf("    Links: %-5d", Sbuf.st_nlink);

	/* Only meaningful if file is device */

	if(  ( (Sbuf.st_mode & S_IFMT) == S_IFCHR)
	    || ( (Sbuf.st_mode & S_IFMT) == S_IFBLK) ) {
		(void) printf("\nDevice Type/Number: %2d,%-2d\n",
			major(Sbuf.st_rdev), minor(Sbuf.st_rdev));
	} else {
		(void) printf("\n");
	}
/*
 	printf("Optimal Blocksize: %ld\n", Sbuf.st_blksize);
*/

	/* The %.24s strips the newline from the ctime() string */

	(void) printf("   Access: %s",ctime(&Sbuf.st_atime));
	(void) printf("   Modify: %s",ctime(&Sbuf.st_mtime));
	(void) printf("   Change: %s",ctime(&Sbuf.st_ctime));

	return(OKAY);
}

print_type()
{
	(void) printf("     Type: ");

	switch( Sbuf.st_mode & S_IFMT) {
	case	S_IFREG:	
		(void) printf("Regular File\n");
		break;
	case	S_IFDIR:	
		(void) printf("Directory\n");
		break;
	case	S_IFCHR:	
		(void) printf("Character Device\n");
		break;
	case	S_IFBLK:	
		(void) printf("Block Device\n");
		break;
#ifdef S_IFLNK
	case	S_IFLNK:	
		(void) printf("Symbolic Link\n");
		break;
#endif S_IFLNK
#ifdef S_IFSOCK
	case	S_IFSOCK:	
		(void) printf("Socket\n");
		break;
#endif S_IFSOCK
#if (S_IFIFO | S_IFPORT)
	case	S_IFIFO:	
		(void) printf("Fifo (Named Pipe) File\n");
		break;
#endif (S_IFIFO | S_IFPORT)
#ifdef S_IFCTG
	case	S_IFCTG:	
		(void) printf("Contiguous File\n");
		break;
#endif S_IFCTG
#ifdef S_IFMPC
	case	S_IFMPC:
		(void) printf("Multiplexed Character Special\n");
		break;
#endif S_IFMPC
#ifdef S_IFMPB
	case	S_IFMPB:
		(void) printf("Multiplexed Block Special\n");
		break;
#endif S_IFMPB
	default		:	
		(void) printf("Unknown\n");
	}
}

print_mode()
{
	(void) strcpy(Mode,"----------");
	if(Sbuf.st_mode & (S_IEXEC>>6))		/* Other execute */
		Mode[9] = 'x';
	if(Sbuf.st_mode & (S_IWRITE>>6))	/* Other write */
		Mode[8] = 'w';
	if(Sbuf.st_mode & (S_IREAD>>6))		/* Other read */
		Mode[7] = 'r';
	if(Sbuf.st_mode & (S_IEXEC>>3))		/* Group execute */
		Mode[6] = 'x';
	if(Sbuf.st_mode & (S_IWRITE>>3))	/* Group write */
		Mode[5] = 'w';
	if(Sbuf.st_mode & (S_IREAD>>3))		/* Group read */
		Mode[4] = 'r';
	if(Sbuf.st_mode & S_IEXEC)		/* User execute */
		Mode[3] = 'x';
	if(Sbuf.st_mode & S_IWRITE)		/* User write */
		Mode[2] = 'w';
	if(Sbuf.st_mode & S_IREAD)		/* User read */
		Mode[1] = 'r';
	if(Sbuf.st_mode & S_ISVTX)		/* Sticky bit */
		Mode[9] = 't';
	if(Sbuf.st_mode & S_ISGID)		/* Set group id */
		Mode[6] = 's';
	if(Sbuf.st_mode & S_ISUID)		/* Set user id */
		Mode[3] = 's';
	switch( Sbuf.st_mode & S_IFMT) {
	case	S_IFDIR:	
		Mode[0] = 'd';
		break;
	case	S_IFCHR:	
		Mode[0] = 'c';
		break;
	case	S_IFBLK:	
		Mode[0] = 'b';
		break;
	case	S_IFREG:	
		Mode[0] = '-';
		break;
#ifdef S_IFLNK
	case	S_IFLNK:	
		Mode[0] = 'l';
		break;
#endif S_IFLNK
#ifdef S_IFSOCK
	case	S_IFSOCK:	
		Mode[0] = 's';
		break;
#endif S_IFSOCK
#ifdef S_IFIFO
	case	S_IFIFO:	
#ifdef SYSV
		Mode[0] = 'f';
#else SYSV
		Mode[0] = 'p';
		break;
#endif SYSV
#endif S_IFIFO
#ifdef S_IFCTG
	case	S_IFCTG:	
		Mode[0] = 'C';
		break;
#endif S_IFCTG
	default		:	
		Mode[0] = '?';
	}

	(void) printf("     Mode: %s (%04o) %s \n", Mode,Sbuf.st_mode&07777);
}

print_ug()
{
	(void) setpwent();
	if( (pwent = getpwuid(Sbuf.st_uid)) == NULL) {
		(void) fprintf(stderr,"getpwuid() failed\n");
		exit(1);
	}
	(void) printf("    Owner: %s (%d)\n", pwent->pw_name,Sbuf.st_uid);

	(void) setgrent();
	if( (grent = getgrgid(Sbuf.st_gid)) == NULL) {
		(void) fprintf(stderr,"getgrgid() failed\n");
		exit(1);
	}
	(void) printf("    Group: %s (%d)\n", grent->gr_name,Sbuf.st_gid);
}
\End\Of\Shar\
else
  echo "will not over write ./stat.c"
fi
if `test ! -s ./stat.1`
then
echo "writing ./stat.1"
cat > ./stat.1 << '\End\Of\Shar\'
.TH stat 1
.UC 4
.SH NAME
stat \- print inode contents
.SH SYNOPSIS
.B stat
.I filename
.I [filenames ... ]
.SH DESCRIPTION
.PP
.I Stat
prints out the contents of an inode as they appear to \fIstat(2)\fR
in a human-readable format.
.PP
Here is a sample output from \fIstat\fR:
.nf
  File: "/"
  Size: 1024         Allocated Blocks: 2            Filetype: Directory
  Mode: (0755/drwxr-xr-x)         Uid: (    0/    root)  Gid: (    0/  system)
Device:  0,0   Inode: 2         Links: 20   
Access: Wed Jan  8 12:40:16 1986(00000.00:00:01)
Modify: Wed Dec 18 09:32:09 1985(00021.03:08:08)
Change: Wed Dec 18 09:32:09 1985(00021.03:08:08)
.fi
.PP
.SH FILES
.SH "SEE ALSO"
stat(2), ls(1)
.SH DIAGNOSTICS
"Can't stat file" or "Can't lstat file" usually means that it doesn't exist.
"Can't readlink file" implies something is amiss with a symbolic link.
.SH BUGS
The output is still not entirely comprehensible.
\End\Of\Shar\
else
  echo "will not over write ./stat.1"
fi
if `test ! -s ./stat.fmt`
then
echo "writing ./stat.fmt"
cat > ./stat.fmt << '\End\Of\Shar\'
>From iuvax!seismo!mcvax!ukc!rlh@purdue Wed Oct 23 08:31:31 1985
Received: from pucc-k (pucc-k.ARPA) by pucc-j; Wed, 23 Oct 85 08:31:20 est
Received: from pucc-i (pucc-i.ARPA) by pucc-k; Wed, 23 Oct 85 08:31:02 est
Received: from pucc-h (pucc-h.ARPA) by pucc-i; Wed, 23 Oct 85 08:31:07 est
Received: by pucc-h; Wed, 23 Oct 85 08:30:48 est
Received: by pur-phy.UUCP; Wed, 23 Oct 85 08:08:11 EST
Date: Thu Oct 17 19:53:35 1985
Received: by arthur.Purdue.EDU; Thu, 17 Oct 85 19:53:35 EST
Received: by iuvax.UUCP; id AA10429; Thu, 17 Oct 85 19:46:07 est
Received: from mcvax.UUCP by seismo.CSS.GOV with UUCP; Thu, 17 Oct 85 19:36:53 EDT
Received: by mcvax.UUCP; Thu, 17 Oct 85 21:24:39 +0100 (MET)
Received: by mcvax.UUCP; Thu, 17 Oct 85 21:24:21 +0100 (MET)
Message-Id: <8510172024.AA14429@mcvax.UUCP>
Date: Thu, 17 Oct 85 19:33:06 BST
From: Richard Hellier <iuvax!seismo!mcvax!ukc!rlh@purdue>
To: rsk@pucc-k
Subject: Your stat program
Status: R

	I found your stat code very handy but needed a way to customize
its output.  What I did was to add a printf-like format argument (-f fmt)
so that individual fields can be picked out.

	Anyway, here's my version -- hope it's of use to you.

			Richard.

#ifndef lint
static char *sccsid = "@(#)stat.c	1.3 (UKC) 17/10/85";
#endif  lint
/***

* program name:
	stat
* function:
	Display the contents of an i-node.
* switches:
	-f fmt	Display the i-node according to the format characters
		in "fmt".  Syntax is like that of printf(3s) with the
		following formatting characters:-
		%f		File type.
		%d		Device inode lives on.
		%i		Inode itself.
		%p		Protection bits.
		%l		# of links.
		%u		The user id
		%g		The group id.
		%t		Type of device.
		%s		Total size of file.
		%a		Access time.
		%m		Modified time.
		%c		Status change time.
		%b		# of blocks allocated.
* libraries used:
	standard + getopt
* compile time parameters:
	cc -O -o stat stat.c -lgetopt
* history:
	pur-ee!pucc-j!rsk, rsk@purdue-asc.arpa
	Original version by Hoch in the dark days of v6;
	this one by Rsk for 4.2 BSD.

***/

		/*
		 *	System - wide header files
		 */

#include	<stdio.h>
#include	<sys/time.h>
#include	<sys/types.h>
#include	<ctype.h>
#include	<sys/stat.h>
#include	<pwd.h>
#include	<grp.h>

			/*
			 *	Global structures and definitions
			 */


#define	FAIL	-1		/* Failure return code from call */	
#define OKAY	0		/* Success return code from call */

char	*fmt_str;		/* Format string for displaying i-nodes */

char	*progname;		/* Name we're called as */

/*
**  STAT_IT -- Display an i-node.
**
**	Print the contents of an i-node.
**
**	Parameters:
**		ip    --  Reference to a stat structure.
**
**	Returns:
**		None.
**
**	Notes:
**		None.
**
*/

stat_it(filename)
char	*filename;
{
	int		count;
	char		buf [BUFSIZ];
	struct 	stat	Sbuf;		/* for return values from stat() call */
#define	LBUFSIZ		256	/* Length of symbolic link translation buffer */
	char		Lbuf [LBUFSIZ];	/* Symbolic link translation buffer */

	if( lstat(filename,&Sbuf) == FAIL) {
		fprintf(stderr,"Can't lstat %s\n",filename); 
		return(FAIL);
	}

	if( (Sbuf.st_mode & S_IFMT) == S_IFLNK) {
		if( (count = readlink(filename, Lbuf, sizeof Lbuf)) == FAIL) {
			fprintf(stderr, "Can't readlink %s\n", filename);
			return(FAIL);
		}
		if( count < LBUFSIZ)
			Lbuf[count] = '\0';
		printf("  File: \"%s\" -> \"%s\"\n", filename, Lbuf);
	} else
		printf("  File: \"%s\"\n", filename);


	FmtInode(buf, fmt_str, &Sbuf);

	printf("%s\n", buf);

	return(OKAY);
}

/*
**  UTOS  -- Uid to string mapping
**
**	Return the login of the given
**	uid.
**
**	Parameters:
**		buf    --  Buffer to fill,
**		ip     --  Reference to a stat structure.
**
**	Returns:
**		None.
**
**	Notes:
**		None.
**
*/

UtoS(buf, ip)
char		buf [];
struct stat	*ip;
{
	struct passwd	*pwent;
	extern struct passwd	*getpwuid();

	(void) setpwent();
	if ((pwent = getpwuid(ip -> st_uid)) == NULL) {
		fprintf(stderr, "getpwuid() failed\n");
		exit(1);
	}
	sprintf(buf, "%5d/%8s",
		ip -> st_uid,
		pwent->pw_name);
}
/*
**  GTOS -- Group to string mapping
**
**	Given a numeric group-id, return
**	the ASCII name of that group.
**
**	Parameters:
**		buf    --  Buffer to fill,
**		ip      --  Reference to a stat structure.
**
**	Returns:
**		None.
**
**	Notes:
**		None.
**
*/

GtoS(buf, ip)
char		buf [];
struct stat	*ip;
{
	struct group	*grent;
	extern struct group	*getgrid();

	(void) setgrent();
	if( (grent = getgrgid(ip -> st_gid)) == NULL) {
		fprintf(stderr, "getgrgid() failed\n");
		exit(1);
	}
	sprintf(buf, "%5d/%8s",
		ip -> st_gid,
		grent -> gr_name);
}

/*
** DEVTOS --  Device to string mapping
**
**	Return a string containing the type
**	of the device, if the file is a device.
**	Else return a null string.
**
**	Parameters:
**		buf    --  Buffer to fill,
**		ip      --  Reference to a stat structure.
**
**	Returns:
**		None.
**
**	Notes:
**		None.
**
*/

DevToS(buf, ip)
char		buf [];
struct stat	*ip;
{
	if ((ip -> st_mode & S_IFMT) == S_IFCHR
	|| (ip -> st_mode & S_IFMT) == S_IFBLK)
		sprintf(buf, "Device Type: %d", ip -> st_rdev);
	else
		strcpy(buf, "");
}
/*
**  MODETOS -- Mode word to string mapping
**
**	Display the contents of the mode field
**	in a readable format.
**
**	Parameters:
**		buf    --  Buffer to write on,
**		mode   --  Mode field to interpret.
**
**	Returns:
**		None.
**
**	Notes:
**		None.
**
*/

ModeToS(buf, ip)
char		buf [];
struct stat	*ip;
{
	sprintf(buf, "%04o/----------", ip -> st_mode & 07777);

	if(ip -> st_mode & 0000001)	/* Other execute */
		buf[5 + 9] = 'x';
	if(ip -> st_mode & 0000002)	/* Other write */
		buf[5 + 8] = 'w';
	if(ip -> st_mode & 0000004)	/* Other read */
		buf[5 + 7] = 'r';
	if(ip -> st_mode & 0000010)	/* Group execute */
		buf[5 + 6] = 'x';
	if(ip -> st_mode & 0000020)	/* Group write */
		buf[5 + 5] = 'w';
	if(ip -> st_mode & 0000040)	/* Group read */
		buf[5 + 4] = 'r';
	if(ip -> st_mode & 0000100)	/* User execute */
		buf[5 + 3] = 'x';
	if(ip -> st_mode & 0000200)	/* User write */
		buf[5 + 2] = 'w';
	if(ip -> st_mode & 0000400)	/* User read */
		buf[5 + 1] = 'r';
	if(ip -> st_mode & 0001000)	/* Sticky bit */
		buf[5 + 9] = 't';
	if(ip -> st_mode & 0002000)	/* Set group id */
		buf[5 + 6] = 's';
	if(ip -> st_mode & 0004000)	/* Set user id */
		buf[5 + 4] = 's';
	switch( ip -> st_mode & S_IFMT) {
		case	S_IFDIR:	buf[5 + 0] = 'd';
					break;
		case	S_IFCHR:	buf[5 + 0] = 'c';
					break;
		case	S_IFBLK:	buf[5 + 0] = 'b';
					break;
		case	S_IFREG:	buf[5 + 0] = '-';
					break;
		case	S_IFLNK:	buf[5 + 0] = 'l';
					break;
		case	S_IFSOCK:	buf[5 + 0] = 's';
					break;
		default		:	buf[5 + 0] = '?';
	}
}
/*
**  TYPETOS -- Filetype to string mapping
**
**	Given a filetype, return a string
**	representation of that type.
**
**	Parameters:
**		buf    --  Buffer to fill,
**		ip     --  Reference to a stat structure.
**
**	Returns:
**		None.
**
**	Notes:
**		None.
**
*/

TypeToS(buf, ip)
char		buf [];
struct stat	*ip;
{
	switch( ip -> st_mode & S_IFMT ) {
		case	S_IFDIR:
			strcpy(buf, "Directory");
			break;

		case	S_IFCHR:
			strcpy(buf, "Character Device");
			break;

		case	S_IFBLK:
			strcpy(buf, "Block Device");
			break;

		case	S_IFREG:
			strcpy(buf, "Regular File");
			break;

		case	S_IFLNK:
			strcpy(buf, "Symbolic Link");
			break;

		case	S_IFSOCK:
			strcpy(buf, "Socket");
			break;

		default:
			strcpy(buf, "Unknown");
			break;
	}
}
/*
**  FMT_APP -- Append a format string
**
**	Copy the first string argument
**	to the second, returning a pointer
**	to the next free byte.
**
**	Parameters:
**		src  --  Source string,
**		dest --  Destination string.
**
**	Returns:
**		Reference to the next free byte
**		in the destination string.
**
**	Notes:
**		This routine is auxiliary to
**		FmtInode() below.
**
*/

char	*
fmt_app(src, dest)
register char	*src,
		*dest;
{

	while ((*dest++ = *src++) != '\0')
		;	/* NULL BODY */

	return dest - 1;		/* Back over the NUL byte */
}


/*
**  FMTINODE -- Format an Inode
**
**	Build a textual representation of
**	the Inode into the specified buffer
**	according to the printf-like format
**	string.
**
**	Parameters:
**		buf  --  Buffer to fill,
**		fmt  --  Printf-like format string.
**		rp   --  Reference to Inode cell,
**
**	Returns:
**		None.
**
**
**	Notes:
**		The format characters recognised here are:
**
**	%f		File type.
**	%d		Device inode lives on.
**	%i		Inode itself.
**	%p		Protection bits.
**	%l		# of links.
**	%u		The user id
**	%g		The group id.
**	%t		Type of device.
**	%s		Total size of file.
**	%a		Access time.
**	%m		Modified time.
**	%c		Status change time.
**	%b		# of blocks allocated.
**
**	Use a backslash to 'hide' any special character, e.g. '%'
**
**	The default format string is:
**
**		"%r,,%u,%t,%o"
*/

FmtInode(buf, fmt, ip)
char		*buf,
		*fmt;
struct stat	*ip;
{
	char		auxbuf [64];
	register char	*bufp;
	register int	c;
	extern char	*ctime();

	for (bufp = buf; (c = *fmt++) != '\0'; ) {
		if (c == '\\')
			c = *fmt++;
		
		if (c != '%') {
			*bufp++ = c;
		} else {
			switch (c = *fmt++) {
				case 'f':	/* Filetype */
					TypeToS(auxbuf, ip);
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'i':	/* The actual Inode	*/
					sprintf(auxbuf, "%ld", ip -> st_ino);
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'd':	/* The Device	*/
					sprintf(auxbuf, "%ld", ip -> st_dev);
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 't':	/* Device Type */
					DevToS(auxbuf, ip);
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'p':	/* Protection bits */
					ModeToS(auxbuf, ip);
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'l':	/* # of links */
					sprintf(auxbuf, "%d", ip -> st_nlink);
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'u':	/* User id */
					UtoS(auxbuf, ip);
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'g':	/* Group id */
					GtoS(auxbuf, ip);
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 's':	/* Total size of file */
					sprintf(auxbuf, "%d", ip -> st_size);
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'a':	/* Access time */
					sprintf(auxbuf, "%24.24s", ctime(&ip -> st_atime));
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'm':	/* Modified time */
					sprintf(auxbuf, "%24.24s", ctime(&ip -> st_mtime));
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'c':	/* Status change time */
					sprintf(auxbuf, "%24.24s", ctime(&ip -> st_ctime));
					bufp = fmt_app(auxbuf, bufp);
					break;

				case 'b':	/* # of blocks allocated */
					sprintf(auxbuf, "%d", ip -> st_blocks);
					bufp = fmt_app(auxbuf, bufp);
					break;

				default:	/* Just copy it over */
					*bufp++ = c;
					break;
			}
		}
	}
}
/*
**  USAGE -- Display a reminder
**
**	Print a reminder of the correct usage
**	of the command.
**
**	Parameters:
**		None.
**
**	Returns:
**		None.
**
**	Notes:
**		None.
**
*/

Usage()
{
	fprintf(stderr, "Usage: %s [-f fmt] file1 file2 ...\n", progname);
}
main(argc, argv)
int argc;
char *argv[];
{
	extern int	optind;
	extern char	*optarg;
	int		c;


	/*
	 *	Note how we're called ...
	 */

	progname = argv [0];

	if (argc == 1) {
		Usage();
		exit(1);
	}

	/*
	 *	Set some defaults ...
	 */

	fmt_str = "  Size: %s\tAllocated Blocks: %b\tFiletype: %f\n  Mode: (%p)\tUid: (%u)	Gid: (%g)\nDevice: %d\tInode: %i\tLinks: %l\t%t\nAccess: %a\nModify: %m\nChange: %c\n";

	/*
	 *	Check for flag arguments ...
	 */

	while ((c = getopt(argc, argv, "f:")) != EOF)
		switch (c) {
			default:
				Usage();
				exit(1);

			case 'f':		/* Format specifier */
				fmt_str = optarg;
				break;
		}

	/*
	 *	Ok, now for the file arguments ...
	 */

	for (; optind < argc; ++optind) {
		stat_it(argv [optind]);
	}

	exit(0);
}
--
				Richard Hellier

				rlh@ukc.UUCP
				...!mcvax!ukc!rlh

			Phone:  +44 227 66822 xtn 7568

\End\Of\Shar\
else
  echo "will not over write ./stat.fmt"
fi
echo "Finished archive 1 of 1"
exit


