[comp.os.minix] More things I think should be in 1.3

nick@nswitgould.OZ (Nick Andrew) (06/20/88)

	I spent a little more time tonight working on Minix 1.3, and
found a few more things I'd like to be in the official release.  This
article includes some shar scripts interleaved with comments ... don't
just cut and run!

-1-	LS still has a problem with 14-character long names. You thought
that one was fixed in 1.2. Yes, mostly. The remaining bug happens when a
14 character filename is listed, AND the ascii value of the first character
of the inode integer in the next directory slot is a slash '/'.

	In other words, LS's print routine is prepared to print either a
pathname of indeterminate length (with slashes), or a single filename of
up to 14 characters long. Unfortunately if the first byte of the next
directory slot is a '/', the print loop gets confused and prints junk.

-2-	Andy distributed the 1.2 and 1.3 diffs with some "ls -l" listings
of the resulting directories. The only way to check that diffs have been
applied properly (apart from verifying the code by eye) is to match the
lengths of the files against Andy's listing. This is not very reliable.
Using context diffs and Patch would make things more reliable ... but its
not done yet, and anyway, I compiled the posted Patch (patchlevel 4) and
couldn't coerce it to patch a darn thing.  So anyhow I am taking the liberty
of reposting a program called VITALS, which calculates CRC, SUM, and other
info about given files. Checking the CRCs of resultant 1.3 files against
the CRC of Andy's masters is a helluvalot more reliable than comparing the
lengths.  Of course it isn't too good if people have made _any_ local changes
to the file .... but then how do you know the diff file has been applied
properly anyway?  Must check it by hand regardless.  Vitals comes with source
and a manual page, and I'm not the author (as the source plainly tells).

Shar follows...


