echo x - Makefile.ansi
sed '/^X/s///' > Makefile.ansi << '/'
X# Makefile for simple (i.e., single-file) commands
X
Xl=/usr/lib
XCC=exec cc
X
XCFLAGS= -s -i -m -D_MINIX -D_POSIX_SOURCE -I/include
XPRINTK= -Dprintf=printk -Dfprintf=fprintk
X
X# The normal printf routine provided by MINIX is quite large (5K), at least
X# by MINIX standards, because it has to include all kinds of weird features
X# required by the ANSI standard.  However, many programs do not need all
X# these features.  These programs can get away with a much simpler version 
X# of printf (and fprintf) called printk (and fprintk).  The stunt below with
X# OBJ1 and OBJ2 divides the contents of this directory into files that can
X# use printk (OBJ1) and those that cannot (OBJ2).  
X
XOBJ1=animals ascii backup badblocks banner basename cal cat cd cdiff \
X    cgrep chmem chmod chown cksum clr cmp comm cp crc \
X    date dd decomp16 df dhrystone diskcheck du dw echo expand expr factor \
X    fgrep file find fix fold fortune fsck gather getlf getty grep gres \
X    head hyphenate id ifdef inodes join kill leave ln login look lpr machine \
X    man men mkdir mkfifo mknod modem more mount mv ncheck od \
X    paste pathchk prep pretty printenv printroot proto pwd readall recover \
X    rev rm rmdir shar size sleep sort split strings strip stty su \
X    sum swapfs sync tail tee term test time touch tr traverse treecmp tset \
X    tsort ttt tty umount uname unexpand uniq update vol wc \
X    whatsnew which whoami width xargs
X
XOBJ2=at atrun btoa calendar ci co compress cron cut diff diskusage ed fsck2 \
X    last ls mail mkfs mkproto mref nm passwd pr ps readfs roff sed tar \
X    termcap unshar users uud uue who write
X
XOBJ3=life gomoku
X
Xall:	$(OBJ1) $(OBJ2)
X
X$(OBJ1):
X	@echo ----------------------------- $@ -------------------------------
X	@$(CC) $(CFLAGS) $(PRINTK) -o bin/$@ $@.c
X	@chmem =8192 bin/$@ >/dev/null 2>&1
X
X$(OBJ2):
X	@echo ----------------------------- $@ -------------------------------
X	@$(CC) $(CFLAGS) -o bin/$@ $@.c
X	@chmem =8192 bin/$@ >/dev/null 2>&1
X
X$(OBJ3):
X	@echo ----------------------------- $@ -------------------------------
X	@$(CC) $(CFLAGS) -o bin/$@ $@.c -lcurses
X	@chmem =30000 bin/$@ >/dev/null 2>&1
X
X
Xclean:	
X	@rm -f *.o *.s *.bak
X
X
/
echo x - Makefile.kr
sed '/^X/s///' > Makefile.kr << '/'
X# Makefile for simple (i.e., single-file) commands
X
Xl=/usr/lib
XCC=exec cc
X
XCFLAGS= -i -D_MINIX -D_POSIX_SOURCE -I/include
XPRINTK= -Dprintf=printk -Dfprintf=fprintk
X
X# The normal printf routine provided by MINIX is quite large (5K), at least
X# by MINIX standards, because it has to include all kinds of weird features
X# required by the ANSI standard.  However, many programs do not need all
X# these features.  These programs can get away with a much simpler version 
X# of printf (and fprintf) called printk (and fprintk).  The stunt below with
X# OBJ1 and OBJ2 divides the contents of this directory into files that can
X# use printk (OBJ1) and those that cannot (OBJ2).  
X
XOBJ1=animals ascii backup badblocks banner basename cal cat cd cdiff \
X    cgrep chmem chmod chown cksum clr cmp comm cp crc \
X    date dd decomp16 df dhrystone diskcheck du dw echo expand expr factor \
X    fgrep file find fix fold fortune fsck gather getlf getty grep gres \
X    head hyphenate id ifdef inodes join kill leave ln login look lpr machine \
X    man men mkdir mkfifo mknod modem more mount mv ncheck od \
X    paste pathchk prep pretty printenv printroot proto pwd readall recover \
X    rev rm rmdir shar size sleep sort split strings strip stty su \
X    sum swapfs sync tail tee term test time touch tr traverse treecmp tset \
X    tsort ttt tty umount uname unexpand uniq update vol wc \
X    whatsnew which whoami width xargs
X
XOBJ2=at atrun btoa calendar ci co compress cron cut diff diskusage ed fsck2 \
X    last ls mail mkfs mkproto mref nm passwd pr ps readfs roff sed tar \
X    termcap unshar users uud uue who write
X
XOBJ3=life gomoku
X
Xall:	$(OBJ1) $(OBJ2)
X
X$(OBJ1):
X	@echo ----------------------------- $@ -------------------------------
X	@$(CC) $(CFLAGS) $(PRINTK) -o bin/$@ $@.c
X	@chmem =8192 bin/$@ >/dev/null 2>&1
X
X$(OBJ2):
X	@echo ----------------------------- $@ -------------------------------
X	@$(CC) $(CFLAGS) -o bin/$@ $@.c
X	@chmem =8192 bin/$@ >/dev/null 2>&1
X
X$(OBJ3):
X	@echo ----------------------------- $@ -------------------------------
X	@$(CC) $(CFLAGS) -o bin/$@ $@.c -lcurses
X	@chmem =30000 bin/$@ >/dev/null 2>&1
X
X
Xclean:	
X	@rm -f *.o *.s *.bak
X
X
/
echo x - calendar.c
sed '/^X/s///' > calendar.c << '/'
X/* calendar - reminder service		Authors: S. & K. Hirabayashi */
X
X/* Permission is hereby granted for nonprofit use. */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <time.h>
X#include <regexp.h>
X#include <limits.h>
X#include <stdlib.h>
X#include <string.h>
X#include <termcap.h>
X#include <unistd.h>
X#include <utime.h>
X#include <stdio.h>
X
X/* Change these two lines for your system needs. */
X#define MAIL1	"/usr/bin/mail"
X#define MAIL2	"/bin/mail"
X#define PASSWD	"/etc/passwd"	/* system password file */
X#define MAX_EXP		4	/* see date_exp() function */
X
Xchar *mail;			/* mail command path ("/bin/mail" etc) */
Xregexp *exp[MAX_EXP];		/* date expressions */
Xint nexp;			/* # of the date expressions */
Xchar calfile[PATH_MAX];		/* calendar file for the user */
X
Xint rflg;			/* consult aged 'calendar' file and touch */
Xint mflg;			/* mail (multi user) service */
Xchar *cmd;			/* the name of this command */
Xchar buf[BUFSIZ];
X
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(void calendar, (void));
X_PROTOTYPE(char *getstr, (char *s, int n));
X_PROTOTYPE(int newaccess, (char *file));
X_PROTOTYPE(void grep, (char *file, char *user));
X_PROTOTYPE(int date_exp, (void));
X_PROTOTYPE(char *date_pat, (time_t t));
X_PROTOTYPE(void regerror, (char *s));
X_PROTOTYPE(void error, (char *s, char *t));
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X  char *s;
X
X  cmd = *argv;
X  while (--argc > 0 && (*++argv)[0] == '-') {
X	s = argv[0] + 1;
X	if (*s == '\0')
X		mflg++;		/* mail service */
X	else if (strcmp(s, "r") == 0)
X		rflg++, mflg++;
X  }
X
X  if (mflg) {			/* check mailing agent */
X	if (access(MAIL1, X_OK) == 0)
X		mail = MAIL1;
X	else if (access(MAIL2, X_OK) == 0)
X		mail = MAIL2;
X	else
X		error("cannot find %s", MAIL1);
X  }
X  nexp = date_exp();
X  calendar();
X  exit(0);
X}
X
Xvoid calendar()
X{
X  int i;
X  char *s;
X  FILE *fp;
X
X  if (!mflg) {
X	grep("calendar", "");
X	return;
X  }
X
X  /* Mail sevice */
X  if ((fp = fopen(PASSWD, "r")) == (FILE *) NULL)
X	error("cannot open %s", PASSWD);
X
X  while (fgets(buf, BUFSIZ, fp) != (char *) NULL) {
X	for (i = 0, s = buf; *s && *s != '\n'; s++)
X		if (*s == ':') i++;
X	*s = '\0';
X	if (i != 6) error("illegal '/etc/passwd' format: %s", buf);
X
X	/* Calendar file = ${HOME}/calendar */
X	sprintf(calfile, "%s/%s", getstr(buf, 5), "calendar");
X
X	if ((access(calfile, R_OK) != 0) || (rflg && !newaccess(calfile)))
X		continue;
X
X	grep(calfile, getstr(buf, 0));
X  }
X
X  fclose(fp);
X}
X
Xchar *getstr(s, n)
Xchar *s;
Xint n;
X{
X/* Returns the string value of the n-th field in the record (s) */
X  int i;
X  char *t;
X  static char str[512];
X
X  for (i = 0; i < n && *s; s++)
X	if (*s == ':') i++;		/* field separator */
X  for (i = 0, t = str; *s && *s != ':' && i < 511; i++) *t++ = *s++;
X  *t = '\0';
X  return str;
X}
X
Xint newaccess(file)
Xchar *file;			/* file name */
X{
X/* Check whether the file has been touched today. */
X
X  int r = 0;
X  struct tm *tm;
X  struct stat stbuf;
X  time_t clk;
X  char newdate[8], olddate[8];
X
X  time(&clk);
X  tm = localtime(&clk);
X  sprintf(newdate, "%02d%02d%02d", tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
X
X  if (stat(file, &stbuf) == -1) error("cannot stat %s", file);
X  tm = localtime(&stbuf.st_mtime);
X  sprintf(olddate, "%02d%02d%02d", tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
X
X  if (strcmp(newdate, olddate) != 0) {
X	utime(file, NULL);	/* touch */
X	r++;
X  }
X  return r;
X}
X
Xvoid grep(file, user)
Xchar *file, *user;
X{				/* grep 'exp[]' [| mail user] */
X  int i;
X  char command[128];		/* mail command */
X  FILE *ifp, *ofp;
X
X  if ((ifp = fopen(file, "r")) == (FILE *) NULL)
X	error("cannot open %s", file);
X  if (*user != '\0') {
X	sprintf(command, "%s %s", mail, user);
X	ofp = (FILE *) NULL;
X  } else {
X	ofp = stdout;
X  }
X
X  while (fgets(buf, BUFSIZ, ifp) != (char *) NULL) {
X	for (i = 0; i < nexp; i++) {
X		if (regexec(exp[i], buf, 1)) {
X			if ((ofp == (FILE *) NULL) &&
X				  (ofp = popen(command, "w")) == (FILE *) NULL)
X				error("cannot popen %s", mail);
X			fputs(buf, ofp);
X		}
X	}
X  }
X
X  fclose(ifp);
X  if (ofp == stdout)
X	fflush(ofp);
X  else if (ofp != (FILE *) NULL)
X	pclose(ofp);
X}
X
Xint date_exp()
X{
X/* Set compiled regular expressions into the exp[] array. */
X  static int n[] = {2, 2, 2, 2, 2, 4, 3};
X  int i, r, wday;
X  time_t clk;
X
X  time(&clk);
X  wday = localtime(&clk)->tm_wday;
X  r = n[wday];
X  if (r > MAX_EXP) error("too many date expressions", "");
X  for (i = 0; i < r; i++) {
X	exp[i] = regcomp(date_pat(clk));
X	clk += 60 * 60 * 24L;	/* 24 hours */
X  }
X  return(r);
X}
X
Xchar *date_pat(t)
Xtime_t t;
X{				/* returns date expression for the time (t) */
X  static char *month[] = {
X	 "[Jj]an", "[Ff]eb", "[Mm]ar", "[Aa]pr", "[Mm]ay", "[Jj]un",
X	  "[Jj]ul", "[Aa]ug", "[Ss]ep", "[Oo]ct", "[Nn]ov", "[Dd]ec"
X  };
X  static char str[512];
X  struct tm *tm;
X
X  tm = localtime(&t);
X  sprintf(str,
X	"(^|[ \t(,;])(((%s[^ \t]*[ \t])|0*%d/|\\*/)(0*%d|\\*))([^0123456789]|$)",
X	month[tm->tm_mon], tm->tm_mon + 1, tm->tm_mday);
X
X  return str;
X}
X
Xvoid regerror(s)
Xchar *s;
X{				/* regcomp() needs this */
X  error("REGULAR EXPRESSION ERROR (%s)", s);
X}
X
Xvoid error(s, t)
Xchar *s, *t;
X{
X  fprintf(stderr, "%s: ", cmd);
X  fprintf(stderr, s, t);
X  fprintf(stderr, "\n");
X  exit(1);
X}
/
echo x - cd.c
sed '/^X/s///' > cd.c << '/'
X/* cd -- change working directory	Author: Thomas Brupbacher */
X
X
X/* -------------------------------------------------------------------------
X * lit.: 	POSIX 1003.2/D10 section 4.5
X *
X * Thomas Brupbacher (tobr@mw.lpc.ethz.ch)	Oct 1990
X * -------------------------------------------------------------------------
X *
X * This is a new implementation of cd, written from scratch.
X * cd uses the environment variables HOME and CDPATH to determine where
X * to chdir.
X */
X
X#include <sys/types.h>
X#include <stdlib.h>
X#include <limits.h>
X#include <string.h>
X#include <unistd.h>
X#include <stdio.h>
X
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(void get_next_prefix, (char *string, char prefix [PATH_MAX ]));
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X  char *string;
X  char *prog = *argv;
X  char prefix[PATH_MAX];
X  int cdflag, cdpath_flag;
X
X  if (argc == 1) {		/* no directory on command line, cd to home
X			 * dir						 */
X	string = getenv("HOME");
X	if (string == NULL) {
X		fprintf(stderr, "no home directory, directory not changed\n");
X		return(1);
X	}
X  }
X  if (argc > 2)			/* more than one dir on the command line */
X	fprintf(stderr, "%s: ignoring arguments\n", prog);
X
X  argv++;
X  string = getenv("CDPATH");
X  if (string == NULL)/* CDPATH not set, cd relative to .	 */
X	cdflag = chdir(*argv);
X
X  else {
X	cdpath_flag = 1;
X	do {
X		get_next_prefix(string, prefix);
X		if (prefix[0] != '\0') {
X			strcat(prefix, "/");
X			strcat(prefix, *argv);
X			cdflag = chdir(prefix);
X		}
X	} while ((cdflag != 0) && (prefix[0] != '\0'));
X  }
X
X  if (cdflag != 0) {
X	fprintf(stderr, "%s: cannot cd to %s\n", prog, *argv);
X	return(1);
X  }
X  if (cdpath_flag == 1) printf("%s\n", prefix);
X
X  return(0);
X}
X
X/* Get_next_prefix() parses the string <string> for the next : or the
X * end of <string> and copies the parsed chars to <prefix>.
X */
Xvoid get_next_prefix(string, prefix)
Xchar *string;
Xchar prefix[PATH_MAX];
X{
X  int index;
X
X  if (*(++string) == ':')	/* CDPATH contains "::" 		 */
X	prefix[index++] = ' ';
X  while ((*string != ':') && (*string != '\0'))
X	prefix[index++] = *(string++);
X  prefix[index++] = '\0';
X}
/
echo x - cksum.c
sed '/^X/s///' > cksum.c << '/'
X/* cksum.c - Display file checksums and block counts	Author: V. Archer */
X
X/* Copyright 1991 by Vincent Archer
X *	You may freely redistribute this software, in source or binary
X *	form, provided that you do not alter this copyright mention in any
X *	way.
X */
X
X#include <sys/types.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdio.h>
X
Xint error;
X
X/* Table from P1003.2 (4.9/Fig 4.1). In fact, this table was taken from zmodem
X * and rewritten to look like the Draft 11 example.
X */
Xunsigned long crctab[] = {
X		  0x7fffffff,
X	 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
X	 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e,
X	 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
X	 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
X	 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0,
X	 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63,
X	 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
X	 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa,
X	 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75,
X	 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180,
X	 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
X	 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87,
X	 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
X	 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5,
X	 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
X	 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,
X	 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b,
X	 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
X	 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
X	 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541,
X	 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc,
X	 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f,
X	 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
X	 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e,
X	 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
X	 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c,
X	 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
X	 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b,
X	 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2,
X	 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671,
X	 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
X	 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
X	 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767,
X	 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6,
X	 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
X	 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795,
X	 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
X	 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b,
X	 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
X	 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82,
X	 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d,
X	 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8,
X	 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
X	 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff,
X	 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee,
X	 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
X	 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
X	 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c,
X	 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
X	 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02,
X	  0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
X};
X
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(void crc, (int fd, char *name));
X_PROTOTYPE(unsigned long strncrc, (unsigned char *b, int n, unsigned long s));
X
Xstatic int aux;
X
X/* Routine straight out of 4.9.10 */
Xunsigned long strncrc(b, n, s)
Xregister unsigned char *b;	/* byte sequence to checksum */
Xregister int n;			/* length of sequence */
Xregister unsigned long s;	/* initial checksum value */
X{
X  register int i;
X
X  while (n-- > 0) {
X	/* Compute the index to the crc table */
X	i = (s >> 24) ^ ((unsigned int) (*b++));
X
X	if (i == 0) {
X		/* Replace an intermediate zero with the next value
X		 * from the sequence */
X		i = aux++;
X		if (aux >= sizeof(crctab) / sizeof(crctab[0])) aux = 0;
X	}
X
X	/* New checksum value */
X	s = (s << 8) ^ crctab[i];
X  }
X  return(s);
X}
X
X/* Main module. No options switches allowed, none parsed. */
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  argc--;
X  error = 0;
X  if (!argc)
X	crc(0, (char *) 0);
X  else
X	for (argv++; argc--; argv++) crc(open(*argv, O_RDONLY), *argv);
X  return(error);
X}
X
X/* Compute crc and size of input file descriptor. */
Xvoid crc(fd, name)
Xint fd;
Xchar *name;
X{
X  off_t f_size;
X  unsigned long crc;
X  int nb;
X  unsigned char buffer[1024];
X
X  if (fd < 0) {
X	perror(name);
X	error = 1;
X	return;
X  }
X  crc = 0;
X  f_size = 0;
X  aux = 0;
X  for (;;) {
X	nb = read(fd, (char *) buffer, sizeof(buffer));
X	if (nb < 0) {
X		close(fd);
X		perror(name ? name : "stdin");
X		error = 1;
X		return;
X	}
X	if (!nb) break;
X	f_size += nb;
X	crc = strncrc(buffer, nb, crc);
X  }
X  close(fd);
X  printf("%lu %ld", crc, f_size);
X  if (name)
X	printf(" %s\n", name);
X  else
X	putchar('\n');
X}
/
echo x - comic.c
sed '/^X/s///' > comic.c << '/'
X#define VERSION "2.5"
X/*
X   This is COMIC (CO_mpress MI_nix C). It was written (p)
X   by Jan-Mark Wams (email: jms@cs.vu.nl) in 1991.
X  
X   `Comic' is tuned to compress the minix source (kernel, fs, mm, commands).
X   The algorithm replaces repeated strings with an <offset,length> pair.
X   The longer the repeated string, the better the compression. If the text 
X   contains a lot of short repeated strings, (eg. font-files) use an other 
X   compression method like LZW (ie. ``compress'').
X  
X   It should compile under MINIX, UNIX, MS-DOS, etc. But if you have
X   to make any chainges for a new OS. (ie. if you port it.) PLEASE
X   let me know.  (email: jms@cs.vu.nl).
X  
X   Define one of following:
X        _MINIX, AMOEBA, UNIX, DOS, C89, DOS, MSC, GCC, M68
X  
X   Compiler Defines it checks for:
X        _POSIX_SOURCE, __BCC__, __TURBOC__, __STDC__
X  
X   Extra options:
X        H1_SIZE=2^n, H2_SIZE=2^n, LINT, DEBUG, NDEBUG
X   Don't define H2_SIZE without defining H1_SIZE. On big boxes, use
X   256 for both, this will give you a speed up.
X  
X   The file format is as follows. (Note in version 2.0 N is always zero).
X  
X   name                 size            index   remark
X  ---------------------------------------------------------------------
X   MAGIC                1 byte          0       0x69
X   MAGIC and FLAGS      1 byte          1       (0x60 | flags)
X   optional FLAGS       N bytes         2       Encription etc.
X   optional DOS SUFFIX  2 bytes         2+N     Original dos suffix.
X   optional DATA        M > 0 bytes     4+N     Compressed original.
X  
X   History:
X    VERSION |  USER  |  WHAT
X      2.0      jms      Made one source file version.
X      2.1      jms      Made compilable under gcc, turbo-C++ 1.0, ncc etc.
X      2.2      jms      Speedup in Eqlen(). Newstyle layout.
X      2.3      jms      Added ``0xFF & (int)'' twice in output_pair().
X      2.4      jms	Added stack hog in hash_init().
X      2.5      jms	s/MINIX/_MINIX/g
X*/
X
X/* General includes and defines.
X*/
X#ifdef DOS
X#  include <fcntl.h>    /* Use O_BINARY by `setmode()' in SM-DOS. */
X#  include <io.h>       /* For `setmode()' to. */
X# ifdef MSC
X#  include <stdlib.h>
X# endif
X#endif
X#if __STDC__ && ! GCC
X# include <stdlib.h>
X#endif
X#include <assert.h>
X#include <stdio.h>
X#include <errno.h>
X#include <string.h>             /* Included for strxxx(). */
X#include <ctype.h>              /* For isupper() and tolower(). */
X#include <sys/types.h>          /* Included for stat(). */
X#include <sys/stat.h>           /* Idem. */
X#include <unistd.h>
X
X/*
X   The S_ISREG works with Turbo C! Isn't life beautiful?
X*/
X#ifndef S_ISREG 
X#define S_ISREG(m) (((m) & 0170000) == 0100000)
X#endif
X
X#ifdef DOS
X# define TTY    "CON"           /* The terminal device under MS-DOS. */
X#else   /* DOS */
X# define TTY    "/dev/tty"
X#endif /* DOS */
X
X# define next_arg()\
X    (argc-- <= 0 ? NULL : *(argv++))
X
X#define str_equel(s1,s2)    (strcmp(s1, s2) == 0)
X
X#define NAMELEN_MAX     128
X
Xchar *COMIC      = "comic";
Xchar *XCAT       = "xcat";
Xchar *DECOMIC    = "decomic";
Xchar *STDIN      = "stdin"; /* Name of the current std* files. */
Xchar *STDOUT     = "stdout";
X
Xchar *SUFFIX     = "-X"; /* Suffix for comiced files. */
X#define SUFFIX_LEN 2     /* Change SUFFIX and SUFFIX_LEN together. */
X
X/* Compress constants.
X*/
X#define HUFFMAN_BITS    8       /* Huffman codes are 8 bits. */
X#define LENGTH_BITS     8       /* # of bits in length info. */
X#define OFFSET_BITS     13      /* # of bits in offset info. */
X#define PAIR_MAX        1       /* There are two pairs. */
X#define HUFFMAN_SIZE    256     /* Max for 8 bits. */
X#define LENGTH_SIZE     256     /* Max for 8 bits. */
X#define OFFSET_SIZE     8192    /* 13 Bits. OFFSET_SIZE > LENGHT_SIZE * 2 */
X#define OFFSET_MIN      1       /* Minimum offset. */
X#define LENGTH_MIN      2       /* Minimum length. */
X#define OFFSET_MAX      (OFFSET_SIZE + OFFSET_MIN - 1)
X#define LENGTH_MAX      (LENGTH_SIZE + LENGTH_MIN - 1)
X#define INPUT_SIZE      (LENGTH_SIZE + PAIR_MAX + LENGTH_MIN)
X#define BUFF_SIZE       (INPUT_SIZE + OFFSET_SIZE + OFFSET_MIN)
X#define BUFF_MAX        (BUFF_SIZE - 1)
X#define NON_INPUT_SIZE  (BUFF_SIZE - INPUT_SIZE)
X#define LOW_OFFSET_BITS (OFFSET_BITS - HUFFMAN_BITS)
X
X/* To shut up lint, a bit ;-(
X*/
X#ifdef LINT
Xextern char *memset();
Xextern void *malloc();
X#endif
X
X/* Global variables.
X*/
Xchar *pname;                    /* Name of program. */
Xchar suffix[SUFFIX_LEN];       /* Last two DOS suffix characters. */
X
X/* Pairs are built of a start pointer and a length pointer.
X*/
Xtypedef struct pair {           /* Part descriptor type. */
X        char * start;           /* Pointer in the circular buffer. */
X        int length;             /* Length of part. */
X} pair_t, *pair_p;
X
Xpair_t pairs[2];                /* Buffer for pair descriptors. */
Xpair_p pair_0 = &(pairs[0]);    /* Short hands. */
Xpair_p pair_1 = &(pairs[1]);
X
Xchar Buff[BUFF_SIZE + 1];       /* The Buffer. Add one for Sentinel. */
Xchar *Bend;                     /* Pointer to the last char in Buff. */
X#define Sentp (Bend + 1)	/* First char after buffer. */
Xchar *Bp = Buff;                /* Pointer to unprocessed char. */
Xchar *Binputend = Buff;         /* End of read ahead input. */
Xint  Bsize;
X
Xlong Nin = 0, Nout = 0;         /* Total # of bytes read/written. */
X
Xint v_flag = 0;                 /* Verbose flag given. */
Xint c_flag = 0;                 /* Cat (output to stdout) flag. */
Xint f_flag = 0;                 /* Force flag. */
Xint d_flag = 0;                 /* Decomic flag. */
Xint r_flag = 0;                 /* Raw flag, no header, only data. */
X#ifdef DOS
Xint s_flag = 1;                 /* Save suffix MS-DOS like. */
Xint a_flag = 0;                 /* Ascii option, cast \r\n to \n. */
X#else
Xint s_flag = 0;                 /* No MS-DOS, no default suffix savage. */
X#endif
X
X#ifdef __TURBOC__
Xextern unsigned _stklen = 256;
X#endif
X
X#ifdef DOS
X# define str_2_upper(s) (void)strupr(s)
X# define str_2_lower(s) (void)strlwr(s)
X#endif /* DOS */
X
X/* Index type is used for indexing the buffer and the hash tables.
X*/
Xtypedef unsigned short indext;
X#define INDEX_END       ((indext)BUFF_SIZE + 1)
X
X/* Buffer macros.
X*/
X#define Bsucc(p) ((p) == Bend ? Buff : (p) + 1)
X#define Bpred(p) ((p) == Buff ? Bend : (p) - 1)
X#define Badd(p, n) ((p) + (n) - ((p) + (n) > Bend ? Bsize : 0))
X#define Bsub(p, n) ((p) - (n) + ((p) < Buff + (n) ? Bsize : 0))
X#define Bdelta(p, q) (int)((p) - (q) + ((p) < (q) ? Bsize : 0))
X#define Blookupstart() Bsub(Bp, NON_INPUT_SIZE)
X#define Bindex(p) (indext)((p) - Buff)
X#define Binit() (void)memset (Buff, '\0', Bsize)
X
X/*
X   Pre filling the buffer might give better compression, but
X   would enlarge the compress program. '-) Perhaps a pseudo
X   random generator, filling the buffer with the most likely
X   (lowest number of bits in their huffman code) characters.
X   Note: the buffer (Buff) must be filled with something.
X*/
X
X/* 
X   If H1_SIZE and H2_SIZE are defined on compile time, the hash 
X   functions might be quicker on some compilers if not the maximum
X   values for H1_SIZE and H2_SIZE will be found at run time.
X*/
X#ifndef H2_SIZE
Xint H1_SIZE = 256;   /* Max value for SIZE = 256. */
Xint H2_SIZE = 256;
X#endif
X
X/* Define Hash functions.
X*/
X#define H1(i) ((indext)((i) & (H1_SIZE -1)))
X#define H2(i) ((indext)((i) & (H2_SIZE -1)))
X
X/* The buffer index macros.
X*/
X#define Ipred(i) (((i) == 0 ? BUFF_SIZE : (i)) - 1)
X#define Isucc(i) ((i) == BUFF_SIZE - 1 ? 0 : (i) + 1)
X#define hash_entry(i,j) hash_tbl[H1(i) + H1_SIZE * H2(j)]
X
X/* 
X   About magic; The first byte is a normal magic byte. The second byte 
X   is 0x6X, where the X nybble contains extra info.
X*/
X
X#define MAGIC1          (char)0x69      /* Magic number. */
X#define MAGIC2          (char)0x60      /* High part of 2d byte. */
X
X#define STATIC_BIT      (char)0x8       /* Use builtin Huffman tables. */
X#define DYNAMIC_BIT     (char)0x4       /* Huffman tables precede data. */
X#define SUFFIX_BIT      (char)0x2       /* Next two bytes are old suffix. */
X#define EXTEND_BIT      (char)0x1       /* More header data. */
X
X/*
X   Third byte indicates extra data-processing. To allow a third byte
X   the EXTEND_BIT has to been set in the second header byte. This leaves
X   room for futer expansions like encription etc. This will make the
X   current version signal something is wrong incase it gets data from
X   a new version jet to come.
X*/
X
X#define EXTRA_EXTEND    (char)0x0       /* Extra extension bytes. */
X#define TRANSLATE       (char)0x1       /* Input was xlated. */
X
X/* Huffman types.
X*/
Xtypedef long bitstr_t;
X
Xtypedef struct tree_s {
X        int _0, _1;
X} tree_t[];
X
Xtypedef struct ctab_s {
X        bitstr_t code;
X	char     length; /* Has to hold up to sizeof(bitstr_t) * 8 bits. */
X} ctab_t[];
X
X#define Hchar 0
X#define Hoff 1
X#define Hlen 2
X
X/* 
X   There is a big redundancy in the defined tables: both encode and 
X   decode tables are included. (The bit length per code would be 
X   enough but this would mean timeconsuming run time generation.) Ctab 
X   tables hold <bitpattern,length> pairs. Tree tables hold a binary 
X   decsent tree with per node a 0 and a 1 side.
X*/
X
X/* Huffman Tables these are generated by comicgen.
X*/
Xctab_t ctab_char = {
X        {0x54L,9},{0x3B6L,10},{0x67AL,11},{0x242L,10},
X        {0x33DCL,14},{0xD99L,13},{0xD98L,13},{0x76BL,11},
X        {0xCF6L,12},{0x17L,5},{0x2CL,6},{0x1977L,14},
X        {0xCF749L,20},{0x1B6L,10},{0xAAL,10},{0x13BL,9},
X        {0x6DEL,12},{0xCF748L,20},{0x6CFL,12},{0x1976L,14},
X        {0x1975L,14},{0xD97L,13},{0x76AL,11},{0xB4DL,12},
X        {0xD96L,13},{0xB4CL,12},{0x1974L,14},{0x1973L,14},
X        {0xB4BL,12},{0xB4AL,12},{0xB49L,12},{0x1972L,14},
X        {0x8L,5},{0x4FL,7},{0x1CL,6},{0x120L,9},
X        {0x3B4L,10},{0x31L,8},{0x75L,7},{0x28L,6},
X        {0x1AL,5},{0x10L,5},{0x1CL,7},{0x30L,8},
X        {0x3L,6},{0x26L,6},{0x31L,6},{0x3AL,7},
X        {0x15L,6},{0x2L,6},{0xBL,6},{0x1L,7},
X        {0x3EL,7},{0x54L,7},{0x74L,7},{0x61L,7},
X        {0x55L,7},{0x13L,8},{0x1DL,7},{0xFL,6},
X        {0x77L,7},{0x29L,7},{0x56L,7},{0x38L,9},
X        {0x12L,8},{0x14L,7},{0x2BL,8},{0x2FL,7},
X        {0x6EL,7},{0x13L,7},{0x66L,7},{0x51L,8},
X        {0xB5L,8},{0x45L,7},{0x19FL,9},{0xA1L,9},
X        {0x37L,7},{0x6FL,7},{0x57L,7},{0x3DL,7},
X        {0x60L,7},{0x156L,11},{0x44L,7},{0xFL,7},
X        {0x2EL,7},{0x5BL,7},{0xC9L,9},{0x9CL,8},
X        {0xDAL,9},{0xC8L,9},{0x13AL,9},{0x3CL,7},
X        {0x39L,9},{0x19L,7},{0x33CL,10},{0x36L,6},
X        {0xD95L,13},{0xDL,6},{0x32L,6},{0x1CL,5},
X        {0x8L,6},{0x1FL,5},{0x16L,6},{0x8L,7},
X        {0x33L,7},{0x6L,6},{0xCEL,8},{0x3BL,7},
X        {0x25L,6},{0x23L,6},{0x5L,6},{0x1L,6},
X        {0x18L,6},{0x168L,9},{0x1AL,6},{0x9L,5},
X        {0x1EL,5},{0x29L,6},{0x3FL,7},{0x12L,7},
X	{0x1DL,8},{0,7},{0xECL,8},{0x91L,8},
X        {0xA0L,9},{0x49L,7},{0x5A7L,11},{0xCF747L,20},
X        {0xB48L,12},{0xCF746L,20},{0x1971L,14},{0xCF745L,20},
X        {0x1970L,14},{0xCF744L,20},{0x196FL,14},{0xCF743L,20},
X        {0xD94L,13},{0xCF742L,20},{0xCF741L,20},{0xCF740L,20},
X        {0x67BBFL,19},{0x196EL,14},{0x67BBEL,19},{0x67BBDL,19},
X        {0x196DL,14},{0x67BBCL,19},{0x67BBBL,19},{0x67BBAL,19},
X        {0xD93L,13},{0x67BB9L,19},{0x196CL,14},{0x67BB8L,19},
X        {0x67BB7L,19},{0x196BL,14},{0xD92L,13},{0x196AL,14},
X        {0x1969L,14},{0x1968L,14},{0x1967L,14},{0x1966L,14},
X        {0x1965L,14},{0xD91L,13},{0xD90L,13},{0xD8FL,13},
X        {0x3B7L,10},{0xD8EL,13},{0xD8DL,13},{0x1964L,14},
X        {0x1963L,14},{0xD8CL,13},{0x1962L,14},{0xD8BL,13},
X        {0x1961L,14},{0xD8AL,13},{0x1960L,14},{0x195FL,14},
X        {0x90FL,12},{0xD89L,13},{0x195EL,14},{0xD88L,13},
X        {0x195DL,14},{0x90EL,12},{0x195CL,14},{0xD87L,13},
X        {0x195BL,14},{0x195AL,14},{0x1959L,14},{0xD86L,13},
X        {0x67BB6L,19},{0xD85L,13},{0x67BB5L,19},{0x1958L,14},
X        {0x1957L,14},{0x36EL,11},{0xD84L,13},{0x1956L,14},
X        {0x1955L,14},{0xD83L,13},{0x1954L,14},{0x1953L,14},
X        {0x67BB4L,19},{0x1952L,14},{0x1951L,14},{0x1950L,14},
X        {0x194FL,14},{0x194EL,14},{0x67BB3L,19},{0x194DL,14},
X        {0x67BB2L,19},{0x194CL,14},{0x67BB1L,19},{0xD82L,13},
X        {0x67BB0L,19},{0x194BL,14},{0x67BAFL,19},{0x194AL,14},
X        {0x67BAEL,19},{0x1949L,14},{0x67BADL,19},{0x1948L,14},
X        {0x67BACL,19},{0x1947L,14},{0x67BABL,19},{0x1946L,14},
X        {0x67BAAL,19},{0x1945L,14},{0x1944L,14},{0x1943L,14},
X        {0x1942L,14},{0x1941L,14},{0x67BA9L,19},{0x1940L,14},
X        {0x67BA8L,19},{0xD81L,13},{0x67BA7L,19},{0xD80L,13},
X        {0x67BA6L,19},{0x6CEL,12},{0xABFL,14},{0xABEL,14},
X        {0xABDL,14},{0x90DL,12},{0xABCL,14},{0x6CDL,12},
X        {0x67BA5L,19},{0xCBFL,13},{0xABBL,14},{0xCBEL,13},
X        {0xABAL,14},{0xCBDL,13},{0xAB9L,14},{0x90CL,12},
X        {0xAB8L,14},{0xCBCL,13},{0x19EFL,13},{0x6DFL,12}
X};
X
Xtree_t tree_char = {
X        {17,12},{129,127},{133,131},{137,135},
X        {139,138},{142,140},{145,143},{147,146},
X        {151,149},{188,152},{200,190},{208,206},
X        {212,210},{216,214},{220,218},{224,222},
X        {232,230},{236,234},{256,244},{258,257},
X        {260,259},{262,261},{264,263},{266,265},
X        {268,267},{270,269},{272,271},{274,273},
X        {276,275},{278,277},{280,279},{282,281},
X        {284,283},{286,285},{288,287},{290,289},
X        {4,291},{19,11},{26,20},{31,27},
X        {132,130},{141,134},{150,144},{155,153},
X        {157,156},{159,158},{167,160},{170,168},
X        {174,172},{178,175},{182,180},{185,184},
X        {191,186},{195,192},{198,196},{201,199},
X        {203,202},{205,204},{209,207},{215,213},
X        {219,217},{223,221},{226,225},{228,227},
X        {231,229},{239,238},{242,240},{248,246},
X        {252,250},{292,254},{6,5},{24,21},
X        {136,96},{154,148},{162,161},{165,163},
X        {169,166},{173,171},{179,177},{187,183},
X        {194,189},{211,197},{235,233},{247,245},
X        {253,249},{294,293},{296,295},{298,297},
X        {300,299},{302,301},{304,303},{306,305},
X        {308,307},{310,309},{312,311},{314,313},
X        {316,315},{318,317},{320,319},{322,321},
X        {324,323},{8,325},{25,23},{29,28},
X        {128,30},{181,176},{251,241},{16,255},
X        {237,18},{326,243},{328,327},{330,329},
X        {332,331},{334,333},{336,335},{338,337},
X        {340,339},{342,341},{344,343},{346,345},
X	{348,347},{350,349},{352,351},{354,353},
X	{356,355},{22,7},{2,357},{358,126},
X        {360,359},{362,361},{193,363},{365,364},
X        {367,366},{369,368},{371,370},{373,372},
X        {375,374},{377,376},{379,378},{81,380},
X        {1,164},{36,381},{94,382},{384,383},
X        {3,385},{13,386},{388,387},{390,389},
X        {392,391},{394,393},{14,395},{397,396},
X        {398,74},{113,399},{90,15},{35,400},
X        {88,401},{403,402},{405,404},{89,86},
X        {124,75},{0,406},{63,92},{122,407},
X        {106,408},{409,72},{87,410},{411,123},
X        {413,412},{415,414},{416,71},{43,37},
X        {417,66},{418,120},{64,57},{419,60},
X        {54,38},{68,77},{70,420},{80,55},
X        {421,85},{62,78},{53,56},{422,33},
X        {423,125},{82,73},{52,118},{91,79},
X        {47,107},{424,76},{425,104},{84,67},
X        {426,61},{42,58},{427,93},{65,428},
X        {119,69},{429,83},{103,430},{121,51},
X        {432,431},{95,433},{98,434},{435,46},
X        {10,436},{438,437},{39,117},{45,439},
X        {440,108},{441,109},{443,442},{34,444},
X        {114,445},{112,446},{102,447},{448,48},
X        {449,59},{450,97},{451,50},{100,452},
X        {105,453},{454,110},{49,44},{455,111},
X        {116,101},{99,456},{40,457},{459,458},
X        {460,9},{462,461},{464,463},{41,465},
X        {467,466},{469,468},{471,470},{32,115},
X        {473,472},{475,474},{477,476},{479,478},
X        {481,480},{483,482},{485,484},{487,486},
X        {489,488},{491,490},{493,492},{495,494},
X        {497,496},{499,498},{501,500},{503,502},
X        {505,504},{507,506},{509,508}
X};
X
Xctab_t ctab_len = {
X	{0x2L,3},{0,3},{0x3L,3},{0x5L,3},
X        {0x6L,3},{0x3L,4},{0x9L,4},{0xFL,4},
X        {0x5L,5},{0x1CL,5},{0x8L,6},{0x21L,6},
X        {0x3AL,6},{0x13L,7},{0x41L,7},{0x45L,7},
X        {0x76L,7},{0x24L,8},{0x8CL,8},{0x88L,8},
X        {0x8EL,8},{0xEEL,8},{0x4AL,9},{0x100L,9},
X        {0x102L,9},{0x101L,9},{0x11EL,9},{0x206L,10},
X        {0x225L,10},{0x207L,10},{0x235L,10},{0x1DFL,9},
X        {0x237L,10},{0x47DL,11},{0x3BDL,10},{0x448L,11},
X        {0x234L,10},{0x44CL,11},{0x12EL,11},{0x47CL,11},
X        {0x46DL,11},{0x258L,12},{0x779L,11},{0x778L,11},
X        {0x25EL,12},{0x8D9L,12},{0x259D41L,24},{0x4BEL,13},
X        {0x892L,12},{0x8D8L,12},{0x89FL,12},{0x966L,14},
X        {0x8FCL,12},{0x4B7L,13},{0x4B6L,13},{0x11FFL,13},
X        {0x113DL,13},{0x11FEL,13},{0x259D40L,24},{0x11FDL,13},
X        {0x4B5L,13},{0x2275L,14},{0x11FCL,13},{0x259CL,16},
X        {0x2274L,14},{0x259D3FL,24},{0x2273L,14},{0x2272L,14},
X        {0x2271L,14},{0x2270L,14},{0x226FL,14},{0x4B4L,13},
X        {0x226EL,14},{0x226DL,14},{0x259D3EL,24},{0x44D1L,15},
X        {0x226CL,14},{0x4B2L,13},{0x113CL,13},{0x113BL,13},
X        {0x44D0L,15},{0x449FL,15},{0x449EL,15},{0x11FBL,13},
X        {0x259D3DL,24},{0x259D3CL,24},{0x259D3BL,24},{0x259D3AL,24},
X        {0x226BL,14},{0x259D39L,24},{0x449DL,15},{0x449CL,15},
X        {0x449BL,15},{0x449AL,15},{0x259D38L,24},{0x226AL,14},
X        {0x11FAL,13},{0x4499L,15},{0x259D37L,24},{0x259D36L,24},
X        {0x4498L,15},{0x2269L,14},{0x259D35L,24},{0x259D34L,24},
X        {0x259D33L,24},{0x259D32L,24},{0x259D31L,24},{0x259D30L,24},
X        {0x259D2FL,24},{0x259D2EL,24},{0x259D2DL,24},{0x259D2CL,24},
X        {0x259D2BL,24},{0x259D2AL,24},{0x259D29L,24},{0x12FFL,15},
X        {0x259D28L,24},{0x259D27L,24},{0x259D26L,24},{0x259D25L,24},
X        {0x259D24L,24},{0x259D23L,24},{0x259D22L,24},{0x259D21L,24},
X        {0x259D20L,24},{0x259D1FL,24},{0x12FEL,15},{0x259D1EL,24},
X        {0x259D1DL,24},{0x259D1CL,24},{0x259D1BL,24},{0x259D1AL,24},
X        {0x259D19L,24},{0x259D18L,24},{0x259D17L,24},{0x259D16L,24},
X        {0x259D15L,24},{0x12FDL,15},{0x259D14L,24},{0x259D13L,24},
X        {0x259D12L,24},{0x259D11L,24},{0x259D10L,24},{0x259D0FL,24},
X        {0x259D0EL,24},{0x259D0DL,24},{0x259D0CL,24},{0x259D0BL,24},
X        {0x259D0AL,24},{0x259D09L,24},{0x259D08L,24},{0x259D07L,24},
X        {0x259D06L,24},{0x259D05L,24},{0x12FCL,15},{0x259D04L,24},
X        {0x259D03L,24},{0x259D02L,24},{0x259D01L,24},{0x259D00L,24},
X        {0x12CEFFL,23},{0x12CEFEL,23},{0x12CEFDL,23},{0x12CEFCL,23},
X        {0x12CEFBL,23},{0x12CEFAL,23},{0x12CEF9L,23},{0x12CEF8L,23},
X        {0x12CEF7L,23},{0x12CEF6L,23},{0x12CEF5L,23},{0x12CFL,15},
X        {0x12CEF4L,23},{0x12CEF3L,23},{0x12CEF2L,23},{0x12CEF1L,23},
X        {0x12CEF0L,23},{0x12CEEFL,23},{0x12CEEEL,23},{0x12CEEDL,23},
X        {0x12CEECL,23},{0x12CEEBL,23},{0x12CEEAL,23},{0x12CEE9L,23},
X        {0x12CEE8L,23},{0x12CEE7L,23},{0x12CEE6L,23},{0x12CEE5L,23},
X        {0x12CEE4L,23},{0x12CEE3L,23},{0x12CEE2L,23},{0x12CEE1L,23},
X        {0x12CEE0L,23},{0x12CEDFL,23},{0x12CEDEL,23},{0x12CEDDL,23},
X        {0x12CEDCL,23},{0x12CEDBL,23},{0x12CEDAL,23},{0x12CED9L,23},
X        {0x12CED8L,23},{0x12CED7L,23},{0x12CED6L,23},{0x12CED5L,23},
X        {0x12CED4L,23},{0x12CED3L,23},{0x12CED2L,23},{0x12CED1L,23},
X        {0x12CED0L,23},{0x12CECFL,23},{0x12CECEL,23},{0x12CECDL,23},
X        {0x12CECCL,23},{0x12CECBL,23},{0x12CECAL,23},{0x12CEC9L,23},
X        {0x12CEC8L,23},{0x12CEC7L,23},{0x12CEC6L,23},{0x12CEC5L,23},
X        {0x12CEC4L,23},{0x12CEC3L,23},{0x12CEC2L,23},{0x12CEC1L,23},
X        {0x12CEC0L,23},{0x12CEBFL,23},{0x12CEBEL,23},{0x12CEBDL,23},
X        {0x12CEBCL,23},{0x12CEBBL,23},{0x12CEBAL,23},{0x12CEB9L,23},
X        {0x12CEB8L,23},{0x12CEB7L,23},{0x12CEB6L,23},{0x12CEB5L,23},
X        {0x12CEB4L,23},{0x12CEB3L,23},{0x12CEB2L,23},{0x12CEB1L,23},
X        {0x12CEB0L,23},{0x12CEAFL,23},{0x12CEAEL,23},{0x12CEADL,23},
X        {0x12CEACL,23},{0x12CEABL,23},{0x12CEAAL,23},{0x12CEA9L,23},
X        {0x12CEA8L,23},{0x12CEA7L,23},{0x12CEA6L,23},{0x12CEA5L,23},
X        {0x12CEA4L,23},{0x12CEA3L,23},{0x12CEA2L,23},{0x12CEA1L,23}
X};
X
Xtree_t tree_len = {
X        {58,46},{74,65},{85,84},{87,86},
X        {94,89},{99,98},{103,102},{105,104},
X        {107,106},{109,108},{111,110},{113,112},
X        {116,114},{118,117},{120,119},{122,121},
X        {124,123},{127,125},{129,128},{131,130},
X        {133,132},{135,134},{138,136},{140,139},
X        {142,141},{144,143},{146,145},{148,147},
X        {150,149},{152,151},{155,153},{157,156},
X        {159,158},{161,160},{163,162},{165,164},
X        {167,166},{169,168},{172,170},{174,173},
X        {176,175},{178,177},{180,179},{182,181},
X        {184,183},{186,185},{188,187},{190,189},
X        {192,191},{194,193},{196,195},{198,197},
X        {200,199},{202,201},{204,203},{206,205},
X        {208,207},{210,209},{212,211},{214,213},
X        {216,215},{218,217},{220,219},{222,221},
X        {224,223},{226,225},{228,227},{230,229},
X        {232,231},{234,233},{236,235},{238,237},
X        {240,239},{242,241},{244,243},{246,245},
X        {248,247},{250,249},{252,251},{254,253},
X        {256,255},{258,257},{260,259},{262,261},
X        {264,263},{266,265},{268,267},{270,269},
X        {272,271},{274,273},{276,275},{278,277},
X        {280,279},{282,281},{284,283},{286,285},
X        {288,287},{290,289},{292,291},{294,293},
X        {296,295},{298,297},{300,299},{302,301},
X        {304,303},{306,305},{308,307},{310,309},
X        {312,311},{314,313},{316,315},{318,317},
X        {320,319},{322,321},{324,323},{326,325},
X        {328,327},{330,329},{332,331},{334,333},
X        {336,335},{338,337},{340,339},{342,341},
X        {344,343},{346,345},{348,347},{350,349},
X        {352,351},{354,353},{356,355},{358,357},
X        {360,359},{362,361},{364,363},{366,365},
X        {368,367},{370,369},{372,371},{374,373},
X        {376,375},{378,377},{380,379},{382,381},
X        {384,383},{386,385},{388,387},{390,389},
X        {392,391},{394,393},{396,395},{398,397},
X        {400,399},{402,401},{404,403},{406,405},
X        {408,407},{410,409},{412,411},{414,413},
X        {63,415},{80,75},{82,81},{91,90},
X        {93,92},{100,97},{126,115},{154,137},
X        {416,171},{64,61},{67,66},{69,68},
X        {72,70},{76,73},{95,88},{417,101},
X        {419,418},{421,420},{423,422},{51,424},
X        {57,55},{62,59},{96,83},{78,56},
X        {425,79},{427,426},{429,428},{431,430},
X        {433,432},{47,434},{54,53},{71,60},
X        {77,435},{437,436},{52,438},{49,45},
X        {439,50},{441,440},{443,442},{48,444},
X        {44,445},{447,446},{41,448},{43,42},
X        {450,449},{39,33},{451,40},{453,452},
X        {37,454},{35,455},{38,456},{458,457},
X        {459,34},{461,460},{462,32},{36,30},
X        {464,463},{465,28},{27,29},{467,466},
X        {468,31},{26,469},{471,470},{473,472},
X        {24,474},{23,25},{22,475},{21,476},
X        {20,477},{18,478},{19,479},{481,480},
X        {17,482},{16,483},{485,484},{486,15},
X        {487,14},{488,13},{12,489},{491,490},
X        {492,11},{10,493},{9,494},{496,495},
X        {497,8},{498,7},{499,6},{500,5},
X        {4,501},{502,3},{0,2},{1,503},
X        {505,504},{507,506},{509,508}
X};
X
Xctab_t ctab_off = {
X        {0x7L,3},{0x3L,4},{0xCL,4},{0xAL,5},
X        {0x12L,5},{0x1BL,5},{0x8L,6},{0x10L,6},
X        {0x1CL,6},{0x1FL,6},{0x28L,6},{0x8L,7},
X        {0x35L,6},{0x3L,7},{0xBL,7},{0x2FL,6},
X        {0xEL,7},{0x24L,7},{0x26L,7},{0x3AL,7},
X        {0x3CL,7},{0x40L,7},{0x4EL,7},{0x45L,7},
X        {0x5L,8},{0x57L,7},{0x5AL,7},{0x3L,8},
X        {0xCL,8},{0x2AL,8},{0x1FL,8},{0x2L,8},
X        {0xAL,8},{0x4CL,7},{0x9L,8},{0x2CL,8},
X        {0x4FL,8},{0x19L,8},{0x65L,8},{0x89L,8},
X        {0x87L,8},{0x29L,8},{0x2FL,8},{0x8DL,8},
X        {0x6BL,8},{0x63L,8},{0x6DL,8},{0x5AL,8},
X        {0x85L,8},{0x60L,8},{0x5CL,8},{0x9BL,8},
X        {0xA5L,8},{0x6FL,8},{0xA4L,8},{0x83L,8},
X        {0xACL,8},{0x84L,8},{0x8EL,8},{0x9AL,8},
X        {0xD2L,8},{0xBBL,8},{0x2BL,9},{0xABL,8},
X        {0x17L,9},{0xBAL,8},{0xAAL,8},{0x35L,9},
X        {0xA8L,8},{0x16L,9},{0xB9L,8},{0x8L,9},
X        {0x3DL,9},{0x8AL,9},{0x26L,9},{0x9L,9},
X	{0xB8L,8},{0x1DL,9},{0,9},{0xB7L,8},
X        {0x2AL,9},{0x5DL,9},{0x95L,9},{0x50L,9},
X        {0x4AL,9},{0xBFL,9},{0x4FL,9},{0xBBL,9},
X        {0x8DL,9},{0x4EL,9},{0x3CL,9},{0x9CL,9},
X        {0xCFL,9},{0xC5L,9},{0x57L,9},{0x88L,9},
X        {0xD8L,9},{0x37L,9},{0x14FL,9},{0x56L,9},
X        {0x94L,9},{0x51L,9},{0xB0L,9},{0xCEL,9},
X        {0x5CL,9},{0xF7L,9},{0x97L,9},{0xDDL,9},
X        {0xD5L,9},{0xD4L,9},{0x8CL,9},{0xB6L,9},
X        {0xF6L,9},{0xD3L,9},{0xBEL,9},{0x118L,9},
X        {0x16CL,9},{0xD2L,9},{0xBDL,9},{0x23L,10},
X        {0xDCL,9},{0x105L,9},{0x167L,9},{0xF5L,9},
X        {0x111L,9},{0x4BL,10},{0xF4L,9},{0xC4L,9},
X        {0x13EL,9},{0xC9L,9},{0xCDL,9},{0x4AL,10},
X        {0xC3L,9},{0x11FL,9},{0x14EL,9},{0x167L,10},
X        {0x1A1L,9},{0x153L,9},{0x119L,9},{0xEDL,9},
X        {0x39L,10},{0x9BL,10},{0xD1L,9},{0x163L,9},
X        {0xB7L,10},{0x162L,9},{0x52L,10},{0x152L,9},
X        {0x51L,10},{0x68L,10},{0x38L,10},{0xBCL,9},
X        {0x37L,10},{0x14DL,9},{0x13DL,9},{0x7L,10},
X        {0x10CL,9},{0x161L,9},{0x49L,10},{0x6L,10},
X        {0x11EL,9},{0x6DL,10},{0x160L,9},{0x1A6L,9},
X        {0x104L,9},{0x166L,9},{0x48L,10},{0x1A3L,9},
X        {0x14CL,9},{0x15BL,9},{0x165L,9},{0x36L,10},
X        {0x63L,10},{0x1A0L,9},{0x5L,10},{0x164L,9},
X        {0x93L,10},{0x22L,10},{0x110L,9},{0x6CL,10},
X        {0x4L,10},{0x13CL,9},{0x3L,10},{0x3FL,10},
X        {0x2L,10},{0x1A2L,9},{0x9AL,10},{0x35L,10},
X        {0x116L,10},{0x1A7L,9},{0x13FL,9},{0x50L,10},
X        {0x4FL,10},{0x113L,10},{0x12CL,10},{0x92L,10},
X        {0x34L,10},{0x175L,10},{0x166L,10},{0x91L,10},
X        {0x99L,10},{0x1D8L,10},{0x3EL,10},{0x112L,10},
X        {0xB6L,10},{0x190L,10},{0x1A0L,10},{0x4EL,10},
X        {0x13AL,10},{0x15AL,9},{0x1B3L,10},{0x21BL,10},
X        {0x165L,10},{0x62L,10},{0x98L,10},{0x97L,10},
X        {0x21L,10},{0x69L,10},{0x61L,10},{0x164L,10},
X        {0x11FL,10},{0x163L,10},{0x174L,10},{0x12DL,10},
X        {0x1B2L,10},{0x96L,10},{0x11EL,10},{0x11DL,10},
X        {0x1A1L,10},{0x90L,10},{0x199L,10},{0x3DL,10},
X        {0xB5L,10},{0x162L,10},{0x1DFL,10},{0x16FL,10},
X        {0x185L,10},{0x3CL,10},{0x1DEL,10},{0x11CL,10},
X        {0x13BL,10},{0x184L,10},{0x2DBL,10},{0x198L,10},
X        {0x21AL,10},{0xB4L,10},{0x2DAL,10},{0x60L,10},
X        {0x1DDL,10},{0x1DCL,10},{0x1D9L,10},{0x53L,10},
X        {0x117L,10},{0x20L,10},{0x191L,10},{0x16EL,10}
X};
X
Xtree_t tree_off = {
X        {246,242},{244,211},{238,234},{249,248},
X        {201,250},{224,210},{206,228},{243,230},
X        {205,254},{241,236},{222,197},{255,235},
X        {198,135},{219,212},{233,221},{208,240},
X        {194,223},{226,220},{239,227},{188,252},
X        {203,193},{204,144},{245,232},{186,141},
X        {214,200},{225,215},{195,176},{229,199},
X        {179,161},{149,217},{213,172},{247,218},
X        {146,251},{191,148},{207,192},{131,125},
X        {166,158},{202,183},{237,231},{150,140},
X        {171,152},{196,187},{177,119},{253,216},
X        {159,155},{180,174},{184,182},{163,189},
X        {185,167},{173,136},{116,256},{165,122},
X        {175,170},{145,143},{162,157},{209,169},
X        {147,137},{134,98},{168,153},{128,190},
X        {181,154},{160,133},{115,138},{178,124},
X        {156,257},{164,121},{112,105},{126,123},
X        {259,258},{260,139},{120,107},{96,261},
X        {109,108},{117,113},{262,142},{103,92},
X        {263,130},{264,129},{127,93},{265,132},
X        {114,85},{151,118},{266,87},{111,267},
X        {269,268},{102,270},{91,271},{272,106},
X        {100,82},{274,273},{110,88},{73,275},
X        {95,276},{104,81},{278,277},{99,94},
X        {83,101},{89,86},{280,279},{84,281},
X        {283,282},{90,72},{284,97},{285,67},
X        {287,286},{80,62},{289,288},{74,290},
X        {292,291},{294,293},{295,77},{297,296},
X        {69,64},{299,298},{71,75},{301,300},
X        {78,302},{60,303},{305,304},{65,61},
X        {76,70},{306,79},{308,307},{310,309},
X        {56,311},{66,63},{68,312},{314,313},
X        {54,52},{316,315},{59,51},{58,317},
X        {318,43},{319,39},{320,40},{57,48},
X        {321,55},{323,322},{325,324},{326,53},
X        {327,46},{328,44},{330,329},{332,331},
X        {333,38},{334,45},{49,335},{337,336},
X        {50,338},{47,339},{341,340},{342,36},
X        {344,343},{346,345},{348,347},{349,42},
X        {35,350},{29,351},{352,41},{354,353},
X        {356,355},{357,30},{359,358},{360,37},
X        {362,361},{364,363},{366,365},{28,367},
X        {32,368},{369,34},{370,24},{31,27},
X        {372,371},{374,373},{376,375},{26,377},
X        {379,378},{380,25},{382,381},{384,383},
X        {22,385},{33,386},{388,387},{389,23},
X        {391,390},{21,392},{20,393},{19,394},
X        {396,395},{398,397},{400,399},{402,401},
X        {404,403},{406,405},{18,407},{17,408},
X        {410,409},{412,411},{414,413},{416,415},
X        {16,417},{419,418},{420,14},{11,421},
X        {423,422},{425,424},{426,13},{428,427},
X        {429,12},{430,15},{432,431},{434,433},
X        {10,435},{437,436},{439,438},{441,440},
X        {442,9},{8,443},{445,444},{447,446},
X        {449,448},{451,450},{7,452},{454,453},
X        {6,455},{457,456},{459,458},{461,460},
X        {463,462},{464,5},{466,465},{468,467},
X        {4,469},{471,470},{473,472},{475,474},
X        {3,476},{478,477},{480,479},{482,481},
X        {484,483},{2,485},{487,486},{489,488},
X        {491,490},{493,492},{494,1},{496,495},
X        {497,0},{499,498},{501,500},{503,502},
X        {505,504},{507,506},{509,508}
X};
X
X/*
X   The bits are put on a file, the first bit putted with ``put_bit()''
X   is the high bit of the first byte in the file. `Flush_bits()' will 
X   add a `1' and pad the byte up to a full byte with zeroes. This will
X   make the last bit in the last byte the eof marker. No original length 
X   information is stored in the output file.
X*/
X
X#define BIT_BUFF_SIZE    1024
Xchar bit_buff[BIT_BUFF_SIZE];
X#define eo_buff (bit_buff + BIT_BUFF_SIZE)
Xchar *bit_index = bit_buff;
Xchar *eof_index = bit_buff;
Xint put_bits = 0;
Xint put_room;
Xint get_bits = 0;
X
X#define next()          (bit_index++)            /* The next char. */
X#define no_next()       (bit_index == eof_index) /* There is no next. */
X#define bit_buff_full() (bit_index == eo_buff)   /* Buffer full. */
X
X
X_PROTOTYPE(void fatal, (char *failed ));
X_PROTOTYPE(void write_bit_buff, (void));
X_PROTOTYPE(void read_bit_buff, (void));
X_PROTOTYPE(void put_bit, (int bit ));
X_PROTOTYPE(int get_bit, (void));
X_PROTOTYPE(void init_bits, (void));
X_PROTOTYPE(void flush_bits, (void));
X_PROTOTYPE(void put_n_bits, (long code, int n ));
X_PROTOTYPE(int get_n_bits, (int n ));
X_PROTOTYPE(char *basename, (char *name ));
X_PROTOTYPE(char *new_name, (char *fname ));
X_PROTOTYPE(char *org_name, (char *fname ));
X_PROTOTYPE(int new_stdin, (char *newin ));
X_PROTOTYPE(int new_stdout, (char *newout ));
X_PROTOTYPE(void print_ratio, (void));
X_PROTOTYPE(void verbose_info, (void));
X_PROTOTYPE(void usage, (void));
X_PROTOTYPE(void file_start, (void));
X_PROTOTYPE(void file_done, (void));
X_PROTOTYPE(void hash_init, (void));
X_PROTOTYPE(void hash_update, (void));
X_PROTOTYPE(void decode_pair, (void));
X_PROTOTYPE(void decode_char, (void));
X_PROTOTYPE(int get_input, (void));
X_PROTOTYPE(int eqlen, (char *p, char *q, int count ));
X_PROTOTYPE(void get_token, (int pair_0used ));
X_PROTOTYPE(int magic_ok, (void));
X_PROTOTYPE(void put_magic, (void));
X_PROTOTYPE(int descend, (struct tree_s *tree ));
X_PROTOTYPE(void Hinit, (void));
X_PROTOTYPE(int Hdecode, (int index ));
X_PROTOTYPE(int Hcodelen, (int index, int c ));
X_PROTOTYPE(void Hencode, (int index, int i ));
X_PROTOTYPE(void decode, (void));
X_PROTOTYPE(void output_pair, (int *done ));
X_PROTOTYPE(void output_char, (void));
X_PROTOTYPE(void encode, (void));
X_PROTOTYPE(int main, (int argc, char **argv ));
X
X
X/* fatal: Print a error on stderr, and exit.
X*/
Xvoid fatal (failed)
Xchar *failed;
X{
X  fprintf(stderr, "\r%s: Fatal couldn't %s ", pname, failed);
X  if (errno != 0)
X        perror("");             /* Prints EOLN to ;-( */
X  else
X        printf("\n");
X  exit(-1);
X}
X
X
X/* write_bit_buff: write the bit i/o buffer to stdout.
X*/
Xvoid write_bit_buff()
X{
X  if (write(1, bit_buff, bit_index - bit_buff) != bit_index - bit_buff)
X        fatal("write");
X  Nout += bit_index - bit_buff;
X  bit_index = bit_buff;
X}
X
X/* read_bit_buff: read the bit i/o buffer from stdin.
X*/
Xvoid read_bit_buff()
X{
X  if ((eof_index = bit_buff + read(0, bit_buff, BIT_BUFF_SIZE)) < bit_buff)
X        fatal("read");
X
X  Nin += eof_index - bit_buff;
X  bit_index = bit_buff;
X}
X
X
X/* put_bit: put a bit on stdout.
X*/
Xvoid put_bit(bit)
Xint bit;
X{
X  assert(bit == 1 || bit == 0);
X
X  put_bits = (put_bits << 1) | bit;
X
X  if (--put_room == 0) {
X        *next() = put_bits;
X	if (bit_buff_full()) write_bit_buff();
X        put_bits = 0;           /* Flag. */
X        put_room = 8;
X  }
X}
X
X
X/* get_bit: get a bit from stdin.
X*/
Xint get_bit()
X{
X  if ((get_bits & 0x7F) == 0) {
X        if (get_bits == 0) {    /* First time only. */
X                read_bit_buff();
X                if (no_next()) {
X                        fprintf(stderr, "\r%s: Warning empty file.\n", pname);
X                        fflush(stderr);
X                        return EOF;
X                }
X	}                                   
X        if (no_next()) return EOF;
X	get_bits = (0xFF & (int)*next()) << 1;
X        if (no_next()) read_bit_buff();
X        if (no_next()) {
X                if (get_bits == 0x100)
X                        return EOF;     /* Bad luck, think ;-) */
X        } else
X                get_bits |= 1;  /* Last byte has own EOF marker. */
X  } else
X        get_bits <<= 1;
X
X  return(get_bits >> 8) & 1;
X}
X
X/* Init_bits: Init the bits package.
X*/
Xvoid init_bits()
X{
X  bit_index = bit_buff;         /* Not necessary, but nice. */
X  eof_index = bit_buff;
X  put_bits = 0;                 /* Very necessary. */
X  put_room = 8;
X  get_bits = 0;
X}
X
X
X/* Flush_bits: Flush the buffered bits to stdout.
X*/
Xvoid flush_bits()
X{
X  int i;
X  put_bit(1);                            /* Eof marker. */
X  for (i = 0; i < 7; i++) put_bit(0);    /* Fillup byte. */
X  write_bit_buff();
X}
X
X/* put_n_bits: put low `n' bits from code on stream.
X*/
Xvoid put_n_bits(code, n)
Xlong code;
Xint n;
X{
X  int uggy_buggy;       /* The Minix C compiler won't handle longs properly */
X
X  if (n < 0 || n > sizeof(long) * 8)
X        n = n;
X  assert(n >= 0 && n < sizeof(long) * 8);
X
X  code &= ((long) 1 << n) - 1;
X  while (n > put_room) {
X        n -= put_room;
X	uggy_buggy = (int)(code >> n) & ((1 << put_room) - 1);
X        *next() = (put_bits << put_room) | uggy_buggy;
X	if (bit_buff_full()) write_bit_buff();
X        put_bits = 0;           /* Flag. */
X        put_room = 8;
X  }
X  put_bits = (put_bits << n) | (int)code;
X  if ((put_room -= n) == 0) {
X        *next() = put_bits;
X	if (bit_buff_full()) write_bit_buff();
X        put_bits = 0;
X        put_room = 8;
X  }
X}
X
X/* get_n_bits: Get `n' bits from stdin.
X*/
Xint get_n_bits(n)
Xint n;
X{
X  int ret = 0;                  /* Return value. */
X  int bit;
X
X  assert(n > 0 && n < sizeof(int) * 8);
X
X  while (n-- > 0) {
X        ret <<= 1;
X        bit = get_bit();
X        if (bit == 0) {
X                /* EMPTY */
X        } else if (bit == 1) {
X                ret |= 1;
X        } else if (bit == EOF) {
X                fprintf(stderr, "\r%s: Unexpected EOF\n", pname);
X                exit(-1);
X        } else {
X                fprintf(stderr, "\r%s: funny bit\n", pname);
X                exit(-1);
X        }
X  }
X  return ret;
X}
X
X/* Basename: Do a check on name, only comic, decomic and xcat are allowed.
X*/
Xchar *basename(name)
Xchar *name;
X{
X  char *p;
X#ifdef DOS
X  /* DOS needs special attention. Uppercase letters and leading path
X  ** must be removed. Also .com or .exe suffixes have to be removed.
X  */
X  p = strrchr(name, '\\');
X  if (p != NULL)
X        name = p + 1;                   /* Kill path prefix. */
X
X  str_2_lower (p);                         /* Make name lower case. */
X
X  p = strrchr(name, '.');
X  if (p != NULL) {
X	if (!str_equel(p, ".exe") && !str_equel(p, ".com")) {
X		fprintf(stderr, "\r%s: Warning funny suffix %s\n", pname, p);
X        }
X        *p = '\0';                      /* Kill the .exe or .com suffix. */
X  }
X  else
X	fprintf(stderr, "\r%s: Warning no DOS suffix\n", pname);
X
X#else /* Non DOS. */
X  p = strrchr(name, '/');
X  if (p != NULL)
X	name = p + 1;                   /* Kill path prefix. */
X#endif
X  if (strncmp(name, "[de]comic", 9) == 0) {
X#ifdef DOS
X	printf("\rHUH?\n");
X#else
X	printf("\rYou are FUNNY!\n");
X#endif
X	exit(-99);
X  }
X  if (!str_equel(name, COMIC)
X   && !str_equel(name, DECOMIC)
X   && !str_equel(name, XCAT)) {
X	fprintf(stderr, "\rThis program must be called [de]comic ");
X	fprintf(stderr, "or xcat, not \"%s\".\n", name);
X#ifndef DEBUG
X        /* In debug or force mode, allow other names.
X        */
X	if (f_flag < 2) exit(1);
X#endif
X  }
X  return name;
X}
X
X
X/* new_name: generate new output name according to the given name.
X*/
Xchar *new_name(fname)
Xchar *fname;
X{
X  static char ret_name[NAMELEN_MAX];   /* Buffer for return value. */
X  char *p;
X
X  /* Check the tail. If the suffix is present, just return it.
X  */
X  if ((p = strrchr(fname, SUFFIX[0])) != NULL
X  && str_equel(p, SUFFIX))
X        return fname;
X
X  strncpy(ret_name, fname, NAMELEN_MAX);
X  ret_name[(NAMELEN_MAX - 1) - strlen(SUFFIX)] = '\0'; /* Truncate. */
X
X  /* Truncate suffix to be able to hold the SUFFIX. Save the suffix 
X  ** for the header. If there is no suffix, add a "." string (DOS).
X  */
X#ifndef DOS
X  if (s_flag) {
X#endif
X	  if ((p = strrchr(ret_name, '.')) != NULL) {
X		if (!f_flag && strlen(p) > 4) {
X			fprintf(stderr, "%s: Warning ", pname);
X			fprintf(stderr, "suffix %s ", p);
X			fprintf(stderr, "will be trucated ");
X			p[4] = '\0';
X			fprintf(stderr, "to %s\n", p);
X                }
X                if (!d_flag && s_flag)
X			strncpy(suffix, p + 4 - SUFFIX_LEN, SUFFIX_LEN);
X		p[4 - SUFFIX_LEN] = '\0';              /* Truncate. */
X          }
X#ifdef DOS
X          else
X		strcat(ret_name, ".");
X#else
X  }
X#endif
X  strcat(ret_name, SUFFIX);
X  return ret_name;
X}
X
X
X/* org_name: generate original name according to the given name.
X*/
Xchar *org_name(fname)
Xchar *fname;
X{
X  static char ret_name[NAMELEN_MAX];   /* Buffer for return value. */
X  char *p;
X
X  strncpy(ret_name, fname, NAMELEN_MAX);       /* Make private copy. */
X  ret_name[NAMELEN_MAX - 1] = '\0';            /* Terminate. */
X
X  /* If the -X suffix is there delete it.
X  */
X  if ((p = strrchr(ret_name, SUFFIX[0])) != NULL
X  && str_equel(p, SUFFIX))
X        *p = '\0';
X
X  if (d_flag && suffix[0] != '\0') {           /* If there is a suffix, */
X	p = strchr(ret_name, '.');
X	if (p!= NULL)                   /* Allow one suffix char. */
X		p[2] = '\0';
X	strncat(ret_name, suffix, SUFFIX_LEN); /* Add original suffix. */
X  }
X
X#ifdef DOS
X  p = ret_name + strlen(ret_name) -1;
X  if (*p == '.')
X        *p = '\0';   /* Kill empty suffix. */
X#endif /* DOS */
X
X  return ret_name;
X}
X
X/* new_stin: Set stdin to newin. Return success or fail.
X*/
Xint new_stdin(newin)
Xchar *newin;
X{
X  if (freopen(newin, "r", stdin) == (FILE *)NULL) {
X	fprintf(stderr, "\r%s: Can't open \"%s\"", pname, newin);
X	perror(" for reading: ");
X	fflush(stderr);
X        return 0;               /* Report error. */
X  }
X  Nin = 0;                      /* Reset input bytecounter. */
X  STDIN = newin;
X
X  return 1;
X}
X
X/* new_stdout: Set stdout to newout. Return success or fail.
X*/
Xint new_stdout(newout)
Xchar *newout;
X{
X  FILE *tty;                    /* File pointer for "/dev/tty" */
X  static char buf[2];
X  char *ans = buf;              /* To contain the answer, "y" or "n" */
X
X  Nout = 0;
X
X  /* If the cat flag is set, don't reopen stdout.
X  */
X  if (c_flag)
X          return 1;             /* Return success. */
X
X  /* Check if we will overwrite a file. (Unless the -f flag was given.)
X  */
X  if (!f_flag && access (newout, 0) == 0) {
X	if (!isatty(2) || (tty = fopen(TTY, "r")) == (FILE *)NULL) {
X		fprintf(stderr, "\r%s: Won't overwrite %s\n", pname, newout);
X		fflush(stderr);
X                return 0;
X        }
X	fprintf(stderr, "\r%s: Overwrite %s (y/n)? ", pname, newout);
X	fflush(stderr);
X	ans = fgets(ans, 2, tty);
X	if (tty != (FILE *)NULL) fclose(tty);
X	if (ans == NULL || *ans != 'y')
X		return 0;
X  }
X
X  /* Reopen stdout.
X  */
X  if (freopen(newout, "w", stdout) == (FILE *)NULL) {
X	fprintf(stderr, "\r%s: Can't open \"%s\"", pname, newout);
X	perror(" for writing: ");
X	fflush(stderr);
X        return 0;               /* Report fail. */
X  }
X  STDOUT = newout;
X  return 1;                     /* Return success. */
X}
X
X/* print_ratio: print the compression ratio if its negative, or the
X** verbose flag (v_flag) is TRUE. 
X*/
Xvoid print_ratio()
X{
X  long rat;
X
X  if (Nin == 0) {
X	if (!v_flag)
X		fprintf(stderr, "\r%s: Warning %s ", pname, STDIN);
X	fprintf(stderr, "is empty\n");
X        return;
X  }
X
X  /* Divide Nin and Nout by 2 as long as they are too big, to 
X  ** prevent overflowing the rat variable.
X  */
X  while (Nin > 10000 || Nout > 10000) { /* Get smaller value. */
X        Nin >>= 1;
X        Nout >>= 1;
X  }
X  if (Nin == 0) 
X	Nin = 1;
X  rat = ((Nin - Nout) * 10000) / Nin;
X
X  if (rat < 0L) {
X	if (!v_flag)
X		fprintf(stderr, "\r%s: ", pname);
X	fprintf(stderr, "Warning ");
X	if (!v_flag)
X		fprintf(stderr, "%s ", STDIN);
X  }
X
X  if (rat < 0L || v_flag) {
X	fprintf(stderr, "compression: %d", (int)(rat / 100));
X	fprintf(stderr, ".%02d%%\n", abs ((int)(rat % 100)));
X  }
X}
X
X/* Verbose option displays the info structure.
X*/
Xchar *info[] = {
X  "\rThis is comic Version ", VERSION, "\t  ",
X  "(p) Jan-Mark Wams (email: jms@cs.vu.nl)\n",
X#ifdef __DATE__
X  "Compiled on: ", __DATE__, "\n",
X#endif
X  "Flags: ",
X#ifdef DEBUG
X  "DEBUG ",
X#endif
X#ifdef C89
X  "C89 ",
X#endif
X#ifdef _MINIX
X  "MINIX ",
X#endif
X#ifdef UNIX
X  "UNIX ",
X#endif
X#ifdef AMOEBA
X  "AMOEBA ",
X#endif
X#ifdef M68
X  "M68 ",
X#endif
X#ifdef __BCC__
X  "BCC ",
X#endif
X#ifdef GCC
X  "GCC ",
X#endif
X#ifdef DOS
X  "DOS ",
X#endif
X#ifdef MSC
X  "MSC ",
X#endif
X#ifdef __TURBOC__
X  "TURBOC ",
X#else
X# ifdef __STDC__
X#  if ! __STDC__
X  "!",
X#  endif
X  "STDC ",
X# endif
X#endif
X#ifdef NDEBUG
X  "NDEBUG ",
X#endif
X#ifdef _POSIX_SOURCE
X  "_POSIX_SOURCE ",
X#endif
X  "\n",
X#ifdef H2_SIZE
X  "Hash table: %d,%d",
X#else
X  "Dynamic hash table",
X#endif
X  "\n",
X  NULL,
X};
X
X/* verbose_info: Give verbose information about this program.
X*/
Xvoid verbose_info()
X{
X  char **p;
X  for (p = info; *p != NULL; p++)
X	fprintf(stderr, *p, H1_SIZE, H2_SIZE); /* SIZEs not always needed. */
X}
X
X/* Usage: print the usage of comic.
X*/
Xvoid usage()
X{
X#ifndef DOS
X  char *options = "cdfrsvV?";
X
X  if (str_equel(pname, DECOMIC))
X        options = "cfrvV?";
X  else if (str_equel(pname, XCAT))
X        options = "rvV?";
X#else
X  char *options = "acdfrSvV?";
X  char *optstr;
X
X  if (str_equel(pname, DECOMIC))
X        options = "acfrvV?";
X  else if (str_equel(pname, XCAT))
X        options = "arvV?";
X#endif /* DOS */
X
X  fprintf(stderr, "Usage: %s [-%s] [<file>[-X]...]\n", pname, options);
X
X#ifdef DOS              /* DOS has no manual pages so we add extra info. */
X  while (*options != '\0') {
X        switch (*options) {
X          case 'r': optstr = "Raw; don't use a header";            break;
X          case 'c': optstr = "Cat; generate ouput on stdout";      break;
X          case 'd': optstr = "De-comic; decomic given files";      break;
X          case 'f': optstr = "Force; just carry on";               break;
X          case 'S': optstr = "Suffix; don't save the suffix";      break;
X          case 'a': optstr = "Ascii; %ss ascii files only";        break;
X          case 'v': optstr = "Verbose; tell what's going on";      break;
X          case 'V': optstr = "Version; give %ss version";          break;
X          case '?': optstr = "What; give usage of %s";             break;
X          default:  optstr = "even I don't know this one";
X        }
X	fprintf(stderr, "    -%c:  ", *options);
X	fprintf(stderr, optstr, pname); /* Pname not always needed. */
X	fprintf(stderr, ".\n");
X        options ++;
X  }
X  fprintf(stderr, "   -ff:  Carry on through fatal errors.\n");
X  if (str_equel(pname, COMIC))
X	fprintf(stderr, "   -vv:  Extra verbose output.\n");
X# ifdef DEBUG
X  fprintf(stderr, "  -vvv:  Super verbose (debug) output.\n");
X# endif /* DEBUG */
X#endif /* DOS */
X}
X
X
X/* File_start: Print a message if verbose option.
X*/
Xvoid file_start()
X{
X  if (v_flag) {
X	fprintf(stderr, "%s: ", STDIN);
X        if (d_flag)
X		fprintf(stderr, "decomicing");
X  }
X  fflush(stderr);
X}
X
X/* File_done: Print a message if verbose option.
X*/
Xvoid file_done()
X{
X  if (v_flag && d_flag)
X	fprintf(stderr, "\b\b\bed to %s\n", STDOUT);
X  if (!d_flag)
X	print_ratio();
X  fflush(stderr);
X}
X
X/* 
X   For speed's sake, a (two dimensional) hash table is implemented
X   on top of the existing structure (circular buffer).
X   For each character pair {c1, c2} there exists an index(at hash_tbl 
X   [H1(c1), H2(c2)]) containing the index of the first pair {d1, d2}
X   in the buffer so that H1(c1) == H1(d1) and H2(c2) == H2(d2). 
X   Both Hs are functions ie. if H (c) != H (d) than c != d. The same 
X   index is used as an index to the index list, to find the next index. 
X   Again this index is used in both the buffer and the index list 
X   (next_list) etc. The final index is INDEX_END. There is also an 
X   index list pointing back, so the index list can be quickly updated. 
X   This leaves us with a double linked list like construction.
X*/
X
Xindext *hash_tbl = (indext *)NULL;
Xindext next_list[BUFF_SIZE];                   /* The index list. */
Xindext back_list[BUFF_SIZE];                   /* The back list. */
X
X  static char *Hash_Mem = NULL;
X
X/* hash_init: Initialise the hash table.
X*/
Xvoid hash_init()
X{
X  int i;
X#ifndef H2_SIZE
X  char _stack_space_needed_by_program[2048];
X  _stack_space_needed_by_program[0] |= 1;
X#endif
X
X  /* First time Hash_Mem == NULL
X  */
X  if (Hash_Mem == NULL)
X	Hash_Mem = malloc(H1_SIZE * H2_SIZE * sizeof(indext));
X
X#ifndef H2_SIZE
X  /* Find the maximum amount of memory, Note that this 
X  ** might leave us with a stack space shortage ;-(.
X  */ 
X  while (Hash_Mem == NULL && H1_SIZE > 4) {
X        if (H1_SIZE == H2_SIZE)
X	       H2_SIZE >>= 1;
X        else 
X               H1_SIZE >>= 1;
X	Hash_Mem = (char *)malloc(H1_SIZE * H2_SIZE * sizeof(indext));
X  }
X  if (v_flag > 1)
X	fprintf(stderr, "\r%s: Hash size %d,%d\n", pname, H1_SIZE, H2_SIZE);
X#endif /* H2_SIZE */
X
X  if (Hash_Mem == NULL) {
X	fprintf(stderr, "\r%s: Out of memory.\n", pname);
X	exit(-1);
X  }
X  hash_tbl = (indext *)Hash_Mem;
X
X  /* Init the hash table.
X  */
X  for (i = 0; i < H1_SIZE * H2_SIZE; i++)
X	hash_tbl[i] = INDEX_END;
X
X  /* Fill the next_list and back_list.
X  */
X  next_list[0] = BUFF_SIZE - 1;
X  back_list[BUFF_SIZE - 1] = 0;
X  for (i = 1; i < BUFF_SIZE; i++) {
X	next_list[i] = i - 1;
X	back_list[i - 1] = i;
X  }
X
X  /* Update the hash table for a buffer full of zeros.
X  */
X  hash_entry('\0', '\0') = i = Bindex(Bsub(Bp, 2));
X  back_list[i] = INDEX_END;
X  next_list[Bindex(Bsub(Bp, OFFSET_MAX))] = INDEX_END;
X}
X
X
X/* Hash_update: Update the hash table. (Using the char at Bp)
X*/
Xvoid hash_update()
X{
X  char p = *Bpred(Bp);                         /* Previous char. */
X  char c = *Bp;                                 /* Current char. */
X  indext icur = Bindex(Bp);                    /* Current index. */
X  indext ipre = Ipred(icur);                   /* Previous index. */
X  char *  tail = Bsub(Bp, OFFSET_MAX);         /* Tail of offset buff. */
X  indext new_tail = back_list[Bindex(tail)];  /* New tail of next list. */
X  indext ipc = hash_entry(p, c);               /* Index of hash (p,c). */
X
X  if (next_list[Bindex(tail)] != INDEX_END)
X        *Bp = *Bp;
X
X  /* assert (next_list[Bindex(tail)] == INDEX_END); @@@ */
X
X  if ((next_list[ipre] = ipc) != INDEX_END)
X  back_list[ipc] = ipre;
X  hash_entry(p, c) = ipre;             /* Update list at head of buffer. */
X  back_list[ipre] = INDEX_END;
X
X  if (new_tail == INDEX_END) {          /* Idem tail. */
X	hash_entry(*tail, *Bsucc (tail)) = INDEX_END;
X  }
X  else {
X	next_list[new_tail] = INDEX_END;
X  }
X}
X
X/*
X   Decoding: Note we always decode stdin to stdout. Get a bit, 
X   if it's a 0, decode a pair, if it's a 1, decode a char. If 
X   it's 1 nor 0, fly the broomstick. *8-)
X*/
X
X/* decode_pair: Read offset and length, and put substring on stdout.
X*/
Xvoid decode_pair()
X{
X  int len, off = Hdecode(Hoff);
X  char *p;
X
X  off = off << LOW_OFFSET_BITS;
X  off |= get_n_bits(LOW_OFFSET_BITS);
X  off += OFFSET_MIN;
X  len = Hdecode(Hlen) + LENGTH_MIN;
X#ifdef DEBUG
X  if (v_flag > 1)
X	printf("<%d,%d>\"", off, len);
X#endif
X  p = Bsub(Bp, off);
X  while (len --) {
X        putchar (*p);
X        *Bp = *p;
X	p = Bsucc(p);
X	Bp = Bsucc(Bp);
X  }
X#ifdef DEBUG
X  if (v_flag > 1)
X# ifdef DOS
X	printf("\"\r\n");
X# else
X	printf("\"\n");
X# endif
X#endif
X}
X
X/* decode_char: Get a huffman encoded char and put it on stdout.
X*/
Xvoid decode_char()
X{
X  int c = Hdecode(Hchar);
X  putchar (c);
X#ifdef DEBUG
X  if (v_flag > 1) {
X# ifdef DOS
X        putchar ('\r');
X# endif
X        putchar ('\n');
X  }
X#endif
X  *Bp = c;
X  Bp = Bsucc(Bp);
X}
X
X/* get_input: Get input buffer full, return EOF if end of file, SPC otherwise.
X*/
Xint get_input()
X{
X  static unsigned long fsize = 0L;
X  static struct stat st[1];
X  static int printed = -1;              /* -1 Means don't print. */
X  int percent, c;
X  char *stop = Blookupstart(), *Oinputend = Binputend;
X
X  if (v_flag > 1 && Nin == 0 && fstat (0, st) == 0 
X      && S_ISREG (st[0].st_mode)) {
X	fsize = (unsigned long) (st[0].st_size);
X	fprintf(stderr, "  0%%");
X	fflush(stderr);
X        printed = 0;
X  }
X
X/*
X   Read stdin till stop. This code may look complicated, but it
X   isn't. Most of it is about printing.
X*/
X
X  while (Binputend != stop && (c = getchar()) != EOF) {
X        *Binputend = c;
X#ifdef DOS
X        if (a_flag && c == '\n')        /* Size of file is including \r. */
X                Nin += 1;               /* But we don't read it, so adjust. */
X#endif
X	Binputend = Bsucc(Binputend);  /* Increase the input end marker. */
X  }
X  Nin += Bdelta(Binputend, Oinputend); /* Count the number of char's read. */
X
X  if (Nin < fsize) {    /* Note 0 <=  Nin < fsize A thus 0 < fsize */
X        percent = 100 - (int)((fsize - Nin) / (fsize / 100));
X        if (percent > printed) {
X		fprintf(stderr, "\b\b\b\b%3d%%", percent);
X		fflush(stderr);
X                printed = percent;
X        }
X  }
X
X  if (Bp == Binputend) {
X        assert (Oinputend == Binputend);
X#ifdef DOS
X        if (a_flag && fsize != 0 && Nin != fsize && Nin != fsize -1) {
X		fprintf(stderr, "\r%s: -a used on binary data:", pname);
X		fprintf(stderr, " aberrant decomic results\n");
X        }
X        else
X                assert (fsize == 0 || Nin == fsize || Nin == fsize - 1);
X#else
X        /* This assertion might fail if one comics a binary file under MS-DOS.
X        */
X        assert (fsize == 0 || Nin == fsize);
X#endif /* DOS */
X        if (printed != -1) {
X		fprintf(stderr, "\b\b\b\b");
X		fflush(stderr);
X        }
X        return EOF;
X  }
X  else
X	return (int)' ';
X}
X
X/*
X   To find the best (longest) part to output we try to find the longest 
X   part matching the input in the lookup buffer. Well actually, we look 
X   for two srings, one, matching the current input, starting at the current 
X   buffer start, and one matching the string starting at the next input 
X   byte, (as if we decoded a char.) This is just in case decoding two 
X   pairs could have been done, using one char and pair. (This will save 
X   a few % extra.) To show what I mean, consider:
X  
X                                        xxxxx.AxAxxxxx
X        This would be parsed            x xxxx . A x Ax xxxx
X        but xxxx costs (about) as
X        much as xxxxx. So               x xxxx . A x A xxxxx
X        will be better.
X*/
X
X
X/* Eqlen: Return the number of bytes for which p[i] and q[i] are the same.
X*/
Xint eqlen(p, q, count)
Xchar *p;
Xregister char *q;
Xint count;
X{
X  register char *r;
X  char *stop, save;
X
X  assert (p != q);
X
X#ifdef OLD_SLOW_CODE
X  /*
X      If the code below look fussy, it's just a quick version of:
X  */
X  while (*r == *q && r != stop) {
X	r = Bsucc(r);
X	q = Bsucc(q);
X  }
X#else
X
X  if (p > q) {
X	r = q;
X	q = p;
X	p = r;
X  }
X  else
X	r = p;
X
X  /*
X      +-------------------------+-+
X      |           Buff          | | 
X      +-------------------------+-+
X      p=r^   q^   stop^    Bend^ ^Sentp
X  */
X
X  assert (r < q);
X
X  /* Prevent q from equeling stop in while loop. */
X  if (q - r <= count) {
X	stop = Badd(q, count);
X	save = *stop;
X	*stop = ~*Badd(r, count);
X  }
X  else {
X	stop = Badd(r, count);
X	save = *stop;
X	*stop = ~*Badd(q, count);
X  }
X
X  *Sentp = ~r[Sentp - q];
X  while (*r == *q) {
X	r++; 
X	q++;
X  }
X  if (q == Sentp) {
X	q = Buff;
X	*Sentp = ~Buff[Sentp - r];
X	while (*r == *q) {
X		r++;
X		q++;
X	}
X	if (r == Sentp) {
X		r = Buff;
X		while (*r == *q) {
X			r++;
X			q++;
X		}
X	}
X  }
X  *stop = save;
X#endif 
X
X  assert (Bdelta(r, p) <= count);
X  return Bdelta(r, p);
X}
X
X
X/* get_token: Find the best (longest) part to output.
X*/
Xvoid get_token(pair_0used)
Xint pair_0used;             /* Indicate if pair_0 was used. */
X{
X  register indext i;
X  register int len;             /* Used to store the result of eqlen. */
X  register int length;          /* Used for p[01]->length. */
X  register char *start = NULL;  /* Used for p[01]->start. */
X
X  /* Itail is a valid start value for pair_0, but not for pair_1.
X  */
X  indext itail = Bindex(Bsub(Bp, OFFSET_MAX)); /* Last index. */
X
X  int maxlen = Bdelta(Binputend, Bp);  /* Max match length. */
X  char *Bp1 = Bsucc(Bp);            /* Successor of Bp. */
X  char *Bp2 = Bsucc(Bp1);           /* Guess... */
X  char *Bp_1 = Bpred(Bp);
X
X  if (maxlen < LENGTH_MIN) {
X	pair_0->length = 0;
X        return;
X  }
X
X  if (maxlen > LENGTH_MAX) {
X        assert (maxlen <= LENGTH_MAX + PAIR_MAX + 1);
X        maxlen = LENGTH_MAX;
X  }
X
X  if (!pair_0used) {                      /* If pair_0 wasn't used, pair_1 */
X	pair_0->start = pair_1->start;   /* will be the new pair_0. */
X	     pair_0->length = pair_1->length; /* pair_1->length might be */
X	     if (pair_0->length >= maxlen) {   /* one too big. */
X			  pair_0->length = maxlen;
X			  pair_1->length = 0;
X		          return;                    /* We can't beat maxlen. */
X        }
X  }
X  else {
X        if (*Bp_1 == *Bp && *Bp == *Bp1) {    /* Bp - 1 isn't in the hash */
X                 start = Bp_1;
X		 length = eqlen(Bp_1, Bp, maxlen);
X                 if (length == maxlen) {
X                         pair_0->start = start;   /* This test saves time */
X                         pair_0->length = length; /* while comic-ing binary */
X                         pair_1->length = 0;      /* data (eg. tar files). */
X                         return;
X                 }
X        }         
X        else
X                length = 0;
X
X	i = hash_entry(*Bp, *Bp1);
X
X        while (i != INDEX_END) {
X		if (*Badd(Buff + i, length) == *Badd(Bp, length)
X		&& (len = eqlen(Buff + i, Bp, maxlen)) > length) {
X                        start = Buff + i;
X                        length = len;
X                }
X		i = next_list[i];
X        }
X	pair_0->start = start;
X	pair_0->length = length;
X  }
X
X  /* We should adjust maxlen here, but we get faster code if we just check 
X  ** if pair_1->length is (one) too long whilst copying pair_1 to pair_0.
X  */
X
X  if (*Bp == *Bp1 && *Bp1 == *Bp2) {   /* Bp1 - 1 isn't in the hash. */
X        start = Bp;
X	length = eqlen(Bp, Bp1, maxlen);
X        if (length == maxlen) {
X		pair_1->start = start;
X		pair_1->length = length;
X                return;
X        }
X  }
X  else if (*Bp_1 == *Bp1) {             /* Bp1 - 2 neither. */
X        start = Bp_1;
X	length = eqlen(Bp_1, Bp1, maxlen);
X        if (length == maxlen) {
X		pair_1->start = start;
X		pair_1->length = length;
X                return;
X        }
X  }
X  else
X        length = 0;
X
X  i = hash_entry(*Bp1, *Bp2);          /* Do pair_1. */
X
X  while (i != INDEX_END /* (i != itail) is done in if below. */) {
X	if (*Bp != Buff[Ipred(i)])
X	if (*Badd(Buff + i, length) == *Badd(Bp1, length))
X	if ((len = eqlen(Buff + i, Bp1, maxlen)) > length)
X	if (i != itail) {
X		start = Buff + i;
X		length = len;
X	}
X	i = next_list[i];
X  }
X
X  pair_1->start = start;
X  pair_1->length = length;
X
X  assert (pair_0->length <= maxlen);
X  assert (pair_1->length <= maxlen);
X}
X
X/* Magic_ok: Check the first bytes on stdin. They should be ok.
X** Return True if magic is ok, else False. Also set suffix if one
X** is there.
X*/
Xint magic_ok()
X{
X  char c1, c2;
X
X  if (r_flag)
X        return 1; /* No header in raw mode. */
X
X#ifdef DOS
X  setmode(0, O_BINARY);
X#endif
X
X  if (read (0, &c1, 1) != 1) {
X	fprintf(stderr, "\r%s: Can't read header\n", pname);
X        if (f_flag < 2) return 0;
X  }
X
X  if (read (0, &c2, 1) != 1) {
X	fprintf(stderr, "\r%s: Can't read header's 2nd byte\n", pname);
X        if (f_flag < 2) return 0;
X  }
X
X  if (c1 != MAGIC1 || (c2 & 0xF0) != MAGIC2) {
X	fprintf(stderr, "\r%s: Wrong magic in header\n", pname);
X        if (f_flag < 2) return 0;
X  }
X
X  suffix[0] = '\0';
X  if ((c2 & SUFFIX_BIT) != 0 && read (0, suffix, SUFFIX_LEN) != SUFFIX_LEN) {
X	fprintf(stderr, "\r%s: Can't read suffix bytes\n", pname);
X        if (f_flag < 2) return 0;
X  }
X
X  if ((c2 & DYNAMIC_BIT) != 0 || (c2 & STATIC_BIT) == 0) {
X	fprintf(stderr, "\r%s: Version %s ", pname, VERSION);
X	fprintf(stderr, "can't handle dynamic bit\n");
X        if (f_flag < 2) return 0;
X  }
X  if ((c2 & EXTEND_BIT) != 0) {
X	fprintf(stderr, "\r%s: Version %s ", pname, VERSION);
X	fprintf(stderr, "can't handle extend bit\n");
X        if (f_flag < 2) return 0;
X  }
X
X  return 1;
X}
X
X/* Put_magic: Write magic header on stdout. Append MS-DOS suffix to.
X*/
Xvoid put_magic()
X{
X  char c1 = MAGIC1, c2 = (MAGIC2 | STATIC_BIT);
X
X  if (r_flag)
X        return; /* Don't put magic in raw mode. */
X
X  /* Put the suffix bits if necessary.
X  */
X  if (s_flag && suffix[0] != '\0')
X      c2 |= SUFFIX_BIT;
X
X  if (write (1, &c1, 1) != 1 || write (1, &c2, 1) != 1) {
X	fprintf(stderr, "\r%s: Can't write header\n", pname);
X	exit(-1);
X  }
X#ifdef DOS
X  setmode(1, O_BINARY);
X#endif
X  if (s_flag && suffix[0] != '\0') {
X        if (write (1, suffix, SUFFIX_LEN) != SUFFIX_LEN) {
X		fprintf(stderr, "\r%s: Can't write suffix\n", pname);
X		exit(-1);
X        }
X        Nout += SUFFIX_LEN;  /* Account two byte suffix. */
X  }
X  Nout += 2;    /* Account two bytes magic. */
X}
X
X/* 
X   H (huffman) routines to get and put huffman codes. Note: If the 
X   Hencode is called for SWITCH codes with a codelength > HUFFMAN_BITS,
X   the actual code is used. This is mainly an optimisation for binary 
X   chunks in the text. This could be replaced by dynamic huffman code.
X   (See f.e. "Data Compression" ACM Computing Surveys, Vol.19 No. 3 
X   September 1987). I tried modified BSTW, but that wasn't too good.
X*/
X
X#define SWITCH 8
X
X#if OFFSET_BITS != 13
X# include "COMILER ERROR: the tables are generated for 13 bits."
X#endif
X
Xstruct ctab_s * ctab_tab[] = { ctab_char, ctab_off, ctab_len };
Xstruct tree_s * tree_tab[] = { tree_char, tree_off, tree_len };
Xint Ntolong[3];                /* Ntolong for each table. */
X
X/* Descend: descend down the tree.
X*/
Xint descend (tree)
Xstruct tree_s *tree;
X{
X  int i = (HUFFMAN_SIZE * 2) - 2;
X  int bit;
X
X  while (i >= HUFFMAN_SIZE) {
X        bit = get_bit();
X        if (bit == 0) {
X                i = tree[i - HUFFMAN_SIZE]._0;
X        } else
X        if (bit == 1) {
X                i = tree[i - HUFFMAN_SIZE]._1;
X        } else
X        if (bit == EOF) {
X                fprintf(stderr, "\r%s: Unexpected EOF\n", pname);
X                exit(-1);
X        } else {
X                fprintf(stderr, "\r%s: Funny bit\n", pname);
X                exit(-1);
X        }
X  }
X  return i;
X}
X
X
X/* Hinit: Get the proper huffman code tables.
X*/
Xvoid Hinit()
X{
X  Ntolong[0] = 0;
X  Ntolong[1] = 0;
X  Ntolong[2] = 0;
X}
X
X
X/* Hdecode: Get an int using a huffman tree.
X*/
Xint Hdecode(index)
Xint index;
X{
X  struct tree_s *tree = tree_tab[index];
X  struct ctab_s *ctab = ctab_tab[index];
X  int i;
X
X  if (Ntolong[index] > SWITCH) {
X	i = (int)get_n_bits(HUFFMAN_BITS);
X	if (ctab[i].length > HUFFMAN_BITS)
X		Ntolong[index] = SWITCH << 1;
X        else
X		Ntolong[index] -= 1;
X  }
X  else {
X        i = descend (tree);
X	if (ctab[i].length > HUFFMAN_BITS)
X		Ntolong[index] += 1;
X        else
X		Ntolong[index] = 0;
X  }
X  return i;
X}
X
X
X/* Hcodelen: Return the length of the encoded word in bits.
X*/
Xint Hcodelen(index, c)
Xint index;
Xint c;
X{
X  return Ntolong[index] > SWITCH ? HUFFMAN_BITS : ctab_tab[index][c].length;
X}
X
X/* Hencode: output code i from code table ctab
X*/
Xvoid Hencode(index, i)
Xint index, i;
X{
X  struct ctab_s *ctab = ctab_tab[index];
X  int len = ctab[i].length;
X
X  if (Ntolong[index] > SWITCH) {
X	put_n_bits((long)i, HUFFMAN_BITS);
X        if (len > HUFFMAN_BITS)
X		Ntolong[index] = SWITCH << 1;
X        else
X		Ntolong[index] -= 1;
X  }
X  else {
X	put_n_bits((long)(ctab[i].code), len);
X        if (len > HUFFMAN_BITS)
X		Ntolong[index] += 1;
X        else
X		Ntolong[index] = 0;
X  }
X}
X
X
X/* Decode: decode stdin. Read a bit from stdin, if it's a 0, decode a pair,
X** if it's a 1 decode a char, if it's EOF, return.
X*/
Xvoid decode()
X{
X  int bit;
X
X  Bsize = OFFSET_SIZE + OFFSET_MIN;
X  Bend = &(Buff[OFFSET_MAX]);
X  Bp = Binputend = Buff;        /* Not necessary, but.. */
X  Binit();                     /* Init the buffer. */
X  Hinit();                     /* Init the huffman tables. */
X  init_bits();                 /* Init the bit package. */
X
X#ifdef DOS
X  setmode(0, O_BINARY);        /* And you wonder why they call it SM_DOS. */
X  if (a_flag)
X	setmode(1, O_TEXT);
X  else
X	setmode(1, O_BINARY);
X#endif
X
X  for (;;) {
X        bit = get_bit();
X        if (bit == 0) {
X                decode_pair();
X        } else
X        if (bit == 1) {
X                decode_char();
X        } else
X        if (bit == EOF) {
X                fflush(stdout);
X                return;                 /* EOF: we're done */
X        } else {
X                fprintf(stderr, "\r%s: Funny bit\n", pname);
X                exit(-1);
X        }
X  }
X}
X
X
X/*
X   Encoding is simple: Get next two longest strings, if the second 
X   one is longer, or the first one isn't long enough, encode a char,
X   else encode a pair, (offset, length).
X*/
X
X/* output_pair: Output pair_0's length and offset.
X*/
Xvoid output_pair(done)
Xint *done;      /* Set to False if pair codes are longer than char codes. */
X{
X  int offset = Bdelta(Bp, pair_0->start) - OFFSET_MIN;
X  int length = pair_0->length;
X
X  assert (offset >= 0);
X  assert (offset < OFFSET_SIZE);
X  assert (length >= LENGTH_MIN);
X  assert (length - LENGTH_MIN < HUFFMAN_SIZE);
X
X#if LENGTH_MIN <= 2
X  if (length == 2
X  &&
X      Hcodelen(Hoff, offset >> LOW_OFFSET_BITS) + LOW_OFFSET_BITS
X    + Hcodelen(Hlen, 2 - LENGTH_MIN)
X    >
X      Hcodelen(Hchar, 0xFF & (int)*Bp) 
X    + Hcodelen(Hchar, 0xFF & (int)*Bsucc(Bp))) {
X	*done = 0;
X	return;
X  }
X#endif
X
X  put_bit(0);                                  /* Put a 0. */
X  Hencode(Hoff, offset >> LOW_OFFSET_BITS);    /* Put offset high. */
X  put_n_bits((long)offset, LOW_OFFSET_BITS);   /* Put offset low. */
X  Hencode(Hlen, length - LENGTH_MIN);          /* Put index length. */
X
X#ifdef DEBUG
X  if (v_flag > 2) {
X	fprintf(stderr, "(%d,%d)", offset + OFFSET_MIN, length);
X	putc('"', stderr);
X  }
X#endif
X        while (length -- > 0) {
X#ifdef DEBUG
X		if (v_flag > 2) putc(*Bp, stderr);
X#endif
X		hash_update();         /* Update hash tables. */
X		Bp = Bsucc(Bp);
X        }
X#ifdef DEBUG
X        if (v_flag > 2) {
X		fprintf(stderr, "\"\n");
X		fflush(stderr);
X        }
X#endif /* DEBUG */
X  assert (done);
X}
X
X/* output_char: Output char *Bp.
X*/
Xvoid output_char()
X{
X  put_bit(1);                          /* Put a 1. */
X  Hencode(Hchar, (0xFF & (int)*Bp));   /* Put this char. */
X#ifdef DEBUG
X  if (v_flag > 2) {
X	putc('`', stderr);
X	putc(*Bp, stderr);
X	putc('\'', stderr);
X	putc('\n', stderr);
X  }
X#endif /* DEBUG */
X  hash_update();
X  Bp = Bsucc(Bp);                      /* Increase Bp. */
X}
X
X
X/* Encode: parse stdin, write huffman codes and bits on stdout.
X*/
Xvoid encode()
X{
X  /* Pairout indicates the pair pair_0 will be output, not just char *Bp.
X  */
X  int pairout = 1;
X  Bsize = BUFF_SIZE;
X  Bend = &(Buff[BUFF_MAX]);
X  Bp = Binputend = Buff;        /* Not necessary, but.. */
X  Binit();                     /* Init the buffer. */
X  Hinit();                     /* Init the huffman tables. */
X  init_bits();                 /* Init the bit package. */
X  hash_init();                 /* Init the hash tables. */
X
X#ifdef DOS
X  if (a_flag)
X	setmode(0, O_TEXT);
X  else
X	setmode(0, O_BINARY);  /* And you wonder why they call it SM_DOS. */
X
X  setmode(1, O_BINARY);
X#endif
X
X  while (get_input() != EOF) {
X	get_token(pairout);                      /* Find matching strings. */
X	pairout =  pair_0->length >= LENGTH_MIN  /* Long enough? */
X		&& pair_0->length >= pair_1->length;
X        if (pairout)
X		output_pair(&pairout);           /* If so, output its pair. */
X	if (!pairout)
X		output_char();                   /* Else do one char. */
X  }
X  flush_bits();                                  /* Flush buffered bits. */
X}
X
X/* main: Parse arguments, call proper (en/de) code routine.
X*/
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X  char *p;              /* Used for flag processing etc. */
X  char *fname;
X
X#ifdef DOS
X  /* DOS-file names are in UPPER case.
X  */
X  str_2_upper(SUFFIX);
X#endif
X
X  pname = basename(*argv);
X
X  argc --;
X  argv ++;      /* Skip pname. */
X
X
X  if (str_equel(pname, DECOMIC))   /* If this program is called */
X        d_flag = -1;            /* decomic set the decode flag. */
X
X  if (str_equel(pname, XCAT)) {    /* If this program is called */
X        d_flag = -1;            /* xcat set the decode */
X        c_flag = -1;            /* and cat flag. */
X  }
X
X  while (argc > 0 && (*argv)[0] == '-' && (*argv)[1] != '\0') {
X        for (p = *argv + 1; *p != '\0'; p++) {
X                switch (*p) {
X                case 'd': d_flag = 1; break;           /* decode flag on. */
X                case 'r': r_flag = 1; break;           /* Raw flag. */
X                case 'v': v_flag ++; break;            /* Verbose flag. */
X                case 'f': f_flag ++; break;            /* Force flag on. */
X#ifdef DOS
X                case 'a': a_flag = 1; break;           /* Ascii mode. */
X                case 'S': s_flag = 0; break;           /* No suffix save. */
X#else
X                case 's': s_flag = 1; break;           /* Save suffix. */
X#endif
X                case 'c': c_flag = 1; break;           /* Cat flag on. */
X		case 'V': verbose_info(); exit(0);   /* Verbose info. */
X		case '?': usage(); exit(0);          /* Usage and exit. */
X                default :
X		    fprintf(stderr, "\r%s: -%c ignored\n", pname, *p);
X		    fflush(stderr);
X                }
X        }
X        argc --; argv ++;	/* Next please. */
X  }
X
X  if (argc == 0) {		/* No args, do stdin to stdout. */
X        c_flag = 1;		/* Cat mode. */
X	file_start();
X        if (d_flag) {
X		if (magic_ok())
X			decode();
X        }
X        else {
X		put_magic();
X		encode();
X        }
X	file_done();
X  }
X  else {
X        if (c_flag && !d_flag && f_flag < 2 && argc > 1) {
X		fprintf(stderr, "\r%s: Won't concatanate ", pname);
X		fprintf(stderr, "multiple files.\n");
X		exit(-1);
X        }
X  }
X
X  while ((fname = next_arg()) != NULL) {
X#ifdef DOS
X	str_2_upper(fname);
X#endif
X        if (d_flag) {   /* Decode. */
X		if ( !new_stdin(new_name(fname))
X		||   !magic_ok()
X		||   !new_stdout(org_name(fname)))
X                        continue;       /* If not reopened, do next file. */
X		file_start();
X		decode();      /* Decode stdin. */
X		file_done();
X        }
X        else /* No d_flag */ {  /* Encode. */
X		if ((p = strrchr(fname, *SUFFIX)) != NULL
X		&&  strncmp(p, SUFFIX, SUFFIX_LEN) == 0) {
X                        if (v_flag) {
X				fprintf(stderr, "\r%s: ", pname);
X				fprintf(stderr, "%s already has ", fname);
X				fprintf(stderr, "%s suffix\n", SUFFIX);
X				fflush(stderr);
X                        }
X                        continue;
X                }
X		if ( !new_stdin(org_name(fname))
X		||   !new_stdout(new_name(fname)))
X                        continue;       /* If not reopened, do next file. */
X		file_start();
X		put_magic();
X		encode();              /* Put data on stdout. */
X		file_done();
X        }
X  }
X  return 0;
X}
/
echo x - decomp16.c
sed '/^X/s///' > decomp16.c << '/'
X/* decomp16: decompress 16bit compressed files on a 16bit Intel processor
X *
X * Version 1.3 of 25 Mar 92.
X *
X * This was written by John N. White on 6/30/91 and is Public Domain.
X * Patched to run under news by Will Rose, Feb 92.
X * J N White's (earlier) patches added by Will Rose, 20 Feb 92.
X * Unsigned int increment/wrap bug fixed by Will Rose, 24 Mar 92.
X * Argument bug fixed, stdio generalised by Will Rose, 25 Mar 92.
X *
X * decomp16 can use as as little as 512 bytes of stack; since it forks
X * four additional copies, it's probably worth using minimum stack rather
X * than the 8192 byte Minix default.  To reduce memory still further,
X * change BUFSZ below to 256; it is currently set to 1024 for speed.  The
X * minimal decomp16 needs about 280k to run in pipe mode (56k per copy).
X *
X * This program acts as a filter:
X *    decomp16 < compressed_file > decompressed_file
X * The arguments -0 to -4 run only the corresponding pass.
X * Thus:
X *    decomp16 -4 < compressed_file > 3;
X *    decomp16 -3 < 3 > 2;
X *    decomp16 -2 < 2 > 1;
X *    decomp16 -1 < 1 > 0;
X *    decomp16 -0 < 0 > decompressed_file
X * will also work, as will connecting the passes by explicit pipes if
X * there is enough memory to do so.  File name arguments can also be
X * given directly on the command line.
X *
X * Compress uses a modified LZW compression algorithm. A compressed file
X * is a set of indices into a dictionary of strings. The number of bits
X * used to store each index depends on the number of entries currently
X * in the dictionary. If there are between 257 and 512 entries, 9 bits
X * are used. With 513 entries, 10 bits are used, etc. The initial dictionary
X * consists of 0-255 (which are the corresponding chars) and 256 (which
X * is a special CLEAR code). As each index in the compressed file is read,
X * a new entry is added to the dictionary consisting of the current string
X * with the first char of the next string appended. When the dictionary
X * is full, no further entries are added. If a CLEAR code is received,
X * the dictionary will be completely reset. The first two bytes of the
X * compressed file are a magic number, and the third byte indicates the
X * maximum number of bits, and whether the CLEAR code is used (older versions
X * of compress didn't have CLEAR).
X *
X * This program works by forking four more copies of itself. The five
X * programs form a pipeline. Copy 0 writes to stdout, and forks copy 1
X * to supply its input, which in turn forks and reads from copy 2, etc.
X * This sequence is used so that when the program exits, all writes
X * are completed and a program that has exec'd uncompress (such as news)
X * can immediately use the uncompressed data when the wait() call returns.
X *
X * If given a switch -#, where # is a digit from 0 to 4 (example: -2), the
X * program will run as that copy, reading from stdin and writing to stdout.
X * This allows decompressing with very limited RAM because only one of the
X * five passes is in memory at a time.
X *
X * The compressed data is a series of string indices (and a header at
X * the beginning and an occasional CLEAR code). As these indices flow
X * through the pipes, each program decodes the ones it can. The result
X * of each decoding will be indices that the following programs can handle.
X *
X * Each of the 65536 strings in the dictionary is an earlier string with
X * some character added to the end (except for the the 256 predefined
X * single char strings). When new entries are made to the dictionary,
X * the string index part will just be the last index to pass through.
X * But the char part is the first char of the next string, which isn't
X * known yet. So the string can be stored as a pair of indices. When
X * this string is specified, it is converted to this pair of indices,
X * which are flagged so that the first will be decoded in full while
X * the second will be decoded to its first char. The dictionary takes
X * 256k to store (64k strings of 2 indices of 2 bytes each). This is
X * too big for a 64k data segment, so it is divided into 5 equal parts.
X * Copy 4 of the program maintains the high part and copy 0 holds the
X * low part.
X */
X
X#include <sys/types.h>
X#include <fcntl.h>
X#include <stdlib.h>
X#include <unistd.h>
X
X#define BUFSZ		1024	/* size of i/o buffers */
X#define BUFSZ_2		(BUFSZ/2)	/* # of unsigned shorts in i/o bufs */
X#define DICTSZ		(unsigned)13056	/* # of local dictionary entries */
X#define EOF_INDEX	(unsigned short)0xFFFF	/* EOF flag for pipeline */
X#define FALSE		0
X#define TRUE		~FALSE
X
Xint fdin, fdout, fderr;		/* input, output, and error file descriptors */
Xint ibufstart, obufind, ibufend;/* i/o buffer indices */
Xint ipbufind = BUFSZ_2;		/* pipe buffer indices */
Xint opbufind = 0;
Xint pnum = -1;			/* ID of this copy */
Xunsigned short ipbuf[BUFSZ_2];	/* for buffering input */
Xunsigned short opbuf[BUFSZ_2];	/* for buffering output */
Xunsigned char *ibuf = (unsigned char *) ipbuf;
Xunsigned char *obuf = (unsigned char *) opbuf;
X
Xunsigned short dindex[DICTSZ];	/* dictionary: index to substring */
Xunsigned short dchar[DICTSZ];	/* dictionary: last char of string */
Xunsigned iindex, tindex, tindex2;	/* holds index being processed */
Xunsigned base;			/* where in global dict local dict starts */
Xunsigned tbase;
Xunsigned locend;		/* where in global dict local dict ends */
Xunsigned curend = 256;		/* current end of global dict */
Xunsigned maxend;		/* max end of global dict */
Xint dcharp;			/* ptr to dchar that needs next index entry */
Xint curbits;			/* number of bits for getbits() to read */
Xint maxbits;			/* limit on number of bits */
Xint clearflg;			/* if set, allow CLEAR */
Xint inmod;			/* mod 8 for getbits() */
X
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(void ffork, (void));
X_PROTOTYPE(void die, (char *s));
X_PROTOTYPE(void myputc, (unsigned c));
X_PROTOTYPE(unsigned mygetc, (void));
X_PROTOTYPE(void getbits, (void));
X_PROTOTYPE(void getpipe, (void));
X_PROTOTYPE(void putpipe, (unsigned u, int flag));
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X  char c, *cp;
X  int j, k, fdtmp;
X  unsigned int len;
X
X  /* Find the program name */
X  j = 0;
X  while (argv[0][j] != '\0') j++;
X  len = (unsigned int) j;
X  while (j--)
X	if (argv[0][j] == '/') break;
X  if (argv[0][j] == '/') j++;
X  cp = argv[0] + j;
X  len -= j;
X
X  /* Sort out the flags */
X  for (k = 1; k < argc; k++) {
X	if (argv[k][0] == '-') {
X		c = argv[k][1];
X		switch (c) {
X		    case '0':	/* pass numbers */
X		    case '1':
X		    case '2':
X		    case '3':
X		    case '4':	pnum = c - '0';	break;
X		    case 'd':	/* used by news */
X			break;
X		    default:
X			(void) write(1, "Usage: ", 7);
X			(void) write(1, cp, len);
X			(void) write(1, " [-#] [in] [out]\n", 17);
X			exit(0);
X			break;
X		}
X
X		/* Once it's checked, lose it anyway */
X		for (j = k; j < argc; j++) argv[j] = argv[j + 1];
X		argc--;
X		k--;
X	}
X  }
X
X  /* Default i/o settings */
X  fdin = 0;
X  fdout = 1;
X  fderr = 2;
X
X  /* Try to open specific files and connect them to stdin/stdout */
X  if (argc > 1) {
X	if ((fdtmp = open(argv[1], 0)) == -1) die("input open failed");
X	(void) close(0);
X	if ((fdin = dup(fdtmp)) == -1) die("input dup failed\n");
X	(void) close(fdtmp);
X  }
X  if (argc > 2) {
X	(void) unlink(argv[2]);
X	if ((fdtmp = creat(argv[2], 0666)) == -1) die("output creat failed");
X	(void) close(1);
X	if ((fdout = dup(fdtmp)) == -1) die("output dup failed\n");
X	(void) close(fdtmp);
X  }
X
X  /* Sort out type of compression */
X  if (pnum == -1 || pnum == 4) {/* if this is pass 4 */
X	/* Check header of compressed file */
X	if (mygetc() != 0x1F || mygetc() != 0x9D)      /* check magic number */
X		die("not a compressed file\n");
X	iindex = mygetc();	/* get compression style */
X  } else
X	getpipe();		/* get compression style */
X
X  maxbits = iindex & 0x1F;
X  clearflg = ((iindex & 0x80) != 0) ? TRUE : FALSE;
X  if (maxbits < 9 || maxbits > 16)	/* check for valid maxbits */
X	die("can't decompress\n");
X  if (pnum != -1 && pnum != 0)
X	putpipe(iindex, 0);	/* pass style to next copy */
X
X  /* Fork off an ancestor if necessary - ffork() increments pnum */
X  if (pnum == -1) {
X	pnum = 0;
X	if (pnum == 0) ffork();
X	if (pnum == 1) ffork();
X	if (pnum == 2) ffork();
X	if (pnum == 3) ffork();
X  }
X
X  /* Preliminary inits. Note: end/maxend/curend are highest, not
X   * highest + 1 */
X  base = DICTSZ * pnum + 256;
X  locend = base + DICTSZ - 1;
X  maxend = (1 << maxbits) - 1;
X  if (maxend > locend) maxend = locend;
X
X  while (TRUE) {
X	curend = 255 + (clearflg ? 1 : 0);	/* init dictionary */
X	dcharp = DICTSZ;	/* flag for none needed */
X	curbits = 9;		/* init curbits (for copy 0) */
X	while (TRUE) {		/* for each index in input */
X		if (pnum == 4) {/* get index using getbits() */
X			if (curbits < maxbits && (1 << curbits) <= curend) {
X				/* Curbits needs to be increased */
X				/* Due to uglyness in compress, these
X				 * indices in the compressed file are
X				 * wasted */
X				while (inmod) getbits();
X				curbits++;
X			}
X			getbits();
X		} else
X			getpipe();	/* get next index */
X
X		if (iindex == 256 && clearflg) {
X			if (pnum > 0) putpipe(iindex, 0);
X			/* Due to uglyness in compress, these indices
X			 * in the compressed file are wasted */
X			while (inmod) getbits();
X			break;
X		}
X		tindex = iindex;
X		/* Convert the index part, ignoring spawned chars */
X		while (tindex >= base) tindex = dindex[tindex - base];
X		/* Pass on the index */
X		putpipe(tindex, 0);
X		/* Save the char of the last added entry, if any */
X		if (dcharp < DICTSZ) dchar[dcharp++] = tindex;
X		if (curend < maxend && ++curend > (base - 1))
X			dindex[dcharp = (curend - base)] = iindex;
X
X		/* Do spawned chars. They are naturally produced in
X		 * the wrong order. To get them in the right order
X		 * without using memory, a series of passes,
X		 * progressively less deep, are used */
X		tbase = base;
X		while ((tindex = iindex) >= tbase) {/* for each char to spawn*/
X			while ((tindex2 = dindex[tindex - base]) >= tbase)
X				tindex = tindex2;    /* scan to desired char */
X			putpipe(dchar[tindex-base], 1); /* put it to the pipe*/
X			tbase = tindex + 1;
X			if (tbase == 0) break;	/* it's a wrap */
X		}
X	}
X  }
X}
X
X
X/* F f o r k
X *
X * Fork off the previous pass - the parent reads from the child.
X */
Xvoid ffork()
X{
X  int j, pfd[2];
X
X  if (pipe(pfd) == -1) die("pipe() error\n");
X  if ((j = fork()) == -1) die("fork() error\n");
X  if (j == 0) {			/* this is the child */
X	if (close(1) == -1) die("close(1) error\n");
X	if (dup(pfd[1]) != 1) die("dup(1) error\n");
X	(void) close(pfd[0]);
X	pnum++;
X  } else {			/* this is the parent */
X	if (close(0) == -1) die("close(0) error\n");
X	if (dup(pfd[0]) != 0) die("dup(0) error\n");
X	(void) close(pfd[1]);
X  }
X}
X
X
X/* D i e
X *
X * If s is a message, write it to stderr. Flush buffers if needed. Then exit.
X */
Xvoid die(s)
Xchar *s;
X{
X  /* Flush stdout buffer if needed */
X  if (obufind != 0) {
X	if (write(fdout, (char *) obuf, (unsigned) obufind) != obufind)
X		s = "bad stdout write\n";
X	obufind = 0;
X  }
X
X  /* Flush pipe if needed */
X  do
X	putpipe(EOF_INDEX, 0);
X  while (opbufind);
X  /* Write any error message */
X  if (s != (char *) NULL) {
X	while (*s) (void) write(fderr, s++, 1);
X  }
X  exit((s == (char *) NULL) ? 0 : 1);
X}
X
X
X/* M p u t c
X *
X * Put a char to stdout.
X */
Xvoid myputc(c)
Xunsigned c;
X{
X  obuf[obufind++] = c;
X  if (obufind >= BUFSZ) {	/* if stdout buffer full */
X	if (write(fdout, (char *) obuf, BUFSZ) != BUFSZ)	/* flush to stdout */
X		die("bad stdout write\n");
X	obufind = 0;
X  }
X}
X
X
X/* M y g e t c
X *
X * Get a char from stdin. If EOF, then die() and exit.
X */
Xunsigned mygetc()
X{
X  if (ibufstart >= ibufend) {	/* if stdin buffer empty */
X	if ((ibufend = read(fdin, (char *) ibuf, BUFSZ)) <= 0)
X		die((char *) NULL);	/* if EOF, do normal exit */
X	ibufstart = 0;
X  }
X  return(ibuf[ibufstart++] & 0xff);
X}
X
X
X/* G e t b i t s
X *
X * Put curbits bits into index from stdin. Note: only copy 4 uses this.
X * The bits within a byte are in the correct order. But when the bits
X * cross a byte boundry, the lowest bits will be in the higher part of
X * the current byte, and the higher bits will be in the lower part of
X * the next byte.
X */
Xvoid getbits()
X{
X  int have;
X  static unsigned curbyte;	/* byte having bits extracted from it */
X  static int left;		/* how many bits are left in curbyte */
X
X  inmod = (inmod + 1) & 7;	/* count input mod 8 */
X  iindex = curbyte;
X  have = left;
X  if (curbits - have > 8) {
X	iindex |= mygetc() << have;
X	have += 8;
X  }
X  iindex |= ((curbyte = mygetc()) << have) & ~((unsigned) 0xFFFF << curbits);
X  curbyte >>= curbits - have;
X  left = 8 - (curbits - have);
X}
X
X
X/* G e t p i p e
X *
X * Get an index from the pipeline. If flagged firstonly, handle it here.
X */
Xvoid getpipe()
X{
X  static short flags;
X  static int n = 0;		/* number of flags in flags */
X
X  while (TRUE) {		/* while index with firstonly flag set */
X	if (n <= 0) {
X		if (ipbufind >= BUFSZ_2) {	/* if pipe input buffer
X						 * empty */
X			if (read(fdin, (char *) ipbuf, BUFSZ) != BUFSZ)
X				die("bad pipe read\n");
X			ipbufind = 0;
X		}
X		flags = ipbuf[ipbufind++];
X		n = 15;
X	}
X	iindex = ipbuf[ipbufind++];
X	if (iindex > curend)
X		die((iindex == EOF_INDEX) ? (char *) NULL : "invalid data\n");
X	flags <<= 1;
X	n--;
X	/* Assume flags < 0 if highest remaining flag is set */
X	if (flags < 0) {	/* if firstonly flag for index is not set */
X		while (iindex >= base) iindex = dindex[iindex - base];
X		putpipe(iindex, 1);
X	} else
X		return;		/* return with valid non-firstonly index */
X  }
X}
X
X
X/* P u t p i p e
X *
X * put an index into the pipeline.
X */
Xvoid putpipe(u, flag)
Xunsigned u;
Xint flag;
X{
X  static unsigned short flags, *flagp;
X  static int n = 0;		/* number of flags in flags */
X
X  if (pnum == 0) {		/* if we should write to stdout */
X	myputc(u);		/* index will be the char value */
X	return;
X  }
X  if (n == 0) {			/* if we need to reserve a flag entry */
X	flags = 0;
X	flagp = opbuf + opbufind;
X	opbufind++;
X  }
X  opbuf[opbufind++] = u;	/* add index to buffer */
X  flags = (flags << 1) | flag;	/* add firstonly flag */
X  if (++n >= 15) {		/* if block of 15 indices */
X	n = 0;
X	*flagp = flags;		/* insert flags entry */
X	if (opbufind >= BUFSZ_2) {	/* if pipe out buffer full */
X		opbufind = 0;
X		if (write(fdout, (char *) opbuf, BUFSZ) != BUFSZ)
X			die("bad pipe write\n");
X	}
X  }
X}
/
echo x - diskusage.c
sed '/^X/s///' > diskusage.c << '/'
X/* Diskusg - determines usage disk	  Author: Don Chapman */
X
X/*
X *
X * Diskusg -	Patterned after System V Administrative command
X *		but written for MINIX V1.5 or V1.6 from scratch.
X *		Does not access disk structures directly.  Should
X *		be fairly portable to C with dirent.  This version
X *		will count files that are linked to other names for
X *		each name.
X *
X * Output:	Output is a listing, on stdout, by uid of the blocks
X *		in use on a special device (block structured, ie. disk)
X *		sorted by uid.  Shows total blocks in use on the
X *		device for each uid. Form: uid username longint.
X *
X * Usage:	diskusg [-p fil] [-u fil] [-s] [-v] [-i flst] spec.file ...
X *
X * Flags:	-p fil	Use "fil" to obtain a list of the usernames and
X *			uids rather than /etc/passwd.  The file must be
X *			similar in form to /etc/passwd at least beyond
X *			the uid. eg: ast:Oky||V|yoZ7vO:8: or ast::8:
X *
X *		-u fil	Make an ascii list in "fil" of files that seem to
X *			belong to nobody.  The form of the list is:
X *			    special-file-name i-node-number user-ID.
X *
X *		-s	The input files are files of diskusg outputs and
X *			the new output should be the cumulative sum of the
X *			usages.  The files were probably made using the
X *			command diskusg /specdev > file.  This one deletes
X *			any duplicate usernames and charges all to the
X *			first username it sees.
X *
X *		-v	Verbose makes a listing on stderr of the files or
X *			directorys found with unknown owners.
X *
X *		-i flst	Ignore the data on the file systems whose name is
X *			in flst.  Flst is a list of names separated by
X *			commas or enclosed within quotes. Diskusg compares
X *			each name with the names on the spec. file relative
X *			to the root (/) of the spec. file.
X *			ie: dskusg -i /tmp/ignoreme,/joe,/lib /dev/fd1
X *
X *		specfil	The name of a special file (block structured) to be
X *			searched for disk usage.
X *			eg.: /dev/hd2
X *
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <string.h>
X#include <dirent.h>
X#include <errno.h>
X#include <limits.h>
X#include <blocksize.h>
X#include <stdlib.h>
X#include <ctype.h>
X#include <unistd.h>
X#include <stdio.h>
X
X/* Un-comment or compile -DREMOVE_DUPES if you wish */
X /* #define REMOVE_DUPES *//* option to always remove duplicate usernames */
X#define FALSE 0
X#define TRUE ~FALSE
X#define PWLEN 100
X#define PLENGTH 40
X
X#define USEREC struct userecord
XUSEREC {
X  char *name;
X  uid_t uid;
X  long blocks;
X  USEREC *next;
X};
X
X#define IGNREC struct ignrecord
XIGNREC {
X  char *structname;
X  IGNREC *next;
X};
X
Xstatic char *Version = "@(#) DISKUSG 1.00 D.E.C. (04/10/91)";
X
X/* Globals */
Xchar *progname;
Xchar *passwd = "/etc/passwd";
Xchar *ufile = NULL;
Xint uflag = FALSE;
XFILE *ufd;
XUSEREC *list_head = NULL;
Xint verbose = FALSE;
Xint sflag = FALSE;
Xchar *spec_name = "\0";
Xstruct stat *this_stat;
Xdev_t real_dev;
Xchar *ilist = NULL;
Xint iflag = FALSE;
XIGNREC *ign_head = NULL;
Xint didmount = FALSE;
Xint mountlength;
X
X_PROTOTYPE(int exists, (USEREC * head, Uid_t uid));
X_PROTOTYPE(void insert, (USEREC ** head, USEREC * rec));
X_PROTOTYPE(void make_userlist, (void));
X_PROTOTYPE(void showlist, (void));
X_PROTOTYPE(int update_list, (Uid_t uid, off_t bytes));
X_PROTOTYPE(void search_all, (char *cur_dir));
X_PROTOTYPE(int ilist_search, (char *path));
X_PROTOTYPE(void usage, (void));
X_PROTOTYPE(int main, (int argc, char *argv[]));
X_PROTOTYPE(void malloc_chk, (void *p));
X
X
X/* For -s flag that builds the list as it goes */
Xint exists(head, uid)		/* See if uid already exists.    */
XUSEREC *head;			/* In -s list disallow dupes. */
XUid_t uid;
X{
X  USEREC *curs;
X  for (curs = head; curs != NULL; curs = curs->next)
X	if (curs->uid == uid) return(TRUE);
X  return(FALSE);
X}
X
Xvoid insert(head, rec)		/* Sorted by uid (keep duplicates)   */
XUSEREC **head;			/* Normally there should be none but */
XUSEREC *rec;			/* I wanted option to see them...    */
X{
X  if (*head == NULL) {
X	rec->next = *head;
X	*head = rec;
X#ifdef REMOVE_DUPES
X  } else if ((*head)->uid == rec->uid) {
X	return;
X#endif
X  } else if ((*head)->uid > rec->uid) {
X	rec->next = *head;
X	*head = rec;
X  } else
X	insert(&((*head)->next), rec);
X}
X
Xvoid make_userlist()
X{				/* Make list of known users.  */
X  FILE *fp1;			/* do not remove duplicates   */
X  USEREC *temp_rec;		/* however the blocks will    */
X  char line[PWLEN];		/* counted against first name */
X  char *p1;
X  size_t name_length;
X
X  fp1 = fopen(passwd, "r");
X  while (!feof(fp1)) {
X	if (fgets(line, PWLEN, fp1)) {
X		temp_rec = (USEREC *) malloc(sizeof(USEREC));
X		malloc_chk(temp_rec);
X		p1 = line;
X		name_length = 0;
X		while (*p1 && *p1 != ':') {
X			p1++;
X			name_length++;
X		}
X		*p1++ = '\0';
X		temp_rec->name = (char *) malloc(name_length + 1);
X		malloc_chk(temp_rec);
X		strcpy(temp_rec->name, line);
X		while (*p1 && *p1 != ':') p1++;	/* skip passwd */
X		temp_rec->uid = atoi(++p1);
X		temp_rec->blocks = 0L;
X		insert(&list_head, temp_rec);
X	}
X  }
X  fclose(fp1);
X}
X
Xvoid showlist()
X{
X  USEREC *curs;
X  for (curs = list_head; curs != NULL; curs = curs->next)
X	printf("%d\t%-14s\t%ld\n", curs->uid, curs->name, curs->blocks);
X}
X
Xint update_list(uid, bytes)	/* Increment uid's total.   */
XUid_t uid;			/* If uid has duplicates    */
Xoff_t bytes;			/* will be charged to first. */
X{
X  USEREC *curs;
X  int found = 0;
X  for (curs = list_head; curs != NULL; curs = curs->next) {
X	if (curs->uid == uid) {
X		found++;
X		curs->blocks += (bytes + BLOCK_SIZE - 1) / BLOCK_SIZE;	/* ceiling */
X		break;
X	}
X  }
X  return(found);		/* -u and -v option need to know */
X}
X
X/* Traverse recursively: all directories on volume. */
Xvoid search_all(cur_dir)		/* If another volume is mounted on this vol */
Xchar *cur_dir;			/* only the files really on this volume are */
X{				/* to be counted in the accumulated total.  */
X  struct dirent *this_file;
X  DIR *dp1;			/* Activation record 4 pointers 1 int so */
X  char *next_entry;		/* should be able to recurse very deep.  */
X  int dir_length;		/* Uses malloc and free for temporary space */
X  int s;
X
X  dir_length = strlen(cur_dir);
X  next_entry = (char *) malloc(strlen(cur_dir) + NAME_MAX + 2);
X  malloc_chk(next_entry);
X  strcpy(next_entry, cur_dir);
X  if (next_entry[dir_length - 1] != '/') {
X	strcat(next_entry, "/");
X	dir_length++;
X  }
X  dp1 = opendir(cur_dir);
X  if (dp1 == NULL) {
X	fprintf(stderr, "Opendir returned NULL.  (%s).\n", strerror(errno));
X	exit(EXIT_FAILURE);
X  }
X  while ((this_file = readdir(dp1)) != NULL) {
X	/* Iterate through this directory */
X	if (strcmp(this_file->d_name, ".") &&
X	    strcmp(this_file->d_name, "..")) {
X		strcpy(&next_entry[dir_length], this_file->d_name);
X		stat(next_entry, this_stat);
X		if (real_dev != this_stat->st_dev) continue;
X		if (iflag) {
X			if (ilist_search(next_entry)) continue;
X		}
X		if (S_ISDIR(this_stat->st_mode)) {
X			/* Is a directory need to recurse */
X			s = update_list((Uid_t) this_stat->st_uid, 
X							   this_stat->st_size);
X			if (!s) {
X				if (verbose) fprintf(stderr,
X						"%s: Directory, No Owner, %s\n",
X					      progname, next_entry);
X				if (uflag) fprintf(ufd, "%s %d %d\n",
X						spec_name,
X						this_stat->st_ino,
X						this_stat->st_uid);
X			}
X			search_all(next_entry);	/* recursive call */
X		} else {
X			/* Is regular file or spec. file */
X			if (S_ISREG(this_stat->st_mode)) {
X				s = update_list((Uid_t) this_stat->st_uid,
X							   this_stat->st_size);
X				if (!s) {
X					if (verbose) fprintf(stderr,
X							"%s: File, No Owner, %s\n",
X							progname, next_entry);
X					if (uflag) fprintf(ufd, "%s %d %d\n",
X						spec_name, this_stat->st_ino,
X						this_stat->st_uid);
X				}	/* endif !update */
X			}	/* end S_ISREG */
X			/* Ignores any Specials: b, c, pipe, etc. */
X		}		/* endelse */
X	}			/* endif "." */
X  }				/* endwhile */
X  closedir(dp1);
X  free(next_entry);
X}
X
Xint ilist_search(path)
Xchar *path;
X{
X  IGNREC *ptr;
X  for (ptr = ign_head; ptr != NULL; ptr = ptr->next) {
X	if (!strcmp(&path[mountlength], ptr->structname)) return(TRUE);
X  }
X  return(FALSE);
X}
X
Xvoid usage()
X{
X  fprintf(stderr,
X   "Usage: %s [-p file] [-s] [-u file] [-v] [spec file]\n", progname);
X  exit(EXIT_FAILURE);
X}
X
X/* Later be sure have counted the directory file sizes too ! */
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  FILE *mtb;
X  FILE *dskusg;
X  USEREC *m_rec;
X  IGNREC *i_temp;
X  char line[PLENGTH];
X  char mountedon[PLENGTH];
X  char mf1[PLENGTH], mf2[PLENGTH], mf3[PLENGTH], mf4[PLENGTH], mf5[PLENGTH];
X  char *p1, *p2, *p3;
X  int r;
X  size_t siz;
X  uid_t m_uid;
X  long m_blocks;
X  unsigned scan_uid;
X  progname = argv[0];
X  argc--;
X  argv++;
X  while (argv[0][0] == '-') {
X	switch (argv[0][1]) {
X	    case 'p':
X		if (argc > 1) passwd = argv[1];
X		argc--;
X		argv++;
X		break;
X	    case 'v':	verbose++;	break;
X	    case 'u':
X		if (argc > 1) {
X			ufile = argv[1];
X			uflag++;
X			argc--;
X			argv++;
X			break;
X		} else
X			usage();
X	    case 'i':
X		if (argc > 1) {
X			ilist = argv[1];
X			iflag++;
X			argc--;
X			argv++;
X			break;
X		} else
X			usage();
X	    case 's':	sflag++;	break;
X	    default:	usage();
X	}
X	/* Else spec file ? */
X
X	argc--;
X	argv++;
X  }				/* end while '-' */
X  if (!argc) {
X	fprintf(stderr, "Usage: %s special\n", progname);
X	exit(EXIT_FAILURE);
X  }
X  if (!sflag) make_userlist();
X  if (iflag) {			/* parse the ignore string and make list */
X	p1 = p2 = ilist;
X	if (!*p1) {
X		fprintf(stderr, "%s: Bad -i list\n", progname);
X		exit(EXIT_FAILURE);
X	}
X	while (*p1) {
X		while (*p1 && !isspace(*p1) && *p1 != ',') p1++;
X		if (*p1) {
X			*p1 = '\0';
X			p1++;
X			while (isspace(*p1)) p1++;
X		}
X		i_temp = (IGNREC *) malloc(sizeof(IGNREC));
X		malloc_chk(i_temp);
X		siz = strlen(p2) + 1;
X		p3 = (char *) malloc(siz);
X		malloc_chk(p3);
X		i_temp->structname = p3;
X		strcpy(i_temp->structname, p2);
X		p2 = p1;
X		i_temp->next = ign_head;	/* just stack'em */
X		ign_head = i_temp;
X	}			/* end while */
X  }				/* if iflag */
X  if (uflag && !sflag) ufd = fopen(ufile, "w");
X
X/* While there are more "files" to this command */
X  while (argc > 0) {		/* more to do */
X	spec_name = argv[0];
X	argc--;
X	argv++;
X
X	/* Option -s sum values from previous diskusg output */
X	if (sflag) {
X		/* Read output of previous diskusg output and total it */
X		if ((dskusg = fopen(spec_name, "r")) == NULL) {
X			fprintf(stderr, "%s: -s open failed on %s\n", progname, spec_name);
X			exit(EXIT_FAILURE);
X		}
X		while (fgets(line, PLENGTH, dskusg)) {
X			sscanf(line, "%u%s%ld", &scan_uid, mf1, &m_blocks);
X			m_uid = scan_uid;
X			if (!exists(list_head, m_uid)) {
X				m_rec = (USEREC *) malloc(sizeof(USEREC));
X				malloc_chk(m_rec);
X				m_rec->name = (char *) malloc(strlen(mf1) + 1);
X				malloc_chk(m_rec->name);
X				strcpy(m_rec->name, mf1);
X				m_rec->uid = m_uid;
X				m_rec->blocks = 0L;
X				insert(&list_head, m_rec);
X			}	/* if !exist */
X			update_list((Uid_t) m_uid,
X				    (off_t) BLOCK_SIZE * m_blocks);
X		}		/* while fgets */
X		fclose(dskusg);
X		continue;	/* go on to next "while" file */
X	}			/* if sflag */
X	/* Search all the files on the special device (not option -s) */
X	stat(spec_name, this_stat);	/* will ignore "mounted on
X					 * spec.dev" */
X	real_dev = this_stat->st_rdev;	/* using only files really on
X					 * device */
X	/* See if is block special */
X	if (!S_ISBLK(this_stat->st_mode)) usage();
X
X	/* See if device is mounted already by searching mtab (old or new) */
X	if ((mtb = fopen("/etc/mtab", "r")) == NULL) {
X		fprintf(stderr, "%s: No /etc/mtab found.\n", progname);
X		exit(EXIT_FAILURE);
X	}
X	mountedon[0] = '\0';
X	while (!feof(mtb)) {	/* see if mounted already */
X		if (fgets(line, PLENGTH, mtb)) {
X			mf1[0] = mf2[0] = mf3[0] = mf4[0] = mf5[0] = '\0';
X			r = sscanf(line, "%s%s%s%s%s", mf1, mf2, mf3, mf4, mf5);
X			if (!strcmp(spec_name, mf1)) {
X				if (r > 4)
X					strcpy(mountedon, mf5);	/* hmmm.. old mtab */
X				else {
X					if (!strcmp(mf3, "root"))
X						strcpy(mountedon, "/");	/* old mtab */
X					else
X						strcpy(mountedon, mf2);	/* new mtab */
X				}
X				break;
X			}
X		}
X	}
X	fclose(mtb);
X	if (!mountedon[0]) {	/* not mounted so mount temporarily */
X		strcpy(mountedon, "tmpXXXXXX");
X		mktemp(mountedon);
X		if (mkdir(mountedon, 0700)) {
X			fprintf(stderr, "%s: Can not make a temporary directory in pwd\n", progname);
X			exit(EXIT_FAILURE);
X		}
X		if (mount(spec_name, mountedon, 1)) {	/* read only */
X			rmdir(mountedon);	/* clean up before leaving */
X			if (geteuid() != 0) {
X				fprintf(stderr, "%s: Must run as root in order to mount %s\n", progname, spec_name);
X				exit(EXIT_FAILURE);
X			}
X			fprintf(stderr, "%s: Could not mount %s\n", progname, spec_name);
X			exit(EXIT_FAILURE);
X		}
X		didmount = TRUE;
X	}
X	mountlength = strlen(mountedon);	/* Note: means -i names
X						 * begin with / */
X	search_all(mountedon);	/* call the "traverse and accumulate"
X				 * routine */
X	if (didmount) {
X		umount(spec_name);
X		rmdir(mountedon);
X		didmount = FALSE;
X	}
X	spec_name[0] = '\0';
X	mountedon[0] = '\0';
X  }				/* while argc > 0 .. spec_name */
X  if (uflag && !sflag) fclose(ufd);
X  showlist();			/* list results to stdout */
X  return(EXIT_SUCCESS);
X}
X
Xvoid malloc_chk(ptr)
Xvoid *ptr;
X{
X  if (ptr == NULL) {
X	fprintf(stderr, 
X		  "Malloc returned NULL.  Use chmem to allocate more stack\n");
X	exit(EXIT_FAILURE);
X  }
X}
/
echo x - dw.c
sed '/^X/s///' > dw.c << '/'
X/* dw - find duplicate words in a file		Author: Nelson Beebe */
X
X/* Usage: dw [file] */
X
X#include <stdlib.h>
X#include <string.h>
X#include <ctype.h>
X#include <stdio.h>
X
X_PROTOTYPE(int main, (int argc, char *argv []));
X_PROTOTYPE(int get_token, (FILE *f ));
X_PROTOTYPE(void make_lower, (void));
X_PROTOTYPE(void other, (void));
X_PROTOTYPE(void word, (void));
X
Xchar last_word[1024];
Xchar yytext[1024];
Xint yyleng;
Xlong last_line_number = 0L;
Xlong line_number = 1L;
X
X#define	T_EOF	EOF
X#define	T_WORD	0
X#define T_WHITE	1
X#define T_OTHER	2
X
X#define	isinitial(c)	(isalpha(c) || ((c) == '_'))
X#define ismiddle(c)	(isinitial(c) || isdigit(c))
X
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  register int token;
X  FILE *f;
X
X  if (argc > 2) {
X	fprintf(stderr, "Usage: dw [file]\n");
X	exit(1);
X  }
X
X  if (argc == 2) {
X	f = fopen(argv[1], "r");
X	if (f == NULL) {
X		fprintf(stderr, "dw: cannot open file %s\n", argv[1]);
X		exit(1);
X	}
X  } else {
X	f = stdin;
X  }
X  last_word[0] = '\0';
X
X  while ((token = get_token(f)) != T_EOF) {
X	switch (token) {
X	    case T_WORD:	word();		break;
X	    case T_WHITE:			break;
X	    case T_OTHER:	other();	break;
X	    default:				break;
X	}
X  }
X  exit(EXIT_SUCCESS);
X  return(0);			/* keep optimizers happy */
X}
X
Xint get_token(f)
XFILE *f;
X{
X  register int c;
X  register char *p;
X  register int token;
X
X  p = yytext;
X  c = fgetc(f);
X  if (c == EOF)
X	token = T_EOF;
X  else if (isinitial(c)) {
X	token = T_WORD;
X	while (ismiddle(c)) {
X		*p++ = c;
X		c = fgetc(f);
X	}
X	ungetc(c, f);		/* push back lookahead */
X  } else if (isspace(c)) {	/* whitespace forms single token */
X	token = T_WHITE;
X	while (isspace(c)) {
X		if (c == '\n') line_number++;
X		*p++ = c;
X		c = fgetc(f);
X	}
X	ungetc(c, f);		/* push back lookahead */
X  } else {			/* all other tokens are single char */
X	token = T_OTHER;
X  }
X  *p = '\0';			/* terminate token in yytext[] */
X  yyleng = (int) (p - yytext);
X  return(token);
X}
X
Xvoid make_lower()
X{
X  int n;
X  for (n = 0; n < yyleng; ++n)
X	if (isupper(yytext[n])) yytext[n] = tolower(yytext[n]);
X}
X
Xvoid other()
X{
X  strcpy(last_word, yytext);	/* so intervening 'words' do not */
X  /* Trigger output of duplicates */
X}
X
Xvoid word()
X{
X  make_lower();
X  if (strcmp(yytext, last_word) == 0) {
X	if (last_line_number == line_number)
X		printf("%ld: %s\n", line_number, yytext);
X	else
X		printf("%ld-%ld: %s\n", last_line_number, line_number, yytext);
X  }
X  strcpy(last_word, yytext);
X  last_line_number = line_number;
X}
/
echo x - fsck2.c
sed '/^X/s///' > fsck2.c << '/'
X/* Hacks for version 1.6 */					
X
X#define INODES_PER_BLOCK V2_INODES_PER_BLOCK
X#define INODE_SIZE ((int) V2_INODE_SIZE)
X#define INTS_PER_BLOCK (BLOCK_SIZE / (int) sizeof(int))
X#define MAX_ZONES (V2_NR_DZONES+V2_INDIRECTS+(long)V2_INDIRECTS*V2_INDIRECTS)
X#define NR_DZONE_NUM V2_NR_DZONES
X#define NR_INDIRECTS V2_INDIRECTS
X#define NR_ZONE_NUMS V2_NR_TZONES
X#define ZONE_NUM_SIZE V2_ZONE_NUM_SIZE
X#define bit_nr bit_t
X#define block_nr block_t
X#define d_inode d2_inode
X#define d_inum d_ino
X#define dir_struct struct direct
X#define i_mode d2_mode
X#define i_nlinks d2_nlinks
X#define i_size d2_size
X#define i_zone d2_zone
X#define zone_nr zone_t
X
X/* fsck - file system checker		Author: Robbert van Renesse */
X
X/* Modified by Norbert Schlenker
X*   Removed vestiges of standalone/DOS versions:
X*     - various unused variables and buffers removed
X*     - now uses library functions rather than private internal routines
X*     - bytewise structure copies replaced by structure assignment
X*     - fixed one bug with 14 character file names
X*     - other small tweaks for speed
X*
X* Modified by Lars Fredriksen at the request of Andy Tanenbaum, 90-03-10.
X*   Removed -m option, by which fsck could be told to make a file
X*   system on a 360K floppy.  The code had limited utility, was buggy,
X*   and failed due to a bug in the ACK C compiler.  Use mkfs instead!
X*/
X
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <ctype.h>
X#include <errno.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X#include <minix/config.h>
X#include <minix/const.h>
X#include <minix/type.h>
X#include "../fs/const.h"
X#include "../fs/inode.h"
X#include "../fs/type.h"
X#include <minix/fslib.h>
X
X#undef printf			/* defined as printk in "../fs/const.h" */
X
X#include <stdio.h>
X
X#if INTEL_32BITS || (CHIP == SPARC)
X#define BITSHIFT	  5	/* = log2(#bits(int)) */
X#else
X#define BITSHIFT	  4	/* = log2(#bits(int)) */
X#endif
X
X#define MAXPRINT	  8	/* max. number of error lines in chkmap */
X#define MAXDIRSIZE     5000	/* max. size of a reasonable directory */
X#define CINDIR		128	/* number of indirect zno's read at a time */
X#define CDIRECT		 16	/* number of dir entries read at a time */
X
X/* Macros for handling bitmaps.  Now bit_t is long, these are bulky and the
X * type demotions produce a lot of lint.  The explicit demotion in POWEROFBIT
X * is for efficiency and assumes 2's complement ints.  Lint should be clever
X * enough not to warn about it since BITMASK is small, but isn't.  (It would
X * be easier to get right if bit_t was was unsigned (long) since then there
X * would be no danger from wierd sign representations.  Lint doesn't know
X * we only use non-negative bit numbers.) There will usually be an implicit
X * demotion when WORDOFBIT is used as an array index.  This should be safe
X * since memory for bitmaps will run out first.
X */
X#define BITMASK		((1 << BITSHIFT) - 1)
X#define WORDOFBIT(b)	((b) >> BITSHIFT)
X#define POWEROFBIT(b)	(1 << ((int) (b) & BITMASK))
X#define setbit(w, b)	(w[WORDOFBIT(b)] |= POWEROFBIT(b))
X#define clrbit(w, b)	(w[WORDOFBIT(b)] &= ~POWEROFBIT(b))
X#define bitset(w, b)	(w[WORDOFBIT(b)] & POWEROFBIT(b))
X
X#define ZONE_CT 	360	/* default zones  (when making file system) */
X#define INODE_CT	 95	/* default inodes (when making file system) */
X
X#include "../fs/super.h"
Xstruct super_block sb;
X
X#define STICKY_BIT	01000	/* not defined anywhere else */
X
X/* Ztob gives the block address of a zone
X * btoa gives the byte address of a block
X */
X#define ztob(z)		((block_nr) (z) << sb.s_log_zone_size)
X#define btoa(b)		((long) (b) * BLOCK_SIZE)
X#define SCALE		((int) ztob(1))	/* # blocks in a zone */
X#define FIRST		((zone_nr) sb.s_firstdatazone)	/* as the name says */
X
X/* # blocks of each type */
X#define N_SUPER		1
X#define N_IMAP		(sb.s_imap_blocks)
X#define N_ZMAP		(sb.s_zmap_blocks)
X#define N_ILIST		((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
X#define N_DATA		(sb.s_zones - FIRST)
X
X/* Block address of each type */
X#define BLK_SUPER	(SUPER_BLOCK)
X#define BLK_IMAP	(BLK_SUPER + N_SUPER)
X#define BLK_ZMAP	(BLK_IMAP  + N_IMAP)
X#define BLK_ILIST	(BLK_ZMAP  + N_ZMAP)
X#define BLK_FIRST	ztob(FIRST)
X#define ZONE_SIZE	((int) ztob(BLOCK_SIZE))
X#define NLEVEL		(NR_ZONE_NUMS - NR_DZONE_NUM + 1)
X
X/* Byte address of a zone/of an inode */
X#define zaddr(z)	btoa(ztob(z))
X#define inoaddr(i)	((long) (i - 1) * INODE_SIZE + (long) btoa(BLK_ILIST))
X#define INDCHUNK	((int) (CINDIR * ZONE_NUM_SIZE))
X#define DIRCHUNK	((int) (CDIRECT * DIR_ENTRY_SIZE))
X
Xchar *prog, *device;		/* program name (fsck), device name */
Xint firstcnterr;		/* is this the first inode ref cnt error? */
Xunsigned *imap, *spec_imap;	/* inode bit maps */
Xunsigned *zmap, *spec_zmap;	/* zone bit maps */
Xunsigned *dirmap;		/* directory (inode) bit map */
Xchar rwbuf[BLOCK_SIZE];		/* one block buffer cache */
Xblock_nr thisblk;		/* block in buffer cache */
Xchar nullbuf[BLOCK_SIZE];	/* null buffer */
Xnlink_t *count;			/* inode count */
Xint changed;			/* has the diskette been written to? */
Xstruct stack {
X  dir_struct *st_dir;
X  struct stack *st_next;
X  char st_presence;
X} *ftop;
X
Xint dev;			/* file descriptor of the device */
X
X#define DOT	1
X#define DOTDOT	2
X
X/* Counters for each type of inode/zone. */
Xint nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
Xint npipe, nsyml, ztype[NLEVEL];
Xlong nfreezone;
X
Xint repair, automatic, listing, listsuper;	/* flags */
Xint firstlist;			/* has the listing header been printed? */
Xunsigned part_offset;		/* sector offset for this partition */
Xchar answer[] = "Answer questions with y or n.  Then hit RETURN";
X
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(void initvars, (void));
X_PROTOTYPE(void fatal, (char *s));
X_PROTOTYPE(int eoln, (int c));
X_PROTOTYPE(int yes, (char *question));
X_PROTOTYPE(int atoo, (char *s));
X_PROTOTYPE(int input, (char *buf, int size));
X_PROTOTYPE(char *alloc, (unsigned nelem, unsigned elsize));
X_PROTOTYPE(void printname, (char *s));
X_PROTOTYPE(void printrec, (struct stack *sp));
X_PROTOTYPE(void printpath, (int mode, int nlcr));
X_PROTOTYPE(void devopen, (void));
X_PROTOTYPE(void devclose, (void));
X_PROTOTYPE(void devio, (block_nr bno, int dir));
X_PROTOTYPE(void devread, (long offset, char *buf, int size));
X_PROTOTYPE(void devwrite, (long offset, char *buf, int size));
X_PROTOTYPE(void pr, (char *fmt, int cnt, char *s, char *p));
X_PROTOTYPE(void lpr, (char *fmt, long cnt, char *s, char *p));
X_PROTOTYPE(bit_nr getnumber, (char *s));
X_PROTOTYPE(char **getlist, (char ***argv, char *type));
X_PROTOTYPE(void lsuper, (void));
X_PROTOTYPE(void getsuper, (void));
X_PROTOTYPE(void chksuper, (void));
X_PROTOTYPE(void lsi, (char **clist));
X_PROTOTYPE(unsigned *allocbitmap, (int nblk));
X_PROTOTYPE(void loadbitmap, (unsigned *bitmap, block_nr bno, int nblk));
X_PROTOTYPE(void dumpbitmap, (unsigned *bitmap, block_nr bno, int nblk));
X_PROTOTYPE(void initbitmap, (unsigned *bitmap, bit_nr bit, int nblk));
X_PROTOTYPE(void fillbitmap, (unsigned *bitmap, bit_nr lwb, bit_nr upb, char **list));
X_PROTOTYPE(void freebitmap, (unsigned *p));
X_PROTOTYPE(void getbitmaps, (void));
X_PROTOTYPE(void putbitmaps, (void));
X_PROTOTYPE(void chkword, (unsigned w1, unsigned w2, bit_nr bit, bit_nr nbit, char *type, int *n, int *report));
X_PROTOTYPE(void chkmap, (unsigned *cmap, unsigned *dmap, bit_nr bit, block_nr blkno, int nblk, bit_nr nbit, char *type));
X_PROTOTYPE(void chkilist, (void));
X_PROTOTYPE(void getcount, (void));
X_PROTOTYPE(void counterror, (Ino_t ino));
X_PROTOTYPE(void chkcount, (void));
X_PROTOTYPE(void freecount, (void));
X_PROTOTYPE(void printperm, (Mode_t mode, int shift, int special, int overlay));
X_PROTOTYPE(void list, (Ino_t ino, d_inode *ip));
X_PROTOTYPE(int Remove, (dir_struct *dp));
X_PROTOTYPE(void make_printable_name, (char *dst, char *src, int n));
X_PROTOTYPE(int chkdots, (Ino_t ino, off_t pos, dir_struct *dp, Ino_t exp));
X_PROTOTYPE(int chkname, (Ino_t ino, dir_struct *dp));
X_PROTOTYPE(int chkentry, (Ino_t ino, off_t pos, dir_struct *dp));
X_PROTOTYPE(int chkdirzone, (Ino_t ino, d_inode *ip, off_t pos, zone_nr zno));
X_PROTOTYPE(void errzone, (char *mess, zone_nr zno, int level, off_t pos));
X_PROTOTYPE(int markzone, (zone_nr zno, int level, off_t pos));
X_PROTOTYPE(int chkindzone, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level));
X_PROTOTYPE(off_t jump, (int level));
X_PROTOTYPE(int zonechk, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level));
X_PROTOTYPE(int chkzones, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist, int len, int level));
X_PROTOTYPE(int chkfile, (Ino_t ino, d_inode *ip));
X_PROTOTYPE(int chkdirectory, (Ino_t ino, d_inode *ip));
X_PROTOTYPE(int chklink, (Ino_t ino, d_inode *ip));
X_PROTOTYPE(int chkspecial, (Ino_t ino, d_inode *ip));
X_PROTOTYPE(int chkmode, (Ino_t ino, d_inode *ip));
X_PROTOTYPE(int chkinode, (Ino_t ino, d_inode *ip));
X_PROTOTYPE(int descendtree, (dir_struct *dp));
X_PROTOTYPE(void chktree, (void));
X_PROTOTYPE(void printtotal, (void));
X_PROTOTYPE(void chkdev, (char *f, char **clist, char **ilist, char **zlist));
X
X/* Initialize the variables used by this program. */
Xvoid initvars()
X{
X  register level;
X
X  nregular = ndirectory = nblkspec = ncharspec = nbadinode = npipe = nsyml = 0;
X  for (level = 0; level < NLEVEL; level++) ztype[level] = 0;
X  changed = 0;
X  thisblk = NO_BLOCK;
X  firstlist = 1;
X  firstcnterr = 1;
X}
X
X/* Print the string `s' and exit. */
Xvoid fatal(s)
Xchar *s;
X{
X  printf("%s\nfatal\n", s);
X  exit(-1);
X}
X
X/* Test for end of line. */
Xint eoln(c)
Xint c;
X{
X  return(c == EOF || c == '\n' || c == '\r');
X}
X
X/* Ask a question and get the answer unless automatic is set. */
Xint yes(question)
Xchar *question;
X{
X  register int c, answerchar;
X
X  if (!repair) {
X	printf("\n");
X	return(0);
X  }
X  printf("%s? ", question);
X  if (automatic) {
X	printf("yes\n");
X	return(1);
X  }
X  fflush(stdout);
X  if ((c = answerchar = getchar()) == 'q' || c == 'Q') exit(1);
X  while (!eoln(c)) c = getchar();
X  return !(answerchar == 'n' || answerchar == 'N');
X}
X
X/* Convert string to integer.  Representation is octal. */
Xint atoo(s)
Xregister char *s;
X{
X  register int n = 0;
X
X  while ('0' <= *s && *s < '8') {
X	n <<= 3;
X	n += *s++ - '0';
X  }
X  return n;
X}
X
X/* If repairing the file system, print a prompt and get a string from user. */
Xint input(buf, size)
Xchar *buf;
Xint size;
X{
X  register char *p = buf;
X
X  printf("\n");
X  if (repair) {
X	printf("--> ");
X	fflush(stdout);
X	while (--size) {
X		*p = getchar();
X		if (eoln(*p)) {
X			*p = 0;
X			return(p > buf);
X		}
X		p++;
X	}
X	*p = 0;
X	while (!eoln(getchar()));
X	return(1);
X  }
X  return(0);
X}
X
X/* Allocate some memory and zero it. */
Xchar *alloc(nelem, elsize)
Xunsigned nelem, elsize;
X{
X  char *p;
X
X  if ((p = (char *)malloc((size_t)nelem * elsize)) == 0)fatal("out of memory");
X  memset((void *) p, 0, (size_t)nelem * elsize);
X  return(p);
X}
X
X/* Print the name in a directory entry. */
Xvoid printname(s)
Xchar *s;
X{
X  register n = NAME_MAX;
X  int c;
X
X  do {
X	if ((c = *s) == 0) break;
X	if (!isprint(c)) c = '?';
X	putchar(c);
X	s++;
X  } while (--n);
X}
X
X/* Print the pathname given by a linked list pointed to by `sp'.  The
X * names are in reverse order.
X */
Xvoid printrec(sp)
Xstruct stack *sp;
X{
X  if (sp->st_next != 0) {
X	printrec(sp->st_next);
X	putchar('/');
X	printname(sp->st_dir->d_name);
X  }
X}
X
X/* Print the current pathname.  */
Xvoid printpath(mode, nlcr)
Xint mode;
Xint nlcr;
X{
X  if (ftop->st_next == 0)
X	putchar('/');
X  else
X	printrec(ftop);
X  switch (mode) {
X      case 1:
X	printf(" (ino = %u, ", ftop->st_dir->d_inum);
X	break;
X      case 2:
X	printf(" (ino = %u)", ftop->st_dir->d_inum);
X	break;
X  }
X  if (nlcr) printf("\n");
X}
X
X/* Open the device.  */
Xvoid devopen()
X{
X  if ((dev = open(device, repair ? O_RDWR : O_RDONLY)) < 0) {
X	perror(device);
X	fatal("");
X  }
X}
X
X/* Close the device. */
Xvoid devclose()
X{
X  if (close(dev) != 0) {
X	perror("close");
X	fatal("");
X  }
X}
X
X/* Read or write a block. */
Xvoid devio(bno, dir)
Xblock_nr bno;
Xint dir;
X{
X  if (dir == READING && bno == thisblk) return;
X  thisblk = bno;
X
X#if 0
Xprintf("%s at block %5d\n", dir == READING ? "reading " : "writing", bno);
X#endif
X  lseek(dev, (off_t) btoa(bno), SEEK_SET);
X  if (dir == READING) {
X	if (read(dev, rwbuf, BLOCK_SIZE) == BLOCK_SIZE)
X		return;
X  } else {
X	if (write(dev, rwbuf, BLOCK_SIZE) == BLOCK_SIZE)
X		return;
X  }
X
X  printf("%s: can't %s block %ld (error = 0x%x)\n", prog,
X         dir == READING ? "read" : "write", (long) bno, errno);
X  if (dir == READING) {
X	printf("Continuing with a zero-filled block.\n");
X	memset(rwbuf, 0, BLOCK_SIZE);
X	return;
X  }
X  fatal("");
X}
X
X/* Read `size' bytes from the disk starting at byte `offset'. */
Xvoid devread(offset, buf, size)
Xlong offset;
Xchar *buf;
Xint size;
X{
X  devio((block_nr) (offset / BLOCK_SIZE), READING);
X  memmove(buf, &rwbuf[(int) (offset % BLOCK_SIZE)], (size_t)size);  /* lint but OK */
X}
X
X/* Write `size' bytes to the disk starting at byte `offset'. */
Xvoid devwrite(offset, buf, size)
Xlong offset;
Xchar *buf;
Xint size;
X{
X  if (!repair) fatal("internal error (devwrite)");
X  if (size != BLOCK_SIZE) devio((block_nr) (offset / BLOCK_SIZE), READING);
X  memmove(&rwbuf[(int) (offset % BLOCK_SIZE)], buf, (size_t)size);  /* lint but OK */
X  devio((block_nr) (offset / BLOCK_SIZE), WRITING);
X  changed = 1;
X}
X
X/* Print a string with either a singular or a plural pronoun. */
Xvoid pr(fmt, cnt, s, p)
Xchar *fmt, *s, *p;
Xint cnt;
X{
X  printf(fmt, cnt, cnt == 1 ? s : p);
X}
X
X/* Same as above, but with a long argument */
Xvoid lpr(fmt, cnt, s, p)
Xchar *fmt, *s, *p;
Xlong cnt;
X{
X  printf(fmt, cnt, cnt == 1 ? s : p);
X}
X
X/* Convert string to number. */
Xbit_nr getnumber(s)
Xregister char *s;
X{
X  register bit_nr n = 0;
X
X  if (s == NULL)
X	return NO_BIT;
X  while (isdigit(*s))
X	n = (n << 1) + (n << 3) + *s++ - '0';
X  return (*s == '\0') ? n : NO_BIT;
X}
X
X/* See if the list pointed to by `argv' contains numbers. */
Xchar **getlist(argv, type)
Xchar ***argv, *type;
X{
X  register char **list = *argv;
X  register empty = 1;
X
X  while (getnumber(**argv) != NO_BIT) {
X	(*argv)++;
X	empty = 0;
X  }
X  if (empty) {
X	printf("warning: no %s numbers given\n", type);
X	return(NULL);
X  }
X  return(list);
X}
X
X/* Make a listing of the super block.  If `repair' is set, ask the user
X * for changes.
X */
Xvoid lsuper()
X{
X  char buf[80];
X
X  do {
X	/* Most of the following atol's enrage lint, for good reason. */  
X	printf("ninodes       = %u", sb.s_ninodes);
X	if (input(buf, 80)) sb.s_ninodes = atol(buf);
X	printf("nzones        = %ld", sb.s_zones);
X	if (input(buf, 80)) sb.s_zones = atol(buf);
X	printf("imap_blocks   = %u", sb.s_imap_blocks);
X	if (input(buf, 80)) sb.s_imap_blocks = atol(buf);
X	printf("zmap_blocks   = %u", sb.s_zmap_blocks);
X	if (input(buf, 80)) sb.s_zmap_blocks = atol(buf);
X	printf("firstdatazone = %u", sb.s_firstdatazone);
X	if (input(buf, 80)) sb.s_firstdatazone = atol(buf);
X	printf("log_zone_size = %u", sb.s_log_zone_size);
X	if (input(buf, 80)) sb.s_log_zone_size = atol(buf);
X	printf("maxsize       = %ld", sb.s_max_size);
X	if (input(buf, 80)) sb.s_max_size = atol(buf);
X	if (yes("ok now")) {
X		devwrite(btoa(BLK_SUPER), (char *) &sb, sizeof(sb));
X		return;
X	}
X  } while (yes("Do you want to try again"));
X  if (repair) exit(0);
X}
X
X/* Get the super block from either disk or user.  Do some initial checks. */
Xvoid getsuper()
X{
X  devread(btoa(BLK_SUPER), (char *) &sb, sizeof(sb));
X  if (listsuper) lsuper();
X  if (sb.s_magic == SUPER_MAGIC) fatal("Cannot handle V1 file systems");
X  if (sb.s_magic != SUPER_V2) fatal("bad magic number in super block");
X  if (sb.s_ninodes <= 0) fatal("no inodes");
X  if (sb.s_zones <= 0) fatal("no zones");
X  if (sb.s_imap_blocks <= 0) fatal("no imap");
X  if (sb.s_zmap_blocks <= 0) fatal("no zmap");
X  if (sb.s_firstdatazone <= 4) fatal("first data zone too small");
X  if (sb.s_log_zone_size < 0) fatal("zone size < block size");
X  if (sb.s_max_size <= 0) fatal("max. file size <= 0");
X}
X
X/* Check the super block for reasonable contents. */
Xvoid chksuper()
X{
X  register n;
X  register off_t maxsize;
X
X  n = bitmapsize((bit_t) sb.s_ninodes + 1);
X  if (sb.s_magic != SUPER_V2) fatal("bad magic number in super block");
X  if (sb.s_imap_blocks < n) fatal("too few imap blocks");
X  if (sb.s_imap_blocks != n) {
X	pr("warning: expected %d imap_block%s", n, "", "s");
X	printf(" instead of %d\n", sb.s_imap_blocks);
X  }
X  n = bitmapsize((bit_t) sb.s_zones);
X  if (sb.s_zmap_blocks < n) fatal("too few zmap blocks");
X  if (sb.s_zmap_blocks != n) {
X	pr("warning: expected %d zmap_block%s", n, "", "s");
X	printf(" instead of %d\n", sb.s_zmap_blocks);
X  }
X  if (sb.s_firstdatazone >= sb.s_zones)
X	fatal("first data zone too large");
X  if (sb.s_log_zone_size >= 8 * sizeof(block_nr))
X	fatal("log_zone_size too large");
X  if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n",
X	       sb.s_log_zone_size);
X  n = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size;
X  if (sb.s_firstdatazone < n) fatal("first data zone too small");
X  if (sb.s_firstdatazone != n) {
X	printf("warning: expected first data zone to be %d ", n);
X	printf("instead of %u\n", sb.s_firstdatazone);
X  }
X  maxsize = MAX_FILE_POS;
X  if (((maxsize - 1) >> sb.s_log_zone_size) / BLOCK_SIZE >= MAX_ZONES)
X	maxsize = ((long) MAX_ZONES * BLOCK_SIZE) << sb.s_log_zone_size;
X  if (sb.s_max_size != maxsize) {
X	printf("warning: expected max size to be %ld ", maxsize);
X	printf("instead of %ld\n", sb.s_max_size);
X  }
X}
X
X/* Make a listing of the inodes given by `clist'.  If `repair' is set, ask
X * the user for changes.
X */
Xvoid lsi(clist)
Xchar **clist;
X{
X  register bit_nr bit;
X  register ino_t ino;
X  d_inode inode, *ip = &inode;
X  char buf[80];
X
X  if (clist == 0) return;
X  while ((bit = getnumber(*clist++)) != NO_BIT) {
X	setbit(spec_imap, bit);
X	ino = bit;
X	do {
X		devread(inoaddr(ino), (char *) ip, INODE_SIZE);
X		printf("inode %u:\n", ino);
X		printf("    mode   = %6o", ip->i_mode);
X		if (input(buf, 80)) ip->i_mode = atoo(buf);
X		printf("    nlinks = %6u", ip->i_nlinks);
X		if (input(buf, 80)) ip->i_nlinks = atol(buf);
X		printf("    size   = %6ld", ip->i_size);
X		if (input(buf, 80)) ip->i_size = atol(buf);
X		if (yes("Write this back")) {
X			devwrite(inoaddr(ino), (char *) ip, INODE_SIZE);
X			break;
X		}
X	} while (yes("Do you want to change it again"));
X  }
X}
X
X/* Allocate `nblk' blocks worth of bitmap. */
Xunsigned *allocbitmap(nblk)
Xint nblk;
X{
X  register unsigned *bitmap;
X
X  bitmap = (unsigned *) alloc((unsigned) nblk, BLOCK_SIZE);
X  *bitmap |= 1;
X  return(bitmap);
X}
X
X/* Load the bitmap starting at block `bno' from disk. */
Xvoid loadbitmap(bitmap, bno, nblk)
Xunsigned *bitmap;
Xblock_nr bno;
Xint nblk;
X{
X  register i;
X  register unsigned *p;
X
X  p = bitmap;
X  for (i = 0; i < nblk; i++, bno++, p += INTS_PER_BLOCK)
X	devread(btoa(bno), (char *) p, BLOCK_SIZE);
X  *bitmap |= 1;
X}
X
X/* Write the bitmap starting at block `bno' to disk. */
Xvoid dumpbitmap(bitmap, bno, nblk)
Xunsigned *bitmap;
Xblock_nr bno;
Xint nblk;
X{
X  register i;
X  register unsigned *p = bitmap;
X
X  for (i = 0; i < nblk; i++, bno++, p += INTS_PER_BLOCK)
X	devwrite(btoa(bno), (char *) p, BLOCK_SIZE);
X}
X
X/* Initialize the given bitmap by setting all the bits starting at `bit'. */
Xvoid initbitmap(bitmap, bit, nblk)
Xunsigned *bitmap;
Xbit_nr bit;
Xint nblk;
X{
X  register unsigned *first, *last;
X
X  while (bit & BITMASK) {
X	setbit(bitmap, bit);
X	bit++;
X  }
X  first = &bitmap[bit >> BITSHIFT];
X  last = &bitmap[nblk * INTS_PER_BLOCK];
X  while (first < last) *first++ = ~(unsigned) 0;
X}
X
X/* Set the bits given by `list' in the bitmap. */
Xvoid fillbitmap(bitmap, lwb, upb, list)
Xunsigned *bitmap;
Xbit_nr lwb, upb;
Xchar **list;
X{
X  register bit_nr bit;
X
X  if (list == 0) return;
X  while ((bit = getnumber(*list++)) != NO_BIT)
X	if (bit < lwb || bit >= upb) {
X		if (bitmap == spec_imap)
X			printf("inode number %ld ", bit);
X		else
X			printf("zone number %ld ", bit);
X		printf("out of range (ignored)\n");
X	} else
X		setbit(bitmap, bit - lwb + 1);
X}
X
X/* Deallocate the bitmap `p'. */
Xvoid freebitmap(p)
Xunsigned *p;
X{
X  free((char *) p);
X}
X
X/* Get all the bitmaps used by this program. */
Xvoid getbitmaps()
X{
X  imap = allocbitmap(N_IMAP);
X  zmap = allocbitmap(N_ZMAP);
X  spec_imap = allocbitmap(N_IMAP);
X  spec_zmap = allocbitmap(N_ZMAP);
X  dirmap = allocbitmap(N_IMAP);
X}
X
X/* Release all the space taken by the bitmaps. */
Xvoid putbitmaps()
X{
X  freebitmap(imap);
X  freebitmap(zmap);
X  freebitmap(spec_imap);
X  freebitmap(spec_zmap);
X  freebitmap(dirmap);
X}
X
X/* `w1' and `w2' are differing words from two bitmaps that should be
X * identical.  Print what's the matter with them.
X */
Xvoid chkword(w1, w2, bit, nbit, type, n, report)
Xunsigned w1, w2;
Xchar *type;
Xbit_nr bit, nbit;
Xint *n, *report;
X{
X  for (; (w1 | w2) && bit < nbit; w1 >>= 1, w2 >>= 1, bit++)
X	if ((w1 ^ w2) & 1 && ++(*n) % MAXPRINT == 0 && *report &&
X	    (!repair || automatic || yes("stop this listing")))
X		*report = 0;
X	else if (*report)
X		if ((w1 & 1) && !(w2 & 1))
X			printf("%s %ld is missing\n", type, bit);
X		else if (!(w1 & 1) && (w2 & 1))
X			printf("%s %ld is not free\n", type, bit);
X}
X
X/* Check if the given (correct) bitmap is identical with the one that is
X * on the disk.  If not, ask if the disk should be repaired.
X */
Xvoid chkmap(cmap, dmap, bit, blkno, nblk, nbit, type)
Xunsigned *cmap, *dmap;
Xbit_nr bit, nbit;
Xblock_nr blkno;
Xint nblk;
Xchar *type;
X{
X  register unsigned *p = dmap, *q = cmap;
X  int report = 1, nerr = 0;
X
X  printf("Checking %s map\n", type);
X  loadbitmap(dmap, blkno, nblk);
X  do {
X	if (*p != *q) chkword(*p, *q, bit, nbit, type, &nerr, &report);
X	p++;
X	q++;
X  } while ((bit += 8 * sizeof(unsigned)) < nbit
X	 && bit >= 8 * sizeof(unsigned));	/* += may overflow */
X  if ((!repair || automatic) && !report) printf("etc. ");
X  if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr);
X  if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk);
X  if (nerr > 0) printf("\n");
X}
X
X/* See if the inodes that aren't allocated are cleared. */
Xvoid chkilist()
X{
X  register ino_t ino = 1;
X  mode_t mode;
X
X  printf("Checking inode list\n");
X  do
X	if (!bitset(imap, (bit_nr) ino)) {
X		devread(inoaddr(ino), (char *) &mode, sizeof(mode));
X		if (mode != I_NOT_ALLOC) {
X			printf("mode inode %u not cleared", ino);
X			if (yes(". clear")) devwrite(inoaddr(ino), nullbuf,
X					 INODE_SIZE);
X		}
X	}
X  while (++ino <= sb.s_ninodes);
X  printf("\n");
X}
X
X/* Allocate an array to maintain the inode reference counts in. */
Xvoid getcount()
X{
X  count = (nlink_t *) alloc((unsigned) (sb.s_ninodes + 1), sizeof(nlink_t));
X}
X
X/* The reference count for inode `ino' is wrong.  Ask if it should be adjusted. */
Xvoid counterror(ino)
Xino_t ino;
X{
X  d_inode inode;
X
X  if (firstcnterr) {
X	printf("INODE NLINK COUNT\n");
X	firstcnterr = 0;
X  }
X  devread(inoaddr(ino), (char *) &inode, INODE_SIZE);
X  count[ino] += inode.i_nlinks;	/* it was already subtracted; add it back */
X  printf("%5u %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]);
X  if (yes(" adjust")) {
X	if ((inode.i_nlinks = count[ino]) == 0) {
X		fatal("internal error (counterror)");
X		inode.i_mode = I_NOT_ALLOC;
X		clrbit(imap, (bit_nr) ino);
X	}
X	devwrite(inoaddr(ino), (char *) &inode, INODE_SIZE);
X  }
X}
X
X/* Check if the reference count of the inodes are correct.  The array `count'
X * is maintained as follows:  an entry indexed by the inode number is
X * incremented each time a link is found; when the inode is read the link
X * count in there is substracted from the corresponding entry in `count'.
X * Thus, when the whole file system has been traversed, all the entries
X * should be zero.
X */
Xvoid chkcount()
X{
X  register ino_t ino;
X
X  for (ino = 1; ino <= sb.s_ninodes; ino++)
X	if (count[ino] != 0) counterror(ino);
X  if (!firstcnterr) printf("\n");
X}
X
X/* Deallocate the `count' array. */
Xvoid freecount()
X{
X  free((char *) count);
X}
X
X/* Print the inode permission bits given by mode and shift. */
Xvoid printperm(mode, shift, special, overlay)
Xmode_t mode;
Xint shift;
Xint special;
Xint overlay;
X{
X  if (mode >> shift & R_BIT)
X	putchar('r');
X  else
X	putchar('-');
X  if (mode >> shift & W_BIT)
X	putchar('w');
X  else
X	putchar('-');
X  if (mode & special)
X	putchar(overlay);
X  else
X	if (mode >> shift & X_BIT)
X		putchar('x');
X	else
X		putchar('-');
X}
X
X/* List the given inode. */
Xvoid list(ino, ip)
Xino_t ino;
Xd_inode *ip;
X{
X  if (firstlist) {
X	firstlist = 0;
X	printf(" inode permission link   size name\n");
X  }
X  printf("%6u ", ino);
X  switch (ip->i_mode & I_TYPE) {
X      case I_REGULAR:		putchar('-');	break;
X      case I_DIRECTORY:		putchar('d');	break;
X      case I_CHAR_SPECIAL:	putchar('c');	break;
X      case I_BLOCK_SPECIAL:	putchar('b');	break;
X      case I_NAMED_PIPE:	putchar('p');	break;
X#ifdef I_SYMBOLIC_LINK
X      case I_SYMBOLIC_LINK:	putchar('l');	break;
X#endif
X      default:			putchar('?');
X}
X  printperm(ip->i_mode, 6, I_SET_UID_BIT, 's');
X  printperm(ip->i_mode, 3, I_SET_GID_BIT, 's');
X  printperm(ip->i_mode, 0, STICKY_BIT, 't');
X  printf(" %3u ", ip->i_nlinks);
X  switch (ip->i_mode & I_TYPE) {
X      case I_CHAR_SPECIAL:
X      case I_BLOCK_SPECIAL:
X	printf("  %2x,%2x ", (dev_t) ip->i_zone[0] >> MAJOR & 0xFF,
X	       (dev_t) ip->i_zone[0] >> MINOR & 0xFF);
X	break;
X      default:	printf("%7ld ", ip->i_size);
X  }
X  printpath(0, 1);
X}
X
X/* Remove an entry from a directory if ok with the user.
X * Don't name the function remove() - that is owned by ANSI, and chaos results
X * when it is a macro.
X */
Xint Remove(dp)
Xdir_struct *dp;
X{
X  setbit(spec_imap, (bit_nr) dp->d_inum);
X  if (yes(". remove entry")) {
X	count[dp->d_inum]--;
X	memset((void *) dp, 0, sizeof(dir_struct));
X	return(1);
X  }
X  return(0);
X}
X
X/* Convert string so that embedded control characters are printable. */
Xvoid make_printable_name(dst, src, n)
Xregister char *dst;
Xregister char *src;
Xregister int n;
X{
X  register int c;
X
X  while (--n >= 0 && (c = *src++) != '\0') {
X	if (isprint(c) && c != '\\')
X		*dst++ = c;
X	else {
X		*dst++ = '\\';
X		switch (c) {
X		      case '\\':
X			*dst++ = '\\'; break;
X		      case '\b':
X			*dst++ = 'b'; break;
X		      case '\f':
X			*dst++ = 'f'; break;
X		      case '\n':
X			*dst++ = 'n'; break;
X		      case '\r':
X			*dst++ = 'r'; break;
X		      case '\t':
X			*dst++ = 't'; break;
X		      default:
X			*dst++ = '0' + ((c >> 6) & 03);
X			*dst++ = '0' + ((c >> 3) & 07);
X			*dst++ = '0' + (c & 07);
X		}
X	}
X  }
X  *dst = '\0';
X}
X
X/* See if the `.' or `..' entry is as expected. */
Xint chkdots(ino, pos, dp, exp)
Xino_t ino, exp;
Xoff_t pos;
Xdir_struct *dp;
X{
X  char printable_name[4 * NAME_MAX + 1];
X
X  if (dp->d_inum != exp) {
X	make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
X	printf("bad %s in ", printable_name);
X	printpath(1, 0);
X	printf("%s is linked to %u ", printable_name, dp->d_inum);
X	printf("instead of %u)", exp);
X	setbit(spec_imap, (bit_nr) ino);
X	setbit(spec_imap, (bit_nr) dp->d_inum);
X	setbit(spec_imap, (bit_nr) exp);
X	if (yes(". repair")) {
X		count[dp->d_inum]--;
X		dp->d_inum = exp;
X		count[exp]++;
X		return(0);
X	}
X  } else if (pos != (dp->d_name[1] ? DIR_ENTRY_SIZE : 0)) {
X	make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
X	printf("warning: %s has offset %ld in ", printable_name, pos);
X	printpath(1, 0);
X	printf("%s is linked to %u)\n", printable_name, dp->d_inum);
X	setbit(spec_imap, (bit_nr) ino);
X	setbit(spec_imap, (bit_nr) dp->d_inum);
X	setbit(spec_imap, (bit_nr) exp);
X  }
X  return(1);
X}
X
X/* Check the name in a directory entry. */
Xint chkname(ino, dp)
Xino_t ino;
Xdir_struct *dp;
X{
X  register n = NAME_MAX + 1;
X  register char *p = dp->d_name;
X
X  if (*p == '\0') {
X	printf("null name found in ");
X	printpath(0, 0);
X	setbit(spec_imap, (bit_nr) ino);
X	if (Remove(dp)) return(0);
X  }
X  while (*p != '\0' && --n != 0)
X	if (*p++ == '/') {
X		printf("found a '/' in entry of directory ");
X		printpath(1, 0);
X		setbit(spec_imap, (bit_nr) ino);
X		printf("entry = '");
X		printname(dp->d_name);
X		printf("')");
X		if (Remove(dp)) return(0);
X		break;
X	}
X  return(1);
X}
X
X/* Check a directory entry.  Here the routine `descendtree' is called
X * recursively to check the file or directory pointed to by the entry.
X */
Xint chkentry(ino, pos, dp)
Xino_t ino;
Xoff_t pos;
Xdir_struct *dp;
X{
X  if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) {
X	printf("bad inode found in directory ");
X	printpath(1, 0);
X	printf("ino found = %u, ", dp->d_inum);
X	printf("name = '");
X	printname(dp->d_name);
X	printf("')");
X	if (yes(". remove entry")) {
X		memset((void *) dp, 0, sizeof(dir_struct));
X		return(0);
X	}
X	return(1);
X  }
X  if ((unsigned) count[dp->d_inum] == LINK_MAX) {
X	printf("too many links to ino %u\n", dp->d_inum);
X	printf("discovered at entry '");
X	printname(dp->d_name);
X	printf("' in directory ");
X	printpath(0, 1);
X	if (Remove(dp)) return(0);
X  }
X  count[dp->d_inum]++;
X  if (strcmp(dp->d_name, ".") == 0) {
X	ftop->st_presence |= DOT;
X	return(chkdots(ino, pos, dp, ino));
X  }
X  if (strcmp(dp->d_name, "..") == 0) {
X	ftop->st_presence |= DOTDOT;
X	return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino :
X			ftop->st_next->st_dir->d_inum));
X  }
X  if (!chkname(ino, dp)) return(0);
X  if (bitset(dirmap, (bit_nr) dp->d_inum)) {
X	printf("link to directory discovered in ");
X	printpath(1, 0);
X	printf("name = '");
X	printname(dp->d_name);
X	printf("', dir ino = %u)", dp->d_inum);
X	return !Remove(dp);
X  }
X  return(descendtree(dp));
X}
X
X/* Check a zone of a directory by checking all the entries in the zone.
X * The zone is split up into chunks to not allocate too much stack.
X */
Xint chkdirzone(ino, ip, pos, zno)
Xino_t ino;
Xd_inode *ip;
Xoff_t pos;
Xzone_nr zno;
X{
X  dir_struct dirblk[CDIRECT];
X  register dir_struct *dp;
X  register n = SCALE * (NR_DIR_ENTRIES / CDIRECT), dirty;
X  register long offset = zaddr(zno);
X
X  do {
X	devread(offset, (char *) dirblk, DIRCHUNK);
X	dirty = 0;
X	for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) {
X		if (ip->i_size - pos < DIR_ENTRY_SIZE) {
X			printf("bad format in directory ");
X			printpath(2, 0);
X			if (yes(". truncate")) {
X				setbit(spec_imap, (bit_nr) ino);
X				ip->i_size = pos;
X				dirty = 1;
X			} else
X				return(0);
X		}
X		if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp))dirty= 1;
X		if ((pos += DIR_ENTRY_SIZE) >= ip->i_size) break;
X	}
X	if (dirty) devwrite(offset, (char *) dirblk, DIRCHUNK);
X	offset += DIRCHUNK;
X  } while (--n && pos < ip->i_size);
X  return(1);
X}
X
X/* There is something wrong with the given zone.  Print some details. */
Xvoid errzone(mess, zno, level, pos)
Xchar *mess;
Xzone_nr zno;
Xint level;
Xoff_t pos;
X{
X  printf("%s zone in ", mess);
X  printpath(1, 0);
X  printf("zno = %ld, type = ", zno);
X  switch (level) {
X      case 0:	printf("DATA");	break;
X      case 1:	printf("SINGLE INDIRECT");	break;
X      case 2:	printf("DOUBLE INDIRECT");	break;
X      default:	printf("VERY INDIRECT");
X  }
X  printf(", pos = %ld)\n", pos);
X}
X
X/* Found the given zone in the given inode.  Check it, and if ok, mark it
X * in the zone bitmap.
X */
Xint markzone(zno, level, pos)
Xzone_nr zno;
Xint level;
Xoff_t pos;
X{
X  register bit_nr bit = (bit_nr) zno - FIRST + 1;
X
X  ztype[level]++;
X  if (zno < FIRST || zno >= sb.s_zones) {
X	errzone("out-of-range", zno, level, pos);
X	return(0);
X  }
X  if (bitset(zmap, bit)) {
X	setbit(spec_zmap, bit);
X	errzone("duplicate", zno, level, pos);
X	return(0);
X  }
X  nfreezone--;
X  if (bitset(spec_zmap, bit)) errzone("found", zno, level, pos);
X  setbit(zmap, bit);
X  return(1);
X}
X
X/* Check an indirect zone by checking all of its entries.
X * The zone is split up into chunks to not allocate too much stack.
X */
Xint chkindzone(ino, ip, pos, zno, level)
Xino_t ino;
Xd_inode *ip;
Xoff_t *pos;
Xzone_nr zno;
Xint level;
X{
X  zone_nr indirect[CINDIR];
X  register n = NR_INDIRECTS / CINDIR;
X  register long offset = zaddr(zno);
X
X  do {
X	devread(offset, (char *) indirect, INDCHUNK);
X	if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0);
X	offset += INDCHUNK;
X  } while (--n && *pos < ip->i_size);
X  return(1);
X}
X
X/* Return the size of a gap in the file, represented by a null zone number
X * at some level of indirection.
X */
Xoff_t jump(level)
Xint level;
X{
X  off_t power = ZONE_SIZE;
X
X  if (level != 0) do
X		power *= NR_INDIRECTS;
X	while (--level);
X  return(power);
X}
X
X/* Check a zone, which may be either a normal data zone, a directory zone,
X * or an indirect zone.
X */
Xint zonechk(ino, ip, pos, zno, level)
Xino_t ino;
Xd_inode *ip;
Xoff_t *pos;
Xzone_nr zno;
Xint level;
X{
X  if (level == 0) {
X	if ((ip->i_mode & I_TYPE) == I_DIRECTORY &&
X	    !chkdirzone(ino, ip, *pos, zno))
X		return(0);
X	*pos += ZONE_SIZE;
X	return(1);
X  } else
X	return chkindzone(ino, ip, pos, zno, level);
X}
X
X/* Check a list of zones given by `zlist'. */
Xint chkzones(ino, ip, pos, zlist, len, level)
Xino_t ino;
Xd_inode *ip;
Xoff_t *pos;
Xzone_nr *zlist;
Xint len;
Xint level;
X{
X  register ok = 1, i;
X
X  /* The check on the position in the next loop is commented out, since FS
X   * now requires valid zone numbers in each level that is necessary and FS
X   * always deleted all the zones in the double indirect block.
X   */
X  for (i = 0; i < len /* && *pos < ip->i_size */ ; i++)
X	if (zlist[i] == NO_ZONE)
X		*pos += jump(level);
X	else if (!markzone(zlist[i], level, *pos)) {
X		*pos += jump(level);
X		ok = 0;
X	} else if (!zonechk(ino, ip, pos, zlist[i], level))
X		ok = 0;
X  return(ok);
X}
X
X/* Check a file or a directory. */
Xint chkfile(ino, ip)
Xino_t ino;
Xd_inode *ip;
X{
X  register ok, i, level;
X  off_t pos = 0;
X
X  ok = chkzones(ino, ip, &pos, &ip->i_zone[0], NR_DZONE_NUM, 0);
X  for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++)
X	ok &= chkzones(ino, ip, &pos, &ip->i_zone[i], 1, level);
X  return(ok);
X}
X
X/* Check a directory by checking the contents.  Check if . and .. are present. */
Xint chkdirectory(ino, ip)
Xino_t ino;
Xd_inode *ip;
X{
X  register ok;
X
X  setbit(dirmap, (bit_nr) ino);
X  if (ip->i_size > MAXDIRSIZE) {
X	printf("warning: huge directory: ");
X	printpath(2, 1);
X  }
X  ok = chkfile(ino, ip);
X  if (!(ftop->st_presence & DOT)) {
X	printf(". missing in ");
X	printpath(2, 1);
X	ok = 0;
X  }
X  if (!(ftop->st_presence & DOTDOT)) {
X	printf(".. missing in ");
X	printpath(2, 1);
X	ok = 0;
X  }
X  return(ok);
X}
X
X#ifdef I_SYMBOLIC_LINK
X
X/* Check the validity of a symbolic link. */
Xint chklink(ino, ip)
Xino_t ino;
Xd_inode *ip;
X{
X  int ok;
X
X  ok = chkfile(ino, ip);
X  if (ip->i_size <= 0 || ip->i_size > BLOCK_SIZE) {
X	if (ip->i_size == 0)
X		printf("empty symbolic link ");
X	else
X		printf("symbolic link too large (size %ld) ", ip->i_size);
X	printpath(2, 1);
X	ok = 0;
X  }
X  return(ok);
X}
X
X#endif
X
X/* Check the validity of a special file. */
Xint chkspecial(ino, ip)
Xino_t ino;
Xd_inode *ip;
X{
X  int i, ok;
X
X  ok = 1;
X  if ((dev_t) ip->i_zone[0] == NO_DEV) {
X	printf("illegal device number %ld for special file ", ip->i_zone[0]);
X	printpath(2, 1);
X	ok = 0;
X  }
X
X  /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
X   * they are nonzero, since this should not happen.
X   */
X  for (i = 1; i < NR_ZONE_NUMS; i++)
X	if (ip->i_zone[i] != NO_ZONE) {
X		printf("nonzero zone number %ld for special file ",
X		       ip->i_zone[i]);
X		printpath(2, 1);
X		ok = 0;
X	}
X  return(ok);
X}
X
X/* Check the mode and contents of an inode. */
Xint chkmode(ino, ip)
Xino_t ino;
Xd_inode *ip;
X{
X  switch (ip->i_mode & I_TYPE) {
X      case I_REGULAR:
X	nregular++;
X	return chkfile(ino, ip);
X      case I_DIRECTORY:
X	ndirectory++;
X	return chkdirectory(ino, ip);
X      case I_BLOCK_SPECIAL:
X	nblkspec++;
X	return chkspecial(ino, ip);
X      case I_CHAR_SPECIAL:
X	ncharspec++;
X	return chkspecial(ino, ip);
X      case I_NAMED_PIPE:
X	npipe++;
X	return chkfile(ino, ip);
X#ifdef I_SYMBOLIC_LINK
X      case I_SYMBOLIC_LINK:
X	nsyml++;
X	return chklink(ino, ip);
X#endif
X      default:
X	nbadinode++;
X	printf("bad mode of ");
X	printpath(1, 0);
X	printf("mode = %o)", ip->i_mode);
X	return(0);
X  }
X}
X
X/* Check an inode. */
Xint chkinode(ino, ip)
Xino_t ino;
Xd_inode *ip;
X{
X  if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) {
X	printf("root inode is not a directory ");
X	printf("(ino = %u, mode = %o)\n", ino, ip->i_mode);
X	fatal("");
X  }
X  if (ip->i_nlinks == 0) {
X	printf("link count zero of ");
X	printpath(2, 0);
X	return(0);
X  }
X  nfreeinode--;
X  setbit(imap, (bit_nr) ino);
X  if ((unsigned) ip->i_nlinks > LINK_MAX) {
X	printf("link count too big in ");
X	printpath(1, 0);
X	printf("cnt = %u)\n", (unsigned) ip->i_nlinks);
X	count[ino] -= LINK_MAX;
X	setbit(spec_imap, (bit_nr) ino);
X  } else {
X	count[ino] -= (unsigned) ip->i_nlinks;
X  }
X  return chkmode(ino, ip);
X}
X
X/* Check the directory entry pointed to by dp, by checking the inode. */
Xint descendtree(dp)
Xdir_struct *dp;
X{
X  d_inode inode;
X  register ino_t ino = dp->d_inum;
X  register visited;
X  struct stack stk;
X
X  stk.st_dir = dp;
X  stk.st_next = ftop;
X  ftop = &stk;
X  if (bitset(spec_imap, (bit_nr) ino)) {
X	printf("found inode %u: ", ino);
X	printpath(0, 1);
X  }
X  visited = bitset(imap, (bit_nr) ino);
X  if (!visited || listing) {
X	devread(inoaddr(ino), (char *) &inode, INODE_SIZE);
X	if (listing) list(ino, &inode);
X	if (!visited && !chkinode(ino, &inode)) {
X		setbit(spec_imap, (bit_nr) ino);
X		if (yes("remove")) {
X			count[ino] += inode.i_nlinks - 1;
X			clrbit(imap, (bit_nr) ino);
X			devwrite(inoaddr(ino), nullbuf, INODE_SIZE);
X			memset((void *) dp, 0, sizeof(dir_struct));
X			ftop = ftop->st_next;
X			return(0);
X		}
X	}
X  }
X  ftop = ftop->st_next;
X  return(1);
X}
X
X/* Check the file system tree. */
Xvoid chktree()
X{
X  dir_struct dir;
X
X  nfreeinode = sb.s_ninodes;
X  nfreezone = N_DATA;
X  dir.d_inum = ROOT_INODE;
X  dir.d_name[0] = 0;
X  if (!descendtree(&dir)) fatal("bad root inode");
X  putchar('\n');
X}
X
X/* Print the totals of all the objects found. */
Xvoid printtotal()
X{
X  printf("blocksize = %5d        ", BLOCK_SIZE);
X  printf("zonesize  = %5d\n", ZONE_SIZE);
X  printf("\n");
X  pr("%6u    Regular file%s\n", nregular, "", "s");
X  pr("%6u    Director%s\n", ndirectory, "y", "ies");
X  pr("%6u    Block special file%s\n", nblkspec, "", "s");
X  pr("%6u    Character special file%s\n", ncharspec, "", "s");
X  if (nbadinode != 0) pr("%6u    Bad inode%s\n", nbadinode, "", "s");
X  pr("%6u    Free inode%s\n", nfreeinode, "", "s");
X  pr("%6u    Named pipe%s\n", npipe, "", "s");
X  pr("%6u    Symbolic link%s\n", nsyml, "", "s");
X/* Don't print some fields.
X  printf("\n");
X  pr("%6u    Data zone%s\n",		  ztype[0],	 "",   "s");
X  pr("%6u    Single indirect zone%s\n",	  ztype[1],	 "",   "s");
X  pr("%6u    Double indirect zone%s\n",	  ztype[2],	 "",   "s");
X*/
X  lpr("%6ld    Free zone%s\n", nfreezone, "", "s");
X}
X
X/* Check the device which name is given by `f'.  The inodes listed by `clist'
X * should be listed separately, and the inodes listed by `ilist' and the zones
X * listed by `zlist' should be watched for while checking the file system.
X */
X
Xvoid chkdev(f, clist, ilist, zlist)
Xchar *f, **clist, **ilist, **zlist;
X{
X  if (automatic) repair = 1;
X  device = f;
X  initvars();
X
X  devopen();
X
X  getsuper();
X  chksuper();
X
X  lsi(clist);
X
X  getbitmaps();
X  initbitmap(imap, (bit_nr) sb.s_ninodes + 1, N_IMAP);
X  initbitmap(zmap, (bit_nr) sb.s_zones - (bit_nr) FIRST + 1, N_ZMAP);
X
X  fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist);
X  fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_zones, zlist);
X
X  getcount();
X  chktree();
X  chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP,
X         (bit_nr) sb.s_zones, "zone");
X  chkcount();
X  chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP,
X         (bit_nr) sb.s_ninodes + 1, "inode");
X  chkilist();
X  printtotal();
X
X  putbitmaps();
X  freecount();
X  devclose();
X
X  if (changed) printf("----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
X}
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X  register char **clist = 0, **ilist = 0, **zlist = 0;
X
X  register devgiven = 0;
X  register char *arg;
X
X  if ((1 << BITSHIFT) != 8 * sizeof(int)) {
X	printf("Fsck was compiled with the wrong BITSHIFT!\n");
X	exit(1);
X  }
X
X  sync();
X  prog = *argv++;
X  while ((arg = *argv++) != 0)
X	if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) {
X		    case 'a':	automatic ^= 1;	break;
X		    case 'c':
X			clist = getlist(&argv, "inode");
X			break;
X		    case 'i':
X			ilist = getlist(&argv, "inode");
X			break;
X		    case 'z':
X			zlist = getlist(&argv, "zone");
X			break;
X		    case 'r':	repair ^= 1;	break;
X		    case 'l':	listing ^= 1;	break;
X		    case 's':	listsuper ^= 1;	break;
X		    default:
X			printf("%s: unknown flag '%s'\n", prog, arg);
X		}
X	else {
X		chkdev(arg, clist, ilist, zlist);
X		clist = 0;
X		ilist = 0;
X		zlist = 0;
X		devgiven = 1;
X	}
X  if (!devgiven) {
X	printf("Usage: fsck [-acilrsz] file\n");
X	exit(1);
X  }
X  return(0);
X}
/
echo x - gomoku.c
sed '/^X/s///' > gomoku.c << '/'
X/* gomoku - 5 in a row game		Author: ? */
X
X/* This program plays a very old Japanese game called GO-MOKU,
X   perhaps better known as  5-in-line.   The game is played on
X   a board with 19 x 19 squares, and the object of the game is
X   to get 5 stones in a row.
X*/
X
X#include <sys/types.h>
X#include <curses.h>
X#include <ctype.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <sgtty.h>
X
X/* Size of the board */
X#define SIZE 19
X
X/* Importance of attack (1..16) */
X#define AttackFactor 4
X
X/* Value of having 0, 1,2,3,4 or 5 pieces in line */
Xint Weight[7] = {0, 0, 4, 20, 100, 500, 0};
X
X#define Null 0
X#define Horiz 1
X#define DownLeft 2
X#define DownRight 3
X#define Vert 4
X
X/* The two players */
X#define Empty 0
X#define Cross 1
X#define Nought 2
X
Xchar PieceChar[Nought + 1] = {' ', 'X', '0'};
X
Xint Board[SIZE + 1][SIZE + 1];/* The board */
Xint Player;			/* The player whose move is next */
Xint TotalLines;			/* The number of Empty lines left */
Xint GameWon;			/* Set if one of the players has won */
X
Xint Line[4][SIZE + 1][SIZE + 1][Nought + 1];
X
X/* Value of each square for each player */
Xint Value[SIZE + 1][SIZE + 1][Nought + 1];
X
Xint X, Y;			/* Move coordinates */
Xchar Command;			/* Command from keyboard */
Xint AutoPlay = FALSE;		/* The program plays against itself */
X
Xstruct sgttyb old_tty, new_tty;
X
X_PROTOTYPE(void Initialize, (void));
X_PROTOTYPE(int Abort, (char *s));
X_PROTOTYPE(void WriteLetters, (void));
X_PROTOTYPE(void WriteLine, (int j, int *s));
X_PROTOTYPE(void WriteBoard, (int N, int *Top, int *Middle, int *Bottom));
X_PROTOTYPE(void SetUpScreen, (void));
X_PROTOTYPE(void GotoSquare, (int x, int y));
X_PROTOTYPE(void PrintMove, (int Piece, int X, int Y));
X_PROTOTYPE(void ClearMove, (void));
X_PROTOTYPE(void PrintMsg, (char *Str));
X_PROTOTYPE(void ClearMsg, (void));
X_PROTOTYPE(void WriteCommand, (char *S));
X_PROTOTYPE(void ResetGame, (int FirstGame));
X_PROTOTYPE(int OpponentColor, (int Player));
X_PROTOTYPE(void BlinkRow, (int X, int Y, int Dx, int Dy, int Piece));
X_PROTOTYPE(void BlinkWinner, (int Piece, int X, int Y, int WinningLine));
X_PROTOTYPE(int Random, (int x));
X_PROTOTYPE(void Add, (int *Num));
X_PROTOTYPE(void Update, (int Lin[], int Valu[], int Opponent));
X_PROTOTYPE(void MakeMove, (int X, int Y));
X_PROTOTYPE(int GameOver, (void));
X_PROTOTYPE(void FindMove, (int *X, int *Y));
X_PROTOTYPE(char GetChar, (void));
X_PROTOTYPE(void ReadCommand, (int X, int Y, char *Command));
X_PROTOTYPE(void InterpretCommand, (int Command));
X_PROTOTYPE(void PlayerMove, (void));
X_PROTOTYPE(void ProgramMove, (void));
X_PROTOTYPE(int main, (void));
X
X/* Get the termcap entry and set terminal to raw mode. */
Xvoid Initialize()
X{
X  /* Save old terminal parameters. */
X  ioctl(0, TIOCGETP, &old_tty);
X
X  /* Set tty to CBREAK mode */
X  ioctl(0, TIOCGETP, &new_tty);
X  new_tty.sg_flags |= CBREAK;
X  new_tty.sg_flags &= ~ECHO;
X  ioctl(0, TIOCSETP, &new_tty);
X
X  srand(getpid() + 13);		/* Initialize the random seed with our pid */
X  initscr();
X  raw();
X  noecho();
X  clear();
X}
X
X/* Reset terminal and exit from the program. */
Xint Abort(s)
Xchar *s;
X{
X  move(LINES - 1, 0);
X  refresh();
X  endwin();
X  ioctl(0, TIOCSETP, &old_tty);	/* restore terminal parameters */
X  exit(0);
X}
X
X/* Set up the screen ----------------------------------------------- */
X
X/* Write the letters */
Xvoid WriteLetters()
X{
X  int i;
X
X  addch(' ');
X  addch(' ');
X  for (i = 1; i <= SIZE; i++) printw(" %c", 'A' + i - 1);
X  addch('\n');
X}
X
X/* Write one line of the board */
Xvoid WriteLine(j, s)
Xint j;
Xint *s;
X{
X  int i;
X
X  printw("%2d ", j);
X  addch(s[0]);
X  for (i = 2; i <= SIZE - 1; i++) {
X	addch(s[1]);
X	addch(s[2]);
X  }
X  addch(s[1]);
X  addch(s[3]);
X  printw(" %-2d\n", j);
X}
X
X/* Print the Empty board and the border */
Xvoid WriteBoard(N, Top, Middle, Bottom)
Xint N;
Xint *Top, *Middle, *Bottom;
X{
X  int j;
X
X  move(1, 0);
X  WriteLetters();
X  WriteLine(N, Top);
X  for (j = N - 1; j >= 2; j--) WriteLine(j, Middle);
X  WriteLine(1, Bottom);
X  WriteLetters();
X}
X
X/* Sets up the screen with an Empty board */
Xvoid SetUpScreen()
X{
X  int top[4], middle[4], bottom[4];
X
X  top[0] = ACS_ULCORNER;
X  top[1] = ACS_HLINE;
X  top[2] = ACS_TTEE;
X  top[3] = ACS_URCORNER;
X
X  middle[0] = ACS_LTEE;
X  middle[1] = ACS_HLINE;
X  middle[2] = ACS_PLUS;
X  middle[3] = ACS_RTEE;
X
X  bottom[0] = ACS_LLCORNER;
X  bottom[1] = ACS_HLINE;
X  bottom[2] = ACS_BTEE;
X  bottom[3] = ACS_LRCORNER;
X
X  WriteBoard(SIZE, top, middle, bottom);
X}
X
X/* Show moves ----------------------------------------------- */
X
Xvoid GotoSquare(x, y)
Xint x, y;
X{
X  move(SIZE + 2 - y, 1 + x * 2);
X}
X
X/* Prints a move */
Xvoid PrintMove(Piece, X, Y)
Xint Piece;
Xint X, Y;
X{
X  move(22, 49);
X  printw("%c %c %d", PieceChar[Piece], 'A' + X - 1, Y);
X  clrtoeol();
X  GotoSquare(X, Y);
X  addch(PieceChar[Piece]);
X  GotoSquare(X, Y);
X  refresh();
X}
X
X/* Clears the line where a move is displayed */
Xvoid ClearMove()
X{
X  move(22, 49);
X  clrtoeol();
X}
X
X/* Message handling ---------------------------------------------- */
X
X/* Prints a message */
Xvoid PrintMsg(Str)
Xchar *Str;
X{
X  mvprintw(23, 1, "%s", Str);
X}
X
X/* Clears the message about the winner */
Xvoid ClearMsg()
X{
X  move(23, 1);
X  clrtoeol();
X}
X
X/* Highlights the first letter of S */
Xvoid WriteCommand(S)
Xchar *S;
X{
X  standout();
X  addch(*S);
X  standend();
X  printw("%s", S + 1);
X}
X
X/* Display the board ----------------------------------------------- */
X
X/* Resets global variables to start a new game */
Xvoid ResetGame(FirstGame)
Xint FirstGame;
X{
X  int I, J;
X  int C, D;
X
X  SetUpScreen();
X  if (FirstGame) {
X	move(1, 49);
X	addstr("G O M O K U");
X	move(3, 49);
X	WriteCommand("Newgame    ");
X	WriteCommand("Quit ");
X	move(5, 49);
X	WriteCommand("Auto");
X	move(7, 49);
X	WriteCommand("Play");
X	move(9, 49);
X	WriteCommand("Hint");
X	move(14, 60);
X	WriteCommand("Left, ");
X	WriteCommand("Right, ");
X	move(16, 60);
X	WriteCommand("Up, ");
X	WriteCommand("Down");
X	move(18, 60);
X	standout();
X	addstr("SPACE");
X	move(20, 49);
X	WriteCommand(" NOTE: Use Num Lock & arrows");
X	standend();
X	mvaddstr(14, 49, "7  8  9");
X	mvaddch(15, 52, ACS_UARROW);
X	mvaddch(16, 49, '4');
X	addch(ACS_LARROW);
X	mvaddch(16, 54, ACS_RARROW);
X	addch('6');
X	mvaddch(17, 52, ACS_DARROW);
X	mvaddstr(18, 49, "1  2  3");
X	FirstGame = FALSE;
X  } else {
X	ClearMsg();
X	ClearMove();
X  }
X
X  /* Clear tables */
X  for (I = 1; I <= SIZE; I++) for (J = 1; J <= SIZE; J++) {
X		Board[I][J] = Empty;
X		for (C = Cross; C <= Nought; C++) {
X			Value[I][J][C] = 0;
X			for (D = 0; D <= 3; D++) Line[D][I][J][C] = 0;
X		}
X	}
X
X  /* Cross starts */
X  Player = Cross;
X  /* Total number of lines */
X  TotalLines = 2 * 2 * (SIZE * (SIZE - 4) + (SIZE - 4) * (SIZE - 4));
X  GameWon = FALSE;
X}
X
Xint OpponentColor(Player)
Xint Player;
X{
X  if (Player == Cross)
X	return Nought;
X  else
X	return Cross;
X}
X
X/* Blink the row of 5 stones */
Xvoid BlinkRow(X, Y, Dx, Dy, Piece)
Xint X, Y, Dx, Dy, Piece;
X{
X  int I;
X
X  attron(A_BLINK);
X  for (I = 1; I <= 5; I++) {
X	GotoSquare(X, Y);
X	addch(PieceChar[Piece]);
X	X = X - Dx;
X	Y = Y - Dy;
X  }
X  attroff(A_BLINK);
X}
X
X/* Prints the 5 winning stones in blinking color */
Xvoid BlinkWinner(Piece, X, Y, WinningLine)
Xint Piece, X, Y, WinningLine;
X{
X  /* Used to store the position of the winning move */
X  int XHold, YHold;
X  /* Change in X and Y */
X  int Dx, Dy;
X
X  /* Display winning move */
X  PrintMove(Piece, X, Y);
X  /* Preserve winning position */
X  XHold = X;
X  YHold = Y;
X  switch (WinningLine) {
X      case Horiz:
X	{
X		Dx = 1;
X		Dy = 0;
X		break;
X	}
X
X      case DownLeft:
X	{
X		Dx = 1;
X		Dy = 1;
X		break;
X	}
X
X      case Vert:
X	{
X		Dx = 0;
X		Dy = 1;
X		break;
X	}
X
X      case DownRight:
X	{
X		Dx = -1;
X		Dy = 1;
X		break;
X	}
X  }
X
X  /* Go to topmost, leftmost */
X  while (Board[X + Dx][Y + Dy] != Empty && Board[X + Dx][Y + Dy] == Piece) {
X	X = X + Dx;
X	Y = Y + Dy;
X  }
X  BlinkRow(X, Y, Dx, Dy, Piece);
X  /* Restore winning position */
X  X = XHold;
X  Y = YHold;
X  /* Go back to winning square */
X  GotoSquare(X, Y);
X}
X
X/* Functions for playing a game -------------------------------- */
X
Xint Random(x)
Xint x;
X{
X  return((rand() / 19) % x);
X}
X
X/* Adds one to the number of pieces in a line */
Xvoid Add(Num)
Xint *Num;
X{
X  /* Adds one to the number.     */
X  *Num = *Num + 1;
X  /* If it is the first piece in the line, then the opponent cannot use
X   * it any more.  */
X  if (*Num == 1) TotalLines = TotalLines - 1;
X  /* The game is won if there are 5 in line. */
X  if (*Num == 5) GameWon = TRUE;
X}
X
X/* Updates the value of a square for each player, taking into
X   account that player has placed an extra piece in the square.
X   The value of a square in a usable line is Weight[Lin[Player]+1]
X   where Lin[Player] is the number of pieces already placed
Xin the line */
Xvoid Update(Lin, Valu, Opponent)
Xint Lin[];
Xint Valu[];
Xint Opponent;
X{
X  /* If the opponent has no pieces in the line, then simply update the
X   * value for player */
X  if (Lin[Opponent] == 0)
X	Valu[Player] += Weight[Lin[Player] + 1] - Weight[Lin[Player]];
X  else
X	/* If it is the first piece in the line, then the line is
X	 * spoiled for the opponent */
X  if (Lin[Player] == 1) Valu[Opponent] -= Weight[Lin[Opponent] + 1];
X}
X
X/* Performs the move X,Y for player, and updates the global variables
X(Board, Line, Value, Player, GameWon, TotalLines and the screen) */
Xvoid MakeMove(X, Y)
Xint X, Y;
X{
X  int Opponent;
X  int X1, Y1;
X  int K, L, WinningLine;
X
X  WinningLine = Null;
X  Opponent = OpponentColor(Player);
X  GameWon = FALSE;
X
X  /* Each square of the board is part of 20 different lines. The adds
X   * one to the number of pieces in each of these lines. Then it
X   * updates the value for each of the 5 squares in each of the 20
X   * lines. Finally Board is updated, and the move is printed on the
X   * screen. */
X
X  /* Horizontal lines, from left to right */
X  for (K = 0; K <= 4; K++) {
X	X1 = X - K;		/* Calculate starting point */
X	Y1 = Y;
X	if ((1 <= X1) && (X1 <= SIZE - 4)) {	/* Check starting point */
X		Add(&Line[0][X1][Y1][Player]);	/* Add one to line */
X		if (GameWon && (WinningLine == Null))	/* Save winning line */
X			WinningLine = Horiz;
X		for (L = 0; L <= 4; L++)	/* Update value for the
X						 * 5 squares in the line */
X			Update(Line[0][X1][Y1], Value[X1 + L][Y1], Opponent);
X	}
X  }
X
X  for (K = 0; K <= 4; K++) {	/* Diagonal lines, from lower left to
X				 * upper right */
X	X1 = X - K;
X	Y1 = Y - K;
X	if ((1 <= X1) && (X1 <= SIZE - 4) &&
X	    (1 <= Y1) && (Y1 <= SIZE - 4)) {
X		Add(&Line[1][X1][Y1][Player]);
X		if (GameWon && (WinningLine == Null))	/* Save winning line */
X			WinningLine = DownLeft;
X		for (L = 0; L <= 4; L++)
X			Update(Line[1][X1][Y1], Value[X1 + L][Y1 + L], Opponent);
X	}
X  }				/* for */
X
X  for (K = 0; K <= 4; K++) {	/* Diagonal lines, down right to upper left */
X	X1 = X + K;
X	Y1 = Y - K;
X	if ((5 <= X1) && (X1 <= SIZE) &&
X	    (1 <= Y1) && (Y1 <= SIZE - 4)) {
X		Add(&Line[3][X1][Y1][Player]);
X		if (GameWon && (WinningLine == Null))	/* Save winning line */
X			WinningLine = DownRight;
X		for (L = 0; L <= 4; L++)
X			Update(Line[3][X1][Y1], Value[X1 - L][Y1 + L], Opponent);
X	}
X  }				/* for */
X
X  for (K = 0; K <= 4; K++) {	/* Vertical lines, from down to up */
X	X1 = X;
X	Y1 = Y - K;
X	if ((1 <= Y1) && (Y1 <= SIZE - 4)) {
X		Add(&Line[2][X1][Y1][Player]);
X		if (GameWon && (WinningLine == Null))	/* Save winning line */
X			WinningLine = Vert;
X		for (L = 0; L <= 4; L++)
X			Update(Line[2][X1][Y1], Value[X1][Y1 + L], Opponent);
X	}
X  }
X
X  Board[X][Y] = Player;		/* Place piece in board */
X  if (GameWon)
X	BlinkWinner(Player, X, Y, WinningLine);
X  else
X	PrintMove(Player, X, Y);/* Print move on screen */
X  Player = Opponent;		/* The opponent is next to move */
X}
X
Xint GameOver()
X/* A game is over if one of the players have
Xwon, or if there are no more Empty lines */
X{
X  return(GameWon || (TotalLines <= 0));
X}
X
X/* Finds a move X,Y for player, simply by picking the one with the
Xhighest value */
Xvoid FindMove(X, Y)
Xint *X, *Y;
X{
X  int Opponent;
X  int I, J;
X  int Max, Valu;
X
X  Opponent = OpponentColor(Player);
X  Max = -10000;
X  /* If no square has a high value then pick the one in the middle */
X  *X = (SIZE + 1) / 2;
X  *Y = (SIZE + 1) / 2;
X  if (Board[*X][*Y] == Empty) Max = 4;
X  /* The evaluation for a square is simply the value of the square for
X   * the player (attack points) plus the value for the opponent
X   * (defense points). Attack is more important than defense, since it
X   * is better to get 5 in line yourself than to prevent the op- ponent
X   * from getting it. */
X
X  /* For all Empty squares */
X  for (I = 1; I <= SIZE; I++) for (J = 1; J <= SIZE; J++)
X		if (Board[I][J] == Empty) {
X			/* Calculate evaluation */
X			Valu = Value[I][J][Player] * (16 + AttackFactor) / 16 + Value[I][J][Opponent] + Random(4);
X			/* Pick move with highest value */
X			if (Valu > Max) {
X				*X = I;
X				*Y = J;
X				Max = Valu;
X			}
X		}
X}
X
Xchar GetChar()
X/* Get a character from the keyboard */
X{
X  int c;
X
X  c = getch();
X  if (c < 0) abort();
X  if (islower(c))
X	return toupper(c);
X  else
X	return c;
X}
X
X/* Reads in a valid command character */
Xvoid ReadCommand(X, Y, Command)
Xint X, Y;
Xchar *Command;
X{
X  int ValidCommand;
X
X  do {
X	ValidCommand = TRUE;
X	GotoSquare(X, Y);	/* Goto square */
X	refresh();
X	*Command = GetChar();	/* Read from keyboard */
X	switch (*Command) {
X	    case '\n':		/* '\n' or space means place a */
X	    case ' ':
X		*Command = 'E';
X		break;		/* stone at the cursor position  */
X
X	    case 'L':
X	    case 'R':
X	    case 'U':
X	    case '7':
X	    case '9':
X	    case '1':
X	    case '3':
X	    case 'N':
X	    case 'Q':
X	    case 'A':
X	    case 'P':
X	    case 'H':
X		break;
X
X	    case '8':	*Command = 'U';	break;
X	    case '2':	*Command = 'D';	break;
X	    case '4':	*Command = 'L';	break;
X	    case '6':	*Command = 'R';	break;
X	    default:
X		{
X			if (GameOver())
X				*Command = 'P';
X			else
X				ValidCommand = FALSE;
X			break;
X		}
X	}
X  } while (!ValidCommand);
X}
X
Xvoid InterpretCommand(Command)
Xchar Command;
X{
X  int Temp;
X
X  switch (Command) {
X      case 'N':{		/* Start new game */
X		ResetGame(FALSE);	/* ResetGame but only redraw
X					 * the board */
X		X = (SIZE + 1) / 2;
X		Y = X;
X		break;
X	}
X      case 'H':
X	FindMove(&X, &Y);
X	break;			/* Give the user a hint */
X      case 'L':
X	X = (X + SIZE - 2) % SIZE + 1;
X	break;			/* Left  */
X      case 'R':
X	X = X % SIZE + 1;
X	break;			/* Right */
X      case 'D':
X	Y = (Y + SIZE - 2) % SIZE + 1;
X	break;			/* Down  */
X      case 'U':
X	Y = Y % SIZE + 1;
X	break;			/* Up    */
X      case '7':{
X		if ((X == 1) || (Y == SIZE)) {	/* Move diagonally    *//* t
X						 * owards upper left */
X			Temp = X;
X			X = Y;
X			Y = Temp;
X		} else {
X			X = X - 1;
X			Y = Y + 1;
X		}
X		break;
X	}
X      case '9':{		/* Move diagonally    */
X		if (X == SIZE) {/* toward upper right */
X			X = (SIZE - Y) + 1;
X			Y = 1;
X		} else if (Y == SIZE) {
X			Y = (SIZE - X) + 1;
X			X = 1;
X		} else {
X			X = X + 1;
X			Y = Y + 1;
X		}
X		break;
X	}
X      case '1':{		/* Move diagonally   */
X		if (Y == 1) {	/* toward lower left */
X			Y = (SIZE - X) + 1;
X			X = SIZE;
X		} else if (X == 1) {
X			X = (SIZE - Y) + 1;
X			Y = SIZE;
X		} else {
X			X = X - 1;
X			Y = Y - 1;
X		}
X		break;
X	}
X      case '3':{		/* Move diagonally    */
X		if ((X == SIZE) || (Y == 1)) {	/* toward lower right */
X			Temp = X;
X			X = Y;
X			Y = Temp;
X		} else {
X			X = X + 1;
X			Y = Y - 1;
X		}
X		break;
X	}
X      case 'A':
X	AutoPlay = TRUE;
X	break;			/* Auto play mode */
X  }				/* case */
X}				/* InterpretCommand */
X
Xvoid PlayerMove()
X/* Enter and make a move */
X{
X  if (Board[X][Y] == Empty) {
X	MakeMove(X, Y);
X	if (GameWon) PrintMsg("Congratulations, You won!");
X	Command = 'P';
X  }
X  refresh();
X}				/* PlayerMove */
X
Xvoid ProgramMove()
X/* Find and perform programs move */
X{
X  do {
X	if (GameOver()) {
X		AutoPlay = FALSE;
X		if ((Command != 'Q') && (!GameWon)) PrintMsg("Tie game!");
X	} else {
X		FindMove(&X, &Y);
X		MakeMove(X, Y);
X		if (GameWon) PrintMsg("I won!");
X	}
X	refresh();
X  } while (AutoPlay);
X}
X
Xint main()
X{
X  Initialize();
X  ResetGame(TRUE);		/* ResetGame and draw the entire screen */
X  refresh();
X  X = (SIZE + 1) / 2;		/* Set starting position to */
X  Y = X;			/* the middle of the board  */
X  do {
X	ReadCommand(X, Y, &Command);
X	if (GameOver())
X		if (Command != 'Q') Command = 'N';
X	InterpretCommand(Command);
X	if (Command == 'E') PlayerMove();
X	if (Command == 'P' || Command == 'A') ProgramMove();
X  } while (Command != 'Q');
X  Abort("Good bye!");
X  return(0);
X}
/
echo x - hyphenate.c
sed '/^X/s///' > hyphenate.c << '/'
X/* Hyphenate English text for mroff	Author: Alan I. Holub */
X
X/* This filter reads English text and ouputs it with \% at reasonable
X * places to hyphenate words.  It is normally used as an mroff preprocessor.
X * The original algorithm is due to Donald Knuth.  The program itself
X * came with Michael Haardt's mroff package.
X */
X
X#include <ctype.h>
X#include <string.h>
X#include <stdlib.h>
X#include <stdio.h>
X
Xtypedef enum { FALSE, TRUE} bool;
X
X#define HYPHEN          0x80
X#define HYPHENATE(c)    ( (c) |=  HYPHEN )
X#define UNHYPHENATE(c)  ( (c) &= ~HYPHEN )
X#define HAS_HYPHEN(c)   ( (c) &   HYPHEN )
X
Xchar **States;
Xextern char *Suffixes[];
Xextern char *Prefixes[];
X
X#define ER(p,end) ((* p & 0x7f)=='e' && (*(p+1) & 0x7f) == 'r' && (p+1) == end)
X
X#define CH ('z' + 1 )		/* {   0x7b  \173    */
X#define GH ('z' + 2 )		/* |   0x7c  \174    */
X#define PH ('z' + 3 )		/* }   0x7d  \175    */
X#define SH ('z' + 4 )		/* ~   0x7e  \176    */
X#define TH ('z' + 5 )		/* DEL   0x7f  \177    */
X
X/* a b c d e f g h i j k l m n o p q r s t u v w x y z */
Xchar vt[] = {1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0};
X
X#define isvowel(c)  ( islower((c) & 0x7f)  &&  vt[ ((c) & 0x7f) - 'a'] )
X#define isconsonant(c)  ((c) && !isvowel(c))
X
Xtypedef struct
X{
X  char arg, type;
X  void *variable;
X} ARG;
X
X
X_PROTOTYPE(char *suffix, (char *beg, char *end ));
X_PROTOTYPE(char *prefix, (char *beg, char *end ));
X_PROTOTYPE(char nextch, (char **pp, char *endp ));
X_PROTOTYPE(int isweird, (int x, int y, char *p ));
X_PROTOTYPE(void consonants, (char *beg, char *end ));
X_PROTOTYPE(int hyphen, (char *beg, char *end ));
X_PROTOTYPE(int next, (int cur_state, int cur_char ));
X_PROTOTYPE(bool process_word, (char *w ));
X_PROTOTYPE(int wcmp, (const void *word2, const void *tabp1 ));
X_PROTOTYPE(int exception, (char *word, char *end ));
X_PROTOTYPE(char *setarg, (ARG *argp, char *linep ));
X_PROTOTYPE(ARG *findarg, (int c, ARG *tabp, int tabsize ));
X_PROTOTYPE(int argparse, (int argc, char **argv, ARG *tabp, int tabsize ));
X_PROTOTYPE(void fail, (char *word ));
X_PROTOTYPE(void outtext, (int c ));
X_PROTOTYPE(void outspec, (int c ));
X_PROTOTYPE(int nextchar, (void));
X_PROTOTYPE(int escapeseq, (void));
X_PROTOTYPE(void nonletter, (void));
X_PROTOTYPE(int special, (void));
X_PROTOTYPE(int letter, (void));
X_PROTOTYPE(void word1, (void));
X_PROTOTYPE(void words, (void));
X_PROTOTYPE(int macro, (void));
X_PROTOTYPE(void line, (void));
X_PROTOTYPE(void text, (FILE *fd ));
X_PROTOTYPE(int main, (int argc, char *argv []));
X
X
Xchar *suffix(beg, end)
Xchar *beg, *end;
X{
X  register char *p, c, c2;
X  register int state;
X  register unsigned int times;
X
X  state = 1;
X  times = 0;
X  States = Suffixes;
X
X  for (p = end; p >= beg;) {
X	state = next(state, c = *p-- & 0x7f);
X
X	if (!('a' <= c && c <= 'z'))	/* Worter mit Grossbuch-  */
X		return end;	/* staben werden nicht   */
X
X	if (state == 0) {
X		if (times == 0)
X			p = end;	/* entferne endendes e,d */
X		else if (times == 1)	/* entf. endendes ed, de */
X			p = end - 1;	/* ee oder dd            */
X		else
X			return end;
X
X		times++;
X	}
X	switch (state) {
X	    case 86:
X		c = *p & 0x7f;
X		c2 = *(p - 1) & 0x7f;
X
X		if (p - beg < 3) return end;	/* FAIL */
X		else if ((c == c2) && (!isvowel(c))
X			 && (c != 'f') && (c != 's')
X			 && (c != 'l') && (c != 'z')) {
X			--p;
X		} else if (c == 'l' && strchr("bcdfghkptz", c2)) {
X			p -= (c2 == 'k' && (*(p - 2) & 0x7f) == 'c')
X				? 1 : 2;
X		}
X
X	    case 87:
X		HYPHENATE(*(p + 1));
X		return p;
X
X	    case 88:
X		HYPHENATE(*(p + 2));
X		return(p + 1);
X
X	    case 89:
X		HYPHENATE(*(p + 5));
X		HYPHENATE(*(p + 1));
X		return p;
X
X	    case 82:
X		p++;		/* p += 3 */
X	    case 81:
X		p++;		/* p += 2 */
X	    case 80:
X		p++;		/* P += 1 */
X	    case 83:
X		end = p;
X		HYPHENATE(*(p + 1));
X		state = 1;
X		break;
X
X	    case 84:		/* Fehl-Status */
X		return end;
X	}
X  }
X
X  return end;
X}
Xchar *prefix(beg, end)
Xchar *beg, *end;
X{
X
X  register char *p, c;
X  register int state;
X
X  state = 1;
X  States = Prefixes;
X
X  for (p = beg; p < end;) {
X	switch (state = next(state, c = *p++ & 0x7f)) {
X	    case 82:
X		HYPHENATE(*p);
X		HYPHENATE(*(p - 1));
X		return p;
X	    case 83:
X		HYPHENATE(*p);
X		HYPHENATE(*(p - 2));
X		return p;
X	    case 84:
X		HYPHENATE(*p);
X		HYPHENATE(*(p - 3));
X		return p;
X
X	    case 81:
X		--p;
X	    case 87:
X		HYPHENATE(*p);
X		return p;
X
X	    case 85:
X		--p;
X	    case 86:
X		beg = p;
X		state = 1;
X	    case 69:	HYPHENATE(*p);	break;
X
X	    case 70:	HYPHENATE(*(p - 1));	break;
X	    case 71:
X	    case 72:
X	    case 73:
X	    case 74:
X	    case 75:
X	    case 76:
X	    case 77:
X	    case 78:	case 79:	break;
X	}
X  }
X
X  return beg;
X}
X
Xchar *vccv_except[] =
X{
X  /* A  */ "",
X  /* B  */ "lr",
X  /* C  */ "lr",
X  /* D  */ "gr",
X  /* E  */ "",
X  /* F  */ "lr",
X  /* G  */ "lr",
X  /* H  */ "",
X  /* I  */ "",
X  /* J  */ "",
X  /* K  */ "n",
X  /* L  */ "kq",
X  /* M  */ "",
X  /* N  */ "{kx",		/* CH, k, x */
X  /* O  */ "",
X  /* P  */ "lr",
X  /* Q  */ "",
X  /* R  */ "k",
X  /* S  */ "pq",
X  /* T  */ "{r",		/* CH, r    */
X  /* U  */ "",
X  /* V  */ "",
X  /* W  */ "hlnr",
X  /* X  */ "",
X  /* Y  */ "",
X  /* Z  */ "",
X  /* CH */ "lr",
X  /* GH */ "t",
X  /* PH */ "r",
X  /* SH */ "",
X  /* TH */ "r"
X};
Xchar nextch(pp, endp)
Xchar **pp, *endp;
X{
X
X  register char rval, *p;
X
X  if ((p = *pp) > endp) return(char) 0;
X
X  rval = *p++ & 0x7f;
X
X  if ((*p & 0x7f) == 'h') {
X	switch ((int) rval) {
X	    case 't':
X		rval = TH;
X		p++;
X		break;
X	    case 's':
X		rval = SH;
X		p++;
X		break;
X	    case 'p':
X		rval = PH;
X		p++;
X		break;
X	    case 'c':
X		rval = CH;
X		p++;
X		break;
X	    case 'g':
X		rval = GH;
X		p++;
X		break;
X	}
X  }
X  *pp = p;
X  return rval;
X}
Xint isweird(x, y, p)
Xchar x, y, *p;
X{
X
X  register unsigned int c1, c2, c3;
X
X  c1 = *p++ & 0x7f;
X  c2 = *p++ & 0x7f;
X  c3 = *p & 0x7f;
X
X  x &= 0x7f;
X  y &= 0x7f;
X
X  return(
X	(
X	 (c1 == 'e' && c2 == 'r')
X	 || (c1 == 'a' && c2 == 'g' && c3 == 'e')
X	 || (c1 == 'e' && c2 == 's' && c3 == 't')
X	 )
X	&&
X	((x == 'f' && y == 't')
X	 || (x == 'l' && y == 'd')
X	 || (x == 'm' && y == 'p')
X	 || (x == 's' && y == 't')
X	 || (x == 'n' && strchr("dgst", (int) (y & 0x7f)))
X	 || (x == 'r' && strchr("gmnt", (int) (y & 0x7f)))
X	 )
X	);
X}
Xvoid consonants(beg, end)
Xchar *beg, *end;
X{
X
X  register char c1, c2, *cp;
X  register char *p;
X
X  while (1) {
Xstate1:
X
X	do {
X		c2 = nextch(&beg, end);
X	} while (isconsonant(c2));
X
X	do {
X		for (c1 = c2; isvowel(c1);) {
X			cp = beg;
X			c1 = nextch(&beg, end);
X		}
X
X
X		if (c1 == 'q' && *beg == 'u') {	/* Vqu */
X			HYPHENATE(*cp);	/* V-qu */
X			nextch(&beg, end);	/* uberspringe u */
X			goto state1;
X		}
X		cp = beg;
X		c2 = nextch(&beg, end);
X
X	} while (isvowel(c2));
X
X	if (!c1 || !c2) break;
X
X	if (c1 == 'c' && c2 == 'k') {	/* Vck  */
X		if (*beg) HYPHENATE(*beg);	/* Vck- */
X	} else if (c1 == c2) {	/* ller(s) */
X		if ((c1 != 'l' && c1 != 's') ||
X		    (isvowel(*beg) && !ER(beg, end)))
X			HYPHENATE(*cp);
X	} else if (isvowel(*beg)) {	/* VCCV */
X		if (!isweird(c1, c2, beg)) {
X			if (!((p = vccv_except[(int) c1 - 'a'])
X			      && strchr(p, (int) c2)))
X				HYPHENATE(*cp);
X		}
X	}
X  }
X
X  UNHYPHENATE(*end);
X}
X
Xint hyphen(beg, end)
Xchar *beg, *end;
X{
X
X  register char *prefixp, *suffixp;
X  int c;
X
X  if (end - beg <= 4) return 0;
X
X  for (prefixp = beg; prefixp <= end; prefixp++) {
X	if (HAS_HYPHEN(*prefixp)) return 1;
X
X	if (!islower(*prefixp)) return 0;
X  }
X
X  if (exception(beg, end)) return 1;
X
X  suffixp = suffix(beg, end);	/* Trenne und entferne alle     */
X  /* Endungen (Suffixe)           */
X  if (suffixp == end) {
X	c = *end & 0x7f;
X
X	if (c == 's' || c == 'e') suffixp = end - 1;
X
X	else if ((*(end - 1) & 0x7f) == 'e' && c == 'd')
X		suffixp = end - 2;
X  }
X  prefixp = prefix(beg, suffixp);	/* Trenne und entferne alle */
X  /* Vorsilben (Prafixe)      */
X
X  if ((suffixp - prefixp) >= 3) {
X	/* Die Anwendung der Konsonantenpaar-Regel findet nur auf
X	 * Worter mit mindestens 4 Buchsten statt (nachdem Vor- und
X	 * Nachsilben entfernt wurden) */
X
X	consonants(prefixp, suffixp);
X  }
X  return 1;
X}
Xint next(cur_state, cur_char)
Xchar cur_char;
Xint cur_state;
X{
X  char *p = States[cur_state];
X  int rval, i, c;
X
X  c = cur_char & 0x7f;
X
X
X  if (!*p)
X	rval = (int) (p[(c - 'a') + 1]);
X  else {
X	for (rval = 0, i = *p++; --i >= 0; p += 2)
X		if (c == p[0]) {
X			rval = p[1];
X			break;
X		}
X  }
X
X
X  return(rval);
X}
X
X#define S(x)  char x[]
X
XS(s0) =
X{0,84,84,84,1,1,84,84,84,84,84,84,84,84,84,84,84,84,84,1,84,84,84,84,84,84,84};
X
XS(s1) = {0,0,0,2,0,7,0,21,0,0,0,0,23,0,30,0,0,0,33,38,45,0,0,0,0,49,0};
XS(s2) ={  1, 'i', 3};
XS(s3) ={  1, 'p', 4};
XS(s4) ={  1, 'o', 5};
XS(s5) ={  1, 'c', 6};
XS(s6) ={  1, 's', 87};
XS(s7) ={0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,4,0,10,0,16,0,15,0,0,0,19};
XS(s8) ={  1, 'b', 9};
XS(s9) ={  1, 'a', 55};
XS(s10) ={  2, 'e', 11, 'u', 14};
XS(s11) ={  1, 'h', 12};
XS(s12) ={  1, 'p', 6};
XS(s13) ={  2, 'n', 81, 'r', 81};
XS(s14) ={  1, 't', 87};
XS(s15) ={  1, 'i', 14};
XS(s16) ={  1, 'a', 17};
XS(s17) ={  2, 'c', 18, 'l', 18};
XS(s18) ={0,88,0,0,0,88,0,0,0,88,0,0,0,0,0,88,0,0,0,0,0,88,0,0,0,88,0};
XS(s19) ={  1, 'i', 20};
XS(s20) ={  1, 'l', 80};
XS(s21) ={  1, 'n', 22};
XS(s22) ={  1, 'i', 86};
XS(s23) ={  2, 'a', 25, 'u', 24};
XS(s24) ={  1, 'f', 83};
XS(s25) ={0,0,0,87,0,0,0,0,0,26,0,0,0,0,27,0,0,0,0,0,87,0,0,0,0,0,0};
XS(s26) ={  2, 't', 87, 'c', 87};
XS(s27) ={  1, 'o', 28};
XS(s28) ={  1, 'i', 29};
XS(s29) ={  1, 't', 89};
XS(s30) ={  1, 'o', 31};
XS(s31) ={  1, 'i', 32};
XS(s32) ={  2, 't', 87, 'c', 6};
XS(s33) ={  1, 'e', 34};
XS(s34) ={  1, 'h', 35};
XS(s35) ={  1, 'p', 36};
XS(s36) ={  1, 'a', 37};
XS(s37) ={  1, 'r', 87};
XS(s38) ={  2, 's', 39, 'u', 41};
XS(s39) ={  1, 'e', 40};
XS(s40) ={  2, 'l', 83, 'n', 83};
XS(s41) ={  1, 'o', 42};
XS(s42) ={  1, 'i', 43};
XS(s43) ={  1, 'c', 44};
XS(s44)={0,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,87,
X							88,88,88,88,88,88,88};
XS(s45) ={  1, 'n', 46};
XS(s46) ={  1, 'e', 47};
XS(s47)={0,0,0,0,87,0,0,0,0,48,0,0,0,83,0,0,0,0,0,0,0,0,0,0,0,0,0};
XS(s48) ={  1, 'c', 87};
XS(s49)={0,0,0,0,0,0,0,50,35,0,0,0,83,0,0,0,0,0,51,0,0,0,0,0,0,0,0};
XS(s50) ={  1, 'o', 87};
XS(s51) ={  1, 'a', 52};
XS(s52) ={  1, 'n', 53};
XS(s53)={0,88,88,88,88,81,88,88,88,88,88,88,88,88,88,54,88,88,
X						88,88,88,88,88,88,88,88,88};
XS(s54) ={  1, 'i', 82};
XS(s55)={0,0,0,0,0,80,0,0,80,80,0,80,80,0,0,80,0,0,0,0,13,80,80,80,80,80,0};
X
X
Xchar *Suffixes[] =
X{
X s0, s1, s2, s3, s4, s5, s6, s7, s8, s9,
X s10, s11, s12, s13, s14, s15, s16, s17, s18, s19,
X s20, s21, s22, s23, s24, s25, s26, s27, s28, s29,
X s30, s31, s32, s33, s34, s35, s36, s37, s38, s39,
X s40, s41, s42, s43, s44, s45, s46, s47, s48, s49,
X s50, s51, s52, s53, s54, s55
X};
XS(p0) =
X{
X  1, 0, 0
X};
X
XS(p1) =
X{
X  0, 0, 2, 4, 6, 9, 0, 0, 13, 22, 0, 0, 26, 29, 39, 41, 45, 50, 0, 53, 57, 64,
X	0, 0, 0, 0, 0
X};
X
XS(p2) =
X{
X  1, 'e', 3
X};
X
XS(p3) =
X{
X  0, 0, 0, 81, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 81, 0, 0, 0
X};
X
XS(p4) =
X{
X  1, 'o', 5
X};
X
XS(p5) =
X{
X  2, 'm', 87, 'n', 87
X};
X
XS(p6) =
X{
X  1, 'i', 7
X};
X
XS(p7) =
X{
X  1, 's', 8
X};
X
XS(p8) =
X{
X  0, 85, 85, 85, 85, 85, 85, 85, 0, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
X	85, 85, 85, 85, 0, 85
X};
X
XS(p9) =
X{
X  2, 'q', 10, 'x', 87
X};
X
XS(p10) =
X{
X  1, 'u', 11
X};
X
XS(p11) =
X{
X  1, 'i', 12
X};
X
XS(p12) =
X{
X  0, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
X	81, 0, 81, 81, 81, 81
X};
X
XS(p13) =
X{
X  0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0
X};
X
XS(p14) =
X{
X  1, 'n', 15
X};
X
XS(p15) =
X{
X  1, 'd', 87
X};
X
XS(p16) =
X{
X  1, 'r', 17
X};
X
XS(p17) =
X{
X  1, 's', 18
X};
X
XS(p18) =
X{
X  1, 'e', 87
X};
X
XS(p19) =
X{
X  1, 'p', 20
X};
X
XS(p20) =
X{
X  1, 'e', 21
X};
X
XS(p21) =
X{
X  1, 'r', 84
X};
X
XS(p22) =
X{
X  2, 'n', 69, 'm', 86
X};
X
XS(p23) =
X{
X  0, 81, 0, 0, 0, 0, 81, 81, 0, 0, 0, 0, 81, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
X};
X
XS(p24) =
X{
X  2, 'e', 21, 'r', 25
X};
X
XS(p25) =
X{
X  1, 'o', 87
X};
X
XS(p26) =
X{
X  1, 'e', 27
X};
X
XS(p27) =
X{
X  1, 'x', 35
X};
X
XS(p28) =
X{
X  1, 'i', 87
X};
X
XS(p29) =
X{
X  0, 30, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0
X};
X
XS(p30) =
X{
X  0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 35, 0, 0
X};
X
XS(p31) =
X{
X  1, 'r', 32
X};
X
XS(p32) =
X{
X  1, 'o', 83
X};
X
XS(p33) =
X{
X  1, 'h', 34
X};
X
XS(p34) =
X{
X  1, 'e', 82
X};
X
XS(p35) =
X{
X  1, 'i', 82
X};
X
XS(p36) =
X{
X  1, 'n', 35
X};
X
XS(p37) =
X{
X  1, 'l', 38
X};
X
XS(p38) =
X{
X  1, 't', 65
X};
X
XS(p39) =
X{
X  1, 'o', 40
X};
X
XS(p40) =
X{
X  1, 'n', 86
X};
X
XS(p41) =
X{
X  2, 'u', 42, 'v', 43
X};
X
XS(p42) =
X{
X  1, 't', 87
X};
X
XS(p43) =
X{
X  1, 'e', 44
X};
X
XS(p44) =
X{
X  1, 'r', 86
X};
X
XS(p45) =
X{
X  1, 's', 46
X};
X
XS(p46) =
X{
X  1, 'e', 47
X};
X
XS(p47) =
X{
X  1, 'u', 48
X};
X
XS(p48) =
X{
X  1, 'd', 49
X};
X
XS(p49) =
X{
X  1, 'o', 83
X};
X
XS(p50) =
X{
X  1, 'u', 51
X};
X
XS(p51) =
X{
X  1, 'a', 52
X};
X
XS(p52) =
X{
X  1, 'd', 87
X};
X
XS(p53) =
X{
X  0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0
X};
X
XS(p54) =
X{
X  1, 'm', 28
X};
X
XS(p55) =
X{
X  1, 'm', 18
X};
X
XS(p56) =
X{
X  2, 'b', 87, 'p', 20
X};
X
XS(p57) =
X{
X  2, 'h', 58, 'r', 61
X};
X
XS(p58) =
X{
X  1, 'e', 59
X};
X
XS(p59) =
X{
X  1, 'r', 60
X};
X
XS(p60) =
X{
X  1, 'e', 87
X};
X
XS(p61) =
X{
X  2, 'a', 62, 'i', 68
X};
X
XS(p62) =
X{
X  1, 'n', 63
X};
X
XS(p63) =
X{
X  1, 's', 23
X};
X
XS(p64) =
X{
X  1, 'n', 66
X};
X
XS(p65) =
X{
X  1, 'i', 83
X};
X
XS(p66) =
X{
X  0, 85, 85, 85, 70, 85, 85, 85, 85, 0, 85, 85, 85, 85, 85, 85, 85, 85, 85,
X	85, 85, 85, 85, 85, 85, 85, 85
X};
X
XS(p67) =
X{
X  1, 'r', 87
X};
X
XS(p68) =
X{
X  0, 81, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0
X};
X
XS(p69) =
X{
X  0, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
X	85, 24, 85, 85, 85, 85, 85, 85
X};
X
XS(p70) =
X{
X  1, 'e', 67
X};
X
Xchar *Prefixes[] =
X{
X p0, p1, p2, p3, p4, p5, p6, p7, p8, p9,
X p10, p11, p12, p13, p14, p15, p16, p17, p18, p19,
X p20, p21, p22, p23, p24, p25, p26, p27, p28, p29,
X p30, p31, p32, p33, p34, p35, p36, p37, p38, p39,
X p40, p41, p42, p43, p44, p45, p46, p47, p48, p49,
X p50, p51, p52, p53, p54, p55, p56, p57, p58, p59,
X p60, p61, p62, p63, p64, p65, p66, p67, p68, p69,
X p70
X};
X
Xbool process_word(w)
Xchar *w;
X{
X  char word[80], *s = word;
X
X  hyphen(w, w + strlen(w) - 1);
X  strcpy(word, w);
X  while (*s) {
X	if (HAS_HYPHEN(*s)) {
X		*w++ = '\\';
X		*w++ = '%';
X	}
X	*w++ = UNHYPHENATE(*s++);
X  }
X  *w++ = '\0';
X  return TRUE;
X}
X
X
Xchar *Hyexcept[] =
X{
X "ab-sorb-ent", "ac-cept-able", "ac-ceptor",
X "ac-cord-ance", "ac-count-ant", "ac-know-ledge",
X "adapt-able", "adapt-er", "af-firm-ative",
X "al-go-rithm", "an-nouncer", "ant-acid",
X "ant-eater", "ant-hill", "an-tiq-uity",
X "any-thing", "apart-heid", "arch-an-gel",
X "arch-ery", "ar-mi-stice", "art-ist",
X "askance", "astig-ma-tism", "astir",
X "astonish-ment", "at-mos-phere", "bal-ding",
X "bar-on-ess", "beach-comber", "beck-on",
X "bes-tial", "be-tween", "bib-li-og-raphy",
X "bind-ery", "bi-no-mial", "blast-off",
X "board-er", "bomb-er", "bouncer",
X "bound-ary", "buff-er", "bull-ish",
X "buzz-er", "by-stand-er", "candle-stick",
X "carb-on", "cast-away", "cast-off",
X "cat-ion", "cav-ern-ous", "cen-ter",
X "change-over", "child-ish", "chordal",
X "civ-i-lize", "class-ify", "class-room",
X "climb-er", "clinch-er",
X "coars-en", "cognac",
X "cole-slaw", "com-a-tose", "com-bat-ive",
X "come-back", "co-me-dian", "com-men-da-tory",
X "comp-troller", "com-put-abil-ity", "con-de-scend",
X "cone-flower", "con-form-ity", "con-sult-ant",
X "con-test-ant", "con-trol-lable", "co-nun-drum",
X "con-vert-ible", "co-star", "count-ess",
X "court-house", "court-yard", "cre-scendo",
X "crest-fallen", "cross-over", "crypt-analysis",
X "crys-tal-lize", "curl-i-cue", "damp-en",
X "damp-est", "dar-ling", "debt-or",
X "dec-la-ra-tion", "de-cre-scendo", "de-duct-ible",
X "de-form-ity", "de-gree", "de-pend-able",
X "de-pend-ent", "de-scend-ent", "de-scent",
X "de-test-able", "di-gest-ible", "dis-cern-ible",
X "dis-miss-al", "dis-till-ery", "dump-ling",
X "earth-en-ware", "east-ern", "egg-head",
X "egg-nog", "eld-est", "else-where",
X "eq-uable", "equipped", "err-ing",
X "es-tab-lish", "eu-logy", "eve-ning",
X "every-thing", "ex-ac-ti-tude", "ex-ist-ence",
X "ex-pend-able", "ex-press-ible", "fall-out",
X "false-hood", "far-thing", "fencer",
X "fiend-ish", "for-eign-er", "fore-short-en",
X "fore-stall", "found-ling", "gen-er-ator",
X "gold-en", "handle-bar", "hang-out",
X "hang-over", "hap-hazard", "ha-rangue",
X "hard-en", "hard-ened", "hard-est",
X "harp-ist", "haz-ard-ous", "heart-ache",
X "heart-ily", "hence-forth", "her-bal",
X "hogs-head", "hold-out", "hold-over",
X "hold-up",
X "idler", "im-mo-bi-lize",
X "im-pass-able", "im-per-turb-able", "inch-worm",
X "in-clem-ent", "in-con-test-able", "in-de-pend-ent",
X "in-di-gest-ible", "ineq-uity", "in-ex-acti-tude",
X "in-ex-haust-ible", "in-form-ant", "iniq-uity",
X "ink-blot", "ink-ling", "inn-keeper",
X "in-sa-tiable", "in-te-rior", "in-ter-rupt-ible",
X "ir-re-vers-ible", "jeop-ard-ize", "kib-itzer",
X "land-owner", "launch-er", "left-ist",
X "left-over", "less-en", "life-style",
X "lift-off", "lime-stone", "li-on-ess",
X "liq-uefy", "liq-uid", "liq-ui-date",
X "liq-ui-da-tion", "liq-uor", "live-stock",
X "lull-aby", "lunch-eon", "lus-cious",
X "main-spring", "mast-head", "me-ringue",
X "me-ta-bo-lize", "met-al", "mile-stone",
X "mince-meat", "min-is-ter", "min-is-try",
X "mo-bi-lize", "mod-ern-ize", "mo-nop-o-lize",
X "morgue", "needle-work", "neg-li-gible",
X "ne-go-tiable", "nerv-ous", "nest-ling",
X "non-con-form-ist", "none-the-less", "non-ex-ist-ent",
X "non-metal", "north-east", "north-ern",
X "nurse-maid", "nurs-ery", "ob-serv-able",
X "ob-server", "off-beat", "off-hand",
X "off-print", "off-shoot", "off-shore",
X "off-spring", "orange-ade", "out-land-ish",
X "pal-ate", "pass-able", "ped-a-gogy",
X "pent-house", "per-cent-age", "pe-ri-odic",
X "per-sist-ent", "pet-al", "pho-to-stat",
X "play-thing", "pleb-i-scite", "plumb-er",
X "poly-no-mial", "port-hole", "post-al",
X "post-hu-mous", "pre-dict-able", "pre-req-ui-site",
X "pre-school", "pre-serv-ative", "pre-vious",
X "priest-hood", "prob-abil-ity", "prob-able",
X "pro-ce-dure", "pro-gram", "pro-gram-mer",
X "pro-grams", "psalm-ist", "pub-li-ca-tion",
X "pub-lish", "qua-drille", "ranch-er",
X "rattle-snake", "re-corder", "re-hears-al",
X "rent-al", "re-place-ment", "rep-re-sentative",
X "req-ui-si-tion", "re-scind", "re-search-er",
X "re-solv-able", "re-spect-able", "re-start-ed",
X "re-state-ment", "re-store", "re-vers-ible",
X "re-volv-er", "roll-away", "round-about",
X "sap-ling", "sea-scape", "self-ish",
X "sell-out", "send-off", "sense-less",
X "serv-er", "serv-ice-able", "sharpen",
X "shoe-string", "short-en", "shy-ster",
X "sib-ling", "side-step", "side-swipe",
X "si-lencer",
X "smoke-stack",
X "snake-skin", "so-ciable", "soft-hearted",
X "solv-able", "som-er-sault", "some-thing",
X "sta-bi-lize", "stand-ard-ize", "stand-out",
X "star-ling", "stat-ure", "ster-ling",
X "stew-ard-ess", "stiff-en", "sub-se-quence",
X "sug-gest-ible", "su-pe-rior", "surf-er",
X "tan-ta-lize", "thermo-stat", "tongue",
X "torque", "toss-up", "trench-ant",
X "turn-about", "turn-over", "turn-table",
X "ubiq-ui-tous", "una-nim-ity", "u-nan-i-mous",
X "un-civ-i-lized", "un-class-ified", "un-con-trollable",
X "unc-tuous", "un-der-stand-able", "un-err-ing",
X "un-gov-ern-able", "un-pre-dict-able", "un-search-able",
X "un-so-ciable", "un-solv-able", "up-swing",
X "venge-ance", "vict-ual", "vignette",
X "volt-age", "wall-eye", "waste-bas-ket",
X "waste-land", "watt-meter", "weak-ling",
X "west-ern-ize", "when-ever", "whisk-er",
X "wors-en", "yard-age", "year-ling"
X};
X
X#define TABSIZE ( sizeof( Hyexcept ) / sizeof(char *) )
X
Xint wcmp(word2, tabp1)
X_CONST void *word2;
X_CONST void *tabp1;
X{
X  /* Zur Behandlung des Plurals modifiziert am 17.7.87. Die Funktion
X   * liefert TRUE, falls das Wort passt, jedoch auf ein s oder es endet. */
X
X  char *word = (char *) word2;
X  char **tabp = (char **) tabp1;
X  register char *p = *tabp;
X
X  while (*word && *p) {
X	if (*p == '-') p++;
X
X	if (*word != *p) break;
X
X	word++;
X	p++;
X  }
X
X  if (!*p && (word[0] == 's' ||
X	    (word[0] == 'e' && word[1] == 's')))
X	return 0;
X
X  return(*word - *p);
X}
X
Xint exception(word, end)
Xchar *word, *end;
X{
X  /* Durchsucht die Ausnahmeliste und liefert einen Zeiger auf den
X   * Eintrag, falls es einen gibt, Null, falls nicht. */
X
X  char **pp, *p;
X  char oend;
X  int rval = 0;
X
X  oend = *++end;
X  *end = 0;
X
X  pp = (char **) bsearch(word, Hyexcept, TABSIZE, sizeof(char *),  wcmp);
X
X  if (pp) {
X	for (p = *pp; *p; word++, p++) {
X		if (*p == '-') {
X			HYPHENATE(*word);
X			p++;
X		}
X	}
X
X	rval = 1;
X  }
X  *end = oend;
X  return rval;
X}
X
Xchar linebuf[512], *s;
Xbool font4 = FALSE, only_font4 = FALSE, usage = FALSE;
X
X#define INT_ARG 0
X#define BOOL_ARG 1
X#define CHAR_ARG 2
X#define STRING_ARG 3
X
Xchar *setarg( argp, linep ) ARG *argp; char *linep;
X/* set an argument.  argp points to the entry in the argument table, which
X * fits to *linep.  returns linep which points after the processed argument.
X */
X{
X  char *not_s;			/* too many variables named s, s1, ... */
X
X  ++linep;
X
X  switch( argp->type )
X  {
X    case INT_ARG:
X	*(int*)argp->variable=atoi(linep);
X	while (*linep) linep++;
X	break;
X
X    case BOOL_ARG: 
X	*(int*)argp->variable = 1; break;
X
X    case CHAR_ARG: 
X	 *(char*)argp->variable = *linep++; break;
X
X    case STRING_ARG:
X	not_s = (char*) argp->variable;
X	while (*linep) *not_s++ = *linep++;
X	*not_s='\0';
X	break;
X  }
X  return(linep);
X}
X
XARG *findarg(c, tabp, tabsize) 
Xchar c; ARG *tabp; 
Xint tabsize;
X{
X  for (; --tabsize >= 0 ; tabp++ )
X  if (tabp->arg == c ) return tabp;
X
X  return NULL;
X}
X
Xint argparse(argc,argv,tabp,tabsize)
Xint argc; char **argv; 
XARG *tabp; 
Xint tabsize;
X{
X  int nargc;
X  char **nargv, *p;
X  ARG   *argp;
X
X  nargc = 1 ;
X  for(nargv = ++argv ; --argc > 0 ; argv++ )
X  {
X    if (**argv=='-' && (argp = findarg(*(p=argv[0]+1), tabp, tabsize)))
X      do 
X        if (*(p=setarg(argp,p))) argp=findarg(*p,tabp,tabsize);
X      while (*p);
X    else
X    {
X      *nargv++ = *argv ;
X      nargc++;
X    }
X  }
X  return nargc ;
X}
X
X
Xvoid fail(word)
Xchar *word;
X{
X  fprintf(stderr, "Can't process '%s'\nLine: %s\n", word, linebuf);
X}
X
Xchar transbuf[512], *t = transbuf;
X
Xvoid outtext(c)
Xchar c;
X{
X  *t++ = c;
X}
X
Xvoid outspec(c)
Xchar c;
X{
X  if (t != transbuf) {
X	*t++ = '\0';
X	if (only_font4 && !font4)
X		printf("%s", transbuf);
X	else if (process_word(transbuf))
X		printf("%s", transbuf);
X	t = transbuf;
X  }
X  putchar(c);
X}
X
Xint nextchar()
X{
X  if (*s == '\0') return 0;
X  s++;
X  return 1;
X}
X
X/* I don't echo the backslash, because special did it when it failed to match
X   the special rule.  Not the best way, but who cares.
X*/
Xint escapeseq()
X{
X  if (*s != '\\') return 0;
X  nextchar();
X  switch (*s) {
X      case '*':
X      case 'n':
X	{
X		outspec(*s);
X		nextchar();
X		if (*s == '(') {
X			outspec('(');
X			nextchar();
X			outspec(*s);
X			nextchar();
X		}
X		outspec(*s);
X		nextchar();
X		break;
X	}
X      default:
X	outspec(*s);
X	nextchar();
X  }
X  return 1;
X}
X
Xvoid nonletter()
X{
X  if (!escapeseq()) {
X	outspec(*s);
X	nextchar();
X  }
X}
X
X/* This rule is context-sensitive, because not all special characters are
X * accepted as a letter, see the return codes.
X */
Xint special()
X{
X  char *olds;
X
X  if (*s != '\\') return 0;
X  olds = s;
X  nextchar();
X  switch (*s) {
X      case '%':
X	outspec('\\');
X	outspec('%');
X	nextchar();
X	return 1;
X      case 'z':
X	outspec('\\');
X	outspec('z');
X	nextchar();
X	return 1;
X      case 'f':			/* font ::= 'f' anychar */
X	{
X		outspec('\\');
X		outspec('f');
X		nextchar();
X		font4 = (*s == '4');
X		outspec(*s);
X		nextchar();
X		return 1;
X	}
X
X      case 's':			/* size ::= [ '+' | '-' ] { digit } */
X	{
X		outspec('\\');
X		outspec('s');
X		nextchar();
X		if (*s == '-' || *s == '+') nextchar();
X		while (*s >= '0' && *s <= '9') nextchar();
X		return 1;
X	}
X
X      case '(':
X	{
X		outspec('\\');
X		outspec('(');
X		nextchar();
X		outspec(*s);
X		nextchar();
X		return 2;
X	}
X
X      default:
X	outspec('\\');
X	s = olds;
X	return 0;
X  }
X}
X
Xint letter()
X{
X  int x;
X
X  x = special();
X  if (x) return 1;
X  if (x == 0)
X	if ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z')) {
X		outtext(*s);
X		nextchar();
X		return 1;
X	}
X  return 0;
X}
X
Xvoid word1()
X{
X  if (letter()) {
X	while (letter());
X  }
X}
X
Xvoid words()
X{
X  while (*s) {
X	word1();
X	if (*s) nonletter();
X  }
X}
X
X/* Arguments not implemented yet */
Xint macro()
X{
X  if (*s == '.') {
X	printf("%s", s);
X	return 1;
X  } else
X	return 0;
X}
X
Xvoid line()
X{
X  if (!macro()) words();
X}
X
Xvoid text(fd)
XFILE *fd;
X{
X  int l;
X
X  while (fgets(linebuf, sizeof(linebuf), fd)) {
X	if ((l = strlen(linebuf)) != 0) linebuf[l - 1] = '\0';
X	s = linebuf;
X	line();
X	outspec('\n');
X  }
X}
X
X#define argnum 2
X
XARG argtab[argnum] =
X{
X '?', BOOL_ARG, (void *) &usage,
X '4', BOOL_ARG, (void *) &only_font4
X};
X
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  FILE *in;
X
X  argc = argparse(argc, argv, argtab, argnum);
X  if (usage) {
X	fprintf(stderr, "Usage: %s {-4} {file}\n", argv[0]);
X	exit(0);
X  }
X  if (argc == 2) {
X	if ((in = fopen(argv[1], "r")) == NULL) {
X		fprintf(stderr, "%s: unvalid argument\n", argv[0]);
X		exit(1);
X	}
X  } else
X	in = stdin;
X  text(in);
X  if (in != stdin) fclose(in);
X  return 0;
X}
/
echo x - join.c
sed '/^X/s///' > join.c << '/'
X/* join - relation data base operator	Author:  Saeko Hirabayashi */
X
X/* Written by Saeko Hirabayashi, 1989.
X * 1992-01-28 Modified by Kouichi Hirabayashi to add some POSIX1003.2 options.
X *
X * This a free program.
X */
X
X#include <string.h>
X#include <stdio.h>
X
X#define MAXFLD	200		/* maximum # of fields to accept */
X
X_PROTOTYPE(long ftell, (FILE * fp));
X_PROTOTYPE(void main, (int argc, char **argv));
X_PROTOTYPE(void error, (char *s, char *t));
X_PROTOTYPE(void usage, (void));
X_PROTOTYPE(void match, (void));
X_PROTOTYPE(void f1_only, (void));
X_PROTOTYPE(void f2_only, (void));
X_PROTOTYPE(void output, (int flag));
X_PROTOTYPE(void outfld, (int file));
X_PROTOTYPE(void outputf, (int flag));
X_PROTOTYPE(int compare, (void));
X_PROTOTYPE(int get1, (void));
X_PROTOTYPE(int get2, (int back));
X_PROTOTYPE(int getrec, (int file));
X_PROTOTYPE(int split, (int file));
X_PROTOTYPE(int atoi, (char *str));
X_PROTOTYPE(int exit, (int val));
X_PROTOTYPE(FILE * efopen, (char *file, char *mode));
X_PROTOTYPE(void (*outfun), (int file));	/* output func: output() or outputf()*/
X
X#define F1	1
X#define F2	2
X#define SEP	(sep ? sep : ' ')
X
XFILE *fp[2];			/* file pointer for file1 and file2 */
Xlong head;			/* head of the current (same)key group of the
X				 * file2 */
X
Xchar buf[2][BUFSIZ];		/* input buffer for file1 and file2 */
Xchar *fld[2][MAXFLD];		/* field vector for file1 and file2 */
Xint nfld[2];			/* # of fields for file1 and file2 */
X
Xint kpos[2];			/* key field position for file1 and file2
X				 * (from 0) */
Xchar oldkey[BUFSIZ];		/* previous key of the file1 */
X
Xstruct {			/* output list by -o option */
X  int o_file;			/* file #: 0 or 1 */
X  int o_field;			/* field #: 0, 1, 2, .. */
X} olist[MAXFLD];
Xint nout;			/* # of output filed */
X
Xint aflag;			/* n for '-an': F1 or F2 or both */
Xint vflag;			/* n for '-vn': F1 or F2 or both */
Xchar *es;			/* s for '-e s' */
Xchar sep;			/* c for -tc: filed separator */
Xchar *cmd;			/* name of this program */
X
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
X  register char *s;
X  int c, i, j;
X
X  cmd = argv[0];
X  outfun = output;		/* default output form */
X
X  while (--argc > 0 && (*++argv)[0] == '-' && (*argv)[1]) {
X	/* "-" is a file name (stdin) */
X	s = argv[0] + 1;
X	if ((c = *s) == '-' && !s[1]) {
X		++argv;
X		--argc;
X		break;		/* -- */
X	}
X	if (*++s == '\0') {
X		s = *++argv;
X		--argc;
X	}
X	switch (c) {
X	    case 'a':		/* add unpairable line to output */
X		vflag = 0;
X		switch (*s) {
X		    case '1':	aflag |= F1;	break;
X		    case '2':	aflag |= F2;	break;
X		    default:	aflag |= (F1 | F2);	break;
X		}
X		break;
X
X	    case 'e':		/* replace empty field by es */
X		es = s;
X		break;
X
X	    case 'j':		/* key field (obsolute) */
X		c = *s++;
X		if (*s == '\0') {
X			s = *++argv;
X			--argc;
X		}
X
X	    case '1':		/* key field of file1 */
X	    case '2':		/* key field of file2 */
X		i = atoi(s) - 1;
X
X		switch (c) {
X		    case '1':	kpos[0] = i;	break;
X		    case '2':	kpos[1] = i;	break;
X	            default:	kpos[0] = kpos[1] = i;
X				break;
X		}
X		break;
X
X	    case 'o':		/* specify output format */
X		do {
X			i = j = 0;
X			sscanf(s, "%d.%d", &i, &j);
X			if (i < 1 || j < 1 || i > 2) usage();
X			olist[nout].o_file = i - 1;
X			olist[nout].o_field = j - 1;
X			nout++;
X			if ((s = strchr(s, ',')) != (char *) 0)
X				s++;
X			else {
X				s = *++argv;
X				--argc;
X			}
X		} while (argc > 2 && *s != '-');
X		++argc;
X		--argv;		/* compensation */
X		outfun = outputf;
X		break;
X
X	    case 't':		/* tab char */
X		sep = *s;
X		break;
X
X	    case 'v':		/* output unpairable line only */
X		aflag = 0;
X		switch (*s) {
X		    case '1':	vflag |= F1;	break;
X		    case '2':	vflag |= F2;	break;
X		    default:	vflag |= (F1 | F2);	break;
X		}
X		break;
X
X	    default:	usage();
X	}
X  }
X  if (argc != 2) usage();
X
X  fp[0] = strcmp(argv[0], "-") ? efopen(argv[0], "r") : stdin;
X  fp[1] = efopen(argv[1], "r");
X
X  nfld[0] = get1();		/* read file1 */
X  nfld[1] = get2(0);		/* read file2 */
X
X  while (nfld[0] || nfld[1]) {
X	if ((i = compare()) == 0)
X		match();
X	else if (i < 0)
X		f1_only();
X	else
X		f2_only();
X  }
X  fflush(stdout);
X
X  exit(0);
X}
X
Xvoid usage()
X{
X  fprintf(stderr,
X    "Usage: %s [-an|-vn] [-e str] [-o list] [-tc] [-1 f] [-2 f] file1 file2\n",
X    cmd);
X  exit(1);
X}
X
Xint compare()
X{				/* compare key field */
X  register int r;
X
X  if (nfld[1] == 0)		/* file2 EOF */
X	r = -1;
X  else if (nfld[0] == 0)	/* file1 EOF */
X	r = 1;
X  else {
X	if (nfld[0] <= kpos[0])
X		error("missing key field in file1", (char *) 0);
X	if (nfld[1] <= kpos[1])
X		error("missing key field in file2", (char *) 0);
X
X	r = strcmp(fld[0][kpos[0]], fld[1][kpos[1]]);
X  }
X  return r;
X}
X
Xvoid match()
X{
X  long p;
X
X  if (!vflag) (*outfun) (F1 | F2);
X
X  p = ftell(fp[1]);
X  nfld[1] = get2(0);		/* check key order */
X  if (nfld[1] == 0 || strcmp(fld[0][kpos[0]], fld[1][kpos[1]])) {
X	nfld[0] = get1();
X	if (strcmp(fld[0][kpos[0]], oldkey) == 0) {
X		fseek(fp[1], head, 0);	/* re-do from head */
X		nfld[1] = get2(1);	/* don't check key order */
X	} else
X		head = p;	/* mark here */
X  }
X}
X
Xvoid f1_only()
X{
X  if ((aflag & F1) || (vflag & F1)) (*outfun) (F1);
X  nfld[0] = get1();
X}
X
Xvoid f2_only()
X{
X  if ((aflag & F2) || (vflag & F2)) (*outfun) (F2);
X  head = ftell(fp[1]);		/* mark */
X  nfld[1] = get2(0);		/* check key order */
X}
X
Xvoid output(f)
X{				/* default output form */
X  if (f & F1)
X	fputs(fld[0][kpos[0]], stdout);
X  else
X	fputs(fld[1][kpos[1]], stdout);
X  if (f & F1) outfld(0);
X  if (f & F2) outfld(1);
X  fputc('\n', stdout);
X}
X
Xvoid outfld(file)
X{				/* output all fields except key_field */
X  register int i;
X  int k, n;
X
X  k = kpos[file];
X  n = nfld[file];
X  for (i = 0; i < n; i++)
X	if (i != k) {
X		fputc(SEP, stdout);
X		fputs(fld[file][i], stdout);
X	}
X}
X
Xvoid outputf(f)
X{				/* output by '-o list' */
X  int i, j, k;
X  register char *s;
X
X  for (i = k = 0; i < nout; i++) {
X	j = olist[i].o_file;
X	if ((f & (j + 1)) && (olist[i].o_field < nfld[j]))
X		s = fld[j][olist[i].o_field];
X	else
X		s = es;
X	if (s) {
X		if (k++) fputc(SEP, stdout);
X		fputs(s, stdout);
X	}
X  }
X  fputc('\n', stdout);
X}
X
Xint get1()
X{				/* read file1 */
X  int r;
X  static char oldkey1[BUFSIZ];
X
X  strcpy(oldkey, fld[0][kpos[0]]);	/* save previous key for control */
X  r = getrec(0);
X
X  if (r && strcmp(oldkey1, fld[0][kpos[0]]) > 0)
X	error("file1 is not sorted", (char *) 0);
X  strcpy(oldkey1, fld[0][kpos[0]]);	/* save previous key for sort check */
X
X  return r;
X}
X
Xint get2(back)
X{				/* read file2 */
X  static char oldkey2[BUFSIZ];
X  int r;
X
X  r = getrec(1);
X
X  if (!back && r && strcmp(oldkey2, fld[1][kpos[1]]) > 0)
X	error("file2 is not sorted", (char *) 0);
X  strcpy(oldkey2, fld[1][kpos[1]]);	/* save previous key for sort check */
X
X  return r;
X}
X
Xint getrec(file)
X{				/* read one line to split it */
X  if (fgets(buf[file], BUFSIZ, fp[file]) == (char *) 0)
X	*buf[file] = '\0';
X  else if (*buf[file] == '\n' || *buf[file] == '\r')
X	error("null line in file%s", file ? "1" : "0");
X
X  return split(file);
X}
X
Xint split(file)
X{				/* setup fields */
X  register int n;
X  register char *s, *t;
X
X  for (n = 0, s = buf[file]; *s && *s != '\n' && *s != '\r';) {
X	if (sep) {
X		for (t = s; *s && *s != sep && *s != '\n' && *s != '\r'; s++);
X	} else {
X		while (*s == ' ' || *s == '\t')
X			s++;	/* skip leading white space */
X		for (t = s; *s && *s != ' ' && *s != '\t'
X		     && *s != '\n' && *s != '\r'; s++);
X		/* We will treat trailing white space as NULL field */
X	}
X	if (*s) *s++ = '\0';
X	fld[file][n++] = t;
X	if (n == MAXFLD) error("too many filed in file%s", file ? "1" : "0");
X  }
X  fld[file][n] = (char *) 0;
X
X  return n;
X}
X
XFILE *efopen(file, mode)
Xchar *file, *mode;
X{
X  FILE *fp;
X
X  if ((fp = fopen(file, mode)) == (FILE *) 0) error("can't open %s", file);
X
X  return fp;
X}
X
Xvoid error(s, t)
Xchar *s, *t;
X{
X  fprintf(stderr, "%s: ", cmd);
X  fprintf(stderr, s, t);
X  fprintf(stderr, "\n");
X
X  exit(1);
X}
/
echo x - life.c
sed '/^X/s///' > life.c << '/'
X
X/* life - Conway's game of life		Author: Jim King */
X
X/* clife.c - curses life simulator.  Translated from Pascal to C implementing
X *           curses Oct 1988 by pulsar@lsrhs, not jek5036@ritvax.isc.rit.edu
X *           life needs about 18kb stack space on MINIX.
X *
X * Flags:	-d  draw your own screen using arrows and space bar
X *		-p  print statistics on the bottom line during the game
X */
X
X#include <sys/types.h>
X#include <signal.h>
X#include <time.h>
X#include <curses.h>
X#include <stdlib.h>
X#include <sgtty.h>
X#include <unistd.h>
X#include <stdio.h>
X
X/* A value of -1 will make it go forever */
X/* A value of 0 will make it exit immediately */
X#define	REPSTOP		-1	/* number of repetitions before stop */
X
Xint present[23][80];		/* screen 1 cycle ago */
Xint past[23][80];		/* screen this cycle */
Xint total;			/* total # of changes */
Xint icnt;			/* counter to check for repetition */
Xint maxrow = 22;		/* some defines to represent the screen */
Xint maxcol = 79;
Xint minrow = 0;
Xint mincol = 0; 
Xint pri = 0;			/* flag for printing stats on bottom line */
Xint draw = 0;			/* flag for drawing your own screen */
Xint i, j, k;			/* loop counters */
Xint cycle;			/* current cycle # */
Xint changes;			/* # of changes this cycle (live + die) */
Xint die;			/* number of deaths this cycle */
Xint live;			/* number of births this cycle */
X
XWINDOW *mns;			/* Main Screen */
XWINDOW *info;			/* Bottom line */
X
Xstruct sgttyb old_tty, new_tty;
X
X_PROTOTYPE(void cleanup, (int s));
X_PROTOTYPE(void initialize, (void));
X_PROTOTYPE(void makscr, (void));
X_PROTOTYPE(void update, (void));
X_PROTOTYPE(void print, (void));
X_PROTOTYPE(int main, (int ac, char *av[]));
X
X/* Cleanup - cleanup then exit */
Xvoid cleanup(s)
Xint s;
X{
X  move(23, 0);			/* go to bottom of screen */
X  refresh();			/* update cursor */
X
X  endwin();			/* shutdown curses */
X  ioctl(0, TIOCSETP, &old_tty);	/* restore terminal parameters */
X  exit(1);			/* exit */
X}
X
X/* Initialize - init windows, variables, and signals */
X
Xvoid initialize()
X{
X
X  /* Save old terminal parameters. */
X  ioctl(0, TIOCGETP, &old_tty);
X
X  /* Set tty to CBREAK mode */
X  ioctl(0, TIOCGETP, &new_tty);
X  new_tty.sg_flags |= CBREAK;
X  new_tty.sg_flags &= ~ECHO;
X  ioctl(0, TIOCSETP, &new_tty);
X
X  srand(getpid());		/* init random seed */
X  initscr();			/* init curses */
X  noecho();
X  curs_set(0);
X  signal(SIGINT, cleanup);	/* catch ^C */
X  mns = newwin(maxrow, maxcol, 0, 0);	/* new window */
X  scrollok(mns, FALSE);
X  info = newwin(1, 80, 23, 0);
X  scrollok(info, FALSE);
X  wclear(mns);
X  wclear(info);
X  wmove(info, 0, 0);
X  wrefresh(info);
X  if (!draw) {			/* if no draw, make random pattern */
X	for (j = 0; j < maxrow; j++) {
X		for (k = 0; k < maxcol; k++) {
X			present[j][k] = rand() % 2;
X			if (present[j][k] == 1) changes++, live++;
X		}
X	}
X  }
X}
X
X/* Makscr - make your own screen using arrow keys and space bar */
Xvoid makscr()
X{
X  int curx, cury;		/* current point on screen */
X  char c;			/* input char */
X
X  wclear(info);
X  wmove(info, 0, 0);
X  wprintw(info, "Use arrow keys to move, space to place / erase, ^D to start", NULL);
X  wrefresh(info);
X  curx = cury = 1;
X  wmove(mns, cury - 1, curx - 1);
X  wrefresh(mns);
X  noecho();
X  for (;;) {
X	c = wgetch(mns);
X	if (c == '\004')
X		break;
X	else if (c == ' ') {
X		if (present[cury][curx]) {
X			--present[cury][curx];
X			changes++;
X			die++;
X			mvwaddch(mns, cury, curx, ' ');
X		} else {
X			++present[cury][curx];
X			changes++;
X			live++;
X			mvwaddch(mns, cury, curx, '*');
X		}
X	} else if (c == '\033') {
X		wgetch(mns);
X		switch (wgetch(mns)) {
X		    case 'A':	--cury;	break;
X		    case 'B':	++cury;	break;
X		    case 'C':	++curx;	break;
X		    case 'D':	--curx;	break;
X		    default:	break;
X		}
X	}
X	if (cury > maxrow) cury = minrow;
X	if (cury < minrow) cury = maxrow;
X	if (curx > maxcol) curx = mincol;
X	if (curx < mincol) curx = maxcol;
X	wmove(mns, cury, curx);
X	wrefresh(mns);
X  }
X  wclear(info);
X}
X
X/* Update rules:  2 or 3 adjacent alive --- stay alive
X *                3 adjacent alive -- dead to live
X *                all else die or stay dead
X */
Xvoid update()
X{				/* Does all mathmatical calculations */
X  int howmany, w, x, y, z;
X  changes = die = live = 0;
X  for (j = 0; j < maxrow; j++) {
X	for (k = 0; k < maxcol; k++) {
X		w = j - 1;
X		x = j + 1;
X		y = k - 1;
X		z = k + 1;
X
X		howmany = (past[w][y] + past[w][k] + past[w][z] +
X			   past[j][y] + past[j][z] + past[x][y] +
X			   past[x][k] + past[x][z]);
X
X		switch (howmany) {
X		    case 0:
X		    case 1:
X		    case 4:
X		    case 5:
X		    case 6:
X		    case 7:
X		    case 8:
X			present[j][k] = 0;
X			if (past[j][k]) changes++, die++;
X			break;
X		    case 3:
X			present[j][k] = 1;
X			if (!past[j][k]) changes++, live++;
X			break;
X		    default:	break;
X		}
X	}
X  }
X  if (live == die)
X	++icnt;
X  else
X	icnt = 0;
X
X  if (icnt == REPSTOP) cleanup(0);
X}
X
X/* Print - updates the screen according to changes from past to present */
Xvoid print()
X{	
X/* Updates the screen, greatly improved using curses */
X  if (pri) {
X	wmove(info, 0, 0);
X	total += changes;
X	cycle++;
X	wprintw(info, "Cycle %5d | %5d changes: %5d died + %5d born = %5u total changes", (char *) cycle, changes, die, live, total);
X	wclrtoeol(info);
X  }
X  for (j = 1; j < maxrow; j++) {
X	for (k = 1; k < maxcol; k++) {
X		if (present[j][k] != past[j][k] && present[j][k] == 1) {
X			wmove(mns, j, k);
X			wprintw(mns, "*", NULL);
X		} else if (present[j][k] != past[j][k] && present[j][k] == 0) {
X			wmove(mns, j, k);
X			wprintw(mns, " ", NULL);
X		}
X	}
X  }
X  if (pri) wrefresh(info);
X  wrefresh(mns);
X}
X
X/* Main - main procedure */
Xint main(ac, av)
Xint ac;
Xchar *av[];
X{
X  if (ac > 1) {
X	for (j = 1; j < ac; j++) {
X		switch (av[j][1]) {
X		    case 'd':	++draw;	break;
X		    case 'p':	++pri;	break;
X		    default:
X			fprintf(stderr, "%s: usage: %s [-d] [-p]\n", av[0], av[0]);
X			exit(1);
X		}
X	}
X  }
X
X  initialize();
X  if (draw) makscr();
X
X  for (;;) {
X	print();
X	for (j = 0; j < maxrow; j++) {
X		for (k = 0; k < maxcol; k++) past[j][k] = present[j][k];
X	}
X	update();
X  }
X}
/
echo x - men.c
sed '/^X/s///' > men.c << '/'
X/* men - menu system for MINIX		Author: Andy Tanenbaum */
X
X/* This is a simple menu system for MINIX.  By creating a .menu file and
X * putting men at the end of a users .profile, when the user logs in, a
X * menu appears.  The user can select items from the menu by typing short
X * commands.  The .menu file consists of lines, one per menu entry.
X * Each line has three parts, separated by semicolons.  The first is the
X * string to be typed to invoke the menu item.  The second is text to
X * appear on the screen.  The third is the command sequence to execute
X * when the item is selected.  The command sequence may need parameters,
X * so this program allows prompting for them.  At the place where a
X * parameter must be filled in, the menu writer should put %<prompt>%
X * where <prompt> tells the user what to fill in.  Many commands produce
X * some sort of output for the user to inspect (e.g. ls).  To allow this
X * output to remain on the screen until the user has read it, the special
X * action: # may be used.  This is a macro for: 
X *
X *	getlf "Hit RETURN to menu"
X *
X * Here is an example of the .menu file:
X *
X * ca:Calendar:cal %month% %year%;getlf "Hit RETURN to continue"
X * cp:Copy file:cp %source file% %destination file%
X * da:Date:date;sleep 3
X * du:Disk Usage:du %directory name%;getlf "Hit RETURN to continue"
X * e:ELLE:elle %file name%
X * f:Tell fortune:fortune;getlf "Hit RETURN to continue"
X * g:Grep:grep %pattern% %file(s)%;getlf "Hit RETURN to continue"
X * k:Kermit:kermit 
X * ls:List directory (short):ls -C;getlf "Hit RETURN to continue"
X * ll:List directory (long):ls -l;getlf "Hit RETURN to continue"
X * mi:Mined:mined %file name%
X * mk:Make file system:mkfs %special% %size or prototype name%
X * mor:Examine file:more %file name%
X * mou:Mount floppy:/etc/mount /dev/fd0 %directory to mount on%
X * mv:Rename a file:mv %old name% %new name%
X * p:Print current dir name:pwd;getlf Hit RETURN to continue"
X * rec:Recover lost file:recover %file name%
X * rm:Remove file:rm %file name(s)%
X * v:vi:/bin/vi
X * +:RPN calculator:ic
X * q:Exit menu system:exit
X * !:Temporary escape to shell:/bin/sh
X * 
X */
X
X#include <sys/types.h>
X#include <fcntl.h>
X#include <sgtty.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X#include <stdio.h>
X
X#define MAX_ITEMS 44		/* max items in all the visible menus */
X#define EXEC_BUF_SIZE 1024	/* max chars in an executable command */
X#define MAX_FILE_SIZE 5000	/* # bytes in the .menu file */
X#define PROMPT_SIZE 256		/* size of the prompt buffer */
X#define DEFAULT_FILE ".menu"	/* default file where menu is found */
X#define ENTRIES_PER_COL 11	/* each menu is limited to this many entries */
X#define LINE_SIZE 80		/* input buffer size */
X#define SCREEN_WIDTH 80		/* # columns in the screen */
X#define LINES 23		/* lines on the screen */
X#define SCREEN_SIZE (LINES * (SCREEN_WIDTH + 1))
X
X/* These items define the characters used for building frames around menus. */
X#define ULCORNER 201
X#define MIDDLE   205
X#define URCORNER 187
X#define LLCORNER 200
X#define LRCORNER 188
X#define SINGLE   179
X#define DOUBLE   186
X#define LMIDT    204
X#define RMIDT    185
X#define DOWN     209
X#define UP       207
X#define CROSS    216
X
Xstruct item {
X  char *code;			/* pointer to code symbol for invocation */
X  char *desc;			/* pointer to text describing menu item */
X  char *exec;			/* pointer to commands to execute */
X} item[MAX_ITEMS];
X
Xint nitems;			/* number of items in item table */
Xchar file_buf[MAX_FILE_SIZE+2];	/* buffer for holding .menu file */
Xchar screen[SCREEN_SIZE];	/* screen buffer image */
Xchar backspace = '\b';		/* backspace */
Xchar newline = '\n';		/* newline */
Xchar separator = ':';		/* menu items are separated by this char */
Xchar prompt = '%';		/* separator for prompts in commands */
Xchar ret = '#';			/* generates special message */
Xchar *clr_str = "\033[H\033[0J";	/* ANSI for clear the screen */
Xchar *ret_str = "getlf \"\n\nPlease hit RETURN to go back to the menu\"";
X
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(void read_file, (int argc, char *argv []));
X_PROTOTYPE(void build_item_table, (void));
X_PROTOTYPE(void legality_check, (void));
X_PROTOTYPE(void build_display, (void));
X_PROTOTYPE(void init_screen, (void));
X_PROTOTYPE(void build_col, (struct item *ip, int count, int offset, int wid1, int wid2));
X_PROTOTYPE(void draw, (void));
X_PROTOTYPE(void barfill, (char *s, int lt, int mid, int rt, int wid1, int wid2));
X_PROTOTYPE(void execute, (void));
X_PROTOTYPE(void expand, (char *menu, char *exec));
X_PROTOTYPE(void clr_screen, (void));
X_PROTOTYPE(void syntax_err, (char *s));
X_PROTOTYPE(void code_err, (struct item *ip, struct item *jp));
X
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X  read_file(argc, argv);	/* read in the menu file */
X  build_item_table();		/* extract info from menu file */
X  legality_check();		/* check for duplicates etc. */
X  build_display();
X
X  /* Display the menu and get a command to execute. */
X  while (1) {
X	draw();
X	execute();
X  }
X  return(0);
X}
X
Xvoid read_file(argc, argv)
Xint argc;
Xchar *argv[];
X{
X/* Read the menu file into screen. */
X
X  char *file_name;
X  int fd, n;
X
X  if (argc > 2) {
X	fprintf(stderr, "Usage: men [file]\n");
X	exit(1);
X  }
X
X  file_name = (argc == 2 ? argv[1] : DEFAULT_FILE);
X  fd = open(file_name, O_RDONLY);
X  if (fd < 0) {
X	fprintf(stderr, "Cannot open %s\n", file_name);
X	exit(1);
X  }
X
X  n = read(fd, file_buf, MAX_FILE_SIZE);
X  if (n == MAX_FILE_SIZE) {
X	fprintf(stderr, "%s is too large\n", file_name);
X	exit(1);
X  }
X
X  file_buf[n+1] = '\n';
X  file_buf[n+2] = '\0';
X}
X
Xvoid build_item_table()
X{
X/* Examine the menu file line by line and build struct item. */
X
X  char *p;
X  struct item *ip;
X
X  p = file_buf;
X  ip = &item[0];
X  nitems = 0;
X
X  while (*p != 0) {
X	/* Check for too many items. */
X	if (nitems > MAX_ITEMS) {
X		fprintf(stderr, "Too many items in the menu (%d)\n", nitems);
X		exit(1);
X	}
X
X	ip->code = p;		/* p points to the code for this item */
X
X	/* Search line for first separator.  It's absence is an error. */
X	while (*p != separator && *p != '\n') p++;
X	if (*p == '\n') syntax_err(ip->code);
X	*p++ = '\0';
X
X	/* Search line for second separator.  It's absence is also an error. */
X	ip->desc = p;		/* p points to the description for this item */
X	while (*p != separator && *p != '\n') p++;
X	if (*p == '\n') syntax_err(ip->code);
X	*p++ = '\0';
X	
X	/* Search line for line feed.  It cannot be absent (one was added). */
X	ip->exec = p;
X	while (*p != '\n') p++;
X	*p++ = '\0';
X
X	/* Move on to next item. */
X	ip++;
X	nitems++;
X  }
X}
X
Xvoid legality_check()
X{
X/* It is forbidden to repeat a code in the menu.  It is also forbidden to
X * have one code be the prefix of another code, i.e., you can't have a
X * code 'a' and a code 'am' because carriage returns are not used.  As soon
X * as you type 'a', the first item will be executed.
X */
X
X  size_t n1, n2;
X  int prompt_count;
X  char *p;
X  struct item *ip, *jp;
X
X  for (ip = &item[0]; ip < &item[nitems]; ip++) {
X	for (jp = ip + 1; jp < &item[nitems]; jp++) {
X		if (strcmp(ip->code, jp->code) == 0) code_err(ip, jp);
X		n1 = strlen(ip->code);
X		n2 = strlen(jp->code);
X		if (strncmp(ip->code, jp->code, n1) == 0) code_err(ip, jp);
X		if (strncmp(ip->code, jp->code, n2) == 0) code_err(ip, jp);
X	}
X
X	/* If the exec part uses %, they better be balanced. */
X	prompt_count = 0;
X	p = ip->exec;
X	while (*p != '\0') {
X		if (*p == prompt) prompt_count++;
X		p++;
X	}
X
X	/* Check to see that it is even. */
X	if (prompt_count & 01) {
X		fprintf(stderr,"Unbalanced %% ... %% in: %s\n",ip->exec);
X		exit(1);
X	}
X  }
X  	
X}
X	
X
Xvoid build_display()
X{
X/* The display is constructed in screen and written out in one blow. */
X
X  int wid1, wid2, wid3, cols, k, offset, left, count;
X  struct item *ip;
X
X  /* Determine how wide the columns must be. */
X  wid1 = 0;			/* code string column width */
X  wid2 = 0;			/* description column width */
X  for (ip = &item[0]; ip < &item[nitems]; ip++) {
X	if (strlen(ip->code) > wid1) wid1 = strlen(ip->code);
X	if (strlen(ip->desc) > wid2) wid2 = strlen(ip->desc);
X  }
X
X  /* Is there enough room on the screen? */
X  wid3 = wid1 + wid2 + 9;	/* allow for spaces around strings, etc. */
X  cols = (nitems + ENTRIES_PER_COL - 1)/ENTRIES_PER_COL;
X  if (cols * wid3 > SCREEN_WIDTH) {
X	fprintf(stderr, "Menus are too wide to fit %d of them on the screen\n",
X								cols);
X	exit(1);
X  }
X
X  /* There may be several menus next to each other.  Build them separately. */
X  k = 0;
X  offset = 0;			/* which column to display the menu in */
X  left = nitems;		/* how many items left to display */
X  init_screen();
X
X  while (left > 0) {
X	count = (left < ENTRIES_PER_COL ? left : ENTRIES_PER_COL);
X	build_col(&item[k], count, offset, wid1, wid2);
X	left -= count;
X	k += count;
X	offset += wid1 + wid2 + 9;
X  }
X}
X
Xvoid init_screen()
X{
X/* Clear the screen buffer */
X
X  char *p;
X
X  for (p = &screen[0]; p < &screen[SCREEN_SIZE]; p++) *p = ' ';
X  for (p = &screen[SCREEN_WIDTH]; p < &screen[SCREEN_SIZE]; p +=SCREEN_WIDTH+1)
X	*p = '\n';
X}
X
Xvoid build_col(ip, count, offset, wid1, wid2)
Xstruct item *ip;		/* pointer into item table */
Xint count;			/* number of items to display */
Xint offset;			/* column offset for this menu */
Xint wid1;			/* width of code string */
Xint wid2;			/* width of description screen */
X{
X/* Build one vertical menu in screen. */
X
X  int k;
X  char *s, *base;
X
X  /* Build top of menu. */
X  s = &screen[offset];
X  barfill(s, ULCORNER, DOWN, URCORNER, wid1, wid2);
X  base = s += SCREEN_WIDTH + 1;
X
X  for (k = 0; k < count; k++) {
X	/* Iterate on each line to be entered. */
X	s = base;
X	*s++ = DOUBLE;
X	*s++ = ' ';
X	strcpy(s, ip->code);
X	s = base + wid1 + 3;
X	*s = SINGLE;
X
X	strcpy(base + wid1 + 5, ip->desc);
X	s = base + wid1 + wid2 + 6;
X	*s = DOUBLE;
X
X	/* Draw the line under the entry.  Last one is different. */
X	s = base + SCREEN_WIDTH + 1;
X	if (k != count -1) {
X		barfill(s, LMIDT, CROSS, RMIDT, wid1, wid2);
X	} else {
X		barfill(s, LLCORNER, UP, LRCORNER, wid1, wid2);
X	}
X	base += 2 * SCREEN_WIDTH + 2;
X	ip++;
X  }
X}
X
Xvoid draw()
X{
X/* Draw the menu on the screen. */
X  char *p;
X
X  for (p = &screen[0]; p < &screen[SCREEN_SIZE]; p++)
X	if (*p == '\0') *p = ' ';
X
X  write(1, "\n", 1);
X  write(1, screen, SCREEN_SIZE);
X}
X
X
Xvoid barfill(s, lt, mid, rt, wid1, wid2)
Xchar *s;			/* where to start */
Xint lt;				/* symbol to use on left */
Xint mid;			/* symbol to use in middle */
Xint rt;				/* symbol to use on right */
Xint wid1;			/* col1 width */
Xint wid2;			/* col2 width */
X{
X/* Draw a bar of symbols. */
X
X  int i;
X
X  *s++ = lt;
X  for (i = 0; i < wid1 + 2; i++) *s++ = MIDDLE;
X  *s++ = mid;
X  for (i = 0; i < wid2 + 2; i++) *s++ = MIDDLE;
X  *s++ = rt;
X}
X
X  
Xvoid execute()
X{
X/* Get input and execute a command. */
X
X  struct sgttyb save, argp;
X  struct item *ip;
X  char c[LINE_SIZE], exec_buf[EXEC_BUF_SIZE], *cp;
X
X  /* Put terminal in cbreak mode. */
X  ioctl(fileno(stdin), TIOCGETP, &save);
X  argp = save;
X  argp.sg_flags |= CBREAK;
X
X  /* Read in characters */
X  cp = &c[0];
X  while (1) {
X	ioctl(fileno(stdin), TIOCSETP, &argp);
X	read(fileno(stdin), cp, 1);
X	ioctl(fileno(stdin), TIOCSETP, &save);
X	if (*cp == newline) {
X		cp = &c[0]; /* restart */
X		continue;
X	}
X	if (*cp == backspace && cp > c) {
X		cp--;
X		write(1, " \b", 2);
X		continue;
X	}	
X	*(cp+1) = 0;
X
X	/* Search for a match. */
X	for (ip = &item[0]; ip < &item[nitems]; ip++) {
X		if (strcmp(c, ip->code) == 0) {
X			/* Hit found. */
X			if (strcmp(ip->exec, "exit") == 0) {
X				clr_screen();
X				exit(0);
X			}
X			expand(ip->exec, exec_buf);
X			clr_screen();
X			system(exec_buf);
X			return;
X		}
X	}
X	cp++;
X  }
X}
X
X
Xvoid expand(menu, exec)
Xchar *menu;			/* pointer to exec part of menu item */
Xchar *exec;			/* pointer to exec buffer */
X{
X/* The exec part of the menu item may have parameters, delimited by %...%
X * with a prompt in between.  The command is copied to the exec buffer,
X * and the parameters prompted for and filled in.  The final executable
X * command is passed by in exec.
X */
X
X  register char *mp, *ep;
X  int n;
X  char prompt_buf[PROMPT_SIZE], *pb;
X
X  mp = menu;
X  ep = exec;
X  *ep = 0;
X
X  /* Loop need here.  One iteration per parameter prompted for. */
X  while (1) {
X	while (*mp != '\0' && *mp != prompt && *mp != ret) *ep++ = *mp++;
X	if (*mp == '\0') {
X		*ep = '\0';
X		return;
X	}
X
X	/* '#' is a macro for calling getlf. */
X	if (*mp == ret) {
X		pb = ret_str;
X		while (*pb != '\0') *ep++ = *pb++;
X		mp++;
X		continue;
X	}
X
X	/* Start of parameter prompt. Copy it to prompt_buf. */
X	mp++;
X	pb = &prompt_buf[0];
X	while (*mp != prompt) *pb++ = *mp++;
X	*pb = '\0';
X	mp++;
X	*ep = '\0';
X
X	/* Prompt the user for the parameter. */
X	clr_screen();
X
X	printf("Please enter:\n\n\t%s\n\nThen hit RETURN\n\n%s",
X							prompt_buf, exec);
X	fflush(stdout);
X
X	/* Get the reply. */
X	n = read(0, prompt_buf, PROMPT_SIZE);
X	prompt_buf[n-1] = '\0';
X	pb = &prompt_buf[0];
X	while (*pb != '\0') *ep++ = *pb++;
X  }		
X}
X
X
Xvoid clr_screen()
X{
X  /* Could use Termcap, but this is simpler and probably faster. */
X  write(1, clr_str, strlen(clr_str));
X}
X
Xvoid syntax_err(s)
Xchar *s;
X{
X  fprintf(stderr, "Syntax error in menu file in line:\n%s\n",s);
X  exit(1);
X}
X
Xvoid code_err(ip, jp)
Xstruct item *ip, *jp;
X{
X  fprintf(stderr, "The following lines have strings that conflict:\n");
X  fprintf(stderr, "%s;%s;%s\n",ip->code,ip->desc,ip->exec);
X  fprintf(stderr, "%s;%s;%s\n",jp->code,jp->desc,jp->exec);
X  exit(1);
X}
/
echo x - mkfifo.c
sed '/^X/s///' > mkfifo.c << '/'
X/* mkfifo - Make FIFO special files		Author: V. Archer */
X
X/* Copyright 1991 by Vincent Archer
X *	You may freely redistribute this software, in source or binary
X *	form, provided that you do not alter this copyright mention in any
X *	way.
X */
X
X#include <sys/types.h>
X#include <stdlib.h>
X#include <sys/stat.h>
X#include <string.h>
X#include <unistd.h>
X#include <minix/minlib.h>
X#include <stdio.h>
X
X#define USR_MODES (S_ISUID|S_IRWXU)
X#define GRP_MODES (S_ISGID|S_IRWXG)
X#define EXE_MODES (S_IXUSR|S_IXGRP|S_IXOTH)
X#ifdef S_ISVTX
X#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO|S_ISVTX)
X#else
X#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO)
X#endif
X#define DEFAULT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
X
X
X/* Global u_mask needed in changemode.h */
Xmode_t u_mask;
X
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(mode_t parsemode, (char *symbolic, Mode_t oldmode));
X_PROTOTYPE(void usage, (void));
X
X/* Parse a P1003.2 4.7.7-conformant symbolic mode. */
Xmode_t parsemode(symbolic, oldmode)
Xchar *symbolic;
Xmode_t oldmode;
X{
X  mode_t who, mask, newmode, tmpmask;
X  char action;
X
X  newmode = oldmode & ALL_MODES;
X  while (*symbolic) {
X	who = 0;
X	for (; *symbolic; symbolic++) {
X		if (*symbolic == 'a') {
X			who |= ALL_MODES;
X			continue;
X		}
X		if (*symbolic == 'u') {
X			who |= USR_MODES;
X			continue;
X		}
X		if (*symbolic == 'g') {
X			who |= GRP_MODES;
X			continue;
X		}
X		if (*symbolic == 'o') {
X			who |= S_IRWXO;
X			continue;
X		}
X		break;
X	}
X	if (!*symbolic || *symbolic == ',') usage();
X	while (*symbolic) {
X		if (*symbolic == ',') break;
X		switch (*symbolic) {
X		    default:
X			usage();
X		    case '+':
X		    case '-':
X		    case '=':	action = *symbolic++;
X		}
X		mask = 0;
X		for (; *symbolic; symbolic++) {
X			if (*symbolic == 'u') {
X				tmpmask = newmode & S_IRWXU;
X				mask |= tmpmask | (tmpmask << 3) | (tmpmask << 6);
X				symbolic++;
X				break;
X			}
X			if (*symbolic == 'g') {
X				tmpmask = newmode & S_IRWXG;
X				mask |= tmpmask | (tmpmask >> 3) | (tmpmask << 3);
X				symbolic++;
X				break;
X			}
X			if (*symbolic == 'o') {
X				tmpmask = newmode & S_IRWXO;
X				mask |= tmpmask | (tmpmask >> 3) | (tmpmask >> 6);
X				symbolic++;
X				break;
X			}
X			if (*symbolic == 'r') {
X				mask |= S_IRUSR | S_IRGRP | S_IROTH;
X				continue;
X			}
X			if (*symbolic == 'w') {
X				mask |= S_IWUSR | S_IWGRP | S_IWOTH;
X				continue;
X			}
X			if (*symbolic == 'x') {
X				mask |= EXE_MODES;
X				continue;
X			}
X			if (*symbolic == 's') {
X				mask |= S_ISUID | S_ISGID;
X				continue;
X			}
X			if (*symbolic == 'X') {
X				if (S_ISDIR(oldmode) || (oldmode & EXE_MODES))
X					mask |= EXE_MODES;
X				continue;
X			}
X#ifdef S_ISVTX
X			if (*symbolic == 't') {
X				mask |= S_ISVTX;
X				who |= S_ISVTX;
X				continue;
X			}
X#endif
X			break;
X		}
X		switch (action) {
X		    case '=':
X			if (who)
X				newmode &= ~who;
X			else
X				newmode = 0;
X		    case '+':
X			if (who)
X				newmode |= who & mask;
X			else
X				newmode |= mask & (~u_mask);
X			break;
X		    case '-':
X			if (who)
X				newmode &= ~(who & mask);
X			else
X				newmode &= ~mask | u_mask;
X		}
X	}
X	if (*symbolic) symbolic++;
X  }
X  return(newmode);
X}
X
X
X/* Main module. Since only one option (-m mode) is allowed, there's no need
X * to include the whole getopt() stuff.
X */
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int errors = 0;
X  char *symbolic;
X
X  if (argc > 2 && *argv[1] == '-' && strcmp(argv[1], "-m") != 0) usage();
X  argc--;
X  argv++;
X  if (argc && strncmp(*argv, "-m", (size_t) 2) == 0) {
X	argc--;
X	if ((argv[0])[2])
X		symbolic = (*argv++) + 2;
X	else {
X		if (!argc--) usage();
X		argv++;
X		symbolic = *argv++;
X	}
X	u_mask = umask(0);
X	umask(u_mask);
X  } else
X	symbolic = (char *) 0;
X
X  if (!argc) usage();
X  for (; argc--; argv++)
X	if (mkfifo(*argv, DEFAULT_MODE)) {
X		perror(*argv);
X		errors = 1;
X	} else if (symbolic && chmod(*argv, parsemode(symbolic, DEFAULT_MODE))) {
X		unlink(*argv);
X		perror(*argv);
X		errors = 1;
X	}
X  return(errors);
X}
X
X
X/* Posix command prototype. */
Xvoid usage()
X{
X  std_err("Usage: mkfifo [-m mode] file...\n");
X  exit(1);
X}
/
echo x - ncheck.c
sed '/^X/s///' > ncheck.c << '/'
X/* ncheck   name check			  Author:  Raymond Michiels */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <dirent.h>
X#include <string.h>
X#include <limits.h>
X#include <ctype.h>
X#include <errno.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <stdio.h>
X
Xino_t *ilist;
Xint iflag = 0, aflag = 0, sflag = 0, nr_inodes = 0, opt, skip_len;
Xchar *progname;
Xchar *filesystem = NULL;
Xchar *mnt_point = NULL;
Xchar path[PATH_MAX];
X
Xextern int optind;
Xextern char *optarg;
X
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(void usage, (void));
X_PROTOTYPE(void myexit, (int n));
X_PROTOTYPE(void readilist, (char *p));
X_PROTOTYPE(int inlist, (Ino_t inode));
X_PROTOTYPE(int dotfile, (char *fullname));
X_PROTOTYPE(int toprint, (struct stat *statbuf, char *name));
X_PROTOTYPE(void traverse, (char *dirname));
X
Xvoid myexit(n)		/* maybe I could use something like _cleanup() */
Xint n;
X{
X  if (filesystem != NULL)
X	umount(filesystem);
X  if (mnt_point != NULL)
X	rmdir(mnt_point);
X  exit(n);
X}
X
X
Xvoid usage()
X{
X  fprintf(stderr, "usage: %s [ -i numbers] [-s] [-a] file_system\n", progname);
X  myexit(1);
X}
X
X
Xvoid readilist(p)
Xchar *p;
X{
X  ilist = (ino_t *)malloc(strlen(p)/2+1);
X  if (ilist == NULL) {
X	fprintf(stderr, "couldn't malloc i-node list\n");
X	myexit(1);
X  }
X  do {
X	if (*p == ',') p++;	/* skip comma's */
X	if (!isdigit(*p)) {
X		fprintf(stderr, "malformed i-node list\n");
X		myexit(1);
X	}
X	ilist[nr_inodes++] = atoi(p);
X  } while ((p = strchr(p, ',')) != NULL);
X}
X
X
Xint inlist(inode)
Xino_t inode;
X{
X  int i;
X
X  for (i = 0; i < nr_inodes; i++) {
X	if (ilist[i] == inode)
X		return(1);
X  }
X  return(0);
X}
X
X
Xint dotfile(fullname)
Xchar *fullname;
X{
X  char *name;
X
X  name = strrchr(fullname, '/') + 1;
X
X  return(!(strcmp(name, ".") && strcmp(name, "..")));
X}
X
X
Xint toprint(statbuf, name)
Xstruct stat *statbuf;
Xchar *name;
X{
X#define S_SPECIAL(x) (x & (S_ISUID | S_ISGID) || S_ISCHR(x) || S_ISBLK(x))
X
X  return ((!iflag || inlist(statbuf->st_ino)) &&
X	(aflag || !dotfile(name)) &&
X	(!sflag || S_SPECIAL(statbuf->st_mode)));
X}
X
X
Xvoid traverse(dirname)
Xchar *dirname;
X{
X  struct dirent *dirent;
X  DIR *dir;
X  struct stat statbuf;
X  int len;
X
X  len = strlen(dirname);
X  if (stat(dirname, &statbuf) < 0) {
X	fprintf(stderr, "could not stat %s: %s\n", dirname, strerror(errno));
X	return;
X  }
X  if (toprint(&statbuf, dirname))
X	printf("%5ld %s\n", (long) statbuf.st_ino, dirname+skip_len);
X
X  if (!dotfile(dirname) && S_ISDIR(statbuf.st_mode)) {
X	if ((dir = opendir(dirname)) == NULL) {
X		fprintf(stderr, "could not open %s: %s\n", dirname,
X			strerror(errno));
X		return;
X	}
X	dirname[len++] = '/';
X	while ((dirent = readdir(dir)) != NULL) {
X		strcpy(dirname+len, dirent->d_name);
X		traverse(dirname);
X	}
X	closedir(dir);
X  }
X}
X
X
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  progname = argv[0];
X
X  while ((opt = getopt(argc, argv, "i:as")) != EOF) {
X	switch (opt) {
X	case 'i':
X		if (nr_inodes > 0)
X			usage();
X		iflag = 1;
X		readilist(optarg);
X		break;
X	case 'a':
X		aflag = 1;
X		break;
X	case 's':
X		sflag = 1;
X		break;
X	}
X  }
X  if (optind > argc-1)
X	usage();
X  filesystem = argv[optind];
X
X  mnt_point = tmpnam((char *)NULL);
X  mkdir(mnt_point, 0777);
X  if (mount(filesystem, mnt_point, 1) < 0) {
X	perror("mount");
X	myexit(1);
X  }
X  strcpy(path, mnt_point);
X  skip_len = strlen(path);
X  
X  traverse(path);
X  myexit(0);
X
X  /* NOTREACHED */
X  return(0);
X}
/
echo x - pathchk.c
sed '/^X/s///' > pathchk.c << '/'
X/* pathchk - check pathnames		Author: V. Archer */
X
X/* Copyright 1991 by Vincent Archer
X *	You may freely redistribute this software, in source or binary
X *	form, provided that you do not alter this copyright mention in any
X *	way.
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <limits.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X#include <minix/minlib.h>
X#include <stdio.h>
X
X/* Global variables. */
Xchar directory[PATH_MAX + 1];
Xchar POSIX_CHAR_SET[] = "\
X.#-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_~";
X
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(void perr, (char *name, char *msg));
X_PROTOTYPE(void usage, (void));
X
X/* Perror-like function, but with a user supplied message rather than an
X * error one. The standard limits-related messages are not very clear on
X * what is wrong. :-)
X */
Xvoid perr(name, msg)
Xchar *name, *msg;
X{
X  std_err(name);
X  std_err(":");
X  std_err(msg);
X}
X
X
X/* Main module. Since only one option (-p) is allowed, do not include all
X * the getopt() stuff.
X */
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  char *name, *arg;
X  int pflag, length, maxl;
X  int rtstat = 0;
X  uid_t uid;
X  gid_t gid;
X  mode_t mask;
X  struct stat perms;
X  int Maxname;
X
X  argc--;
X  argv++;
X  if (argc && !strcmp(*argv, "-p")) {
X	argc--;
X	argv++;
X	pflag = 1;
X  } else
X	pflag = 0;
X  uid = getuid();
X  gid = getgid();
X
X  if (!argc) usage();
X
X  while (argc--) {
X	arg = *argv++;
X#if PATH_MAX != _POSIX_PATH_MAX
X	if (pflag) {
X		if (strlen(arg) > _POSIX_PATH_MAX) {
X			perr(arg, "pathname too long for Posix\n");
X			rtstat = 1;
X			continue;
X		}
X	} else
X#endif
X	if (strlen(arg) > PATH_MAX) {
X		perr(arg, "pathname too long\n");
X		rtstat = 1;
X		continue;
X	}
X	length = 0;
X	maxl = 0;
X	directory[0] = '.';
X	directory[1] = '\0';
X	if (pflag) {
X		Maxname = _POSIX_NAME_MAX;
X	} else
X		Maxname = pathconf(directory, _PC_NAME_MAX);
X
X	for (name = arg; *name; name++) {
X		if (*name == '/') {
X			if (length > Maxname) break;
X/* I do not allow a//b (empty component). Too ugly. */
X			if (length == 0 && maxl) {
X				perr(arg, "empty component\n");
X				rtstat = 1;
X				break;
X			}
X			length = 0;
X
X			if (!pflag && directory[0]) {
X				if (maxl == 0) {
X					directory[0] = '/';
X					directory[1] = '\0';
X				} else {
X					strncpy(directory, arg, (size_t) maxl);
X					directory[maxl] = '\0';
X				}
X
X				if (stat(directory, &perms) == 0) {
X					Maxname = pathconf(directory, _PC_NAME_MAX);
X					if (uid) {
X						if (uid == perms.st_uid)
X							mask = S_IXUSR;
X						else if (gid == perms.st_gid)
X							mask = S_IXGRP;
X						else
X							mask = S_IXOTH;
X						if (!(mask & perms.st_mode)) {
X							perr(arg, "not searchable\n");
X							rtstat = 1;
X							break;
X						}
X					}
X				} else
X					directory[0] = '\0';
X			}
X		} else {
X			if (!strchr(POSIX_CHAR_SET, *name)) {
X				perr(arg, "illegal character\n");
X				rtstat = 1;
X				name = "";
X				length = 0;	/* do not print 2 msgs */
X				break;
X			}
X			length++;
X		}
X		maxl++;
X	}
X	if (length > Maxname) {
X		perr(arg, pflag ? "component name too long for Posix\n"
X		     : "component name too long\n");
X		rtstat = 1;
X	}
X  }
X  return(rtstat);
X}
X
X
X/* Posix command prototype. */
Xvoid usage()
X{
X  std_err("Usage: pathchk [-p] file...\n");
X  exit(1);
X}
/
echo x - proto.c
sed '/^X/s///' > proto.c << '/'
X/* proto - Generate ANSI C prototypes.	Author:	Eric R. Smith */
X
X/* Program to extract function declarations from C source code
X * Written by Eric R. Smith and placed in the public domain
X * Thanks are due to Jwahar R. Bammi for fixing several bugs
X * And providing the Unix makefiles.
X */
X#define EXIT_SUCCESS  0
X#define EXIT_FAILURE  1
X
X#include <string.h>
X#include <ctype.h>
X#include <stdlib.h>
X#include <stdio.h>
X
X#define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_' ))
X#define ABORTED ( (Word *) -1 )
X#define MAXPARAM 20		/* max. number of parameters to a function */
X
Xtypedef struct word {
X  struct word *next;
X  char string[1];
X} Word;
X
Xint inquote = 0;		/* in a quote? */
Xint newline_seen = 1;		/* are we at the start of a line */
Xlong linenum = 1L;		/* line number in current file */
Xlong endline = 0L;		/* the last line before the { of a f'n */
Xlong symline = 0L;		/* Line that symbol was on, set by getsym() */
Xint dostatic = 0;		/* do static functions? */
Xint donum = 0;			/* print line numbers? */
Xint dohead = 1;			/* do file headers? */
Xint docond = 1;			/* conditionalize for non-ANSI compilers? */
Xint dodiff = 0;			/* Output a diff file to prototype original */
Xint doold = 0;			/* do old style: P() */
Xint glastc = ' ';		/* last char. seen by getsym() */
XWord *endlist;			/* Parentheses after the parameters */
Xchar *progname;			/* name of program (for error messages) */
X
X
X_PROTOTYPE(Word * word_alloc, (char *s));
X_PROTOTYPE(void word_free, (Word * w));
X_PROTOTYPE(int List_len, (Word * w));
X_PROTOTYPE(Word * word_append, (Word * w1, Word * w2));
X_PROTOTYPE(int foundin, (Word * w1, Word * w2));
X_PROTOTYPE(void addword, (Word * w, char *s));
X_PROTOTYPE(void printlist, (Word * p));
X_PROTOTYPE(Word * typelist, (Word * p));
X_PROTOTYPE(void typefixhack, (Word * w));
X_PROTOTYPE(int ngetc, (FILE * f));
X_PROTOTYPE(int fnextch, (FILE * f));
X_PROTOTYPE(int nextch, (FILE * f));
X_PROTOTYPE(int getsym, (char *buf, FILE * f));
X_PROTOTYPE(int skipit, (char *buf, FILE * f));
X_PROTOTYPE(Word * getparamlist, (FILE * f));
X_PROTOTYPE(void emit, (Word * wlist, Word * plist, long startline));
X_PROTOTYPE(void getdecl, (FILE * f));
X_PROTOTYPE(int main, (int argc, char **argv));
X_PROTOTYPE(void Usage, (void));
X
X/* Routines for manipulating lists of words. */
X
XWord *word_alloc(s)
Xchar *s;
X{
X  Word *w;
X
X  w = (Word *) malloc(sizeof(Word) + strlen(s) + 1);
X  if (w == NULL) {
X	fprintf(stderr, "%s: out of memory\n", progname);
X	exit(1);
X  }
X  (void) strcpy(w->string, s);
X  w->next = NULL;
X  return w;
X}
X
Xvoid word_free(w)
XWord *w;
X{
X  Word *oldw;
X  while (w) {
X	oldw = w;
X	w = w->next;
X	free((char *) oldw);
X  }
X}
X
X/* Return the length of a list; empty words are not counted */
Xint List_len(w)
XWord *w;
X{
X  int count = 0;
X
X  while (w) {
X	if (*w->string) count++;
X	w = w->next;
X  }
X  return count;
X}
X
X/* Append two lists, and return the result */
XWord *word_append(w1, w2)
XWord *w1, *w2;
X{
X  Word *r, *w;
X
X  r = w = word_alloc("");
X
X  while (w1) {
X	w->next = word_alloc(w1->string);
X	w = w->next;
X	w1 = w1->next;
X  }
X  while (w2) {
X	w->next = word_alloc(w2->string);
X	w = w->next;
X	w2 = w2->next;
X  }
X
X  return r;
X}
X
X/* See if the last entry in w2 is in w1 */
Xint foundin(w1, w2)
XWord *w1, *w2;
X{
X  while (w2->next) w2 = w2->next;
X
X  while (w1) {
X	if (!strcmp(w1->string, w2->string)) return 1;
X	w1 = w1->next;
X  }
X  return 0;
X}
X
X/* Add the string s to the given list of words */
Xvoid addword(w, s)
XWord *w;
Xchar *s;
X{
X  while (w->next) w = w->next;
X  w->next = word_alloc(s);
X}
X
X/* Printlist: print out a list */
Xvoid printlist(p)
XWord *p;
X{
X  Word *w;
X  int i = 0;
X
X  for (w = p; w; w = w->next) {
X	printf("%s", w->string);
X	if (ISCSYM(w->string[0]) && i > 0) printf(" ");
X	i++;
X  }
X}
X
X/* Given a list representing a type and a variable name, extract just
X * the base type, e.g. "struct word *x" would yield "struct word".
X * Similarly, "unsigned char x[]" would yield "unsigned char".
X */
XWord *typelist(p)
XWord *p;
X{
X  Word *w, *r, *last;
X
X  last = r = w = word_alloc("");
X  while (p && p->next) {
X	if (p->string[0] == '[') {
X		word_free(w);
X		last->next = NULL;
X		break;
X	}
X	if (p->string[0] && !ISCSYM(p->string[0])) break;
X	w->next = word_alloc(p->string);
X	last = w;
X	w = w->next;
X	p = p->next;
X  }
X  return r;
X}
X
X/* Typefixhack: promote formal parameters of type "char", "unsigned char",
X * "short", or "unsigned short" to "int".
X */
Xvoid typefixhack(w)
XWord *w;
X{
X  Word *oldw = 0;
X
X  while (w) {
X	if (*w->string) {
X		if ((!strcmp(w->string, "char") ||
X		     !strcmp(w->string, "short"))
X		    && (List_len(w->next) < 2)) {
X			if (oldw && !strcmp(oldw->string, "unsigned")) {
X				oldw->next = w->next;
X				free((char *) w);
X				w = oldw;
X			}
X			(void) strcpy(w->string, "int");
X		}
X	}
X	w = w->next;
X  }
X}
X
X/* Read a character: if it's a newline, increment the line count */
Xint ngetc(f)
XFILE *f;
X{
X  int c;
X
X  c = getc(f);
X  if (c == '\n') linenum++;
X
X  return c;
X}
X
X/* Read the next character from the file. If the character is '\' then
X * read and skip the next character. Any comment sequence is converted
X * to a blank.
X */
Xint fnextch(f)
XFILE *f;
X{
X  int c, lastc, incomment;
X
X  c = ngetc(f);
X  while (c == '\\') {
X	c = ngetc(f);		/* skip a character */
X	c = ngetc(f);
X  }
X  if (c == '/' && !inquote) {
X	c = ngetc(f);
X	if (c == '*') {
X		incomment = 1;
X		c = ' ';
X		while (incomment) {
X			lastc = c;
X			c = ngetc(f);
X			if (lastc == '*' && c == '/')
X				incomment = 0;
X			else if (c < 0)
X				return c;
X		}
X		return fnextch(f);
X	} else {
X		if (c == '\n') linenum--;
X		(void) ungetc(c, f);
X		return '/';
X	}
X  }
X  return c;
X}
X
X
X/* Get the next "interesting" character. Comments are skipped, and strings
X * are converted to "0". Also, if a line starts with "#" it is skipped.
X */
Xint nextch(f)
XFILE *f;
X{
X  int c;
X
X  c = fnextch(f);
X  if (newline_seen && c == '#') {
X	do {
X		c = fnextch(f);
X	} while (c >= 0 && c != '\n');
X	if (c < 0) return c;
X  }
X  newline_seen = (c == '\n');
X
X  if (c == '\'' || c == '\"') {
X	inquote = c;
X	while ((c = fnextch(f)) >= 0) {
X		if (c == inquote) {
X			inquote = 0;
X			return '0';
X		}
X	}
X  }
X  return c;
X}
X
X/* Get the next symbol from the file, skipping blanks.
X * Return 0 if OK, -1 for EOF.
X * Also collapses everything between { and }
X */
Xint getsym(buf, f)
Xchar *buf;
XFILE *f;
X{
X  register int c;
X  int inbrack = 0;
X
X  c = glastc;
X  while ((c > 0) && isspace(c)) c = nextch(f);
X  if (c < 0) return -1;
X  if (c == '{') {
X	inbrack = 1;
X	endline = linenum;
X	while (inbrack) {
X		c = nextch(f);
X		if (c < 0) {
X			glastc = c;
X			return c;
X		}
X		if (c == '{')
X			inbrack++;
X		else if (c == '}')
X			inbrack--;
X	}
X	(void) strcpy(buf, "{}");
X	glastc = nextch(f);
X	return 0;
X  }
X  if (!ISCSYM(c)) {
X	*buf++ = c;
X	glastc = nextch(f);
X	if (c == '(' && glastc == '*') {	/* Look for a 'f'n pointer */
X		*buf++ = glastc;
X		glastc = nextch(f);
X	}
X	*buf = 0;
X	return 0;
X  }
X  symline = linenum;
X  while (ISCSYM(c)) {
X	*buf++ = c;
X	c = nextch(f);
X  }
X  *buf = 0;
X  glastc = c;
X  return 0;
X}
X
X
X/* Skipit: skip until a ";" or the end of a function declaration is seen */
Xint skipit(buf, f)
Xchar *buf;
XFILE *f;
X{
X  int i;
X
X  do {
X	i = getsym(buf, f);
X	if (i < 0) return i;
X  } while (*buf != ';' && *buf != '{');
X
X  return 0;
X}
X
X/* Get a parameter list; when this is called the next symbol in line
X * should be the first thing in the list.
X */
XWord *getparamlist(f)
XFILE *f;
X{
X  static Word *pname[MAXPARAM];	/* parameter names */
X  Word *tlist,			/* type name */
X  *plist;			/* temporary */
X  int np = 0;			/* number of parameters */
X  int typed[MAXPARAM];		/* parameter has been given a type */
X  int tlistdone;		/* finished finding the type name */
X  int sawsomething;
X  int i;
X  int inparen = 0;
X  char buf[80];
X
X  for (i = 0; i < MAXPARAM; i++) typed[i] = 0;
X
X  plist = word_alloc("");
X  endlist = word_alloc("");
X
X  /* First, get the stuff inside brackets (if anything) */
X
X  sawsomething = 0;		/* gets set nonzero when we see an arg */
X  for (;;) {
X	if (getsym(buf, f) < 0) return(NULL);
X	if (*buf == ')' && (--inparen < 0)) {
X		if (sawsomething) {	/* if we've seen an arg */
X			pname[np] = plist;
X			plist = word_alloc("");
X			np++;
X		}
X		break;
X	}
X	if (*buf == ';') {	/* something weird */
X		return ABORTED;
X	}
X	sawsomething = 1;	/* there's something in the arg. list */
X	if (*buf == ',' && inparen == 0) {
X		pname[np] = plist;
X		plist = word_alloc("");
X		np++;
X	} else {
X		addword(plist, buf);
X		if (*buf == '(') inparen++;
X	}
X  }
X
X  /* Next, get the declarations after the function header */
X  inparen = 0;
X  tlist = word_alloc("");
X  plist = word_alloc("");
X  tlistdone = 0;
X  sawsomething = 0;
X  for (;;) {
X	if (getsym(buf, f) < 0) return(NULL);
X
X	/* Handle parentheses, which should indicate func pointer rtn values */
X	if (*buf == '(') {
X		addword(endlist, buf);
X		addword(endlist, " void ");
X		inparen++;
X	} else if (*buf == ')') {
X		if (symline == linenum) {
X			addword(endlist, buf);
X			addword(endlist, buf);
X		}
X		inparen--;
X	} else if (*buf == ',' && !inparen) {
X		/* Handle a list like "int x,y,z" */
X		if (!sawsomething) return(NULL);
X		for (i = 0; i < np; i++) {
X			if (!typed[i] && foundin(plist, pname[i])) {
X				typed[i] = 1;
X				word_free(pname[i]);
X				pname[i] = word_append(tlist, plist);
X				/* Promote types */
X				typefixhack(pname[i]);
X				break;
X			}
X		}
X		if (!tlistdone) {
X			tlist = typelist(plist);
X			tlistdone = 1;
X		}
X		word_free(plist);
X		plist = word_alloc("");
X	} else if (*buf == ';') {
X		/* Handle the end of a list */
X		if (!sawsomething) return ABORTED;
X		for (i = 0; i < np; i++) {
X			if (!typed[i] && foundin(plist, pname[i])) {
X				typed[i] = 1;
X				word_free(pname[i]);
X				pname[i] = word_append(tlist, plist);
X				typefixhack(pname[i]);
X				break;
X			}
X		}
X		tlistdone = 0;
X		word_free(tlist);
X		word_free(plist);
X		tlist = word_alloc("");
X		plist = word_alloc("");
X	} else if (!strcmp(buf, "{}"))
X		break;	/* Handle the  beginning of the function */
X		/* Otherwise, throw word into list (except for "register") */
X	else if (strcmp(buf, "register")) {
X		sawsomething = 1;
X		addword(plist, buf);
X		if (*buf == '(') inparen++;
X		if (*buf == ')') inparen--;
X	}
X  }
X
X  /* Now take the info we have and build a prototype list */
X
X  /* Empty parameter list means "void" */
X  if (np == 0) return word_alloc("void");
X
X  plist = tlist = word_alloc("");
X  for (i = 0; i < np; i++) {
X
X  /* If no type provided, make it an "int" */
X	if (!(pname[i]->next) ||
X	    (!(pname[i]->next->next)&&strcmp(pname[i]->next->string,"void"))) {
X		addword(tlist, "int");
X	}
X	while (tlist->next) tlist = tlist->next;
X	tlist->next = pname[i];
X	if (i < np - 1) addword(tlist, ", ");
X  }
X  return plist;
X}
X
X/* Emit a function declaration. The attributes and name of the function
X * are in wlist; the parameters are in plist.
X */
Xvoid emit(wlist, plist, startline)
XWord *wlist, *plist;
Xlong startline;
X{
X  Word *w;
X  int count = 0;
X
X  if (doold == 0) printf("_PROTOTYPE(");
X  if (dodiff) {
X	printf("%lda%ld,%ld\n", startline - 1, startline, startline +2);
X	printf("> #ifdef __STDC__\n> ");
X  }
X  if (donum) printf("/*%8ld */ ", startline);
X  for (w = wlist; w; w = w->next) {
X	if (w->string[0]) count++;
X  }
X  if (count < 2) printf("int ");
X  printlist(wlist);
X  if (docond) {
X	if (doold)
X		printf("P((");
X	else
X		printf(", (");
X  } else {
X	printf("( ");
X  }
X
X  printlist(plist);
X  printlist(endlist);
X
X  if (docond)
X	printf("))");
X  else
X	printf(")");
X
X  if (!dodiff)
X	printf(";\n");
X  else
X	printf("\n");
X
X  if (dodiff) {
X	printf("> #else\n");
X	printf("%lda%ld\n", endline - 1, endline);
X	printf("> #endif\n");
X  }
X}
X
X/* Get all the function declarations */
Xvoid getdecl(f)
XFILE *f;
X{
X  Word *plist, *wlist = NULL;
X  char buf[80];
X  int sawsomething;
X  long startline = 0L;		/* line where declaration started */
X  int oktoprint;
X
Xagain:				/* SHAME SHAME */
X  word_free(wlist);
X  wlist = word_alloc("");
X  sawsomething = 0;
X  oktoprint = 1;
X
X  for (;;) {
X	if (getsym(buf, f) < 0) return;
X
X	/* Guess when a declaration is not an external function definition */
X	if (!strcmp(buf, ",") || !strcmp(buf, "{}") ||
X	    !strcmp(buf, "=") || !strcmp(buf, "typedef") ||
X	    !strcmp(buf, "extern")) {
X		(void) skipit(buf, f);
X		goto again;
X	}
X	if (!dostatic && !strcmp(buf, "static")) oktoprint = 0;
X
X	/* For the benefit of compilers that allow "inline" declarations */
X	if (!strcmp(buf, "inline") && !sawsomething) continue;
X	if (!strcmp(buf, ";")) goto again;
X
X	/* A left parenthesis *might* indicate a function definition */
X	if (!strcmp(buf, "(")) {
X		if (!sawsomething || !(plist = getparamlist(f))) {
X			(void) skipit(buf, f);
X			goto again;
X		}
X		if (plist == ABORTED) goto again;
X
X		/* It seems to have been what we wanted */
X		if (oktoprint) emit(wlist, plist, startline);
X		word_free(plist);
X		goto again;
X	}
X	addword(wlist, buf);
X	if (!sawsomething) startline = symline;
X	sawsomething = 1;
X  }
X}
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X  FILE *f, *g;
X  char *t;
X  char newname[40];
X
X  progname = argv[0];
X  argv++;
X  argc--;
X  g = stdout;
X
X  while (*argv && **argv == '-') {
X	t = *argv++;
X	--argc;
X	t++;
X	while (*t) {
X		if (*t == 's')
X			dostatic = 1;
X		else if (*t == 'n')
X			donum = 1;
X		else if (*t == 'p')
X			docond = 0;
X		else if (*t == 'P')
X			doold =1;
X		else if (*t == 'd') {
X			dodiff = 1;
X			docond = 0;
X			donum = 0;
X			dostatic = 1;
X		} else
X			Usage();
X		t++;
X	}
X  }
X
X  if (docond && doold) {
X	printf("#ifdef __STDC__\n");
X	printf("# define\tP(s) s\n");
X	printf("#else\n");
X	printf("# define P(s) ()\n");
X	printf("#endif\n\n");
X  }
X  if (argc == 0)
X	getdecl(stdin);
X  else
X	while (argc > 0 && *argv) {
X		if (!(f = fopen(*argv, "r"))) {
X			perror(*argv);
X			exit(EXIT_FAILURE);
X		}
X		if (dodiff) {
X			(void) sprintf(newname, "%sdif", *argv);
X			(void) fclose(g);
X			if (!(g = fopen(newname, "w"))) {
X				perror(newname);
X				exit(EXIT_FAILURE);
X			}
X		}
X		if (doold && dohead && !dodiff) printf("\n/* %s */\n", *argv);
X		linenum = 1;
X		newline_seen = 1;
X		glastc = ' ';
X		getdecl(f);
X		argc--;
X		argv++;
X		(void) fclose(f);
X	}
X  if (docond && doold) printf("\n#undef P\n");	/* clean up namespace */
X  (void) fclose(g);
X  return(EXIT_SUCCESS);
X}
X
X
Xvoid Usage()
X{
X  fputs("Usage: ", stderr);
X  fputs(progname, stderr);
X  fputs(" [-d][-n][-p][-s] [files ...]\n", stderr);
X  fputs("   -P: use P() style instead of _PROTOTYPE\n", stderr);
X  fputs("   -d: produce a diff file to prototype original source\n", stderr);
X  fputs("   -n: put line numbers of declarations as comments\n", stderr);
X  fputs("   -p: don't make header files readable by K&R compilers\n", stderr);
X  fputs("   -s: include declarations for static functions\n", stderr);
X  exit(EXIT_FAILURE);
X}
/
echo x - swapfs.c
sed '/^X/s///' > swapfs.c << '/'
X/* swapfs - swap a Minix file system	    Author: Niels C. Willems */
X
X
X/* $Id: swapfs.c,v 1.10 1992/04/15 10:51:46 ncwille Exp $ */
X
X/* Swapfs, a program to convert V1 or V2 Minix file systems from big endian
X   byte order to little endian and vv.
X
X   Some examples:
X   swapfs -v disk.01			! only show verbose information.
X   swapfs /dev/fd0 | compress > fd0r.Z	! convert and compress filesystem.
X   swapfs -v fileA fileA	! read, convert and write the same filesystem.
X
X  This program uses one byte of heap memory for each data block (1Kbytes)
X  in the file system, so with Minix-PC 16-bit you can't swap file systems
X  bigger than about 32 Mbytes
X
X  Be careful with 'swapfs fileA fileA'. If the program aborts e.g. by
X  user interrupt, power failure or an inconsistent file system, you
X  better have a backup of fileA
X
X  This program only converts directories and indirect blocks of files
X  that are in use. Converting indirect blocks or directories of deleted
X  files is hard and not yet done.
X
X  If you have a (1.6.xx, xx < 18) version of Minix that supports the
X  mounting of reversed file systems always mount them read-only and
X  avoid any attemp to modify them (mkdir, open, creat) too!
X  These problems have been fixed in Minix 1.6.18.
X
X  In this version you can get some more information about the
X  file system with the -d (debug) flag.
X
X      Please send your bug reports or ideas to ncwille@cs.vu.nl
X */
X
X
X#define _POSIX_SOURCE	1
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdlib.h>
X#include <fcntl.h>
X#include <string.h>
X#include <unistd.h>
X#include <stdio.h>
X
X#include <assert.h>
X
X#if __STDC__ == 1
X#define	_PROTOTYPE(function, params)	function params
X#else
X#define	_PROTOTYPE(function, params)	function()
X#endif
X
X#define BLOCK_SIZE	1024
X
X#define BOOT_BLOCK_OFF	   (blockn_t) 0
X#define SUPER_BLOCK_OFF    (blockn_t) 1
X
X#define V1_MAGIC		0x137F
X#define V2_MAGIC		0x2468
X#define NINODES_OFFSET		     0
X#define V1_ZONES_OFFSET		     2
X#define IMAP_BLOCKS_OFFSET	     4
X#define ZMAP_BLOCKS_OFFSET	     6
X#define FIRSTDATAZONE_OFFSET	     8
X#define LOG_ZONE_SIZE_OFFSET        10
X#define MAGIC_OFFSET		    16
X#define V2_ZONES_OFFSET		    20
X
X
X#define NR_DIRECT_ZONES	 7
X#define V1_NR_TZONES	 9
X#define V2_NR_TZONES	10
X#define V1_INODE_SIZE	32
X#define V2_INODE_SIZE	64
X
X#define INODE1_MODE_OFF		 0
X#define INODE1_SIZE_OFF		 4
X#define INODE1_DIRECT_OFF	14
X#define INODE1_IND1_OFF		28
X#define INODE1_IND2_OFF		30
X
X#define INODE2_MODE_OFF		 0
X#define INODE2_SIZE_OFF		 8
X#define INODE2_DIRECT_OFF	24
X#define INODE2_IND1_OFF		52
X#define INODE2_IND2_OFF		56
X#define INODE2_IND3_OFF		60
X
X#define INODE_MODE_MASK		0xf000	/* file type mask    */
X#define INODE_DIR_MODE		0x4000	/* directory         */
X#define INODE_BLK_SPECIAL_MODE	0x6000	/* block special     */
X#define INODE_CHR_SPECIAL_MODE  0x2000	/* character special */
X
X#define T_MASK		0x1c
X#define T_UNKNOWN	0x00
X#define T_MAYBE_OLD_DIR	0x04
X#define T_OLD_NON_DIR	0x08
X#define T_DIR		0x0c
X#define T_NON_DIR	0x10
X
X#define INDIRECT_MASK	0x03
X
X#define IND_PROCESSED_BIT 0x20	/* set when all blocks in ind block are
X			 * marked */
X#define IND_CONFLICT_BIT  0x40
X#define TYPE_CONFLICT_BIT 0x80
X
X#define DIR_ENTRY_SIZE    16
X
Xtypedef enum {
X  Unused_zone, Old_zone, In_use_zone
X} class_t;
X
Xtypedef unsigned long blockn_t;
Xtypedef unsigned int inodesn_t;
X
Xtypedef struct {
X  inodesn_t ninodes;		/* # usable inodes on the minor device */
X  blockn_t imap_blocks;		/* # of blocks used by inode bit map */
X  blockn_t zmap_blocks;		/* # of blocks used by zone bit map */
X  blockn_t firstdatazone;	/* number of first data zone */
X  int log_zone_size;		/* log2 of blocks/zone */
X  blockn_t zones;		/* number of zones */
X
X  int version;			/* file system version */
X  inodesn_t inodes_per_block;
X  blockn_t first_imap_block;
X  blockn_t first_zmap_block;
X  blockn_t first_inode_block;	/* number of first block with inodes */
X  size_t dzmap_size;		/* # of data zone blocks */
X} super_t;
X
X
Xtypedef struct {		/* summary of inode */
X  long size;			/* current file size in bytes */
X  blockn_t direct[NR_DIRECT_ZONES];	/* block numbers for direct,
X					 * ind, ... */
X  blockn_t ind1;		/* single indirect block number */
X  blockn_t ind2;		/* double indirect block number */
X  blockn_t ind3;		/* triple indirect block number */
X  int ztype;			/* type of zones that belong to this inode */
X} inode_t;
X
Xstatic char rcsid[] = "$Id: swapfs.c,v 1.10 1992/04/15 10:51:46 ncwille Exp $";
X
Xstatic int super_format[] = {2, 2, 2, 2, 2, 2, 4, 2, 2, 4, 0};
Xstatic int inode1_format[] = {2, 2, 4, 4, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0};
Xstatic int inode2_format[] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
X		      4, 4, 0};
X
Xstatic char *ind_str[4] = {"direct", "single indirect",
X		   "double indirect", "triple indirect"};
X
Xstatic int big_endian_fs;	/* set in init_super(), 1 iff file system has
X			 * big endian byte order */
Xstatic int verbose_flag;
Xstatic int debug_flag;
Xstatic int test_flag;
X
Xtypedef unsigned char *dzmap_t;
X
X
Xint _PROTOTYPE(main, (int argc, char *argv[]));
Xstatic void _PROTOTYPE(parse_args_init_io, (int argc, char *argv[]));
Xstatic void _PROTOTYPE(rw_boot, (void));
Xstatic void _PROTOTYPE(rw_init_super, (super_t * sp));
Xstatic void _PROTOTYPE(init_dzmap, (dzmap_t * dzmap_ptr, size_t dzmap_size));
Xstatic void _PROTOTYPE(rw_ibmap, (super_t super));
Xstatic void _PROTOTYPE(rw_zbmap, (super_t super));
Xstatic void _PROTOTYPE(print_stat, (dzmap_t dzmap, super_t super));
Xstatic void _PROTOTYPE(p1_rw_inodes, (dzmap_t dzmap, super_t super));
Xstatic void _PROTOTYPE(rd_indirects, (dzmap_t dzmap, super_t super, int ind,
X			       class_t required_class));
Xstatic void _PROTOTYPE(rw_data_zones, (dzmap_t dzmap, super_t super));
X
Xstatic int _PROTOTYPE(read_block, (char *buf, blockn_t offset));
Xstatic void _PROTOTYPE(write_block, (char *buf));
Xstatic int _PROTOTYPE(convcpy, (char *dst, char *src, int *format));
Xstatic void _PROTOTYPE(conv2_blkcpy, (char *dst, char *src));
Xstatic void _PROTOTYPE(conv4_blkcpy, (char *dst, char *src));
Xstatic void _PROTOTYPE(conv2cpy, (char *dst, char *src));
Xstatic int _PROTOTYPE(inode_size, (int version));
X
Xstatic void _PROTOTYPE(init_super, (super_t * sp, char *buf));
Xstatic void _PROTOTYPE(get_inode, (inode_t * ip, char *buf, int version));
Xstatic int _PROTOTYPE(check_inode, (inode_t inode, super_t super));
Xstatic int _PROTOTYPE(was_blk_special, (inode_t inode));
Xstatic int _PROTOTYPE(check_blk_number, (blockn_t num, super_t super));
Xstatic void _PROTOTYPE(cw_inode_block, (char *buf, inodesn_t ninodes,
X				 int version));
Xstatic void _PROTOTYPE(proc_ind, (dzmap_t dzmap, size_t curr_ind,
X			   char *buf, super_t super));
Xstatic void _PROTOTYPE(cw_dir_block, (char *buf));
Xstatic void _PROTOTYPE(dzmap_add_inode, (dzmap_t dzmap, inode_t inode,
X				  super_t super));
Xstatic void _PROTOTYPE(dz_update, (dzmap_t dzmap, blockn_t blknum,
X		     int new_indnum, int new_ztype, super_t super));
Xstatic class_t _PROTOTYPE(ztype_class, (int ztype));
X
Xstatic unsigned int _PROTOTYPE(two_bytes, (char buf[2]));
Xstatic long _PROTOTYPE(four_bytes, (char buf[4]));
X
Xstatic void _PROTOTYPE(fail, (char *string));
Xstatic void _PROTOTYPE(usage, (char *arg0));
X
X
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  super_t super;
X  dzmap_t dzmap;
X
X  parse_args_init_io(argc, argv);
X  rw_boot();
X  rw_init_super(&super);
X  init_dzmap(&dzmap, super.dzmap_size);
X  rw_ibmap(super);
X  rw_zbmap(super);
X  p1_rw_inodes(dzmap, super);
X
X  rd_indirects(dzmap, super, 3, In_use_zone);
X  rd_indirects(dzmap, super, 2, In_use_zone);
X  rd_indirects(dzmap, super, 1, In_use_zone);
X  if (verbose_flag) putc('\n', stderr);
X
X  print_stat(dzmap, super);
X  rw_data_zones(dzmap, super);
X  return 0;
X}
X
X
Xstatic void parse_args_init_io(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  char *str;
X  struct stat buf;
X  ino_t src_ino;
X  int i;
X
X  debug_flag = 0;
X  verbose_flag = 0;
X  test_flag = 0;
X
X  for (i = 1; i < argc; i++) {
X	str = argv[i];
X	if (*str != '-') break;
X	switch (*++str) {
X	    case 'v':	verbose_flag = 1;	break;
X	    case 'd':
X		debug_flag = 1;
X		verbose_flag = 1;
X		break;
X	    case 't':	test_flag = 1;	break;
X	    default:	usage(argv[0]);
X	}
X  }
X  if ((argc - i == 0 && isatty(0)) || (argc - i) > 2) usage(argv[0]);
X
X  if (argc - i > 0) {
X	(void) close(0);
X	if (open(argv[i], O_RDONLY) != 0) {
X		fprintf(stderr, "Can't open input file %s", argv[i]);
X		fail("");
X	}
X  }
X  if (isatty(1) || argc - i == 2) {
X	if (argc - i < 2)
X		test_flag = 1;
X	else {
X		i++;
X		(void) close(1);
X		(void) fstat(0, &buf);
X		src_ino = buf.st_ino;
X		if (stat(argv[i], &buf) == 0 && src_ino == buf.st_ino) {
X			/* Src and dest are the same */
X			if (open(argv[i], O_WRONLY) != 1) {
X				fprintf(stderr, "Can't open output file %s", argv[i]);
X				fail("");
X			}
X		} else if (creat(argv[i], 0644) != 1) {
X			fprintf(stderr, "Can't creat output file %s", argv[i]);
X			fail("");
X		}
X	}
X  }
X}
X
X
Xstatic void rw_boot()
X{
X  char buf[BLOCK_SIZE];
X
X  if (read_block(buf, BOOT_BLOCK_OFF) != BLOCK_SIZE)
X	fail("Can't read bootblock");
X  write_block(buf);
X}
X
X
Xstatic void rw_init_super(sp)
Xsuper_t *sp;
X{
X  char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
X
X  if (read_block(ibuf, SUPER_BLOCK_OFF) != BLOCK_SIZE)
X	fail("Can't read superblock");
X
X  init_super(sp, ibuf);
X
X  memcpy(obuf, ibuf, (size_t) BLOCK_SIZE);	/* preserve 'unused' data */
X  (void) convcpy(obuf, ibuf, super_format);
X
X  write_block(obuf);
X}
X
X
Xstatic void init_dzmap(dzmap_ptr, dzmap_size)
Xdzmap_t *dzmap_ptr;
Xsize_t dzmap_size;
X{
X  if ((*dzmap_ptr = (dzmap_t) malloc(dzmap_size)) == (dzmap_t) NULL)
X	fail("Not enough space for data zone map");
X  memset(*dzmap_ptr, '\0', (size_t) dzmap_size);
X}
X
X
Xstatic void rw_ibmap(super)
Xsuper_t super;
X{
X  char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
X  blockn_t i;
X
X  for (i = 0; i < super.imap_blocks; i++) {
X	if (read_block(ibuf, super.first_imap_block + i) != BLOCK_SIZE)
X		fail("Can't read inode bit map");
X	conv2_blkcpy(obuf, ibuf);
X	write_block(obuf);
X  }
X}
X
X
Xstatic void rw_zbmap(super)
Xsuper_t super;
X{
X  char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
X  blockn_t i;
X
X  for (i = 0; i < super.zmap_blocks; i++) {
X	if (read_block(ibuf, super.first_zmap_block + i) != BLOCK_SIZE)
X		fail("Can't read zone bit map");
X	conv2_blkcpy(obuf, ibuf);
X	write_block(obuf);
X  }
X}
X
X
Xstatic void p1_rw_inodes(dzmap, super)
Xdzmap_t dzmap;
Xsuper_t super;
X{
X  char buf[BLOCK_SIZE], *buf_ptr;
X  inodesn_t i, num_inodes;
X  blockn_t next_block;
X  inode_t inode;
X
X
X  next_block = super.first_inode_block;
X
X  for (i = 1; i <= super.ninodes; i++) {
X	if ((i - 1) % super.inodes_per_block == 0) {
X		if (read_block(buf, next_block) != BLOCK_SIZE)
X			fail("read failed in inode block");
X		buf_ptr = buf;
X		next_block++;
X		num_inodes = super.ninodes + 1 - i;
X		if (num_inodes > super.inodes_per_block)
X			num_inodes = super.inodes_per_block;
X		cw_inode_block(buf, num_inodes, super.version);
X	}
X	get_inode(&inode, buf_ptr, super.version);
X	dzmap_add_inode(dzmap, inode, super);
X	buf_ptr += inode_size(super.version);
X  }
X}
X
X
Xstatic void print_stat(dzmap, super)
Xdzmap_t dzmap;
Xsuper_t super;
X{
X  size_t i;
X  register unsigned char dz;
X  int both_conflict = 0, ind_conflict = 0, type_conflict = 0, unreferenced = 0;
X  int not_in_use = 0;
X
X  if (!verbose_flag) return;
X
X  for (i = 0; i < super.dzmap_size; i++) {
X	dz = dzmap[i];
X	if (dz & IND_CONFLICT_BIT && dz & TYPE_CONFLICT_BIT)
X		both_conflict++;
X	else if (dz & IND_CONFLICT_BIT)
X		ind_conflict++;
X	else if (dz & TYPE_CONFLICT_BIT)
X		type_conflict++;
X
X	if (dz == 0) unreferenced++;
X	if (ztype_class(dz & T_MASK) < In_use_zone) not_in_use++;
X
X  }
X  if (debug_flag) {
X	fprintf(stderr, "%5d zone blocks with conflicting indir.\n",
X		ind_conflict);
X	fprintf(stderr, "%5d zone blocks with conflicting types.\n",
X		type_conflict);
X	fprintf(stderr, "%5d zone blocks with conflicting types and indir.\n",
X		both_conflict);
X	fprintf(stderr, "%5d zone blocks never referenced.\n", unreferenced);
X  }
X  fprintf(stderr, "%5d zone blocks not in use.\n", not_in_use);
X  putc('\n', stderr);
X}
X
X
Xstatic void rd_indirects(dzmap, super, ind, required_class)
Xdzmap_t dzmap;
Xsuper_t super;
Xint ind;
Xclass_t required_class;
X{
X  size_t i;
X  int ind_cnt;
X  off_t dz_offset;
X  char buf[BLOCK_SIZE];
X
X  dz_offset = super.firstdatazone;
X  ind_cnt = 0;
X  for (i = 0; i < super.dzmap_size; i++) {
X	if (ztype_class(dzmap[i] & T_MASK) != required_class ||
X	    (dzmap[i] & INDIRECT_MASK) != ind ||
X	    (dzmap[i] & IND_PROCESSED_BIT))
X		continue;
X
X	ind_cnt++;
X	if (read_block(buf, dz_offset + i) != BLOCK_SIZE) {
X		fprintf(stderr, "Can't read %s block", ind_str[ind]);
X		fail("");
X	}
X	proc_ind(dzmap, i, buf, super);
X  }
X  if ((verbose_flag && ind_cnt > 0) || debug_flag)
X	fprintf(stderr, "%5d %s zone blocks.\n", ind_cnt, ind_str[ind]);
X}
X
X
Xstatic void rw_data_zones(dzmap, super)
Xdzmap_t dzmap;
Xsuper_t super;
X{
X  char ibuf[BLOCK_SIZE], obuf[BLOCK_SIZE];
X  size_t i;
X  int ztype, ind, last_read;
X  off_t dz_offset;
X
X  dz_offset = super.firstdatazone;
X  for (i = 0; i < super.dzmap_size; i++) {
X	last_read = read_block(ibuf, dz_offset + i);
X	if (last_read != BLOCK_SIZE) break;
X
X	ind = dzmap[i] & INDIRECT_MASK;
X	if (ind == 0) {
X		ztype = dzmap[i] & T_MASK;
X		if (ztype == T_DIR)
X			cw_dir_block(ibuf);
X		else
X			write_block(ibuf);
X	} else {
X		if (super.version == 1)
X			conv2_blkcpy(obuf, ibuf);
X		else
X			conv4_blkcpy(obuf, ibuf);
X		write_block(obuf);
X	}
X	if (verbose_flag && i && i % 1024 == 0) {
X		fprintf(stderr, ".");
X		fflush(stderr);
X	}
X  }
X  if (verbose_flag && i > 1024) putc('\n', stderr);
X
X  if (last_read != BLOCK_SIZE) for (; i < super.dzmap_size; i++)
X		if (ztype_class(dzmap[i] & T_MASK) == In_use_zone)
X			fail("Can't read data zone");
X}
X
X
Xstatic int read_block(buf, offset)
Xchar *buf;
Xblockn_t offset;
X{
X  static blockn_t curr_offset = 0;
X  int bytes;
X
X  if (offset != curr_offset) {
X	if (lseek(0, (off_t) offset * BLOCK_SIZE, 0) == -1)
X		fail("lseek failed on input file");
X	curr_offset = offset;
X  }
X  bytes = read(0, buf, BLOCK_SIZE);
X  if (bytes < 0) fail("read failed on input file");
X
X  curr_offset += bytes;
X
X  return bytes;
X}
X
X
Xstatic void write_block(buf)
Xchar *buf;
X{
X  if (test_flag) return;
X
X  if (write(1, buf, BLOCK_SIZE) != BLOCK_SIZE)
X	fail("write failed on output file");
X}
X
X
Xstatic int convcpy(dst, src, format)
Xchar *dst;
Xchar *src;
Xint *format;
X{
X  char *old_src = src;
X  register char tmp;
X  int i;
X
X  for (i = 0; format[i] > 0; i++) {
X	switch (format[i]) {
X	    case 1:	*dst++ = *src++;	break;
X	    case 2:
X		tmp = *src++;
X		*dst++ = *src++;
X		*dst++ = tmp;
X		break;
X	    case 4:
X		tmp = src[0];
X		dst[0] = src[3];
X		dst[3] = tmp;
X		tmp = src[1];
X		dst[1] = src[2];
X		dst[2] = tmp;
X		src += 4;
X		dst += 4;
X		break;
X	    default:
X		fail("wrong format array for convcpy");
X	}
X  }
X  return(src - old_src);
X}
X
X
Xstatic void conv2_blkcpy(dst, src)
Xchar *dst;
Xchar *src;
X{
X  int i;
X  register char tmp;
X
X  for (i = 0; i < BLOCK_SIZE; i += 2) {
X	tmp = *src++;
X	*dst++ = *src++;
X	*dst++ = tmp;
X  }
X}
X
X
Xstatic void conv4_blkcpy(dst, src)
Xchar *dst;
Xchar *src;
X{
X  int i;
X  register char tmp;
X
X  for (i = 0; i < BLOCK_SIZE; i += 4) {
X	tmp = src[0];
X	dst[0] = src[3];
X	dst[3] = tmp;
X
X	tmp = src[1];
X	dst[1] = src[2];
X	dst[2] = tmp;
X
X	src += 4;
X	dst += 4;
X  }
X}
X
X
Xstatic void conv2cpy(dst, src)
Xchar *dst;
Xchar *src;
X{
X  register char tmp;
X  tmp = *src++;
X  *dst++ = *src++;
X  *dst++ = tmp;
X}
X
X
Xstatic int inode_size(version)
Xint version;
X{
X  return(version == 1) ? V1_INODE_SIZE : V2_INODE_SIZE;
X}
X
X
Xstatic void init_super(sp, buf)
Xsuper_t *sp;
Xchar *buf;
X{
X  int magic;
X  long imapblks, zmapblks;
X
X  big_endian_fs = 0;		/* guess the file system is little endian */
X  magic = two_bytes(buf + MAGIC_OFFSET);
X
X  if (magic != V1_MAGIC && magic != V2_MAGIC) {
X	big_endian_fs = 1;
X	magic = two_bytes(buf + MAGIC_OFFSET);
X  }
X  switch (magic) {
X      case V1_MAGIC:	sp->version = 1;	break;
X      case V2_MAGIC:	sp->version = 2;	break;
X      default:	fail("Not a Minix file system");
X}
X
X  if (verbose_flag) fprintf(stderr, "\nVersion = V%d, %s endian.\n",
X		sp->version, big_endian_fs ? "big" : "little");
X
X  sp->ninodes = two_bytes(buf + NINODES_OFFSET);
X  imapblks = two_bytes(buf + IMAP_BLOCKS_OFFSET);
X  sp->imap_blocks = imapblks;
X  zmapblks = two_bytes(buf + ZMAP_BLOCKS_OFFSET);
X  sp->zmap_blocks = zmapblks;
X  sp->firstdatazone = two_bytes(buf + FIRSTDATAZONE_OFFSET);
X  sp->log_zone_size = two_bytes(buf + LOG_ZONE_SIZE_OFFSET);
X
X  if (sp->version == 1)
X	sp->zones = two_bytes(buf + V1_ZONES_OFFSET);
X  else
X	sp->zones = four_bytes(buf + V2_ZONES_OFFSET);
X
X  sp->inodes_per_block = BLOCK_SIZE / inode_size(sp->version);
X
X  if (imapblks < 0 || zmapblks < 0 || sp->ninodes < 1 || sp->zones < 1)
X	fail("Bad superblock");
X
X
X  if (sp->log_zone_size != 0)
X	fail("Can't swap file systems with different zone and block sizes");
X
X  sp->first_imap_block = SUPER_BLOCK_OFF + 1;
X  sp->first_zmap_block = sp->first_imap_block + sp->imap_blocks;
X  sp->first_inode_block = sp->first_zmap_block + sp->zmap_blocks;
X
X  sp->dzmap_size = sp->zones - sp->firstdatazone;
X  if (verbose_flag) {
X	fprintf(stderr, "nzones = %ld, ", sp->zones);
X	fprintf(stderr, "ninodes = %u, ", sp->ninodes);
X	fprintf(stderr, "first data zone = %ld.\n\n", sp->firstdatazone);
X  }
X}
X
X
Xstatic void get_inode(ip, buf, version)
Xinode_t *ip;
Xchar *buf;
Xint version;
X{
X  int i;
X  int mode;
X
X  if (version == 1) {
X	mode = two_bytes(buf + INODE1_MODE_OFF);
X	ip->size = four_bytes(buf + INODE1_SIZE_OFF);
X	ip->ind1 = two_bytes(buf + INODE1_IND1_OFF);
X	ip->ind2 = two_bytes(buf + INODE1_IND2_OFF);
X	ip->ind3 = 0;
X	for (i = 0; i < NR_DIRECT_ZONES; i++)
X		ip->direct[i] = two_bytes(buf + INODE1_DIRECT_OFF + 2 * i);
X  } else {
X	mode = two_bytes(buf + INODE2_MODE_OFF);
X	ip->size = four_bytes(buf + INODE2_SIZE_OFF);
X	ip->ind1 = four_bytes(buf + INODE2_IND1_OFF);
X	ip->ind2 = four_bytes(buf + INODE2_IND2_OFF);
X	ip->ind3 = four_bytes(buf + INODE2_IND3_OFF);
X	for (i = 0; i < NR_DIRECT_ZONES; i++)
X		ip->direct[i] = four_bytes(buf + INODE2_DIRECT_OFF + 4 * i);
X  }
X
X  if (mode == 0) {
X	if (ip->size % DIR_ENTRY_SIZE == 0)
X		ip->ztype = T_MAYBE_OLD_DIR;
X	else
X		ip->ztype = T_OLD_NON_DIR;
X	if (was_blk_special(*ip)) ip->size = 0;
X  } else {
X	mode = mode & INODE_MODE_MASK;
X	if (mode == INODE_BLK_SPECIAL_MODE || mode == INODE_CHR_SPECIAL_MODE)
X		ip->size = 0;	/* prevent the use of the block numbers. */
X	ip->ztype = (mode == INODE_DIR_MODE) ? T_DIR : T_NON_DIR;
X  }
X}
X
X
Xstatic int check_inode(inode, super)
Xinode_t inode;
Xsuper_t super;
X{
X  int i;
X
X  for (i = 0; i < NR_DIRECT_ZONES; i++)
X	if (!check_blk_number(inode.direct[i], super)) return 0;
X
X  return(check_blk_number(inode.ind1, super) &&
X	check_blk_number(inode.ind2, super) &&
X	check_blk_number(inode.ind3, super));
X}
X
X
Xstatic int check_blk_number(num, super)
Xblockn_t num;
Xsuper_t super;
X{
X  if (num == 0 || (num >= super.firstdatazone && num < super.zones))
X	return 1;
X
X  fprintf(stderr, "warning bad block number %ld in inode.\n", num);
X  return 0;
X}
X
X
Xstatic int was_blk_special(inode)
Xinode_t inode;
X{
X  int i, result;
X  blockn_t block_size;
X
X  if (inode.size % BLOCK_SIZE || inode.ind1) return 0;
X  block_size = inode.size / BLOCK_SIZE;
X
X  for (i = NR_DIRECT_ZONES - 1; i >= 0; i--)
X	if (inode.direct[i] != 0) break;
X
X  result = (i < 1 && block_size > i + 1);
X
X  if (debug_flag && result) {
X	fprintf(stderr, "old block special file detected (slot = %d).\n", i);
X  }
X  return result;
X}
X
X
Xstatic void cw_inode_block(buf, ninodes, version)
Xchar *buf;
Xinodesn_t ninodes;
Xint version;
X{
X  char output_buf[BLOCK_SIZE];
X  char *src, *dst;
X  inodesn_t i;
X  int cnt, free_bytes;
X  int *format;
X
X  src = buf;
X  dst = output_buf;
X
X  format = (version == 1) ? inode1_format : inode2_format;
X  for (i = 0; i < ninodes; i++) {
X	cnt = convcpy(dst, src, format);
X	src += cnt;
X	dst += cnt;
X  }
X
X  assert(cnt == inode_size(version));
X
X  free_bytes = BLOCK_SIZE - (src - buf);
X  assert(free_bytes >= 0);
X  if (verbose_flag && free_bytes > 0) {
X	/* There is a small change that the last free inode has no
X	 * matching bit in the last inode bit map block: e.g. if
X	 * sp->ninodes == 8191. */
X	fprintf(stderr, "%5d bytes (%d inodes) free in last inode block.\n",
X		free_bytes, free_bytes / inode_size(version));
X	memcpy(dst, src, (size_t) free_bytes);
X  }
X  write_block(output_buf);
X}
X
X
Xstatic void proc_ind(dzmap, curr_ind, buf, super)
Xdzmap_t dzmap;
Xsize_t curr_ind;
Xchar *buf;
Xsuper_t super;
X{
X  int indnum, i, ztype;
X  int word_size;		/* size of zone block number in ind. block in
X			 * bytes */
X  unsigned char dz, tmp_dz;
X  blockn_t blk, ind_blk;
X  int bad_range = 0, hidden_zero = 0, zero_flag = 0, expired = 0;
X  size_t blk_index;
X
X  dz = dzmap[curr_ind];
X  indnum = dz & INDIRECT_MASK;
X  ztype = dz & T_MASK;
X  ind_blk = curr_ind + super.firstdatazone;
X
X  word_size = (super.version == 1) ? 2 : 4;
X  assert(indnum > 0);
X
X  for (i = 0; i < BLOCK_SIZE; i += word_size) {
X	if (word_size == 2)
X		blk = two_bytes(buf + i);
X	else
X		blk = four_bytes(buf + i);
X
X	if (blk == 0)
X		zero_flag = 1;
X	else if (blk < super.firstdatazone || blk >= super.zones)
X		bad_range = 1;
X	else {
X		if (zero_flag) hidden_zero = 1;
X		blk_index = blk - super.firstdatazone;
X		tmp_dz = dzmap[blk_index];
X		if (ztype_class(tmp_dz & T_MASK) == In_use_zone) expired = 1;
X	}
X
X  }
X
X  if (ztype_class(ztype) == In_use_zone) {
X	if (bad_range) {
X		fprintf(stderr, "%s zone block contains ", ind_str[indnum]);
X		fail("illegal value");
X	}
X	if ((ztype == T_DIR || indnum > 1) && hidden_zero) {
X		fprintf(stderr, "WARNING: %s zone block %ld contains ",
X			ind_str[indnum], ind_blk);
X		fprintf(stderr, "unexpected zero block numbers\n");
X	}
X  } else {
X	if (expired) {
X		dzmap[curr_ind] &= ~(INDIRECT_MASK & IND_CONFLICT_BIT);
X		return;
X	}
X
X	/* Not yet implemented. :-( if (bad_range || (indnum > 1 &&
X	 * hidden_zero) || equal_values(buf, super.version ) { } */
X  }
X
X  for (i = 0; i < BLOCK_SIZE; i += word_size) {
X	if (word_size == 2)
X		blk = two_bytes(buf + i);
X	else
X		blk = four_bytes(buf + i);
X
X	if (blk == 0) continue;
X	blk_index = blk - super.firstdatazone;
X	tmp_dz = dzmap[blk_index];
X	if (ztype_class(tmp_dz & T_MASK) == In_use_zone) {	/* trouble */
X		if ((tmp_dz & INDIRECT_MASK) == indnum - 1 &&
X		    (tmp_dz & T_MASK) == ztype)
X			fprintf(stderr, "WARNING: %s zone block %ld used more \
Xthan once\n", ind_str[indnum - 1], blk);
X		else {
X			fprintf(stderr, "Block %ld used more than ", blk);
X			fail("once with different types");
X		}
X	}
X	dzmap[blk_index] = (dz & ~INDIRECT_MASK) | (indnum - 1);
X  }
X  dzmap[curr_ind] |= IND_PROCESSED_BIT;
X}
X
X
Xstatic void cw_dir_block(buf)
Xchar *buf;
X{
X  char output_buf[BLOCK_SIZE];
X  int ino, i, old_ino_offset;
X
X  memcpy(output_buf, buf, BLOCK_SIZE);
X
X  for (i = 0; i < BLOCK_SIZE; i += DIR_ENTRY_SIZE) {
X	ino = two_bytes(buf + i);
X	if (ino == 0) {
X		old_ino_offset = i + DIR_ENTRY_SIZE - 2;
X		conv2cpy(output_buf + old_ino_offset, buf + old_ino_offset);
X	} else
X		conv2cpy(output_buf + i, buf + i);
X  }
X  write_block(output_buf);
X}
X
X
Xstatic void dzmap_add_inode(dzmap, inode, super)
Xdzmap_t dzmap;
Xinode_t inode;
Xsuper_t super;
X{
X  int i;
X
X  if (inode.size == 0 || !check_inode(inode, super)) return;
X
X  for (i = 0; i < NR_DIRECT_ZONES; i++)
X	dz_update(dzmap, inode.direct[i], 0, inode.ztype, super);
X
X  dz_update(dzmap, inode.ind1, 1, inode.ztype, super);
X  dz_update(dzmap, inode.ind2, 2, inode.ztype, super);
X  dz_update(dzmap, inode.ind3, 3, inode.ztype, super);
X}
X
X
Xstatic void dz_update(dzmap, blknum, new_indnum, new_ztype, super)
Xdzmap_t dzmap;
Xblockn_t blknum;
Xint new_indnum;
Xint new_ztype;
Xsuper_t super;
X{
X  size_t dznum;
X  int old_indnum;
X  int old_ztype;
X  unsigned char *dz;
X  char new_dz;
X
X
X  if (blknum == 0) return;
X
X  dznum = (size_t) (blknum - super.firstdatazone);
X
X  dz = &dzmap[dznum];
X  old_indnum = *dz & INDIRECT_MASK;
X  old_ztype = *dz & T_MASK;
X
X  new_dz = new_ztype | new_indnum;
X
X  if (ztype_class(new_ztype) > ztype_class(old_ztype)) {
X	*dz = new_dz;
X	return;
X  } else if (ztype_class(new_ztype) < ztype_class(old_ztype))
X	return;
X
X  /* Collision: old and new have the same class */
X
X  if (ztype_class(old_ztype) == In_use_zone) {	/* trouble */
X	if (new_indnum == old_indnum && new_ztype == old_ztype) {
X		fprintf(stderr, "WARNING: file system corrupt, zone block %ld \
Xis used more than once.\n", blknum);
X		return;
X	}
X	fprintf(stderr, "ERROR: file system corrupt, zone block %ld is used \
Xmore than once.\n", blknum);
X	fail("Can't determine its type");
X  }
X  assert(ztype_class(old_ztype) == Old_zone);
X
X
X  if (new_indnum != old_indnum) {
X	*dz |= IND_CONFLICT_BIT;
X	if (new_indnum > old_indnum) {
X		*dz &= ~INDIRECT_MASK;
X		*dz |= new_indnum;
X	}
X  }
X  if (new_ztype == T_MAYBE_OLD_DIR || old_ztype == T_MAYBE_OLD_DIR) {
X	*dz |= TYPE_CONFLICT_BIT;
X	*dz &= ~T_MASK;
X	*dz |= T_MAYBE_OLD_DIR;
X  }
X}
X
X
Xstatic class_t ztype_class(ztype)
Xint ztype;
X{
X  class_t class;
X
X  if (ztype == T_MAYBE_OLD_DIR || ztype == T_OLD_NON_DIR)
X	class = Old_zone;
X  else if (ztype == T_DIR || ztype == T_NON_DIR)
X	class = In_use_zone;
X  else
X	class = Unused_zone;
X
X  return class;
X}
X
X
Xstatic void fail(str)
Xchar *str;
X{
X  fprintf(stderr, "%s\n", str);
X  exit(1);
X}
X
X
Xstatic unsigned int two_bytes(buf)
Xchar buf[2];
X{
X  unsigned char *ubuf = (unsigned char *) buf;
X
X  if (big_endian_fs)
X	return(ubuf[0] << 8) | ubuf[1];
X  else
X	return(ubuf[1] << 8) | ubuf[0];
X}
X
X
Xstatic long four_bytes(buf)
Xchar buf[4];
X{
X  unsigned char *ubuf = (unsigned char *) buf;
X  register int r1, r2;
X
X  if (big_endian_fs) {
X	r1 = (ubuf[0] << 8) | ubuf[1];
X	r2 = (ubuf[2] << 8) | ubuf[3];
X  } else {
X	r2 = (ubuf[1] << 8) | ubuf[0];
X	r1 = (ubuf[3] << 8) | ubuf[2];
X  }
X  return((long) r1 << 16) | r2;
X}
X
X
Xstatic void usage(arg0)
Xchar *arg0;
X{
X  fprintf(stderr, "usage: %s [-v] srcfs [destfs]\n", arg0);
X  exit(2);
X}
/
echo x - term.c
sed '/^X/s///' > term.c << '/'
X/* term - terminal simulator		Author: Andy Tanenbaum */
X
X/* This program allows the user to turn a MINIX system into a dumb
X * terminal to communicate with a remote computer through one of the ttys.
X * It forks into two processes.  The parent sits in a tight loop copying
X * from stdin to the tty.  The child sits in a tight loop copying from
X * the tty to stdout.
X *
X * 2 Sept 88 BDE (Bruce D. Evans): Massive changes to make current settings the
X * default, allow any file as the "tty", support fancy baud rates and remove
X * references to and dependencies on modems and keyboards, so (e.g.)
X * a local login on /dev/tty1 can do an external login on /dev/tty2.
X *
X * 3 Sept 88 BDE: Split parent again to main process copies from stdin to a
X * pipe which is copied to the tty.  This stops a blocked write to the
X * tty from hanging the program.
X *
X * 11 Oct 88 BDE: Cleaned up baud rates and parity stripping.
X *
X * 09 Oct 90 MAT (Michael A. Temari): Fixed bug where terminal isn't reset
X * if an error occurs.
X *
X * Nov 90 BDE: Don't broadcast kill(0, SIGINT) since two or more of these
X * in a row will kill the parent shell.
X *
X * 19 Oct 89 RW (Ralf Wenk): Adapted to MINIX ST 1.1 + RS232 driver. Split
X * error into error_n and error. Added resetting of the terminal settings
X * in error.
X *
X * 24 Nov 90 RW: Adapted to MINIX ST 1.5.10.2. Forked processes are now
X * doing an exec to get a better performance. This idea is stolen from
X * a terminal program written by Felix Croes.
X *
X * 01 May 91 RW: Merged the MINIX ST patches with Andys current version.
X * Most of the 19 Oct 89 patches are deleted because they are already there.
X *
X * Example usage:
X *	term			: baud, bits/char, parity from /dev/tty1
X *	term 9600 7 even	: 9600 baud, 7 bits/char, even parity
X *	term odd 300 7		:  300 baud, 7 bits/char, odd parity
X *	term /dev/tty2		: use /dev/tty2 rather than /dev/tty1
X *				: Any argument starting with "/" is
X *				: taken as the communication device.
X */
X
X#include <sys/types.h>
X#include <minix/config.h>
X#include <fcntl.h>
X#include <sgtty.h>
X#include <signal.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X
X#define MAXARGS  3		/* maximum number of uart params */
X#define CHUNK 1024		/* how much to read at once */
X
X/* Hack some new baud rates for Minix. Minix uses a divide-by-100 encoding. */
X#define B200     2
X#define B600     6
X#define B1800   18
X#define B3600   36
X#define B7200   72
X#define B19200 192
X#define EXTA   192
X
X/* We can't handle some standard (slow) V7 speeds and speeds above 25500 since
X * since the speed is packed into a char :-(. Trap them with an illegal value.
X */
X#define B50      0
X#define B75      0
X#define B134     0
X#define EXTB     0
X#ifndef B38400
X#define B38400   0
X#endif
X#ifndef B57600
X#define B57600   0
X#endif
X#ifndef B115200
X#define B115200  0
X#endif
X
X#define TERM_LINE "/dev/tty1"	/* which serial port to use */
X
Xint commfd;			/* open file no. for comm device */
Xint readpid;			/* pid of child reading commfd */
Xstruct sgttyb sgcommfd;		/* saved terminal parameters for commfd */
Xstruct sgttyb sgstdin;		/* saved terminal parameters for stdin */
Xint writepid;			/* pid of child writing commfd */
X
X/* Sequence to leave simulator.  It must arrive in a single read. */
X#if (MACHINE == ATARI)
X#if 0
Xchar endseq[] = "\033OY";	/* 'F10' (pre 1.6.20) */
X#endif
Xchar endseq[] = "\033[20~";	/* 'F10' */
X#endif
X#if (CHIP == INTEL)
X#if 0
Xchar endseq[] = "\005";		/* Ctrl-E (if no numeric keypad) */
X#endif
Xchar endseq[] = "\033[G";	/* numeric keypad '5' */
X#endif
X
Xstruct param_s {
X  char *pattern;
X  int value;
X  char type;
X#define BAD      0
X#define BITS     1
X#define NOSTRIP  2
X#define PARITY   3
X#define SPEED    4
X}
X
X params[] =
X{
X  "5", BITS5, BITS,
X  "6", BITS6, BITS,
X  "7", BITS7, BITS,
X  "8", BITS8, BITS,
X
X  "even", EVENP, PARITY,
X  "odd", ODDP, PARITY,
X  "nostrip", 0, NOSTRIP,
X
X  "50", B50, SPEED,
X  "75", B75, SPEED,
X  "110", B110, SPEED,
X  "134", B134, SPEED,
X  "200", B200, SPEED,
X  "300", B300, SPEED,
X  "600", B600, SPEED,
X  "1200", B1200, SPEED,
X  "1800", B1800, SPEED,
X  "2400", B2400, SPEED,
X  "3600", B3600, SPEED,
X  "4800", B4800, SPEED,
X  "7200", B7200, SPEED,
X  "9600", B9600, SPEED,
X  "19200", B19200, SPEED,
X  "EXTA", EXTA, SPEED,
X  "EXTB", EXTB, SPEED,
X  "38400", B38400, SPEED,
X  "57600", B57600, SPEED,
X  "115200", B115200, SPEED,
X  "", 0, BAD,			/* BAD type to end list */
X};
Xunsigned char strip_parity = 1;	/* nonzero to strip high bits before output */
X
X_PROTOTYPE(int main, (int argc, char *argv[]));
X_PROTOTYPE(void set_uart, (int argc, char *argv[]));
X_PROTOTYPE(void set_mode, (int fd, int speed, int parity, int bits,
X			   struct sgttyb * sgsavep));
X_PROTOTYPE(void copy, (int in, char *inname, int out,char *outname,char *end));
X_PROTOTYPE(void error, (char *s1, char *s2));
X_PROTOTYPE(void quit, (int dummy));
X_PROTOTYPE(void write2sn, (char *s1, char *s2));
X
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  char *commdev = (char *) NULL;
X  int i;
X  int pipefd[2];
X#if ( CHIP == M68000 )
X  char in[2], out[2];
X  in[1] = out[1] = '\0';
X
X/* Ugly way to process both hidden special arguments "read" or "write" early
X * enough. If one of the special arguments is given the other arguments are
X * ASCII values used by the copy() function. File descriptors are encoded
X * as characters starting with '0'.
X */
X  if (argc > 1 &&
X      (strcmp(argv[1], "-read") == 0 || strcmp(argv[1], "-write") == 0))
X	copy(*argv[2] - '0', argv[3], *argv[4] - '0', argv[5], argv[6]);
X#endif
X
X  sync();
X  for (i = 1; i < argc; ++i)
X	if (argv[i][0] == '/') {
X		if (commdev != (char *) NULL) {
X			write2sn("Too many communication devices", "");
X			exit(1);
X		}
X		commdev = argv[i];
X	}
X  if (commdev == (char *) NULL) {
X	i = MAXARGS + 1;
X	commdev = TERM_LINE;
X  } else
X	i = MAXARGS + 2;
X  if (argc > i) {
X	write2sn("Usage: term [baudrate] [data_bits] [parity]", "");
X	exit(1);
X  }
X  commfd = open(commdev, O_RDWR);
X  if (commfd < 0) {
X	write2sn("Can't open ", commdev);
X	exit(1);
X  }
X
X  /* Save state of both devices before altering either (may be identical!). */
X  ioctl(0, TIOCGETP, &sgstdin);
X  ioctl(commfd, TIOCGETP, &sgcommfd);
X  set_mode(0, -1, -1, -1, &sgstdin);	/* RAW mode on stdin, others
X					 * current */
X  set_uart(argc, argv);
X
X  /* Main body of the terminal simulator. */
X  signal(SIGINT, quit);
X  signal(SIGPIPE, quit);
X  if (pipe(pipefd) < 0) error("Can't create pipe", "");
X  switch ((writepid = fork())) {
X      case -1:
X	error("Can't create process to write to comm device", "");
X      case 0:
X	/* Piped stdin to tty */
X	close(pipefd[1]);
X#if (CHIP == M68000)
X	in[0] = '0' + pipefd[0];
X	out[0] = '0' + commfd;
X	execlp(argv[0], argv[0], "-write", in, "piped stdin", out, commdev, "",
X	       (char *) NULL);
X	/* If execlp() failed, try the usual way. */
X#endif
X	copy(pipefd[0], "piped stdin", commfd, commdev, "");
X  }
X  close(pipefd[0]);
X  switch ((readpid = fork())) {
X      case -1:
X	error("Can't create process to read from comm device", "");
X      case 0:
X	/* Tty to stdout */
X#if (CHIP == M68000)
X	in[0] = '0' + commfd;
X	out[0] = '0' + 1;
X	execlp(argv[0], argv[0], "-read", in, commdev, out, "stdout", "",
X	       (char *) NULL);
X	/* If execlp() failed, try the usual way. */
X#endif
X	copy(commfd, commdev, 1, "stdout", "");
X  }
X
X  /* Stdin to pipe */
X  copy(0, "stdin", pipefd[1], "redirect stdin", endseq);
X  return(0);
X}
X
X
Xvoid set_uart(argc, argv)
Xint argc;
Xchar *argv[];
X{
X/* Set up the UART parameters. */
X
X  int i, j, bits, nbits, parity, nparities, speed, nspeeds;
X  char *arg;
X  register struct param_s *param;
X
X  /* Examine all the parameters and check for validity. */
X  nspeeds = nparities = nbits = 0;
X  speed = parity = bits = -1;	/* -1 means use current value */
X  for (i = 1; i < argc; ++i) {
X	if ((arg = argv[i])[0] == '/') continue;
X
X	/* Check parameter for legality. */
X	for (j = 0, param = &params[0];
X	     param->type != BAD && strcmp(arg, param->pattern) != 0;
X	     ++j, ++param);
X	switch (param->type) {
X	    case BAD:
X		error("Invalid parameter: ", arg);
X	    case BITS:
X		bits = param->value;
X		if (++nbits > 1) error("Too many character sizes", "");
X		break;
X	    case PARITY:
X		parity = param->value;
X		if (++nparities > 1) error("Too many parities", "");
X		break;
X	    case SPEED:
X		speed = param->value;
X		if (speed == 0) error("Invalid speed: ", arg);
X		if (++nspeeds > 1) error("Too many speeds", "");
X		break;
X	    case NOSTRIP:	strip_parity = 0;	break;
X	}
X  }
X  set_mode(commfd, speed, parity, bits, &sgcommfd);
X}
X
X
Xvoid set_mode(fd, speed, parity, bits, sgsavep)
Xint fd;
Xint speed;
Xint parity;
Xint bits;
Xstruct sgttyb *sgsavep;
X{
X  /* Set open file fd to RAW mode with the given other modes. If fd is
X   * not a tty, this may do nothing but connecting ordinary files as
X   * ttys may have some use. */
X
X  struct sgttyb sgtty;
X  int tabs;
X
X  sgtty = *sgsavep;
X  tabs = sgtty.sg_flags & XTABS;
X  if (speed == -1) speed = sgtty.sg_ispeed;
X  if (parity == -1) parity = sgtty.sg_flags & (EVENP | ODDP);
X  if (bits == -1)
X	bits = sgtty.sg_flags & BITS8;	/* BITS8 is actually a mask */
X  sgtty.sg_ispeed = speed;
X  sgtty.sg_ospeed = speed;
X  sgtty.sg_flags = RAW | parity | bits | tabs;
X  ioctl(fd, TIOCSETP, &sgtty);
X}
X
X
Xvoid copy(in, inname, out, outname, end)
Xint in;
Xchar *inname;
Xint out;
Xchar *outname;
Xchar *end;
X{
X/* Copy from one open file to another. If the 'end' sequence is not "", and
X * precisely matches the input, terminate the copy and various children.
X * The end sequence is best provided by keyboard input from one of the
X * special keys which always produces chars in a bunch. RAW mode almost
X * guarantees exactly one keystroke's worth of input at a time.
X */
X
X  static char buf[CHUNK];
X  char *bufend;
X  register char *bufp;
X  int count;
X  int len;
X
X  len = strlen(end);
X  while (1) {
X	if ((count = read(in, buf, CHUNK)) <= 0) {
X		write2sn("Can't read from ", inname);
X		quit(0);
X	}
X	if (count == len && strncmp(buf, end, (size_t) count) == 0) quit(0);
X	if (strip_parity) for (bufp = buf, bufend = bufp + count;
X		     bufp < bufend; ++bufp)
X			*bufp &= 0x7F;
X	if (write(out, buf, (size_t) count) != count) {
X		write2sn("Can't write to ", outname);
X		quit(0);
X	}
X  }
X}
X
X
Xvoid error(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X  ioctl(commfd, TIOCSETP, &sgcommfd);
X  ioctl(0, TIOCSETP, &sgstdin);
X  write2sn(s1, s2);
X  exit(1);
X}
X
X
Xvoid quit(s)
Xint s;				/* not used, just to make prototype ok */
X{
X  if (readpid != 0 && writepid != 0) {
X	/* This is the parent of the other two processes.  It cleans up. */
X	ioctl(commfd, TIOCSETP, &sgcommfd);
X	ioctl(0, TIOCSETP, &sgstdin);
X	kill(readpid, SIGINT);
X	kill(writepid, SIGINT);
X  }
X  exit(0);
X}
X
X
Xvoid write2sn(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X  write(1, s1, strlen(s1));
X  write(1, s2, strlen(s2));
X  write(1, "\r\n", 2);
X}
/
echo x - uname.c
sed '/^X/s///' > uname.c << '/'
X/*  uname - print system name			Author: Earl Chew */
X
X/* The system name is printed based on the file /etc/uname. This should be
X * world readable but only writeable by system administrators. The
X * file contains lines of text. Lines beginning with # are treated
X * as comments. All other lines contain information to be read into
X * the uname structure. The sequence of the lines matches the sequence
X * in which the structure components are declared:
X *
X *	system name		Minix
X *	node name		waddles
X *	release name		1.5
X *	version			10
X *	machine name		IBM_PC
X *	serial number		N/A
X */
X
X#include <sys/types.h>
X#include <sys/utsname.h>
X#include <stdarg.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X
X/* Define the uname components. */
X#define ALL	 ((unsigned) ~0x0)
X#define SYSNAME  ((unsigned) 0x01)
X#define NODENAME ((unsigned) 0x02)
X#define RELEASE  ((unsigned) 0x04)
X#define VERSION  ((unsigned) 0x08)
X#define MACHINE  ((unsigned) 0x10)
X
X_PROTOTYPE(int main, (int argc, char **argv ));
X_PROTOTYPE(void print, (int fd, ... ));
X_PROTOTYPE(void usage, (void ));
X
X#ifdef __STDC__
Xvoid print(int fd, ...)
X#else
Xvoid print(fd)
Xint fd;
X#endif
X{
X/* Print a sequence of strings onto the named channel. */
X  va_list argp;
X  char *p;
X
X  va_start(argp, fd);
X  while (1) {
X	p = va_arg(argp, char *);
X	if (p == (char *) NULL) break;
X	write(fd, p, strlen(p));
X  }
X  va_end(argp);
X}
X
Xvoid usage()
X{
X  print(STDERR_FILENO, "Usage: uname -amnrsv\n", (char *) NULL);
X  exit(EXIT_FAILURE);
X}
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X  int info;
X  char *p;
X  struct utsname un;
X
X  for (info = 0; argc > 1; argc--, argv++) {
X  	if (argv[1][0] == '-') {
X  		for (p = &argv[1][1]; *p; p++) {
X  			switch (*p) {
X				case 'a': info |= ALL;      break;
X				case 'm': info |= MACHINE;  break;
X				case 'n': info |= NODENAME; break;
X				case 'r': info |= RELEASE;  break;
X				case 's': info |= SYSNAME;  break;
X				case 'v': info |= VERSION;  break;
X				default: usage();
X  			}
X		}
X	} else {
X		usage();
X	}
X  }
X
X  if (uname(&un) != 0) {
X	print(STDERR_FILENO, "unable to determine uname values\n", (char *) NULL);
X	exit(EXIT_FAILURE);
X  }
X
X  if (info == 0 || (info & SYSNAME) != 0)
X	print(STDOUT_FILENO, un.sysname, (char *) NULL);
X  if ((info & NODENAME) != 0) {
X	if ((info & (SYSNAME)) != 0)
X		print(STDOUT_FILENO, " ", (char *) NULL);
X	print(STDOUT_FILENO, un.nodename, (char *) NULL);
X  }
X  if ((info & RELEASE) != 0) {
X	if ((info & (SYSNAME|NODENAME)) != 0)
X		print(STDOUT_FILENO, " ", (char *) NULL);
X	print(STDOUT_FILENO, un.release, (char *) NULL);
X  }
X  if ((info & VERSION) != 0) {
X	if ((info & (SYSNAME|NODENAME|RELEASE)) != 0)
X		print(STDOUT_FILENO, " ", (char *) NULL);
X	print(STDOUT_FILENO, un.version, (char *) NULL);
X  }
X  if ((info & MACHINE) != 0) {
X	if ((info & (SYSNAME|NODENAME|RELEASE|VERSION)) != 0)
X		print(STDOUT_FILENO, " ", (char *) NULL);
X	print(STDOUT_FILENO, un.machine, (char *) NULL);
X  }
X  print(STDOUT_FILENO, "\n", (char *) NULL);
X  return EXIT_SUCCESS;
X}
/
echo x - xargs.c
sed '/^X/s///' > xargs.c << '/'
X/* xargs - Make and execute commands	     Author: Ian Nicholls:  1 Mar 90 */
X
X/*
X * xargs  - Accept words from stdin until, combined with the arguments
X *	    given on the command line, just fit into the command line limit.
X *	    Then, execute the result.
X * 		e.g.    ls | xargs compress
X *			find . -name '*.s' -print | xargs ar qv libc.a
X *
X * flags: -t		Print the command just before it is run
X *	  -l len	Use len as maximum line length (default 490, max 1023)
X *	  -e ending	Append ending to the command before executing it.
X *
X * Exits with:	0  No errors.
X *		1  If any system(3) call returns a nonzero status.
X *		2  Usage error
X *		3  Line length too short to contain some single argument.
X *
X * Examples:	xargs ar qv libc.a < liborder		# Create a new libc.a
X *		find . -name '*.s' -print | xargs rm	# Remove all .s files
X *		find . -type f ! -name '*.Z' \		# Compress old files.
X *		       -atime +60 -print  | xargs compress -v
X *
X * Bugs:  If the command contains unquoted wildflags, then the system(3) call
X *		call may expand this to larger than the maximum line size.
X *	  The command is not executed if nothing was read from stdin.
X *	  xargs may give up too easily when the command returns nonzero.
X */
X#define USAGE "usage: xargs [-t] [-l len] [-e endargs] command [args...]\n"
X
X#include <errno.h>
X#include <stdlib.h>
X#include <string.h>
X#include <stdio.h>
X
Xextern int optind;
Xextern char *optarg;
X
X#ifndef MAX_ARGLINE
X# define MAX_ARGLINE 1023
X#endif
X#ifndef min
X# define min(a,b) ((a) < (b) ? (a) : (b))
X#endif
X
Xchar outlin[MAX_ARGLINE];
Xchar inlin[MAX_ARGLINE];
Xchar startlin[MAX_ARGLINE];
Xchar *ending = NULL;
Xchar traceflag = 0;
X
X_PROTOTYPE(int main, (int argc, char **argv));
X
Xint main(ac,av)
Xint ac;
Xchar *av[];
X{
X   int outlen, inlen, startlen, endlen=0, i;
X   char errflg = 0;
X   int maxlin = MAX_ARGLINE;
X
X   while ((i = getopt(ac, av, "tl:e:")) != EOF)
X       switch (i) {
X	   case 't': traceflag = 1;	  break;
X	   case 'l': maxlin = min(MAX_ARGLINE, atoi(optarg)); break;
X	   case 'e': ending = optarg;	  break;
X	   case '?': errflg++;		  break;
X       }
X   if (errflg)	{
X       fprintf(stderr, USAGE);
X       exit(2);
X   }
X
X   startlin[0] = 0;
X   if (optind == ac) {
X       strcat(startlin, "echo ");
X   }
X   else for ( ; optind < ac; optind++) {
X       strcat(startlin, av[optind]);
X       strcat(startlin, " ");
X   }
X   startlen = strlen(startlin);
X   if (ending) endlen = strlen(ending);
X   maxlin = maxlin - 1 - endlen;	/* Pre-compute */
X
X   strcpy(outlin, startlin);
X   outlen = startlen;
X
X   while (gets(inlin) != NULL) {
X       inlen = strlen(inlin);
X       if (maxlin <= (outlen + inlen)) {
X	   if (outlen == startlen) {
X	       fprintf(stderr, "%s: Line length too short to process '%s'\n",
X		       av[0], inlin);
X	       exit(3);
X	   }
X	   if (ending) strcat(outlin, ending);
X	   if (traceflag) fputs(outlin,stderr);
X	   errno = 0;
X	   if (0 != system(outlin)) {
X	       if (errno != 0) perror("xargs");
X	       exit(1);
X	   }
X	   strcpy(outlin, startlin);
X	   outlen = startlen;
X       }
X       strcat(outlin, inlin);
X       strcat(outlin, " ");
X       outlen = outlen + inlen + 1;
X   }
X   if (outlen != startlen) {
X       if (ending) strcat(outlin, ending);
X       if (traceflag) fputs(outlin,stderr);
X       errno = 0;
X       if (0 != system(outlin)) {
X	   if (errno != 0) perror("xargs");
X	   exit(1);
X       }
X   }    
X   return 0;
X}
/
echo x - simple.cd
sed '/^X/s///' > simple.cd << '/'
Xecho x - animals.c.d
Xsed '/^X/s///' > animals.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/animals.c  crc=15992   5677	Sun Apr 25 21:34:44 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/animals.c  crc=37998   6167	Wed Nov  4 04:19:03 1992
XX***************
XX*** 6,11 ****
XX--- 6,14 ----
XX  #include <sgtty.h>
XX  #include <ctype.h>
XX  #include <unistd.h>
XX+ #include <stdlib.h>
XX+ #include <sys/stat.h>
XX+ #include <minix/minlib.h>
XX  #include <stdio.h>
XX  
XX  #define  ANIMALS	"/usr/lib/animals"
XX***************
XX*** 13,23 ****
XX  #define  MAX_NODES	999	/* Enough for 500 animals  */
XX  #define  MAX_LINE	90
XX  
XX! void Abort();
XX! char *Get_Animal();
XX! char *Get_Question();
XX! char *A_or_An();
XX! char *Alloc();
XX  
XX  struct node {
XX    int question;
XX--- 16,31 ----
XX  #define  MAX_NODES	999	/* Enough for 500 animals  */
XX  #define  MAX_LINE	90
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void Read_Animals, (char *animal_file));
XX! _PROTOTYPE(void Write_Animals, (char *animal_file));
XX! _PROTOTYPE(int Ask, (char *question));
XX! _PROTOTYPE(char *Get_Animal, (void));
XX! _PROTOTYPE(char *Get_Question, (void));
XX! _PROTOTYPE(char *A_or_An, (char *word));
XX! _PROTOTYPE(char *Alloc, (int size));
XX! _PROTOTYPE(void Abort, (int dummy));
XX! _PROTOTYPE(void Error, (char *message));
XX  
XX  struct node {
XX    int question;
XX***************
XX*** 30,39 ****
XX  struct sgttyb old_tty_mode;
XX  
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX- 
XX  {
XX    char *animal_file = ANIMALS;
XX  
XX--- 38,46 ----
XX  struct sgttyb old_tty_mode;
XX  
XX  
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX    char *animal_file = ANIMALS;
XX  
XX***************
XX*** 122,135 ****
XX    sleep(1);
XX    printf("\nBye.\n");
XX  
XX!   exit(0);
XX  }
XX  
XX  
XX  /*  Reading and writing the animal data base */
XX  
XX  
XX! Read_Animals(animal_file)
XX  char *animal_file;
XX  
XX  {
XX--- 129,142 ----
XX    sleep(1);
XX    printf("\nBye.\n");
XX  
XX!   return(0);
XX  }
XX  
XX  
XX  /*  Reading and writing the animal data base */
XX  
XX  
XX! void Read_Animals(animal_file)
XX  char *animal_file;
XX  
XX  {
XX***************
XX*** 160,166 ****
XX  	string = Alloc(string_length + 1);
XX  
XX  	string[0] = '\0';
XX! 	strncat(string, buffer + 1, string_length);
XX  
XX  	animals[count].text = string;
XX  
XX--- 167,173 ----
XX  	string = Alloc(string_length + 1);
XX  
XX  	string[0] = '\0';
XX! 	strncat(string, buffer + 1, (size_t)string_length);
XX  
XX  	animals[count].text = string;
XX  
XX***************
XX*** 171,177 ****
XX  }
XX  
XX  
XX! Write_Animals(animal_file)
XX  char *animal_file;
XX  
XX  {
XX--- 178,184 ----
XX  }
XX  
XX  
XX! void Write_Animals(animal_file)
XX  char *animal_file;
XX  
XX  {
XX***************
XX*** 232,238 ****
XX    text_length = strlen(s);
XX    text = Alloc(text_length);
XX    text[0] = '\0';
XX!   strncat(text, s, text_length - 1);
XX    return(text);
XX  }
XX  
XX--- 239,245 ----
XX    text_length = strlen(s);
XX    text = Alloc(text_length);
XX    text[0] = '\0';
XX!   strncat(text, s, (size_t)(text_length - 1));
XX    return(text);
XX  }
XX  
XX***************
XX*** 274,290 ****
XX  char *Alloc(size)
XX  int size;
XX  {
XX-   char *malloc();
XX    char *memory;
XX  
XX!   if ((memory = malloc(size)) == NULL)
XX  	Error("No room in memory for all the animals");
XX  
XX    return(memory);
XX  }
XX  
XX  
XX! void Abort()
XX  {
XX    ioctl(0, TIOCSETP, &old_tty_mode);
XX  
XX--- 281,297 ----
XX  char *Alloc(size)
XX  int size;
XX  {
XX    char *memory;
XX  
XX!   if ((memory = (char *)malloc((size_t)size)) == NULL)
XX  	Error("No room in memory for all the animals");
XX  
XX    return(memory);
XX  }
XX  
XX  
XX! void Abort(dummy)
XX! int dummy; /* to keep the compiler happy */
XX  {
XX    ioctl(0, TIOCSETP, &old_tty_mode);
XX  
XX***************
XX*** 296,302 ****
XX  }
XX  
XX  
XX! Error(message)
XX  char *message;
XX  {
XX    ioctl(0, TIOCSETP, &old_tty_mode);
XX--- 303,309 ----
XX  }
XX  
XX  
XX! void Error(message)
XX  char *message;
XX  {
XX    ioctl(0, TIOCSETP, &old_tty_mode);
X/
Xecho x - ascii.c.d
Xsed '/^X/s///' > ascii.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/ascii.c  crc=19229   2115	Sun Apr 25 21:34:44 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/ascii.c  crc=29389   2270	Wed Nov  4 04:19:03 1992
XX***************
XX*** 4,9 ****
XX--- 4,11 ----
XX  #include <fcntl.h>
XX  #include <unistd.h>
XX  #include <string.h>
XX+ #include <stdlib.h>
XX+ #include <minix/minlib.h>
XX  #include <stdio.h>
XX  
XX  #define BUFSIZE 4*1024
XX***************
XX*** 11,16 ****
XX--- 13,20 ----
XX  static char buf[BUFSIZE + 1];	/* input buffer - +1 for sentinel */
XX  static char carry[BUFSIZE];	/* buffer for partial line carryover */
XX  
XX+ _PROTOTYPE(int main, (int argc, char **argv));
XX+ 
XX  int main(argc, argv)
XX  int argc;
XX  char **argv;
XX***************
XX*** 58,72 ****
XX  		if ((*end & 0x80) != 0) {
XX  			ascii_line = 0;
XX  			ascii_file = 0;
XX! 			end = (char *) memchr(end, '\n', BUFSIZE);
XX  			break;
XX  		}
XX  	if (end != sentinel) {
XX  		++end;
XX  		if (ascii_line != nflag) {
XX  			if (carry_count != 0)
XX! 				fwrite(carry, carry_count, 1, stdout);
XX! 			fwrite(start, (int)(end - start), 1, stdout);
XX  		}
XX  		carry_count = 0;
XX  		start = end;
XX--- 62,76 ----
XX  		if ((*end & 0x80) != 0) {
XX  			ascii_line = 0;
XX  			ascii_file = 0;
XX! 			end = (char *) memchr(end, '\n', (size_t)BUFSIZE);
XX  			break;
XX  		}
XX  	if (end != sentinel) {
XX  		++end;
XX  		if (ascii_line != nflag) {
XX  			if (carry_count != 0)
XX! 				fwrite(carry, (size_t)carry_count, (size_t)1, stdout);
XX! 			fwrite(start, (size_t)(end - start), (size_t)1, stdout);
XX  		}
XX  		carry_count = 0;
XX  		start = end;
XX***************
XX*** 78,84 ****
XX  		}
XX  		if (ascii_line != nflag) {
XX  			carry_count = end - start;
XX! 			memcpy(carry, start, carry_count);
XX  		}
XX  		if ((count = read(0, buf, BUFSIZE)) <= 0) break;
XX  		*(sentinel = &buf[count]) = '\n';
XX--- 82,88 ----
XX  		}
XX  		if (ascii_line != nflag) {
XX  			carry_count = end - start;
XX! 			memcpy(carry, start, (size_t)carry_count);
XX  		}
XX  		if ((count = read(0, buf, BUFSIZE)) <= 0) break;
XX  		*(sentinel = &buf[count]) = '\n';
XX***************
XX*** 86,92 ****
XX  	}
XX    }
XX    if (ascii_line != nflag && carry_count != 0)
XX! 	fwrite(carry, carry_count, 1, stdout);
XX  
XX!   exit(ascii_file == 0);
XX  }
XX--- 90,96 ----
XX  	}
XX    }
XX    if (ascii_line != nflag && carry_count != 0)
XX! 	fwrite(carry, (size_t)carry_count, (size_t)1, stdout);
XX  
XX!   return(ascii_file == 0);
XX  }
X/
Xecho x - at.c.d
Xsed '/^X/s///' > at.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/at.c  crc=62419   4819	Sun Apr 25 21:34:45 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/at.c  crc=60318   5181	Wed Nov  4 04:19:03 1992
XX***************
XX*** 3,8 ****
XX--- 3,12 ----
XX  #include <sys/types.h>
XX  #include <time.h>
XX  #include <fcntl.h>
XX+ #include <unistd.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <sys/stat.h>
XX  #include <stdio.h>
XX  
XX  #define	STARTDAY	0	/* see ctime(3)	 */
XX***************
XX*** 10,25 ****
XX  #define	MAXDAYNR	STARTDAY+365
XX  #define	NODAY		-2
XX  
XX  
XX! main(argc, argv, envp)
XX  int argc;
XX  char **argv, **envp;
XX  {
XX!   int i, count, ltim, year, getltim(), getlday(), lday = NODAY;
XX!   char c, buf[10], job[30], *dp, *sp;
XX!   struct tm *p, *localtime();
XX!   long clock;
XX!   FILE *fp, *pin, *popen();
XX  
XX  /*-------------------------------------------------------------------------*
XX   *	check arguments	& pipe to "pwd"				           *
XX--- 14,33 ----
XX  #define	MAXDAYNR	STARTDAY+365
XX  #define	NODAY		-2
XX  
XX+ _PROTOTYPE(int main, (int argc, char **argv, char **envp));
XX+ _PROTOTYPE(int getltim, (char *t));
XX+ _PROTOTYPE(int getlday, (char *m, char *d));
XX+ _PROTOTYPE(int digitstring, (char *s));
XX  
XX! int main(argc, argv, envp)
XX  int argc;
XX  char **argv, **envp;
XX  {
XX!   int i, c, count, ltim, year, lday = NODAY;
XX!   char buf[10], job[30], *dp, *sp;
XX!   struct tm *p;
XX!   long clk;
XX!   FILE *fp, *pin;
XX  
XX  /*-------------------------------------------------------------------------*
XX   *	check arguments	& pipe to "pwd"				           *
XX***************
XX*** 48,61 ****
XX  /*-------------------------------------------------------------------------*
XX   *	determine execution time and create 'at' job file		   *
XX   *-------------------------------------------------------------------------*/
XX!   time(&clock);
XX!   p = localtime(&clock);
XX    year = p->tm_year;
XX    if (lday == NODAY) {		/* no [month day] given */
XX  	lday = p->tm_yday;
XX  	if (ltim <= (p->tm_hour * 100 + p->tm_min)) {
XX  		lday++;
XX! 		if (lday == MAXDAYNR && (year % 4) || lday == MAXDAYNR + 1) {
XX  			lday = STARTDAY;
XX  			year++;
XX  		}
XX--- 56,69 ----
XX  /*-------------------------------------------------------------------------*
XX   *	determine execution time and create 'at' job file		   *
XX   *-------------------------------------------------------------------------*/
XX!   time(&clk);
XX!   p = localtime(&clk);
XX    year = p->tm_year;
XX    if (lday == NODAY) {		/* no [month day] given */
XX  	lday = p->tm_yday;
XX  	if (ltim <= (p->tm_hour * 100 + p->tm_min)) {
XX  		lday++;
XX! 		if ((lday == MAXDAYNR && (year % 4)) || lday == MAXDAYNR + 1) {
XX  			lday = STARTDAY;
XX  			year++;
XX  		}
XX***************
XX*** 63,70 ****
XX    } else
XX  	switch (year % 4) {
XX  	    case 0:
XX! 		if (lday < p->tm_yday || lday == p->tm_yday &&
XX! 		    ltim <= (p->tm_hour * 100 + p->tm_min)) {
XX  			year++;
XX  			if (lday > LEAPDAY) lday--;
XX  		}
XX--- 71,79 ----
XX    } else
XX  	switch (year % 4) {
XX  	    case 0:
XX! 		if (lday < p->tm_yday ||
XX! 		    (lday == p->tm_yday &&
XX! 		    ltim <= (p->tm_hour * 100 + p->tm_min))) {
XX  			year++;
XX  			if (lday > LEAPDAY) lday--;
XX  		}
XX***************
XX*** 72,85 ****
XX  	    case 1:
XX  	    case 2:
XX  		if (lday > LEAPDAY) lday--;
XX! 		if (lday < p->tm_yday || lday == p->tm_yday &&
XX! 		    ltim <= (p->tm_hour * 100 + p->tm_min))
XX  			year++;
XX  		break;
XX  	    case 3:
XX  		if (lday < ((lday > LEAPDAY) ? p->tm_yday + 1 : p->tm_yday) ||
XX! 		    lday == ((lday > LEAPDAY) ? p->tm_yday + 1 : p->tm_yday) &&
XX! 		    ltim <= (p->tm_hour * 100 + p->tm_min))
XX  			year++;
XX  		else if (lday > LEAPDAY)
XX  			lday--;
XX--- 81,95 ----
XX  	    case 1:
XX  	    case 2:
XX  		if (lday > LEAPDAY) lday--;
XX! 		if (lday < p->tm_yday ||
XX! 		    (lday == p->tm_yday &&
XX! 		     ltim <= (p->tm_hour * 100 + p->tm_min)))
XX  			year++;
XX  		break;
XX  	    case 3:
XX  		if (lday < ((lday > LEAPDAY) ? p->tm_yday + 1 : p->tm_yday) ||
XX! 		    (lday ==((lday > LEAPDAY) ? p->tm_yday + 1 : p->tm_yday) &&
XX! 		     ltim <= (p->tm_hour * 100 + p->tm_min)))
XX  			year++;
XX  		else if (lday > LEAPDAY)
XX  			lday--;
XX***************
XX*** 106,130 ****
XX    }
XX    fprintf(fp, "cd ");
XX    while ((c = getc(pin)) != EOF) putc(c, fp);
XX!   fprintf(fp, "umask %o\n", umask());
XX    if (argc == 3 || argc == 5)
XX  	fprintf(fp, "%s\n", argv[argc - 1]);
XX    else				/* read from stdinput */
XX  	while ((c = getchar()) != EOF) putc(c, fp);
XX  
XX    printf("%s: %s created\n", argv[0], job);
XX!   exit(0);
XX  }
XX  
XX  /*-------------------------------------------------------------------------*
XX   *	getltim()		return((time OK) ? daytime : -1)	   *
XX   *-------------------------------------------------------------------------*/
XX! getltim(t)
XX  char *t;
XX  {
XX    if (t[4] == '\0' && t[3] >= '0' && t[3] <= '9' &&
XX        t[2] >= '0' && t[2] <= '5' && t[1] >= '0' && t[1] <= '9' &&
XX!       (t[0] == '0' || t[0] == '1' || t[1] <= '3' && t[0] == '2'))
XX  	return(atoi(t));
XX    else
XX  	return(-1);
XX--- 116,143 ----
XX    }
XX    fprintf(fp, "cd ");
XX    while ((c = getc(pin)) != EOF) putc(c, fp);
XX!   fprintf(fp, "umask %o\n", umask(0));
XX    if (argc == 3 || argc == 5)
XX  	fprintf(fp, "%s\n", argv[argc - 1]);
XX    else				/* read from stdinput */
XX  	while ((c = getchar()) != EOF) putc(c, fp);
XX+   fclose(fp);
XX  
XX+   if (chown(job, getuid(), getgid()) == -1)
XX+ 	unlink(job);		 /* else there could be a security hole */
XX    printf("%s: %s created\n", argv[0], job);
XX!   return(0);
XX  }
XX  
XX  /*-------------------------------------------------------------------------*
XX   *	getltim()		return((time OK) ? daytime : -1)	   *
XX   *-------------------------------------------------------------------------*/
XX! int getltim(t)
XX  char *t;
XX  {
XX    if (t[4] == '\0' && t[3] >= '0' && t[3] <= '9' &&
XX        t[2] >= '0' && t[2] <= '5' && t[1] >= '0' && t[1] <= '9' &&
XX!       (t[0] == '0' || t[0] == '1' || (t[1] <= '3' && t[0] == '2')))
XX  	return(atoi(t));
XX    else
XX  	return(-1);
XX***************
XX*** 133,142 ****
XX  /*-------------------------------------------------------------------------*
XX   *	getlday()		return ((date OK) ? yearday : -1)	   *
XX   *-------------------------------------------------------------------------*/
XX! getlday(m, d)
XX  char *m, *d;
XX  {
XX!   int i, month, day, im;
XX    static int cumday[] = {0, 0, 31, 60, 91, 121, 152,
XX  		       182, 213, 244, 274, 305, 335};
XX    static struct date {
XX--- 146,155 ----
XX  /*-------------------------------------------------------------------------*
XX   *	getlday()		return ((date OK) ? yearday : -1)	   *
XX   *-------------------------------------------------------------------------*/
XX! int getlday(m, d)
XX  char *m, *d;
XX  {
XX!   int i, day, im;
XX    static int cumday[] = {0, 0, 31, 60, 91, 121, 152,
XX  		       182, 213, 244, 274, 305, 335};
XX    static struct date {
XX***************
XX*** 162,168 ****
XX  
XX  
XX  
XX! digitstring(s)
XX  char *s;
XX  {
XX    while (*s >= '0' && *s <= '9') s++;
XX--- 175,181 ----
XX  
XX  
XX  
XX! int digitstring(s)
XX  char *s;
XX  {
XX    while (*s >= '0' && *s <= '9') s++;
X/
Xecho x - atrun.c.d
Xsed '/^X/s///' > atrun.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/atrun.c  crc=02442   1817	Sun Apr 25 21:34:45 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/atrun.c  crc=52423   1905	Wed Nov  4 07:51:31 1992
XX***************
XX*** 4,53 ****
XX   *	atrun scans directory /usr/spool/at for 'at' jobs to be executed.  *
XX   *	Finished jobs have been moved to directory /usr/spool/at/past.     *
XX   *-------------------------------------------------------------------------*/
XX  #include <sys/types.h>
XX  #include <sys/dir.h>
XX  #include <sys/stat.h>
XX  #include <fcntl.h>
XX  #include <limits.h>
XX  #include <time.h>
XX  #include <stdio.h>
XX  
XX! main()
XX  {
XX-   int fd, nr;
XX    char realtime[15], procname[35], procpast[35];
XX!   struct direct dirbuf;
XX!   struct tm *p, *localtime();
XX    struct stat sbuf;
XX!   time_t clock;
XX  
XX  /*-------------------------------------------------------------------------*
XX   *	Compute real time,  move 'at' jobs whose filenames < real time to  *
XX   *	/usr/spool/at/past and start a sh for each job.			   *
XX   *-------------------------------------------------------------------------*/
XX!   time(&clock);
XX!   p = localtime(&clock);
XX    sprintf(realtime, "%02d.%03d.%02d%02d.00",
XX  	p->tm_year % 100, p->tm_yday, p->tm_hour, p->tm_min);
XX!   if ((fd = open("/usr/spool/at", O_RDONLY)) > 0)
XX! 	while (read(fd, (char *) &dirbuf, sizeof(dirbuf)) > 0)
XX! 		if (dirbuf.d_ino > 0 &&
XX! 		    dirbuf.d_name[0] != '.' &&
XX! 		    dirbuf.d_name[0] != 'p' &&
XX! 		    strncmp(dirbuf.d_name, realtime, 11) <= 0) {
XX  
XX! 			sprintf(procname, "/usr/spool/at/%.14s", dirbuf.d_name);
XX! 			sprintf(procpast, "/usr/spool/at/past/%.14s", dirbuf.d_name);
XX  
XX  			if (fork() == 0)	/* code for child */
XX  				if (link(procname, procpast) == 0) {	/* link ok? */
XX  					unlink(procname);
XX  					stat(procpast, &sbuf);
XX! 					setgid(sbuf.st_uid);
XX! 					setuid(sbuf.st_gid);
XX  					execl("/bin/sh", "sh", procpast, (char *) 0);
XX  					fprintf(stderr, "proc %s can't start\n", procpast);
XX  					exit(1);
XX  				}
XX  		}
XX  }
XX--- 4,61 ----
XX   *	atrun scans directory /usr/spool/at for 'at' jobs to be executed.  *
XX   *	Finished jobs have been moved to directory /usr/spool/at/past.     *
XX   *-------------------------------------------------------------------------*/
XX+ 
XX  #include <sys/types.h>
XX  #include <sys/dir.h>
XX  #include <sys/stat.h>
XX  #include <fcntl.h>
XX  #include <limits.h>
XX  #include <time.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX+ #include <dirent.h>
XX  
XX! _PROTOTYPE(int main, (void));
XX! 
XX! int main()
XX  {
XX    char realtime[15], procname[35], procpast[35];
XX!   DIR *dir;
XX!   struct dirent *entry;
XX!   struct tm *p;
XX    struct stat sbuf;
XX!   time_t clk;
XX  
XX  /*-------------------------------------------------------------------------*
XX   *	Compute real time,  move 'at' jobs whose filenames < real time to  *
XX   *	/usr/spool/at/past and start a sh for each job.			   *
XX   *-------------------------------------------------------------------------*/
XX!   time(&clk);
XX!   p = localtime(&clk);
XX    sprintf(realtime, "%02d.%03d.%02d%02d.00",
XX  	p->tm_year % 100, p->tm_yday, p->tm_hour, p->tm_min);
XX!   if ((dir = opendir("/usr/spool/at")) != NULL)
XX! 	while ((entry = readdir(dir)) != NULL)
XX! 		if (entry->d_ino > 0 &&
XX! 		    entry->d_name[0] != '.' &&
XX! 		    entry->d_name[0] != 'p' &&
XX! 		strncmp(entry->d_name, realtime, (size_t) 11) <= 0) {
XX  
XX! 			sprintf(procname, "/usr/spool/at/%s", entry->d_name);
XX! 			sprintf(procpast, "/usr/spool/at/past/%s", entry->d_name);
XX  
XX  			if (fork() == 0)	/* code for child */
XX  				if (link(procname, procpast) == 0) {	/* link ok? */
XX  					unlink(procname);
XX  					stat(procpast, &sbuf);
XX! 					setgid(sbuf.st_gid);
XX! 					setuid(sbuf.st_uid);
XX  					execl("/bin/sh", "sh", procpast, (char *) 0);
XX  					fprintf(stderr, "proc %s can't start\n", procpast);
XX  					exit(1);
XX  				}
XX  		}
XX+   return(0);
XX  }
X/
Xecho x - backup.c.d
Xsed '/^X/s///' > backup.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/backup.c  crc=35148  12464	Sun Apr 25 21:34:45 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/backup.c  crc=47386  14512	Wed Nov  4 04:19:03 1992
XX***************
XX*** 17,35 ****
XX   *	-j  Don't copy junk: *.o, *.Z, *.bak, *.log, a.out, and core
XX   *	-m  If ENOSPC encountered, ask for another diskette
XX   *	-n  No directories, only loose files are backed up
XX   *	-s  Don't copy *.s files
XX   *      -t  set creation date of target-file equal to cdate of source-file
XX   *	-v  Verbose (announce what is being done)
XX   *	-z  Compress the backed up files
XX   *
XX   */
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX  #include <errno.h>
XX- #include <stdio.h>
XX  #include <fcntl.h>
XX  #include <utime.h>
XX  
XX  #define COPY_SIZE 4096
XX  #define MAX_ENTRIES 512
XX--- 17,43 ----
XX   *	-j  Don't copy junk: *.o, *.Z, *.bak, *.log, a.out, and core
XX   *	-m  If ENOSPC encountered, ask for another diskette
XX   *	-n  No directories, only loose files are backed up
XX+  *	-o  Don't copy *.o files
XX+  *	-r  Restore filenames (ie. uncompress if necessary)
XX   *	-s  Don't copy *.s files
XX   *      -t  set creation date of target-file equal to cdate of source-file
XX   *	-v  Verbose (announce what is being done)
XX   *	-z  Compress the backed up files
XX   *
XX+  * Patches:
XX+  *	30 Mar 91.  Added restore option.  cwr. 
XX   */
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX  #include <errno.h>
XX  #include <fcntl.h>
XX  #include <utime.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <unistd.h>
XX+ #include <sys/wait.h>
XX+ #include <stdio.h>
XX  
XX  #define COPY_SIZE 4096
XX  #define MAX_ENTRIES 512
XX***************
XX*** 41,50 ****
XX  #define NO_SAVINGS 512		/* compress can return code 2 */
XX  #define OUT_OF_SPACE 2
XX  
XX- typedef unsigned short unshort;
XX- 
XX  struct dir_buf {		/* list of the src directory */
XX!   unshort ino;
XX    char name[NAME_SIZE];
XX  } dir_buf[MAX_ENTRIES];
XX  
XX--- 49,56 ----
XX  #define NO_SAVINGS 512		/* compress can return code 2 */
XX  #define OUT_OF_SPACE 2
XX  
XX  struct dir_buf {		/* list of the src directory */
XX!   unsigned short ino;
XX    char name[NAME_SIZE];
XX  } dir_buf[MAX_ENTRIES];
XX  
XX***************
XX*** 56,76 ****
XX  } sorted[MAX_ENTRIES];
XX  
XX  char copybuf[COPY_SIZE];
XX  
XX- unshort dflag, jflag, mflag, nflag, rflag, sflag, tflag, vflag, zflag;
XX- 
XX  extern int errno;
XX! extern char *environ;
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX!   int i, ct, n, m, fd;
XX    char *dir1, *dir2, *cp, c;
XX  
XX    /* Get the flags. */
XX    sync();
XX    if (argc < 3 || argc > 4) usage();
XX    if (argc == 4) {
XX  	cp = argv[1];
XX--- 62,97 ----
XX  } sorted[MAX_ENTRIES];
XX  
XX  char copybuf[COPY_SIZE];
XX+ char *pname;
XX+ int dflag, jflag, mflag, nflag, oflag, rflag, sflag, tflag, vflag, zflag;
XX  
XX  extern int errno;
XX! extern char **environ;
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void maketarget, (char *dir2));
XX! _PROTOTYPE(int make_dir, (char *dir));
XX! _PROTOTYPE(int stat_all, (char *dir1, int n));
XX! _PROTOTYPE(void sort_dir, (int m));
XX! _PROTOTYPE(void process, (int m, char *dir1, char *dir2));
XX! _PROTOTYPE(void swap, (struct sorted *sp1, struct sorted *sp2));
XX! _PROTOTYPE(int copy, (char *dir1, struct sorted *sp, char *cbuf2));
XX! _PROTOTYPE(int zcopy, (char *src, char *targ));
XX! _PROTOTYPE(void copydir, (char *dir1, char *dir2, char *namep));
XX! _PROTOTYPE(void newdisk, (char *dir));
XX! _PROTOTYPE(void usage, (void));
XX! _PROTOTYPE(void error, (int type, char *s1, char *s2, char *s3));
XX! 
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX!   int ct, n, m, fd;
XX    char *dir1, *dir2, *cp, c;
XX  
XX    /* Get the flags. */
XX    sync();
XX+   pname = argv[0];
XX    if (argc < 3 || argc > 4) usage();
XX    if (argc == 4) {
XX  	cp = argv[1];
XX***************
XX*** 81,86 ****
XX--- 102,108 ----
XX  		    case 'j':	jflag++;	break;
XX  		    case 'm':	mflag++;	break;
XX  		    case 'n':	nflag++;	break;
XX+ 		    case 'o':	oflag++;	break;
XX  		    case 's':	sflag++;	break;
XX  		    case 'r':	rflag++;	break;
XX  		    case 't':	tflag++;	break;
XX***************
XX*** 95,106 ****
XX  	dir1 = argv[1];
XX  	dir2 = argv[2];
XX    }
XX  
XX    /* Read in the source directory */
XX  
XX    fd = open(dir1, O_RDONLY);
XX    if (fd < 0) error(FATAL, "cannot open ", dir1, "");
XX!   ct = read(fd, &dir_buf[0], MAX_ENTRIES * DIR_ENT_SIZE);
XX    close(fd);
XX    if (ct == MAX_ENTRIES * DIR_ENT_SIZE)
XX  	error(FATAL, "directory ", dir1, " is too large");
XX--- 117,129 ----
XX  	dir1 = argv[1];
XX  	dir2 = argv[2];
XX    }
XX+   if (!strcmp(pname, "restore") && !rflag) rflag++;
XX  
XX    /* Read in the source directory */
XX  
XX    fd = open(dir1, O_RDONLY);
XX    if (fd < 0) error(FATAL, "cannot open ", dir1, "");
XX!   ct = read(fd, (char *)&dir_buf[0], MAX_ENTRIES * DIR_ENT_SIZE);
XX    close(fd);
XX    if (ct == MAX_ENTRIES * DIR_ENT_SIZE)
XX  	error(FATAL, "directory ", dir1, " is too large");
XX***************
XX*** 117,127 ****
XX  
XX    /* Process each of the m entries one at a time. */
XX    process(m, dir1, dir2);
XX!   exit(0);
XX  }
XX  
XX  
XX! maketarget(dir2)
XX  char *dir2;
XX  {
XX  /* The target directory is created if it does not already exist. */
XX--- 140,150 ----
XX  
XX    /* Process each of the m entries one at a time. */
XX    process(m, dir1, dir2);
XX!   return(0);
XX  }
XX  
XX  
XX! void maketarget(dir2)
XX  char *dir2;
XX  {
XX  /* The target directory is created if it does not already exist. */
XX***************
XX*** 165,170 ****
XX--- 188,194 ----
XX  	execle("/usr/bin/mkdir", "mkdir", dir, (char *) 0, environ);
XX  	error(FATAL, "cannot execute mkdir", "", "");
XX    }
XX+   return(0);
XX  }
XX  
XX  
XX***************
XX*** 179,186 ****
XX    int i, j;
XX    char cbuf[MAX_PATH];
XX    struct stat s;
XX-   struct dir_buf *dp;
XX-   struct sorted *sp;
XX  
XX    for (i = 0; i < n; i++) {
XX  	/* Mark "." and ".." as null entries, as well as unstatable ones. */
XX--- 203,208 ----
XX***************
XX*** 190,197 ****
XX  
XX  	/* Stat the file. */
XX  	strcpy(cbuf, dir1);
XX! 	strncat(cbuf, "/", 1);
XX! 	strncat(cbuf, dir_buf[i].name, NAME_SIZE);
XX  	if (stat(cbuf, &s) < 0) {
XX  		error(NONFATAL, "cannot stat ", cbuf, "");
XX  		dir_buf[i].ino = 0;	/* mark as unusable */
XX--- 212,219 ----
XX  
XX  	/* Stat the file. */
XX  	strcpy(cbuf, dir1);
XX! 	strncat(cbuf, "/", (size_t)1);
XX! 	strncat(cbuf, dir_buf[i].name, (size_t)NAME_SIZE);
XX  	if (stat(cbuf, &s) < 0) {
XX  		error(NONFATAL, "cannot stat ", cbuf, "");
XX  		dir_buf[i].ino = 0;	/* mark as unusable */
XX***************
XX*** 215,221 ****
XX  }
XX  
XX  
XX! int sort_dir(m)
XX  int m;
XX  {
XX  /* Sort the directory using bubble sort. */
XX--- 237,243 ----
XX  }
XX  
XX  
XX! void sort_dir(m)
XX  int m;
XX  {
XX  /* Sort the directory using bubble sort. */
XX***************
XX*** 224,237 ****
XX  
XX    for (sp1 = &sorted[0]; sp1 < &sorted[m - 1]; sp1++) {
XX  	for (sp2 = sp1 + 1; sp2 < &sorted[m]; sp2++) {
XX! 		if (strncmp(sp1->namep, sp2->namep, NAME_SIZE) > 0)
XX  			swap(sp1, sp2);
XX  	}
XX    }
XX  }
XX  
XX  
XX! process(m, dir1, dir2)
XX  int m;
XX  char *dir1, *dir2;
XX  {
XX--- 246,259 ----
XX  
XX    for (sp1 = &sorted[0]; sp1 < &sorted[m - 1]; sp1++) {
XX  	for (sp2 = sp1 + 1; sp2 < &sorted[m]; sp2++) {
XX! 		if (strncmp(sp1->namep, sp2->namep, (size_t)NAME_SIZE) > 0)
XX  			swap(sp1, sp2);
XX  	}
XX    }
XX  }
XX  
XX  
XX! void process(m, dir1, dir2)
XX  int m;
XX  char *dir1, *dir2;
XX  {
XX***************
XX*** 250,261 ****
XX  	if (fmode == S_IFREG) {
XX  		/* Regular file.  Construct target name and stat it. */
XX  		strcpy(cbuf, dir2);
XX! 		strncat(cbuf, "/", 1);
XX! 		strncat(cbuf, sp->namep, NAME_SIZE);
XX  		namlen = strlen(sp->namep);
XX! 		if (sp->namep[namlen - 2] != '.' || sp->namep[namlen - 1] != 'Z')
XX! 			if (zflag && (namlen <= (NAME_SIZE - 2)))
XX! 				strncat(cbuf, ".Z", 2);
XX  		er = stat(cbuf, &s);
XX  		if (er < 0 || sp->modtime > s.st_mtime) {
XX  			res = copy(dir1, sp, cbuf);
XX--- 272,286 ----
XX  	if (fmode == S_IFREG) {
XX  		/* Regular file.  Construct target name and stat it. */
XX  		strcpy(cbuf, dir2);
XX! 		strncat(cbuf, "/", (size_t)1);
XX! 		strncat(cbuf, sp->namep, (size_t)NAME_SIZE);
XX  		namlen = strlen(sp->namep);
XX! 		/* Switch between compressed and uncompressed file names */
XX! 		if (zflag && !rflag && strncmp((sp->namep + namlen - 2), ".Z", (size_t)2)
XX! 				&& (namlen <= (NAME_SIZE - 2)))
XX! 			strncat(cbuf, ".Z", (size_t)2);
XX! 		if (zflag && rflag && !strncmp((sp->namep + namlen - 2), ".Z", (size_t)2))
XX! 			cbuf[strlen(cbuf) - 2] = '\0';
XX  		er = stat(cbuf, &s);
XX  		if (er < 0 || sp->modtime > s.st_mtime) {
XX  			res = copy(dir1, sp, cbuf);
XX***************
XX*** 280,286 ****
XX  		copydir(dir1, dir2, sp->namep);
XX  	} else if (fmode == S_IFBLK || fmode == S_IFCHR) {
XX  		/* Special file. */
XX! 		strncpy(cbuf, sp->namep, NAME_SIZE);
XX  		printf("%s is special file.  Not backed up.\n", cbuf);
XX  	}
XX    }
XX--- 305,311 ----
XX  		copydir(dir1, dir2, sp->namep);
XX  	} else if (fmode == S_IFBLK || fmode == S_IFCHR) {
XX  		/* Special file. */
XX! 		strncpy(cbuf, sp->namep, (size_t)NAME_SIZE);
XX  		printf("%s is special file.  Not backed up.\n", cbuf);
XX  	}
XX    }
XX***************
XX*** 289,295 ****
XX  
XX  
XX  
XX! swap(sp1, sp2)
XX  struct sorted *sp1, *sp2;
XX  {
XX  /* Swap two directory entries. */
XX--- 314,320 ----
XX  
XX  
XX  
XX! void swap(sp1, sp2)
XX  struct sorted *sp1, *sp2;
XX  {
XX  /* Swap two directory entries. */
XX***************
XX*** 309,335 ****
XX  /* Copy a regular file. */
XX  
XX    int fd1, fd2, nr, nw, res, n, namlen;
XX!   char cbuf1[MAX_PATH], *p;
XX  
XX    /* If the -j or -s flags were given, suppress certain files. */
XX    p = sp->namep;
XX    n = strlen(p);
XX    if (jflag) {
XX  	if (strcmp(p, "a.out") == 0) return(0);
XX  	if (strcmp(p, "core") == 0) return (0);
XX- 	if (strcmp(p + n - 2, ".o") == 0) return (0);
XX  	if (strcmp(p + n - 2, ".Z") == 0) return (0);
XX  	if (strcmp(p + n - 4, ".bak") == 0) return (0);
XX  	if (strcmp(p + n - 4, ".log") == 0) return (0);
XX    }
XX    if (sflag) {
XX  	if (strcmp(p + n - 2, ".s") == 0) return(0);
XX    }
XX    res = 0;
XX    if (dflag) return(0);		/* backup -d means only directories */
XX    strcpy(cbuf1, dir1);
XX!   strncat(cbuf1, "/", 1);
XX!   strncat(cbuf1, sp->namep, NAME_SIZE);	/* cbuf1 = source file name */
XX  
XX    /* At this point, cbuf1 contains the source file name, cbuf2 the target. */
XX    fd1 = open(cbuf1, O_RDONLY);
XX--- 334,368 ----
XX  /* Copy a regular file. */
XX  
XX    int fd1, fd2, nr, nw, res, n, namlen;
XX!   char cbuf1[MAX_PATH], *p, msg[20];
XX  
XX+   /* The message changes with the program name */
XX+   if (!strcmp(pname, "restore"))
XX+ 	strcpy(msg, "Restored");
XX+   else
XX+ 	strcpy(msg, "Backed up");
XX+ 
XX    /* If the -j or -s flags were given, suppress certain files. */
XX    p = sp->namep;
XX    n = strlen(p);
XX    if (jflag) {
XX  	if (strcmp(p, "a.out") == 0) return(0);
XX  	if (strcmp(p, "core") == 0) return (0);
XX  	if (strcmp(p + n - 2, ".Z") == 0) return (0);
XX  	if (strcmp(p + n - 4, ".bak") == 0) return (0);
XX  	if (strcmp(p + n - 4, ".log") == 0) return (0);
XX    }
XX+   if (oflag) {
XX+ 	if (strcmp(p + n - 2, ".o") == 0) return(0);
XX+   }
XX    if (sflag) {
XX  	if (strcmp(p + n - 2, ".s") == 0) return(0);
XX    }
XX    res = 0;
XX    if (dflag) return(0);		/* backup -d means only directories */
XX    strcpy(cbuf1, dir1);
XX!   strncat(cbuf1, "/", (size_t)1);
XX!   strncat(cbuf1, sp->namep, (size_t)NAME_SIZE);	/* cbuf1 = source file name */
XX  
XX    /* At this point, cbuf1 contains the source file name, cbuf2 the target. */
XX    fd1 = open(cbuf1, O_RDONLY);
XX***************
XX*** 350,364 ****
XX  
XX    /* Both files are now open.  Do the copying. */
XX    namlen = strlen(sp->namep);
XX!   if (sp->namep[namlen - 2] != '.' || sp->namep[namlen - 1] != 'Z')
XX! 	if (zflag && (namlen <= (NAME_SIZE - 2))) {
XX  		close(fd1);
XX  		close(fd2);
XX  		res = zcopy(cbuf1, cbuf2);
XX  		if (tflag) utime(cbuf2, (struct utimbuf *) & (sp->acctime));
XX  		if (res != 0) unlink(cbuf2);	/* if error, get rid of the
XX  					 * corpse */
XX! 		if (vflag && res == 0) printf("Backing up %s\n", cbuf1);
XX  		return(res);
XX  	}
XX    while (1) {
XX--- 383,398 ----
XX  
XX    /* Both files are now open.  Do the copying. */
XX    namlen = strlen(sp->namep);
XX!   if ((!rflag && strncmp((sp->namep + namlen - 2), ".Z", (size_t)2)) ||
XX! 		(rflag && !strncmp((sp->namep + namlen - 2), ".Z", (size_t)2)))
XX! 	if (zflag && (rflag || (namlen <= (NAME_SIZE - 2)))) {
XX  		close(fd1);
XX  		close(fd2);
XX  		res = zcopy(cbuf1, cbuf2);
XX  		if (tflag) utime(cbuf2, (struct utimbuf *) & (sp->acctime));
XX  		if (res != 0) unlink(cbuf2);	/* if error, get rid of the
XX  					 * corpse */
XX! 		if (vflag && res == 0) printf("%s %s\n", msg, cbuf1);
XX  		return(res);
XX  	}
XX    while (1) {
XX***************
XX*** 384,390 ****
XX  	}
XX    }
XX    if (res == 0) {
XX! 	if (vflag) printf("Backing up %s\n", cbuf1);
XX    } else {
XX  	unlink(cbuf2);
XX    }
XX--- 418,424 ----
XX  	}
XX    }
XX    if (res == 0) {
XX! 	if (vflag) printf("%s %s\n", msg, cbuf1);
XX    } else {
XX  	unlink(cbuf2);
XX    }
XX***************
XX*** 400,406 ****
XX--- 434,447 ----
XX  {
XX  
XX    int pid, status, res, s;
XX+   char fbuf[20];
XX  
XX+   strcpy(fbuf, "-c");
XX+   if (rflag)
XX+ 	strcat(fbuf, "d");
XX+   else
XX+ 	strcat(fbuf, "f");
XX+ 
XX    if ((pid = fork()) < 0) error(FATAL, "cannot fork", "", "");
XX    if (pid > 0) {
XX  	wait(&status);
XX***************
XX*** 413,464 ****
XX  	close(1);
XX  	s = open(targ, O_RDWR);
XX  	if (s < 0) error(FATAL, "cannot write on ", "targ", "");
XX! 	execle("/bin/compress", "compress", "-fc", src, (char *) 0, environ);
XX! 	execle("/usr/bin/compress", "compress", "-fc", src, (char *)0,environ);
XX  	error(FATAL, "cannot exec compress", "", "");
XX    }
XX  }
XX  
XX  
XX! copydir(dir1, dir2, namep)
XX  char *dir1, *dir2, *namep;
XX  {
XX  /* Copy a directory. */
XX  
XX!   int pid, res, status;
XX    char fbuf[20], d1buf[MAX_PATH], d2buf[MAX_PATH];
XX  
XX!   res = 0;
XX!   if (nflag) return(res);	/* backup -n means no directories */
XX  
XX    /* Handle directory copy by forking off 'backup' ! */
XX!   strcpy(fbuf, "-r");
XX    if (jflag) strcat(fbuf, "j");
XX    if (mflag) strcat(fbuf, "m");
XX    if (sflag) strcat(fbuf, "s");
XX    if (tflag) strcat(fbuf, "t");
XX    if (vflag) strcat(fbuf, "v");
XX    if (zflag) strcat(fbuf, "z");
XX    strcpy(d1buf, dir1);
XX!   strcat(d1buf, "/", 1);
XX!   strncat(d1buf, namep, NAME_SIZE);
XX    strcpy(d2buf, dir2);
XX!   strcat(d2buf, "/", 2);
XX!   strncat(d2buf, namep, NAME_SIZE);
XX  
XX    if ((pid = fork()) < 0) error(FATAL, "cannot fork", "", "");
XX    if (pid > 0) {
XX  	wait(&status);
XX  	return;
XX!   } else {
XX  	execle("backup", "backup", fbuf, d1buf, d2buf, (char *) 0, environ);
XX  	execle("/bin/backup", "backup", fbuf, d1buf, d2buf, (char *)0,environ);
XX  	execle("/usr/bin/backup","backup",fbuf,d1buf,d2buf,(char *)0,environ);
XX  	error(FATAL, "cannot recursively exec backup", "", "");
XX    }
XX  }
XX  
XX! newdisk(dir)
XX  char *dir;
XX  {
XX  /* Ask for a new diskette. A big problem is that this program does not
XX--- 454,517 ----
XX  	close(1);
XX  	s = open(targ, O_RDWR);
XX  	if (s < 0) error(FATAL, "cannot write on ", "targ", "");
XX! 	execle("/bin/compress", "compress", fbuf, src, (char *)0, environ);
XX! 	execle("/usr/bin/compress", "compress", fbuf, src, (char *)0, environ);
XX  	error(FATAL, "cannot exec compress", "", "");
XX    }
XX+   return(0);
XX  }
XX  
XX  
XX! void copydir(dir1, dir2, namep)
XX  char *dir1, *dir2, *namep;
XX  {
XX  /* Copy a directory. */
XX  
XX!   int pid, status;
XX    char fbuf[20], d1buf[MAX_PATH], d2buf[MAX_PATH];
XX  
XX!   if (nflag) return;	/* backup -n means no directories */
XX  
XX+   fbuf[0] = '\0';
XX+ 
XX    /* Handle directory copy by forking off 'backup' ! */
XX!   if (jflag || mflag || rflag || sflag || tflag || vflag || zflag)
XX! 	strcpy(fbuf, "-");
XX    if (jflag) strcat(fbuf, "j");
XX    if (mflag) strcat(fbuf, "m");
XX+   if (rflag) strcat(fbuf, "r");
XX    if (sflag) strcat(fbuf, "s");
XX    if (tflag) strcat(fbuf, "t");
XX    if (vflag) strcat(fbuf, "v");
XX    if (zflag) strcat(fbuf, "z");
XX    strcpy(d1buf, dir1);
XX!   strcat(d1buf, "/");
XX!   strncat(d1buf, namep, (size_t)NAME_SIZE);
XX    strcpy(d2buf, dir2);
XX!   strcat(d2buf, "/");
XX!   strncat(d2buf, namep, (size_t)NAME_SIZE);
XX  
XX    if ((pid = fork()) < 0) error(FATAL, "cannot fork", "", "");
XX    if (pid > 0) {
XX+ 	/* Parent waits for child, then returns. */
XX  	wait(&status);
XX  	return;
XX!   }
XX! 
XX!   if (fbuf[0] == '-') {
XX  	execle("backup", "backup", fbuf, d1buf, d2buf, (char *) 0, environ);
XX  	execle("/bin/backup", "backup", fbuf, d1buf, d2buf, (char *)0,environ);
XX  	execle("/usr/bin/backup","backup",fbuf,d1buf,d2buf,(char *)0,environ);
XX  	error(FATAL, "cannot recursively exec backup", "", "");
XX+   } else {
XX+ 	execle("backup", "backup", d1buf, d2buf, (char *) 0, environ);
XX+ 	execle("/bin/backup", "backup", d1buf, d2buf, (char *)0,environ);
XX+ 	execle("/usr/bin/backup","backup", d1buf, d2buf, (char *)0,environ);
XX+ 	error(FATAL, "cannot recursively exec backup", "", "");
XX    }
XX  }
XX  
XX! void newdisk(dir)
XX  char *dir;
XX  {
XX  /* Ask for a new diskette. A big problem is that this program does not
XX***************
XX*** 472,478 ****
XX    printf("   1. Unmount the diskette using /etc/umount\n");
XX    printf("   2. Physically replace the diskette by the next one.\n");
XX    printf("   3. Mount the new diskette using /etc/mount\n");
XX!   printf("   4. Type CTRL-D to return to the backup program\n");
XX  
XX    if ((pid = fork()) < 0) error(FATAL, "cannot fork", "", "");
XX    if (pid > 0) {
XX--- 525,531 ----
XX    printf("   1. Unmount the diskette using /etc/umount\n");
XX    printf("   2. Physically replace the diskette by the next one.\n");
XX    printf("   3. Mount the new diskette using /etc/mount\n");
XX!   printf("   4. Type CTRL-D to return to the backup/restore program\n");
XX  
XX    if ((pid = fork()) < 0) error(FATAL, "cannot fork", "", "");
XX    if (pid > 0) {
XX***************
XX*** 485,501 ****
XX    }
XX  }
XX  
XX! usage()
XX  {
XX!   error(2, "Usage: backup [-djmnstvz] dir1 dir2", "", "");
XX  }
XX  
XX  
XX! error(type, s1, s2, s3)
XX  int type;
XX  char *s1, *s2, *s3;
XX  {
XX!   fprintf(stderr, "backup: %s%s%s\n", s1, s2, s3);
XX  
XX    if (type == NONFATAL)
XX  	return;
XX--- 538,555 ----
XX    }
XX  }
XX  
XX! void usage()
XX  {
XX!   fprintf(stderr, "Usage: backup [-djmnorstvz] dir1 dir2\n");
XX!   exit(2);
XX  }
XX  
XX  
XX! void error(type, s1, s2, s3)
XX  int type;
XX  char *s1, *s2, *s3;
XX  {
XX!   fprintf(stderr, "%s: %s%s%s\n", pname, s1, s2, s3);
XX  
XX    if (type == NONFATAL)
XX  	return;
X/
Xecho x - badblocks.c.d
Xsed '/^X/s///' > badblocks.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/badblocks.c  crc=49945  13140	Sun Apr 25 21:34:46 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/badblocks.c  crc=62664  15472	Sun Jan 10 14:26:15 1993
XX***************
XX*** 4,10 ****
XX  
XX  /* This program is written to handle BADBLOCKS on a hard or floppy disk.
XX   * The program asks for block_numbers. These numbers can be obtained with
XX!  * the program disk_check; written by A. Tanenbaum.  It then creates a
XX   * file on the disk containing up to 7 bad blocks.
XX   *
XX   * BUG:
XX--- 4,10 ----
XX  
XX  /* This program is written to handle BADBLOCKS on a hard or floppy disk.
XX   * The program asks for block_numbers. These numbers can be obtained with
XX!  * the program readall, written by A. Tanenbaum.  It then creates a
XX   * file on the disk containing up to 7 bad blocks.
XX   *
XX   * BUG:
XX***************
XX*** 19,35 ****
XX   *
XX   */
XX  
XX- #include <minix/config.h>
XX- #include <minix/type.h>
XX- 
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX  #include <fcntl.h>
XX  #include <unistd.h>
XX! #include <stdio.h>
XX  
XX  
XX  
XX  /* 		Super block table.
XX   *
XX   * 	The disk layout is:
XX--- 19,58 ----
XX   *
XX   */
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX+ #include <minix/config.h>
XX+ #include <minix/type.h>
XX  #include <fcntl.h>
XX  #include <unistd.h>
XX! #include <stdlib.h>
XX  
XX+ #include "../fs/const.h"	/* must be included before stdio.h */
XX+ #undef printf			/* so its define of printf can be undone */
XX+ #include "../fs/type.h"
XX  
XX+ #include <string.h>
XX+ #include <stdio.h>
XX  
XX+ _PROTOTYPE(int main, (int argc, char **argv));
XX+ _PROTOTYPE(void rw_super, (int flag));
XX+ _PROTOTYPE(void get_super, (void));
XX+ _PROTOTYPE(void put_super, (void));
XX+ _PROTOTYPE(void rw_inode, (struct stat * stat_ptr, int rw_mode));
XX+ _PROTOTYPE(void get_inode, (struct stat * stat_ptr));
XX+ _PROTOTYPE(void put_inode, (struct stat * stat_ptr));
XX+ _PROTOTYPE(long rd_cmdline, (int argc, char *argv[]));
XX+ _PROTOTYPE(void modify, (int nr_blocks));
XX+ _PROTOTYPE(void save_blk, (block_t blk_num));
XX+ _PROTOTYPE(void reset_blks, (void));
XX+ _PROTOTYPE(void show_blks, (void));
XX+ _PROTOTYPE(int blk_is_used, (block_t blk_num));
XX+ _PROTOTYPE(int blk_ok, (block_t num));
XX+ _PROTOTYPE(void set_bit, (zone_t num));
XX+ _PROTOTYPE(long rd_num, (void));
XX+ _PROTOTYPE(int ok, (char *str));
XX+ _PROTOTYPE(void done, (int nr));
XX+ 
XX  /* 		Super block table.
XX   *
XX   * 	The disk layout is:
XX***************
XX*** 39,80 ****
XX   *    super block     1
XX   *    inode map     s_imap_blocks
XX   *    zone map      s_zmap_blocks
XX!  *    inodes        (s_ninodes + 1 + INODES_PER_BLOCK - 1)/INODES_PER_BLOCK
XX   *    unused
XX   *    data zones    (s_nzones - s_firstdatazone) << s_log_zone_size
XX   *
XX   */
XX  
XX- 
XX- struct super_block {
XX-   ino_t s_ninodes;		/* # usable inodes on the minor device */
XX-   zone_nr s_nzones;		/* total device size, including bit maps etc */
XX-   unshort s_imap_block;		/* # of block used by inode bit map */
XX-   unshort s_zmap_block;		/* # of block used by zone bit map */
XX-   zone_nr s_firstdatazone;	/* number of first data zone */
XX-   short int s_log_zone_size;	/* log2 of block/zone */
XX-   off_t s_max_size;		/* maximum file size on this device */
XX-   int s_magic;			/* magic number to recognize super-block */
XX- } super_block;
XX- 
XX- #define SUPER_MAGIC	0x137F
XX- 
XX- 
XX- #define NR_ZONE_NUMS	9
XX- #define NR_DZONE_NUMS	(NR_ZONE_NUMS -2 )
XX- 
XX- struct d_inode {		/* disk inode. */
XX-   mode_t i_mode;		/* file type, protection, etc. */
XX-   uid_t i_uid;			/* user id of the file's owner */
XX-   off_t i_size;			/* current file size in bytes */
XX-   time_t i_mtime;		/* when was file data last changed */
XX-   gid_t i_gid;			/* group number */
XX-   nlink_t i_nlinks;		/* how many links to this file */
XX-   zone_nr i_zone[NR_ZONE_NUMS];	/* blocks nums for direct, ind, and dbl ind */
XX- } d_inode;
XX- 
XX- 
XX- 
XX  #define OK	0
XX  #define NOT_OK	1
XX  #define QUIT	2
XX--- 62,73 ----
XX   *    super block     1
XX   *    inode map     s_imap_blocks
XX   *    zone map      s_zmap_blocks
XX!  *    inodes        (s_ninodes + 1 + inodes_per_block - 1)/inodes_per_block
XX   *    unused
XX   *    data zones    (s_nzones - s_firstdatazone) << s_log_zone_size
XX   *
XX   */
XX  
XX  #define OK	0
XX  #define NOT_OK	1
XX  #define QUIT	2
XX***************
XX*** 88,100 ****
XX  #define FILE_EXISTS	3
XX  #define SUCCESS		4
XX  
XX! #define BLOCK_SIZE	1024
XX! #define INODES_PER_BLOCK	(BLOCK_SIZE/sizeof(struct d_inode))
XX! 
XX! #define INODE_SIZE (sizeof (struct d_inode) )
XX! #define SUPER_SIZE (sizeof (struct super_block) )
XX  #define SIZE_OF_INT   (sizeof (int) )
XX  
XX   /* ====== globals ======= */
XX  
XX  char *dev_name;
XX--- 81,112 ----
XX  #define FILE_EXISTS	3
XX  #define SUCCESS		4
XX  
XX! #define BYTE         0377
XX! #define BLOCK_SIZE   1024
XX  #define SIZE_OF_INT   (sizeof (int) )
XX  
XX+ /* Define V_NR_DZONES as the larger of V1_NR_DZONES and V2_NR_DZONES. */
XX+ #if (V1_NR_DZONES > V2_NR_DZONES)
XX+ #define V_NR_DZONES V1_NR_DZONES
XX+ #define V_SMALLER   V2_NR_DZONES
XX+ #else
XX+ #define V_NR_DZONES V2_NR_DZONES
XX+ #define V_SMALLER   V1_NR_DZONES
XX+ #endif
XX+ 
XX+ struct super_block {
XX+   ino_t s_ninodes;		/* # usable inodes on the minor device */
XX+   zone1_t s_nzones;		/* total device size, including bit maps etc */
XX+   short s_imap_blocks;		/* # of blocks used by inode bit map */
XX+   short s_zmap_blocks;		/* # of blocks used by zone bit map */
XX+   zone1_t s_firstdatazone;	/* number of first data zone */
XX+   short s_log_zone_size;	/* log2 of blocks/zone */
XX+   off_t s_max_size;		/* maximum file size on this device */
XX+   short s_magic;		/* magic number to recognize super-blocks */
XX+   short s_pad;			/* try to avoid compiler-dependent padding */
XX+   zone_t s_zones;		/* number of zones (replaces s_nzones in V2) */
XX+ } super_block;
XX+ 
XX   /* ====== globals ======= */
XX  
XX  char *dev_name;
XX***************
XX*** 102,124 ****
XX  char file_name[50];
XX  char dir_name[] = "/tmpXXXXXX";
XX  
XX! int block[NR_DZONE_NUMS + 1];	/* last block contains zero */
XX  int interactive;		/* 1 if interactive (argc == 2) */
XX  int position = 2;		/* next block # is argv[position] */
XX  
XX! FILE *fp, *fopen();
XX  int fd;
XX  int eofseen;			/* set if '\n' seen */
XX  struct stat stat_buf;
XX- struct d_inode *ip;
XX  struct super_block *sp;
XX  
XX! extern char *strcat();
XX  
XX  
XX   /* ====== super block routines ======= */
XX  
XX! rw_super(flag)
XX  {				/* read or write a superblock */
XX    int rwd;
XX  
XX--- 114,142 ----
XX  char file_name[50];
XX  char dir_name[] = "/tmpXXXXXX";
XX  
XX! block_t block[V_NR_DZONES + 1];	/* last block contains zero */
XX  int interactive;		/* 1 if interactive (argc == 2) */
XX  int position = 2;		/* next block # is argv[position] */
XX  
XX! FILE *f;
XX  int fd;
XX  int eofseen;			/* set if '\n' seen */
XX  struct stat stat_buf;
XX  struct super_block *sp;
XX+ int inodes_per_block;
XX+ size_t inode_size;
XX+ int v1fs;			/* TRUE for V1 file system, FALSE for V2 */
XX  
XX! d1_inode d1inode;		/* declare a V1 disk inode */
XX! d1_inode *ip1;
XX! d2_inode d2inode;		/* declare a V2 disk inode */
XX! d2_inode *ip2;
XX  
XX  
XX   /* ====== super block routines ======= */
XX  
XX! void rw_super(flag)
XX! int flag;
XX  {				/* read or write a superblock */
XX    int rwd;
XX  
XX***************
XX*** 130,194 ****
XX    else
XX  	rwd = write(fd, (char *) sp, SUPER_SIZE);
XX    if (rwd != SUPER_SIZE) {	/* ok ? */
XX! 	printf("Bad %s in get_super() (should be %d is %d)\n",
XX  	       flag == READ ? "read" : "write",
XX! 	       SUPER_SIZE, rwd);
XX  	done(DIR_CREATED);
XX    }
XX  }
XX  
XX! get_super()
XX   /* Get super_block. global pointer sp is used */
XX  {
XX    rw_super(READ);
XX  
XX!   if (sp->s_magic != SUPER_MAGIC) {	/* check */
XX! 	printf("Bad magic number in super_block?!\n");
XX  	done(DIR_CREATED);
XX    }
XX  }
XX  
XX  
XX! put_super()
XX  {
XX    rw_super(WRITE);
XX  }
XX  
XX   /* ========== inode routines =========== */
XX  
XX! rw_inode(stat_ptr, rw_mode)
XX  struct stat *stat_ptr;
XX  {
XX!   int rwd, i_num;
XX!   long blk, offset;
XX  
XX  
XX    i_num = stat_ptr->st_ino;
XX  
XX!   blk = (long) (2 + sp->s_imap_block + sp->s_zmap_block);
XX!   blk += (long) ((i_num - 1) / INODES_PER_BLOCK);
XX!   blk *= (long) (BLOCK_SIZE);	/* this block */
XX  
XX!   offset = (long) ((i_num - 1) % INODES_PER_BLOCK);
XX!   offset *= (long) (INODE_SIZE);/* and this offset */
XX  
XX!   lseek(fd, 0L, SEEK_SET);	/* rewind */
XX!   lseek(fd, (long) (blk + offset), SEEK_SET);	/* seek */
XX  
XX    /* Pointer is at the inode */
XX!   if (rw_mode == READ) {	/* read it */
XX! 	rwd = read(fd, (char *) ip, INODE_SIZE);
XX!   } else {			/* write it */
XX! 	rwd = write(fd, (char *) ip, INODE_SIZE);
XX    }
XX!   if (rwd != INODE_SIZE) {	/* ok ? */
XX  	printf("Bad %s in get_inode()\n", (rw_mode == READ) ? "read" :
XX  	       "write");
XX  	done(DIR_CREATED);
XX    }
XX  }
XX  
XX! get_inode(stat_ptr)
XX  struct stat *stat_ptr;
XX  {
XX  
XX--- 148,233 ----
XX    else
XX  	rwd = write(fd, (char *) sp, SUPER_SIZE);
XX    if (rwd != SUPER_SIZE) {	/* ok ? */
XX! 	printf("Bad %s in get_super() (should be %u is %d)\n",
XX  	       flag == READ ? "read" : "write",
XX! 	       (unsigned) SUPER_SIZE, rwd);
XX  	done(DIR_CREATED);
XX    }
XX  }
XX  
XX! void get_super()
XX   /* Get super_block. global pointer sp is used */
XX  {
XX    rw_super(READ);
XX  
XX!   if (sp->s_magic == SUPER_MAGIC) {
XX! 	/* This is a V1 file system. */
XX! 	v1fs = 1;		/* file system is not V2 */
XX!   } else if (sp->s_magic == SUPER_V2) {
XX! 	/* This is a V2 file system. */
XX! 	v1fs = 0;		/* this is a V2 file system */
XX!   } else {
XX! 	/* Neither V1 nor V2. */
XX! 	printf("Bad magic number in super_block (0x%x)\n",
XX! 	       (unsigned) sp->s_magic);
XX  	done(DIR_CREATED);
XX    }
XX  }
XX  
XX  
XX! void put_super()
XX  {
XX    rw_super(WRITE);
XX  }
XX  
XX   /* ========== inode routines =========== */
XX  
XX! void rw_inode(stat_ptr, rw_mode)
XX  struct stat *stat_ptr;
XX+ int rw_mode;
XX  {
XX!   int rwd;
XX!   ino_t i_num;
XX!   block_t blk, offset;
XX  
XX  
XX    i_num = stat_ptr->st_ino;
XX  
XX!   blk = (block_t) (2 + sp->s_imap_blocks + sp->s_zmap_blocks);
XX!   blk += (block_t) ((i_num - 1) / inodes_per_block);
XX!   blk *= (block_t) (BLOCK_SIZE);/* this block */
XX  
XX!   offset = (block_t) ((i_num - 1) % inodes_per_block);
XX!   offset *= (block_t) (inode_size);	/* and this offset */
XX  
XX!   lseek(fd, (off_t) 0, SEEK_SET);	/* rewind */
XX!   lseek(fd, (off_t) (blk + offset), SEEK_SET);	/* seek */
XX  
XX    /* Pointer is at the inode */
XX!   if (v1fs) {
XX! 	/* This is a V1 file system. */
XX! 	if (rw_mode == READ) {	/* read it */
XX! 		rwd = read(fd, (char *) ip1, inode_size);
XX! 	} else {		/* write it */
XX! 		rwd = write(fd, (char *) ip1, inode_size);
XX! 	}
XX!   } else {
XX! 	/* This is a V2 file system. */
XX! 	if (rw_mode == READ) {	/* read it */
XX! 		rwd = read(fd, (char *) ip2, inode_size);
XX! 	} else {		/* write it */
XX! 		rwd = write(fd, (char *) ip2, inode_size);
XX! 	}
XX    }
XX! 
XX!   if (rwd != inode_size) {	/* ok ? */
XX  	printf("Bad %s in get_inode()\n", (rw_mode == READ) ? "read" :
XX  	       "write");
XX  	done(DIR_CREATED);
XX    }
XX  }
XX  
XX! void get_inode(stat_ptr)
XX  struct stat *stat_ptr;
XX  {
XX  
XX***************
XX*** 196,206 ****
XX  
XX    rw_inode(stat_ptr, READ);
XX  
XX!   for (cnt = 0; cnt < NR_ZONE_NUMS; cnt++)
XX! 	ip->i_zone[cnt] = 0;	/* Just to be safe */
XX  }
XX  
XX! put_inode(stat_ptr)
XX  struct stat *stat_ptr;
XX  {
XX    rw_inode(stat_ptr, WRITE);
XX--- 235,250 ----
XX  
XX    rw_inode(stat_ptr, READ);
XX  
XX!   if (v1fs) {
XX! 	for (cnt = 0; cnt < V1_NR_TZONES; cnt++)
XX! 		ip1->d1_zone[cnt] = 0;	/* Just to be safe */
XX!   } else {
XX! 	for (cnt = 0; cnt < V2_NR_TZONES; cnt++)
XX! 		ip2->d2_zone[cnt] = 0;	/* Just to be safe */
XX!   }
XX  }
XX  
XX! void put_inode(stat_ptr)
XX  struct stat *stat_ptr;
XX  {
XX    rw_inode(stat_ptr, WRITE);
XX***************
XX*** 208,228 ****
XX  
XX  
XX   /* ==============  main program ================= */
XX! main(argc, argv)
XX  char *argv[];
XX  {
XX    int cnt, finished;
XX!   unsigned blk_nr;
XX    struct stat dev_stat;
XX  
XX    sp = &super_block;
XX!   ip = &d_inode;
XX  
XX    if (argc < 2 || argc > 9) {
XX  	fprintf(stderr, "Usage: %s block_special [up_to_7_blocks]\n", argv[0]);
XX  	done(HARMLESS);
XX    }
XX- 
XX    interactive = (argc == 2 ? 1 : 0);
XX  
XX    /* Do some test. */
XX--- 252,274 ----
XX  
XX  
XX   /* ==============  main program ================= */
XX! int main(argc, argv)
XX! int argc;
XX  char *argv[];
XX  {
XX    int cnt, finished;
XX!   block_t blk_nr;
XX    struct stat dev_stat;
XX+   FILE *fp;
XX  
XX    sp = &super_block;
XX!   ip1 = &d1inode;
XX!   ip2 = &d2inode;
XX  
XX    if (argc < 2 || argc > 9) {
XX  	fprintf(stderr, "Usage: %s block_special [up_to_7_blocks]\n", argv[0]);
XX  	done(HARMLESS);
XX    }
XX    interactive = (argc == 2 ? 1 : 0);
XX  
XX    /* Do some test. */
XX***************
XX*** 299,313 ****
XX  	printf("This program can not handle it\n");
XX  	done(DIR_CREATED);
XX    }
XX    get_inode(&stat_buf);
XX  
XX    for (finished = 0; !finished;) {
XX  	if (interactive)
XX  		printf("Give up to %d bad block numbers separated by spaces\n",
XX! 							       NR_DZONE_NUMS);
XX  	reset_blks();
XX  	cnt = 0;		/* cnt keep track of the zone's */
XX! 	while (cnt < NR_DZONE_NUMS) {
XX  		int tst;
XX  
XX  		if (interactive)
XX--- 345,369 ----
XX  	printf("This program can not handle it\n");
XX  	done(DIR_CREATED);
XX    }
XX+ 
XX+   /* The number of inodes in a block differs in V1 and V2. */
XX+   if (v1fs) {
XX+ 	inodes_per_block = V1_INODES_PER_BLOCK;
XX+ 	inode_size = V1_INODE_SIZE;
XX+   } else {
XX+ 	inodes_per_block = V2_INODES_PER_BLOCK;
XX+ 	inode_size = V2_INODE_SIZE;
XX+   }
XX+ 
XX    get_inode(&stat_buf);
XX  
XX    for (finished = 0; !finished;) {
XX  	if (interactive)
XX  		printf("Give up to %d bad block numbers separated by spaces\n",
XX! 		       V_SMALLER);
XX  	reset_blks();
XX  	cnt = 0;		/* cnt keep track of the zone's */
XX! 	while (cnt < V_SMALLER) {
XX  		int tst;
XX  
XX  		if (interactive)
XX***************
XX*** 327,337 ****
XX  	if (interactive) show_blks();
XX  	if (!cnt) done(FILE_EXISTS);
XX  	if (interactive) {
XX! 	   switch (ok("All these blocks ok <y/n/q> (y:Device will change) ")) {
XX! 		case OK:	finished = 1; break;
XX! 		case NOT_OK:	break;
XX! 		case QUIT:	done(FILE_EXISTS);
XX! 	   }
XX  	} else {
XX  		finished = 1;
XX  	}
XX--- 383,394 ----
XX  	if (interactive) show_blks();
XX  	if (!cnt) done(FILE_EXISTS);
XX  	if (interactive) {
XX! 		switch (ok("All these blocks ok <y/n/q> (y:Device will change) ")) {
XX! 		    case OK:	finished = 1;	break;
XX! 		    case NOT_OK:
XX! 			break;
XX! 		    case QUIT:	done(FILE_EXISTS);
XX! 		}
XX  	} else {
XX  		finished = 1;
XX  	}
XX***************
XX*** 340,366 ****
XX    modify(cnt);
XX    close(fd);			/* free device */
XX    done(SUCCESS);
XX  }
XX  
XX! rd_cmdline(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX    if (position == argc) return(-1);
XX!   return(atoi(argv[position++]));
XX  }
XX  
XX  
XX! modify(nr_blocks)
XX  {
XX    int i;
XX  
XX    if (nr_blocks == 0) return;
XX!   for (i = 0; i < nr_blocks; i++) {
XX! 	set_bit(block[i]);
XX! 	ip->i_zone[i] = block[i];
XX    }
XX!   ip->i_size = (long) (BLOCK_SIZE * nr_blocks);	/* give file size */
XX    put_inode(&stat_buf);		/* save the inode on disk */
XX    put_super();			/* bit_maps too */
XX  }
XX--- 397,441 ----
XX    modify(cnt);
XX    close(fd);			/* free device */
XX    done(SUCCESS);
XX+   return(0);
XX  }
XX  
XX! long rd_cmdline(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX    if (position == argc) return(-1);
XX!   return(atol(argv[position++]));
XX  }
XX  
XX  
XX! void modify(nr_blocks)
XX! int nr_blocks;
XX  {
XX    int i;
XX  
XX    if (nr_blocks == 0) return;
XX!   if (v1fs) {
XX! 	/* This is a V1 file system. */
XX! 	for (i = 0; i < nr_blocks; i++) {
XX! 		set_bit(block[i]);
XX! 		ip1->d1_zone[i] = block[i];
XX! 	}
XX!   } else {
XX! 	/* This is a V2 file system. */
XX! 	for (i = 0; i < nr_blocks; i++) {
XX! 		set_bit(block[i]);
XX! 		ip2->d2_zone[i] = block[i];
XX! 	}
XX    }
XX!   if (v1fs) {
XX! 	ip1->d1_size = (long) (BLOCK_SIZE * nr_blocks);	/* give file size */
XX! 	ip1->d1_mtime = 0;	/* Who wants a file from 1970? */
XX!   } else {
XX! 	ip2->d2_size = (long) (BLOCK_SIZE * nr_blocks);	/* give file size */
XX! 	ip2->d2_atime = ip2->d2_mtime = ip2->d2_ctime = 0;
XX!   }
XX! 
XX    put_inode(&stat_buf);		/* save the inode on disk */
XX    put_super();			/* bit_maps too */
XX  }
XX***************
XX*** 368,397 ****
XX  
XX  static blk_cnt = 0;
XX  
XX! save_blk(blk_num)
XX! int blk_num;
XX  {
XX    block[blk_cnt++] = blk_num;
XX  }
XX  
XX! reset_blks()
XX  {
XX    int i;
XX  
XX!   for (i = 0; i <= NR_DZONE_NUMS; i++)
XX  	block[i] = 0;		/* Note: Last block_number is set to zero */
XX    blk_cnt = 0;
XX  }
XX  
XX! show_blks()
XX  {
XX    int i;
XX  
XX!   for (i = 0; i < blk_cnt; i++) printf("Block[%d] = %d\n", i, block[i]);
XX  }
XX  
XX! blk_is_used(blk_num)
XX! int blk_num;
XX  {				/* return TRUE(1) if used */
XX    int i;
XX  
XX--- 443,473 ----
XX  
XX  static blk_cnt = 0;
XX  
XX! void save_blk(blk_num)
XX! block_t blk_num;
XX  {
XX    block[blk_cnt++] = blk_num;
XX  }
XX  
XX! void reset_blks()
XX  {
XX    int i;
XX  
XX!   for (i = 0; i <= V_NR_DZONES; i++)
XX  	block[i] = 0;		/* Note: Last block_number is set to zero */
XX    blk_cnt = 0;
XX  }
XX  
XX! void show_blks()
XX  {
XX    int i;
XX  
XX!   for (i = 0; i < blk_cnt; i++)
XX! 	printf("Block[%d] = %lu\n", i, (unsigned long) block[i]);
XX  }
XX  
XX! int blk_is_used(blk_num)
XX! block_t blk_num;
XX  {				/* return TRUE(1) if used */
XX    int i;
XX  
XX***************
XX*** 405,423 ****
XX  #define BIT_MAP_SHIFT	13
XX  #define INT_BITS	(SIZE_OF_INT << 3)
XX  
XX! blk_ok(num)			/* is this zone free (y/n) */
XX! unsigned num;
XX  {
XX!   long blk_offset;
XX    int rd;
XX!   int block, offset, words, bit, tst_word;
XX!   unsigned z_num;
XX  
XX-   if (num < 0) {
XX- 	return QUIT;		/* negative number is not allowed */
XX-   }
XX    if (blk_is_used(num)) {
XX! 	printf("Duplicate block (%d) given\n", num);
XX  	return NOT_OK;
XX    }
XX  
XX--- 481,496 ----
XX  #define BIT_MAP_SHIFT	13
XX  #define INT_BITS	(SIZE_OF_INT << 3)
XX  
XX! int blk_ok(num)			/* is this zone free (y/n) */
XX! block_t num;
XX  {
XX!   block_t blk_offset;
XX    int rd;
XX!   int blk, offset, words, bit, tst_word;
XX!   zone_t z_num;
XX  
XX    if (blk_is_used(num)) {
XX! 	printf("Duplicate block (%lu) given\n", (unsigned long) num);
XX  	return NOT_OK;
XX    }
XX  
XX***************
XX*** 426,442 ****
XX    z_num = num - (sp->s_firstdatazone - 1);	/* account offset */
XX  
XX    /* Calculate the word in the bitmap. */
XX!   block = z_num >> BIT_MAP_SHIFT;	/* which block */
XX!   offset = z_num - (block << BIT_MAP_SHIFT);	/* offset */
XX    words = z_num / INT_BITS;	/* which word */
XX  
XX!   blk_offset = (long) (2 + sp->s_imap_block);	/* zone map */
XX!   blk_offset *= (long) BLOCK_SIZE;	/* of course in block */
XX!   blk_offset += (long) (words * SIZE_OF_INT);	/* offset */
XX  
XX  
XX!   lseek(fd, 0L, SEEK_SET);	/* rewind */
XX!   lseek(fd, blk_offset, SEEK_SET);	/* set pointer at word */
XX  
XX    rd = read(fd, (char *) &tst_word, SIZE_OF_INT);
XX    if (rd != SIZE_OF_INT) {
XX--- 499,515 ----
XX    z_num = num - (sp->s_firstdatazone - 1);	/* account offset */
XX  
XX    /* Calculate the word in the bitmap. */
XX!   blk = z_num >> BIT_MAP_SHIFT;	/* which block */
XX!   offset = z_num - (blk << BIT_MAP_SHIFT);	/* offset */
XX    words = z_num / INT_BITS;	/* which word */
XX  
XX!   blk_offset = (block_t) (2 + sp->s_imap_blocks);	/* zone map */
XX!   blk_offset *= (block_t) BLOCK_SIZE;	/* of course in block */
XX!   blk_offset += (block_t) (words * SIZE_OF_INT);	/* offset */
XX  
XX  
XX!   lseek(fd, (off_t) 0, SEEK_SET);	/* rewind */
XX!   lseek(fd, (off_t) blk_offset, SEEK_SET);	/* set pointer at word */
XX  
XX    rd = read(fd, (char *) &tst_word, SIZE_OF_INT);
XX    if (rd != SIZE_OF_INT) {
XX***************
XX*** 450,483 ****
XX    if (((tst_word >> bit) & 01) == 0)	/* free */
XX  	return OK;
XX    else {
XX! 	printf("Bad number %d. ", num);
XX  	printf("This zone (block) is marked in bitmap\n");
XX  	return NOT_OK;
XX    }
XX  }
XX  
XX! set_bit(num)			/* write in the bitmap */
XX! unsigned num;
XX  {
XX    int rwd;
XX    long blk_offset;
XX!   int block, offset, words, tst_word, bit;
XX    unsigned z_num;
XX-   char wrd_str[17], bit_str[17];
XX  
XX!   z_num = num + 1 - sp->s_firstdatazone;
XX  
XX!   block = z_num >> BIT_MAP_SHIFT;	/* which block */
XX!   offset = z_num - (block << BIT_MAP_SHIFT);	/* offset in block */
XX!   words = offset / INT_BITS;	/* which word */
XX  
XX!   blk_offset = (long) (2 + sp->s_imap_block);
XX    blk_offset *= (long) BLOCK_SIZE;
XX    blk_offset += (long) (words * SIZE_OF_INT);
XX  
XX  
XX!   lseek(fd, 0L, SEEK_SET);	/* rewind */
XX!   lseek(fd, blk_offset, SEEK_SET);
XX  
XX    rwd = read(fd, (char *) &tst_word, SIZE_OF_INT);
XX    if (rwd != SIZE_OF_INT) {
XX--- 523,555 ----
XX    if (((tst_word >> bit) & 01) == 0)	/* free */
XX  	return OK;
XX    else {
XX! 	printf("Bad number %lu. ", (unsigned long) num);
XX  	printf("This zone (block) is marked in bitmap\n");
XX  	return NOT_OK;
XX    }
XX  }
XX  
XX! void set_bit(num)		/* write in the bitmap */
XX! zone_t num;
XX  {
XX    int rwd;
XX    long blk_offset;
XX!   int blk, offset, words, tst_word, bit;
XX    unsigned z_num;
XX  
XX!   z_num = num - (sp->s_firstdatazone - 1);
XX  
XX!   blk = z_num >> BIT_MAP_SHIFT;	/* which block */
XX!   offset = z_num - (blk << BIT_MAP_SHIFT);	/* offset in block */
XX!   words = z_num / INT_BITS;	/* which word */
XX  
XX!   blk_offset = (long) (2 + sp->s_imap_blocks);
XX    blk_offset *= (long) BLOCK_SIZE;
XX    blk_offset += (long) (words * SIZE_OF_INT);
XX  
XX  
XX!   lseek(fd, (off_t) 0, SEEK_SET);	/* rewind */
XX!   lseek(fd, (off_t) blk_offset, SEEK_SET);
XX  
XX    rwd = read(fd, (char *) &tst_word, SIZE_OF_INT);
XX    if (rwd != SIZE_OF_INT) {
XX***************
XX*** 487,493 ****
XX    bit = offset % INT_BITS;
XX    if (((tst_word >> bit) & 01) == 0) {	/* free */
XX  	lseek(fd, 0L, SEEK_SET);/* rewind */
XX! 	lseek(fd, blk_offset, SEEK_SET);
XX  	tst_word |= (1 << bit);	/* not free anymore */
XX  	rwd = write(fd, (char *) &tst_word, SIZE_OF_INT);
XX  	if (rwd != SIZE_OF_INT) {
XX--- 559,565 ----
XX    bit = offset % INT_BITS;
XX    if (((tst_word >> bit) & 01) == 0) {	/* free */
XX  	lseek(fd, 0L, SEEK_SET);/* rewind */
XX! 	lseek(fd, (off_t) blk_offset, SEEK_SET);
XX  	tst_word |= (1 << bit);	/* not free anymore */
XX  	rwd = write(fd, (char *) &tst_word, SIZE_OF_INT);
XX  	if (rwd != SIZE_OF_INT) {
XX***************
XX*** 497,512 ****
XX  	}
XX  	return;
XX    }
XX!   printf("Bit map indicates that block %u is in use. Not marked.\n",num);
XX  /*  done(DIR_CREATED); */
XX    return;
XX  }
XX  
XX   /* ======= interactive interface ======= */
XX  
XX! rd_num()
XX  {				/* read a number from stdin */
XX!   static num;
XX    int c;
XX  
XX    if (eofseen) return(-1);
XX--- 569,585 ----
XX  	}
XX  	return;
XX    }
XX!   printf("Bit map indicates that block %lu is in use. Not marked.\n",
XX! 	 (unsigned long) num);
XX  /*  done(DIR_CREATED); */
XX    return;
XX  }
XX  
XX   /* ======= interactive interface ======= */
XX  
XX! long rd_num()
XX  {				/* read a number from stdin */
XX!   long num;
XX    int c;
XX  
XX    if (eofseen) return(-1);
XX***************
XX*** 531,537 ****
XX  
XX  
XX  
XX! ok(str)
XX  char *str;
XX  {
XX    int c;
XX--- 604,610 ----
XX  
XX  
XX  
XX! int ok(str)
XX  char *str;
XX  {
XX    int c;
XX***************
XX*** 542,558 ****
XX  	       c != 'y' && c != 'n' && c != 'q')
XX  		if (c != '\n') printf(" Bad character %c\n", (char) c);
XX  	switch (c) {
XX! 	    case EOF:		return QUIT;
XX! 	    case 'y':		return OK;
XX! 	    case 'n':		return NOT_OK;
XX! 	    case 'q':		return QUIT;
XX  	}
XX  	printf("\n");
XX    }
XX  }
XX  
XX  
XX! done(nr)
XX  int nr;
XX  {
XX    switch (nr) {
XX--- 615,634 ----
XX  	       c != 'y' && c != 'n' && c != 'q')
XX  		if (c != '\n') printf(" Bad character %c\n", (char) c);
XX  	switch (c) {
XX! 	    case EOF:
XX! 		return QUIT;
XX! 	    case 'y':
XX! 		return OK;
XX! 	    case 'n':
XX! 		return NOT_OK;
XX! 	    case 'q':	return QUIT;
XX  	}
XX  	printf("\n");
XX    }
XX  }
XX  
XX  
XX! void done(nr)
XX  int nr;
XX  {
XX    switch (nr) {
XX***************
XX*** 562,571 ****
XX        case DEV_MOUNTED:
XX  	umount(dev_name);
XX        case DIR_CREATED:
XX! 	unlink(dir_name);
XX        case HARMLESS:;
XX    }
XX    sync();
XX    exit(nr == SUCCESS ? 0 : 1);
XX  }
XX- 
XX--- 638,646 ----
XX        case DEV_MOUNTED:
XX  	umount(dev_name);
XX        case DIR_CREATED:
XX! 	rmdir(dir_name);
XX        case HARMLESS:;
XX    }
XX    sync();
XX    exit(nr == SUCCESS ? 0 : 1);
XX  }
X/
Xecho x - banner.c.d
Xsed '/^X/s///' > banner.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/banner.c  crc=00311   6597	Sun Apr 25 21:34:46 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/banner.c  crc=52356   6710	Wed Nov  4 07:51:29 1992
XX***************
XX*** 20,59 ****
XX   *
XX   *****************************************************************/
XX  
XX  #include <stdio.h>
XX  
XX  char *glyphs[] = {
XX! 	  "         @@@  @@@ @@@  @ @   @@@@@ @@@   @  @@     @@@  ",
XX! 	"         @@@  @@@ @@@  @ @  @  @  @@ @  @  @  @    @@@   ",
XX! 	  "         @@@   @   @ @@@@@@@@  @   @@@ @    @@      @   ",
XX  	  "          @            @ @   @@@@@    @    @@@     @    ",
XX! 	  "                     @@@@@@@   @  @  @ @@@@   @ @       ",
XX! 	  "         @@@           @ @  @  @  @ @  @ @@    @        ",
XX! 	  "         @@@           @ @   @@@@@ @   @@@ @@@@ @       ",
XX  
XX  	  "   @@    @@                                            @",
XX  	  "  @        @   @   @    @                             @ ",
XX  	  " @          @   @ @     @                            @  ",
XX! 	  " @          @ @@@ @@@ @@@@@   @@@   @@@@@           @   ",
XX! 	  " @          @   @ @     @     @@@           @@@    @    ",
XX  	  "  @        @   @   @    @      @            @@@   @     ",
XX  	  "   @@    @@                   @             @@@  @      ",
XX  
XX  	  "  @@@     @    @@@@@  @@@@@ @      @@@@@@@ @@@@@ @@@@@@@",
XX  	  " @   @   @@   @     @@     @@    @ @      @     @@    @ ",
XX! 	  "@ @   @ @ @         @      @@    @ @      @          @  ",
XX  	  "@  @  @   @    @@@@@  @@@@@ @@@@@@@ @@@@@ @@@@@@    @   ",
XX! 	  "@   @ @   @   @            @     @       @@     @  @    ",
XX  	  " @   @    @   @      @     @     @ @     @@     @  @    ",
XX  	  "  @@@   @@@@@ @@@@@@@ @@@@@      @  @@@@@  @@@@@   @    ",
XX  
XX! 	  " @@@@@  @@@@@    @     @@@      @           @     @@@@@ ",
XX! 	  "@     @@     @  @ @    @@@     @             @   @     @",
XX! 	  "@     @@     @   @            @     @@@@@     @        @",
XX  	  " @@@@@  @@@@@@         @@@   @                 @     @@ ",
XX! 	  "@     @      @   @     @@@    @     @@@@@     @     @   ",
XX! 	  "@     @@     @  @ @     @      @             @          ",
XX! 	  " @@@@@  @@@@@    @     @        @           @       @   ",
XX  
XX  	  " @@@@@    @   @@@@@@  @@@@@ @@@@@@ @@@@@@@@@@@@@@ @@@@@ ",
XX  	  "@     @  @ @  @     @@     @@     @@      @      @     @",
XX--- 20,62 ----
XX   *
XX   *****************************************************************/
XX  
XX+ #include <string.h>
XX  #include <stdio.h>
XX  
XX+ _PROTOTYPE(int main, (int argc, char **argv));
XX+ 
XX  char *glyphs[] = {
XX! 	  "         @@@  @@   @@  @ @   @@@@@          @@     @@@  ",
XX! 	  "         @@@  @@   @@  @ @  @  @  @@@   @  @  @    @@@  ",
XX! 	  "         @@@   @   @ @@@@@@@@  @   @@  @    @@      @   ",
XX  	  "          @            @ @   @@@@@    @    @@@     @    ",
XX! 	  "                     @@@@@@@   @  @  @    @   @ @       ",
XX! 	  "         @@@           @ @  @  @  @ @  @@ @    @        ",
XX! 	  "         @@@           @ @   @@@@@ @   @@  @@@@ @       ",
XX  
XX  	  "   @@    @@                                            @",
XX  	  "  @        @   @   @    @                             @ ",
XX  	  " @          @   @ @     @                            @  ",
XX! 	  " @          @ @@@@@@@ @@@@@   @@@   @@@@@           @   ",
XX! 	  " @          @   @ @     @     @@@                  @    ",
XX  	  "  @        @   @   @    @      @            @@@   @     ",
XX  	  "   @@    @@                   @             @@@  @      ",
XX  
XX  	  "  @@@     @    @@@@@  @@@@@ @      @@@@@@@ @@@@@ @@@@@@@",
XX  	  " @   @   @@   @     @@     @@    @ @      @     @@    @ ",
XX! 	  "@   @ @ @ @         @      @@    @ @      @          @  ",
XX  	  "@  @  @   @    @@@@@  @@@@@ @@@@@@@ @@@@@ @@@@@@    @   ",
XX! 	  "@ @   @   @   @            @     @       @@     @  @    ",
XX  	  " @   @    @   @      @     @     @ @     @@     @  @    ",
XX  	  "  @@@   @@@@@ @@@@@@@ @@@@@      @  @@@@@  @@@@@   @    ",
XX  
XX! 	  " @@@@@  @@@@@          @@@      @           @     @@@@@ ",
XX! 	  "@     @@     @  @@@    @@@     @             @   @     @",
XX! 	  "@     @@     @  @@@           @     @@@@@     @        @",
XX  	  " @@@@@  @@@@@@         @@@   @                 @     @@ ",
XX! 	  "@     @      @         @@@    @     @@@@@     @     @   ",
XX! 	  "@     @@     @  @@@     @      @             @          ",
XX! 	  " @@@@@  @@@@@   @@@    @        @           @       @   ",
XX  
XX  	  " @@@@@    @   @@@@@@  @@@@@ @@@@@@ @@@@@@@@@@@@@@ @@@@@ ",
XX  	  "@     @  @ @  @     @@     @@     @@      @      @     @",
XX***************
XX*** 117,126 ****
XX  	  "   @@      @      @  @@                 @@        @ @ @ ",
XX  	  "   @@      @     @    @        @        @        @ @ @ @",
XX  	  "  @  @     @    @     @        @        @         @ @ @ ",
XX! 	" @    @    @   @@@@@@  @@@     @     @@@         @ @ @ @"};
XX  
XX! 
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX--- 120,129 ----
XX  	  "   @@      @      @  @@                 @@        @ @ @ ",
XX  	  "   @@      @     @    @        @        @        @ @ @ @",
XX  	  "  @  @     @    @     @        @        @         @ @ @ ",
XX! 	  " @    @    @   @@@@@@  @@@     @     @@@         @ @ @ @"
XX! };
XX  
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX***************
XX*** 134,140 ****
XX  		for (b = 0; b < len; b++) {
XX  			if ((ind = (*argv)[b] - ' ') < 0) ind = 0;
XX  			for (c = 0; c < 7; c++) {
XX! 				line[b * 8 + c] = glyphs[(ind / 8 * 7) + a][(ind % 8 * 7) + c];
XX  			}
XX  			line[b * 8 + 7] = ' ';
XX  		}
XX--- 137,143 ----
XX  		for (b = 0; b < len; b++) {
XX  			if ((ind = (*argv)[b] - ' ') < 0) ind = 0;
XX  			for (c = 0; c < 7; c++) {
XX! 				line[b * 8 + c] = glyphs[(ind / 8 * 7) + a][(ind % 8 * 7) + c] == '@' ? ind + ' ' : ' ';
XX  			}
XX  			line[b * 8 + 7] = ' ';
XX  		}
XX***************
XX*** 146,149 ****
XX--- 149,153 ----
XX  	}
XX  	printf("\n");
XX    }
XX+   return(0);
XX  }
X/
Xecho x - basename.c.d
Xsed '/^X/s///' > basename.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/basename.c  crc=39542    609	Sun Apr 25 21:34:46 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/basename.c  crc=16635   1896	Wed Nov  4 04:19:04 1992
XX***************
XX*** 1,35 ****
XX! /* basename - print the last part of a path:	Author: Blaine Garfolo */
XX  
XX! #define NULL 0
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX!   int j, suflen;
XX!   char *c;
XX!   char *d;
XX!   extern char *rindex();
XX  
XX!   if (argc < 2) {
XX! 	std_err("Usage: basename string [suffix]  \n");
XX  	exit(1);
XX    }
XX-   c = argv[1];
XX-   d = rindex(argv[1], '/');
XX-   if (d == NULL)
XX- 	d = argv[1];
XX-   else
XX- 	d++;
XX  
XX!   if (argc == 2) {		/* if no suffix */
XX! 	prints("%s\n", d);
XX  	exit(0);
XX-   } else {			/* if suffix is present */
XX- 	c = d;
XX- 	suflen = strlen(argv[2]);
XX- 	j = strlen(c) - suflen;
XX- 	if (strcmp(c + j, argv[2]) == 0) *(c + j) = 0;
XX    }
XX!   prints("%s\n", c);
XX  }
XX--- 1,76 ----
XX! /* basename - print last part of a path      Authors: B. Garfolo & P. Nelson */
XX  
XX! /* Basename - print the last part of a path.
XX!  *
XX!  *    For MINIX  --  Conforms to POSIX - P1003.2/D10
XX!  *      Exception -- it ignores the LC environment variables.
XX!  *
XX!  *    Original MINIX author:  Blaine Garfolo
XX!  *    POSIX rewrite author:   Philip A. Nelson
XX!  *
XX!  *    POSIX version - October 20, 1990
XX!  *      Feb 14, 1991: changed rindex to strrchr. (PAN)
XX!  *
XX!  */
XX  
XX! 
XX! #include <string.h>
XX! #include <stdlib.h>
XX! #include <stdio.h>
XX! 
XX! #define EOS '\0'
XX! 
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! 
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX!   char *result_string;		/* The pointer into argv[1]. */
XX!   char *temp;			/* Used to move around in argv[1]. */
XX!   int suffix_len;		/* Length of the suffix. */
XX!   int suffix_start;		/* Where the suffix should start. */
XX  
XX! 
XX!   /* Check for the correct number of arguments. */
XX!   if ((argc < 2) || (argc > 3)) {
XX! 	fprintf(stderr, "Usage: basename string [suffix] \n");
XX  	exit(1);
XX    }
XX  
XX!   /* Check for all /'s */
XX!   for (temp = argv[1]; *temp == '/'; temp++)	/* Move to next char. */
XX! 	;
XX!   if (*temp == EOS) {
XX! 	printf("/\n");
XX  	exit(0);
XX    }
XX! 
XX!   /* Build the basename. */
XX!   result_string = argv[1];
XX! 
XX!   /* Find the last /'s */
XX!   temp = strrchr(result_string, '/');
XX! 
XX!   if (temp != NULL) {
XX! 	/* Remove trailing /'s. */
XX! 	while ((*(temp + 1) == EOS) && (*temp == '/')) *temp-- = EOS;
XX! 
XX! 	/* Set result_string to last part of path. */
XX! 	if (*temp != '/') temp = strrchr(result_string, '/');
XX! 	if (temp != NULL && *temp == '/') result_string = temp + 1;
XX!   }
XX! 
XX!   /* Remove the suffix, if any. */
XX!   if (argc > 2) {
XX! 	suffix_len = strlen(argv[2]);
XX! 	suffix_start = strlen(result_string) - suffix_len;
XX! 	if (suffix_start > 0)
XX! 		if (strcmp(result_string + suffix_start, argv[2]) == EOS)
XX! 			*(result_string + suffix_start) = EOS;
XX!   }
XX! 
XX!   /* Print the resultant string. */
XX!   printf("%s\n", result_string);
XX!   return(0);
XX  }
X/
Xecho x - btoa.c.d
Xsed '/^X/s///' > btoa.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/btoa.c  crc=57022  28324	Sun Apr 25 21:34:47 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/btoa.c  crc=24998  27635	Wed Nov  4 04:19:05 1992
XX***************
XX*** 71,76 ****
XX--- 71,77 ----
XX  #include <sys/types.h>
XX  #include <ctype.h>
XX  #include <string.h>
XX+ #include <stdlib.h>
XX  #include <stdio.h>
XX  
XX  #define MAXPERLINE      78
XX***************
XX*** 91,140 ****
XX    struct Diagnosis *next, *last;
XX  };
XX  
XX- extern char *malloc();
XX- 
XX  /* Following functions have been converted to macros:  calcchecksum() */
XX  
XX  
XX- #if LATTICE			/* Prototypes for Lattice C */
XX- 
XX- void asciiout(int), exit(int),
XX-  intodiaglist(struct Diagnosis *, LONG, LONG),
XX-  outdiaglist(struct Diagnosis *, LONG *, LONG *), printhelp(void),
XX-  producediag(struct Diagnosis *, FILE *), wordout(LONG);
XX- 
XX- BYTE atob(FILE *), btoa(FILE *, BYTE *), copyfile(FILE *, FILE *, BYTE *),
XX-  decode_line(BYTE *, int), new_decodefile(FILE *, LONG *, LONG, int),
XX-  old_decodefile(FILE *, LONG *), performrepair(FILE *),
XX-  pro_repair(FILE *), readbuffer(BYTE *, BYTE *, FILE *),
XX- *truncname(BYTE *);
XX- 
XX- int nextbyte(FILE *);
XX- 
XX- FILE *fopen_read(BYTE *), *fopen_write(BYTE *);
XX- 
XX- #if USE_MACROS
XX- void calcchecksum(int);
XX- #endif /* USE_MACROS */
XX- 
XX- #else /* !LATTICE */	/* For compilers which don't know about prototypes. */
XX- 
XX- void asciiout(), exit(), intodiaglist(), outdiaglist(),
XX-  printhelp(), producediag(), wordout();
XX- 
XX- BYTE atob(), btoa(), copyfile(), decode_line(), new_decodefile(),
XX-  old_decodefile(), performrepair(), pro_repair(), readbuffer(),
XX- *truncname();
XX- 
XX- int nextbyte();
XX- 
XX- FILE *fopen_read(), *fopen_write();
XX- 
XX- #if USE_MACROS
XX- void calcchecksum();
XX- #endif /* USE_MACROS */
XX- 
XX- #endif /* LATTICE */
XX  /* Chksum.h */
XX  /* Calcchecksum() was converted to a macro for effectivity reasons. */
XX  /* Don't (!!) give it an argument that has to be evaluated. This    */
XX--- 92,121 ----
XX    struct Diagnosis *next, *last;
XX  };
XX  
XX  /* Following functions have been converted to macros:  calcchecksum() */
XX  
XX+ _PROTOTYPE(int main, (int argc, char **argv));
XX+ _PROTOTYPE(BYTE btoa, (FILE *infile, BYTE *infilename));
XX+ _PROTOTYPE(void printhelp, (void));
XX+ _PROTOTYPE(void calcchecksum, (int ch));
XX+ _PROTOTYPE(void wordout, (LONG codeword));
XX+ _PROTOTYPE(void asciiout, (int ch));
XX+ _PROTOTYPE(BYTE *truncname, (BYTE *name));
XX+ _PROTOTYPE(BYTE atob, (FILE *infile));
XX+ _PROTOTYPE(int nextbyte, (FILE *infile));
XX+ _PROTOTYPE(BYTE new_decodefile, (FILE *infile, LONG *lastline, LONG filepos, int maxperline));
XX+ _PROTOTYPE(BYTE old_decodefile, (FILE *infile, LONG *lastline));
XX+ _PROTOTYPE(BYTE decode_line, (BYTE *buffer, int length));
XX+ _PROTOTYPE(void producediag, (struct Diagnosis *diaglist, FILE *infile));
XX+ _PROTOTYPE(void intodiaglist, (struct Diagnosis *diaglist, LONG startpos, LONG endpos));
XX+ _PROTOTYPE(void outdiaglist, (struct Diagnosis *diaglist, LONG *startpos, LONG *endpos));
XX+ _PROTOTYPE(BYTE copyfile, (FILE *infile, FILE *outfile, BYTE *searchstring));
XX+ _PROTOTYPE(BYTE readbuffer, (BYTE *buffer, BYTE *errormsg, FILE *infile));
XX+ _PROTOTYPE(FILE *fopen_read, (BYTE *filename));
XX+ _PROTOTYPE(FILE *fopen_write, (BYTE *filename));
XX+ _PROTOTYPE(BYTE pro_repair, (FILE *infile));
XX+ _PROTOTYPE(BYTE performrepair, (FILE *infile));
XX  
XX  /* Chksum.h */
XX  /* Calcchecksum() was converted to a macro for effectivity reasons. */
XX  /* Don't (!!) give it an argument that has to be evaluated. This    */
XX***************
XX*** 144,151 ****
XX  
XX  #define calcchecksum(ch)        \
XX  {                               \
XX-   extern LONG Ceor, Csum, Crot; \
XX-                                 \
XX    Ceor ^= ch;                   \
XX    Csum += ch + 1;               \
XX                                  \
XX--- 125,130 ----
XX***************
XX*** 177,191 ****
XX  FILE *outfile;
XX  
XX  
XX! void main(argc, argv)
XX  int argc;
XX! BYTE **argv;
XX  {
XX    register BYTE openinput, error, ch, a_to_b, diag, repair;
XX    register BYTE *infilename, *text;
XX    register FILE *infile;
XX-   extern BYTE new_version, openoutput;
XX-   extern FILE *outfile;
XX  #ifdef AMIGA
XX    extern int _bufsiz;
XX  
XX--- 156,168 ----
XX  FILE *outfile;
XX  
XX  
XX! int main(argc, argv)
XX  int argc;
XX! char **argv;
XX  {
XX    register BYTE openinput, error, ch, a_to_b, diag, repair;
XX    register BYTE *infilename, *text;
XX    register FILE *infile;
XX  #ifdef AMIGA
XX    extern int _bufsiz;
XX  
XX***************
XX*** 267,272 ****
XX--- 244,250 ----
XX    if (openoutput) fclose(outfile);
XX  
XX    if (error) exit(1);
XX+   return(0);
XX  }
XX  
XX  
XX***************
XX*** 276,284 ****
XX  {
XX    register LONG codeword, filesize;
XX    register int ch1, ch2, ch3, ch4, readbytes;
XX-   extern FILE *outfile;
XX-   extern BYTE new_version, buffer[BUFSIZE];
XX-   extern LONG Ceor, Csum, Crot;
XX  
XX    Ceor = Csum = Crot = 0;
XX  
XX--- 254,259 ----
XX***************
XX*** 292,298 ****
XX    /* Encode entire input file. */
XX    filesize = 0;
XX    do {
XX! 	readbytes = fread(buffer, 1, 4, infile);
XX  
XX  	if (readbytes < 4) {
XX  		ch1 = (readbytes > 0) ? ((int) buffer[0] & 0xFF) : 0;
XX--- 267,273 ----
XX    /* Encode entire input file. */
XX    filesize = 0;
XX    do {
XX! 	readbytes = fread(buffer, (size_t)1, (size_t)4, infile);
XX  
XX  	if (readbytes < 4) {
XX  		ch1 = (readbytes > 0) ? ((int) buffer[0] & 0xFF) : 0;
XX***************
XX*** 362,369 ****
XX  void calcchecksum(ch)
XX  register int ch;
XX  {
XX-   extern LONG Ceor, Csum, Crot;
XX- 
XX    Ceor ^= ch;
XX    Csum += ch + 1;
XX  
XX--- 337,342 ----
XX***************
XX*** 380,386 ****
XX  register LONG codeword;
XX  {
XX    register int tmp, quote;
XX-   extern BYTE new_version;
XX  
XX    if (codeword == 0)		/* Encode 4 zeros as a 'z'. */
XX  	asciiout('z');
XX--- 353,358 ----
XX***************
XX*** 429,437 ****
XX  register int ch;
XX  {
XX    static WORD linepos = 0;
XX-   extern FILE *outfile;
XX-   extern LONG Csum;
XX-   extern BYTE new_version;
XX  
XX    if (ch == EOF) {		/* Signal to flush buffer. */
XX  	/* Linepos == 0 means '\n' just written in asciiout(). This */
XX--- 401,406 ----
XX***************
XX*** 495,503 ****
XX    int maxperline;
XX    LONG n1, n2, oeor, osum, orot, lastline;
XX    static BYTE outfilename[BUFSIZE];
XX-   extern LONG Ceor, Csum, Crot;
XX-   extern FILE *outfile;
XX-   extern BYTE new_version, openoutput, buffer[BUFSIZE];
XX  
XX    error = FALSE;
XX  
XX--- 464,469 ----
XX***************
XX*** 507,513 ****
XX  
XX  	if (readbuffer(buffer, "archive", infile)) error = TRUE;
XX    }
XX!   while (!(error || strncmp(buffer, "xbtoa", 5) == 0));
XX  
XX    if (!error)
XX  	if (strcmp(buffer, "xbtoa Begin\n") == 0) {
XX--- 473,479 ----
XX  
XX  	if (readbuffer(buffer, "archive", infile)) error = TRUE;
XX    }
XX!   while (!(error || strncmp(buffer, "xbtoa", (size_t)5) == 0));
XX  
XX    if (!error)
XX  	if (strcmp(buffer, "xbtoa Begin\n") == 0) {
XX***************
XX*** 577,584 ****
XX    register BYTE stop, error, newerror, errorstart;
XX    register LONG line, prevfilepos, startpos;
XX    struct Diagnosis diaglist;
XX-   extern LONG Csum;
XX-   extern BYTE buffer[BUFSIZE];
XX  
XX    error = FALSE;
XX  
XX--- 543,548 ----
XX***************
XX*** 620,644 ****
XX  		}
XX  		if (newerror)
XX  			fprintf(stderr, "btoa: Bad line length on line %ld.\n", line);
XX! 	}
XX! 	if (!(newerror || stop)) {
XX! 		if (decode_line(buffer, length - 1)) {
XX! 			if (!error)
XX! 				fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
XX! 			newerror = TRUE;
XX! 		}
XX! 
XX! 		/* Examine checksum. */
XX! 		if ((ch = buffer[length - 1]) == ENCODE(Csum % 85)) {
XX! 			if (errorstart) {
XX! 				intodiaglist(&diaglist, startpos, filepos);
XX! 				errorstart = FALSE;
XX  			}
XX! 		} else {
XX! 			newerror = TRUE;
XX! 			fprintf(stderr, "btoa: Bad checksum on line %ld.\n", line);
XX! 			Csum = DECODE(ch);	/* Make Csum correct
XX! 						 * (modulo 85). */
XX  		}
XX  	}
XX  	if (newerror) {
XX--- 584,608 ----
XX  		}
XX  		if (newerror)
XX  			fprintf(stderr, "btoa: Bad line length on line %ld.\n", line);
XX! 		if (!(newerror || stop)) {
XX! 			if (decode_line(buffer, length - 1)) {
XX! 				if (!error)
XX! 					fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
XX! 				newerror = TRUE;
XX  			}
XX! 	
XX! 			/* Examine checksum. */
XX! 			if ((ch = buffer[length - 1]) == ENCODE(Csum % 85)) {
XX! 				if (errorstart) {
XX! 					intodiaglist(&diaglist, startpos, filepos);
XX! 					errorstart = FALSE;
XX! 				}
XX! 			} else {
XX! 				newerror = TRUE;
XX! 				fprintf(stderr, "btoa: Bad checksum on line %ld.\n", line);
XX! 				Csum = DECODE(ch);	/* Make Csum correct
XX! 							 * (modulo 85). */
XX! 			}
XX  		}
XX  	}
XX  	if (newerror) {
XX***************
XX*** 672,678 ****
XX    register int length;
XX    register BYTE stop, error;
XX    register LONG line;
XX-   extern BYTE buffer[BUFSIZE];
XX  
XX    error = FALSE;
XX  
XX--- 636,641 ----
XX***************
XX*** 690,703 ****
XX  		if (buffer[length] != '\n')
XX  			error = stop = TRUE;	/* The line was longer
XX  						 * than the buffer. */
XX! 	}
XX! 
XX! 	if (!stop) {
XX! 		if (decode_line(buffer, length)) {
XX! 			fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
XX! 			error = stop = TRUE;
XX  		}
XX  	}
XX    }
XX  
XX    *lastline = line;
XX--- 653,666 ----
XX  		if (buffer[length] != '\n')
XX  			error = stop = TRUE;	/* The line was longer
XX  						 * than the buffer. */
XX! 		else {
XX! 			if (decode_line(buffer, length)) {
XX! 				fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
XX! 				error = stop = TRUE;
XX! 			}
XX  		}
XX  	}
XX+ 
XX    }
XX  
XX    *lastline = line;
XX***************
XX*** 706,727 ****
XX  }
XX  
XX  
XX! BYTE decode_line(buffer, length)
XX! register BYTE *buffer;
XX  register int length;
XX  {
XX    register int ch;
XX    register BYTE error;
XX    register LONG tmp_codeword;
XX-   extern BYTE new_version;
XX-   extern FILE *outfile;
XX    static LONG codeword;
XX    static int ch1, ch2, ch3, ch4;
XX    static BYTE bytecount = 0;
XX  
XX    error = FALSE;
XX  
XX!   if (buffer == NULL) {		/* Flush last characters. */
XX  	if (bytecount > 0) {
XX  		fputc(ch1, outfile);
XX  		if (length > 0) fputc(ch2, outfile);
XX--- 669,688 ----
XX  }
XX  
XX  
XX! BYTE decode_line(buf, length)
XX! register BYTE *buf;
XX  register int length;
XX  {
XX    register int ch;
XX    register BYTE error;
XX    register LONG tmp_codeword;
XX    static LONG codeword;
XX    static int ch1, ch2, ch3, ch4;
XX    static BYTE bytecount = 0;
XX  
XX    error = FALSE;
XX  
XX!   if (buf == NULL) {		/* Flush last characters. */
XX  	if (bytecount > 0) {
XX  		fputc(ch1, outfile);
XX  		if (length > 0) fputc(ch2, outfile);
XX***************
XX*** 731,737 ****
XX    } else {
XX  	while (length > 0) {
XX  		length--;
XX! 		ch = *buffer++;
XX  
XX  		/* Delayed output. This is to make sure that files
XX  		 * with lengths */
XX--- 692,698 ----
XX    } else {
XX  	while (length > 0) {
XX  		length--;
XX! 		ch = *buf++;
XX  
XX  		/* Delayed output. This is to make sure that files
XX  		 * with lengths */
XX***************
XX*** 760,766 ****
XX  					codeword = codeword * 85 + DECODE(ch);
XX  
XX  				for (bytecount++; bytecount < 5; bytecount++) {
XX! 					ch = *buffer++;
XX  					if (new_version) calcchecksum(ch);
XX  					codeword = codeword * 85 + DECODE(ch);
XX  				}
XX--- 721,727 ----
XX  					codeword = codeword * 85 + DECODE(ch);
XX  
XX  				for (bytecount++; bytecount < 5; bytecount++) {
XX! 					ch = *buf++;
XX  					if (new_version) calcchecksum(ch);
XX  					codeword = codeword * 85 + DECODE(ch);
XX  				}
XX***************
XX*** 842,848 ****
XX    register FILE *diagfile;
XX    LONG startpos, endpos;
XX    register LONG currentpos;
XX-   extern BYTE *diagname, *diagheader, buffer[BUFSIZE];
XX  
XX    currentpos = ftell(infile);
XX  
XX--- 803,808 ----
XX***************
XX*** 918,932 ****
XX  
XX  	diaglist->next = diagitem->next;
XX  	free((BYTE *) diagitem);
XX! 	if (diaglist->next == NULL) diaglist->last = NULL;
XX    }
XX  }
XX  
XX  
XX  /* Copy infile to outfile until searchstring is found. If outfile */
XX  /* Is NULL nothing will be written.                               */
XX! BYTE copyfile(infile, outfile, searchstring)
XX! register FILE *infile, *outfile;
XX  register BYTE *searchstring;
XX  {
XX    register BYTE stop, error;
XX--- 878,893 ----
XX  
XX  	diaglist->next = diagitem->next;
XX  	free((BYTE *) diagitem);
XX! 	if (diaglist->next == NULL)
XX! 	    diaglist->last = NULL;
XX    }
XX  }
XX  
XX  
XX  /* Copy infile to outfile until searchstring is found. If outfile */
XX  /* Is NULL nothing will be written.                               */
XX! BYTE copyfile(infile, outfil, searchstring)
XX! register FILE *infile, *outfil;
XX  register BYTE *searchstring;
XX  {
XX    register BYTE stop, error;
XX***************
XX*** 937,943 ****
XX  	if (readbuffer(copybuffer, "archive", infile))
XX  		error = TRUE;
XX  	else {
XX! 		if (outfile != NULL) fputs(copybuffer, outfile);
XX  		if (strcmp(copybuffer, searchstring) == 0) stop = TRUE;
XX  	}
XX  
XX--- 898,904 ----
XX  	if (readbuffer(copybuffer, "archive", infile))
XX  		error = TRUE;
XX  	else {
XX! 		if (outfil != NULL) fputs(copybuffer, outfil);
XX  		if (strcmp(copybuffer, searchstring) == 0) stop = TRUE;
XX  	}
XX  
XX***************
XX*** 947,960 ****
XX  
XX  /* Read a line from infile into buffer. Returns TRUE if */
XX  /* End-of-file has been reached.                        */
XX! BYTE readbuffer(buffer, errormsg, infile)
XX! register BYTE *buffer, *errormsg;
XX  register FILE *infile;
XX  {
XX    register BYTE error;
XX  
XX    error = FALSE;
XX!   if (fgets(buffer, BUFSIZE, infile) == NULL) {
XX  	fprintf(stderr, "btoa: Unexpected end of %s file.\n", errormsg);
XX  	error = TRUE;
XX    }
XX--- 908,921 ----
XX  
XX  /* Read a line from infile into buffer. Returns TRUE if */
XX  /* End-of-file has been reached.                        */
XX! BYTE readbuffer(buf, errormsg, infile)
XX! register BYTE *buf, *errormsg;
XX  register FILE *infile;
XX  {
XX    register BYTE error;
XX  
XX    error = FALSE;
XX!   if (fgets(buf, BUFSIZE, infile) == NULL) {
XX  	fprintf(stderr, "btoa: Unexpected end of %s file.\n", errormsg);
XX  	error = TRUE;
XX    }
XX***************
XX*** 977,988 ****
XX  FILE *fopen_write(filename)
XX  register BYTE *filename;
XX  {
XX!   register FILE *outfile;
XX  
XX!   if ((outfile = fopen(filename, "w")) == NULL)
XX  	fprintf(stderr, "btoa: Can't open '%s' for output.\n", filename);
XX  
XX!   return(outfile);
XX  }
XX  
XX  
XX--- 938,949 ----
XX  FILE *fopen_write(filename)
XX  register BYTE *filename;
XX  {
XX!   register FILE *outfil;
XX  
XX!   if ((outfil = fopen(filename, "w")) == NULL)
XX  	fprintf(stderr, "btoa: Can't open '%s' for output.\n", filename);
XX  
XX!   return(outfil);
XX  }
XX  
XX  
XX***************
XX*** 993,999 ****
XX    register FILE *repairfile, *diagfile;
XX    register BYTE error, stop;
XX    static BYTE *errormsg = "diag";
XX-   extern BYTE *diagname, *diagheader, *repairname, *repairheader, buffer[BUFSIZE];
XX  
XX    error = FALSE;
XX    diagfile = repairfile = NULL;
XX--- 954,959 ----
XX***************
XX*** 1059,1065 ****
XX    register FILE *repairfile, *outfile;
XX    register BYTE error, stop;
XX    static BYTE *errormsg = "repair";
XX-   extern BYTE *repairname, *repairedname, *repairheader, buffer[BUFSIZE];
XX  
XX    error = FALSE;
XX    repairfile = outfile = NULL;
XX--- 1019,1024 ----
XX***************
XX*** 1104,1114 ****
XX    }
XX  
XX    if (!error)			/* Write rest of archive. */
XX! 	while (fgets(buffer, BUFSIZE, infile) != NULL)
XX  		fputs(buffer, outfile);
XX  
XX!   if (outfile != NULL) fclose(outfile);
XX!   if (repairfile != NULL) fclose(repairfile);
XX  
XX    return(error);
XX  }
XX--- 1063,1073 ----
XX    }
XX  
XX    if (!error)			/* Write rest of archive. */
XX! 	while (fgets(buffer, BUFSIZE, infile) != (char *)NULL)
XX  		fputs(buffer, outfile);
XX  
XX!   if (outfile != (FILE *)NULL) fclose(outfile);
XX!   if (repairfile != (FILE *)NULL) fclose(repairfile);
XX  
XX    return(error);
XX  }
X/
Xecho x - cal.c.d
Xsed '/^X/s///' > cal.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/cal.c  crc=01661   7795	Sun Apr 25 21:34:47 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/cal.c  crc=26281   8318	Wed Nov  4 04:19:05 1992
XX***************
XX*** 1,5 ****
XX--- 1,7 ----
XX  /* cal - print a calendar		Author: Maritn Minow */
XX  
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX  #include <stdio.h>
XX  
XX  #define do3months	domonth
XX***************
XX*** 31,41 ****
XX  	     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
XX  };
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX-   register int month;
XX    register int year;
XX  
XX    register int arg1val;
XX--- 33,53 ----
XX  	     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
XX  };
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void doyear, (int year));
XX! _PROTOTYPE(void domonth, (int year, int month));
XX! _PROTOTYPE(void output, (int nmonths));
XX! _PROTOTYPE(void calendar, (int year, int month, int indx));
XX! _PROTOTYPE(void usage, (char *s));
XX! _PROTOTYPE(int date, (int year, int month, int week, int wday));
XX! _PROTOTYPE(void setmonth, (int year, int month));
XX! _PROTOTYPE(int getdate, (int week, int wday));
XX! _PROTOTYPE(static int Jan1, (int year));
XX! 
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX    register int year;
XX  
XX    register int arg1val;
XX***************
XX*** 64,73 ****
XX  			do3months(arg2val, arg1val);
XX  	}
XX    }
XX!   exit(IO_SUCCESS);
XX  }
XX  
XX! doyear(year)
XX  int year;
XX  /* Print the calendar for an entire year. */
XX  {
XX--- 76,85 ----
XX  			do3months(arg2val, arg1val);
XX  	}
XX    }
XX!   return(IO_SUCCESS);
XX  }
XX  
XX! void doyear(year)
XX  int year;
XX  /* Print the calendar for an entire year. */
XX  {
XX***************
XX*** 95,101 ****
XX    printf("\n\n\n");
XX  }
XX  
XX! domonth(year, month)
XX  int year;
XX  int month;
XX  /* Do one specific month -- note: no longer used */
XX--- 107,113 ----
XX    printf("\n\n\n");
XX  }
XX  
XX! void domonth(year, month)
XX  int year;
XX  int month;
XX  /* Do one specific month -- note: no longer used */
XX***************
XX*** 108,114 ****
XX    printf("\n\n");
XX  }
XX  
XX! output(nmonths)
XX  int nmonths;			/* Number of months to do	 */
XX  /* Clean up and output the text. */
XX  {
XX--- 120,126 ----
XX    printf("\n\n");
XX  }
XX  
XX! void output(nmonths)
XX  int nmonths;			/* Number of months to do	 */
XX  /* Clean up and output the text. */
XX  {
XX***************
XX*** 135,144 ****
XX    }
XX  }
XX  
XX! calendar(year, month, index)
XX  int year;
XX  int month;
XX! int index;			/* Which of the three months		 */
XX  /* Actually build the calendar for this month. */
XX  {
XX    register char *tp;
XX--- 147,156 ----
XX    }
XX  }
XX  
XX! void calendar(year, month, indx)
XX  int year;
XX  int month;
XX! int indx;			/* Which of the three months		 */
XX  /* Actually build the calendar for this month. */
XX  {
XX    register char *tp;
XX***************
XX*** 149,155 ****
XX    setmonth(year, month);
XX    for (week = 0; week < WEEKS_PER_MONTH; week++) {
XX  	for (wday = 0; wday < DAYS_PER_WEEK; wday++) {
XX! 		tp = &layout[index][week][wday][0];
XX  		*tp++ = ' ';
XX  		today = getdate(week, wday);
XX  		if (today <= 0) {
XX--- 161,167 ----
XX    setmonth(year, month);
XX    for (week = 0; week < WEEKS_PER_MONTH; week++) {
XX  	for (wday = 0; wday < DAYS_PER_WEEK; wday++) {
XX! 		tp = &layout[indx][week][wday][0];
XX  		*tp++ = ' ';
XX  		today = getdate(week, wday);
XX  		if (today <= 0) {
XX***************
XX*** 166,172 ****
XX    }
XX  }
XX  
XX! usage(s)
XX  char *s;
XX  {
XX  /* Fatal parameter error. */
XX--- 178,184 ----
XX    }
XX  }
XX  
XX! void usage(s)
XX  char *s;
XX  {
XX  /* Fatal parameter error. */
XX***************
XX*** 220,226 ****
XX    return(getdate(week, wday));
XX  }
XX  
XX! setmonth(year, month)
XX  int year;			/* Year to compute		 */
XX  int month;			/* Month, January is month 1	 */
XX  /* Setup the parameters needed to compute this month
XX--- 232,238 ----
XX    return(getdate(week, wday));
XX  }
XX  
XX! void setmonth(year, month)
XX  int year;			/* Year to compute		 */
XX  int month;			/* Month, January is month 1	 */
XX  /* Setup the parameters needed to compute this month
X/
Xecho x - cat.c.d
Xsed '/^X/s///' > cat.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/cat.c  crc=32311   1702	Sun Apr 25 21:34:47 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/cat.c  crc=45262   1967	Wed Nov  4 04:19:05 1992
XX***************
XX*** 8,19 ****
XX--- 8,27 ----
XX  #include <fcntl.h>
XX  #include <string.h>
XX  #include <unistd.h>
XX+ #include <stdlib.h>
XX+ #include <minix/minlib.h>
XX+ #include <stdio.h>
XX  
XX  static int unbuffered;
XX  static char ibuf[BLOCK_SIZE];
XX  static char obuf[BLOCK_SIZE];
XX  static char *op = obuf;
XX  
XX+ _PROTOTYPE(int main, (int argc, char **argv));
XX+ _PROTOTYPE(void copyfile, (int ifd, int ofd));
XX+ _PROTOTYPE(void flush, (void));
XX+ _PROTOTYPE(void fatal, (void));
XX+ 
XX  int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX***************
XX*** 46,55 ****
XX  	}
XX    }
XX    flush();
XX!   exit(0);
XX  }
XX  
XX! copyfile(ifd, ofd)
XX  int ifd, ofd;
XX  {
XX    int n;
XX--- 54,63 ----
XX  	}
XX    }
XX    flush();
XX!   return(0);
XX  }
XX  
XX! void copyfile(ifd, ofd)
XX  int ifd, ofd;
XX  {
XX    int n;
XX***************
XX*** 65,91 ****
XX  
XX  		bytes_left = &obuf[BLOCK_SIZE] - op;
XX  		if (n <= bytes_left) {
XX! 			memcpy(op, ibuf, n);
XX  			op += n;
XX  		} else {
XX! 			memcpy(op, ibuf, bytes_left);
XX  			if (write(ofd, obuf, BLOCK_SIZE) != BLOCK_SIZE)
XX  				fatal();
XX  			n -= bytes_left;
XX! 			memcpy(obuf, ibuf + bytes_left, n);
XX  			op = obuf + n;
XX  		}
XX  	}
XX    }
XX  }
XX  
XX! flush()
XX  {
XX    if (op != obuf)
XX  	if (write(STDOUT_FILENO, obuf, (size_t) (op - obuf)) <= 0) fatal();
XX  }
XX  
XX! fatal()
XX  {
XX    perror("cat");
XX    exit(1);
XX--- 73,99 ----
XX  
XX  		bytes_left = &obuf[BLOCK_SIZE] - op;
XX  		if (n <= bytes_left) {
XX! 			memcpy(op, ibuf, (size_t)n);
XX  			op += n;
XX  		} else {
XX! 			memcpy(op, ibuf, (size_t)bytes_left);
XX  			if (write(ofd, obuf, BLOCK_SIZE) != BLOCK_SIZE)
XX  				fatal();
XX  			n -= bytes_left;
XX! 			memcpy(obuf, ibuf + bytes_left, (size_t)n);
XX  			op = obuf + n;
XX  		}
XX  	}
XX    }
XX  }
XX  
XX! void flush()
XX  {
XX    if (op != obuf)
XX  	if (write(STDOUT_FILENO, obuf, (size_t) (op - obuf)) <= 0) fatal();
XX  }
XX  
XX! void fatal()
XX  {
XX    perror("cat");
XX    exit(1);
X/
Xecho x - cdiff.c.d
Xsed '/^X/s///' > cdiff.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/cdiff.c  crc=55503   5669	Sun Apr 25 21:34:47 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/cdiff.c  crc=41225   7712	Sun Jan 17 20:52:39 1993
XX***************
XX*** 9,21 ****
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX  #include <ctype.h>
XX  #include <stdio.h>
XX  
XX  char buff[512];
XX  
XX  FILE *inputfp, *oldfp, *newfp;
XX- char *ctime();
XX  
XX  int oldmin, oldmax, newmin, newmax;
XX  int oldbeg, oldend, newbeg, newend;
XX--- 9,27 ----
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX+ #include <sys/wait.h>
XX  #include <ctype.h>
XX+ #include <fcntl.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <time.h>
XX+ #include <unistd.h>
XX+ #include <limits.h>
XX  #include <stdio.h>
XX  
XX  char buff[512];
XX  
XX  FILE *inputfp, *oldfp, *newfp;
XX  
XX  int oldmin, oldmax, newmin, newmax;
XX  int oldbeg, oldend, newbeg, newend;
XX***************
XX*** 24,60 ****
XX  int oldwanted, newwanted;
XX  
XX  char *oldhunk, *newhunk;
XX! unsigned oldsize, oldalloc, newsize, newalloc;
XX  
XX! void dumphunk();
XX! char *getold();
XX! char *getnew();
XX! char *malloc();
XX! char *realloc();
XX! char *fgets();
XX! FILE *popen();
XX  
XX  #define Nullfp (FILE*)0
XX  #define Nullch (char*)0
XX  
XX! main(argc, argv)
XX  int argc;
XX  char **argv;
XX  {
XX    char *old, *new;
XX    int context = 3;
XX    struct stat statbuf;
XX    register char *s;
XX    char op;
XX    char *newmark, *oldmark;
XX    int len;
XX    char *line;
XX    int i;
XX  
XX    oldalloc = 512;
XX!   oldhunk = malloc(oldalloc);
XX    newalloc = 512;
XX!   newhunk = malloc(newalloc);
XX  
XX    for (argc--, argv++; argc; argc--, argv++) {
XX  	if (argv[0][0] != '-') break;
XX--- 30,72 ----
XX  int oldwanted, newwanted;
XX  
XX  char *oldhunk, *newhunk;
XX! char *progname;
XX! size_t oldsize, oldalloc, newsize, newalloc;
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void dumphunk, (void));
XX! _PROTOTYPE(char *getold, (int targ));
XX! _PROTOTYPE(char *getnew, (int targ));
XX! _PROTOTYPE(void *xmalloc, (size_t size));
XX! _PROTOTYPE(void *xrealloc, (void *ptr, size_t size));
XX  
XX  #define Nullfp (FILE*)0
XX  #define Nullch (char*)0
XX+ #define ENOUGH (NAME_MAX + PATH_MAX + 1)
XX+ #define CRC_END 12
XX  
XX! int main(argc, argv)
XX  int argc;
XX  char **argv;
XX  {
XX+   FILE *crcfp;
XX    char *old, *new;
XX    int context = 3;
XX    struct stat statbuf;
XX    register char *s;
XX    char op;
XX    char *newmark, *oldmark;
XX+   char sysbuf1[ENOUGH], sysbuf2[ENOUGH];
XX    int len;
XX    char *line;
XX    int i;
XX+   int status;
XX  
XX+   progname = argv[0];
XX    oldalloc = 512;
XX!   oldhunk = (char *) xmalloc(oldalloc);
XX    newalloc = 512;
XX!   newhunk = (char *) xmalloc(newalloc);
XX  
XX    for (argc--, argv++; argc; argc--, argv++) {
XX  	if (argv[0][0] != '-') break;
XX***************
XX*** 64,94 ****
XX  
XX    if (argc != 2) {
XX  	fprintf(stderr, "Usage: cdiff old new\n");
XX! 	exit(1);
XX    }
XX    old = argv[0];
XX    new = argv[1];
XX  
XX-   sprintf(buff, "diff %s %s", old, new);
XX-   inputfp = popen(buff, "r");
XX-   if (!inputfp) {
XX- 	fprintf(stderr, "Can't execute diff %s %s\n", old, new);
XX- 	exit(1);
XX-   }
XX    oldfp = fopen(old, "r");
XX    if (!oldfp) {
XX  	fprintf(stderr, "Can't open %s\n", old);
XX! 	exit(1);
XX    }
XX    newfp = fopen(new, "r");
XX    if (!newfp) {
XX  	fprintf(stderr, "Can't open %s\n", new);
XX! 	exit(1);
XX    }
XX    fstat(fileno(oldfp), &statbuf);
XX!   printf("*** %s\t%s", old, ctime(&statbuf.st_mtime));
XX    fstat(fileno(newfp), &statbuf);
XX!   printf("--- %s\t%s", new, ctime(&statbuf.st_mtime));
XX  
XX    preoldend = -1000;
XX  
XX--- 76,142 ----
XX  
XX    if (argc != 2) {
XX  	fprintf(stderr, "Usage: cdiff old new\n");
XX! 	exit(2);
XX    }
XX    old = argv[0];
XX    new = argv[1];
XX  
XX    oldfp = fopen(old, "r");
XX    if (!oldfp) {
XX  	fprintf(stderr, "Can't open %s\n", old);
XX! 	exit(2);
XX    }
XX    newfp = fopen(new, "r");
XX    if (!newfp) {
XX  	fprintf(stderr, "Can't open %s\n", new);
XX! 	exit(2);
XX    }
XX+ 
XX+   /* Compute crcs by popen()ing crc and reading the output.  Do this before
XX+    * popen()ing diff to do the work.  popen() attempts to support multiple
XX+    * clients, but the 1.3-1.6.24b versions don't succeed.
XX+    */
XX+   sprintf(sysbuf1, "crc %s", old);
XX+   crcfp = popen(sysbuf1, "r");
XX+   if (!crcfp) {
XX+ 	/* The only advantage of cdiff over diff is that it prints crcs, so
XX+ 	 * give up easily if crc fails.
XX+ 	 */
XX+ 	fprintf(stderr, "Can't execute crc %s\n", old);
XX+ 	exit(2);
XX+   }
XX+   fgets(sysbuf1, sizeof(sysbuf1), crcfp);
XX+   sysbuf1[CRC_END] = '\0';
XX+   status = pclose(crcfp);
XX+   if (status != 0) {
XX+ 	fprintf(stderr, "crc %s returned bad status %d\n", old, status);
XX+ 	exit(2);
XX+   }
XX+   sprintf(sysbuf2, "crc %s", new);
XX+   crcfp = popen(sysbuf2, "r");
XX+   if (!crcfp) {
XX+ 	fprintf(stderr, "Can't execute crc %s\n", new);
XX+ 	exit(2);
XX+   }
XX+   fgets(sysbuf2, sizeof(sysbuf2), crcfp);
XX+   sysbuf2[CRC_END] = '\0';
XX+   status = pclose(crcfp);
XX+   if (status != 0) {
XX+ 	fprintf(stderr, "crc %s returned bad status %d\n", new, status);
XX+ 	exit(2);
XX+   }
XX+ 
XX+   sprintf(buff, "diff %s %s 2>/dev/null", old, new);
XX+   inputfp = popen(buff, "r");
XX+   if (!inputfp) {
XX+ 	fprintf(stderr, "Can't execute diff %s %s\n", old, new);
XX+ 	exit(2);
XX+   }
XX+ 
XX    fstat(fileno(oldfp), &statbuf);
XX!   printf("*** %s  crc=%s\t%s", old, sysbuf1, ctime(&statbuf.st_mtime));
XX    fstat(fileno(newfp), &statbuf);
XX!   printf("--- %s  crc=%s\t%s", new, sysbuf2, ctime(&statbuf.st_mtime));
XX  
XX    preoldend = -1000;
XX  
XX***************
XX*** 104,111 ****
XX  			oldmax = oldmin;
XX  		}
XX  		if (*s != 'a' && *s != 'd' && *s != 'c') {
XX! 			fprintf(stderr, "Unparseable input: %s", s);
XX! 			exit(1);
XX  		}
XX  		op = *s;
XX  		s++;
XX--- 152,159 ----
XX  			oldmax = oldmin;
XX  		}
XX  		if (*s != 'a' && *s != 'd' && *s != 'c') {
XX! 			fprintf(stderr, "Unparseable input: %s\n", s);
XX! 			exit(2);
XX  		}
XX  		op = *s;
XX  		s++;
XX***************
XX*** 119,126 ****
XX  			newmax = newmin;
XX  		}
XX  		if (*s != '\n' && *s != ' ') {
XX! 			fprintf(stderr, "Unparseable input: %s", s);
XX! 			exit(1);
XX  		}
XX  		newmark = oldmark = "! ";
XX  		if (op == 'a') {
XX--- 167,174 ----
XX  			newmax = newmin;
XX  		}
XX  		if (*s != '\n' && *s != ' ') {
XX! 			fprintf(stderr, "Unparseable input: %s\n", s);
XX! 			exit(2);
XX  		}
XX  		newmark = oldmark = "! ";
XX  		if (op == 'a') {
XX***************
XX*** 153,166 ****
XX  
XX  		for (i = oldbeg; i <= oldmax; i++) {
XX  			line = getold(i);
XX! 			if (!*line) {
XX  				oldend = oldmax = i - 1;
XX  				break;
XX  			}
XX  			len = strlen(line) + 2;
XX  			if (oldsize + len + 1 >= oldalloc) {
XX  				oldalloc *= 2;
XX! 				oldhunk = realloc(oldhunk, oldalloc);
XX  			}
XX  			if (i >= oldmin) {
XX  				strcpy(oldhunk + oldsize, oldmark);
XX--- 201,214 ----
XX  
XX  		for (i = oldbeg; i <= oldmax; i++) {
XX  			line = getold(i);
XX! 			if (!line) {
XX  				oldend = oldmax = i - 1;
XX  				break;
XX  			}
XX  			len = strlen(line) + 2;
XX  			if (oldsize + len + 1 >= oldalloc) {
XX  				oldalloc *= 2;
XX! 				oldhunk = (char *) xrealloc(oldhunk, oldalloc);
XX  			}
XX  			if (i >= oldmin) {
XX  				strcpy(oldhunk + oldsize, oldmark);
XX***************
XX*** 176,189 ****
XX  
XX  		for (i = newbeg; i <= newmax; i++) {
XX  			line = getnew(i);
XX! 			if (!*line) {
XX  				newend = newmax = i - 1;
XX  				break;
XX  			}
XX  			len = strlen(line) + 2;
XX  			if (newsize + len + 1 >= newalloc) {
XX  				newalloc *= 2;
XX! 				newhunk = realloc(newhunk, newalloc);
XX  			}
XX  			if (i >= newmin) {
XX  				strcpy(newhunk + newsize, newmark);
XX--- 224,237 ----
XX  
XX  		for (i = newbeg; i <= newmax; i++) {
XX  			line = getnew(i);
XX! 			if (!line) {
XX  				newend = newmax = i - 1;
XX  				break;
XX  			}
XX  			len = strlen(line) + 2;
XX  			if (newsize + len + 1 >= newalloc) {
XX  				newalloc *= 2;
XX! 				newhunk = (char *) xrealloc(newhunk, newalloc);
XX  			}
XX  			if (i >= newmin) {
XX  				strcpy(newhunk + newsize, newmark);
XX***************
XX*** 202,207 ****
XX--- 250,259 ----
XX    if (preoldend >= 0) {
XX  	dumphunk();
XX    }
XX+   status = pclose(inputfp);
XX+   if (!WIFEXITED(status)) exit(2);
XX+   status = WEXITSTATUS(status);
XX+   return(status == 0 || status == 1 ? status : 2);
XX  }
XX  
XX  void dumphunk()
XX***************
XX*** 219,225 ****
XX  	len = strlen(line) + 2;
XX  	if (oldsize + len + 1 >= oldalloc) {
XX  		oldalloc *= 2;
XX! 		oldhunk = realloc(oldhunk, oldalloc);
XX  	}
XX  	strcpy(oldhunk + oldsize, "  ");
XX  	strcpy(oldhunk + oldsize + 2, line);
XX--- 271,277 ----
XX  	len = strlen(line) + 2;
XX  	if (oldsize + len + 1 >= oldalloc) {
XX  		oldalloc *= 2;
XX! 		oldhunk = (char *) xrealloc(oldhunk, oldalloc);
XX  	}
XX  	strcpy(oldhunk + oldsize, "  ");
XX  	strcpy(oldhunk + oldsize + 2, line);
XX***************
XX*** 234,253 ****
XX  	len = strlen(line) + 2;
XX  	if (newsize + len + 1 >= newalloc) {
XX  		newalloc *= 2;
XX! 		newhunk = realloc(newhunk, newalloc);
XX  	}
XX  	strcpy(newhunk + newsize, "  ");
XX  	strcpy(newhunk + newsize + 2, line);
XX  	newsize += len;
XX    }
XX!   fputs("***************\n", stdout);
XX    if (preoldbeg >= preoldend) {
XX  	printf("*** %d ****\n", preoldend);
XX    } else {
XX  	printf("*** %d,%d ****\n", preoldbeg, preoldend);
XX    }
XX    if (oldwanted) {
XX! 	fputs(oldhunk, stdout);
XX    }
XX    oldsize = 0;
XX    *oldhunk = '\0';
XX--- 286,305 ----
XX  	len = strlen(line) + 2;
XX  	if (newsize + len + 1 >= newalloc) {
XX  		newalloc *= 2;
XX! 		newhunk = (char *) xrealloc(newhunk, newalloc);
XX  	}
XX  	strcpy(newhunk + newsize, "  ");
XX  	strcpy(newhunk + newsize + 2, line);
XX  	newsize += len;
XX    }
XX!   printf("***************\n");
XX    if (preoldbeg >= preoldend) {
XX  	printf("*** %d ****\n", preoldend);
XX    } else {
XX  	printf("*** %d,%d ****\n", preoldbeg, preoldend);
XX    }
XX    if (oldwanted) {
XX! 	printf("%s", oldhunk);
XX    }
XX    oldsize = 0;
XX    *oldhunk = '\0';
XX***************
XX*** 257,270 ****
XX  	printf("--- %d,%d ----\n", prenewbeg, prenewend);
XX    }
XX    if (newwanted) {
XX! 	fputs(newhunk, stdout);
XX    }
XX    newsize = 0;
XX    *newhunk = '\0';
XX  }
XX  
XX! char *
XX!  getold(targ)
XX  int targ;
XX  {
XX    static int oldline = 0;
XX--- 309,321 ----
XX  	printf("--- %d,%d ----\n", prenewbeg, prenewend);
XX    }
XX    if (newwanted) {
XX! 	printf("%s", newhunk);
XX    }
XX    newsize = 0;
XX    *newhunk = '\0';
XX  }
XX  
XX! char *getold(targ)
XX  int targ;
XX  {
XX    static int oldline = 0;
XX***************
XX*** 276,283 ****
XX    return Nullch;
XX  }
XX  
XX! char *
XX!  getnew(targ)
XX  int targ;
XX  {
XX    static int newline = 0;
XX--- 327,333 ----
XX    return Nullch;
XX  }
XX  
XX! char *getnew(targ)
XX  int targ;
XX  {
XX    static int newline = 0;
XX***************
XX*** 287,290 ****
XX--- 337,365 ----
XX  	if (newline == targ) return buff;
XX    }
XX    return Nullch;
XX+ }
XX+ 
XX+ void *xmalloc(size)
XX+ size_t size;
XX+ {
XX+   void *ptr;
XX+ 
XX+   ptr = malloc(size);
XX+   if (ptr == NULL) {
XX+ 	fprintf(stderr, "%s: out of memory\n", progname);
XX+ 	exit(2);
XX+   }
XX+   return(ptr);
XX+ }
XX+ 
XX+ void *xrealloc(ptr, size)
XX+ void *ptr;
XX+ size_t size;
XX+ {
XX+   ptr = realloc(ptr, size);
XX+   if (ptr == NULL) {
XX+ 	fprintf(stderr, "%s: out of memory\n", progname);
XX+ 	exit(2);
XX+   }
XX+   return(ptr);
XX  }
X/
Xecho x - cgrep.c.d
Xsed '/^X/s///' > cgrep.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/cgrep.c  crc=27074   9044	Sun Apr 25 21:34:48 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/cgrep.c  crc=50864   9281	Wed Nov  4 04:19:05 1992
XX***************
XX*** 71,76 ****
XX--- 71,81 ----
XX  
XX  /* Internal routines */
XX  
XX+ _PROTOTYPE(int main, (int argc, char **argv));
XX+ _PROTOTYPE(void dosrch, (char *ifnm));
XX+ _PROTOTYPE(void shwlin, (char *fnm, int linnum, char *line));
XX+ _PROTOTYPE(int matlin, (char *line));
XX+ _PROTOTYPE(void regerror, (char *s));
XX  
XX  /* External data */
XX  
XX***************
XX*** 79,85 ****
XX  
XX  static int Debug = {FALSE};	/* Debug enabled flag */
XX  static int Lcur = {0};		/* Current line (in Lines array) */
XX! static char **Lines = {(char **) NULL};	/* Lines pointer array */
XX  static int Linlen = {100};	/* Line length */
XX  static int Lone = {0};		/* Line one (in Lines array) */
XX  static int Nmr = {0};		/* Number of matched regions */
XX--- 84,90 ----
XX  
XX  static int Debug = {FALSE};	/* Debug enabled flag */
XX  static int Lcur = {0};		/* Current line (in Lines array) */
XX! static char **Lines = {NULL};	/* Lines pointer array */
XX  static int Linlen = {100};	/* Line length */
XX  static int Lone = {0};		/* Line one (in Lines array) */
XX  static int Nmr = {0};		/* Number of matched regions */
XX***************
XX*** 92,98 ****
XX  
XX  regexp *Re;			/* Result from reg compilation */
XX  
XX! main(argc, argv)
XX  int argc;			/* Argument count */
XX  char **argv;			/* Argument values */
XX  
XX--- 97,103 ----
XX  
XX  regexp *Re;			/* Result from reg compilation */
XX  
XX! int main(argc, argv)
XX  int argc;			/* Argument count */
XX  char **argv;			/* Argument values */
XX  
XX***************
XX*** 149,155 ****
XX  
XX  		    case 'b':	/* Lines before */
XX  			Wbef = atoi(aptr);
XX! 			Lines = (char **) NULL;
XX  			i = n;
XX  			break;
XX  
XX--- 154,160 ----
XX  
XX  		    case 'b':	/* Lines before */
XX  			Wbef = atoi(aptr);
XX! 			Lines = NULL;
XX  			i = n;
XX  			break;
XX  
XX***************
XX*** 191,196 ****
XX--- 196,202 ----
XX    }
XX    if (nf == 0)			/* No files processed ? */
XX  	dosrch((char *)NULL);		/* Do standard input */
XX+   return(0);
XX  }
XX  
XX   /* Dosrch (ifnm) Perform the search 
XX***************
XX*** 204,210 ****
XX    * 
XX    */
XX  
XX! dosrch(ifnm)
XX  char *ifnm;			/* Input filelname */
XX  
XX  {
XX--- 210,216 ----
XX    * 
XX    */
XX  
XX! void dosrch(ifnm)
XX  char *ifnm;			/* Input filelname */
XX  
XX  {
XX***************
XX*** 226,235 ****
XX  
XX    if (Lines == NULL) {		/* If no line table allocated.. */
XX  	Wsiz = Wbef + 2;	/* Determine total window size */
XX! 	Lines = (char **) calloc(Wsiz, sizeof(char *));
XX  	/* Allocate pointer table */
XX  	for (i = 0; i < Wsiz; i++)	/* Allocate line buffers */
XX! 		Lines[i] = (char *) calloc(Linlen, sizeof(char));
XX    }
XX    Lcur = Lone = 0;		/* Setup line pointers */
XX    nlb = 0;			/* No lines buffered */
XX--- 232,241 ----
XX  
XX    if (Lines == NULL) {		/* If no line table allocated.. */
XX  	Wsiz = Wbef + 2;	/* Determine total window size */
XX! 	Lines = (char **) calloc((size_t)Wsiz, sizeof(char *));
XX  	/* Allocate pointer table */
XX  	for (i = 0; i < Wsiz; i++)	/* Allocate line buffers */
XX! 		Lines[i] = (char *) calloc((size_t)Linlen, sizeof(char));
XX    }
XX    Lcur = Lone = 0;		/* Setup line pointers */
XX    nlb = 0;			/* No lines buffered */
XX***************
XX*** 288,301 ****
XX    * 
XX    */
XX  
XX! shwlin(fnm, linnum, line)
XX  char *fnm;			/* File name */
XX  int linnum;			/* Line number */
XX  char *line;			/* Line (with newline at end) to print */
XX  
XX  {
XX    if (Shwfile && (fnm != NULL)) printf("%s%s", fnm, Shwline ? " " : ":");
XX!   if (Shwline) printf("@%05d%:", linnum);
XX    printf("%s", line);
XX  }
XX  
XX--- 294,307 ----
XX    * 
XX    */
XX  
XX! void shwlin(fnm, linnum, line)
XX  char *fnm;			/* File name */
XX  int linnum;			/* Line number */
XX  char *line;			/* Line (with newline at end) to print */
XX  
XX  {
XX    if (Shwfile && (fnm != NULL)) printf("%s%s", fnm, Shwline ? " " : ":");
XX!   if (Shwline) printf("@%05d:", linnum);
XX    printf("%s", line);
XX  }
XX  
XX***************
XX*** 333,339 ****
XX  #endif	/* REGEX */
XX  
XX  #ifdef	REGCMP
XX!   rtncode = (regexec(Re, line, TRUE) != (int) NULL);
XX  #endif /* REGCMP */
XX  
XX  #ifdef	NOREGEX			/* Have to do menial comparison.. */
XX--- 339,345 ----
XX  #endif	/* REGEX */
XX  
XX  #ifdef	REGCMP
XX!   rtncode = (regexec(Re, line, TRUE) != 0);
XX  #endif /* REGCMP */
XX  
XX  #ifdef	NOREGEX			/* Have to do menial comparison.. */
X/
Xecho x - chmem.c.d
Xsed '/^X/s///' > chmem.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/chmem.c  crc=28568   3571	Sun Apr 25 21:34:48 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/chmem.c  crc=11962   3289	Sun Jan 10 14:26:16 1993
XX***************
XX*** 1,27 ****
XX  /* chmem - set total memory size for execution	Author: Andy Tanenbaum */
XX  
XX  #include <sys/types.h>
XX  #include <fcntl.h>
XX  #include <stdlib.h>
XX  #include <unistd.h>
XX  
XX! /* Should include a.out.h or exec.h.  Here is an approximation. */
XX! #define HLONG            8	/* header size in longs */
XX! #define TEXT             2	/* where is text size in header */
XX! #define DATA             3	/* where is data size in header */
XX! #define BSS              4	/* where is bss size in header */
XX! #define TOT              6	/* where in header is total allocation */
XX! #define TOTPOS          24	/* where is total in header */
XX! #define SEPBIT  0x00200000	/* this bit is set for separate I/D */
XX! #define MAGIC       0x0301	/* magic number for executable progs */
XX! #define MAX_8086   0x10000L	/* maximum allocation size for 8086 */
XX! #define MAX_386 0x7FFFFFFFL	/* etc */
XX! #define MAX_68K 0x7FFFFFFFL
XX! #define CPU_8086         4	/* CPU code for 8086 executables */
XX! #define CPU_386       0x10	/* etc */
XX! #define CPU_68K       0x0B	/* from Minix-PC a.out.h - unreliable */
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX--- 1,26 ----
XX  /* chmem - set total memory size for execution	Author: Andy Tanenbaum */
XX  
XX+ #include <minix/config.h>
XX  #include <sys/types.h>
XX+ #include <a.out.h>
XX+ #include <errno.h>
XX  #include <fcntl.h>
XX  #include <stdlib.h>
XX  #include <unistd.h>
XX+ #include <stdio.h>
XX  
XX! #define MAX_8086     0x10000L	/* maximum allocation size for 8086 */
XX! #define MAX_386	  0x7FFFFFFFL	/* etc */
XX! #define MAX_68K   0x7FFFFFFFL
XX! #define MAX_SPARC 0x20000000L	/* No more than 512MB on a SparcStation! */
XX  
XX! char *progname;
XX! 
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void error, (char *s1, char *s2));
XX! _PROTOTYPE(void usage, (void));
XX! 
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX***************
XX*** 38,108 ****
XX  
XX    char *p;
XX    int fd, separate;
XX!   long lsize, olddynam, newdynam, newtot, overflow, header[HLONG];
XX    char cpu;
XX    long max;
XX  
XX!   if (argc != 3) usage();
XX    p = argv[1];
XX    if (*p != '=' && *p != '+' && *p != '-') usage();
XX    lsize = atol(p + 1);
XX  
XX!   fd = open(argv[2], O_RDWR);
XX!   if (fd < 0) stderr3("chmem: can't open ", argv[2], "\n");
XX  
XX!   if (read(fd, (char *) header, sizeof(header)) != sizeof(header))
XX! 	stderr3("chmem: ", argv[2], "bad header\n");
XX!   if ((header[0] & 0xFFFFL) != MAGIC)
XX! 	stderr3("chmem: ", argv[2], " not executable\n");
XX!   separate = (header[0] & SEPBIT ? 1 : 0);
XX  
XX!   cpu = (char) (header[0] >> 24);	/* cpu byte is most significant */
XX!   if (cpu == CPU_8086 && *(unsigned short *) &header[0] != MAGIC)
XX! 	cpu = CPU_68K;		/* 8086 code with 68K byte order == 68K */
XX!   switch(cpu) {
XX! 	case CPU_8086:	max = MAX_8086;	break;
XX! 	case CPU_386:	max = MAX_386;	break;
XX! 	case CPU_68K:	max = MAX_68K;	break;
XX! 	default:	stderr3("chmem: ", argv[2], "bad CPU type\n");
XX!   }  
XX  
XX!   if (lsize < 0) stderr3("chmem: ", p+1, " negative size not allowed\n");
XX!   if (lsize > max) stderr3("chmem: ", p + 1, " too large\n");
XX  
XX!   olddynam = header[TOT] - header[DATA] - header[BSS];
XX!   if (separate == 0) olddynam -= header[TEXT];
XX  
XX!   if (*p == '=')
XX! 	newdynam = lsize;
XX!   else if (*p == '+')
XX! 	newdynam = olddynam + lsize;
XX!   else if (*p == '-')
XX! 	newdynam = olddynam - lsize;
XX  
XX!   newtot = header[DATA] + header[BSS] + newdynam;
XX!   if (separate == 0) newtot += header[TEXT];
XX!   overflow = (newtot > max ? newtot - max : 0);
XX!   newdynam -= overflow;
XX!   newtot -= overflow;
XX!   lseek(fd, (long) TOTPOS, SEEK_SET);
XX!   if (write(fd, (char *) &newtot, 4) < 0)
XX! 	stderr3("chmem: can't modify ", argv[2], "\n");
XX!   printf("%s: Stack+malloc area changed from %ld to %ld bytes.\n",
XX!          argv[2], olddynam, newdynam);
XX!   exit(0);
XX  }
XX  
XX! usage()
XX  {
XX!   std_err("chmem {=+-} amount file\n");
XX!   exit(1);
XX  }
XX  
XX! stderr3(s1, s2, s3)
XX! char *s1, *s2, *s3;
XX  {
XX!   std_err(s1);
XX!   std_err(s2);
XX!   std_err(s3);
XX    exit(1);
XX  }
XX--- 37,140 ----
XX  
XX    char *p;
XX    int fd, separate;
XX!   size_t s;
XX!   long lsize, olddynam, newdynam, newtot, overflow;
XX!   struct exec exec;
XX    char cpu;
XX    long max;
XX  
XX!   progname = argv[0];
XX!   if (argc < 3) usage();
XX    p = argv[1];
XX    if (*p != '=' && *p != '+' && *p != '-') usage();
XX    lsize = atol(p + 1);
XX+   s = sizeof(struct exec);
XX  
XX!   if (lsize < 0) {
XX! 	error(p + 1, "is negative");
XX! 	exit(1);
XX!   }
XX!   argc -= 1;
XX!   argv += 1;
XX  
XX!   while (--argc) {
XX! 	++argv;
XX! 	fd = open(*argv, O_RDWR);
XX! 	if (fd < 0) {
XX! 		error("can't open", *argv);
XX! 		continue;
XX! 	}
XX! 	if (read(fd, (char *) &exec, s) != s) {
XX! 		error("can't read header in", *argv);
XX! 		continue;
XX! 	}
XX! 	if (BADMAG(exec)) {
XX! 		error(*argv, "is not executable");
XX! 		continue;
XX! 	}
XX! 	separate = (exec.a_flags & A_SEP ? 1 : 0);
XX! 	cpu = exec.a_cpu;
XX  
XX! #if (CHIP == M68000)
XX! 	if (cpu == A_I8086) cpu = A_M68K;
XX! #endif
XX  
XX! 	switch (cpu) {
XX! 	    case A_I8086:	max = MAX_8086;	break;
XX! 	    case A_I80386:	max = MAX_386;	break;
XX! 	    case A_M68K:	max = MAX_68K;	break;
XX! 	    case A_SPARC:	max = MAX_SPARC;	break;
XX! 	    default:
XX! 		error("bad CPU type in", *argv);
XX! 		continue;
XX! 	}
XX  
XX! 	if (lsize > max) {
XX! 		error("size is too large for", *argv);
XX! 		continue;
XX! 	}
XX! 	olddynam = exec.a_total - exec.a_data - exec.a_bss;
XX! 	if (separate == 0) olddynam -= exec.a_text;
XX  
XX! 	if (*p == '=')
XX! 		newdynam = lsize;
XX! 	else if (*p == '+')
XX! 		newdynam = olddynam + lsize;
XX! 	else if (*p == '-')
XX! 		newdynam = olddynam - lsize;
XX  
XX! 	newtot = exec.a_data + exec.a_bss + newdynam;
XX! 	if (separate == 0) newtot += exec.a_text;
XX! 	overflow = (newtot > max ? newtot - max : 0);
XX! 	newdynam -= overflow;
XX! 	newtot -= overflow;
XX! 	exec.a_total = newtot;
XX! 	lseek(fd, (long) 0, SEEK_SET);
XX! 	if (write(fd, (char *) &exec, s) != s) {
XX! 		error("can't modify", *argv);
XX! 		continue;
XX! 	}
XX! 	printf("%s: Stack+malloc area changed from %ld to %ld bytes.\n",
XX! 	       *argv, olddynam, newdynam);
XX! 	close(fd);
XX!   }
XX!   return(0);
XX  }
XX  
XX! void error(s1, s2)
XX! char *s1;
XX! char *s2;
XX  {
XX!   fprintf(stderr, "%s: %s ", progname, s1);
XX!   if (errno != 0)
XX! 	perror(s2);
XX!   else
XX! 	fprintf(stderr, "%s\n", s2);
XX!   errno = 0;
XX  }
XX  
XX! void usage()
XX  {
XX!   fprintf(stderr, "Usage: %s {=+-} amount file\n", progname);
XX    exit(1);
XX  }
X/
Xecho x - chmod.c.d
Xsed '/^X/s///' > chmod.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/chmod.c  crc=16117   5948	Sun Apr 25 21:34:48 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/chmod.c  crc=15392   5004	Wed Nov  4 04:19:06 1992
XX***************
XX*** 1,275 ****
XX! /* chmod - change mode		Author: James da Silva */
XX  
XX! 
XX! /* Author James da Silva (ihnp4!killer!jaime)
XX!  *
XX!  *  a (hopefully) 7th Edition Unix compatible chmod for Minix.
XX   */
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX  
XX! #define isop(c)         ((c=='+')||(c=='-')||(c=='='))
XX! #define isperm(c)       ((c=='r')||(c=='w')||(c=='x')||(c=='s')||(c=='t')||\
XX!                          (c=='u')||(c=='g')||(c=='o'))
XX  
XX- /* The bits associated with user, group, other */
XX- #define U_MSK   (0700 | S_ISUID)
XX- #define G_MSK   (0070 | S_ISGID)
XX- #define O_MSK    0007
XX  
XX! typedef unsigned short bitset;	/* type used for modes */
XX  
XX! struct stat st;			/* structure returned by stat() */
XX! char *pname, *arg;
XX! bitset newmode, absolute(), symbolic();
XX! int isabsolute;
XX  
XX! main(argc, argv)
XX! int argc;
XX! char **argv;
XX  {
XX!   int i;
XX  
XX!   pname = *(argv++);
XX!   if (argc < 3) usage();
XX!   arg = *argv;			/* save pointer to mode arg */
XX! 
XX!   /* Check for octal mode */
XX!   if (isabsolute = ((*arg >= '0') && (*arg <= '7'))) newmode = absolute();
XX! 
XX!   /* Apply the mode to all files listed */
XX!   for (i = 2; i < argc; i++) {
XX! 	argv++;
XX! 	if (stat(*argv, &st)) {	/* get current file mode */
XX! 		printf("%s: cannot find `%s'\n", pname, *argv);
XX! 		exit(1);
XX  	}
XX! 
XX! 	/* Calculate new mode for this file */
XX! 	if (!isabsolute) newmode = symbolic(st.st_mode);
XX! 
XX! 	if (chmod(*argv, newmode)) {	/* change the mode */
XX! 		printf("%s: cannot chmod `%s'\n", pname, *argv);
XX! 		exit(1);
XX  	}
XX    }
XX!   exit(0);
XX  }
XX  
XX  
XX! /* Absolute interprets an octal mode.
XX!  * The file modes will be set to this value.
XX   */
XX! bitset absolute()
XX  {
XX!   bitset m;
XX!   char *s;
XX  
XX!   m = 0;
XX!   s = arg;
XX  
XX!   /* Convert octal string to integer */
XX!   while ((*s >= '0') && (*s <= '7')) m = m * 8 + (*(s++) - '0');
XX  
XX!   /* If something else is there, choke */
XX!   if (*s) badmode(s);
XX  
XX!   return m;
XX  }
XX  
XX  
XX! /* Symbolic
XX!  *
XX!  * Processes symbolic mode of the form (in EBNF):
XX!  *      <symbolic> ::= <pgroup> { ',' <pgroup> }.
XX!  *      <pgroup> ::= [ <who> ] <op> <permissions> { <op> <permissions> }.
XX!  *
XX!  *      <who> ::= <whoch> { <whoch> }.
XX!  *      <whoch> ::= 'a' | 'u' | 'g' | 'o'.
XX!  *
XX!  *      <op> ::= '+' | '-' | '='.
XX!  *
XX!  *      <permissions> ::= <permch> { <permch> }.
XX!  *      <permch> ::= 'r' | 'w' | 'x' | 's' | 't' | 'u' | 'g' | 'o'.
XX!  *
XX!  * If <who> is omitted, 'a' is assumed, BUT umask()ed bits are uneffected.
XX!  * If <op> is '=', all unspecified permissions are turned off for this <who>.
XX!  * For permissions 'u', 'g', and 'o', the permissions are taken from the
XX!  * specified set.  i.e.  o=g sets the permissions for other the same as for
XX!  * group.
XX!  *
XX!  * Pain in the duff, isn't it?
XX   */
XX! bitset symbolic(mode)
XX! bitset mode;
XX  {
XX!   int g, o, u, haswho, haspcopy;
XX!   bitset u_mask, emask, partial, other, applyop();
XX!   char *s, c, op;
XX  
XX!   s = arg;
XX!   u_mask = umask(0);		/* get the umasked bits */
XX  
XX!   do {				/* pgroup */
XX! 	haswho = u = g = o = 0;
XX! 
XX! 	while (!isop(*s)) {
XX! 		/* We must have a 'who' then */
XX! 		haswho = 1;
XX! 		switch (*s) {
XX! 		    case 'a':	u = g = o = 1;	break;
XX! 		    case 'u':	u = 1;	break;
XX! 		    case 'g':	g = 1;	break;
XX! 		    case 'o':	o = 1;	break;
XX! 
XX! 		    default:	badmode(s);
XX! 		}
XX! 		s++;
XX  	}
XX! 
XX! 	if (!haswho) {
XX! 		u = g = o = 1;	/* assume all */
XX! 		emask = ~u_mask;/* effective umask */
XX! 	} else
XX! 		emask = ~0;
XX! 
XX! 
XX! 	/* Process each given operator */
XX! 	while (isop(*s)) {
XX! 		op = *(s++);
XX! 		other = partial = haspcopy = 0;
XX! 
XX! 		/* Collect the specified permissions */
XX! 
XX! 		while (isperm(*s)) {
XX! 
XX! 			/* Berkeley only allows one of 'u' 'g' or 'o'
XX! 			 * as permissions */
XX! 
XX! 			if ((*s == 'u') || (*s == 'g') || (*s == 'o'))
XX! 				if (haspcopy)
XX! 					badmode(s);
XX! 				else
XX! 					haspcopy = 1;
XX! 
XX! 			switch (*s) {
XX! 			    case 'r':
XX! 				partial |= 4;
XX! 				break;
XX! 			    case 'w':
XX! 				partial |= 2;
XX! 				break;
XX! 			    case 'x':
XX! 				partial |= 1;
XX! 				break;
XX! 
XX! 			    case 'u':
XX! 				partial |= (mode & U_MSK & ~S_ISUID) >> 6;
XX! 				other |= mode & S_ISUID;
XX! 				break;
XX! 			    case 'g':
XX! 				partial |= (mode & G_MSK & ~S_ISGID) >> 3;
XX! 				other |= mode & S_ISGID;
XX! 				break;
XX! 			    case 'o':
XX! 				partial |= (mode & O_MSK);
XX! 				break;
XX! 
XX! #ifdef S_ISVTX
XX! 			    case 't':
XX! 				other |= S_ISVTX;
XX! 				break;
XX! #endif
XX! 
XX! 			    case 's':
XX! 				if (u) other |= S_ISUID;
XX! 				if (g) other |= S_ISGID;
XX! 				break;
XX! 
XX! 			    default:	badmode(s);
XX! 			}
XX! 			s++;
XX  		}
XX! 
XX! 		/* Apply the op using the affected bits and masks */
XX! 		if (u)
XX! 			mode = applyop(mode, op, (other | (partial << 6)), emask, U_MSK);
XX! 		if (g)
XX! 			mode = applyop(mode, op, (other | (partial << 3)), emask, G_MSK);
XX! 		if (o)
XX! 			mode = applyop(mode, op, (other | partial), emask, O_MSK);
XX! 	}
XX! 
XX!   } while (*(s++) == ',');
XX! 
XX!   /* Not at end - choke */
XX! 
XX!   if (*(--s)) badmode(s);
XX! 
XX!   return mode;
XX! }
XX! 
XX! 
XX! /* Applyop
XX!  *
XX!  * applies the operator to the current mode using the specified bitset
XX!  * and mask.  'bits' will contain 1's in every bit affected by the
XX!  * operator '+', '-', or '='.  In the case of '=', msk is used to
XX!  * determine which bits will be forced off. 'emask' is the effective
XX!  * umask.
XX!  */
XX! bitset applyop(mode, op, bits, emask, msk)
XX! char op;
XX! bitset mode, bits, emask, msk;
XX! {
XX!   switch (op) {
XX!       case '+':
XX! 	mode |= bits & emask;	/* turn these bits on */
XX! 	break;
XX!       case '-':
XX! 	mode &= ~(bits & emask);/* turn these off */
XX! 	break;
XX!       case '=':
XX! 	mode |= bits & emask;	/* turn these bits on */
XX! 	mode &= ~(~bits & msk & emask);	/* others off */
XX! 	break;
XX!       default:			/* should never get here (famous last words) */
XX! 	printf("%s: panic: bad op `%c' passed\n", pname, op);
XX    }
XX!   return mode;
XX  }
XX  
XX  
XX! /* Usage
XX!  *
XX!  * Prints a terse usage message and exits.
XX!  */
XX! usage()
XX  {
XX!   printf("Usage: %s [absolute-mode | symbolic-mode] files\n", pname);
XX!   exit(1);
XX! }
XX! 
XX! 
XX! /* Badmode
XX!  *
XX!  * Called when the parser chokes on the given mode.
XX!  * Prints a message showing the offending character and exits.
XX!  */
XX! badmode(s)
XX! char *s;
XX! {
XX!   int i, sp;
XX!   char buffer[80], *bp;
XX! 
XX!   sp = s - arg + strlen(pname) + 21;
XX!   sp = sp > 79 ? 79 : sp;	/* check for buffer overflow */
XX! 
XX!   for (i = 0, bp = buffer; i < sp; i++, bp++) *bp = ' ';
XX!   *bp = '\0';
XX! 
XX!   printf("%s: badly formed mode `%s'\n", pname, arg);
XX!   printf("%s^\n", buffer);
XX    exit(1);
XX  }
XX--- 1,253 ----
XX! /* chmod - Change file modes				Author: V. Archer */
XX  
XX! /* Copyright 1991 by Vincent Archer
XX!  *	You may freely redistribute this software, in source or binary
XX!  *	form, provided that you do not alter this copyright mention in any
XX!  *	way.
XX   */
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX+ #include <dirent.h>
XX+ #include <errno.h>
XX+ #include <limits.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <unistd.h>
XX+ #include <minix/minlib.h>
XX+ #include <stdio.h>
XX  
XX! #define USR_MODES (S_ISUID|S_IRWXU)
XX! #define GRP_MODES (S_ISGID|S_IRWXG)
XX! #define EXE_MODES (S_IXUSR|S_IXGRP|S_IXOTH)
XX! #ifdef S_ISVTX
XX! #define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO|S_ISVTX)
XX! #else
XX! #define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO)
XX! #endif
XX  
XX  
XX! /* Common variables */
XX! char *symbolic;
XX! mode_t new_mode, u_mask;
XX! int rflag, errors;
XX! struct stat st;
XX! uid_t userid;
XX! char path[PATH_MAX + 1];
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(mode_t parsemode, (char *symbolic, Mode_t oldmode));
XX! _PROTOTYPE(int do_change, (char *name));
XX! _PROTOTYPE(void usage, (void));
XX  
XX! /* Parse a P1003.2 4.7.7-conformant symbolic mode. */
XX! mode_t parsemode(symbolic, oldmode)
XX! char *symbolic;
XX! mode_t oldmode;
XX  {
XX!   mode_t who, mask, newmode, tmpmask;
XX!   char action;
XX  
XX!   newmode = oldmode & ALL_MODES;
XX!   while (*symbolic) {
XX! 	who = 0;
XX! 	for (; *symbolic; symbolic++) {
XX! 		if (*symbolic == 'a') {
XX! 			who |= ALL_MODES;
XX! 			continue;
XX! 		}
XX! 		if (*symbolic == 'u') {
XX! 			who |= USR_MODES;
XX! 			continue;
XX! 		}
XX! 		if (*symbolic == 'g') {
XX! 			who |= GRP_MODES;
XX! 			continue;
XX! 		}
XX! 		if (*symbolic == 'o') {
XX! 			who |= S_IRWXO;
XX! 			continue;
XX! 		}
XX! 		break;
XX  	}
XX! 	if (!*symbolic || *symbolic == ',') usage();
XX! 	while (*symbolic) {
XX! 		if (*symbolic == ',') break;
XX! 		switch (*symbolic) {
XX! 		    default:
XX! 			usage();
XX! 		    case '+':
XX! 		    case '-':
XX! 		    case '=':	action = *symbolic++;
XX! 		}
XX! 		mask = 0;
XX! 		for (; *symbolic; symbolic++) {
XX! 			if (*symbolic == 'u') {
XX! 				tmpmask = newmode & S_IRWXU;
XX! 				mask |= tmpmask | (tmpmask << 3) | (tmpmask << 6);
XX! 				symbolic++;
XX! 				break;
XX! 			}
XX! 			if (*symbolic == 'g') {
XX! 				tmpmask = newmode & S_IRWXG;
XX! 				mask |= tmpmask | (tmpmask >> 3) | (tmpmask << 3);
XX! 				symbolic++;
XX! 				break;
XX! 			}
XX! 			if (*symbolic == 'o') {
XX! 				tmpmask = newmode & S_IRWXO;
XX! 				mask |= tmpmask | (tmpmask >> 3) | (tmpmask >> 6);
XX! 				symbolic++;
XX! 				break;
XX! 			}
XX! 			if (*symbolic == 'r') {
XX! 				mask |= S_IRUSR | S_IRGRP | S_IROTH;
XX! 				continue;
XX! 			}
XX! 			if (*symbolic == 'w') {
XX! 				mask |= S_IWUSR | S_IWGRP | S_IWOTH;
XX! 				continue;
XX! 			}
XX! 			if (*symbolic == 'x') {
XX! 				mask |= EXE_MODES;
XX! 				continue;
XX! 			}
XX! 			if (*symbolic == 's') {
XX! 				mask |= S_ISUID | S_ISGID;
XX! 				continue;
XX! 			}
XX! 			if (*symbolic == 'X') {
XX! 				if (S_ISDIR(oldmode) || (oldmode & EXE_MODES))
XX! 					mask |= EXE_MODES;
XX! 				continue;
XX! 			}
XX! #ifdef S_ISVTX
XX! 			if (*symbolic == 't') {
XX! 				mask |= S_ISVTX;
XX! 				who |= S_ISVTX;
XX! 				continue;
XX! 			}
XX! #endif
XX! 			break;
XX! 		}
XX! 		switch (action) {
XX! 		    case '=':
XX! 			if (who)
XX! 				newmode &= ~who;
XX! 			else
XX! 				newmode = 0;
XX! 		    case '+':
XX! 			if (who)
XX! 				newmode |= who & mask;
XX! 			else
XX! 				newmode |= mask & (~u_mask);
XX! 			break;
XX! 		    case '-':
XX! 			if (who)
XX! 				newmode &= ~(who & mask);
XX! 			else
XX! 				newmode &= ~mask | u_mask;
XX! 		}
XX  	}
XX+ 	if (*symbolic) symbolic++;
XX    }
XX!   return(newmode);
XX  }
XX  
XX  
XX! /* Main module. The single option possible (-R) does not warrant a call to
XX!  * the getopt() stuff.
XX   */
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   argc--;
XX!   argv++;
XX  
XX!   if (argc && strcmp(*argv, "-R") == 0) {
XX! 	argc--;
XX! 	argv++;
XX! 	rflag = 1;
XX!   } else
XX! 	rflag = 0;
XX  
XX!   if (!argc--) usage();
XX!   if (!strcmp(argv[0], "--")) {	/* Allow chmod -- -r, as in Draft11 example */
XX! 	if (!argc--) usage();
XX! 	argv++;
XX!   }
XX!   symbolic = *argv++;
XX!   if (!argc) usage();
XX  
XX!   if (*symbolic >= '0' && *symbolic <= '7') {
XX! 	new_mode = 0;
XX! 	while (*symbolic >= '0' && *symbolic <= '7')
XX! 		new_mode = (new_mode << 3) | (*symbolic++ & 07);
XX! 	if (*symbolic) usage();
XX! 	new_mode &= ALL_MODES;
XX! 	symbolic = (char *) 0;
XX!   } else
XX! 	u_mask = umask(0);
XX  
XX!   userid = getuid();
XX! 
XX!   while (argc--)
XX! 	if (do_change(*argv++)) exit(1);
XX!   return(0);
XX  }
XX  
XX  
XX! /* Apply a mode change to a given file system element. chmod(1) may be
XX!  * setuid root, in which case it will enforce the protection itself.
XX   */
XX! int do_change(name)
XX! char *name;
XX  {
XX!   mode_t m;
XX!   DIR *dirp;
XX!   struct dirent *entp;
XX!   char *namp;
XX  
XX!   if (stat(name, &st)) {
XX! 	perror(name);
XX! 	return(1);
XX!   }
XX!   if (!symbolic)
XX! 	m = new_mode;
XX!   else
XX! 	m = parsemode(symbolic, st.st_mode);
XX!   if (chmod(name, m)) {
XX! 	perror(name);
XX! 	errors = 1;
XX!   } else
XX! 	errors = 0;
XX  
XX!   if (S_ISDIR(st.st_mode) && rflag) {
XX! 	if (!(dirp = opendir(name))) {
XX! 		perror(name);
XX! 		return(1);
XX  	}
XX! 	if (name != path) strcpy(path, name);
XX! 	namp = path + strlen(path);
XX! 	*namp++ = '/';
XX! 	while (entp = readdir(dirp))
XX! 		if (entp->d_name[0] != '.' ||
XX! 		    (entp->d_name[1] &&
XX! 		     (entp->d_name[1] != '.' || entp->d_name[2]))) {
XX! 			strcpy(namp, entp->d_name);
XX! 			errors |= do_change(path);
XX  		}
XX! 	closedir(dirp);
XX! 	*--namp = '\0';
XX    }
XX!   return(errors);
XX  }
XX  
XX  
XX! /* Display Posix prototype */
XX! void usage()
XX  {
XX!   std_err("Usage: chmod [-R] mode file...\n");
XX    exit(1);
XX  }
X/
Xecho x - chown.c.d
Xsed '/^X/s///' > chown.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/chown.c  crc=18709   2793	Sun Apr 25 21:34:49 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/chown.c  crc=00602   3652	Wed Nov  4 04:19:06 1992
XX***************
XX*** 1,105 ****
XX! /*
XX!  * chown-	Change the owner and/or group ID of a file.
XX!  *
XX!  * Author:	Bert Reuling (bert@kyber.UUCP) 
XX!  *
XX!  * Revision History:
XX!  *	1.1  89/09/25 bert@kyber.UUCP 		Initial revision
XX!  *	     89/10/04 waltje@kyber.UUCP		Adapted to MINIX Style Sheet
XX   */
XX  #include <sys/types.h>
XX  #include <ctype.h>
XX! #include <grp.h>
XX  #include <pwd.h>
XX  #include <string.h>
XX! #include <sys/stat.h>
XX  #include <stdio.h>
XX  
XX! #ifndef TRUE
XX! #	define TRUE  1
XX! #	define FALSE 0
XX! #endif
XX  
XX! static char rcsid[] = "$Header: chown.c,v 1.1 89/10/04 20:45:00 bert Exp $";
XX  
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX!   int i, uid, gid, Chown, status = 0;
XX!   char *pgmname, *uids, *gids;
XX!   struct passwd *pwd;
XX    struct group *grp;
XX    struct stat st;
XX  
XX!   if ((pgmname = strrchr(argv[0], '/')) != NULL) pgmname++;
XX!     else pgmname = argv[0];
XX!   if (strcmp(pgmname, "chown") == 0) Chown = TRUE;
XX!     else if (strcmp(pgmname, "chgrp") == 0) Chown = FALSE;
XX!            else {
XX!       		 (void) fprintf(stderr, "%s: should be named \"chown\" or \"chgrp\"\n", argv[0]);
XX! 	         (void) exit(-1);
XX!    	   }
XX!   if (argc < 3) {
XX! 	(void) fprintf(stderr,"Usage: %s %s file ...\n", pgmname, (Chown) ? "owner" : "group");
XX!       	(void) exit(1);
XX    }
XX!   if ((gids = strchr(argv[1], '.')) != NULL) {
XX!   	*gids++ = '\0';
XX!       	uids = argv[1];
XX    } else {
XX!           if (Chown) {
XX!          	uids = argv[1];
XX!          	gids = NULL;
XX!       	  } else {
XX!          	  uids = NULL;
XX!          	  gids = argv[1];
XX!       	    }
XX    }
XX!   if (uids == NULL) pwd = NULL;
XX!     else {
XX!           if (isdigit(*uids)) pwd = getpwuid(atoi(uids));
XX!       	    else pwd = getpwnam(uids);
XX!           if (pwd == NULL) {
XX!          	(void) fprintf(stderr, "%s: unknown user id %s\n", pgmname, uids);
XX!          	(void) exit(-1);
XX!       	  }
XX!     }
XX!   if (gids == NULL) grp = NULL;
XX!     else {
XX!           if (isdigit(*gids)) grp = getgrgid(atoi(gids));
XX!             else grp = getgrnam(gids);
XX!           if (grp == NULL) {
XX!          	(void) fprintf(stderr, "%s: unknown group: %s\n", pgmname, gids);
XX!          	(void) exit(-1);
XX!       	  }
XX!     }
XX!   for (i = 2; i < argc; i++) {
XX!   	if (stat(argv[i], &st) != -1) {
XX!         uid = (pwd == NULL) ? st.st_uid : pwd->pw_uid;
XX!         gid = (grp == NULL) ? st.st_gid : grp->gr_gid;
XX!         if (chown(argv[i], uid, gid) == -1) {
XX!         	(void) fprintf(stderr,"%s: not changed\n", argv[i]);
XX!             	status++;
XX!         }
XX! #ifdef _MINIX
XX!         /*
XX!          * chown(2) should do this ...
XX!          */
XX!         if (getuid() != 0) {
XX! 		st.st_mode &= ~S_ISUID;
XX!             	st.st_mode &= ~S_ISGID;
XX!             	if (chmod(argv[i], st.st_mode) == -1) {
XX!                		(void) fprintf(stderr, "%s: mode not changed\n", argv[i]);
XX!                		status++;
XX!             	}
XX!         }
XX! #endif
XX!      } else {
XX!              (void) perror(argv[i]);
XX!              status++;
XX!        }
XX    }
XX!   (void) exit(status);
XX  }
XX--- 1,171 ----
XX! /* chown/chgrp - Change file ownership			Author: V. Archer */
XX! 
XX! /* Copyright 1991 by Vincent Archer
XX!  *	You may freely redistribute this software, in source or binary
XX!  *	form, provided that you do not alter this copyright mention in any
XX!  *	way.
XX   */
XX+ 
XX  #include <sys/types.h>
XX+ #include <sys/stat.h>
XX  #include <ctype.h>
XX! #include <dirent.h>
XX  #include <pwd.h>
XX+ #include <grp.h>
XX  #include <string.h>
XX! #include <limits.h>
XX! #include <errno.h>
XX! #include <stdlib.h>
XX! #include <unistd.h>
XX! #include <minix/minlib.h>
XX  #include <stdio.h>
XX  
XX! #define S_IUGID (S_ISUID|S_ISGID)
XX  
XX! /* Global variables, such as flags and path names */
XX! int gflag, oflag, rflag, error;
XX! char *pgmname, path[PATH_MAX + 1];
XX! uid_t nuid, ouid;
XX! gid_t ngid;
XX  
XX+ _PROTOTYPE(int main, (int argc, char **argv));
XX+ _PROTOTYPE(void do_chown, (char *file));
XX+ _PROTOTYPE(void usage, (void));
XX  
XX! /* Main module. If chown(1) is invoked as chgrp(1), the behaviour is nearly
XX!  * identical, except that the default when a single name is given as an
XX!  * argument is to take a group id rather than an user id. This allow the
XX!  * non-Posix "chgrp user:group file".
XX!  * The single option switch used by chown/chgrp (-R) does not warrant a
XX!  * call to the getopt stuff. The two others flags (-g, -u) are set from
XX!  * the program name and arguments.
XX!  */
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX!   char *id, *id2;
XX    struct group *grp;
XX+   struct passwd *pwp;
XX+ 
XX+   if (pgmname = strrchr(*argv, '/'))
XX+ 	pgmname++;
XX+   else
XX+ 	pgmname = *argv;
XX+   argc--;
XX+   argv++;
XX+   gflag = strcmp(pgmname, "chgrp");
XX+ 
XX+   if (argc && **argv == '-' && argv[0][1] == 'R') {
XX+ 	argc--;
XX+ 	argv++;
XX+ 	rflag = 1;
XX+   }
XX+   if (argc < 2) usage();
XX+ 
XX+   id = *argv++;
XX+   argc--;
XX+   if (id2 = strchr(id, ':')) *id2++ = '\0';
XX+   if (!id2 && !gflag) {
XX+ 	id2 = id;
XX+ 	id = 0;
XX+   }
XX+   if (id) {
XX+ 	if (isdigit(*id))
XX+ 		nuid = atoi(id);
XX+ 	else {
XX+ 		if (!(pwp = getpwnam(id))) {
XX+ 			std_err(id);
XX+ 			std_err(": unknown user name\n");
XX+ 			exit(1);
XX+ 		}
XX+ 		nuid = pwp->pw_uid;
XX+ 	}
XX+ 	oflag = 1;
XX+   } else
XX+ 	oflag = 0;
XX+ 
XX+   if (id2) {
XX+ 	if (isdigit(*id2))
XX+ 		ngid = atoi(id2);
XX+ 	else {
XX+ 		if (!(grp = getgrnam(id2))) {
XX+ 			std_err(id2);
XX+ 			std_err(": unknown group name\n");
XX+ 			exit(1);
XX+ 		}
XX+ 		ngid = grp->gr_gid;
XX+ 	}
XX+ 	gflag = 1;
XX+   } else
XX+ 	gflag = 0;
XX+ 
XX+   ouid = getuid();
XX+   error = 0;
XX+   while (argc--) do_chown(*argv++);
XX+   return(error);
XX+ }
XX+ 
XX+ /* Apply the user/group modification here. If chown/chgrp is setuid root
XX+  * (when POSIX_CHOWN_RESTRICTED is true, as in Minix), chown/chgrp will
XX+  * apply its own protection (you must be owner to change either group/user,
XX+  * and doing so always clears BOTH setuid and setgid bits) if the caller is
XX+  * not 'root'.
XX+  */
XX+ void do_chown(file)
XX+ char *file;
XX+ {
XX+   DIR *dirp;
XX+   struct dirent *entp;
XX+   char *namp;
XX    struct stat st;
XX  
XX!   if (stat(file, &st)) {
XX! 	perror(file);
XX! 	error = 1;
XX! 	return;
XX    }
XX!   if (ouid && ouid != st.st_uid) {
XX! 	errno = EACCES;
XX! 	perror(file);
XX! 	error = 1;
XX    } else {
XX! 	if ((st.st_mode & S_IUGID) && ouid)
XX! 		chmod(file, st.st_mode & ~S_IUGID);
XX! 
XX! 	if (chown(file, oflag ? nuid : st.st_uid, gflag ? ngid : st.st_gid)) {
XX! 		perror(file);
XX! 		error = 1;
XX! 	}
XX    }
XX! 
XX!   if (S_ISDIR(st.st_mode) && rflag) {
XX! 	if (!(dirp = opendir(file))) {
XX! 		perror(file);
XX! 		error = 1;
XX! 		return;
XX! 	}
XX! 	if (path != file) strcpy(path, file);
XX! 	namp = path + strlen(path);
XX! 	*namp++ = '/';
XX! 	while (entp = readdir(dirp))
XX! 		if (entp->d_name[0] != '.' ||
XX! 		    (entp->d_name[1] &&
XX! 		     (entp->d_name[1] != '.' || entp->d_name[2]))) {
XX! 			strcpy(namp, entp->d_name);
XX! 			do_chown(path);
XX! 		}
XX! 	closedir(dirp);
XX! 	*--namp = '\0';
XX    }
XX! }
XX! 
XX! /* Posix prototype of the chown/chgrp function */
XX! void usage()
XX! {
XX!   std_err("Usage: ");
XX!   std_err(pgmname);
XX!   std_err(gflag ? " owner[:group]" : " [owner:]group");
XX!   std_err(" file...\n");
XX!   exit(1);
XX  }
X/
Xecho x - ci.c.d
Xsed '/^X/s///' > ci.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/ci.c  crc=39359   7477	Sun Apr 25 21:34:49 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/ci.c  crc=40916   7973	Wed Nov  4 04:19:06 1992
XX***************
XX*** 5,10 ****
XX--- 5,15 ----
XX  #include <sys/stat.h>
XX  #include <pwd.h>
XX  #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX+ #include <time.h>
XX+ #include <fcntl.h>
XX+ #include <sys/wait.h>
XX  #include <stdio.h>
XX  
XX  #define SUFFIX		",S"	/* svc indicator */
XX***************
XX*** 41,53 ****
XX  char original[] = "/tmp/cioXXXXXX";	/* previous revision */
XX  char diffout[] = "/tmp/cidXXXXXX";	/* diffs */
XX  
XX! extern char *mktemp();
XX! extern char *ctime();
XX  
XX! char *whoami();
XX! void onintr();
XX! 
XX! main(argc, argv)
XX  int argc;
XX  char **argv;
XX  {
XX--- 46,62 ----
XX  char original[] = "/tmp/cioXXXXXX";	/* previous revision */
XX  char diffout[] = "/tmp/cidXXXXXX";	/* diffs */
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void rundiff, (void));
XX! _PROTOTYPE(void logmsg, (FILE *fp));
XX! _PROTOTYPE(void fname, (char *src, char *dst));
XX! _PROTOTYPE(void svcname, (char *src, char *dst));
XX! _PROTOTYPE(int lockcheck, (FILE *fp, int rev));
XX! _PROTOTYPE(void onintr, (int dummy));
XX! _PROTOTYPE(void clean, (void));
XX! _PROTOTYPE(char *whoami, (void));
XX  
XX! int main(argc, argv)
XX  int argc;
XX  char **argv;
XX  {
XX***************
XX*** 91,97 ****
XX  	++p;
XX  
XX    if (strlen(p) > 13) {
XX! 	fprintf(stderr, "ci: filename %s is too long\n");
XX  	exit(1);
XX    }
XX  #endif /* !BSD */
XX--- 100,106 ----
XX  	++p;
XX  
XX    if (strlen(p) > 13) {
XX! 	fprintf(stderr, "ci: filename %s is too long\n", p);
XX  	exit(1);
XX    }
XX  #endif /* !BSD */
XX***************
XX*** 121,127 ****
XX  	}
XX  	if (NULL == (origfp = fopen(original, "w"))) {
XX  		fprintf(stderr, "ci: can't create %s", original);
XX! 		perror("");
XX  	}
XX  	fgets(line, LINELEN, svcfp);	/* skip "cat <<***MAIN-eof***" line */
XX  
XX--- 130,136 ----
XX  	}
XX  	if (NULL == (origfp = fopen(original, "w"))) {
XX  		fprintf(stderr, "ci: can't create %s", original);
XX! 		perror(" ");
XX  	}
XX  	fgets(line, LINELEN, svcfp);	/* skip "cat <<***MAIN-eof***" line */
XX  
XX***************
XX*** 170,176 ****
XX  	fprintf(newfp, "***%d-eof***\n", rev);
XX  	fputs((original == p) ? "mv Fix.$1 $1\n" : FIX, newfp);
XX  	logmsg(newfp);
XX! 	while (NULL != fgets(line, LINELEN, svcfp) && strncmp(line, "#***SVCLOCK***", 14))
XX  		fputs(line, newfp);
XX    } else {
XX  	logmsg(newfp);
XX--- 179,185 ----
XX  	fprintf(newfp, "***%d-eof***\n", rev);
XX  	fputs((original == p) ? "mv Fix.$1 $1\n" : FIX, newfp);
XX  	logmsg(newfp);
XX! 	while (NULL != fgets(line, LINELEN, svcfp) && strncmp(line, "#***SVCLOCK***", (size_t)14))
XX  		fputs(line, newfp);
XX    } else {
XX  	logmsg(newfp);
XX***************
XX*** 205,214 ****
XX  	unlink(file);
XX  
XX    clean();
XX!   exit(0);
XX  }
XX  
XX! rundiff()
XX  {				/* do "diff file original > diffout" */
XX    int fd;			/* redirected output file */
XX  
XX--- 214,223 ----
XX  	unlink(file);
XX  
XX    clean();
XX!   return(0);
XX  }
XX  
XX! void rundiff()
XX  {				/* do "diff file original > diffout" */
XX    int fd;			/* redirected output file */
XX  
XX***************
XX*** 239,245 ****
XX    }
XX  }
XX  
XX! logmsg(fp)
XX  FILE *fp;
XX  {
XX    long now;
XX--- 248,254 ----
XX    }
XX  }
XX  
XX! void logmsg(fp)
XX  FILE *fp;
XX  {
XX    long now;
XX***************
XX*** 251,257 ****
XX  	fprintf(fp, "#***SVC*** %s\n", line);
XX  }
XX  
XX! fname(src, dst)
XX  char *src, *dst;
XX  {
XX    char *p;
XX--- 260,266 ----
XX  	fprintf(fp, "#***SVC*** %s\n", line);
XX  }
XX  
XX! void fname(src, dst)
XX  char *src, *dst;
XX  {
XX    char *p;
XX***************
XX*** 260,266 ****
XX    if (!strcmp(p, SUFFIX)) *p = '\0';
XX  }
XX  
XX! svcname(src, dst)
XX  char *src, *dst;
XX  {
XX    char *p;
XX--- 269,275 ----
XX    if (!strcmp(p, SUFFIX)) *p = '\0';
XX  }
XX  
XX! void svcname(src, dst)
XX  char *src, *dst;
XX  {
XX    char *p;
XX***************
XX*** 271,277 ****
XX    if (0 != access(dst, 4)) {
XX  	char dirname[PATHLEN];
XX  	if (NULL != (p = strrchr(src, '/')))
XX! 		strncpy(dirname, src, p - src + 1);
XX  	else
XX  		dirname[0] = '\0';
XX  	strcat(dirname, SVCDIR);
XX--- 280,286 ----
XX    if (0 != access(dst, 4)) {
XX  	char dirname[PATHLEN];
XX  	if (NULL != (p = strrchr(src, '/')))
XX! 		strncpy(dirname, src, (size_t)(p - src + 1));
XX  	else
XX  		dirname[0] = '\0';
XX  	strcat(dirname, SVCDIR);
XX***************
XX*** 288,294 ****
XX    }
XX  }
XX  
XX! lockcheck(fp, rev)
XX  FILE *fp;
XX  int rev;
XX  {
XX--- 297,303 ----
XX    }
XX  }
XX  
XX! int lockcheck(fp, rev)
XX  FILE *fp;
XX  int rev;
XX  {
XX***************
XX*** 307,320 ****
XX    return ret;
XX  }
XX  
XX! void onintr()
XX  {
XX    fprintf(stderr, "Interrupt - Aborting checkin, cleaning up\n");
XX    clean();
XX    exit(1);
XX  }
XX  
XX! clean()
XX  {
XX    if (strlen(original))		/* if only more programs made this check! */
XX  	unlink(original);
XX--- 316,330 ----
XX    return ret;
XX  }
XX  
XX! void onintr(dummy)
XX! int dummy; /* to keep the compiler happy */
XX  {
XX    fprintf(stderr, "Interrupt - Aborting checkin, cleaning up\n");
XX    clean();
XX    exit(1);
XX  }
XX  
XX! void clean()
XX  {
XX    if (strlen(original))		/* if only more programs made this check! */
XX  	unlink(original);
X/
Xecho x - clr.c.d
Xsed '/^X/s///' > clr.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/clr.c  crc=54599   1518	Sun Apr 25 21:34:49 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/clr.c  crc=32622   1614	Wed Nov  4 04:19:06 1992
XX***************
XX*** 8,13 ****
XX--- 8,17 ----
XX  #include <sys/stat.h>
XX  #include <sgtty.h>
XX  #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <termcap.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  #define reverse()	write(1, SO, strlen(SO))	/* reverse video */
XX***************
XX*** 15,23 ****
XX  #define clearln()	write(1,"\r",1); \
XX  		write(1, CD, strlen(CD))	/* clear line */
XX  
XX- extern char *getenv();
XX- extern char *tgetstr();
XX- extern char *index();
XX  
XX  #define  TC_BUFFER  1024	/* Size of termcap(3) buffer	 */
XX  
XX--- 19,24 ----
XX***************
XX*** 28,35 ****
XX  char clear[30];
XX  char *p = &clear[0];
XX  
XX  
XX! main()
XX  {
XX  
XX    get_termcap();
XX--- 29,39 ----
XX  char clear[30];
XX  char *p = &clear[0];
XX  
XX+ _PROTOTYPE(int main, (void));
XX+ _PROTOTYPE(void get_termcap, (void));
XX+ _PROTOTYPE(void Error, (char *str));
XX  
XX! int main()
XX  {
XX  
XX    get_termcap();
XX***************
XX*** 39,51 ****
XX    clearln();
XX    printf("%s", clear);
XX  
XX!   exit(0);
XX  }
XX  
XX! get_termcap()
XX  {
XX    static char termbuf[50];
XX-   extern char *tgetstr(), *getenv();
XX    char *loc = termbuf;
XX    char entry[1024];
XX  
XX--- 43,54 ----
XX    clearln();
XX    printf("%s", clear);
XX  
XX!   return(0);
XX  }
XX  
XX! void get_termcap()
XX  {
XX    static char termbuf[50];
XX    char *loc = termbuf;
XX    char entry[1024];
XX  
XX***************
XX*** 70,76 ****
XX  
XX  }
XX  
XX! Error(str)
XX  char *str;
XX  {
XX    fprintf(stderr, "clr: %s\n", str);
XX--- 73,79 ----
XX  
XX  }
XX  
XX! void Error(str)
XX  char *str;
XX  {
XX    fprintf(stderr, "clr: %s\n", str);
X/
Xecho x - cmp.c.d
Xsed '/^X/s///' > cmp.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/cmp.c  crc=15254   2647	Sun Apr 25 21:34:49 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/cmp.c  crc=25405   2383	Wed Apr 14 22:40:34 1993
XX***************
XX*** 1,132 ****
XX! /* cmp - compare two files	Authors: Paul Polderman & Michiel Huisjes */
XX  
XX! /* 90-04-10 Schlenker
XX!  *	Fixed incorrect handling of flags.
XX!  *	Reduced buffer size to accommodate 7K pipes (Minix restriction).
XX!  *	Better trapping of file reading errors.
XX!  *	Considerable speedup when using -s flag.
XX!  *	Buffering strategy remains seriously error prone; should be fixed.
XX!  */
XX  
XX! #include <sys/types.h>
XX! #include <fcntl.h>
XX! #include <unistd.h>
XX! #include <stdio.h>
XX  
XX! #define BLOCK_SIZE 6144
XX  
XX! char *file_1, *file_2;
XX! char buf1[BLOCK_SIZE];
XX! char buf2[BLOCK_SIZE];
XX! char lflag, sflag;
XX  
XX! main(argc, argv)
XX  int argc;
XX! char *argv[];
XX  {
XX!   int fd1, fd2, i, exit_status;
XX  
XX!   if (argc < 3 || argc > 4) usage();
XX!   lflag = 0;
XX!   sflag = 0;
XX  
XX!   i = 1;
XX!   if (strcmp(argv[i], "-l") == 0) {
XX! 	lflag++;
XX! 	i++;
XX!   } else
XX!   if (strcmp(argv[i], "-s") == 0) {
XX! 	sflag++;
XX! 	i++;
XX    }
XX  
XX!   if (strcmp(argv[i], "-") == 0) {
XX  	fd1 = 0;
XX- 	file_1 = "<stdin>";
XX    } else {
XX! 	if ((fd1 = open(argv[i], O_RDONLY)) < 0)
XX! 		cantopen(argv[i]);
XX! 	file_1 = argv[i];
XX    }
XX-   i++;
XX  
XX!   if (i == argc || (fd2 = open(argv[i], O_RDONLY)) < 0)
XX! 	cantopen(argv[i]);
XX!   file_2 = argv[i];
XX  
XX!   exit_status = sflag ? fastcmp(fd1, fd2) : cmp(fd1, fd2);
XX! 
XX!   close(fd1);
XX!   close(fd2);
XX! 
XX!   exit(exit_status);
XX  }
XX  
XX! cmp(fd1, fd2)
XX  int fd1, fd2;
XX  {
XX!   register unsigned long char_cnt, line_cnt;
XX!   register int i;
XX!   int n1, n2, n, exit_status;
XX  
XX!   char_cnt = 1L;
XX!   line_cnt = 1L;
XX!   exit_status = 0;
XX!   do {
XX! 	n1 = read(fd1, buf1, BLOCK_SIZE);
XX! 	n2 = read(fd2, buf2, BLOCK_SIZE);
XX! 	n = (n1 < n2) ? n1 : n2;
XX! 	if (n < 0) {
XX! 		printf("cmp: Error on %s\n", (n1 < 0) ? file_1 : file_2);
XX! 		return(1);
XX  	}
XX! 	for (i = 0; i < n; i++) {	/* Check buffers for equality */
XX! 		if (buf1[i] != buf2[i]) {
XX! 			if (!lflag) {
XX  				printf("%s %s differ: char %ld, line %ld\n",
XX! 				file_1, file_2, char_cnt, line_cnt);
XX! 				return(1);
XX  			}
XX! 			printf("%10lu %03o %03o\n",
XX! 			       char_cnt, buf1[i] & 0377, buf2[i] & 0377);
XX! 			exit_status = 1;
XX  		}
XX! 		if (buf1[i] == '\n') line_cnt++;
XX! 		char_cnt++;
XX  	}
XX! 	if (n1 != n2) {		/* EOF on one of the input files. */
XX! 		printf("cmp: EOF on %s\n", (n1 < n2) ? file_1 : file_2);
XX! 		return(1);
XX! 	}
XX!   } while (n > 0);		/* While not EOF on any file */
XX!   return(exit_status);
XX  }
XX  
XX! fastcmp(fd1, fd2)
XX! int fd1, fd2;
XX  {
XX!   int n1, n2;
XX! 
XX!   while (1) {
XX! 	n1 = read(fd1, buf1, BLOCK_SIZE);
XX! 	n2 = read(fd2, buf2, BLOCK_SIZE);
XX! 	if (n1 != n2) return(1);	/* Bug! - depends on buffering */
XX! 	if (n1 == 0) return(0);
XX! 	if (n1 < 0) return(1);
XX! 	if (memcmp((void *) buf1, (void *) buf2, (size_t) n1) != 0)
XX! 		return(1);
XX    }
XX  }
XX  
XX! usage()
XX  {
XX    fprintf(stderr, "Usage: cmp [-l | -s] file1 file2\n");
XX    exit(2);
XX- }
XX- 
XX- cantopen(s)
XX- char *s;
XX- {
XX-   fprintf(stderr, "cmp: cannot open %s\n", s);
XX-   exit(1);
XX  }
XX--- 1,132 ----
XX! /* cmp - compare two files		Author: Kees J. Bot.  */
XX  
XX! #include "sys/types.h"
XX! #include "fcntl.h"
XX! #include "stdlib.h"
XX! #include "unistd.h"
XX! #include "stdio.h"
XX  
XX! _PROTOTYPE(void fatal, (char *label));
XX! _PROTOTYPE(int cmp, (int fd1, int fd2));
XX! _PROTOTYPE(void Usage, (void));
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX  
XX! #define BLOCK	4096
XX  
XX! static int loud = 0, silent = 0;
XX! static char *name1, *name2;
XX  
XX! int main(argc, argv)
XX  int argc;
XX! char **argv;
XX  {
XX!   int fd1, fd2;
XX!   char *opt;
XX  
XX!   /* Process the '-l' or '-s' option. */
XX!   while (argc > 1 && argv[1][0] == '-' && argv[1][1] != 0) {
XX!   	if (argv[1][2] != 0) Usage();
XX  
XX!   	switch (argv[1][1]) {
XX!   	case '-':
XX!   		/* '--': no-op option. */
XX!   		break;
XX!   	case 'l':
XX! 		loud = 1;
XX! 		break;
XX! 	case 's':
XX! 		silent = 1;
XX! 		break;
XX! 	default:
XX! 		Usage();
XX! 	}
XX! 	argc--;
XX! 	argv++;
XX    }
XX+   if (argc != 3) Usage();
XX  
XX!   /* Open the first file, '-' means standard input. */
XX!   if (argv[1][0] == '-' && argv[1][1] == 0) {
XX! 	name1 = "stdin";
XX  	fd1 = 0;
XX    } else {
XX! 	name1 = argv[1];
XX! 	if ((fd1 = open(name1, 0)) < 0) fatal(name1);
XX    }
XX  
XX!   /* Second file likewise. */
XX!   if (argv[2][0] == '-' && argv[2][1] == 0) {
XX! 	name2 = "stdin";
XX! 	fd2 = 0;
XX!   } else {
XX! 	name2 = argv[2];
XX! 	if ((fd2 = open(name2, 0)) < 0) fatal(name2);
XX!   }
XX  
XX!   exit(cmp(fd1, fd2));
XX  }
XX  
XX! int cmp(fd1, fd2)
XX  int fd1, fd2;
XX  {
XX!   static char buf1[BLOCK], buf2[BLOCK];
XX!   int n1 = 0, n2 = 0, i1 = 0, i2 = 0, c1, c2;
XX!   off_t pos = 0, line = 1;
XX!   int eof = 0, differ = 0;
XX  
XX!   for (;;) {
XX! 	if (i1 == n1) {
XX! 		pos += n1;
XX! 
XX! 		if ((n1 = read(fd1, buf1, sizeof(buf1))) <= 0) {
XX! 			if (n1 < 0) fatal(name1);
XX! 			eof |= 1;
XX! 		}
XX! 		i1 = 0;
XX  	}
XX! 	if (i2 == n2) {
XX! 		if ((n2 = read(fd2, buf2, sizeof(buf2))) <= 0) {
XX! 			if (n2 < 0) fatal(name2);
XX! 			eof |= 2;
XX! 		}
XX! 		i2 = 0;
XX! 	}
XX! 	if (eof != 0) break;
XX! 
XX! 	c1 = buf1[i1++];
XX! 	c2 = buf2[i2++];
XX! 
XX! 	if (c1 != c2) {
XX! 		if (!loud) {
XX! 			if (!silent) {
XX  				printf("%s %s differ: char %ld, line %ld\n",
XX! 				       name1, name2, pos + i1, line);
XX  			}
XX! 			return(1);
XX  		}
XX! 		printf("%10ld %3o %3o\n", pos + i1, c1 & 0xFF, c2 & 0xFF);
XX! 		differ = 1;
XX  	}
XX! 	if (c1 == '\n') line++;
XX!   }
XX!   if (eof == (1 | 2)) return(differ);
XX!   if (!silent) fprintf(stderr, "cmp: EOF on %s\n", eof == 1 ? name1 : name2);
XX!   return(1);
XX  }
XX  
XX! void fatal(label)
XX! char *label;
XX  {
XX!   if (!silent) {
XX! 	fprintf(stderr, "cmp: ");
XX! 	fflush(stderr);
XX! 	perror(label);
XX    }
XX+   exit(2);
XX  }
XX  
XX! void Usage()
XX  {
XX    fprintf(stderr, "Usage: cmp [-l | -s] file1 file2\n");
XX    exit(2);
XX  }
X/
Xecho x - co.c.d
Xsed '/^X/s///' > co.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/co.c  crc=08933   5572	Sun Apr 25 21:34:50 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/co.c  crc=20440   5786	Wed Nov  4 04:19:07 1992
XX***************
XX*** 4,9 ****
XX--- 4,11 ----
XX  #include <sys/stat.h>
XX  #include <string.h>
XX  #include <pwd.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  #define SUFFIX		",S"	/* svc indicator */
XX***************
XX*** 27,44 ****
XX  int rev;			/* old revision number */
XX  int lastrev, lockrev;		/* latest file revision, lock into */
XX  int status;			/* wait() buffer */
XX! int lock;			/* lock the SVC file */
XX  struct stat stb;		/* stat() buffer */
XX  char *base;			/* basename of file */
XX  
XX  char difftemp[PATHLEN];		/* extract() fix/patch input */
XX  
XX! extern char *mktemp();
XX! extern struct passwd *getpwuid();
XX  
XX! char *whoami(), *basename();
XX! 
XX! main(argc, argv)
XX  int argc;
XX  char **argv;
XX  {
XX--- 29,49 ----
XX  int rev;			/* old revision number */
XX  int lastrev, lockrev;		/* latest file revision, lock into */
XX  int status;			/* wait() buffer */
XX! int svclock;			/* lock the SVC file */
XX  struct stat stb;		/* stat() buffer */
XX  char *base;			/* basename of file */
XX  
XX  char difftemp[PATHLEN];		/* extract() fix/patch input */
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void fname, (char *src, char *dst));
XX! _PROTOTYPE(void svcname, (char *src, char *dst));
XX! _PROTOTYPE(void extract, (char *script, char *out, int rev));
XX! _PROTOTYPE(char *basename, (char *name));
XX! _PROTOTYPE(char *whoami, (void));
XX! _PROTOTYPE(int getyn, (void));
XX  
XX! int main(argc, argv)
XX  int argc;
XX  char **argv;
XX  {
XX***************
XX*** 58,64 ****
XX  				exit(1);
XX  			}
XX  		} else if ('l' == (*argv)[1])
XX! 			++lock;
XX  		else {
XX  			fprintf(stderr, "co: illegal option -%c\n", (*argv)[1]);
XX  			exit(1);
XX--- 63,69 ----
XX  				exit(1);
XX  			}
XX  		} else if ('l' == (*argv)[1])
XX! 			++svclock;
XX  		else {
XX  			fprintf(stderr, "co: illegal option -%c\n", (*argv)[1]);
XX  			exit(1);
XX***************
XX*** 76,82 ****
XX  
XX    fprintf(stderr, "%s -> %s\n", svc, base = basename(file));
XX  
XX!   if ((FILE *) NULL == (svcfp = fopen(svc, "r"))) {
XX  	perror("co: can't read SVC file");
XX  	exit(1);
XX    }
XX--- 81,87 ----
XX  
XX    fprintf(stderr, "%s -> %s\n", svc, base = basename(file));
XX  
XX!   if (NULL == (svcfp = fopen(svc, "r"))) {
XX  	perror("co: can't read SVC file");
XX  	exit(1);
XX    }
XX***************
XX*** 98,104 ****
XX    fprintf(stderr, "Checking out revision %d", rev);
XX    extract(svc, base, rev);
XX  
XX!   if (lock) {
XX  	lockrev = lastrev + 1;
XX  	fprintf(stderr, "; Locking into revision %d\n", lockrev);
XX  	if (stat(svc, &stb) < 0 || chmod(svc, stb.st_mode | 0200) < 0)
XX--- 103,109 ----
XX    fprintf(stderr, "Checking out revision %d", rev);
XX    extract(svc, base, rev);
XX  
XX!   if (svclock) {
XX  	lockrev = lastrev + 1;
XX  	fprintf(stderr, "; Locking into revision %d\n", lockrev);
XX  	if (stat(svc, &stb) < 0 || chmod(svc, stb.st_mode | 0200) < 0)
XX***************
XX*** 107,113 ****
XX  	if (stat(base, &stb) < 0 || chmod(base, stb.st_mode | 0200) < 0)
XX  		perror("co: can't chmod source file");
XX  
XX! 	if ((FILE *) NULL == (svcfp = fopen(svc, "a"))
XX  	    || (fprintf(svcfp, "#***SVCLOCK*** %s %d\n", whoami(), lockrev), ferror(svcfp))) {
XX  		fprintf(stderr, "co: can't lock %s\n", svc);
XX  		exit(1);
XX--- 112,118 ----
XX  	if (stat(base, &stb) < 0 || chmod(base, stb.st_mode | 0200) < 0)
XX  		perror("co: can't chmod source file");
XX  
XX! 	if (NULL == (svcfp = fopen(svc, "a"))
XX  	    || (fprintf(svcfp, "#***SVCLOCK*** %s %d\n", whoami(), lockrev), ferror(svcfp))) {
XX  		fprintf(stderr, "co: can't lock %s\n", svc);
XX  		exit(1);
XX***************
XX*** 120,130 ****
XX  		perror("co: can't chmod source file");
XX    }
XX  
XX!   exit(0);
XX  }
XX  
XX  
XX! fname(src, dst)
XX  char *src, *dst;
XX  {
XX    char *p;
XX--- 125,135 ----
XX  		perror("co: can't chmod source file");
XX    }
XX  
XX!   return(0);
XX  }
XX  
XX  
XX! void fname(src, dst)
XX  char *src, *dst;
XX  {
XX    char *p;
XX***************
XX*** 133,139 ****
XX    if (!strcmp(p, SUFFIX)) *p = '\0';
XX  }
XX  
XX! svcname(src, dst)
XX  char *src, *dst;
XX  {
XX    char *p;
XX--- 138,144 ----
XX    if (!strcmp(p, SUFFIX)) *p = '\0';
XX  }
XX  
XX! void svcname(src, dst)
XX  char *src, *dst;
XX  {
XX    char *p;
XX***************
XX*** 143,157 ****
XX  
XX    if (0 != access(dst, 4)) {
XX  	char dirname[PATHLEN];
XX! 	if ( (char *) NULL != (p = strrchr(src, '/')))
XX! 		strncpy(dirname, src, (int)(p - src) + 1);
XX  	else
XX  		dirname[0] = '\0';
XX  	strcat(dirname, SVCDIR);
XX  
XX  	if (0 == access(dirname, 1)) {
XX  		strcpy(dst, dirname);
XX! 		if ((char *) NULL == p) {
XX  			strcat(dst, "/");
XX  			strcat(dst, src);
XX  		} else
XX--- 148,162 ----
XX  
XX    if (0 != access(dst, 4)) {
XX  	char dirname[PATHLEN];
XX! 	if (NULL != (p = strrchr(src, '/')))
XX! 		strncpy(dirname, src, (size_t)(p - src) + 1);
XX  	else
XX  		dirname[0] = '\0';
XX  	strcat(dirname, SVCDIR);
XX  
XX  	if (0 == access(dirname, 1)) {
XX  		strcpy(dst, dirname);
XX! 		if (NULL == p) {
XX  			strcat(dst, "/");
XX  			strcat(dst, src);
XX  		} else
XX***************
XX*** 161,167 ****
XX    }
XX  }
XX  
XX! extract(script, out, rev)
XX  char *script, *out;
XX  int rev;
XX  {
XX--- 166,172 ----
XX    }
XX  }
XX  
XX! void extract(script, out, rev)
XX  char *script, *out;
XX  int rev;
XX  {
XX***************
XX*** 175,213 ****
XX    fgets(line, LINELEN, svcfp);	/* skip '# rev' line */
XX    fgets(line, LINELEN, svcfp);	/* skip 'cat <***MAIN-eof***' line */
XX  
XX!   if ((FILE *) NULL == (outfp = fopen(out, "w"))) {
XX  	perror("co: can't create output file");
XX  	return;
XX    }
XX!   while ((char *) NULL != fgets(line, LINELEN, svcfp) &&
XX  	  strcmp(line, "***MAIN-eof***\n"))
XX  	fputs(line, outfp);
XX  
XX    fclose(outfp);
XX  
XX!   while ((char *) NULL != fgets(line, LINELEN, svcfp)) {
XX! 	if (!strncmp(line, "if ", 3)) {
XX  		sscanf(line, "if test $2 -ge %d", &testrev);
XX  		if (rev >= testrev) {
XX  			unlink(difftemp);
XX  			return;
XX  		}
XX! 		if ((FILE *) NULL == (outfp = fopen(difftemp, "w"))) {
XX  			perror("co: can't create output file");
XX  			return;
XX  		}
XX  		sprintf(buf, "***%d-eof***\n", testrev);
XX! 		while ((char *) NULL != fgets(line, LINELEN, svcfp) &&
XX  							strcmp(line, buf))
XX  			fputs(line, outfp);
XX  		fclose(outfp);
XX! 	} else if (!strncmp(line, "mv ", 3)) {
XX  		sprintf(buf, "mv Fix.%s %s", out, out);
XX  		system(buf);
XX! 	} else if (!strncmp(line, "fix ", 4)) {
XX  		sprintf(buf, "fix %s Fix.%s > New.%s; mv New.%s %s", out, out, out, out, out);
XX  		system(buf);
XX! 	} else if (!strncmp(line, "patch ", 6)) {
XX  		sprintf(buf, "patch -n -s %s < Fix.%s; rm -f %s.orig", out, out, out);
XX  		system(buf);
XX  	} else {		/* ignore */
XX--- 180,218 ----
XX    fgets(line, LINELEN, svcfp);	/* skip '# rev' line */
XX    fgets(line, LINELEN, svcfp);	/* skip 'cat <***MAIN-eof***' line */
XX  
XX!   if (NULL == (outfp = fopen(out, "w"))) {
XX  	perror("co: can't create output file");
XX  	return;
XX    }
XX!   while (NULL != fgets(line, LINELEN, svcfp) &&
XX  	  strcmp(line, "***MAIN-eof***\n"))
XX  	fputs(line, outfp);
XX  
XX    fclose(outfp);
XX  
XX!   while (NULL != fgets(line, LINELEN, svcfp)) {
XX! 	if (!strncmp(line, "if ", (size_t)3)) {
XX  		sscanf(line, "if test $2 -ge %d", &testrev);
XX  		if (rev >= testrev) {
XX  			unlink(difftemp);
XX  			return;
XX  		}
XX! 		if (NULL == (outfp = fopen(difftemp, "w"))) {
XX  			perror("co: can't create output file");
XX  			return;
XX  		}
XX  		sprintf(buf, "***%d-eof***\n", testrev);
XX! 		while (NULL != fgets(line, LINELEN, svcfp) &&
XX  							strcmp(line, buf))
XX  			fputs(line, outfp);
XX  		fclose(outfp);
XX! 	} else if (!strncmp(line, "mv ", (size_t)3)) {
XX  		sprintf(buf, "mv Fix.%s %s", out, out);
XX  		system(buf);
XX! 	} else if (!strncmp(line, "fix ", (size_t)4)) {
XX  		sprintf(buf, "fix %s Fix.%s > New.%s; mv New.%s %s", out, out, out, out, out);
XX  		system(buf);
XX! 	} else if (!strncmp(line, "patch ", (size_t)6)) {
XX  		sprintf(buf, "patch -n -s %s < Fix.%s; rm -f %s.orig", out, out, out);
XX  		system(buf);
XX  	} else {		/* ignore */
XX***************
XX*** 223,229 ****
XX  {
XX    char *p;
XX  
XX!   if ((char *) NULL == (p = strrchr(name, '/')))
XX  	return name;
XX    else
XX  	return p + 1;
XX--- 228,234 ----
XX  {
XX    char *p;
XX  
XX!   if (NULL == (p = strrchr(name, '/')))
XX  	return name;
XX    else
XX  	return p + 1;
XX***************
XX*** 233,239 ****
XX  {
XX    struct passwd *pw;
XX  
XX!   if ((struct passwd *) NULL != (pw = getpwuid(getuid())))
XX  	return pw->pw_name;
XX    else
XX  	return "nobody";
XX--- 238,244 ----
XX  {
XX    struct passwd *pw;
XX  
XX!   if (NULL != (pw = getpwuid(getuid())))
XX  	return pw->pw_name;
XX    else
XX  	return "nobody";
XX***************
XX*** 243,247 ****
XX  {
XX    char ans[10];
XX  
XX!   return((char *) NULL != fgets(ans, 10, stdin)) && ('y' == ans[0] || 'Y' == ans[0]);
XX  }
XX--- 248,252 ----
XX  {
XX    char ans[10];
XX  
XX!   return(NULL != fgets(ans, 10, stdin)) && ('y' == ans[0] || 'Y' == ans[0]);
XX  }
X/
Xecho x - comm.c.d
Xsed '/^X/s///' > comm.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/comm.c  crc=00730   3509	Sun Apr 25 21:34:50 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/comm.c  crc=41699   4036	Wed Nov  4 04:19:07 1992
XX***************
XX*** 13,26 ****
XX  
XX  #include <sys/types.h>
XX  #include <fcntl.h>
XX  
XX! #define BUFSIZ (512)
XX  #define LINMAX (600)
XX  
XX  struct file {
XX    char *name;			/* the file's name */
XX    int fd;			/* the file descripter */
XX!   char buf[BUFSIZ];		/* buffer storage */
XX    char *next;			/* the next character to read */
XX    char *endp;			/* the first invalid character */
XX    int seeneof;			/* an end of file has been seen */
XX--- 13,31 ----
XX  
XX  #include <sys/types.h>
XX  #include <fcntl.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <unistd.h>
XX+ #include <minix/minlib.h>
XX+ #include <stdio.h>
XX  
XX! #define BUFFER_SIZE (512)
XX  #define LINMAX (600)
XX  
XX  struct file {
XX    char *name;			/* the file's name */
XX    int fd;			/* the file descripter */
XX!   char buf[BUFFER_SIZE];		/* buffer storage */
XX    char *next;			/* the next character to read */
XX    char *endp;			/* the first invalid character */
XX    int seeneof;			/* an end of file has been seen */
XX***************
XX*** 32,38 ****
XX  
XX  static char *umsg = "Usage: comm [-[123]] file1 file2\n";
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX--- 37,53 ----
XX  
XX  static char *umsg = "Usage: comm [-[123]] file1 file2\n";
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void usage, (void));
XX! _PROTOTYPE(void error, (char *s, char *f));
XX! _PROTOTYPE(void eopen, (char *fn, struct file *file));
XX! _PROTOTYPE(int getbuf, (struct file *file));
XX! _PROTOTYPE(int readline, (int fno));
XX! _PROTOTYPE(void comm, (void));
XX! _PROTOTYPE(void putcol, (int col, char *buf));
XX! _PROTOTYPE(void cpycol, (int col));
XX! 
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX***************
XX*** 57,73 ****
XX    eopen(argv[1], &files[0]);
XX    eopen(argv[2], &files[1]);
XX    comm();
XX!   exit(0);
XX  }
XX  
XX! usage()
XX  {
XX  
XX    std_err(umsg);
XX    exit(1);
XX  }
XX  
XX! error(s, f)
XX  char *s, *f;
XX  {
XX    std_err("comm: ");
XX--- 72,88 ----
XX    eopen(argv[1], &files[0]);
XX    eopen(argv[2], &files[1]);
XX    comm();
XX!   return(0);
XX  }
XX  
XX! void usage()
XX  {
XX  
XX    std_err(umsg);
XX    exit(1);
XX  }
XX  
XX! void error(s, f)
XX  char *s, *f;
XX  {
XX    std_err("comm: ");
XX***************
XX*** 77,83 ****
XX    exit(1);
XX  }
XX  
XX! int eopen(fn, file)
XX  char *fn;
XX  struct file *file;
XX  {
XX--- 92,98 ----
XX    exit(1);
XX  }
XX  
XX! void eopen(fn, file)
XX  char *fn;
XX  struct file *file;
XX  {
XX***************
XX*** 100,106 ****
XX    int n;
XX  
XX    if (file->seeneof) return(1);
XX!   if ((n = read(file->fd, &file->buf[0], BUFSIZ)) < 0)
XX  	error("read error on ", file->name);
XX    if (n == 0) {
XX  	file->seeneof++;
XX--- 115,121 ----
XX    int n;
XX  
XX    if (file->seeneof) return(1);
XX!   if ((n = read(file->fd, &file->buf[0], BUFFER_SIZE)) < 0)
XX  	error("read error on ", file->name);
XX    if (n == 0) {
XX  	file->seeneof++;
XX***************
XX*** 133,139 ****
XX    return(1);
XX  }
XX  
XX! comm()
XX  {
XX    register int res;
XX  
XX--- 148,154 ----
XX    return(1);
XX  }
XX  
XX! void comm()
XX  {
XX    register int res;
XX  
XX***************
XX*** 172,189 ****
XX    /* NOTREACHED */
XX  }
XX  
XX! putcol(col, buf)
XX  int col;
XX  char *buf;
XX  {
XX    int cnt;
XX  
XX    if (colflgs[col] == 0) return;
XX!   for (cnt = 0; cnt < colflgs[col] - 1; cnt++) prints("\t");
XX!   prints("%s", buf);
XX  }
XX  
XX! cpycol(col)
XX  int col;
XX  {
XX    if (colflgs[col]) while (readline(col))
XX--- 187,204 ----
XX    /* NOTREACHED */
XX  }
XX  
XX! void putcol(col, buf)
XX  int col;
XX  char *buf;
XX  {
XX    int cnt;
XX  
XX    if (colflgs[col] == 0) return;
XX!   for (cnt = 0; cnt < colflgs[col] - 1; cnt++) printf("\t");
XX!   printf("%s", buf);
XX  }
XX  
XX! void cpycol(col)
XX  int col;
XX  {
XX    if (colflgs[col]) while (readline(col))
X/
Xecho x - compress.c.d
Xsed '/^X/s///' > compress.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/compress.c  crc=49047  38455	Sun Apr 25 21:34:50 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/compress.c  crc=10051  38972	Wed Nov  4 04:19:07 1992
XX***************
XX*** 73,80 ****
XX  #define DOTZ ".Z"
XX  
XX  #ifdef AZTEC86 
XX- void prratio(),cl_block(),cl_hash(),output(),decompress(),
XX- copystat(),writeerr(),compress(),Usage(),version();
XX  #ifdef AZTECBITS
XX  # define BITS   AZTECBITS
XX  #else
XX--- 73,78 ----
XX***************
XX*** 148,154 ****
XX  #else
XX   typedef	unsigned char	char_type;
XX  #endif /* UCHAR */
XX! char_type magic_header[] = { "\037\235" };	/* 1F 9D */
XX  
XX  /* Defines for third byte of header */
XX  #define BIT_MASK	0x1f
XX--- 146,152 ----
XX  #else
XX   typedef	unsigned char	char_type;
XX  #endif /* UCHAR */
XX! char_type magic_header[] = "\037\235";	/* 1F 9D */
XX  
XX  /* Defines for third byte of header */
XX  #define BIT_MASK	0x1f
XX***************
XX*** 163,168 ****
XX--- 161,170 ----
XX  #include <fcntl.h>
XX  #include <ctype.h>
XX  #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <unistd.h>
XX+ #include <utime.h>
XX  #include <stdio.h>
XX  
XX  #define ARGVAL() (*++(*argv) || (--argc && *++argv))
XX***************
XX*** 183,190 ****
XX  #else
XX  	count_int *htab;
XX  	unsigned short *codetab;
XX! #	define HTABSIZE ((unsigned)(HSIZE*sizeof(count_int)))
XX! #	define CODETABSIZE ((unsigned)(HSIZE*sizeof(unsigned short)))
XX  
XX  
XX  #define htabof(i)	htab[i]
XX--- 185,192 ----
XX  #else
XX  	count_int *htab;
XX  	unsigned short *codetab;
XX! #	define HTABSIZE ((size_t)(HSIZE*sizeof(count_int)))
XX! #	define CODETABSIZE ((size_t)(HSIZE*sizeof(unsigned short)))
XX  
XX  
XX  #define htabof(i)	htab[i]
XX***************
XX*** 214,220 ****
XX  code_int free_ent = 0;			/* first unused entry */
XX  int exit_stat = 0;
XX  
XX! code_int getcode();
XX  
XX  void Usage() {
XX  #ifdef DEBUG
XX--- 216,237 ----
XX  code_int free_ent = 0;			/* first unused entry */
XX  int exit_stat = 0;
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void Usage, (void));
XX! _PROTOTYPE(void compress, (void));
XX! _PROTOTYPE(void onintr, (int dummy));
XX! _PROTOTYPE(void oops, (int dummy));
XX! _PROTOTYPE(void output, (code_int code));
XX! _PROTOTYPE(int foreground, (void));
XX! _PROTOTYPE(void decompress, (void));
XX! _PROTOTYPE(code_int getcode, (void)); 
XX! _PROTOTYPE(void writeerr, (void));
XX! _PROTOTYPE(void copystat, (char *ifname, char *ofname));
XX! _PROTOTYPE(int foreground, (void));
XX! _PROTOTYPE(void cl_block , (void));
XX! _PROTOTYPE(void cl_hash, (count_int hsize));
XX! _PROTOTYPE(void prratio, (FILE *stream, long int num, long int den));
XX! _PROTOTYPE(void version, (void));
XX  
XX  void Usage() {
XX  #ifdef DEBUG
XX***************
XX*** 257,278 ****
XX  #else
XX  int
XX  #endif
XX  (*bgnd_flag)();
XX  #endif
XX  
XX  int do_decomp = 0;
XX  
XX  
XX! void main( argc, argv )
XX! REGISTER int argc; char **argv;
XX  {
XX      int overwrite = 0;	/* Do not overwrite unless given -f flag */
XX      char tempname[100];
XX      char **filelist, **fileptr;
XX!     char *cp;extern char *strrchr(), *malloc();
XX      struct stat statbuf;
XX  #ifndef METAWARE
XX-     extern void onintr(), oops();
XX      if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) {
XX  	signal ( SIGINT, onintr );
XX  	signal ( SIGSEGV, oops );
XX--- 274,299 ----
XX  #else
XX  int
XX  #endif
XX+ #ifndef __STDC__
XX  (*bgnd_flag)();
XX+ #else
XX+ (*bgnd_flag)(int);
XX  #endif
XX+ #endif
XX  
XX  int do_decomp = 0;
XX  
XX  
XX! int main(argc, argv)
XX! int argc;
XX! char **argv;
XX  {
XX      int overwrite = 0;	/* Do not overwrite unless given -f flag */
XX      char tempname[100];
XX      char **filelist, **fileptr;
XX!     char *cp;
XX      struct stat statbuf;
XX  #ifndef METAWARE
XX      if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) {
XX  	signal ( SIGINT, onintr );
XX  	signal ( SIGSEGV, oops );
XX***************
XX*** 300,306 ****
XX      nomagic = 1;	/* Original didn't have a magic number */
XX  #endif /* COMPATIBLE */
XX  
XX!     filelist = fileptr = (char **)(malloc((unsigned)(argc * sizeof(*argv))));
XX      *filelist = NULL;
XX  
XX      if((cp = strrchr(argv[0], '/')) != 0) {
XX--- 321,327 ----
XX      nomagic = 1;	/* Original didn't have a magic number */
XX  #endif /* COMPATIBLE */
XX  
XX!     filelist = fileptr = (char **)(malloc((size_t)(argc * sizeof(*argv))));
XX      *filelist = NULL;
XX  
XX      if((cp = strrchr(argv[0], '/')) != 0) {
XX***************
XX*** 428,434 ****
XX  #else
XX  					/* either tack one on or replace last character */
XX  					{
XX! 						char *dot;extern char *strchr();
XX  						if (NULL == (dot = strchr(tempname,'.')))
XX  						{
XX  							strcat(tempname,".Z");
XX--- 449,455 ----
XX  #else
XX  					/* either tack one on or replace last character */
XX  					{
XX! 						char *dot;
XX  						if (NULL == (dot = strchr(tempname,'.')))
XX  						{
XX  							strcat(tempname,".Z");
XX***************
XX*** 482,488 ****
XX  #else
XX  				/* kludge to handle various common three character extension */
XX  				{
XX! 					char *dot; extern char *strchr();
XX  					char fixup = '\0';
XX  					/* first off, map name to upper case */
XX  					for (dot = ofname; *dot; dot++)
XX--- 503,509 ----
XX  #else
XX  				/* kludge to handle various common three character extension */
XX  				{
XX! 					char *dot; 
XX  					char fixup = '\0';
XX  					/* first off, map name to upper case */
XX  					for (dot = ofname; *dot; dot++)
XX***************
XX*** 561,567 ****
XX  				else
XX  				{
XX  					/* either tack one on or replace last character */
XX! 					char *dot;extern char *strchr();
XX  					if (NULL == (dot = strchr(cp,'.')))
XX  					{
XX  						strcat(cp,".Z");
XX--- 582,588 ----
XX  				else
XX  				{
XX  					/* either tack one on or replace last character */
XX! 					char *dot;
XX  					if (NULL == (dot = strchr(cp,'.')))
XX  					{
XX  						strcat(cp,".Z");
XX***************
XX*** 690,696 ****
XX  #endif /* DEBUG */
XX  		}
XX      }
XX!     exit(exit_stat);
XX  }
XX  
XX  static int offset;
XX--- 711,717 ----
XX  #endif /* DEBUG */
XX  		}
XX      }
XX!     return(exit_stat);
XX  }
XX  
XX  static int offset;
XX***************
XX*** 913,922 ****
XX  	temp = (code << r_off) & lmask[r_off];
XX  	*bp |= temp;
XX  #else
XX! 	*bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
XX  #endif
XX  #else
XX! 	*bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
XX  #endif
XX  	bp++;
XX  	bits -= (8 - r_off);
XX--- 934,943 ----
XX  	temp = (code << r_off) & lmask[r_off];
XX  	*bp |= temp;
XX  #else
XX! 	*bp = (*bp & rmask[r_off]) | ((code << r_off) & lmask[r_off]);
XX  #endif
XX  #else
XX! 	*bp = (*bp & rmask[r_off]) | ((code << r_off) & lmask[r_off]);
XX  #endif
XX  	bp++;
XX  	bits -= (8 - r_off);
XX***************
XX*** 956,962 ****
XX  	     */
XX  	    if ( offset > 0 ) 
XX  		{
XX! 			if( fwrite( buf, 1, n_bits, stdout ) != n_bits)
XX  				writeerr();
XX  			bytes_out += n_bits;
XX  	    }
XX--- 977,983 ----
XX  	     */
XX  	    if ( offset > 0 ) 
XX  		{
XX! 			if( fwrite( buf, (size_t)1, (size_t)n_bits, stdout ) != n_bits)
XX  				writeerr();
XX  			bytes_out += n_bits;
XX  	    }
XX***************
XX*** 989,995 ****
XX  	 * At EOF, write the rest of the buffer.
XX  	 */
XX  	if ( offset > 0 )
XX! 	    fwrite( buf, 1, (offset + 7) / 8, stdout );
XX  	bytes_out += (offset + 7) / 8;
XX  	offset = 0;
XX  	fflush( stdout );
XX--- 1010,1016 ----
XX  	 * At EOF, write the rest of the buffer.
XX  	 */
XX  	if ( offset > 0 )
XX! 	    fwrite( buf, (size_t)1, (size_t)(offset + 7) / 8, stdout );
XX  	bytes_out += (offset + 7) / 8;
XX  	offset = 0;
XX  	fflush( stdout );
XX***************
XX*** 1132,1138 ****
XX      	    maxcode = MAXCODE (n_bits = INIT_BITS);
XX  		    clear_flg = 0;
XX  		}
XX! 		size = fread( buf, 1, n_bits, stdin );
XX  		if ( size <= 0 )
XX  		    return -1;			/* end of file */
XX  		offset = 0;
XX--- 1153,1159 ----
XX      	    maxcode = MAXCODE (n_bits = INIT_BITS);
XX  		    clear_flg = 0;
XX  		}
XX! 		size = fread( buf, (size_t)1, (size_t)n_bits, stdin );
XX  		if ( size <= 0 )
XX  		    return -1;			/* end of file */
XX  		offset = 0;
XX***************
XX*** 1188,1205 ****
XX  	return(p);
XX  }
XX  #endif
XX- #ifdef _MINIX
XX- char *
XX- strrchr(s, c)		/* For those who don't have it in libc.a */
XX- REGISTER char *s, c;
XX- {
XX- 	char *p;
XX- 	for (p = NULL; *s; s++)
XX- 	    if (*s == c)
XX- 		p = s;
XX- 	return(p);
XX- }
XX- #endif
XX  
XX  
XX  #ifndef METAWARE
XX--- 1209,1214 ----
XX***************
XX*** 1266,1272 ****
XX  						stack_top);
XX  		}
XX  		stack_top = in_stack(ent, stack_top);
XX! 		fwrite( &stack[stack_top], 1, STACK_SIZE-stack_top, stderr);
XX  	   	stack_top = STACK_SIZE;
XX  	}
XX     } else if(!debug) {	/* decompressing */
XX--- 1275,1281 ----
XX  						stack_top);
XX  		}
XX  		stack_top = in_stack(ent, stack_top);
XX! 		fwrite( &stack[stack_top], (size_t)1, (size_t)(STACK_SIZE-stack_top), stderr);
XX  	   	stack_top = STACK_SIZE;
XX  	}
XX     } else if(!debug) {	/* decompressing */
XX***************
XX*** 1286,1292 ****
XX  		   ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
XX  	       stack_top = in_stack(tab_suffixof(ent), stack_top);
XX  	   }
XX! 	   fwrite( &stack[stack_top], 1, STACK_SIZE - stack_top, stderr );
XX  	   stack_top = STACK_SIZE;
XX         }
XX      }
XX--- 1295,1301 ----
XX  		   ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
XX  	       stack_top = in_stack(tab_suffixof(ent), stack_top);
XX  	   }
XX! 	   fwrite( &stack[stack_top], (size_t)1, (size_t)(STACK_SIZE - stack_top), stderr );
XX  	   stack_top = STACK_SIZE;
XX         }
XX      }
XX***************
XX*** 1389,1395 ****
XX  		timep[0] = statbuf.st_mtime;
XX  		timep[1] = statbuf.st_mtime;
XX  #endif
XX! 		utime(ofname, timep);	/* Update last accessed and modified times */
XX  /*
XX  		if (unlink(ifname))
XX  		    perror(ifname);
XX--- 1398,1404 ----
XX  		timep[0] = statbuf.st_mtime;
XX  		timep[1] = statbuf.st_mtime;
XX  #endif
XX! 		utime(ofname, (struct utimbuf *)timep);	/* Update last accessed and modified times */
XX  /*
XX  		if (unlink(ifname))
XX  		    perror(ifname);
XX***************
XX*** 1427,1440 ****
XX  #endif
XX  }
XX  #ifndef METAWARE
XX! void onintr ( )
XX  {
XX  	(void)signal(SIGINT,SIG_IGN);
XX      unlink ( ofname );
XX      exit ( 1 );
XX  }
XX  
XX! void oops ( )	/* wild pointer -- assume bad input */
XX  {
XX  	(void)signal(SIGSEGV,SIG_IGN);
XX      if ( do_decomp == 1 ) 
XX--- 1436,1451 ----
XX  #endif
XX  }
XX  #ifndef METAWARE
XX! void onintr (dummy)
XX! int dummy; /* to keep the compiler happy */
XX  {
XX  	(void)signal(SIGINT,SIG_IGN);
XX      unlink ( ofname );
XX      exit ( 1 );
XX  }
XX  
XX! void oops (dummy)	/* wild pointer -- assume bad input */
XX! int dummy; /* to keep the compiler happy */
XX  {
XX  	(void)signal(SIGSEGV,SIG_IGN);
XX      if ( do_decomp == 1 ) 
XX***************
XX*** 1491,1497 ****
XX  #ifdef AZTEC86
XX  #ifdef PCDOS
XX  	/* This function only in PC-DOS lib, not in MINIX lib */
XX! 	memset(htab,-1,(int)(hsize * sizeof(count_int)));
XX  #else
XX  /* MINIX and all non-PC machines do it this way */	
XX  #ifndef XENIX_16	/* Normal machine */
XX--- 1502,1508 ----
XX  #ifdef AZTEC86
XX  #ifdef PCDOS
XX  	/* This function only in PC-DOS lib, not in MINIX lib */
XX! 	memset(htab,-1, hsize * sizeof(count_int));
XX  #else
XX  /* MINIX and all non-PC machines do it this way */	
XX  #ifndef XENIX_16	/* Normal machine */
XX***************
XX*** 1551,1557 ****
XX  
XX  void prratio(stream, num, den)
XX  FILE *stream;
XX! long int num, den;
XX  {
XX  	REGISTER int q;			/* Doesn't need to be long */
XX  	if(num > 214748L) 
XX--- 1562,1569 ----
XX  
XX  void prratio(stream, num, den)
XX  FILE *stream;
XX! long int num;
XX! long int den;
XX  {
XX  	REGISTER int q;			/* Doesn't need to be long */
XX  	if(num > 214748L) 
X/
Xecho x - cp.c.d
Xsed '/^X/s///' > cp.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/cp.c  crc=27469   3954	Sun Apr 25 21:34:51 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/cp.c  crc=24572  12871	Mon Mar  1 12:39:55 1993
XX***************
XX*** 1,210 ****
XX! /* cp - copy files		Author: Andy Tanenbaum */
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX  #include <fcntl.h>
XX  
XX! #define TRANSFER_UNIT    16384
XX! char cpbuf[TRANSFER_UNIT];
XX! int isfloppy;			/* set to 1 for cp x /dev/fd? */
XX  
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX!   int fd1, fd2, m, s;
XX!   struct stat sbuf, sbuf2;
XX  
XX!   if (argc < 3) usage();
XX! 
XX!   /* Get the status of the last named file.  See if it is a directory. */
XX!   s = stat(argv[argc - 1], &sbuf);
XX!   m = sbuf.st_mode & S_IFMT;
XX!   if (s >= 0 && m == S_IFDIR) {
XX! 	/* Last argument is a directory. */
XX! 	exit(cp_to_dir(argc, argv));
XX!   } else if (argc > 3) {
XX! 	/* More than 2 arguments and last one is not a directory. */
XX! 	usage();
XX!   } else if (s < 0 || m == S_IFREG || m == S_IFCHR || m == S_IFBLK) {
XX! 	/* Exactly two arguments.  Check for cp f1 f1. */
XX! 	if (equal(argv[1], argv[2])) {
XX! 		std_err("cp: cannot copy a file to itself\n");
XX! 		exit(-1);
XX  	}
XX  
XX! 	/* Command is of the form cp f1 f2. */
XX! 	fd1 = open(argv[1], O_RDONLY);
XX! 	if (fd1 < 0) {
XX! 		stderr3("cannot open ", argv[1], "\n");
XX! 		exit(1);
XX  	}
XX! 	fstat(fd1, &sbuf);
XX! 	m = sbuf.st_mode & S_IFMT;
XX! 	if (m == S_IFDIR) {
XX! 		stderr3("<", argv[1], "> directory\n");
XX! 		exit(1);
XX! 	}
XX! 	fd2 = creat(argv[2], sbuf.st_mode & 0777);
XX! 	if (fd2 < 0) {
XX! 		stderr3("cannot create ", argv[2], "\n");
XX! 		exit(2);
XX! 	}
XX! 	fstat(fd2, &sbuf2);
XX! 	if ((sbuf2.st_mode & S_IFMT) == S_IFBLK) isfloppy = 1;
XX! 	copyfile(fd1, fd2, argv[2]);
XX!   } else {
XX! 	stderr3("cannot copy to ", argv[2], "\n");
XX! 	exit(3);
XX!   }
XX!   exit(0);
XX  }
XX  
XX  
XX  
XX  
XX  
XX! cp_to_dir(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, mode, fd1, fd2, exit_status = 0;
XX!   char dirname[256], *ptr, *dp;
XX!   struct stat sbuf;
XX  
XX!   for (i = 1; i < argc - 1; i++) {
XX! 	fd1 = open(argv[i], O_RDONLY);
XX! 	if (fd1 < 0) {
XX! 		stderr3("cannot open ", argv[i], "\n");
XX! 		exit_status = 1;
XX! 		continue;
XX! 	}
XX! 	ptr = argv[argc - 1];
XX! 	dp = dirname;
XX! 	while (*ptr != 0) *dp++ = *ptr++;
XX  
XX- 	*dp++ = '/';
XX- 	ptr = argv[i];
XX  
XX! 	/* Concatenate dir and file name in dirname buffer. */
XX! 	while (*ptr != 0) ptr++;/* go to end of file name */
XX! 	while (ptr > argv[i] && *ptr != '/') ptr--;	/* get last component */
XX! 	if (*ptr == '/') ptr++;
XX! 	while (*ptr != 0) *dp++ = *ptr++;
XX! 	*dp++ = 0;
XX! 	fstat(fd1, &sbuf);
XX! 	mode = sbuf.st_mode & S_IFMT;
XX! 	if (mode == S_IFDIR) {
XX! 		stderr3("<", argv[i], "> directory\n");
XX! 		exit_status = 1;
XX! 		close(fd1);
XX! 		continue;
XX! 	}
XX! 	fd2 = creat(dirname, sbuf.st_mode & 0777);
XX! 	if (fd2 < 0) {
XX! 		stderr3("cannot create ", dirname, "\n");
XX! 		exit_status = 2;
XX! 		close(fd1);
XX! 		continue;
XX! 	}
XX! 	copyfile(fd1, fd2, dirname);
XX    }
XX!   return(exit_status);
XX  }
XX  
XX  
XX  
XX  
XX  
XX! copyfile(fd1, fd2, name)
XX! int fd1, fd2;
XX! char *name;
XX  {
XX!   int n, m, mode;
XX!   struct stat sbuf;
XX  
XX!   do {
XX! 	n = read(fd1, cpbuf, TRANSFER_UNIT);
XX  	if (n < 0) {
XX! 		std_err("cp: read error\n");
XX  		break;
XX  	}
XX! 	if (n > 0) {
XX! 		m = write(fd2, cpbuf, n);
XX! 		if (m != n) {
XX! 			/* Write failed.  Don't keep truncated
XX! 			 * regular file. */
XX! 			perror("cp");
XX! 			fstat(fd2, &sbuf);	/* check for special files */
XX! 			mode = sbuf.st_mode & S_IFMT;
XX! 			if (mode == S_IFREG) unlink(name);
XX! 			exit(1);
XX  		}
XX! 		if (isfloppy) sync();	/* purge the cache all at once */
XX  	}
XX!   } while (n == TRANSFER_UNIT);
XX!   close(fd1);
XX    close(fd2);
XX  }
XX  
XX! usage()
XX  {
XX!   std_err("Usage:  cp f1 f2;  or  cp f1 ... fn d2\n");
XX!   exit(-1);
XX! }
XX  
XX! typedef char *cptr;
XX  
XX! int equal(s1, s2)
XX! char *s1, *s2;
XX! {
XX!   struct stat sb1, sb2;
XX  
XX!   /* Same file, different name? */
XX!   stat(s1, &sb1);
XX!   stat(s2, &sb2);
XX!   if (memcmp((cptr) & sb1, (cptr) & sb2, sizeof(struct stat)) == 0)
XX! 	return(1);
XX!   /* Same file, same name? */
XX!   while (1) {
XX! 	if (*s1 == 0 && *s2 == 0) return(1);
XX! 	if (*s1 != *s2) return (0);
XX! 	if (*s1 == 0 || *s2 == 0) return (0);
XX! 	s1++;
XX! 	s2++;
XX    }
XX- }
XX  
XX! int match(s1, s2, n)
XX! char *s1, *s2;
XX! int n;
XX! {
XX!   while (n--) {
XX! 	if (*s1++ != *s2++) return(0);
XX    }
XX-   return(1);
XX  }
XX  
XX  
XX! stderr3(s1, s2, s3)
XX! char *s1, *s2, *s3;
XX  {
XX!   std_err("cp: ");
XX!   std_err(s1);
XX!   std_err(s2);
XX!   std_err(s3);
XX  }
XX  
XX  
XX! int memcmp(b1, b2, n)
XX! cptr b1, b2;
XX! int n;
XX  {
XX!   while (n--) {
XX! 	if (*b1 != *b2) return((int) (*b1 - *b2));
XX! 	++b1;
XX! 	++b2;
XX!   }
XX!   return(0);
XX  }
XX--- 1,600 ----
XX! /* cp - Copy files					Author: V. Archer */
XX  
XX+ /* Copyright 1991 by Vincent Archer
XX+  *	You may freely redistribute this software, in source or binary
XX+  *	form, provided that you do not alter this copyright mention in any
XX+  *	way.
XX+  */
XX+ 
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX+ #include <minix/minlib.h>
XX  #include <fcntl.h>
XX+ #include <dirent.h>
XX+ #include <errno.h>
XX+ #include <limits.h>
XX+ #include <string.h>
XX+ #include <stdlib.h>
XX+ #include <utime.h>
XX+ #include <blocksize.h>
XX+ #include <unistd.h>
XX+ #include <stdio.h>
XX  
XX! #define ALL_MODES (S_IRWXU|S_IRWXG|S_IRWXO)
XX! #define NONE ((char *)0)
XX  
XX+ /* A link (for cpdir) descriptor. Link are never un-allocated, this allow
XX+  * race conditions (a user creating links while another is busy copying the
XX+  * hierarchy in which they reside, for example), at the price of memory
XX+  * shortage...
XX+  */
XX+ typedef struct _link_ {
XX+   struct _link_ *next;
XX+   dev_t st_dev;
XX+   ino_t st_ino;
XX+   char *path;
XX+ } LINK;
XX  
XX! /* A tree (for cp -Rr/cpdir) descriptor. It is used when a directory cannot
XX!  * be opened due to file descriptor shortage. For cp, it would be safe to
XX!  * block on that condition. For mv (which calls cpdir -p), however, P1003.2
XX!  * requires that the copy should NOT fail! Therefore, for each directory to
XX!  * be opened, another might be closed. When we get back to that directory's
XX!  * level, however, we'll have to reopen it and move to our previous position
XX!  * within this directory.
XX!  */
XX! typedef struct _tree_ {
XX!   struct _tree_ *next;
XX!   DIR *dirp;
XX!   off_t pos;
XX!   struct stat st;
XX! } TREE;
XX! 
XX! int cflag, dflag, fflag, iflag, pflag, rflag, rrflag, vflag;
XX! int errors;
XX! 
XX! /* Common variables. The copy buffer is limited to PIPE_BUF to avoid errors
XX!  * in cp -r (lowercase r) while copying from a pipe.
XX!  */
XX! char *dest;
XX! char dst_path[PATH_MAX + 1], src_path[PATH_MAX + 1];
XX! char buffer[PIPE_BUF];
XX! LINK *links;
XX! TREE *toplevel;
XX! struct stat st2;
XX! uid_t userid;
XX! 
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(int negative, (void));
XX! _PROTOTYPE(char *octal, (Mode_t num));
XX! _PROTOTYPE(void doing, (char *what, char *with, char *on));
XX! _PROTOTYPE(void do_close, (void));
XX! _PROTOTYPE(void similar, (struct stat *sp));
XX! _PROTOTYPE(void do_cpfile, (int new, struct stat *st));
XX! _PROTOTYPE(void do_cpdir, (int new, struct stat *oldmode, TREE *dotdot));
XX! _PROTOTYPE(int do_cp, (char *source));
XX! _PROTOTYPE(void usage, (void));
XX! 
XX! extern int optind, opterr;
XX! 
XX! /* Main module. If cp is invoked as "cpdir", the -R flag is automatically
XX!  * turned on. Furthermore, the 'c' pseudo-flag is set, meaning that links
XX!  * to the same source file should be preserved across the copy. 'c' cancels
XX!  * any '-r' invocation.
XX!  * The '-v' flag is maintained for compatibility with old cpdir.
XX!  */
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX!   char *s;
XX!   int c;
XX!   struct stat st;
XX  
XX!   if ((s = strrchr(*argv, '/')) != NULL)
XX! 	s++;
XX!   else
XX! 	s = *argv;
XX!   if (strcmp(s, "cpdir") == 0) {
XX! 	cflag = 1;
XX! 	rflag = 1;
XX! 	rrflag = 1;
XX!   }
XX!   opterr = 0;
XX!   while ((c = getopt(argc, argv, "Rfimprsv")) != EOF) switch (c) {
XX! 	    case 'f':
XX! 		fflag = 1;
XX! 		iflag = 0;
XX! 		break;
XX! 	    case 'i':
XX! 		iflag = 1;
XX! 		fflag = 0;
XX! 		break;
XX! 	    case 'm':
XX! 		break;
XX! 	    case 's':
XX! 	    case 'p':	pflag = 1;	break;
XX! 	    case 'v':	vflag = 1;	break;
XX! 	    case 'R':	rrflag = 1;
XX! 	    case 'r':	rflag = 1;	break;
XX! 	    default:	usage();
XX  	}
XX+   argc -= optind;
XX+   if (argc < 2) usage();
XX+   if (argc > 2 && cflag) usage();
XX+   argv += optind;
XX+   dest = argv[--argc];
XX+   userid = getuid();
XX  
XX!   if (!cflag)
XX! 	if (stat(dest, &st)) {
XX! 		if (argc > 1) {
XX! 			perror(dest);
XX! 			return(1);
XX! 		}
XX! 	} else if (S_ISDIR(st.st_mode))
XX! 		dflag = 1;
XX! 	else if (argc > 1 || rflag) {
XX! 		errno = ENOTDIR;
XX! 		perror(dest);
XX! 		return(1);
XX  	}
XX!   while (argc--) errors |= do_cp(*argv++);
XX!   return(errors);
XX  }
XX  
XX  
XX+ /* Wait for a user answer from the stdin stream (but do not use stdio which
XX+  * is bulky and unneeded in most tools). An error (or end of file) on file
XX+  * descriptor 0 is assumed to mean a NEGATIVE answer. LC_* locale could be
XX+  * handled here.
XX+  */
XX+ int negative()
XX+ {
XX+   char c, t;
XX  
XX+   if (read(0, &c, 1) != 1) return(1);
XX+   t = c;
XX+   while (t != '\n')
XX+ 	if (read(0, &t, 1) != 1) break;
XX+   return(c != 'y' && c != 'Y');
XX+ }
XX  
XX  
XX! /* Quick transformation of a mode_t in 3-digits octal form. */
XX! char *octal(num)
XX! mode_t num;
XX  {
XX!   static char a[4];
XX  
XX!   a[0] = (((num >> 6) & 7) + '0');
XX!   a[1] = (((num >> 3) & 7) + '0');
XX!   a[2] = ((num & 7) + '0');
XX!   a[3] = 0;
XX!   return(a);
XX! }
XX  
XX  
XX! /* Verbose output of the operation. mknod4 could be better shown than thru
XX!  * this, but I don't care...
XX!  */
XX! void doing(what, with, on)
XX! char *what, *with, *on;
XX! {
XX!   std_err(what);
XX!   std_err(with);
XX!   if (on) {
XX! 	std_err(" ");
XX! 	std_err(on);
XX    }
XX!   std_err("\n");
XX  }
XX  
XX  
XX+ /* Close a previously opened directory stream when file descriptors are
XX+  * needed. The streams are closed in a First-Open-First-Closed (FIFO) order,
XX+  * because high-level directories are less likely to be needed soon than
XX+  * lower-level directories.
XX+  */
XX+ void do_close()
XX+ {
XX+   TREE *sweep;
XX  
XX+   for (sweep = toplevel; sweep; sweep = sweep->next)
XX+ 	if (sweep->dirp) {
XX+ 		closedir(sweep->dirp);
XX+ 		sweep->dirp = (DIR *) 0;
XX+ 		return;
XX+ 	}
XX+   std_err("FATAL:");
XX+   perror("cpdir");
XX+   exit(1);
XX+ }
XX  
XX  
XX! /* This function handles the "-p" option. */
XX! void similar(sp)
XX! struct stat *sp;
XX  {
XX!   struct utimbuf timer;
XX  
XX!   timer.actime = sp->st_atime;
XX!   timer.modtime = sp->st_mtime;
XX!   if (utime(dst_path, &timer)) {
XX! 	perror(dst_path);
XX! 	errors = 1;
XX!   }
XX!   if (chown(dst_path, sp->st_uid, sp->st_gid) || userid != 0)
XX! 	sp->st_mode &= ALL_MODES;
XX!   if (chmod(dst_path, sp->st_mode)) {
XX! 	perror(dst_path);
XX! 	errors = 1;
XX!   }
XX! }
XX! 
XX! 
XX! /* This copy a directory entry (non-directory inode) to a (possibly new)
XX!  * destination. Prompting, linking and mkfifo/mknod4 are done here.
XX!  */
XX! void do_cpfile(new, st)
XX! int new;
XX! struct stat *st;
XX! {
XX!   int fd, fd2, n, m;
XX!   char *bufp;
XX!   long s;
XX!   LINK *linkp;
XX! 
XX!   if (!new) {
XX! 	if (iflag) {
XX! 		std_err(dst_path);
XX! 		std_err(": replace ? ");
XX! 		if (negative()) return;
XX! 	}
XX! 	if (access(dst_path, 2)) {
XX! 		perror(dst_path);
XX! 		errors = 1;
XX! 		return;
XX! 	}
XX!   }
XX!   if (cflag && st->st_nlink > 1) {
XX! 	n = 0;
XX! 	for (linkp = links; linkp; linkp = linkp->next)
XX! 		if (linkp->st_dev == st->st_dev &&
XX! 		    linkp->st_ino == st->st_ino) {
XX! 			if (!new) {
XX! 				if (vflag) doing("unlink ", dst_path, NONE);
XX! 				if (unlink(dst_path)) {
XX! 					perror(dst_path);
XX! 					errors = 1;
XX! 					return;
XX! 				} else
XX! 					new = 1;
XX! 			}
XX! 			if (vflag) doing("link ", linkp->path, dst_path);
XX! 			if (!link(linkp->path, dst_path)) {
XX! 				return;
XX! 			}
XX! 			if (errno != EXDEV) {
XX! 				std_err(src_path);
XX! 				std_err(", ");
XX! 				perror(dst_path);
XX! 			} else if (!n) {
XX! 				std_err(dst_path);
XX! 				std_err(": cross device link snapped\n");
XX! 			}
XX! 			n = 1;	/* display snap once */
XX! 		}
XX! 	if ((linkp = (LINK *) malloc(sizeof(LINK))) == (LINK *) 0)
XX! 		perror(dst_path);
XX! 	else if ((linkp->path = (char *)malloc(strlen(dst_path) + 1)) == NONE){
XX! 		perror(dst_path);
XX! 		free(linkp);
XX! 	} else {
XX! 		strcpy(linkp->path, dst_path);
XX! 		linkp->st_dev = st->st_dev;
XX! 		linkp->st_ino = st->st_ino;
XX! 		linkp->next = links;
XX! 		links = linkp;
XX! 	}
XX!   }
XX!   if (
XX! #ifdef S_IFLNK
XX!       S_ISLNK(st->st_mode) ||
XX! #endif
XX!       rrflag && (S_ISBLK(st->st_mode) ||
XX! 		S_ISCHR(st->st_mode) || S_ISFIFO(st->st_mode))) {
XX! 	if (!new) {
XX! 		if (vflag) doing("unlink ", dst_path, NONE);
XX! 		if (unlink(dst_path)) {
XX! 			perror(dst_path);
XX! 			errors = 1;
XX! 			return;
XX! 		}
XX! 	}
XX! 	if (S_ISFIFO(st->st_mode)) {
XX! 		if (vflag) doing("mkfifo ", dst_path, octal(st->st_mode));
XX! 		if (mkfifo(dst_path, st->st_mode & ALL_MODES)) {
XX! 			perror(dst_path);
XX! 			errors = 1;
XX! 			return;
XX! 		}
XX! 	} else if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
XX! 		if (vflag) doing("mknod4 ", dst_path, octal(st->st_mode));
XX! 		s = (long) st->st_size / BLOCK_SIZE;
XX! 		if (mknod4(dst_path, st->st_mode, st->st_rdev, s)) {
XX! 			perror(dst_path);
XX! 			errors = 1;
XX! 			return;
XX! 		}
XX! 	}
XX! #ifdef S_IFLNK
XX! 	else if (S_ISLNK(st->st_mode)) {
XX! 		static char linkname[PATH_MAX + 1];
XX! 		int len;
XX! 
XX! 		len = readlink(src_path, linkname, sizeof(linkname) - 1);
XX! 		if (len < 0) {
XX! 			perror(src_path);
XX! 			errors = 1;
XX! 			return;
XX! 		}
XX! 		linkname[len] = 0;
XX! 		if (vflag) doing("symlink ", linkname, dst_path);
XX! 		if (symlink(linkname, dst_path)) {
XX! 			perror(dst_path);
XX! 			errors = 1;
XX! 			return;
XX! 		}
XX! 	}
XX! #endif
XX! 	if (pflag) similar(st);
XX! 	return;
XX!   }
XX!   while ((fd = open(src_path, O_RDONLY)) < 0) {
XX! 	if (errno != EMFILE && errno != ENFILE) {
XX! 		perror(src_path);
XX! 		errors = 1;
XX! 		return;
XX! 	}
XX! 	do_close();
XX!   }
XX! 
XX!   if (vflag) doing("cp ", src_path, dst_path);
XX!   if (new) {
XX! 	while ((fd2 = open(dst_path, O_WRONLY | O_CREAT,
XX! 			   st->st_mode & ALL_MODES)) < 0)
XX! 		if (errno == EMFILE || errno == ENFILE)
XX! 			do_close();
XX! 		else
XX! 			break;
XX!   } else {
XX! 	while ((fd2 = open(dst_path, O_WRONLY | O_TRUNC)) < 0)
XX! 		if (errno == EMFILE || errno == ENFILE)
XX! 			do_close();
XX! 		else
XX! 			break;
XX!   }
XX!   if (fd2 < 0) {
XX! 	perror(dst_path);
XX! 	close(fd);
XX! 	errors = 1;
XX! 	return;
XX!   }
XX!   while ((n = read(fd, buffer, sizeof(buffer))) != 0) {
XX  	if (n < 0) {
XX! 		perror(src_path);
XX! 		errors = 1;
XX  		break;
XX  	}
XX! 	bufp = buffer;
XX! 	while (n) {
XX! 		m = write(fd2, bufp, n);
XX! 		if (!m) {
XX! 			m = -1;
XX! 			errno = 0;
XX  		}
XX! 		if (m < 0) {
XX! 			perror(dst_path);
XX! 			errors = 1;
XX! 			n = -1;
XX! 			break;
XX! 		}
XX! 		n -= m;
XX! 		bufp += m;
XX  	}
XX! 	if (n < 0) break;
XX!   }
XX! 
XX!   close(fd);
XX    close(fd2);
XX+   if (new && pflag) similar(st);
XX  }
XX  
XX! 
XX! /* Copying a directory's contents is done here. If necessary, the
XX!  * directory will be created, but protected by 'a=,u=rwx' mode until the
XX!  * entire copy is done (or failed, somehow). The mode is the reverted to
XX!  * the "correct" creation mode at the end of the directory copy.
XX!  */
XX! void do_cpdir(new, oldmode, dotdot)
XX! int new;
XX! struct stat *oldmode;
XX! TREE *dotdot;
XX  {
XX!   TREE d;
XX!   char *src, *dst;
XX!   mode_t oldmask;
XX!   int new2;
XX!   struct dirent *entp;
XX  
XX!   if (vflag) doing("cpdir ", src_path, dst_path);
XX!   if (new) {
XX! 	oldmask = umask(0);
XX! 	if (vflag) doing("mkdir ", dst_path, NONE);
XX! 	if (mkdir(dst_path, S_IRWXU)) {
XX! 		perror(dst_path);
XX! 		umask(oldmask);
XX! 		errors = 1;
XX! 		return;
XX! 	}
XX! 	umask(oldmask);
XX!   }
XX!   while ((d.dirp = opendir(src_path)) == (DIR *) 0)
XX! 	if (errno == EMFILE || errno == ENFILE || errno == ENOMEM)
XX! 		do_close();
XX! 	else {
XX! 		perror(src_path);
XX! 		if (new) {
XX! 			if (pflag)
XX! 				similar(oldmode);
XX! 			else
XX! 				chmod(dst_path, oldmode->st_mode & ALL_MODES & ~oldmask);
XX! 		}
XX! 		errors = 1;
XX! 		return;
XX! 	}
XX  
XX!   src = src_path + strlen(src_path);
XX!   dst = dst_path + strlen(dst_path);
XX!   *src++ = '/';
XX!   *dst++ = '/';
XX  
XX!   if (dotdot)
XX! 	dotdot->next = &d;
XX!   else
XX! 	toplevel = &d;
XX! 
XX!   d.pos = 0;
XX! 
XX!   for (;;) {
XX! 	if (d.dirp == (DIR *) 0) {
XX! 		dst[-1] = '\0';
XX! 		if ((d.dirp = opendir(dst_path)) == (DIR *) 0) {
XX! 			perror(dst_path);
XX! 			errors = 1;
XX! 			break;
XX! 		}
XX! 		dst[0] = '/';
XX! 		seekdir(d.dirp, d.pos);
XX! 		if ((entp = readdir(d.dirp)) && entp->d_off == d.pos)
XX! 			entp = readdir(d.dirp);	/* Already processed! */
XX! 	} else
XX! 		entp = readdir(d.dirp);
XX! 
XX! 	if (entp == (struct dirent *) 0) break;
XX! 
XX! 	if (entp->d_name[0] != '.' ||
XX! 	    (entp->d_name[1] &&
XX! 	     (entp->d_name[1] != '.' || entp->d_name[2]))) {
XX! 		strcpy(src, entp->d_name);
XX! 		strcpy(dst, entp->d_name);
XX! 		if (
XX! #ifdef S_IFLNK
XX! 		    cflag && lstat(src_path, &d.st) ||
XX! 		    !cflag && stat(src_path, &d.st)
XX! #else
XX! 		    stat(src_path, &d.st)
XX! #endif
XX! 		   ) {
XX! 			perror(src);
XX! 			errors = 1;
XX! 			continue;
XX! 		}
XX! 		d.pos = entp->d_off;
XX! 
XX! 		if ((new2 = stat(dst_path, &st2)) != 0) {
XX! 			if (S_ISDIR(d.st.st_mode)) {
XX! 				do_cpdir(new2, &d.st, &d);
XX! 				continue;
XX! 			}
XX! 		} else if (S_ISDIR(d.st.st_mode)) {
XX! 			if (S_ISDIR(st2.st_mode)) {
XX! 				do_cpdir(new2, &d.st, &d);
XX! 				continue;
XX! 			}
XX! 			errno = EISDIR;
XX! 			perror(dst_path);
XX! 			errors = 1;
XX! 			continue;
XX! 		}
XX! 		do_cpfile(new2, &d.st);
XX! 	}
XX    }
XX  
XX!   closedir(d.dirp);
XX!   *--src = '\0';
XX!   *--dst = '\0';
XX!   if (dotdot)
XX! 	dotdot->next = (TREE *) 0;
XX!   else
XX! 	toplevel = (TREE *) 0;
XX! 
XX!   if (new) {
XX! 	if (pflag)
XX! 		similar(oldmode);
XX! 	else
XX! 		chmod(dst_path, oldmode->st_mode & ALL_MODES & ~oldmask);
XX    }
XX  }
XX  
XX  
XX! /* This is called to copy each of the ARGUMENTS (specified in cp) to its
XX!  * destination, either the 2nd argument to cp, or somewhere in the
XX!  * specified directory.
XX!  */
XX! int do_cp(source)
XX! char *source;
XX  {
XX!   struct stat st, st2;
XX!   char *s;
XX!   int newfile;
XX! 
XX!   if (stat(source, &st)) {
XX! 	perror(source);
XX! 	return(1);
XX!   }
XX!   strcpy(dst_path, dest);
XX!   if (dflag) {
XX! 	if ((s = strrchr(source, '/')) != NULL)
XX! 		strcat(dst_path, s);
XX! 	else {
XX! 		strcat(dst_path, "/");
XX! 		strcat(dst_path, source);
XX! 	}
XX!   }
XX!   if (!(newfile = stat(dst_path, &st2)))
XX! 	if (st.st_dev == st2.st_dev && st.st_ino == st2.st_ino) {
XX! 		std_err(source);
XX! 		std_err(",");
XX! 		std_err(dst_path);
XX! 		std_err(": Same file\n");
XX! 		return(1);
XX! 	}
XX!   strcpy(src_path, source);
XX!   if (S_ISDIR(st.st_mode)) {
XX! 	if (!rflag) {
XX! 		errno = EISDIR;
XX! 		perror(source);
XX! 		return(1);
XX! 	}
XX! 	if (!newfile && !S_ISDIR(st2.st_mode)) {
XX! 		errno = ENOTDIR;
XX! 		perror(dst_path);
XX! 		return(1);
XX! 	}
XX! 	do_cpdir(newfile, &st, (TREE *) 0);
XX! 	return(0);
XX!   }
XX!   do_cpfile(newfile, &st);
XX!   return(0);
XX  }
XX  
XX  
XX! /* Posix prototype of the command */
XX! void usage()
XX  {
XX!   std_err(cflag ? "Usage: cpdir [-fipv] source_dir target_dir\n"
XX! 	: "Usage: cp [-R|-r] [-fip] source_file... target\n");
XX!   exit(1);
XX  }
X/
Xecho x - crc.c.d
Xsed '/^X/s///' > crc.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/crc.c  crc=50933   3844	Sun Apr 25 21:34:51 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/crc.c  crc=49286   4016	Wed Nov  4 04:19:08 1992
XX***************
XX*** 1,10 ****
XX  /* Compute checksum			Author: Johan W. Stevenson */
XX  
XX  #include <stdio.h>
XX  
XX  int errs;
XX  
XX! main(argc, argv)
XX  char **argv;
XX  {
XX    char line[256];
XX--- 1,18 ----
XX  /* Compute checksum			Author: Johan W. Stevenson */
XX  
XX+ /* Copyright 1988 by Johan W. Stevenson */
XX+ 
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX  #include <stdio.h>
XX  
XX  int errs;
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void crc, (char *fname));
XX! 
XX! int main(argc, argv)
XX! int argc;
XX  char **argv;
XX  {
XX    char line[256];
XX***************
XX*** 23,29 ****
XX  		argv++;
XX  		argc--;
XX  	} while (argc > 1);
XX!   exit(errs != 0);
XX  }
XX  
XX  /* Crctab calculated by Mark G. Mendel, Network Systems Corporation */
XX--- 31,37 ----
XX  		argv++;
XX  		argc--;
XX  	} while (argc > 1);
XX!   return(errs != 0);
XX  }
XX  
XX  /* Crctab calculated by Mark G. Mendel, Network Systems Corporation */
XX***************
XX*** 75,85 ****
XX  
XX  #define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
XX  
XX! crc(fname)
XX  char *fname;
XX  {
XX    register int c;
XX-   register int i;
XX    register long len = 0;
XX    register unsigned short crc = 0;
XX    register FILE *fp;
XX--- 83,92 ----
XX  
XX  #define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
XX  
XX! void crc(fname)
XX  char *fname;
XX  {
XX    register int c;
XX    register long len = 0;
XX    register unsigned short crc = 0;
XX    register FILE *fp;
X/
Xecho x - cron.c.d
Xsed '/^X/s///' > cron.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/cron.c  crc=12322   7203	Sun Apr 25 21:34:51 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/cron.c  crc=65530   8519	Sun Jan 10 14:26:16 1993
XX***************
XX*** 1,183 ****
XX! /* Cron - clock daemon			Author: S.R. Sampson */
XX  
XX! /*	Cron is the clock daemon.  It is typically started up from the
XX!  *	/etc/rc file by the line:
XX!  *		/usr/bin/cron
XX!  *	Cron automatically puts itself in the background, so no & is needed.
XX!  *	If cron is used, it runs all day, spending most of its time asleep.
XX!  *	Once a minute it wakes up and examines /usr/lib/crontab to see if there
XX!  *	are any commands to be executed.  The format of this table is the same
XX!  *	as in UNIX, except that % is not allowed to indicate 'new line.'
XX   *
XX!  *	Each crontab entry has six fields:
XX!  *	   minute    hour  day-of-the-month  month  day-of-the-week  command
XX!  *	Each entry is checked in turn, and any entry matching the current time
XX!  *	is executed.  The entry * matches anything.  Some examples:
XX   *
XX!  *   min hr dat mo day   command
XX!  *    *  *   *  *   *    /usr/bin/date >/dev/tty0   #print date every minute
XX!  *    0  *   *  *   *    /usr/bin/date >/dev/tty0   #print date on the hour
XX!  *   30  4   *  *  1-5   /bin/backup /dev/fd1       #do backup Mon-Fri at 0430
XX!  *   30 19   *  *  1,3,5 /etc/backup /dev/fd1       #Mon, Wed, Fri at 1930
XX!  *    0  9  25 12   *    /usr/bin/sing >/dev/tty0   #Xmas morning at 0900 only
XX   *
XX!  * Version 1.6  SrT  90/04/08
XX!  *      Added casting fixes by Ralf Wenk, and integrated net
XX!  *      changes that release current directory, and use the
XX!  *      1.5.5 include files.  Altered assign, so no temporary
XX!  *	buffer is needed.
XX   *
XX!  * Version 1.5  SrT  89/04/10
XX!  *	Changed sleep code, to type SRS sent me.
XX   *
XX!  * Version 1.4  SrT  89/03/17
XX!  *	Fixed a pointer problem, when reloading crontab.
XX   *
XX!  * Version 1.3  SrT  89/03/16
XX!  *	Loads crontab, into memory and only rereads the disk
XX!  *	version if it changes.  (Free up those clock cycles!)
XX   *
XX!  * Fixed 03/10/89, by Simmule Turner, simmy@nu.cs.fsu.edu
XX!  *	Now correctly cleans up zombie processes
XX!  *	Logs actions to /usr/adm/cronlog
XX!  *	Syncs with clock after each minute
XX!  *	Comments allowed in crontab
XX!  *	Fixed bug that prevented month, from matching
XX! */
XX! 
XX! 
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX  #include <signal.h>
XX! #include <time.h>
XX  #include <string.h>
XX! #include <fcntl.h>
XX  #include <stdio.h>
XX  
XX! #ifndef DEBUG
XX! #define CRONTAB "/usr/lib/crontab"
XX! #define LOGFILE "/usr/adm/cronlog"
XX! #else
XX! #define LOGFILE "/usr/adm/cronlog.dbg"
XX! #define CRONTAB "/usr/adm/crontab.dbg"
XX! #endif
XX  
XX! #define NULLDEV "/dev/null"
XX! #define SEPARATOR " \t"
XX! #define CRONSIZE  2048
XX! #define CRONSTRUCT struct cron_entry
XX  
XX! #define	TRUE	1
XX! #define	FALSE	0
XX  
XX- struct cron_entry {
XX-   char *mn;
XX-   char *hr;
XX-   char *day;
XX-   char *mon;
XX-   char *wkd;
XX-   char *cmd;
XX-   struct cron_entry *next;
XX- } *head, *entry_ptr;
XX  
XX! char crontab[CRONSIZE];
XX! FILE *cronlog;
XX  
XX- int wakeup(), ret();
XX  
XX! time_t previous_time = 0L;
XX  
XX! main()
XX  {
XX!   int status;
XX!   time_t clock;
XX  
XX!   status = fork();
XX!   if (status == -1) {
XX! 	fprintf(stderr, "Can't fork cron\n");
XX! 	exit(1);
XX    }
XX  
XX-   if (status > 0) exit(0);
XX  
XX!   signal(SIGINT, SIG_IGN);
XX!   signal(SIGHUP, SIG_IGN);
XX!   signal(SIGQUIT, SIG_IGN);
XX  
XX-   close(0);
XX-   close(1);
XX-   close(2);
XX  
XX!   chdir("/");
XX  
XX!   open(NULLDEV, O_RDONLY);
XX!   if ((cronlog = fopen(LOGFILE, "a")) == (FILE *) NULL) {
XX! 	open(NULLDEV, O_WRONLY);
XX! 	open(NULLDEV, O_WRONLY);
XX!   } else {
XX! 	setbuf(cronlog, (char *) NULL);
XX! 	dup(fileno(cronlog));
XX    }
XX  
XX!   entry_ptr = (CRONSTRUCT *) malloc(sizeof(CRONSTRUCT));
XX!   entry_ptr->next = (CRONSTRUCT *) NULL;
XX!   head = entry_ptr;
XX  
XX!   while (TRUE) {
XX! 	signal(SIGALRM, wakeup);
XX! 	time(&clock);
XX! 	alarm((unsigned) (60 - clock % 60));
XX! 	pause();
XX! 
XX! 	signal(SIGALRM, ret);
XX! 	alarm(1);
XX! 	while (wait((int *) NULL) != (-1));
XX    }
XX! }
XX  
XX! int ret() {}
XX  
XX! wakeup()
XX! {
XX!   register struct tm *tm;
XX!   time_t cur_time;
XX!   CRONSTRUCT *this_entry = head;
XX  
XX!   load_crontab();
XX! 
XX!   time(&cur_time);
XX!   tm = localtime(&cur_time);
XX! 
XX!   while (this_entry->next && this_entry->mn) {
XX! 	if (match(this_entry->mn, tm->tm_min) &&
XX! 	    match(this_entry->hr, tm->tm_hour) &&
XX! 	    match(this_entry->day, tm->tm_mday) &&
XX! 	    match(this_entry->mon, tm->tm_mon + 1) &&
XX! 	    match(this_entry->wkd, tm->tm_wday)) {
XX! 		fprintf(cronlog, "%02d/%02d-%02d:%02d  %s\n",
XX! 			tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
XX! 			tm->tm_min, this_entry->cmd);
XX! 		if (fork() == 0) {
XX! 			execl("/bin/sh", "/bin/sh", "-c",
XX! 	                      this_entry->cmd, (char *) 0);
XX! 			exit(1);
XX! 		}
XX  	}
XX! 	this_entry = this_entry->next;
XX    }
XX  }
XX  
XX  /*
XX!  *	This routine will match the left string with the right number.
XX   *
XX!  *	The string can contain the following syntax *
XX!  *	*		This will return TRUE for any number
XX!  *	x,y [,z, ...]	This will return TRUE for any number given.
XX!  *	x-y		This will return TRUE for any number within
XX   *			the range of x thru y.
XX   */
XX! 
XX! match(left, right)
XX  register char *left;
XX  register int right;
XX  {
XX--- 1,182 ----
XX! /* Cron - clock daemon.			Author: S.R. Sampson */
XX  
XX! /*
XX!  * cron		clock daemon.
XX!  *		Cron is the clock daemon.  It is typically started up from
XX!  *		the system initialization file (/etc/rc or /etc/inittab) by
XX!  *		the INIT program.
XX   *
XX!  *		If started by hand it must be done by the superuser.
XX   *
XX!  *		Since it is a true daemon, cron automatically puts itself in
XX!  *		the background, to release its control terminal.  If cron is
XX!  *		used, it runs all day, spending most of its time asleep.
XX!  *		Once a minute it wakes up and forks off a child which then
XX!  *		examines /usr/lib/crontab to see if there are any commands to
XX!  *		be executed. The format of this table is the same as in UNIX,
XX!  *		except that % is not allowed to indicate 'new line'.
XX   *
XX!  * Usage:	/usr/bin/cron
XX   *
XX!  * Datafile:	/usr/lib/crontab
XX!  *		Each crontab entry has six fields:
XX   *
XX!  *		 minute hour day-of-month month day-of-week command
XX   *
XX!  *		Each entry is checked in turn, and any entry matching the
XX!  *		current time is executed.  The entry * matches anything.
XX   *
XX!  * Version:	1.9	03/02/91
XX!  *
XX!  * Authors:	Steven R. Sampson, Fred van Kempen, Simmule Turner,
XX!  *		Peter de Vrijer
XX!  */
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX+ #include <fcntl.h>
XX+ #include <limits.h>
XX  #include <signal.h>
XX! #include <stdarg.h>
XX! #include <stdlib.h>
XX  #include <string.h>
XX! #include <time.h>
XX! #include <unistd.h>
XX! #include <sys/wait.h>
XX  #include <stdio.h>
XX  
XX! #define CRONTAB		"/usr/lib/crontab"
XX! #define LOGFILE		"/usr/adm/cronlog"
XX  
XX! #define SEPARATOR	" \t"
XX! #define CRONSIZE	2048
XX  
XX! typedef struct cron_entry {
XX!   struct cron_entry	*next;
XX!   char			*mn;
XX!   char			*hr;
XX!   char			*day;
XX!   char			*mon;
XX!   char			*wkd;
XX!   char			*cmd;
XX! } CRON;
XX  
XX  
XX! static char *Version = "@(#) cron 1.9 (03/02/91)";
XX  
XX  
XX! static char crontab[CRONSIZE];		/* memory for the entries	*/
XX! static CRON *head, *entry_ptr;		/* crontab entry pointers	*/
XX! static time_t prv_time = (time_t) 0;	/* timekeeper: previous wakeup	*/
XX! static FILE *log, *logf;		/* FILE pointer to logfile	*/
XX  
XX! _PROTOTYPE(int main, (int argc, char **argv));
XX! _PROTOTYPE(void log_error, (char *error, ...));
XX! _PROTOTYPE(void assign, (CRON *entry, char *line));
XX! _PROTOTYPE(void load_crontab, (void));
XX! _PROTOTYPE(int match, (char *left, int right));
XX! _PROTOTYPE(void wakeup, (void));
XX! 
XX! /* Write a record to the log file. */
XX! #ifdef __STDC__
XX! void log_error(char *error, ...)
XX  {
XX!   va_list args;
XX  
XX!   va_start (args, error);
XX!   if ((logf = fopen(LOGFILE, "a")) != NULL) {
XX! 	vfprintf(logf, error, args);
XX! 	fclose(logf);
XX    }
XX+   va_end(args);
XX+ }
XX+ #else
XX+ /* the K&R lib does not have vfprintf */
XX+ void log_error(error)
XX+ char *error;
XX+ {
XX+   if ((logf = fopen(LOGFILE, "a")) != NULL) {
XX+ 	fprintf(logf, error);
XX+ 	fclose(logf);
XX+   }
XX+ }
XX+ #endif
XX  
XX  
XX! /* Assign the field values to the current crontab entry in core. */
XX! void assign(entry, line)
XX! CRON *entry;
XX! char *line;
XX! {
XX!   entry->mn	= strtok(line, SEPARATOR);
XX!   entry->hr	= strtok( (char *)NULL, SEPARATOR);
XX!   entry->day	= strtok( (char *)NULL, SEPARATOR);
XX!   entry->mon	= strtok( (char *)NULL, SEPARATOR);
XX!   entry->wkd	= strtok( (char *)NULL, SEPARATOR);
XX!   entry->cmd	= strchr(entry->wkd, '\0') + 1;
XX! }
XX  
XX  
XX! /* Read the on-disk crontab file into core. */
XX! void load_crontab()
XX! {
XX!   int len, pos;
XX!   FILE *cfp;
XX!   struct stat buf;
XX  
XX!   if (stat(CRONTAB, &buf)) {
XX! 	if (prv_time == (time_t) 0) fprintf(log, "Can't stat crontab\n");
XX! 	prv_time = (time_t) 0;
XX! 	return;
XX    }
XX  
XX!   if (buf.st_mtime <= prv_time) return;
XX  
XX!   if ((cfp = fopen(CRONTAB, "r")) == NULL) {
XX! 	if (prv_time == (time_t) 0) fprintf(log, "Can't open crontab\n");
XX! 	prv_time = (time_t) 0;
XX! 	return;
XX    }
XX!   prv_time = buf.st_mtime;
XX!   len = pos = 0;
XX!   entry_ptr = head;
XX  
XX!   while (fgets(&crontab[pos], CRONSIZE - pos, cfp) != NULL) {
XX! 	if (crontab[pos] == '#' || crontab[pos] == '\n') continue;
XX! 	len = strlen(&crontab[pos]);
XX! 	if (crontab[pos + len - 1] == '\n') {
XX! 		len--;
XX! 		crontab[pos + len] = '\0';
XX! 	}
XX  
XX! 	assign(entry_ptr, &crontab[pos]);
XX  
XX! 	if (entry_ptr->next == NULL) {
XX! 		entry_ptr->next = (CRON *)malloc(sizeof(CRON));
XX! 		entry_ptr->next->next = NULL;
XX  	}
XX! 	entry_ptr = entry_ptr->next;
XX! 	pos += ++len;
XX! 	if (pos >= CRONSIZE) break;
XX    }
XX+   (void) fclose(cfp);
XX+ 
XX+   while (entry_ptr) {
XX+ 	entry_ptr->mn = NULL;
XX+ 	entry_ptr = entry_ptr->next;
XX+   }
XX  }
XX  
XX+ 
XX  /*
XX!  * This routine will match the left string with the right number.
XX   *
XX!  * The string can contain the following syntax *
XX!  *	*		This will return 1 for any number
XX!  *	x,y [,z, ...]	This will return 1 for any number given.
XX!  *	x-y		This will return 1 for any number within
XX   *			the range of x thru y.
XX   */
XX! int match(left, right)
XX  register char *left;
XX  register int right;
XX  {
XX***************
XX*** 185,305 ****
XX    register char c;
XX  
XX    n = 0;
XX!   if (!strcmp(left, "*")) return(TRUE);
XX  
XX    while ((c = *left++) && (c >= '0') && (c <= '9')) n = (n * 10) + c - '0';
XX  
XX    switch (c) {
XX!       case '\0':
XX! 	return(right == n);
XX  
XX!       case ',':
XX! 	if (right == n) return(TRUE);
XX! 	do {
XX  		n = 0;
XX  		while ((c = *left++) && (c >= '0') && (c <= '9'))
XX  			n = (n * 10) + c - '0';
XX  
XX- 		if (right == n) return(TRUE);
XX- 	} while (c == ',');
XX- 	return(FALSE);
XX  
XX!       case '-':
XX! 	if (right < n) return(FALSE);
XX  
XX! 	n = 0;
XX! 	while ((c = *left++) && (c >= '0') && (c <= '9'))
XX! 		n = (n * 10) + c - '0';
XX  
XX! 	return(right <= n);
XX    }
XX  }
XX  
XX! load_crontab()
XX  {
XX!   int pos = 0;
XX!   FILE *cfp;
XX!   struct stat buf;
XX  
XX!   if (stat(CRONTAB, &buf)) {
XX! 	if (previous_time == 0L) printf("Can't stat crontab\n");
XX! 	previous_time = 0L;
XX! 	return;
XX!   }
XX! #ifdef DEBUG
XX!   printf("Crontab Time:%ld In_Core:%ld\n", buf.st_mtime, previous_time);
XX! #endif
XX  
XX!   if (buf.st_mtime <= previous_time) return;
XX  
XX!   if ((cfp = fopen(CRONTAB, "r")) == (FILE *) NULL) {
XX! 	if (previous_time == 0L) printf("Can't open crontab\n");
XX! 	previous_time = 0L;
XX! 	return;
XX!   }
XX!   previous_time = buf.st_mtime;
XX  
XX!   entry_ptr = head;
XX!   while (fgets(&crontab[pos], CRONSIZE - pos, cfp) != (char *) NULL) {
XX! 	int len;
XX  
XX! 	if (crontab[pos] == '#') continue;
XX! 	len = strlen(&crontab[pos]);
XX! 	if (crontab[pos + len - 1] == '\n') {
XX! 		len--;
XX! 		crontab[pos + len] = '\0';
XX! 	}
XX! 	assign(entry_ptr, &crontab[pos]);
XX! 	if (entry_ptr->next == (CRONSTRUCT *) NULL) {
XX! 		entry_ptr->next = (CRONSTRUCT *) malloc(sizeof(CRONSTRUCT));
XX! 		entry_ptr->next->next = (CRONSTRUCT *) NULL;
XX! 	}
XX! 	entry_ptr = entry_ptr->next;
XX! 	pos += ++len;
XX! 	if (pos >= CRONSIZE) break;
XX    }
XX-   fclose(cfp);
XX  
XX!   while (entry_ptr) {
XX! 	entry_ptr->mn = (char *) NULL;
XX! 	entry_ptr = entry_ptr->next;
XX!   }
XX  
XX! #ifdef DEBUG
XX!   printf("Crontab uses %d/%d bytes\n", pos, CRONSIZE);
XX!   {
XX! 	CRONSTRUCT *start = head;
XX! 	dumptable(start);
XX!   }
XX! #endif
XX! }
XX  
XX! assign(entry, line)
XX! CRONSTRUCT *entry;
XX! char *line;
XX! {
XX!   entry->mn = strtok(line, SEPARATOR);
XX!   entry->hr = strtok((char *) NULL, SEPARATOR);
XX!   entry->day = strtok((char *) NULL, SEPARATOR);
XX!   entry->mon = strtok((char *) NULL, SEPARATOR);
XX!   entry->wkd = strtok((char *) NULL, SEPARATOR);
XX!   entry->cmd = strchr(entry->wkd,'\0') + 1;
XX! }
XX  
XX! #ifdef DEBUG
XX! dumptable(table)
XX! CRONSTRUCT *table;
XX! {
XX!   time_t clock;
XX!   time(&clock);
XX  
XX!   printf("\nContents of crontab at: %s", ctime(&clock));
XX!   printf("Minute\tHour\tDay\tMonth\tWeekday\tCommand\n");
XX!   while (table->next && table->mn) {
XX! 	printf("%s\t%s\t%s\t%s\t%s\t%s\n",
XX! 	       table->mn, table->hr, table->day, table->mon,
XX! 	       table->wkd, table->cmd);
XX! 	table = table->next;
XX    }
XX  }
XX- #endif
XX--- 184,356 ----
XX    register char c;
XX  
XX    n = 0;
XX!   if (!strcmp(left, "*")) return(1);
XX  
XX    while ((c = *left++) && (c >= '0') && (c <= '9')) n = (n * 10) + c - '0';
XX  
XX    switch (c) {
XX! 	case '\0':
XX! 		return(right == n);
XX! 		/*NOTREACHED*/
XX! 		break;
XX! 	case ',':
XX! 		if (right == n) return(1);
XX! 		do {
XX! 			n = 0;
XX! 			while ((c = *left++) && (c >= '0') && (c <= '9'))
XX! 				n = (n * 10) + c - '0';
XX  
XX! 			if (right == n) return(1);
XX! 		} while (c == ',');
XX! 		return(0);
XX! 		/*NOTREACHED*/
XX! 		break;
XX! 	case '-':
XX! 		if (right < n) return(0);
XX  		n = 0;
XX  		while ((c = *left++) && (c >= '0') && (c <= '9'))
XX  			n = (n * 10) + c - '0';
XX+ 		return(right <= n);
XX+ 		/*NOTREACHED*/
XX+ 		break;
XX+ 	default:
XX+ 		break;
XX+   }
XX+   return(0);
XX+ }
XX  
XX  
XX! /* Wakeup from the sleep(), and check for any work. */
XX! void wakeup()
XX! {
XX!   register struct tm *tm;
XX!   time_t cur_time;
XX!   CRON *this_entry;
XX!   int st, pid;
XX  
XX!   this_entry = head;
XX!   load_crontab();
XX  
XX!   time(&cur_time);
XX!   tm = localtime(&cur_time);
XX! 
XX!   while (this_entry->next && this_entry->mn) {
XX! 	if (match(this_entry->mn, tm->tm_min) &&
XX! 	    match(this_entry->hr, tm->tm_hour) &&
XX! 	    match(this_entry->day, tm->tm_mday) &&
XX! 	    match(this_entry->mon, tm->tm_mon + 1) &&
XX! 	    match(this_entry->wkd, tm->tm_wday)) {
XX! 		fprintf(log, "%02d/%02d-%02d:%02d  %s\n",
XX! 			tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
XX! 							this_entry->cmd);
XX! 		if ((pid = fork()) == 0) {
XX! 			st = execl("/bin/sh", "/bin/sh", "-c",
XX! 						this_entry->cmd, (char *)NULL);
XX! 			log_error("EXEC failed with status = %d\n", st);
XX! 		} else {
XX! 			if (pid < 0)
XX! 				log_error("cron grandchild: Fork failed!\n\n");
XX! 		}
XX! 	}
XX! 	this_entry = this_entry->next;
XX    }
XX  }
XX  
XX! 
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   register struct tm *tm;
XX!   int status, i, pid;
XX!   time_t clk;
XX  
XX!   (void) chdir("/usr/adm");
XX  
XX!   if ((status = fork()) < 0) {
XX! 	fprintf(stderr, "cron: cannot fork!\n");
XX! 	exit(1);
XX!   } else if (status > 0) exit(0);
XX  
XX!   /* We are now the child. Ignore ALL signals. */
XX!   for (i = 1; i <= _NSIG; i++) signal(i, SIG_IGN);
XX  
XX!   /* Attempt to free all open file descriptors (we mostly don't have any
XX!    * files open, and reopen CRONTAB and LOGFILE as necessary).
XX!    */
XX!   for (i = 0; i < OPEN_MAX; i++) close(i);
XX  
XX!   /* Create a logfile, appending to the previous one. */
XX!   if ((log = fopen(LOGFILE, "a")) != NULL) {
XX! 	time(&clk);
XX! 	tm = localtime(&clk);  
XX! 	fprintf(log, "cron started at: %02d/%02d-%02d:%02d\n",
XX!  		tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
XX! 	fclose(log);
XX    }
XX  
XX!   entry_ptr = (CRON *)malloc(sizeof(CRON));
XX!   entry_ptr->next = NULL;
XX!   head = entry_ptr;
XX  
XX!   /* The endless loop. */
XX!   while (1) {
XX! 	/* Sleep till the next full minute */
XX! 	(void) time(&clk);
XX! 	sleep((unsigned) (60 - clk % 60));
XX  
XX! 	/*
XX! 	 * Now fork twice. The grandchild will run wakeup() .
XX! 	 * In that way cron will never have to wait longer than 
XX! 	 * a few seconds
XX! 	 */
XX! 	if ((pid = fork()) == 0) {
XX! 		/*
XX! 		 * This is the child, lets set the process group and
XX! 		 * fork again.  This is the way it should be done in
XX! 		 * a true daemon.
XX! 		 */
XX! 		/* setpgrp();*/ /* make this line a comment if not available */
XX  
XX! 		if ((pid = fork()) == 0) {
XX! 			/*
XX! 			 * This is the grandchild, it has to do all the
XX! 			 * work.  Set up standard file descriptors.  No
XX! 			 * files are open at this point, so their numbers
XX! 			 * will be 0, 1 and 2 as required.  Open the logfile
XX! 			 * if present, otherwise create it.
XX! 			 */
XX! 			(void) open("/dev/null", O_RDWR);
XX! 			if ((log = fopen(LOGFILE, "a")) != NULL) {
XX! 				setbuf(log, (char *)NULL);
XX! 				(void) dup(fileno(log));
XX! 			} else {
XX! 				(void) dup(0);
XX! 				(void) dup(0);
XX! 			}
XX  
XX! 			wakeup();
XX! 
XX! 			/* The grandchild has to do an exit() also. */
XX! 			exit(0);
XX! 		} else {
XX! 			/*
XX! 			 * Here we are still the child, check if everything
XX! 			 * is ok. In any case we do an exit.
XX! 			 */
XX! 			if (pid < 0) {
XX! 			    log_error("cron: fork of grandchild failed\n");
XX! 			}
XX! 			exit(0);
XX! 		}
XX! 	} else {
XX! 		/* This is the parent. */
XX! 		if (pid < 0) {
XX! 			log_error("cron: fork of child failed.\n");
XX! 		} else {
XX! 			/* Wait for the child to change process group. */
XX! 			while (wait( (int *)NULL ) != pid);
XX! 		}
XX! 	}
XX    }
XX  }
X/
Xecho x - cut.c.d
Xsed '/^X/s///' > cut.c.d << '/'
XX*** /home/top/ast/minix/1.5/commands/simple/cut.c  crc=06673   4125	Sun Apr 25 21:34:52 1993
XX--- /home/top/ast/minix/1.6.25/commands/simple/cut.c  crc=63369   7671	Wed Nov  4 04:19:08 1992
XX***************
XX*** 11,59 ****
XX   *          JANET sq79@uk.ac.liv
XX   *          ARPA  sq79%liv.ac.uk@nsfnet-relay.ac.uk
XX   *          U