echo x - vitals.c
gres '^X' '' > vitals.c << '/'
Xstatic char *HPUX_ID = "@(#)27.1   85/02/04";
X/* HPUX_ID: @(#)vitals.c	27.1     85/02/04  */
X/*
X * Compute vital statistics of data:  crc, sum, line, word, and character
X * counts.  See the manual entry for details.
X *
X * Compile with -DTABLE to produce an alternate program, which prints a
X * CRC table for use in this program.
X *
X * The CRC code was lifted from a USENET posting:
X *
X * hpfcla:net.sources / hcrvax!sft /  8:17 pm  Nov 15, 1984
X *
X * The following program is a command to calculate the CRC of files.
X * It is useful for the same purposes as sum(1).  It calculates the
X * true CRC16 (unlike CP/M utilities that say they calculate CRCs
X * but really just hash).  Crc detects more errors than old sum(1);
X * for example, it detects exchanges of characters.  It is also
X * (now) in the public domain.
X *
X *  CRC16 polynomial: x**0 + x**2 + x**15 + x**16 (0xA001)
X * (CCITT polynomial: x**0 + x**5 + x**12 + x**16 (0x8408))
X * Initial condition: 0
X *
X * D. Hugh Redelmeier, 1983 April 15; latest change: 1984 April 2.
X */
X
X
X#include <stdio.h>
X
Xchar	*USAGE = "usage: %s [-rslwcb] [files...]\n";
X
X#define	proc				/* null; easy to grep for procs */
X#define	chNull	   ('\0')
X#define	chNewline  ('\n')
X#define	sbNull	   ((char *) NULL)
X#define	fileNull   ((FILE *) NULL)
X#define	false	   0
X#define	true	   1
X
Xchar	*myname;				/* how command invoked	*/
Xint	rflag = false;				/* -r (crc) option	*/
Xint	sflag = false;				/* -s (sum) option	*/
Xint	lflag = false;				/* -l (lines) option	*/
Xint	wflag = false;				/* -w (words) option	*/
Xint	cflag = false;				/* -c (chars) option	*/
Xint	bflag = false;				/* -b (basenames) opt	*/
X
Xint	retval = 0;				/* return value		 */
Xchar	*defaultargs[] = {"-", sbNull};		/* read stdin by default */
X
X#define	PrintErr(part1,part2) \
X		fprintf (stderr, "%s: %s %s\n", myname, part1, part2);
X
X
X/************************************************************************
X * M A I N
X *
X * Initialize, check arguments, open files, and call another routine to
X * do each file.
X */
X
Xproc main (argc, argv)
Xregister int	argc;
Xregister char	**argv;
X{
Xextern	 int	optind;			/* for getopt()  */
X	 int	optchar;		/* from getopt() */
Xregister FILE	*filep;			/* file to read	 */
X
X#ifdef TABLE					/* just print table */
X	PrintTable();
X#else
X
X/*
X * CHECK ARGUMENTS:
X */
X
X	myname = *argv;
X
X	while ((optchar = getopt (argc, argv, "rslwcb")) != EOF)
X	    switch (optchar)
X	    {
X	    case 'r':	rflag = true;	break;
X	    case 's':	sflag = true;	break;
X	    case 'l':	lflag = true;	break;
X	    case 'w':	wflag = true;	break;
X	    case 'c':	cflag = true;	break;
X	    case 'b':	bflag = true;	break;
X	    default:	fprintf (stderr, USAGE, myname); exit (1);
X	    }
X
X	if (! (rflag || sflag || lflag || wflag || cflag))
X	    rflag = sflag = lflag = wflag = cflag = true;
X
X	argc -= optind;
X	argv += optind;
X
X	if (argc < 1)				/* use default arguments */
X	    argv = defaultargs;
X
X/*
X * OPEN AND DO EACH INPUT FILE:
X *
X * Be careful to keep stdin open for filenames of "-".
X * Argc is not altered; if < 1, it means no file args were given.
X */
X
X	for ( ; *argv != sbNull; argv++)		/* each argument */
X	{
X	    if (strcmp (*argv, "-") == 0)		/* read stdin */
X		filep = stdin;
X
X	    else if ((filep = fopen (*argv, "r")) == fileNull)
X	    {
X		PrintErr ("can't open", *argv);
X		retval = 1;
X		continue;
X	    }
X
X	    DoFile (filep, (argc < 1), *argv);
X
X	    if (filep != stdin)			/* keep stdin open for reuse */
X		fclose (filep);
X	}
X	exit (retval);
X
X#endif /* not TABLE */
X
X} /* main */
X
X
X#ifdef TABLE
X
X/************************************************************************
X * P R I N T   T A B L E
X *
X * Print table needed for CRC computation, as a C array declaration.
X * The output can then be included in this program.  It would be easy
X * to just build the table in memory each time the program is run, but
X * what the heck -- this way is a little more complicated, but already
X * done, and shaves off a bit of startup time.
X *
X * Assumes unsigned and short are at least 16 bits.
X */
X
Xproc PrintTable()
X{
Xregister unsigned index = 0;		/* place in table	*/
Xregister unsigned entry;		/* table entry		*/
Xregister int	  count;		/* for changing entry	*/
X
X	printf ("unsigned short CRCtable [256] = {");
X
X	while (true)
X	{
X	    if ((index % 8) == 0)		/* time for new line */
X		putchar (chNewline);
X
X	    for (entry = index, count = 8; (count--) > 0; )
X	    {
X		if (entry & 1)			/* low bit set */
X		    entry = (entry >> 1) ^ 0xA001;
X		else
X		    entry >>= 1;
X	    }
X
X	    printf ("\t0x%4.4x", entry);
X
X	    if (++index == 256)
X		break;
X
X	    putchar (',');
X	}
X
X	printf ("\n};\n");
X
X} /* PrintTable */
X
X
X#else /* not TABLE */
X
X
X/************************************************************************
X * CRC TABLE AND BYTE SUM STRUCTS
X *
X * CRCtable[], output from PrintTable(), is used for CRC calculation.
X * Structures are used for circular mod-2**16 byte sums.  They assume
X * that two shorts == one long!
X */
X
Xunsigned short CRCtable [256] = {
X	0x0000,	0xc0c1,	0xc181,	0x0140,	0xc301,	0x03c0,	0x0280,	0xc241,
X	0xc601,	0x06c0,	0x0780,	0xc741,	0x0500,	0xc5c1,	0xc481,	0x0440,
X	0xcc01,	0x0cc0,	0x0d80,	0xcd41,	0x0f00,	0xcfc1,	0xce81,	0x0e40,
X	0x0a00,	0xcac1,	0xcb81,	0x0b40,	0xc901,	0x09c0,	0x0880,	0xc841,
X	0xd801,	0x18c0,	0x1980,	0xd941,	0x1b00,	0xdbc1,	0xda81,	0x1a40,
X	0x1e00,	0xdec1,	0xdf81,	0x1f40,	0xdd01,	0x1dc0,	0x1c80,	0xdc41,
X	0x1400,	0xd4c1,	0xd581,	0x1540,	0xd701,	0x17c0,	0x1680,	0xd641,
X	0xd201,	0x12c0,	0x1380,	0xd341,	0x1100,	0xd1c1,	0xd081,	0x1040,
X	0xf001,	0x30c0,	0x3180,	0xf141,	0x3300,	0xf3c1,	0xf281,	0x3240,
X	0x3600,	0xf6c1,	0xf781,	0x3740,	0xf501,	0x35c0,	0x3480,	0xf441,
X	0x3c00,	0xfcc1,	0xfd81,	0x3d40,	0xff01,	0x3fc0,	0x3e80,	0xfe41,
X	0xfa01,	0x3ac0,	0x3b80,	0xfb41,	0x3900,	0xf9c1,	0xf881,	0x3840,
X	0x2800,	0xe8c1,	0xe981,	0x2940,	0xeb01,	0x2bc0,	0x2a80,	0xea41,
X	0xee01,	0x2ec0,	0x2f80,	0xef41,	0x2d00,	0xedc1,	0xec81,	0x2c40,
X	0xe401,	0x24c0,	0x2580,	0xe541,	0x2700,	0xe7c1,	0xe681,	0x2640,
X	0x2200,	0xe2c1,	0xe381,	0x2340,	0xe101,	0x21c0,	0x2080,	0xe041,
X	0xa001,	0x60c0,	0x6180,	0xa141,	0x6300,	0xa3c1,	0xa281,	0x6240,
X	0x6600,	0xa6c1,	0xa781,	0x6740,	0xa501,	0x65c0,	0x6480,	0xa441,
X	0x6c00,	0xacc1,	0xad81,	0x6d40,	0xaf01,	0x6fc0,	0x6e80,	0xae41,
X	0xaa01,	0x6ac0,	0x6b80,	0xab41,	0x6900,	0xa9c1,	0xa881,	0x6840,
X	0x7800,	0xb8c1,	0xb981,	0x7940,	0xbb01,	0x7bc0,	0x7a80,	0xba41,
X	0xbe01,	0x7ec0,	0x7f80,	0xbf41,	0x7d00,	0xbdc1,	0xbc81,	0x7c40,
X	0xb401,	0x74c0,	0x7580,	0xb541,	0x7700,	0xb7c1,	0xb681,	0x7640,
X	0x7200,	0xb2c1,	0xb381,	0x7340,	0xb101,	0x71c0,	0x7080,	0xb041,
X	0x5000,	0x90c1,	0x9181,	0x5140,	0x9301,	0x53c0,	0x5280,	0x9241,
X	0x9601,	0x56c0,	0x5780,	0x9741,	0x5500,	0x95c1,	0x9481,	0x5440,
X	0x9c01,	0x5cc0,	0x5d80,	0x9d41,	0x5f00,	0x9fc1,	0x9e81,	0x5e40,
X	0x5a00,	0x9ac1,	0x9b81,	0x5b40,	0x9901,	0x59c0,	0x5880,	0x9841,
X	0x8801,	0x48c0,	0x4980,	0x8941,	0x4b00,	0x8bc1,	0x8a81,	0x4a40,
X	0x4e00,	0x8ec1,	0x8f81,	0x4f40,	0x8d01,	0x4dc0,	0x4c80,	0x8c41,
X	0x4400,	0x84c1,	0x8581,	0x4540,	0x8701,	0x47c0,	0x4680,	0x8641,
X	0x8201,	0x42c0,	0x4380,	0x8341,	0x4100,	0x81c1,	0x8081,	0x4040
X};
X
Xstruct shorts {			/* as used, order is irrelevant */
X	unsigned short	high, low;
X};
X
Xtypedef union {			/* to map one long to two shorts */
X	unsigned long	sum;
X	struct	 shorts	shorts;
X} convert;
X
X
X/************************************************************************
X * D O   F I L E
X *
X * Read one file, calculate values, and print an output line.
X * Sets retval if necessary.  ch is int, not char, to be sure
X * it can distinguish 0xff and EOF.  As a result, all normal
X * values of ch should be positive, 0..255.
X */
X
Xproc DoFile (filep, nullname, filename)
Xregister FILE	*filep;		/* file to read	    */
X	 int	nullname;	/* ignore filename? */
X	 char	*filename;	/* name of filep    */
X{
Xregister int	ch;		/* current char	*/
Xregister unsigned crc = 0;	/* crc sum	*/
Xregister long	sum   = 0L;	/* byte sum	*/
Xregister long	lines = 0L;	/* line count	*/
Xregister long	words = 0L;	/* word count	*/
Xregister long	chars = 0L;	/* char count	*/
X
X	 convert conv;		/* for 16-sum	*/
Xregister int notword = true;	/* not in word?	*/
X
X/*
X * READ FILE AND COMPUTE SUMS:
X *
X * CRCtable[] values have 16 bits, so the masking is necessary before each
X * repeated index into the array.  sum is allowed to increment to more than
X * 16 bits; overflow is handled later.  Line and char counts are accumulated
X * regardless whether they are needed; it's faster not to check.  Words are
X * counted in the same strange way as wc(1), ignoring special chars.
X */
X
X	while ((ch = getc (filep)) != EOF)
X	{
X	    if (rflag)
X		crc = (crc >> 8) ^ (CRCtable [(crc ^ ch) & 0xff]);
X
X	    if (sflag)
X		sum += ch;
X
X	    if (ch == chNewline)
X		lines++;
X
X	    chars++;
X
X	    if (wflag)
X	    {
X		if ((' ' < ch) && (ch < '\177'))	/* word char */
X		{
X		    if (notword)			/* start of word */
X		    {
X			words++;
X			notword = false;
X		    }
X		}
X		else if ((ch == ' ') || (ch == '\t') || (ch == chNewline))
X		{
X		    notword = true;
X		}
X	    }
X	} /* while */
X
X/*
X * REPORT ERROR OR PRINT TOTALS:
X */
X
X	if (ferror (filep))
X	{
X	    PrintErr ("read failed from", nullname ? "stdin" : filename);
X	    retval = 1;
X	}
X	else
X	{
X	    conv.sum = sum;		/* for adding back overflow */
X
X	    if (rflag)	printf (" %4.4x", crc);
X	    if (sflag)	printf (" %5u",   conv.shorts.high + conv.shorts.low);
X	    if (lflag)	printf (" %6ld",  lines);
X	    if (wflag)	printf (" %6ld",  words);
X	    if (cflag)	printf (" %6ld",  chars);
X
X	    if (! nullname)		/* have name to print */
X	    {
X		if (bflag)		/* basename only */
X		{
X		    char *cp = filename;
X
X		    while (*cp != chNull)	/* till end of name */
X			if (*cp++ == '/')	/* directory level  */
X			    filename = cp;	/* set past '/'	    */
X		}
X		printf (" %s", filename);
X	    }
X	    putchar (chNewline);
X
X	} /* else */
X
X} /* DoFile */
X
X#endif /* not TABLE */
/
echo x - vitals.man
gres '^X' '' > vitals.man << '/'
X.\" $Header: vitals.1,v 1.1 87/08/10 12:07:47 $
X.TH VITALS 1 ""
X.ad b
X.SH NAME
Xvitals \- crc, sum, line, word, and character counts
X.SH SYNOPSIS
X.B vitals
X[
X.B \-rslwcb
X] [
X.I file ...
X]
X.SH DESCRIPTION
X.I Vitals
Xchecks data integrity by
Xcomputing vital statistics related to the data in the given
Xfile(s) or standard input (by default).
XThe statistics include a four-digit hex CRC, a 16-bit byte sum (similar to
X.IR sum (1)
Xwithout the block count)
Xand line, word, and character counts (similar to
X.IR wc (1)).
XOne line is printed for each input file or standard input, consisting of
Xfive statistics fields 
Xfollowed by the file name, if known.
XIf a file is specified as "\fB\-\fR", the program reads standard 
Xinput at that
Xpoint and shows "\fB\-\fR" as the file name.
X.SS Options 
X.TP 15
X.B \-r
XCompute only the CRC:  a true 16-bit cyclic redundancy count
Xthat can
Xdetect, among other things, exchanged characters.
X.TP 
X.B \-s
XCompute only the byte sum:  the modulo-2\(**\(**16, unsigned, circular sum
Xof all the bytes, each taken as an
X.B int
X(therefore normally in the range 0-255).
X.TP
X.B \-l
XCompute only the line count:  the number of newline characters in the input.
X.TP
X.B \-w
XCompute only the word count:  the number of 
Xcharacter sequences
Xdelimited by blanks, tabs, or newlines.
XAs in
X.IR wc (1),
Xnon-printable characters are totally ignored when looking for words.
X.TP
X.B \-c
XCompute only the character count.
X.TP
X.B \-b
XPrint only file basenames, not full path names.
X.PP
XThese options can be used in any combination.
XThe default is
X.BR \-rslwc ,
Xthat is, all but
X.BR \-b .
X.PP
X.I Vitals 
Xis more efficient than separate commands tied together
Xwith a shell script because the input data is read only once.
XUnlike
X.IR wc (1),
Xthis program does not compute totals, since it is intended for fast data
Xvalidation, not size counting.
X.SH DIAGNOSTICS
XIf any file open or read fails, the program writes a message to standard
Xerror when the problem is encountered, and continues with the next file.
XIt ultimately returns non-zero if any error occurs, else zero.
X.SH AUTHOR
X.I Vitals
Xwas developed by Hewlett-Packard.
X.SH "SEE ALSO"
Xsum(1), wc(1).
X
/

-3-	Getopt is in fairly wide use. This is Henry Spencer's redistributable
version, working on Minix.


echo x - /usr/Newlib/getopt.c
gres '^X' '' > /usr/Newlib/getopt.c << '/'
X
X/*
X * getopt - get option letter from argv
X *
X * Copyright (c) Henry Spencer.
X * Written by Henry Spencer.
X *
X * This software is not subject to any license of the American Telephone
X * and Telegraph Company or of the Regents of the University of California.
X *
X * Permission is granted to anyone to use this software for any purpose on
X * any computer system, and to alter it and redistribute it freely, subject
X * to the following restrictions:
X *
X * 1. The author is not responsible for the consequences of use of this
X *    software, no matter how awful, even if they arise from flaws in it.
X *
X * 2. The origin of this software must not be misrepresented, either by
X *    explicit claim or by omission.  Since few users ever read sources,
X *    credits must appear in the documentation.
X *
X * 3. Altered versions must be plainly marked as such, and must not be
X *    misrepresented as being the original software.  Since few users
X *    ever read sources, credits must appear in the documentation.
X *
X * 4. This notice may not be removed or altered.
X */
X
X/*
X * changed index() calls to strchr() - darwin, oct 87.
X */
X
X#include <stdio.h>
X
Xchar	*optarg;	/* Global argument pointer. */
Xint	optind = 0;	/* Global argv index. */
X
Xstatic char	*scan = NULL;	/* Private scan pointer. */
X
Xextern char	*strchr();
X
Xint
Xgetopt(argc, argv, optstring)
Xint argc;
Xchar *argv[];
Xchar *optstring;
X{
X	register char c;
X	register char *place;
X
X	optarg = NULL;
X
X	if (scan == NULL || *scan == '\0') {
X		if (optind == 0)
X			optind++;
X	
X		if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return(EOF);
X		if (strcmp(argv[optind], "--")==0) {
X			optind++;
X			return(EOF);
X		}
X	
X		scan = argv[optind]+1;
X		optind++;
X	}
X
X	c = *scan++;
X	place = strchr(optstring, c);
X
X	if (place == NULL || c == ':') {
X		fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
X		return('?');
X	}
X
X	place++;
X	if (*place == ':') {
X		if (*scan != '\0') {
X			optarg = scan;
X			scan = NULL;
X		} else if (optind < argc) {
X			optarg = argv[optind];
X			optind++;
X		} else {
X			fprintf(stderr, "%s: -%c argument missing\n", argv[0], c);
X			return('?');
X		}
X	}
X
X	return(c);
X}
/


-4-	I was porting some program which used environment strings a while
back, and the Minix 1.2 getenv.c was causing an infinite loop.  I therefore
rewrote the routine, and it appears to work fine, but I don't have an
exact definition of the function of getenv() so I cannot be positive there
is no error in the following ...


echo x - /usr/Newlib/getenv.c
gres '^X' '' > /usr/Newlib/getenv.c << '/'
X#define NULL  (char *) 0
Xchar *getenv(name)
Xregister char *name;
X{
X  extern char **environ;
X  register char **v = environ, *p, *q;
X
X  while ((p = *v++) != NULL) {
X	q = name;
X	while ((*p == *q) && *q) {
X		++p; ++q;
X	}
X
X	if (*q != 0)
X		continue;
X	if (*p == '=') return(p+1);
X	if (*p == 0) return(p);
X  }
X  return(0);
X}
/


-5-	Andy's posting of sys/types.h seemed to lack a couple of defined
types. This is the version I had to hack together in order to port some
software - it too is incomplete but an amalgam of the two may be best.

echo x - /usr/include/sys/types.h
gres '^X' '' > /usr/include/sys/types.h << '/'
X/* this is a poor hack of sys/types.h by nick for time_t & others */
X
X#define major(x)	( (int) (x >> 8) & 0377)
X#define minor(x)	( (int) (x >> 0) & 0377)
X
Xtypedef	long	size_t;
Xtypedef	long	time_t;
Xtypedef	short	dev_t;		/* should be unsigned short? */
Xtypedef unsigned short ino_t;
X
Xtypedef short int	uid_t;
Xtypedef char		gid_t;
/


-6-	This is a diff to 1.2 cc.c to move the preprocessor, library and
the like into /usr/lib. Why?  Not everybody can mount a filesystem just
for /lib (partition table limitation and in-core-superblock table size limit),
or waste the memory to put it on ramdisk. My hard disk has 4 Minix partitions,
/usr is the most important one in terms of compatibility with Unix.


echo x - cc.c.diff
gres '^X' '' > cc.c.diff << '/'
X14a15,16
X> 
X> 	Change pathnames for hard disk system (Mar 5, 1988) Nick Andrew
X30c32
X< !!!!_SEE_BELOW_!!!
X---
X> 
X44,48c46,51
X< 
X< #ifdef MEM640K
X< /* MINIX paths for 640K PC (not 512K AT) */
X< char *PP     = "/lib/cpp";
X< char *CEM    = "/lib/cem";
X---
X> /* #define HARDDISK */
X> 
X> #ifdef HARDDISK
X> /* MINIX paths for hard disk system (640 or 512k) */
X> char *PP     = "/usr/lib/cpp";
X> char *CEM    = "/usr/lib/cem";
X56,59c59,62
X< #ifdef MEM512K
X< /* MINIX paths for 512K AT (not 640K PC) */
X< char *PP     = "/usr/lib/cpp";
X< char *CEM    = "/usr/lib/cem";
X---
X> #ifdef MEM640K
X> /* MINIX paths for 640K PC (not 512K AT) */
X> char *PP     = "/lib/cpp";
X> char *CEM    = "/lib/cem";
X66a70,81
X> 
X> #ifdef MEM512K
X> /* MINIX paths for 512K AT (not 640K PC) */
X> char *PP     = "/usr/lib/cpp";
X> char *CEM    = "/usr/lib/cem";
X> char *OPT    = "/usr/lib/opt";
X> char *CG     = "/usr/lib/cg";
X> char *ASLD   = "/usr/bin/asld";
X> char *SHELL  = "/bin/sh";
X> char *LIBDIR = "/usr/lib";
X> #endif
X> 
/


	I hope the above shars prove useful ...		Nick.