echo x - Makefile.ansi
sed '/^X/s///' > Makefile.ansi << '/'
XCC=exec cc
XDIR=/usr/src
XCFLAGS= -c -O -D_MINIX -D_POSIX_SOURCE -I$(DIR)
X
X
Xall:	
X	@$(CC) $(CFLAGS) *.c
X
Xclean:	
X	@rm -rf *.o *.s *.bak
X
/
echo x - Makefile.kr
sed '/^X/s///' > Makefile.kr << '/'
XCC=exec cc
XDIR=/usr/src
XCFLAGS= -c -O -LIB -D_MINIX -D_POSIX_SOURCE -D_EM_PSIZE=2 -I$(DIR)
X
X# Other files have problems.  Use 1.5 versions
XSRC=_longjerr.c bcmp.c bcopy.c bzero.c closedir.c crypt.c ctermid.c \
X    cuserid.c environ.c errno.c execlp.c ffs.c fprintk.c \
X    fputk.c fslib.c fsversion.c getdents.c getgrent.c getgroups.c \
X    getlogin.c getopt.c getpass.c getpw.c getpwent.c getw.c hypot.c \
X    index.c itoa.c loadname.c lock.c lrand.c lsearch.c memccpy.c \
X    mktemp.c mtab.c nlist.c opendir.c popen.c printk.c putenv.c putk.c \
X    putw.c readdir.c regexp.c regsub.c rewinddir.c rindex.c seekdir.c \
X    stderr.c swab.c syscall.c sysconf.c syslib.c taskcall.c telldir.c \
X    termcap.c ttyname.c
X 
X 
Xall:	 
X	@$(CC) $(CFLAGS) $(SRC) 
X 
Xclean:	 
X	@rm -rf *.o *.s *.bak 
X 
/
echo x - _longjerr.c
sed '/^X/s///' > _longjerr.c << '/'
X#include <lib.h>
X#define longjerr	_longjerr
X#define write		_write
X#include <minix/minlib.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X
X
X_PROTOTYPE( void longjerr, (void));
X
XPUBLIC void longjerr()
X{
X  static char errmsg[] = "longj error\n";
X
X  write(2, errmsg, strlen(errmsg));	/* hope it's stderr */
X  while(1) abort();		/* XXX - maybe just exit */
X}
/
echo x - bcmp.c
sed '/^X/s///' > bcmp.c << '/'
X#include <lib.h>
X/* bcmp - Berklix equivalent of memcmp  */
X
X#include <string.h>
X
Xint bcmp(s1, s2, length)	/* == 0 or != 0 for equality and inequality */ 
X_CONST char *s1;
X_CONST char *s2;
Xint length;
X{
X  return(memcmp((_CONST _VOIDSTAR) s1, (_CONST _VOIDSTAR) s2, (_SIZET) length));
X}
/
echo x - bcopy.c
sed '/^X/s///' > bcopy.c << '/'
X#include <lib.h>
X/* bcopy - Berklix equivalent of memcpy  */
X
X#include <string.h>
X
Xvoid bcopy(src, dst, length)
X_CONST char *src;
Xchar *dst;
Xint length;
X{
X  (void) memcpy((_VOIDSTAR) dst, (_CONST _VOIDSTAR) src, (_SIZET) length);
X}
/
echo x - bzero.c
sed '/^X/s///' > bzero.c << '/'
X#include <lib.h>
X/* bzero - Berklix subset of memset  */
X
X#include <string.h>
X
Xvoid bzero(dst, length)
Xchar *dst;
Xint length;
X{
X  (void) memset((_VOIDSTAR) dst, 0, (_SIZET) length);
X}
/
echo x - closedir.c
sed '/^X/s///' > closedir.c << '/'
X/* closedir -- close a directory stream		Author: D.A. Gwyn */
X
X/*	last edit:	11-Nov-1988	D A Gwyn	*/
X
X#include <stddef.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <limits.h>
X#include <dirent.h>
X#include <stdlib.h>
X#include <unistd.h>
X
Xtypedef char *pointer;		/* (void *) if you have it */
X
X#define DULL (DIR *) NULL
X#define CULL (char *) NULL
X
Xint closedir(dirp)
Xregister DIR *dirp;		/* stream from opendir() */
X{
X  register int fd;
X
X  if (dirp == DULL || dirp->dd_buf == CULL || dirp->dd_magic != _DIR_MAGIC) {
X	errno = EBADF;
X	return(-1);		/* invalid pointer */
X  }
X  fd = dirp->dd_fd;		/* bug fix thanks to R. Salz */
X  dirp->dd_magic = 0;		/* invalidate the entry */
X  free((pointer) dirp->dd_buf);
X  free((pointer) dirp);
X  return(close(fd));
X}
/
echo x - crypt.c
sed '/^X/s///' > crypt.c << '/'
X#include <lib.h>
X_PROTOTYPE( char *crypt, (char *pw, char *salt));
X
Xchar *crypt(pw, salt)
Xchar *pw, *salt;
X{
X  PRIVATE char buf[14];
X  char bits[67];
X  register int i;
X  register int j, rot;
X
X  for (i = 0; i < 67; i++) bits[i] = 0;
X  if (salt[1] == 0) salt[1] = salt[0];
X  rot = (salt[1] * 4 - salt[0]) % 128;
X  for (i = 0; *pw && i < 8; i++) {
X	for (j = 0; j < 7; j++) bits[i + j * 8] = (*pw & (1 << j) ? 1 : 0);
X	bits[i + 56] = (salt[i / 4] & (1 << (i % 4)) ? 1 : 0);
X	pw++;
X  }
X  bits[64] = (salt[0] & 1 ? 1 : 0);
X  bits[65] = (salt[1] & 1 ? 1 : 0);
X  bits[66] = (rot & 1 ? 1 : 0);
X  while (rot--) {
X	for (i = 65; i >= 0; i--) bits[i + 1] = bits[i];
X	bits[0] = bits[66];
X  }
X  for (i = 0; i < 12; i++) {
X	buf[i + 2] = 0;
X	for (j = 0; j < 6; j++)
X		buf[i + 2] |= (bits[i * 6 + j] ? (1 << j) : 0);
X	buf[i + 2] += 48;
X	if (buf[i + 2] > '9') buf[i + 2] += 7;
X	if (buf[i + 2] > 'Z') buf[i + 2] += 6;
X  }
X  buf[0] = salt[0];
X  buf[1] = salt[1];
X  buf[13] = '\0';
X  return(buf);
X}
/
echo x - ctermid.c
sed '/^X/s///' > ctermid.c << '/'
X/*  ctermid(3)
X *
X *  Author: Terrence Holm          Aug. 1988
X *
X *
X *  Ctermid(3) returns a pointer to a string naming the controlling
X *  terminal. If <name_space> is NULL then local PRIVATE storage
X *  is used, otherwise <name_space> must point to storage of at
X *  least L_ctermid characters.
X *
X *  Returns a pointer to "/dev/tty".
X */
X
X#include <lib.h>
X#include <string.h>
X#include <stdio.h>
X
X_PROTOTYPE( char *ctermid, (char *name_space));
X
X#ifndef L_ctermid
X#define L_ctermid  9
X#endif
X
Xchar *ctermid(name_space)
Xchar *name_space;
X{
X  PRIVATE char termid[L_ctermid];
X
X  if (name_space == (char *)NULL) name_space = termid;
X  strcpy(name_space, "/dev/tty");
X  return(name_space);
X}
/
echo x - cuserid.c
sed '/^X/s///' > cuserid.c << '/'
X/*  cuserid(3)
X *
X *  Author: Terrence W. Holm          Sept. 1987
X */
X
X#include <lib.h>
X#include <pwd.h>
X#include <string.h>
X#include <unistd.h>
X#include <stdio.h>
X
X#ifndef  L_cuserid
X#define  L_cuserid   9
X#endif
X
Xchar *cuserid(user_name)
Xchar *user_name;
X{
X  PRIVATE char userid[L_cuserid];
X  struct passwd *pw_entry;
X
X  if (user_name == (char *)NULL) user_name = userid;
X
X  pw_entry = getpwuid(geteuid());
X
X  if (pw_entry == (struct passwd *)NULL) {
X	*user_name = '\0';
X	return((char *)NULL);
X  }
X  strcpy(user_name, pw_entry->pw_name);
X
X  return(user_name);
X}
/
echo x - environ.c
sed '/^X/s///' > environ.c << '/'
X/*
X * environ.c - define the variable environ
X */
X/* $Header: environ.c,v 1.1 90/09/27 13:39:50 eck Exp $ */
X/*
X * This file defines the variable environ and initializes it with a magic
X * value.  The C run-time start-off routine tests whether the variable
X * environ is initialized with this value.  If it is not, it is assumed
X * that it is defined by the user.  Only two bytes are tested, since we
X * don't know the endian-ness and alignment restrictions of the machine.
X * This means that the low-order two-bytes should be equal to the
X * high-order two-bytes on machines with four-byte pointers.  In fact, all
X * the bytes in the pointer are the same, just in case.
X */
X
X#if _EM_PSIZE==2
Xchar **environ = (char **) 0x5353;
X#else
Xchar **environ = (char **) 0x53535353;
X#endif
/
echo x - errno.c
sed '/^X/s///' > errno.c << '/'
X#include <lib.h>
X/* errno.c - declare variable errno             Author: F. Meulenbroeks */
X
Xint errno = 0;
/
echo x - execlp.c
sed '/^X/s///' > execlp.c << '/'
X/* execlp(3) and execvp(3)
X *
X * Author: Terrence W. Holm      July 1988
X */
X
X/* FIXES - Dec 1989 - Jan 1990 Bruce Evans.
X *	 - Don't use search path when file name contains a '/' *anywhere*.
X *	 - Invoke sh(1) on command files.
X *	 - Use PATH_MAX and check strings fit in buffer.
X *	 - Use stdargs, with the unjustified assumption that va_start() turns
X *	   the arg list into a char *[].  Strictly, the arg list should be
X *	   copied, "wasting" up to ARG_MAX bytes.
X */
X
X/*  Execlp(3) and execvp(3) are like execl(3) and execv(3),
X *  except that they use the environment variable $PATH as
X *  a search list of possible locations for the executable
X *  file, if <file> does not contain a '/', and they attempt
X *  to run non-binary executable files using sh(1).
X *
X *  The path search list is a list of directory names separated
X *  by ':'s. If a colon appears at the beginning or end of the
X *  list, or two appear together, then an empty prefix is tried.
X *  If $PATH is not in the environment, it defaults to "".
X *
X *  For example, if <file> is "ls", and the $PATH is
X *  ":/usr/local/bin:/bin:/usr/bin", then  ./ls,
X *  /usr/local/bin/ls, /bin/ls and /usr/bin/ls are tried until
X *  an exectable one is found. If the direct attempt to exec it
X *  fails, the arg list is modified to begin with "sh" and the
X *  absolute name of <file>, and an exec of /bin/sh is tried.
X *  If this fails, no further attempts are made.
X *
X *  This function only returns after an error.  It returns -1
X *  and sets errno like execv().
X */
X
X#include <sys/types.h>
X#include <lib.h>
X#include <errno.h>
X#include <limits.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X#include <stdarg.h>
X
X#undef NULL
X#define NULL 0			/* kludge for ACK not understanding void * */
X
X#define MAX_NUM_ARGS 512	/* maximum number of arguments to execvp */
X
Xextern char **environ;		/* environment pointer */
X
X#ifdef _ANSI
Xint execlp(const char *file, const char *arg, ...)
X#else
Xint execlp(file)
Xchar *file;
X#endif
X{
X  register va_list argp;
X  register int result;
X
X  va_start(argp, file);
X  result = execvp(file, (char **) argp);
X  va_end(argp);
X  return(result);
X}
X
X#ifdef _ANSI
Xint execvp(const char *file, char *const argv[])
X#else
Xint execvp(file, argv)
Xchar *file;
Xchar **argv;
X#endif
X{
X  int i, best_errno;
X  char **envtop;
X  size_t flength;
X  char *searchpath;
X  size_t slength;
X  char *split;
X  char execpath[PATH_MAX + 1];
X  char *arg2[MAX_NUM_ARGS + 3];	/* place to copy argv */
X
X  /* POSIX requires argv to be immutable.  Unfortunately, we have to change it
X   * during execution.  To keep POSIX happy, a copy is made and the copy 
X   * changed.  The question arises: how big should the copy be?  Allocating
X   * space dynamically requires using malloc, which itself takes up a lot
X   * of space.  The solution chosen here is to limit the number of arguments
X   * to MAX_NUM_ARGS and set this value fairly high.  This solution is simpler
X   * and is probably adequate.  Only programs with huge numbers of very short
X   * arguments will get an error (if the arguments are large, ARG_MAX will
X   * be exceeded.
X   */
X
X  if (strchr(file, '/') != NULL || (searchpath = getenv("PATH")) == NULL)
X	searchpath = "";
X  flength = strlen(file);
X  best_errno = ENOENT;
X
X  while (1) {
X	split = strchr(searchpath, ':');
X	if (split == NULL)
X		slength = strlen(searchpath);
X	else
X		slength = split - searchpath;
X	if (slength + flength >= sizeof execpath - 2) {
X		errno = ENAMETOOLONG;	/* too bad if premature */
X		return(-1);
X	}
X	strncpy(execpath, searchpath, slength);
X	if (slength != 0) execpath[slength++] = '/';
X	strcpy(execpath + slength, file);
X
X	/* Don't try to avoid execv() for non-existent files, since the Minix
X	 * shell doesn't, and it is not clear whether access() or stat() work
X	 * right when this code is set-uid.
X	 */
X	execv(execpath, argv);
X	switch (errno) {
X	    case EACCES:
X		best_errno = errno;	/* more useful than ENOENT */
X	    case ENOENT:
X		if (split == NULL) {
X			/* No more path components. */
X			errno = best_errno;
X			return(-1);
X		}
X		searchpath = split + 1;	/* try next in path */
X		break;
X	    case ENOEXEC:
X		/* Assume a command file and invoke sh(1) on it.  Replace arg0
X		 * (which is usually a short name for the command) by the full
X		 * name of the command file.
X		 */
X
X		/* Copy the arg pointers from argv to arg2,  moving them up by
X		 * 1, overlaying the assumed NULL at the end, to make room 
X		 * for "sh" at the beginning.
X		 */
X		i = 0;
X		while (argv[i] != 0) {
X			if (i >= MAX_NUM_ARGS) {
X				/* Copy failed.  Not enough room.  Bad luck. */
X				errno = ENOEXEC;
X				return(-1);
X			}
X			arg2[i + 1] = argv[i];
X			i++;
X		}
X		arg2[0] = "sh";		/* exec the shell */
X		arg2[1] = execpath;	/* full path */
X		arg2[i + 1] = NULL;	/* terminator */
X
X		/* Count the environment pointers. */
X		for (envtop = environ; *envtop != NULL; ) envtop++;
X
X		/* Try only /bin/sh, like the Minix shell.  Lose if the user
X		 * has a different shell or the command has #!another/shell.
X		 */
X		__execve("/bin/sh", arg2, environ, i + 1, (int)(envtop - environ));
X
X		/* Oops, no shell?   Give up. */
X		errno = ENOEXEC;
X		return(-1);
X	    default:
X		return(-1);	/* probably  ENOMEM or E2BIG */
X	}
X  }
X}
/
echo x - fdopen.c
sed '/^X/s///' > fdopen.c << '/'
X/*
X * fdopen - convert a (UNIX) file descriptor into a FILE pointer
X */
X/* $Header: fdopen.c,v 1.4 91/02/22 16:32:05 ceriel Exp $ */
X
X#include	<stdlib.h>
X#include	"../stdio/loc_incl.h"
X#include	<stdio.h>
X
XFILE *
Xfdopen(fd, mode)
Xint fd;
X_CONST char *mode;
X{
X	register int i;
X	FILE *stream;
X	int flags = 0;
X
X	if (fd < 0) return (FILE *)NULL;
X	for (i = 0; __iotab[i] != 0 ; i++) 
X		if (i >= FOPEN_MAX-1)
X			return (FILE *)NULL;
X
X	switch(*mode++) {
X	case 'r':
X		flags |= _IOREAD | _IOREADING;
X		break;
X	case 'a':
X		flags |= _IOAPPEND;
X	case 'w':
X		flags |= _IOWRITE | _IOWRITING;
X		break;
X	default:
X		return (FILE *)NULL;
X	}
X	while(*mode) {
X		switch(*mode++) {
X		case 'b':
X			continue;
X		case '+':
X			flags |= _IOREAD | _IOWRITE;
X			continue;
X		/* The sequence may be followed by aditional characters */
X		default:
X			break;
X		}
X		break;
X	}
X
X	if ((stream = (FILE *) malloc(sizeof(FILE))) == NULL) {
X		return (FILE *)NULL;
X	}
X
X	if ((flags & _IOREAD) && (flags & _IOWRITE))
X		flags &= ~(_IOREADING | _IOWRITING);
X
X	stream->_count = 0;
X	stream->_fd = fd;
X	stream->_flags = flags;
X	stream->_buf = NULL;
X	__iotab[i] = stream;
X	return stream;
X}
/
echo x - ffs.c
sed '/^X/s///' > ffs.c << '/'
X#include <lib.h>
X/*  ffs(3)
X *
X *  Author: Terrence W. Holm          Sep. 1988
X */
X_PROTOTYPE( int ffs, (int word));
X
Xint ffs(word)
Xint word;
X{
X  int i;
X
X  if (word == 0) return(0);
X
X  for (i = 1;; ++i, word >>= 1)
X	if (word & 1) return(i);
X}
/
echo x - fprintk.c
sed '/^X/s///' > fprintk.c << '/'
X#include <lib.h>
X#include <stdarg.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <stdio.h>
X
X#define MAXDIG		11	/* 32 bits in radix 8 */
X
X#define GETARG(typ)	va_arg(args, typ)
X
XPRIVATE int Xflag, STDERR;
X
XPRIVATE _PROTOTYPE(char *_itoa, (char *p, unsigned num, int radix));
XPRIVATE _PROTOTYPE(char *_lota, (char *p, unsigned long num, int radix));
X_PROTOTYPE( void fputk, (int c));
X_PROTOTYPE( void putk, (int c));
X_PROTOTYPE( void Fputk, (int n));
X_PROTOTYPE( void fprintk, (FILE *file, char *fmt, int arg1));
X
XPRIVATE char *_itoa(p, num, radix)
Xregister char *p;
Xregister unsigned num;
Xregister radix;
X{
X  register i;
X  register char *q;
X
X  q = p + MAXDIG;
X  do {
X	i = (int) (num % radix);
X	i += '0';
X	if (i > '9') i += (Xflag ? 'A' : 'a') - '0' - 10;
X	*--q = i;
X  } while (num = num / radix);
X  i = p + MAXDIG - q;
X  do
X	*p++ = *q++;
X  while (--i);
X  return(p);
X}
X
XPRIVATE char *_lota(p, num, radix)
Xregister char *p;
Xregister unsigned long num;
Xregister radix;
X{
X  register i;
X  register char *q;
X
X  q = p + MAXDIG;
X  do {
X	i = (int) (num % radix);
X	i += '0';
X	if (i > '9') i += 'A' - '0' - 10;
X	*--q = i;
X  } while (num = num / radix);
X  i = p + MAXDIG - q;
X  do
X	*p++ = *q++;
X  while (--i);
X  return(p);
X}
X
Xvoid fprintk(file, fmt, arg1)
XFILE *file;
Xregister char *fmt;
Xint arg1;
X{
X  char buf[MAXDIG + 1];		/* +1 for sign */
X  register int *args = &arg1;
X  register char *p, *s;
X  int c, i, ndfnd, ljust, lflag, zfill;
X  short width, ndigit;
X  long l;
X
X  if (file == stderr) {
X	STDERR = 1;
X  } else if (file == stdout) {
X	STDERR = 0;
X  } else {
X	write(fileno(stderr),"fprintf called with bad 1st arg\n", 32);
X	exit(1);
X  }
X
X  for (;;) {
X	c = *fmt++;
X	if (c == 0) {
X		/* We are done.  Flush the buffer. */
X		Fputk(0);
X		return;
X	}
X	if (c != '%') {
X		Fputk(c);
X		continue;
X	}
X	p = buf;
X	s = buf;
X	ljust = 0;
X	if (*fmt == '-') {
X		fmt++;
X		ljust++;
X	}
X	zfill = ' ';
X	if (*fmt == '0') {
X		fmt++;
X		zfill = '0';
X	}
X	for (width = 0;;) {
X		c = *fmt++;
X		if (c >= '0' && c <= '9')
X			c -= '0';
X		else if (c == '*')
X			c = GETARG(int);
X		else
X			break;
X		width *= 10;
X		width += c;
X	}
X	ndfnd = 0;
X	ndigit = 0;
X	if (c == '.') {
X		for (;;) {
X			c = *fmt++;
X			if (c >= '0' && c <= '9')
X				c -= '0';
X			else if (c == '*')
X				c = GETARG(int);
X			else
X				break;
X			ndigit *= 10;
X			ndigit += c;
X			ndfnd++;
X		}
X	}
X	lflag = 0;
X	if (c == 'l' || c == 'L') {
X		lflag++;
X		if (*fmt) c = *fmt++;
X	}
X	switch (c) {
X	    case 'X':
X		Xflag++;
X
X	    case 'x':
X		c = 16;
X		goto oxu;
X
X	    case 'U':
X		lflag++;
X
X	    case 'u':
X		c = 10;
X		goto oxu;
X
X	    case 'O':
X		lflag++;
X
X	    case 'o':
X		c = 8;
X  oxu:
X		if (lflag) {
X			p = _lota(p, (unsigned long) GETARG(long), c);
X			break;
X		}
X		p = _itoa(p, (unsigned int) GETARG(int), c);
X		break;
X
X	    case 'D':
X		lflag++;
X
X	    case 'd':
X		if (lflag) {
X			if ((l = GETARG(long)) < 0) {
X				*p++ = '-';
X				l = -l;
X			}
X			p = _lota(p, (unsigned long) l, 10);
X			break;
X		}
X		if ((i = GETARG(int)) < 0) {
X			*p++ = '-';
X			i = -i;
X		}
X		p = _itoa(p, (unsigned int) i, 10);
X		break;
X
X	    case 'e':
X	    case 'f':
X	    case 'g':
X		zfill = ' ';
X		*p++ = '?';
X		break;
X
X	    case 'c':
X		zfill = ' ';
X		*p++ = GETARG(int);
X		break;
X
X	    case 's':
X		zfill = ' ';
X		if ((s = GETARG(char *)) == 0) s = "(null)";
X		if (ndigit == 0) ndigit = 32767;
X		for (p = s; *p && --ndigit >= 0; p++);
X		break;
X
X	    default:	*p++ = c;	break;
X	}
X	i = p - s;
X	if ((width -= i) < 0) width = 0;
X	if (ljust == 0) width = -width;
X	if (width < 0) {
X		if (*s == '-' && zfill == '0') {
X			Fputk( (int) *s);
X			s++;
X			i--;
X		}
X		do
X			Fputk(zfill);
X		while (++width != 0);
X	}
X	while (--i >= 0) {
X		Fputk( (int ) *s);
X		s++;
X	}
X	while (width) {
X		Fputk(zfill);
X		width--;
X	}
X  }
X}
X
Xvoid
XFputk(n)
Xint n;
X{
X  if (STDERR == 1)
X	fputk(n);
X  else
X	putk(n);
X}
/
echo x - fputk.c
sed '/^X/s///' > fputk.c << '/'
X#include <lib.h>
X#include <unistd.h>
X
X#define BUF_SIZE 1024
X#define FD          2
X
XPRIVATE char outbuf[BUF_SIZE];
XPRIVATE char *bufp = outbuf;
X_PROTOTYPE( void fputk, (int n));
X
Xvoid fputk(n)
Xint n;
X{
X/* Print one char on stdout. */
X
X  if (n == 0) {
X	/* putc(0) means flush the buffer. */
X	if (bufp > outbuf) write(FD, outbuf, (size_t)(bufp - outbuf));
X	bufp = outbuf;
X	return;
X  }
X
X  *bufp++ = (char) n;
X  if (bufp == &outbuf[BUF_SIZE]) {
X	/* The buffer is full.  Flush it. */
X	write(FD, outbuf, BUF_SIZE);
X	bufp = outbuf;
X  }
X}
/
echo x - fslib.c
sed '/^X/s///' > fslib.c << '/'
X/* fslib.c - routines needed by fs and fs utilities */
X
X#include <minix/config.h>	/* for unused stuff in <minix/type.h> :-( */
X#include <ansi.h>
X#include <sys/types.h>
X#include <minix/const.h>
X#include <minix/type.h>		/* for unshort :-( */
X#include "fs/const.h"		/* depends of -I flag in Makefile */
X#include "fs/type.h"		/* ditto */
X#include "fs/inode.h"		/* ditto */
X#include <minix/fslib.h>
X
X/* The next routine is copied from fsck.c and mkfs.c...  (Re)define some
X * things for consistency.  Some things should be done better.  The shifts
X * should be replaced by multiplications and divisions by MAP_BITS_PER_BLOCK
X * since log2 of this is too painful to get right.
X */
X#define BITMAPSHIFT	 13	/* = log2(MAP_BITS_PER_BLOCK) */
X
X/* Convert from bit count to a block count. The usual expression
X *
X *	(nr_bits + (1 << BITMAPSHIFT) - 1) >> BITMAPSHIFT
X *
X * doesn't work because of overflow.
X *
X * Other overflow bugs, such as the expression for N_ILIST overflowing when
X * s_inodes is just over V*_INODES_PER_BLOCK less than the maximum+1, are not
X * fixed yet, because that number of inodes is silly.
X */
X/* The above comment doesn't all apply now bit_t is long.  Overflow is now
X * unlikely, but negative bit counts are now possible (though unlikely)
X * and give silly results.
X */ 
XPUBLIC int bitmapsize(nr_bits)
Xbit_t nr_bits;
X{
X  int nr_blocks;
X
X  nr_blocks = (int) (nr_bits >> BITMAPSHIFT);
X  if (((bit_t) nr_blocks << BITMAPSHIFT) < nr_bits) ++nr_blocks;
X  return(nr_blocks);
X}
X
X
X/*===========================================================================*
X *				conv2					     *
X *===========================================================================*/
XPUBLIC unsigned conv2(norm, w)
Xint norm;			/* TRUE if no swap, FALSE for byte swap */
Xint w;				/* promotion of 16-bit word to be swapped */
X{
X/* Possibly swap a 16-bit word between 8086 and 68000 byte order. */
X
X  if (norm) return( (unsigned) w & 0xFFFF);
X  return( ((w&BYTE) << 8) | ( (w>>8) & BYTE));
X}
X
X
X/*===========================================================================*
X *				conv4					     *
X *===========================================================================*/
XPUBLIC long conv4(norm, x)
Xint norm;			/* TRUE if no swap, FALSE for byte swap */
Xlong x;				/* 32-bit long to be byte swapped */
X{
X/* Possibly swap a 32-bit long between 8086 and 68000 byte order. */
X
X  unsigned lo, hi;
X  long l;
X  
X  if (norm) return(x);			/* byte order was already ok */
X  lo = conv2(FALSE, (int) x & 0xFFFF);	/* low-order half, byte swapped */
X  hi = conv2(FALSE, (int) (x>>16) & 0xFFFF);	/* high-order half, swapped */
X  l = ( (long) lo <<16) | hi;
X  return(l);
X}
X
X
X/*===========================================================================*
X *				conv_inode				     *
X *===========================================================================*/
XPUBLIC void conv_inode(rip, dip, dip2, rw_flag, magic)
Xregister struct inode *rip;	/* pointer to the in-core inode struct */
Xregister d1_inode *dip;		/* pointer to the V1 on-disk inode struct */
Xregister d2_inode *dip2;	/* pointer to the V2 on-disk inode struct */
Xint rw_flag;			/* READING or WRITING */
Xint magic;			/* magic number of file system */
X{ 
X/* Copy the inode from the disk block to the in-core table or vice versa.
X * If the fourth parameter below is FALSE, the bytes are swapped.
X */
X  switch (magic) {
X	case SUPER_MAGIC:	old_icopy(rip, dip,  rw_flag, TRUE);	break;
X	case SUPER_REV:		old_icopy(rip, dip,  rw_flag, FALSE);	break;
X	case SUPER_V2:		new_icopy(rip, dip2, rw_flag, TRUE);	break;
X	case SUPER_V2_REV:	new_icopy(rip, dip2, rw_flag, FALSE);	break;
X  } 
X}
X
X
X/*===========================================================================*
X *				old_icopy				     *
X *===========================================================================*/
XPUBLIC void old_icopy(rip, dip, direction, norm)
Xregister struct inode *rip;	/* pointer to the in-core inode struct */
Xregister d1_inode *dip;		/* pointer to the d1_inode inode struct */
Xint direction;			/* READING (from disk) or WRITING (to disk) */
Xint norm;			/* TRUE = do not swap bytes; FALSE = swap */
X
X{
X/* 4 different on-disk inode layouts are supported, one for each combination
X * of V1.x/V2.x * bytes-swapped/not-swapped.  When an inode is read or written
X * this routine handles the conversions so that the information in the inode
X * table is independent of the disk structure from which the inode came.
X * The old_icopy routine copies to and from V1 disks.
X */
X
X  int i;
X
X  if (direction == READING) {
X	/* Copy V1.x inode to the in-core table, swapping bytes if need be. */
X	rip->i_mode    = conv2(norm, dip->d1_mode);
X	rip->i_uid     = conv2(norm,dip->d1_uid );
X	rip->i_size    = conv4(norm,dip->d1_size);
X	rip->i_mtime   = conv4(norm,dip->d1_mtime);
X	rip->i_atime   = 0;
X	rip->i_ctime   = 0;
X	rip->i_nlinks  = (nlink_t) dip->d1_nlinks;	/* 1 char */
X	rip->i_gid     = (gid_t) dip->d1_gid;		/* 1 char */
X	rip->i_ndzones = V1_NR_DZONES;
X	rip->i_nindirs = V1_INDIRECTS;
X	for (i = 0; i < V1_NR_TZONES; i++)
X		rip->i_zone[i] = conv2(norm, (int) dip->d1_zone[i]);
X  } else {
X	/* Copying V1.x inode to disk from the in-core table. */
X	dip->d1_mode   = conv2(norm,rip->i_mode);
X	dip->d1_uid    = conv2(norm,rip->i_uid );
X	dip->d1_size   = conv4(norm,rip->i_size);
X	dip->d1_mtime  = conv4(norm,rip->i_mtime);
X	dip->d1_nlinks = (nlink_t) rip->i_nlinks;	/* 1 char */
X	dip->d1_gid    = (gid_t) rip->i_gid;		/* 1 char */
X	for (i = 0; i < V1_NR_TZONES; i++)
X		dip->d1_zone[i] = conv2(norm, (int) rip->i_zone[i]);
X  }
X}
X
X
X/*===========================================================================*
X *				new_icopy				     *
X *===========================================================================*/
XPUBLIC void new_icopy(rip, dip, direction, norm)
Xregister struct inode *rip;	/* pointer to the in-core inode struct */
Xregister d2_inode *dip;	/* pointer to the d2_inode struct */
Xint direction;			/* READING (from disk) or WRITING (to disk) */
Xint norm;			/* TRUE = do not swap bytes; FALSE = swap */
X
X{
X/* Same as old_icopy, but to/from V2 disk layout. */
X
X  int i;
X
X  if (direction == READING) {
X	/* Copy V2.x inode to the in-core table, swapping bytes if need be. */
X	rip->i_mode    = conv2(norm,dip->d2_mode);
X	rip->i_uid     = conv2(norm,dip->d2_uid );
X	rip->i_nlinks  = conv2(norm,(int) dip->d2_nlinks);
X	rip->i_gid     = conv2(norm,(int) dip->d2_gid );
X	rip->i_size    = conv4(norm,dip->d2_size);
X	rip->i_atime   = conv4(norm,dip->d2_atime);
X	rip->i_ctime   = conv4(norm,dip->d2_ctime);
X	rip->i_mtime   = conv4(norm,dip->d2_mtime);
X	rip->i_ndzones = V2_NR_DZONES;
X	rip->i_nindirs = V2_INDIRECTS;
X	for (i = 0; i < V2_NR_TZONES; i++)
X		rip->i_zone[i] = conv4(norm, (long) dip->d2_zone[i]);
X  } else {
X	/* Copying V2.x inode to disk from the in-core table. */
X	dip->d2_mode   = conv2(norm,rip->i_mode);
X	dip->d2_uid    = conv2(norm,rip->i_uid );
X	dip->d2_nlinks = conv2(norm,rip->i_nlinks);
X	dip->d2_gid    = conv2(norm,rip->i_gid );
X	dip->d2_size   = conv4(norm,rip->i_size);
X	dip->d2_atime  = conv4(norm,rip->i_atime);
X	dip->d2_ctime  = conv4(norm,rip->i_ctime);
X	dip->d2_mtime  = conv4(norm,rip->i_mtime);
X	for (i = 0; i < V2_NR_TZONES; i++)
X		dip->d2_zone[i] = conv4(norm, (long) rip->i_zone[i]);
X  }
X}
/
echo x - fsversion.c
sed '/^X/s///' > fsversion.c << '/'
X/* This procedure examines a file system and figures out whether it is
X * version 1 or version 2.  It returns the result as an int.  If the
X * file system is neither, it returns -1.  A typical call is:
X *
X *	n = fsversion("/dev/hd1", "df");
X *
X * The first argument is the special file for the file system. 
X * The second is the program name, which is used in error messages.
X */
X
X#include <sys/types.h>
X#include <minix/config.h>
X#include <minix/const.h>
X#include <minix/minlib.h>
X#include <minix/type.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdio.h>
X
X#include "../../fs/const.h"
X#include "../../fs/type.h"
X#include "../../fs/super.h"
X
Xstatic struct super_block super, *sp;
X
Xint fsversion(dev, prog)
Xchar *dev, *prog;
X{
X  int fd;
X
X  if ((fd = open(dev, O_RDONLY)) < 0) {
X	std_err(prog);
X	std_err(" cannot open ");
X	perror(dev);
X	return(-1);
X  }
X
X  lseek(fd, (off_t) BLOCK_SIZE, SEEK_SET);	/* skip boot block */
X  if (read(fd, (char *) &super, (unsigned) SUPER_SIZE) != SUPER_SIZE) {
X	std_err(prog);
X	std_err(" cannot read super block on ");
X	perror(dev);
X	close(fd);
X	return(-1);
X  }
X  close(fd);
X  sp = &super;
X  if (sp->s_magic == SUPER_MAGIC) return(1);
X  if (sp->s_magic == SUPER_V2) return(2);
X  return(-1);
X}
/
echo x - getdents.c
sed '/^X/s///' > getdents.c << '/'
X#include <lib.h>
X/*
X		(SVR3 system call emulation)
X
X  last edit:	27-Oct-1988	D A Gwyn
X
X  This single source file supports several different methods of
X  getting directory entries from the operating system.  Define
X  whichever one of the following describes your system:
X
X  UFS	original UNIX filesystem (14-character name limit)
X  BFS	4.2BSD (also 4.3BSD) native filesystem (long names)
X  NFS	getdirentries() system call
X
X  Also define any of the following flags that are pertinent:
X
X  ATT_SPEC	check user buffer address for longword alignment
X  BSD_SYSV	BRL UNIX System V emulation environment on 4.nBSD
X  INT_SIGS	<signal.h> thinks that signal handlers have
X		return type int (rather than the standard void)
X  NEG_DELS	deleted entries have inode number -1 rather than 0
X  UNK		have _getdents() system call, but kernel may not
X		support it
X
X  If your C library has a getdents() system call interface, but you
X  can't count on all kernels on which your application binaries may
X  run to support it, change the system call interface name to
X  _getdents() and define "UNK" to enable the system-call validity
X  test in this "wrapper" around _getdents().
X
X  If your system has a getdents() system call that is guaranteed
X  to always work, you shouldn't be using this source file at all.
X*/
X
X#define  UFS
X
X#include	<string.h>
X#include	<unistd.h>
X
X#ifdef BSD_SYSV
X#include	<sys/_dir.h>	/* BSD flavor, not System V */
X#else
X#include	<sys/dir.h>
X#undef	MAXNAMLEN		/* avoid conflict with SVR3 */
X /* Good thing we don't need to use the DIRSIZ() macro! */
X#ifdef d_ino			/* 4.3BSD/NFS using d_fileno */
X#undef	d_ino			/* (not absolutely necessary) */
X#else
X#define	d_fileno	d_ino	/* (struct direct) member */
X#endif
X#endif
X#include	<dirent.h>
X
X
X/*==========================================================================*/
X/* This was in the original sys/dirent.h. The local definitions don't work. */
X
X#ifdef BSD_SYSV				/* (e.g., when compiling getdents.c) */
Xextern struct dirent	__dirent;	/* (not actually used) */
X/* The following is portable, although rather silly. */
X#define	DIRENTBASESIZ		(__dirent.d_name - (char *)&__dirent.d_ino)
X
X#else
X/* The following nonportable ugliness could have been avoided by defining
X   DIRENTSIZ and DIRENTBASESIZ to also have (struct dirent *) arguments.
X   There shouldn't be any problem if you avoid using the DIRENTSIZ() macro. */
X
X#define	DIRENTBASESIZ		((int)(((struct dirent *)0)->d_name) \
X				- (int)&((struct dirent *)0)->d_ino)
X#endif
X
X#define	DIRENTSIZ( namlen )	((DIRENTBASESIZ + sizeof(long) + (namlen)) \
X				/ sizeof(long) * sizeof(long))
X/*==========================================================================*/
X
X#include	<sys/stat.h>
X#ifdef UNK
X#ifndef UFS
X#include "***** ERROR ***** UNK applies only to UFS"
X/* One could do something similar for getdirentries(), but I didn't bother. */
X#endif
X#include	<signal.h>
X#endif
X
X#ifdef BSD_SYSV
Xstruct dirent __dirent;		/* (just for the DIRENTBASESIZ macro) */
X#endif
X
X#ifdef UFS
X#define	RecLen( dp )	(sizeof(struct direct))	/* fixed-length entries */
X#else				/* BFS || NFS */
X#define	RecLen( dp )	((dp)->d_reclen)	/* variable-length entries */
X#endif
X
X#ifdef NFS
X#ifdef BSD_SYSV
X#define	getdirentries	_getdirentries	/* package hides this system call */
X#endif
Xextern int getdirentries();
XPRIVATE long dummy;		/* getdirentries() needs basep */
X#define	GetBlock( fd, buf, n )	getdirentries( fd, buf, (unsigned)n, &dummy )
X#else				/* UFS || BFS */
X#ifdef BSD_SYSV
X#define read	_read		/* avoid emulation overhead */
X#endif
X#define	GetBlock( fd, buf, n )	read( fd, buf, n )
X#endif
X
X#ifdef UNK
Xextern int _getdents();		/* actual system call */
X#endif
X
X#ifdef NEG_DELS
X#define	DELETED	(-1)
X#else
X#define	DELETED	0
X#endif
X
X#ifndef DIRENTSIZ
X#define DIRENTSIZ(x)	(x)
X#endif
X#ifndef DIRENTBASESIZ
X#define DIRENTBASESIZ 0
X#endif
X#ifndef DIRBLKSIZ
X#define	DIRBLKSIZ	4096	/* directory file read buffer size */
X#endif
X
X#ifndef NULL
X#define	NULL	0
X#endif
X
X#ifndef SEEK_CUR
X#define	SEEK_CUR	1
X#endif
X
X#ifndef S_ISDIR			/* macro to test for directory file */
X#define	S_ISDIR( mode )		(((mode) & S_IFMT) == S_IFDIR)
X#endif
X
X#ifdef UFS
X
X/*
X  The following routine is necessary to handle DIRSIZ-long entry names.
X  Thanks to Richard Todd for pointing this out.
X*/
X
XPRIVATE _PROTOTYPE( int NameLen, (char *name));
X
XPRIVATE int NameLen(name)	/* return # chars in embedded name */
Xchar name[];			/* -> name embedded in struct direct */
X{
X  register char *s;		/* -> name[.] */
X  register char *stop = &name[NAME_MAX];	/* -> past end of name field */
X
X  for (s = &name[1];		/* (empty names are impossible) */
X       *s != '\0'		/* not NUL terminator */
X       && ++s < stop;		/* < DIRSIZ characters scanned */
X	);
X
X  return (s - name);		/* # valid characters in name */
X}
X
X#else				/* BFS || NFS */
X
X#define	NameLen( name )	strlen( name )	/* names are always NUL-terminated */
X
X#endif
X
X#ifdef UNK
XPRIVATE enum {
X  maybe, no, yes
X} state = maybe;
X
X /* Does _getdents() work? */
X
X#ifdef INT_SIGS
X#define	RET_SIG	int
X#else
X#define	RET_SIG	void
X#endif
X
X/*ARGSUSED*/
XPRIVATE RET_SIG
X sig_catch(sig)
Xint sig;			/* must be SIGSYS */
X{
X  state = no;			/* attempted _getdents() faulted */
X#ifdef INT_SIGS
X  return (0);			/* telling lies */
X#endif
X}
X
X#endif				/* UNK */
X
Xint getdents(fildes, buf, nbyte)/* returns # bytes read; 0 on EOF, -1 on
X			 * error */
Xint fildes;			/* directory file descriptor */
Xchar *buf;			/* where to put the (struct dirent)s */
Xunsigned nbyte;			/* size of buf[] */
X{
X  int serrno;			/* entry errno */
X  off_t offset;			/* initial directory file offset */
X  /* The following are PRIVATE just to keep the stack small. */
X  PRIVATE struct stat statb;	/* fstat() info */
X  PRIVATE union {
X	char dblk[DIRBLKSIZ
X#ifdef UFS
X		  + 1		/* for last entry name terminator */
X#endif
X	];
X	/* Directory file block buffer */
X	struct direct dummy;	/* just for alignment */
X  } u;				/* (avoids having to malloc()) */
X  register struct direct *dp;	/* -> u.dblk[.] */
X  register struct dirent *bp;	/* -> buf[.] */
X
X#ifdef UNK
X  if (state == yes)		/* _getdents() is known to work */
X	return (_getdents(fildes, buf, nbyte));
X
X  if (state == maybe) {		/* first time only */
X	RET_SIG(*shdlr) ();	/* entry SIGSYS handler */
X	register int retval;	/* return from _getdents() if any */
X
X	shdlr = signal(SIGSYS, sig_catch);
X	retval = _getdents(fildes, buf, nbyte);	/* try it */
X	(void) signal(SIGSYS, shdlr);
X
X	if (state == maybe) {	/* SIGSYS did not occur */
X		state = yes;	/* so _getdents() must have worked */
X		return (retval);
X	}
X  }
X
X  /* State == no; perform emulation */
X#endif
X
X  if (buf == (char *)NULL
X#ifdef ATT_SPEC
X      || (unsigned long) buf % sizeof(long) != 0	/* ugh */
X#endif
X	) {
X	errno = EFAULT;		/* invalid pointer */
X	return (-1);
X  }
X  if (fstat(fildes, &statb) != 0) return (-1);	/* errno set by fstat() */
X
X  if (!S_ISDIR(statb.st_mode)) {
X	errno = ENOTDIR;	/* not a directory */
X	return (-1);
X  }
X  if ((offset = lseek(fildes, (off_t) 0, SEEK_CUR)) < 0)
X	return (-1);		/* errno set by lseek() */
X
X#ifdef BFS			/* no telling what remote hosts do */
X  if ((unsigned long) offset % DIRBLKSIZ != 0) {
X	errno = ENOENT;		/* file pointer probably misaligned */
X	return (-1);
X  }
X#endif
X
X  serrno = errno;		/* save entry errno */
X
X  for (bp = (struct dirent *) buf; bp == (struct dirent *) buf;) {	/* convert next
X									 * directory block */
X	int size;
X
X	do
X		size = GetBlock(fildes, u.dblk, DIRBLKSIZ);
X	while (size == -1 && errno == EINTR);
X
X	if (size <= 0) return (size);	/* EOF or error (EBADF) */
X
X	for (dp = (struct direct *) u.dblk;
X	     (char *) dp < &u.dblk[size];
X	     dp = (struct direct *) ((char *) dp + RecLen(dp))
X		) {
X#ifndef UFS
X		if (dp->d_reclen <= 0) {
X			errno = EIO;	/* corrupted directory */
X			return (-1);
X		}
X#endif
X
X		if (dp->d_fileno != DELETED) {	/* non-empty; copy to
X						 * user buffer */
X			register int reclen =
X			DIRENTSIZ(NameLen(dp->d_name));
X
X			if ((char *) bp + reclen > &buf[nbyte]) {
X				errno = EINVAL;
X				return (-1);	/* buf too small */
X			}
X			bp->d_ino = dp->d_fileno;
X			bp->d_off = offset + ((char *) dp - u.dblk);
X			bp->d_reclen = reclen;
X
X			{
X#ifdef UFS
X				/* Is the following kludge ugly?  You bet. */
X
X				register char save = dp->d_name[NAME_MAX];
X				/* Save original data */
X
X				dp->d_name[NAME_MAX] = '\0';
X				/* Ensure NUL termination */
X#endif
X				(void) strncpy(bp->d_name, dp->d_name,
X					       reclen - DIRENTBASESIZ
X					);	/* adds NUL padding */
X#ifdef UFS
X				dp->d_name[NAME_MAX] = save;
X				/* Restore original data */
X#endif
X			}
X
X			bp = (struct dirent *) ((char *) bp + reclen);
X		}
X	}
X
X	if ((char *) dp > &u.dblk[size]) {
X		errno = EIO;	/* corrupted directory */
X		return (-1);
X	}
X  }
X
X  errno = serrno;		/* restore entry errno */
X  return((char *) bp - buf);	/* return # bytes read */
X}
/
echo x - getgrent.c
sed '/^X/s///' > getgrent.c << '/'
X/*
X * getgrent - get entry form group file
X *
X * Author: Patrick van Kleef
X */
X/* $Header: getgrent.c,v 1.3 90/01/22 11:43:16 eck Exp $ */
X
X#include	<sys/types.h>
X#include	<stdlib.h>
X#include	<string.h>
X#include	<fcntl.h>
X#include	<grp.h>
X
X#ifdef _ANSI
Xoff_t _lseek(int d, off_t offset, int whence);
Xssize_t _read(int d, char *buf, size_t nbytes);
Xint _close(int d);
X#endif
X
X#define	RBUFSIZE	1024
Xstatic char _gr_file[] = "/etc/group";
Xstatic char _grbuf[256];
Xstatic char _buffer[RBUFSIZE];
Xstatic char *_pnt;
Xstatic char *_buf;
Xstatic int  _gfd = -1;
Xstatic int  _bufcnt;
Xstatic struct group grp;
X
Xint
Xsetgrent(void)
X{
X        if (_gfd >= 0)
X	        _lseek(_gfd, 0L, 0);
X        else
X	        _gfd = open(_gr_file, O_RDONLY);
X
X        _bufcnt = 0;
X        return _gfd;
X}
X
Xvoid
Xendgrent(void) 
X{
X        if (_gfd >= 0)
X	        _close(_gfd);
X
X        _gfd = -1;
X        _bufcnt = 0;
X}
X
X
Xstatic int
Xgetline(void) 
X{
X        if (_gfd < 0 && setgrent() < 0)
X	        return 0;
X
X        _buf = _grbuf;
X        do {
X	        if (--_bufcnt <= 0){
X	                if ((_bufcnt = _read(_gfd, _buffer, RBUFSIZE)) <= 0)
X		                return 0;
X	                else
X		                _pnt = _buffer;
X		}
X	        *_buf++ = *_pnt++;
X        } while (*_pnt != '\n');
X        _pnt++;
X        _bufcnt--;
X        *_buf = 0;
X        _buf = _grbuf;
X        return 1;
X}
X
Xstatic void
Xskip_period(void) 
X{
X        while (*_buf && *_buf != ':')
X	        _buf++;
X        *_buf++ = '\0';
X}
X
Xstruct group *
Xgetgrent(void) 
X{
X        if (getline() == 0)
X               return 0;
X
X        grp.gr_name = _buf;
X        skip_period();
X        grp.gr_passwd = _buf;
X        skip_period();
X        grp.gr_gid = atoi(_buf);
X        skip_period();
X        return &grp;
X}
X
Xstruct group *
Xgetgrnam(name)
X_CONST char *name;
X{
X        struct group *grp;
X
X        setgrent();
X        while ((grp = getgrent()) != 0)
X	        if (!strcmp(grp -> gr_name, name))
X	                break;
X        endgrent();
X        if (grp != 0)
X	        return grp;
X        else
X	        return 0;
X}
X
Xstruct group *
Xgetgrgid(gid)
Xint gid;
X{
X        struct group   *grp;
X
X        setgrent();
X        while ((grp = getgrent()) != 0)
X	        if (grp -> gr_gid == gid)
X	                break;
X        endgrent();
X        if (grp != 0)
X	        return grp;
X        else
X	        return 0;
X}
/
echo x - getgroups.c
sed '/^X/s///' > getgroups.c << '/'
X/* getgroups.c						POSIX 4.2.3
X *	int getgroups(gidsetsize, grouplist);
X *
X *	This call relates to suplementary group ids, which are not
X *	supported in MINIX.
X */
X
X#include <lib.h>
X#include <unistd.h>
X#include <time.h>
X
XPUBLIC int getgroups(gidsetsize, grouplist)
Xint gidsetsize;
Xgid_t grouplist[];
X{
X  return(0);
X}
/
echo x - getlogin.c
sed '/^X/s///' > getlogin.c << '/'
X/*  getlogin(3)
X *
X *  Author: Terrence W. Holm          Aug. 1988
X */
X
X#include <lib.h>
X#include <pwd.h>
X#include <unistd.h>
X#include <string.h>
X#include <stdio.h>
X
X#ifndef  L_cuserid
X#define  L_cuserid   9
X#endif
X
Xchar *getlogin()
X{
X  PRIVATE char userid[L_cuserid];
X  struct passwd *pw_entry;
X
X  pw_entry = getpwuid(getuid());
X
X  if (pw_entry == (struct passwd *)NULL) return((char *)NULL);
X
X  strcpy(userid, pw_entry->pw_name);
X
X  return(userid);
X}
/
echo x - getopt.c
sed '/^X/s///' > getopt.c << '/'
X/*
X * getopt - parse command-line options
X */
X/* $Header: getopt.c,v 1.1 89/12/18 14:39:31 eck Exp $ */
X
X#include	<stdlib.h>
X#include	<string.h>
X#include	<stdio.h>
X
X#define ERR(s, c)       if(opterr){\
X	fputs(argv[0], stderr);\
X	fputs(s, stderr);\
X	fputc(c, stderr);\
X	fputc('\n', stderr);}
X
Xint     opterr = 1;
Xint     optind = 1;
Xint	optopt;
Xchar    *optarg;
X
Xint
Xgetopt(argc, argv, opts)
Xint argc;
Xchar **argv;
Xchar *opts;
X{
X	static int sp = 1;
X	register c;
X	register char *cp;
X
X	if (sp == 1)
X		if (optind >= argc ||
X		   argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return EOF;
X		else if (!strcmp(argv[optind], "--")) {
X			optind++;
X			return EOF;
X		}
X	optopt = c = argv[optind][sp];
X	if (c == ':' || (cp=strchr(opts, c)) == NULL) {
X		ERR (": illegal option -- ", c);
X		if (argv[optind][++sp] == '\0') {
X			optind++;
X			sp = 1;
X		}
X		return '?';
X	}
X	if (*++cp == ':') {
X		if (argv[optind][sp+1] != '\0')
X			optarg = &argv[optind++][sp+1];
X		else if (++optind >= argc) {
X			ERR (": option requires an argument -- ", c);
X			sp = 1;
X			return '?';
X		} else
X			optarg = argv[optind++];
X		sp = 1;
X	} else {
X		if (argv[optind][++sp] == '\0') {
X			sp = 1;
X			optind++;
X		}
X		optarg = NULL;
X	}
X	return c;
X}
/
echo x - getpass.c
sed '/^X/s///' > getpass.c << '/'
X/*
X * getpass - ask for a password
X */
X/* $Header: getpass.c,v 1.2 90/01/22 11:43:26 eck Exp $ */
X
X#include	<sys/types.h>
X#include	<signal.h>
X#include	<string.h>
X#include	<sgtty.h>
X#include	<fcntl.h>
X
X_PROTOTYPE(char *getpass, (_CONST char *prompt ));
X
X#ifdef _ANSI
Xint _open(const char *path, int flags);
Xssize_t _write(int d, const char *buf, size_t nbytes);
Xssize_t _read(int d, char *buf, size_t nbytes);
Xint _close(int d);
Xint _stty(int, struct sgttyb *);
Xint _gtty(int, struct sgttyb *);
Xvoid (*savesig)(int);
X#else
Xvoid (*savesig)();
X#endif
X
Xchar *
Xgetpass(prompt)
X_CONST char *prompt;
X{
X	int i = 0;
X	struct sgttyb tty, ttysave;
X	static char pwdbuf[9];
X	int fd;
X
X	if ((fd = _open("/dev/tty", O_RDONLY)) < 0) fd = 0;
X	savesig = signal(SIGINT, SIG_IGN);
X	_write(2, prompt, strlen(prompt));
X	_gtty(fd, &tty);
X	ttysave = tty;
X	tty.sg_flags &= ~ECHO;
X	_stty(fd, &tty);
X	i = _read(fd, pwdbuf, 9);
X	while (pwdbuf[i - 1] != '\n')
X		_read(fd, &pwdbuf[i - 1], 1);
X	pwdbuf[i - 1] = '\0';
X	_stty(fd, &ttysave);
X	_write(2, "\n", 1);
X	if (fd != 0) _close(fd);
X	signal(SIGINT, savesig);
X	return(pwdbuf);
X}
/
echo x - getpw.c
sed '/^X/s///' > getpw.c << '/'
X/*
X * getpw - get a password from the password file
X */
X/* $Header: getpw.c,v 1.1 89/12/18 14:39:45 eck Exp $ */
X
X#include	<stdio.h>
X
X_PROTOTYPE(int getpw, (int uid, char buf []));
X
Xint
Xgetpw(uid, buf)
Xint uid; 
Xchar buf[];
X{
X	register FILE *pwf;
X	register int ch, i;
X	register char *bp;
X
X	pwf = fopen("/etc/passwd", "r");
X	if (pwf == NULL) return(1);
X
X	for (;;) {
X		bp = buf;
X		while ((ch = getc(pwf)) != '\n') {
X			if (ch == EOF) return 1;
X			*bp++ = ch;
X		}
X		*bp++ = '\0';
X		bp = buf;
X		for (i = 2; i; i--) {
X			while ((ch = *bp++) != ':') {
X				if(ch = '\0') return 1;
X			}
X		}
X		i = 0;
X		while ((ch = *bp++) != ':') {
X			if (ch < '0' || ch > '9') return 1;
X			i = i * 10 + (ch - '0');
X		}
X		if (i == uid) return(0);
X	}
X	/*NOTREACHED*/
X}
/
echo x - getpwent.c
sed '/^X/s///' > getpwent.c << '/'
X/* get entry from password file
X *
X * By Patrick van Kleef
X *
X * James R. Stuhlmacher  Nov. 1989
X *  - Modified for POSIX conformance.
X */
X
X#include <lib.h>
X#include <sys/stat.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <pwd.h>
X#include <stdlib.h>
X#include <string.h>
X
X#define BUFFERSIZE 1024
X#define PWBUFSIZE 256
X
XPRIVATE char _pw_file[] = "/etc/passwd";
XPRIVATE char _pwbuf[PWBUFSIZE];
XPRIVATE char _buffer[BUFFERSIZE];
XPRIVATE char *_pnt;
XPRIVATE char *_buf;
XPRIVATE int _pw = -1;
XPRIVATE int _bufcnt;
XPRIVATE struct passwd _pwd;
X
XPRIVATE _PROTOTYPE( int getline, (void)		);
XPRIVATE _PROTOTYPE( void skip_period, (void)	);
X
XPUBLIC int setpwent()
X{
X  if (_pw >= 0)
X	lseek(_pw, (off_t) 0, SEEK_SET);
X  else
X	_pw = open(_pw_file, O_RDONLY);
X
X  _bufcnt = 0;
X  return(_pw);
X}
X
X
XPUBLIC void endpwent()
X{
X  if (_pw >= 0) close(_pw);
X
X  _pw = -1;
X  _bufcnt = 0;
X}
X
XPRIVATE int getline()
X{
X  if (_pw < 0 && setpwent() < 0) return(0);
X  _buf = _pwbuf;
X  do {
X	if (--_bufcnt <= 0) {
X		if ((_bufcnt = read(_pw, _buffer, BUFFERSIZE)) <= 0)
X			return(0);
X		else
X			_pnt = _buffer;
X	}
X	*_buf++ = *_pnt++;
X  } while (*_pnt != '\n' && _buf < _pwbuf + PWBUFSIZE - 1);
X  _pnt++;
X  _bufcnt--;
X  *_buf = '\0';
X  _buf = _pwbuf;
X  return(1);
X}
X
XPRIVATE void skip_period()
X{
X  while (*_buf != ':') _buf++;
X
X  *_buf++ = '\0';
X}
X
XPUBLIC struct passwd *getpwent()
X{
X  if (getline() == 0) return((struct passwd *)NULL);
X
X  _pwd.pw_name = _buf;
X  skip_period();
X  _pwd.pw_passwd = _buf;
X  skip_period();
X  _pwd.pw_uid = (uid_t) atoi(_buf);
X  skip_period();
X  _pwd.pw_gid = (gid_t) atoi(_buf);
X  skip_period();
X  _pwd.pw_gecos = _buf;
X  skip_period();
X  _pwd.pw_dir = _buf;
X  skip_period();
X  _pwd.pw_shell = _buf;
X
X  return(&_pwd);
X}
X
XPUBLIC struct passwd *getpwnam(__name)
X_CONST char *__name;
X{
X  struct passwd *pwd;
X
X  setpwent();
X  while ((pwd = getpwent()) != 0)
X	if (!strcmp(pwd->pw_name, __name)) break;
X  endpwent();
X  if (pwd != 0)
X	return(pwd);
X  else
X	return((struct passwd *)NULL);
X}
X
XPUBLIC struct passwd *getpwuid(__uid)
Xint __uid;
X{
X  struct passwd *pwd;
X
X  setpwent();
X  while ((pwd = getpwent()) != 0)
X	if (pwd->pw_uid == __uid) break;
X  endpwent();
X  if (pwd != 0)
X	return(pwd);
X  else
X	return((struct passwd *)NULL);
X}
/
echo x - getw.c
sed '/^X/s///' > getw.c << '/'
X/*
X * getw - read a word from a stream
X */
X/* $Header: getw.c,v 1.1 89/12/18 14:39:51 eck Exp $ */
X
X#include	<stdio.h>
X
X_PROTOTYPE(int getw, (FILE *stream ));
X
Xint getw(stream)
Xregister FILE *stream;
X{
X	register int cnt = sizeof(int);
X	int w;
X	register char *p = (char *) &w;
X
X	while (cnt--) {
X		*p++ = getc(stream);
X	}
X	if (feof(stream) || ferror(stream)) return EOF;
X	return w;
X}
/
echo x - hypot.c
sed '/^X/s///' > hypot.c << '/'
X/*
X * (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
X * See the copyright notice in the ACK home directory, in the file "Copyright".
X *
X * Author: Ceriel J.H. Jacobs
X */
X
X#include <math.h>
X
Xstruct complex {
X	double r,i;
X};
X
X_PROTOTYPE(double hypot, (double x, double y ));
X_PROTOTYPE(double cabs, (struct complex p_compl ));
X
X/* $Header: hypot.c,v 1.1 91/02/26 18:08:08 ceriel Exp $ */
X
Xdouble
Xhypot(x, y)
Xdouble x, y;
X{
X	/*	Computes sqrt(x*x+y*y), avoiding overflow */
X
X	if (x < 0) x = -x;
X	if (y < 0) y = -y;
X	if (x > y) {
X		double t = y;
X		y = x;
X		x = t;
X	}
X	/* sqrt(x*x+y*y) = sqrt(y*y*(x*x/(y*y)+1.0)) = y*sqrt(x*x/(y*y)+1.0) */
X	if (y == 0.0) return 0.0;
X	x /= y;
X	return y*sqrt(x*x+1.0);
X}
X
Xdouble
Xcabs(p_compl)
Xstruct complex p_compl;
X{
X	return hypot(p_compl.r, p_compl.i);
X}
/
echo x - index.c
sed '/^X/s///' > index.c << '/'
X#include <lib.h>
X/* index - find first occurrence of a character in a string */
X
X#include <string.h>
X
Xchar *index(s, charwanted)	/* found char, or NULL if none */
X_CONST char *s;
Xchar charwanted;
X{
X  return(strchr(s, charwanted));
X}
/
echo x - itoa.c
sed '/^X/s///' > itoa.c << '/'
X#include <lib.h>
X/* Integer to ASCII for signed decimal integers. */
X
XPRIVATE int next;
XPRIVATE char qbuf[8];
X
X_PROTOTYPE( char *itoa, (int n));
X
Xchar *itoa(n)
Xint n;
X{
X  register int r, k;
X  int flag = 0;
X
X  next = 0;
X  if (n < 0) {
X	qbuf[next++] = '-';
X	n = -n;
X  }
X  if (n == 0) {
X	qbuf[next++] = '0';
X  } else {
X	k = 10000;
X	while (k > 0) {
X		r = n / k;
X		if (flag || r > 0) {
X			qbuf[next++] = '0' + r;
X			flag = 1;
X		}
X		n -= r * k;
X		k = k / 10;
X	}
X  }
X  qbuf[next] = 0;
X  return(qbuf);
X}
/
echo x - loadname.c
sed '/^X/s///' > loadname.c << '/'
X#include <lib.h>
X#include <string.h>
X
XPUBLIC void _loadname(name, msgptr)
X_CONST char *name;
Xmessage *msgptr;
X{
X/* This function is used to load a string into a type m3 message. If the
X * string fits in the message, it is copied there.  If not, a pointer to
X * it is passed.
X */
X
X  register size_t k;
X
X  k = strlen(name) + 1;
X  msgptr->m3_i1 = k;
X  msgptr->m3_p1 = (char *) name;
X  if (k <= sizeof msgptr->m3_ca1) strcpy(msgptr->m3_ca1, name);
X}
/
echo x - lock.c
sed '/^X/s///' > lock.c << '/'
X#include <lib.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <stdio.h>
X#if _ANSI
X#include <stdlib.h>
X#endif
X
Xtypedef enum {
X  False, True
X} BOOLEAN;
X
X#define LOCKDIR "/tmp/"		/* or /usr/tmp/ as the case may be */
X#define MAXTRIES 3
X#define NAPTIME (unsigned int)5
X
XPRIVATE _PROTOTYPE( char *lockpath, (char *name));
X_PROTOTYPE( void syserr, (char *errstring));
X_PROTOTYPE( BOOLEAN lock, (char *name));
X_PROTOTYPE( void unlock, (char *name));
X
Xvoid
Xsyserr(errstring)
Xchar *errstring;
X{
X	fprintf(stderr,"couldn't %s\n", errstring);
X	exit(1);
X}
X
XBOOLEAN lock(name)		/* acquire lock */
Xchar *name;
X{
X  char *path;
X  int fd, tries;
X
X  path = lockpath(name);
X  tries = 0;
X  while ((fd = creat(path, 0)) == -1 && errno == EACCES) {
X	if (++tries >= MAXTRIES) return(False);
X	sleep(NAPTIME);
X  }
X  if (fd == -1 || close(fd) == -1) syserr("lock");
X  return(True);
X}
X
Xvoid unlock(name)		/* free lock */
Xchar *name;
X{
X  if (unlink(lockpath(name)) == -1) syserr("unlock");
X}
X
XPRIVATE char *lockpath(name)	/* generate lock file path */
Xchar *name;
X{
X  PRIVATE char path[20];
X
X  strcpy(path, LOCKDIR);
X  return(strcat(path, name));
X}
/
echo x - lrand.c
sed '/^X/s///' > lrand.c << '/'
X/*  lrand(3)
X *
X *  Author: Terrence W. Holm          Nov. 1988
X *
X *
X *  A prime modulus multiplicative linear congruential
X *  generator (PMMLCG), or "Lehmer generator".
X *  Implementation directly derived from the article:
X *
X *	S. K. Park and K. W. Miller
X *	Random Number Generators: Good Ones are Hard to Find
X *	CACM vol 31, #10. Oct. 1988. pp 1192-1201.
X *
X *
X *  Using the following multiplier and modulus, we obtain a
X *  generator which:
X *
X *	1)  Has a full period: 1 to 2^31 - 2.
X *	2)  Is testably "random" (see the article).
X *	3)  Has a known implementation by E. L. Schrage.
X */
X
X#include <lib.h>
X
X_PROTOTYPE( long seed, (long lseed));
X_PROTOTYPE( long lrand, (void));
X
X#define  A	  16807L	/* A "good" multiplier	  */
X#define  M   2147483647L	/* Modulus: 2^31 - 1	  */
X#define  Q       127773L	/* M / A		  */
X#define  R         2836L	/* M % A		  */
X
XPRIVATE long _lseed = 1L;
X
Xlong seed(lseed)
Xlong lseed;
X{
X  long previous_seed = _lseed;
X
X  _lseed = lseed;
X
X  return(previous_seed);
X}
X
X
Xlong lrand()
X{
X  _lseed = A * (_lseed % Q) - R * (_lseed / Q);
X
X  if (_lseed < 0) _lseed += M;
X
X  return(_lseed);
X}
/
echo x - lsearch.c
sed '/^X/s///' > lsearch.c << '/'
X#include <lib.h>
X#include <string.h>
X/*  lsearch(3)  and  lfind(3)
X *
X *  Author: Terrence W. Holm          Sep. 1988
X */
X
X#include <stddef.h>
X
X_PROTOTYPE( char *lsearch, (char *key, char *base,
X			    unsigned *count, unsigned width,
X			    int (*keycmp)(const void *, const void *)));
X_PROTOTYPE( char *lfind, (char *key, char *base,
X			    unsigned *count, unsigned width,
X			    int (*keycmp)(const void *, const void *)));
X
Xchar *lsearch(key, base, count, width, keycmp)
Xchar *key;
Xchar *base;
Xunsigned *count;
Xunsigned width;
X_PROTOTYPE( int (*keycmp), (const void *, const void *));
X{
X  char *entry;
X  char *last = base + *count * width;
X
X  for (entry = base; entry < last; entry += width)
X	if (keycmp(key, entry) == 0) return(entry);
X
X  bcopy(key, last, width);
X  *count += 1;
X  return(last);
X}
X
X
Xchar *lfind(key, base, count, width, keycmp)
Xchar *key;
Xchar *base;
Xunsigned *count;
Xunsigned width;
X_PROTOTYPE( int (*keycmp), (const void *, const void *));
X{
X  char *entry;
X  char *last = base + *count * width;
X
X  for (entry = base; entry < last; entry += width)
X	if (keycmp(key, entry) == 0) return(entry);
X
X  return((char *)NULL);
X}
/
echo x - memccpy.c
sed '/^X/s///' > memccpy.c << '/'
X#include <lib.h>
X/* memccpy - copy bytes up to a certain char
X *
X * CHARBITS should be defined only if the compiler lacks "unsigned char".
X * It should be a mask, e.g. 0377 for an 8-bit machine.
X */
X
X#include <ansi.h>
X#include <stddef.h>
X
X_PROTOTYPE( void *memccpy, (void *dst, const void *src,
X			    int ucharstop, size_t size));
X#ifndef CHARBITS
X#	define	UNSCHAR(c)	((unsigned char)(c))
X#else
X#	define	UNSCHAR(c)	((c)&CHARBITS)
X#endif
X
Xvoid *memccpy(dst, src, ucharstop, size)
Xvoid * dst;
X_CONST void * src;
Xint ucharstop;
X_SIZET size;
X{
X  register char *d;
X  register _CONST char *s;
X  register _SIZET n;
X  register int uc;
X
X  if (size <= 0) return( (void *) NULL);
X
X  s = (char *) src;
X  d = (char *) dst;
X  uc = UNSCHAR(ucharstop);
X  for (n = size; n > 0; n--)
X	if (UNSCHAR(*d++ = *s++) == (char) uc) return( (void *) d);
X
X  return( (void *) NULL);
X}
/
echo x - mktemp.c
sed '/^X/s///' > mktemp.c << '/'
X/* $Header: mktemp.c,v 1.1 91/02/01 10:30:41 ceriel Exp $ */
X/* mktemp - make a name for a temporary file; only here for backwards compat */
X/* no _-protected system-calls? */
X
X#include <sys/types.h>
X#include <unistd.h>
X
Xchar *mktemp(template)
Xchar *template;
X{
X  register int pid, k;
X  register char *p;
X
X  pid = getpid();		/* get process id as semi-unique number */
X  p = template;
X  while (*p) p++;		/* find end of string */
X
X  /* Replace XXXXXX at end of template with pid. */
X  while (*--p == 'X') {
X	*p = '0' + (pid % 10);
X	pid /= 10;
X  }
X  p++;
X  for (k = 'a'; k <= 'z'; k++) {
X	*p = k;
X	if (access(template, 0) < 0) {
X		return template;
X	}
X  }
X  return("/");
X}
/
echo x - mtab.c
sed '/^X/s///' > mtab.c << '/'
X/* This package consists of 4 routines for handling the /etc/mtab file.
X * The /etc/mtab file contains information about the root and mounted file
X * systems as a series of lines, each one with exactly four fields separated 
X * by one space as follows:
X *
X *	special mounted_on version rw_flag
X *
X * where 
X *	special is the name of the block special file
X *	mounted_on is the directory on which it is mounted
X *	version is either 1 or 2 for MINIX V1 and V2 file systems
X *	rw_flag is rw or ro for read/write or read only
X *
X * An example /etc/mtab:
X *
X *	/dev/ram / 2 rw
X *	/dev/hd1 /usr 2 rw
X *	/dev/fd0 /user 1 ro
X *
X *
X * The four routines for handling /etc/mtab are as follows.  They use two
X * (hidden) internal buffers, mtab_in for input and mtab_out for output.
X *
X *	load_mtab(&prog_name)		   - read /etc/mtab into mtab_in
X *	get_mtab_entry(&s1, &s2, &s3, &s4) - arrays that are filled in
X *	put_mtab_entry(&s1, &s2, &s3, &s4) - append a line to mtab_out
X *	rewrite_mtab(&prog_name)	   - write mtab_out to /etc/mtab
X *
X * If load_mtab and rewrite_mtab work, they return 0.  If they fail, they
X * print their own error messages on stderr and return -1.  When get_mtab_entry
X * runs out of entries to return, it sets the first pointer to NULL and returns
X * -1 instead of 0.  Also, rewrite_mtab returns -1 if it fails.
X */
X 
X#include <sys/types.h>
X#include <minix/minlib.h>
X#include <ctype.h>
X#include <fcntl.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X#include <stdio.h>
X
X#define BUF_SIZE   512		  /* size of the /etc/mtab buffer */
X
Xchar *etc_mtab = "/etc/mtab";	  /* name of the /etc/mtab file */
Xstatic char mtab_in[BUF_SIZE+1];  /* holds /etc/mtab when it is read in */
Xstatic char mtab_out[BUF_SIZE+1]; /* buf to build /etc/mtab for output later */
Xstatic char *iptr = mtab_in;	  /* pointer to next line to feed out. */
Xstatic char *optr = mtab_out;	  /* pointer to place where next line goes */
X
X_PROTOTYPE(int load_mtab, (char *prog_name ));
X_PROTOTYPE(int rewrite_mtab, (char *prog_name ));
X_PROTOTYPE(int get_mtab_entry, (char *special, char *mounted_on, 
X					char *version, char *rw_flag));
X_PROTOTYPE(int put_mtab_entry, (char *special, char *mounted_on, 
X					char *version, char *rw_flag));
X_PROTOTYPE(void err, (char *prog_name, char *str ));
X
X
Xint load_mtab(prog_name)
Xchar *prog_name;
X{
X/* Read in /etc/mtab and store it in /etc/mtab. */
X
X  int fd, n;
X  char *ptr;
X
X  /* Open the file. */
X  fd = open(etc_mtab, O_RDONLY);
X  if (fd < 0) {
X	err(prog_name, ": cannot open ");
X	return(-1);
X  }
X
X  /* File opened.  Read it in. */
X  n = read(fd, mtab_in, BUF_SIZE);
X  if (n <= 0) {
X	/* Read failed. */
X	err(prog_name, ": cannot read ");
X	return(-1);
X  }
X  if (n == BUF_SIZE) {
X	/* Some nut has mounted 50 file systems or something like that. */
X	std_err(prog_name);
X	std_err(": file too large: ");
X	std_err(etc_mtab);
X	return(-1);
X  }
X
X  close(fd);
X
X  /* Replace all the whitespace by '\0'. */
X  ptr = mtab_in;
X  while (*ptr != '\0') {
X	if (isspace(*ptr)) *ptr = '\0';
X	ptr++;
X  }
X  return(0);
X}
X
X
Xint rewrite_mtab(prog_name)
Xchar *prog_name;
X{
X/* Write mtab_out to /etc/mtab. */
X
X  int fd, n;
X
X  /* Do a creat to truncate the file. */
X  fd = creat(etc_mtab, 0777);
X  if (fd < 0) {
X	err(prog_name, ": cannot overwrite ");
X	return(-1);
X  }
X
X  /* File created.  Write it. */
X  n = write(fd, mtab_out, (unsigned int)(optr - mtab_out));
X  if (n <= 0) {
X	/* Write failed. */
X	err(prog_name, " could not write ");
X	return(-1);
X  }
X
X  close(fd);
X  return(0);
X}
X
X
Xint get_mtab_entry(special, mounted_on, version, rw_flag)
Xchar *special;
Xchar *mounted_on;
Xchar *version;
Xchar *rw_flag;
X{
X/* Return the next entry from mtab_in. */
X
X  if (iptr >= &mtab_in[BUF_SIZE]) {
X	special[0] = '\0';
X	return(-1);
X  }
X
X  strcpy(special, iptr);
X  while (isprint(*iptr)) iptr++;
X  while (*iptr == '\0'&& iptr < &mtab_in[BUF_SIZE]) iptr++;
X
X  strcpy(mounted_on, iptr);
X  while (isprint(*iptr)) iptr++;
X  while (*iptr == '\0'&& iptr < &mtab_in[BUF_SIZE]) iptr++;
X
X  strcpy(version, iptr);
X  while (isprint(*iptr)) iptr++;
X  while (*iptr == '\0'&& iptr < &mtab_in[BUF_SIZE]) iptr++;
X
X  strcpy(rw_flag, iptr);
X  while (isprint(*iptr)) iptr++;
X  while (*iptr == '\0'&& iptr < &mtab_in[BUF_SIZE]) iptr++;
X  return(0);
X}
X
X
Xint put_mtab_entry(special, mounted_on, version, rw_flag)
Xchar *special;
Xchar *mounted_on;
Xchar *version;
Xchar *rw_flag;
X{
X/* Append an entry to the mtab_out buffer. */
X
X  int n1, n2, n3, n4;
X
X  n1 = strlen(special);
X  n2 = strlen(mounted_on);
X  n3 = strlen(version);
X  n4 = strlen(rw_flag);
X
X  if (optr + n1 + n2 + n3 + n4 + 5 >= &mtab_out[BUF_SIZE]) return(-1);
X  strcpy(optr, special);
X  optr += n1;
X  *optr++ = ' ';
X
X  strcpy(optr, mounted_on);
X  optr += n2;
X  *optr++ = ' ';
X
X  strcpy(optr, version);
X  optr += n3;
X  *optr++ = ' ';
X
X  strcpy(optr, rw_flag);
X  optr += n4;
X  *optr++ = '\n';
X  return(0);
X}
X
X
Xvoid
Xerr(prog_name, str)
Xchar *prog_name, *str;
X{
X  std_err(prog_name); 
X  std_err(str);
X  std_err(etc_mtab);
X  perror(" ");
X}
/
echo x - nlist.c
sed '/^X/s///' > nlist.c << '/'
X/*
X * "nlist.c", Peter Valkenburg, january 1989.
X */
X 
X#include <lib.h>
X#include <string.h>
X#include <a.out.h>
X#include <sys/types.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdio.h>
X
X#define fail(fp)	(fclose(fp), -1)	/* ret. exp. when nlist fails */
X
X_PROTOTYPE( int nlist, (char *file, struct nlist nl[]));
X
X/*
X * Nlist fills fields n_sclass and n_value of array nl with values found in
X * non-stripped executable file.  Entries that are not found have their
X * n_value/n_sclass fields set to 0.  Nl ends with a 0 or nul string n_name.
X * The return value is -1 on failure, else the number of entries not found.
X */
Xint nlist(file, nl)
Xchar *file;
Xstruct nlist nl[];
X{
X	int nents, nsrch, nfound, i;
X	struct nlist nlent;
X	FILE *fp;
X	struct exec hd;
X
X	/* open executable with namelist */
X	if ((fp = fopen(file, "r")) == NULL)
X		return -1;
X		
X	/* get header and seek to start of namelist */	
X	if (fread((char *) &hd, sizeof(struct exec), 1, fp) != 1 ||
X	    BADMAG(hd) || fseek(fp, A_SYMPOS(hd), SEEK_SET) != 0)
X		return fail(fp);
X	
X	/* determine number of entries searched for & reset fields */
X	nsrch = 0;
X	while (nl[nsrch].n_name != NULL && *(nl[nsrch].n_name) != '\0') {
X		nl[nsrch].n_sclass = 0;
X		nl[nsrch].n_value = 0;
X		nl[nsrch].n_type = 0;		/* for compatability */
X		nsrch++;
X	}
X
X	/* loop through namelist & fill in user array */
X	nfound = 0;
X	for (nents = (hd.a_syms & 0xFFFF) / sizeof(struct nlist);
X	     nents > 0; nents--) {
X		if (nsrch == nfound)
X			break;			/* no need to look further */
X		if (fread((char *) &nlent, sizeof(struct nlist), 1, fp) != 1)
X			return fail(fp);	  
X		for (i = 0; i < nsrch; i++)
X			if (nl[i].n_sclass == 0 &&
X			    strncmp(nl[i].n_name, nlent.n_name,
X			    	    sizeof(nlent.n_name)) == 0) {
X				nl[i] = nlent;
X				nfound++;
X				break;
X			}
X	}
X
X	(void) fclose(fp);
X	
X	return nsrch - nfound;
X}
/
echo x - opendir.c
sed '/^X/s///' > opendir.c << '/'
X/* opendir -- open a directory stream	Author: D.A. Gwyn */
X
X/*	last edit:	27-Oct-1988	D A Gwyn	*/
X
X#include <lib.h>
X#include <sys/stat.h>
X#include <dirent.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include <fcntl.h>
X
X#define DULL (DIR *) 0
X#define CULL (char *) 0
X
Xtypedef char *pointer;		/* (void *) if you have it */
X
X#ifndef O_RDONLY
X#define	O_RDONLY	0
X#endif
X
X#ifndef S_ISDIR			/* macro to test for directory file */
X#define	S_ISDIR( mode )		(((mode) & S_IFMT) == S_IFDIR)
X#endif
X
XDIR *opendir(dirname)
X_CONST char *dirname;		/* name of directory */
X{
X  register DIR *dirp;		/* -> malloc'ed storage */
X  register int fd;		/* file descriptor for read */
X
X  /* The following is PRIVATE just to keep the stack small. */
X  PRIVATE struct stat sbuf;	/* result of fstat() */
X
X  if ((fd = open(dirname, O_RDONLY)) < 0)
X	return(DULL);		/* errno set by open() */
X
X  if (fstat(fd, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) {
X	(void) close(fd);
X	errno = ENOTDIR;
X	return(DULL);		/* not a directory */
X  }
X  if ((dirp = (DIR *) malloc(sizeof(DIR))) == DULL
X      || (dirp->dd_buf = (char *) malloc((unsigned) _DIRBUF)) == CULL){
X	register int serrno = errno;
X	/* Errno set to ENOMEM by sbrk() */
X
X	if (dirp != (DIR *) DULL) free((pointer) dirp);
X
X	(void) close(fd);
X	errno = serrno;
X	return(DULL);		/* not enough memory */
X  }
X  dirp->dd_fd = fd;
X  dirp->dd_magic = _DIR_MAGIC;	/* to recognize DIRs */
X  dirp->dd_loc = dirp->dd_size = 0;	/* refill needed */
X
X  return(dirp);
X}
/
echo x - popen.c
sed '/^X/s///' > popen.c << '/'
X/*
X * popen - open a pipe
X */
X/* $Header: popen.c,v 1.3 90/08/28 14:53:34 eck Exp $ */
X
X#include	<sys/types.h>
X#include	<limits.h>
X#include	<errno.h>
X#include	<signal.h>
X#include	<stdio.h>
X
X#if	defined(__BSD4_2)
Xunion wait {
X	int	w_status;
X};
Xtypedef union wait wait_arg;
X#else
Xtypedef int wait_arg;
X#endif	/* __BSD4_2 */
X
X#include	"../stdio/loc_incl.h"
X
X#ifdef _ANSI
Xint _close(int d);
Xint _dup2(int oldd, int newd);		/* not present in System 5 */
Xint _execl(const char *name, const char *_arg, ... );
Xpid_t _fork(void);
Xint _pipe(int fildes[2]);
Xpid_t _wait(wait_arg *status);
Xvoid _exit(int status);
X#endif
X
Xstatic int pids[OPEN_MAX];
X
XFILE *
Xpopen(command, type)
X_CONST char *command;
X_CONST char *type;
X{
X	int piped[2];
X	int Xtype = *type == 'r' ? 0 : *type == 'w' ? 1 : 2;
X	int pid;
X
X	if (Xtype == 2 ||
X	    _pipe(piped) < 0 ||
X	    (pid = _fork()) < 0) return 0;
X	
X	if (pid == 0) {
X		/* child */
X		register int *p;
X
X		for (p = pids; p < &pids[OPEN_MAX]; p++) {
X			if (*p) _close((int)(p - pids));
X		}
X		_close(piped[Xtype]);
X		_dup2(piped[!Xtype], !Xtype);
X		_close(piped[!Xtype]);
X		_execl("/bin/sh", "sh", "-c", command, (char *) 0);
X		_exit(127);	/* like system() ??? */
X	}
X
X	pids[piped[Xtype]] = pid;
X	_close(piped[!Xtype]);
X	return fdopen(piped[Xtype], type);
X}
X
X#if	defined(__BSD4_2)
X#define	ret_val	status.w_status
X#else
X#define	ret_val	status
X#endif
X
Xint
Xpclose(stream)
XFILE *stream;
X{
X	int fd = fileno(stream);
X	wait_arg status;
X	int wret;
X
X#ifdef _ANSI
X	void (*intsave)(int) = signal(SIGINT, SIG_IGN);
X	void (*quitsave)(int) = signal(SIGQUIT, SIG_IGN);
X#else
X	void (*intsave)() = signal(SIGINT, SIG_IGN);
X	void (*quitsave)() = signal(SIGQUIT, SIG_IGN);
X#endif
X	fclose(stream);
X	while ((wret = _wait(&status)) != -1) {
X		if (wret == pids[fd]) break;
X	}
X	if (wret == -1) ret_val = -1;
X	signal(SIGINT, intsave);
X	signal(SIGQUIT, quitsave);
X	pids[fd] = 0;
X	return ret_val;
X}
X
X#if	defined(__USG)
Xint _dup(int fildes);
X
Xstatic int
X_dup2(oldd, newd)
Xint oldd, newd;
X{
X	int i = 0, fd, tmp;
X	int fdbuf[_NFILES];
X
X	/* ignore the error on the close() */
X	tmp = errno; (void) _close(newd); errno = tmp;
X	while ((fd = _dup(oldd)) != newd) {
X		if (fd == -1) break;
X		fdbuf[i++] = fd;
X	}
X	tmp = errno;
X	while (--i >= 0) {
X		_close(fdbuf[i]);
X	}
X	errno = tmp;
X	return -(fd == -1);
X}
X#endif	/* __USG */
/
echo x - printk.c
sed '/^X/s///' > printk.c << '/'
X#include <lib.h>
X#include <stdarg.h>
X
X#define MAXDIG		11	/* 32 bits in radix 8 */
X
X#define GETARG(typ)	va_arg(args, typ)
X
XPRIVATE int Xflag;
X
XPRIVATE _PROTOTYPE(char *_itoa, (char *p, unsigned num, int radix));
XPRIVATE _PROTOTYPE(char *_ltoa, (char *p, unsigned long num, int radix));
X_PROTOTYPE(void putk, (int c));
X_PROTOTYPE( void printk, (char *fmt, int arg1));
X
XPRIVATE char *_itoa(p, num, radix)
Xregister char *p;
Xregister unsigned num;
Xregister radix;
X{
X  register i;
X  register char *q;
X
X  q = p + MAXDIG;
X  do {
X	i = (int) (num % radix);
X	i += '0';
X	if (i > '9') i += (Xflag ? 'A' : 'a') - '0' - 10;
X	*--q = i;
X  } while (num = num / radix);
X  i = p + MAXDIG - q;
X  do
X	*p++ = *q++;
X  while (--i);
X  return(p);
X}
X
XPRIVATE char *_ltoa(p, num, radix)
Xregister char *p;
Xregister unsigned long num;
Xregister radix;
X{
X  register i;
X  register char *q;
X
X  q = p + MAXDIG;
X  do {
X	i = (int) (num % radix);
X	i += '0';
X	if (i > '9') i += 'A' - '0' - 10;
X	*--q = i;
X  } while (num = num / radix);
X  i = p + MAXDIG - q;
X  do
X	*p++ = *q++;
X  while (--i);
X  return(p);
X}
X
Xvoid printk(fmt, arg1)
Xregister char *fmt;
Xint arg1;
X{
X  char buf[MAXDIG + 1];		/* +1 for sign */
X  register int *args = &arg1;
X  register char *p, *s;
X  int c, i, ndfnd, ljust, lflag, zfill;
X  short width, ndigit;
X  long l;
X
X  for (;;) {
X	c = *fmt++;
X	if (c == 0) {
X		/* We are done.  Flush the buffer. */
X		putk(0);
X		return;
X	}
X	if (c != '%') {
X		putk(c);
X		continue;
X	}
X	p = buf;
X	s = buf;
X	ljust = 0;
X	if (*fmt == '-') {
X		fmt++;
X		ljust++;
X	}
X	zfill = ' ';
X	if (*fmt == '0') {
X		fmt++;
X		zfill = '0';
X	}
X	for (width = 0;;) {
X		c = *fmt++;
X		if (c >= '0' && c <= '9')
X			c -= '0';
X		else if (c == '*')
X			c = GETARG(int);
X		else
X			break;
X		width *= 10;
X		width += c;
X	}
X	ndfnd = 0;
X	ndigit = 0;
X	if (c == '.') {
X		for (;;) {
X			c = *fmt++;
X			if (c >= '0' && c <= '9')
X				c -= '0';
X			else if (c == '*')
X				c = GETARG(int);
X			else
X				break;
X			ndigit *= 10;
X			ndigit += c;
X			ndfnd++;
X		}
X	}
X	lflag = 0;
X	Xflag = 0;
X	if (c == 'l' || c == 'L') {
X		lflag++;
X		if (*fmt) c = *fmt++;
X	}
X	switch (c) {
X	    case 'X':
X		Xflag++;
X
X	    case 'x':
X		c = 16;
X		goto oxu;
X
X	    case 'U':
X		lflag++;
X
X	    case 'u':
X		c = 10;
X		goto oxu;
X
X	    case 'O':
X		lflag++;
X
X	    case 'o':
X		c = 8;
X  oxu:
X		if (lflag) {
X			p = _ltoa(p, (unsigned long) GETARG(long), c);
X			break;
X		}
X		p = _itoa(p, (unsigned int) GETARG(int), c);
X		break;
X
X	    case 'D':
X		lflag++;
X
X	    case 'd':
X		if (lflag) {
X			if ((l = GETARG(long)) < 0) {
X				*p++ = '-';
X				l = -l;
X			}
X			p = _ltoa(p, (unsigned long) l, 10);
X			break;
X		}
X		if ((i = GETARG(int)) < 0) {
X			*p++ = '-';
X			i = -i;
X		}
X		p = _itoa(p, (unsigned int) i, 10);
X		break;
X
X	    case 'e':
X	    case 'f':
X	    case 'g':
X		zfill = ' ';
X		*p++ = '?';
X		break;
X
X	    case 'c':
X		zfill = ' ';
X		*p++ = GETARG(int);
X		break;
X
X	    case 's':
X		zfill = ' ';
X		if ((s = GETARG(char *)) == 0) s = "(null)";
X		if (ndigit == 0) ndigit = 32767;
X		for (p = s; *p && --ndigit >= 0; p++);
X		break;
X
X	    default:	*p++ = c;	break;
X	}
X	i = p - s;
X	if ((width -= i) < 0) width = 0;
X	if (ljust == 0) width = -width;
X	if (width < 0) {
X		if (*s == '-' && zfill == '0') {
X			putk( (int) *s);
X			s++;
X			i--;
X		}
X		do
X			putk(zfill);
X		while (++width != 0);
X	}
X	while (--i >= 0) {
X		putk( (int ) *s);
X		s++;
X	}
X	while (width) {
X		putk(zfill);
X		width--;
X	}
X  }
X}
X
/
echo x - putenv.c
sed '/^X/s///' > putenv.c << '/'
X/*
X * (c) copyright 1989 by the Vrije Universiteit, Amsterdam, The Netherlands.
X * See the copyright notice in the ACK home directory, in the file "Copyright".
X */
X/* $Header: putenv.c,v 1.3 90/05/14 12:30:18 ceriel Exp $ */
X
X#include	<stdlib.h>
X#include	<string.h>
X
X_PROTOTYPE(int putenv, (char *name ));
X
X#define	ENTRY_INC	10
X#define	rounded(x)	(((x / ENTRY_INC) + 1) * ENTRY_INC)
X
Xextern _CONST char **environ;
X
Xint
Xputenv(name)
Xchar *name;
X{
X	register _CONST char **v = environ;
X	register char *r;
X	static int size = 0;
X	/* When size != 0, it contains the number of entries in the
X	 * table (including the final NULL pointer). This means that the
X	 * last non-null entry  is environ[size - 2].
X	 */
X
X	if (!name) return 0;
X	if (r = strchr(name, '=')) {
X		register _CONST char *p, *q;
X
X		*r = '\0';
X
X		if (v != NULL) {
X			while ((p = *v) != NULL) {
X				q = name;
X				while (*q && (*q++ == *p++))
X					/* EMPTY */ ;
X				if (*q || (*p != '=')) {
X					v++;
X				} else {
X					/* The name was already in the
X					 * environment.
X					 */
X					*r = '=';
X					*v = name;
X					return 0;
X				}
X			}
X		}
X		*r = '=';
X		v = environ;
X	}
X
X	if (!size) {
X		register _CONST char **p;
X		register int i = 0;
X
X		if (v)
X			do {
X				i++;
X			} while (*v++);
X		if (!(v = malloc(rounded(i) * sizeof(char **))))
X			return 1;
X		size = i;
X		p = environ;
X		environ = v;
X		while (*v++ = *p++);		/* copy the environment */
X		v = environ;
X	} else if (!(size % ENTRY_INC)) {
X		if (!(v = realloc(environ, rounded(size) * sizeof(char **))))
X			return 1;
X		environ = v;
X	}
X	v[size - 1] = name;
X	v[size] = NULL;
X	size++;
X	return 0;
X}
/
echo x - putk.c
sed '/^X/s///' > putk.c << '/'
X#include <lib.h>
X#include <unistd.h>
X
X#define BUF_SIZE 1024
X#define FD          1
X
XPRIVATE char outbuf[BUF_SIZE];
XPRIVATE char *bufp = outbuf;
X_PROTOTYPE( void putk, (int n));
X
Xvoid putk(n)
Xint n;
X{
X/* Print one char on stdout. */
X
X  if (n == 0) {
X	/* putc(0) means flush the buffer. */
X	if (bufp > outbuf) write(FD, outbuf, (int)(bufp - outbuf));
X	bufp = outbuf;
X	return;
X  }
X
X  *bufp++ = (char) n;
X  if (bufp == &outbuf[BUF_SIZE]) {
X	/* The buffer is full.  Flush it. */
X	write(FD, outbuf, BUF_SIZE);
X	bufp = outbuf;
X  }
X}
/
echo x - putw.c
sed '/^X/s///' > putw.c << '/'
X/* 
X * putw - write an word on a stream
X */
X/* $Header: putw.c,v 1.1 89/12/18 14:40:15 eck Exp $ */
X
X#include	<stdio.h>
X
X_PROTOTYPE(int putw, (int w, FILE *stream ));
X
Xint
Xputw(w, stream)
Xint w;
Xregister FILE *stream;
X{
X	register int cnt = sizeof(int);
X	register char *p = (char *) &w;
X
X	while (cnt--) {
X		putc(*p++, stream);
X	}
X	if (ferror(stream)) return EOF;
X	return w;
X}
/
echo x - readdir.c
sed '/^X/s///' > readdir.c << '/'
X/* readdir -- read next entry from a directory stream	Author: D.A. Gwyn */
X
X/*	last edit:	25-Apr-1987	D A Gwyn	*/
X
X#include <lib.h>
X#include <dirent.h>
X#include <stddef.h>
X
X#define DULL (DIR *) NULL
X#define CULL (char *) NULL
X
Xstruct dirent *readdir(dirp)
Xregister DIR *dirp;		/* stream from opendir() */
X{
X  register struct dirent *dp;	/* -> directory data */
X
X  if (dirp == DULL || dirp->dd_buf == CULL || dirp->dd_magic != _DIR_MAGIC) {
X	errno = EBADF;
X	return( (struct dirent *) NULL);	/* invalid pointer */
X  }
X
X  do {
X	if (dirp->dd_loc >= dirp->dd_size)	/* empty or obsolete */
X		dirp->dd_loc = dirp->dd_size = 0;
X
X	if (dirp->dd_size == 0	/* need to refill buffer */
X	    && (dirp->dd_size =
X	     getdents(dirp->dd_fd, dirp->dd_buf, (unsigned) _DIRBUF)) <= 0)
X		return((struct dirent *) NULL);	/* EOF or error */
X
X	dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc];
X	dirp->dd_loc += dp->d_reclen;
X  }
X  while (dp->d_ino == 0);	/* don't rely on getdents() */
X
X  return(dp);
X}
/
echo x - regexp.c
sed '/^X/s///' > regexp.c << '/'
X/* regcomp and regexec -- regsub and regerror are elsewhere
X *
X *	Copyright (c) 1986 by University of Toronto.
X *	Written by Henry Spencer.  Not derived from licensed software.
X *
X *	Permission is granted to anyone to use this software for any
X *	purpose on any computer system, and to redistribute it freely,
X *	subject to the following restrictions:
X *
X *	1. The author is not responsible for the consequences of use of
X *		this software, no matter how awful, even if they arise
X *		from defects in it.
X *
X *	2. The origin of this software must not be misrepresented, either
X *		by explicit claim or by omission.
X *
X *	3. Altered versions must be plainly marked as such, and must not
X *		be misrepresented as being the original software.
X *
X * Beware that some of this code is subtly aware of the way operator
X * precedence is structured in regular expressions.  Serious changes in
X * regular-expression syntax might require a total rethink.
X *
X *	The third parameter to regexec was added by Martin C. Atkins.
X *	Andy Tanenbaum also made some changes.
X */
X
X#include <minix/config.h>
X#include <minix/const.h>
X#include <stdlib.h>
X#include <string.h>
X#include <regexp.h>
X#include <stdio.h>
X
X/* The first byte of the regexp internal "program" is actually this magic
X * number; the start node begins in the second byte.
X */
X#define	MAGIC	0234
X
X/* The "internal use only" fields in regexp.h are present to pass info from
X * compile to execute that permits the execute phase to run lots faster on
X * simple cases.  They are:
X *
X * regstart	char that must begin a match; '\0' if none obvious
X * reganch	is the match anchored (at beginning-of-line only)?
X * regmust	string (pointer into program) that match must include, or NULL
X * regmlen	length of regmust string
X *
X * Regstart and reganch permit very fast decisions on suitable starting points
X * for a match, cutting down the work a lot.  Regmust permits fast rejection
X * of lines that cannot possibly match.  The regmust tests are costly enough
X * that regcomp() supplies a regmust only if the r.e. contains something
X * potentially expensive (at present, the only such thing detected is * or +
X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
X * supplied because the test in regexec() needs it and regcomp() is computing
X * it anyway.
X */
X
X/* Structure for regexp "program".  This is essentially a linear encoding
X * of a nondeterministic finite-state machine (aka syntax charts or
X * "railroad normal form" in parsing technology).  Each node is an opcode
X * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
X * all nodes except BRANCH implement concatenation; a "next" pointer with
X * a BRANCH on both ends of it is connecting two alternatives.  (Here we
X * have one of the subtle syntax dependencies:  an individual BRANCH (as
X * opposed to a collection of them) is never concatenated with anything
X * because of operator precedence.)  The operand of some types of node is
X * a literal string; for others, it is a node leading into a sub-FSM.  In
X * particular, the operand of a BRANCH node is the first node of the branch.
X * (NB this is *not* a tree structure:  the tail of the branch connects
X * to the thing following the set of BRANCHes.)  The opcodes are:
X */
X
X/* Definition	number	opnd?	meaning */
X#define	END	0		/* no	End of program. */
X#define	BOL	1		/* no	Match "" at beginning of line. */
X#define	EOL	2		/* no	Match "" at end of line. */
X#define	ANY	3		/* no	Match any one character. */
X#define	ANYOF	4		/* str	Match any character in this string. */
X#define	ANYBUT	5		/* str	Match any character not in this
X			 * string. */
X#define	BRANCH	6		/* node	Match this alternative, or the
X			 * next... */
X#define	BACK	7		/* no	Match "", "next" ptr points backward. */
X#define	EXACTLY	8		/* str	Match this string. */
X#define	NOTHING	9		/* no	Match empty string. */
X#define	STAR	10		/* node	Match this (simple) thing 0 or more
X			 * times. */
X#define	PLUS	11		/* node	Match this (simple) thing 1 or more
X			 * times. */
X#define	OPEN	20		/* no	Mark this point in input as start of
X			 * #n. */
X /* OPEN+1 is number 1, etc. */
X#define	CLOSE	30		/* no	Analogous to OPEN. */
X
X/* Opcode notes:
X *
X * BRANCH	The set of branches constituting a single choice are hooked
X *		together with their "next" pointers, since precedence prevents
X *		anything being concatenated to any individual branch.  The
X *		"next" pointer of the last BRANCH in a choice points to the
X *		thing following the whole choice.  This is also where the
X *		final "next" pointer of each individual branch points; each
X *		branch starts with the operand node of a BRANCH node.
X *
X * BACK		Normal "next" pointers all implicitly point forward; BACK
X *		exists to make loop structures possible.
X *
X * STAR,PLUS	'?', and complex '*' and '+', are implemented as circular
X *		BRANCH structures using BACK.  Simple cases (one character
X *		per match) are implemented with STAR and PLUS for speed
X *		and to minimize recursive plunges.
X *
X * OPEN,CLOSE	...are numbered at compile time.
X */
X
X/* A node is one char of opcode followed by two chars of "next" pointer.
X * "Next" pointers are stored as two 8-bit pieces, high order first.  The
X * value is a positive offset from the opcode of the node containing it.
X * An operand, if any, simply follows the node.  (Note that much of the
X * code generation knows about this implicit relationship.)
X *
X * Using two bytes for the "next" pointer is vast overkill for most things,
X * but allows patterns to get big without disasters.
X */
X#define	OP(p)	(*(p))
X#define	NEXT(p)	(((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
X#define	OPERAND(p)	((p) + 3)
X
X/* Utility definitions.
X */
X#ifndef CHARBITS
X#define	UCHARAT(p)	((int)*(unsigned char *)(p))
X#else
X#define	UCHARAT(p)	((int)*(p)&CHARBITS)
X#endif
X
X#define	CFAIL(m)	{ regerror(m); return((char *)NULL); }
X#define	RFAIL(m)	{ regerror(m); return((regexp *)NULL); }
X#define	ISMULT(c)	((c) == '*' || (c) == '+' || (c) == '?')
X#define	META	"^$.[()|?+*\\"
X
X/* Flags to be passed up and down.
X */
X#define	HASWIDTH	01	/* Known never to match null string. */
X#define	SIMPLE		02	/* Simple enough to be STAR/PLUS operand. */
X#define	SPSTART		04	/* Starts with * or +. */
X#define	WORST		0	/* Worst case. */
X
X/* Global work variables for regcomp().
X */
XPRIVATE char *regparse;		/* Input-scan pointer. */
XPRIVATE int regnpar;		/* () count. */
XPRIVATE char regdummy;
XPRIVATE char *regcode;		/* Code-emit pointer; &regdummy = don't. */
XPRIVATE long regsize;		/* Code size. */
X
X/* Forward declarations for regcomp()'s friends.
X */
X#ifndef STATIC
X#define	STATIC	PRIVATE
X#endif
XSTATIC _PROTOTYPE( char *reg, (int paren, int *flagp)			);
XSTATIC _PROTOTYPE( char *regbranch, (int *flagp)			);
XSTATIC _PROTOTYPE( char *regpiece, (int *flagp)				);
XSTATIC _PROTOTYPE( char *regatom, (int *flagp)				);
XSTATIC _PROTOTYPE( char *regnode, (int op)				);
XSTATIC _PROTOTYPE( char *regnext, (char *p)				);
XSTATIC _PROTOTYPE( void regc, (int b)					);
XSTATIC _PROTOTYPE( void reginsert, (int op, char *opnd)			);
XSTATIC _PROTOTYPE( void regtail, (char *p, char *val)			);
XSTATIC _PROTOTYPE( void regoptail, (char *p, char *val)			);
X
X/*
X - regcomp - compile a regular expression into internal code
X *
X * We can't allocate space until we know how big the compiled form will be,
X * but we can't compile it (and thus know how big it is) until we've got a
X * place to put the code.  So we cheat:  we compile it twice, once with code
X * generation turned off and size counting turned on, and once "for real".
X * This also means that we don't allocate space until we are sure that the
X * thing really will compile successfully, and we never have to move the
X * code and thus invalidate pointers into it.  (Note that it has to be in
X * one piece because free() must be able to free it all.)
X *
X * Beware that the optimization-preparation code in here knows about some
X * of the structure of the compiled regexp.
X */
Xregexp *regcomp(exp)
Xchar *exp;
X{
X  register regexp *r;
X  register char *scan;
X  register char *longest;
X  register int len;
X  int flags;
X
X  if (exp == (char *)NULL) RFAIL("NULL argument");
X
X  /* First pass: determine size, legality. */
X  regparse = exp;
X  regnpar = 1;
X  regsize = 0L;
X  regcode = &regdummy;
X  regc(MAGIC);
X  if (reg(0, &flags) == (char *)NULL) return((regexp *)NULL);
X
X  /* Small enough for pointer-storage convention? */
X  if (regsize >= 32767L)	/* Probably could be 65535L. */
X	RFAIL("regexp too big");
X
X  /* Allocate space. */
X  r = (regexp *) malloc(sizeof(regexp) + (unsigned) regsize);
X  if (r == (regexp *)NULL) RFAIL("out of space");
X
X  /* Second pass: emit code. */
X  regparse = exp;
X  regnpar = 1;
X  regcode = r->program;
X  regc(MAGIC);
X  if (reg(0, &flags) == (char *)NULL) return((regexp *)NULL);
X
X  /* Dig out information for optimizations. */
X  r->regstart = '\0';		/* Worst-case defaults. */
X  r->reganch = 0;
X  r->regmust = (char *)NULL;
X  r->regmlen = 0;
X  scan = r->program + 1;	/* First BRANCH. */
X  if (OP(regnext(scan)) == END) {	/* Only one top-level choice. */
X	scan = OPERAND(scan);
X
X	/* Starting-point info. */
X	if (OP(scan) == EXACTLY)
X		r->regstart = *OPERAND(scan);
X	else if (OP(scan) == BOL)
X		r->reganch++;
X
X	/* If there's something expensive in the r.e., find the
X	 * longest literal string that must appear and make it the
X	 * regmust.  Resolve ties in favor of later strings, since
X	 * the regstart check works with the beginning of the r.e.
X	 * and avoiding duplication strengthens checking.  Not a
X	 * strong reason, but sufficient in the absence of others. */
X	if (flags & SPSTART) {
X		longest = (char *)NULL;
X		len = 0;
X		for (; scan != (char *)NULL; scan = regnext(scan))
X			if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
X				longest = OPERAND(scan);
X				len = strlen(OPERAND(scan));
X			}
X		r->regmust = longest;
X		r->regmlen = len;
X	}
X  }
X  return(r);
X}
X
X/*
X - reg - regular expression, i.e. main body or parenthesized thing
X *
X * Caller must absorb opening parenthesis.
X *
X * Combining parenthesis handling with the base level of regular expression
X * is a trifle forced, but the need to tie the tails of the branches to what
X * follows makes it hard to avoid.
X */
XPRIVATE char *reg(paren, flagp)
Xint paren;			/* Parenthesized? */
Xint *flagp;
X{
X  register char *ret;
X  register char *br;
X  register char *ender;
X  register int parno;
X  int flags;
X
X  *flagp = HASWIDTH;		/* Tentatively. */
X
X  /* Make an OPEN node, if parenthesized. */
X  if (paren) {
X	if (regnpar >= NSUBEXP) CFAIL("too many ()");
X	parno = regnpar;
X	regnpar++;
X	ret = regnode(OPEN + parno);
X  } else {
X	parno = 0;		/* not actually used, keep compiler quiet */
X	ret = (char *)NULL;
X  }
X
X  /* Pick up the branches, linking them together. */
X  br = regbranch(&flags);
X  if (br == (char *)NULL) return((char *)NULL);
X  if (ret != (char *)NULL)
X	regtail(ret, br);	/* OPEN -> first. */
X  else
X	ret = br;
X  if (!(flags & HASWIDTH)) *flagp &= ~HASWIDTH;
X  *flagp |= flags & SPSTART;
X  while (*regparse == '|') {
X	regparse++;
X	br = regbranch(&flags);
X	if (br == (char *)NULL) return((char *)NULL);
X	regtail(ret, br);	/* BRANCH -> BRANCH. */
X	if (!(flags & HASWIDTH)) *flagp &= ~HASWIDTH;
X	*flagp |= flags & SPSTART;
X  }
X
X  /* Make a closing node, and hook it on the end. */
X  ender = regnode((paren) ? CLOSE + parno : END);
X  regtail(ret, ender);
X
X  /* Hook the tails of the branches to the closing node. */
X  for (br = ret; br != (char *)NULL; br = regnext(br)) regoptail(br, ender);
X
X  /* Check for proper termination. */
X  if (paren && *regparse++ != ')') {
X	CFAIL("unmatched ()");
X  } else if (!paren && *regparse != '\0') {
X	if (*regparse == ')') {
X		CFAIL("unmatched ()");
X	} else
X		CFAIL("junk on end");	/* "Can't happen". */
X	/* NOTREACHED */
X  }
X  return(ret);
X}
X
X/*
X - regbranch - one alternative of an | operator
X *
X * Implements the concatenation operator.
X */
XPRIVATE char *regbranch(flagp)
Xint *flagp;
X{
X  register char *ret;
X  register char *chain;
X  register char *latest;
X  int flags;
X
X  *flagp = WORST;		/* Tentatively. */
X
X  ret = regnode(BRANCH);
X  chain = (char *)NULL;
X  while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
X	latest = regpiece(&flags);
X	if (latest == (char *)NULL) return((char *)NULL);
X	*flagp |= flags & HASWIDTH;
X	if (chain == (char *)NULL)	/* First piece. */
X		*flagp |= flags & SPSTART;
X	else
X		regtail(chain, latest);
X	chain = latest;
X  }
X  if (chain == (char *)NULL)		/* Loop ran zero times. */
X	regnode(NOTHING);
X
X  return(ret);
X}
X
X/*
X - regpiece - something followed by possible [*+?]
X *
X * Note that the branching code sequences used for ? and the general cases
X * of * and + are somewhat optimized:  they use the same NOTHING node as
X * both the endmarker for their branch list and the body of the last branch.
X * It might seem that this node could be dispensed with entirely, but the
X * endmarker role is not redundant.
X */
XPRIVATE char *regpiece(flagp)
Xint *flagp;
X{
X  register char *ret;
X  register char op;
X  register char *next;
X  int flags;
X
X  ret = regatom(&flags);
X  if (ret == (char *)NULL) return((char *)NULL);
X
X  op = *regparse;
X  if (!ISMULT(op)) {
X	*flagp = flags;
X	return(ret);
X  }
X  if (!(flags & HASWIDTH) && op != '?') CFAIL("*+ operand could be empty");
X  *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
X
X  if (op == '*' && (flags & SIMPLE))
X	reginsert(STAR, ret);
X  else if (op == '*') {
X	/* Emit x* as (x&|), where & means "self". */
X	reginsert(BRANCH, ret);	/* Either x */
X	regoptail(ret, regnode(BACK));	/* and loop */
X	regoptail(ret, ret);	/* back */
X	regtail(ret, regnode(BRANCH));	/* or */
X	regtail(ret, regnode(NOTHING));	/* null. */
X  } else if (op == '+' && (flags & SIMPLE))
X	reginsert(PLUS, ret);
X  else if (op == '+') {
X	/* Emit x+ as x(&|), where & means "self". */
X	next = regnode(BRANCH);	/* Either */
X	regtail(ret, next);
X	regtail(regnode(BACK), ret);	/* loop back */
X	regtail(next, regnode(BRANCH));	/* or */
X	regtail(ret, regnode(NOTHING));	/* null. */
X  } else if (op == '?') {
X	/* Emit x? as (x|) */
X	reginsert(BRANCH, ret);	/* Either x */
X	regtail(ret, regnode(BRANCH));	/* or */
X	next = regnode(NOTHING);/* null. */
X	regtail(ret, next);
X	regoptail(ret, next);
X  }
X  regparse++;
X  if (ISMULT(*regparse)) CFAIL("nested *?+");
X
X  return(ret);
X}
X
X/*
X - regatom - the lowest level
X *
X * Optimization:  gobbles an entire sequence of ordinary characters so that
X * it can turn them into a single node, which is smaller to store and
X * faster to run.  Backslashed characters are exceptions, each becoming a
X * separate node; the code is simpler that way and it's not worth fixing.
X */
XPRIVATE char *regatom(flagp)
Xint *flagp;
X{
X  register char *ret;
X  int flags;
X
X  *flagp = WORST;		/* Tentatively. */
X
X  switch (*regparse++) {
X      case '^':	ret = regnode(BOL);	  	break;
X      case '$':	ret = regnode(EOL);	  	break;
X      case '.':
X	ret = regnode(ANY);
X	*flagp |= HASWIDTH | SIMPLE;
X	break;
X      case '[':{
X		register int class;
X		register int classend;
X
X		if (*regparse == '^') {	/* Complement of range. */
X			ret = regnode(ANYBUT);
X			regparse++;
X		} else
X			ret = regnode(ANYOF);
X		if (*regparse == ']' || *regparse == '-') regc(*regparse++);
X		while (*regparse != '\0' && *regparse != ']') {
X			if (*regparse == '-') {
X				regparse++;
X				if (*regparse == ']' || *regparse == '\0')
X					regc('-');
X				else {
X					class = UCHARAT(regparse - 2) + 1;
X					classend = UCHARAT(regparse);
X					if (class > classend + 1)
X						CFAIL("invalid [] range");
X					for (; class <= classend; class++)
X						regc(class);
X					regparse++;
X				}
X			} else
X				regc(*regparse++);
X		}
X		regc('\0');
X		if (*regparse != ']') CFAIL("unmatched []");
X		regparse++;
X		*flagp |= HASWIDTH | SIMPLE;
X	}
X	break;
X      case '(':
X	ret = reg(1, &flags);
X	if (ret == (char *)NULL) return((char *)NULL);
X	*flagp |= flags & (HASWIDTH | SPSTART);
X	break;
X      case '\0':
X      case '|':
X      case ')':
X	CFAIL("internal urp");	/* Supposed to be caught earlier. */
X	break;
X      case '?':
X      case '+':
X      case '*':	CFAIL("?+* follows nothing");	  	break;
X      case '\\':
X	if (*regparse == '\0') CFAIL("trailing \\");
X	ret = regnode(EXACTLY);
X	regc(*regparse++);
X	regc('\0');
X	*flagp |= HASWIDTH | SIMPLE;
X	break;
X      default:{
X		register int len;
X		register char ender;
X
X		regparse--;
X		len = strcspn(regparse, META);
X		if (len <= 0) CFAIL("internal disaster");
X		ender = *(regparse + len);
X		if (len > 1 && ISMULT(ender))
X			len--;	/* Back off clear of ?+* operand. */
X		*flagp |= HASWIDTH;
X		if (len == 1) *flagp |= SIMPLE;
X		ret = regnode(EXACTLY);
X		while (len > 0) {
X			regc(*regparse++);
X			len--;
X		}
X		regc('\0');
X	}
X	break;
X  }
X
X  return(ret);
X}
X
X/*
X - regnode - emit a node
X */
XPRIVATE char *regnode(op)
Xchar op;
X{
X  register char *ret;
X  register char *ptr;
X
X  ret = regcode;
X  if (ret == &regdummy) {
X	regsize += 3;
X	return(ret);
X  }
X  ptr = ret;
X  *ptr++ = op;
X  *ptr++ = '\0';		/* Null "next" pointer. */
X  *ptr++ = '\0';
X  regcode = ptr;
X
X  return(ret);
X}
X
X/*
X - regc - emit (if appropriate) a byte of code
X */
XPRIVATE void regc(b)
Xchar b;
X{
X  if (regcode != &regdummy)
X	*regcode++ = b;
X  else
X	regsize++;
X}
X
X/*
X - reginsert - insert an operator in front of already-emitted operand
X *
X * Means relocating the operand.
X */
XPRIVATE void reginsert(op, opnd)
Xchar op;
Xchar *opnd;
X{
X  register char *src;
X  register char *dst;
X  register char *place;
X
X  if (regcode == &regdummy) {
X	regsize += 3;
X	return;
X  }
X  src = regcode;
X  regcode += 3;
X  dst = regcode;
X  while (src > opnd) *--dst = *--src;
X
X  place = opnd;			/* Op node, where operand used to be. */
X  *place++ = op;
X  *place++ = '\0';
X  *place++ = '\0';
X}
X
X/*
X - regtail - set the next-pointer at the end of a node chain
X */
XPRIVATE void regtail(p, val)
Xchar *p;
Xchar *val;
X{
X  register char *scan;
X  register char *temp;
X  register int offset;
X
X  if (p == &regdummy) return;
X
X  /* Find last node. */
X  scan = p;
X  for (;;) {
X	temp = regnext(scan);
X	if (temp == (char *)NULL) break;
X	scan = temp;
X  }
X
X  if (OP(scan) == BACK)
X	offset = scan - val;
X  else
X	offset = val - scan;
X  *(scan + 1) = (offset >> 8) & 0377;
X  *(scan + 2) = offset & 0377;
X}
X
X/*
X - regoptail - regtail on operand of first argument; nop if operandless
X */
XPRIVATE void regoptail(p, val)
Xchar *p;
Xchar *val;
X{
X  /* "Operandless" and "op != BRANCH" are synonymous in practice. */
X  if (p == (char *)NULL || p == &regdummy || OP(p) != BRANCH) return;
X  regtail(OPERAND(p), val);
X}
X
X/* regexec and friends
X */
X
X/* Global work variables for regexec().
X */
XPRIVATE char *reginput;		/* String-input pointer. */
XPRIVATE char *regbol;		/* Beginning of input, for ^ check. */
XPRIVATE char **regstartp;	/* Pointer to startp array. */
XPRIVATE char **regendp;		/* Ditto for endp. */
X
X/* Forwards.
X */
XSTATIC _PROTOTYPE( int regtry, (regexp *prog, char *string)		);
XSTATIC _PROTOTYPE( int regmatch, (char *prog)				);
XSTATIC _PROTOTYPE( int regrepeat, (char *p)				);
X
X#ifdef DEBUG
Xint regnarrate = 0;
Xvoid regdump();
XSTATIC _PROTOTYPE( char *regprop, (char *op)				);
X#endif
X
X/*
X - regexec - match a regexp against a string
X */
Xint regexec(prog, string, bolflag)
Xregister regexp *prog;
Xregister char *string;
Xint bolflag;
X{
X  register char *s;
X
X  /* Be paranoid... */
X  if (prog == (regexp *)NULL || string == (char *)NULL) {
X	regerror("NULL parameter");
X	return(0);
X  }
X
X  /* Check validity of program. */
X  if (UCHARAT(prog->program) != MAGIC) {
X	regerror("corrupted program");
X	return(0);
X  }
X
X  /* If there is a "must appear" string, look for it. */
X  if (prog->regmust != (char *)NULL) {
X	s = string;
X	while ((s = strchr(s, prog->regmust[0])) != (char *)NULL) {
X		if (strncmp(s, prog->regmust, prog->regmlen) == 0)
X			break;	/* Found it. */
X		s++;
X	}
X	if (s == (char *)NULL)		/* Not present. */
X		return(0);
X  }
X
X  /* Mark beginning of line for ^ . */
X  if (bolflag)
X	regbol = string;
X  else
X	regbol = (char *)NULL;
X
X  /* Simplest case:  anchored match need be tried only once. */
X  if (prog->reganch) return(regtry(prog, string));
X
X  /* Messy cases:  unanchored match. */
X  s = string;
X  if (prog->regstart != '\0') 	/* We know what char it must start with. */
X	while ((s = strchr(s, prog->regstart)) != (char *)NULL) {
X		if (regtry(prog, s)) return(1);
X		s++;
X	}
X  else
X	/* We don't -- general case. */
X	do {
X		if (regtry(prog, s)) return(1);
X	} while (*s++ != '\0');
X
X  /* Failure. */
X  return(0);
X}
X
X/*
X - regtry - try match at specific point
X */
XPRIVATE int regtry(prog, string)   /* 0 failure, 1 success */
Xregexp *prog;
Xchar *string;
X{
X  register int i;
X  register char **sp;
X  register char **ep;
X
X  reginput = string;
X  regstartp = prog->startp;
X  regendp = prog->endp;
X
X  sp = prog->startp;
X  ep = prog->endp;
X  for (i = NSUBEXP; i > 0; i--) {
X	*sp++ = (char *)NULL;
X	*ep++ = (char *)NULL;
X  }
X  if (regmatch(prog->program + 1)) {
X	prog->startp[0] = string;
X	prog->endp[0] = reginput;
X	return(1);
X  } else
X	return(0);
X}
X
X/*
X - regmatch - main matching routine
X *
X * Conceptually the strategy is simple:  check to see whether the current
X * node matches, call self recursively to see whether the rest matches,
X * and then act accordingly.  In practice we make some effort to avoid
X * recursion, in particular by going through "ordinary" nodes (that don't
X * need to know whether the rest of the match failed) by a loop instead of
X * by recursion.
X */
XPRIVATE int regmatch(prog)	/* 0 failure, 1 success */ 
Xchar *prog;
X{
X  register char *scan;		/* Current node. */
X  char *next;			/* Next node. */
X
X  scan = prog;
X#ifdef DEBUG
X  if (scan != (char *)NULL && regnarrate) fprintf(stderr, "%s(\n", regprop(scan));
X#endif
X  while (scan != (char *)NULL) {
X#ifdef DEBUG
X	if (regnarrate) fprintf(stderr, "%s...\n", regprop(scan));
X#endif
X	next = regnext(scan);
X
X	switch (OP(scan)) {
X	    case BOL:
X		if (reginput != regbol) return(0);
X		break;
X	    case EOL:
X		if (*reginput != '\0') return(0);
X		break;
X	    case ANY:
X		if (*reginput == '\0') return(0);
X		reginput++;
X		break;
X	    case EXACTLY:{
X			register int len;
X			register char *opnd;
X
X			opnd = OPERAND(scan);
X			/* Inline the first character, for speed. */
X			if (*opnd != *reginput) return(0);
X			len = strlen(opnd);
X			if (len > 1 && strncmp(opnd, reginput, len) != 0)
X				return(0);
X			reginput += len;
X		}
X		break;
X	    case ANYOF:
X		if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == (char *)NULL)
X			return(0);
X		reginput++;
X		break;
X	    case ANYBUT:
X		if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != (char *)NULL)
X			return(0);
X		reginput++;
X		break;
X	    case NOTHING:
X		break;
X	    case BACK:
X		break;
X	    case OPEN + 1:
X	    case OPEN + 2:
X	    case OPEN + 3:
X	    case OPEN + 4:
X	    case OPEN + 5:
X	    case OPEN + 6:
X	    case OPEN + 7:
X	    case OPEN + 8:
X	    case OPEN + 9:{
X			register int no;
X			register char *save;
X
X			no = OP(scan) - OPEN;
X			save = reginput;
X
X			if (regmatch(next)) {
X				/* Don't set startp if some later
X				 * invocation of the same parentheses
X				 * already has. */
X				if (regstartp[no] == (char *)NULL)
X					regstartp[no] = save;
X				return(1);
X			} else
X				return(0);
X		}
X		break;
X	    case CLOSE + 1:
X	    case CLOSE + 2:
X	    case CLOSE + 3:
X	    case CLOSE + 4:
X	    case CLOSE + 5:
X	    case CLOSE + 6:
X	    case CLOSE + 7:
X	    case CLOSE + 8:
X	    case CLOSE + 9:{
X			register int no;
X			register char *save;
X
X			no = OP(scan) - CLOSE;
X			save = reginput;
X
X			if (regmatch(next)) {
X				/* Don't set endp if some later
X				 * invocation of the same parentheses
X				 * already has. */
X				if (regendp[no] == (char *)NULL) regendp[no] = save;
X				return(1);
X			} else
X				return(0);
X		}
X		break;
X	    case BRANCH:{
X			register char *save;
X
X			if (OP(next) != BRANCH)	/* No choice. */
X				next = OPERAND(scan);	/* Avoid recursion. */
X			else {
X				do {
X					save = reginput;
X					if (regmatch(OPERAND(scan)))
X						return(1);
X					reginput = save;
X					scan = regnext(scan);
X				} while (scan != (char *)NULL && OP(scan) == BRANCH);
X				return(0);
X				/* NOTREACHED */
X			}
X		}
X		break;
X	    case STAR:
X	    case PLUS:{
X			register char nextch;
X			register int no;
X			register char *save;
X			register int min;
X
X			/* Lookahead to avoid useless match attempts
X			 * when we know what character comes next. */
X			nextch = '\0';
X			if (OP(next) == EXACTLY) nextch = *OPERAND(next);
X			min = (OP(scan) == STAR) ? 0 : 1;
X			save = reginput;
X			no = regrepeat(OPERAND(scan));
X			while (no >= min) {
X				/* If it could work, try it. */
X				if (nextch == '\0' || *reginput == nextch)
X					if (regmatch(next)) return(1);
X				/* Couldn't or didn't -- back up. */
X				no--;
X				reginput = save + no;
X			}
X			return(0);
X		}
X		break;
X	    case END:
X		return(1);	/* Success! */
X		break;
X	    default:
X		regerror("memory corruption");
X		return(0);
X		break;
X	}
X
X	scan = next;
X  }
X
X  /* We get here only if there's trouble -- normally "case END" is the
X   * terminating point. */
X  regerror("corrupted pointers");
X  return(0);
X}
X
X/*
X - regrepeat - repeatedly match something simple, report how many
X */
XPRIVATE int regrepeat(p)
Xchar *p;
X{
X  register int count = 0;
X  register char *scan;
X  register char *opnd;
X
X  scan = reginput;
X  opnd = OPERAND(p);
X  switch (OP(p)) {
X      case ANY:
X	count = strlen(scan);
X	scan += count;
X	break;
X      case EXACTLY:
X	while (*opnd == *scan) {
X		count++;
X		scan++;
X	}
X	break;
X      case ANYOF:
X	while (*scan != '\0' && strchr(opnd, *scan) != (char *)NULL) {
X		count++;
X		scan++;
X	}
X	break;
X      case ANYBUT:
X	while (*scan != '\0' && strchr(opnd, *scan) == (char *)NULL) {
X		count++;
X		scan++;
X	}
X	break;
X      default:			/* Oh dear.  Called inappropriately. */
X	regerror("internal foulup");
X	count = 0;		/* Best compromise. */
X	break;
X  }
X  reginput = scan;
X
X  return(count);
X}
X
X/*
X - regnext - dig the "next" pointer out of a node
X */
XPRIVATE char *regnext(p)
Xregister char *p;
X{
X  register int offset;
X
X  if (p == &regdummy) return((char *)NULL);
X
X  offset = NEXT(p);
X  if (offset == 0) return((char *)NULL);
X
X  if (OP(p) == BACK)
X	return(p - offset);
X  else
X	return(p + offset);
X}
X
X#ifdef DEBUG
X
XSTATIC char *regprop();
X
X/*
X - regdump - dump a regexp onto stdout in vaguely comprehensible form
X */
Xvoid regdump(r)
Xregexp *r;
X{
X  register char *s;
X  register char op = EXACTLY;	/* Arbitrary non-END op. */
X  register char *next;
X
X  s = r->program + 1;
X  while (op != END) {		/* While that wasn't END last time... */
X	op = OP(s);
X	printf("%2d%s", (int) (s - r->program), regprop(s));	/* Where, what. */
X	next = regnext(s);
X	if (next == (char *)NULL)	/* Next ptr. */
X		printf("(0)");
X	else
X		printf("(%d)", (int) (s - r->program) + (int) (next - s));
X	s += 3;
X	if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
X		/* Literal string, where present. */
X		while (*s != '\0') {
X			putchar(*s);
X			s++;
X		}
X		s++;
X	}
X	putchar('\n');
X  }
X
X  /* Header fields of interest. */
X  if (r->regstart != '\0') printf("start `%c' ", r->regstart);
X  if (r->reganch) printf("anchored ");
X  if (r->regmust != (char *)NULL) printf("must have \"%s\"", r->regmust);
X  printf("\n");
X}
X
X/*
X - regprop - printable representation of opcode
X */
XPRIVATE char *regprop(op)
Xchar *op;
X{
X  register char *p;
X  PRIVATE char buf[50];
X
X  (void) strcpy(buf, ":");
X
X  switch (OP(op)) {
X      case BOL:	p = "BOL";	  	break;
X      case EOL:	p = "EOL";	  	break;
X      case ANY:	p = "ANY";	  	break;
X      case ANYOF:	p = "ANYOF";	  	break;
X      case ANYBUT:	p = "ANYBUT";	  	break;
X      case BRANCH:	p = "BRANCH";	  	break;
X      case EXACTLY:	p = "EXACTLY";	  	break;
X      case NOTHING:	p = "NOTHING";	  	break;
X      case BACK:	p = "BACK";	  	break;
X      case END:	p = "END";	  	break;
X      case OPEN + 1:
X      case OPEN + 2:
X      case OPEN + 3:
X      case OPEN + 4:
X      case OPEN + 5:
X      case OPEN + 6:
X      case OPEN + 7:
X      case OPEN + 8:
X      case OPEN + 9:
X	sprintf(buf + strlen(buf), "OPEN%d", OP(op) - OPEN);
X	p = (char *)NULL;
X	break;
X      case CLOSE + 1:
X      case CLOSE + 2:
X      case CLOSE + 3:
X      case CLOSE + 4:
X      case CLOSE + 5:
X      case CLOSE + 6:
X      case CLOSE + 7:
X      case CLOSE + 8:
X      case CLOSE + 9:
X	sprintf(buf + strlen(buf), "CLOSE%d", OP(op) - CLOSE);
X	p = (char *)NULL;
X	break;
X      case STAR:	p = "STAR";	  	break;
X      case PLUS:	p = "PLUS";	  	break;
X      default:	regerror("corrupted opcode"); p = (char *) NULL; break;
X  }
X  if (p != (char *)NULL) (void) strcat(buf, p);
X  return(buf);
X}
X
X#endif
/
echo x - regsub.c
sed '/^X/s///' > regsub.c << '/'
X/* regsub
X *
X *	Copyright (c) 1986 by University of Toronto.
X *	Written by Henry Spencer.  Not derived from licensed software.
X *
X *	Permission is granted to anyone to use this software for any
X *	purpose on any computer system, and to redistribute it freely,
X *	subject to the following restrictions:
X *
X *	1. The author is not responsible for the consequences of use of
X *		this software, no matter how awful, even if they arise
X *		from defects in it.
X *
X *	2. The origin of this software must not be misrepresented, either
X *		by explicit claim or by omission.
X *
X *	3. Altered versions must be plainly marked as such, and must not
X *		be misrepresented as being the original software.
X */
X
X#include <lib.h>
X#include <string.h>
X#include <regexp.h>
X#include <stdio.h>
X
X/* The first byte of the regexp internal "program" is actually this magic
X * number; the start node begins in the second byte.
X */
X#define	MAGIC	0234
X
X#define CHARBITS 0377
X#ifndef CHARBITS
X#define	UCHARAT(p)	((int)*(unsigned char *)(p))
X#else
X#define	UCHARAT(p)	((int)*(p)&CHARBITS)
X#endif
X
X/*
X - regsub - perform substitutions after a regexp match
X */
Xvoid regsub(prog, source, dest)
Xregexp *prog;
Xchar *source;
Xchar *dest;
X{
X  register char *src;
X  register char *dst;
X  register char c;
X  register int no;
X  register int len;
X
X  if (prog == (regexp *)NULL || source == (char *)NULL || dest == (char *)NULL) {
X	regerror("NULL parm to regsub");
X	return;
X  }
X  if (UCHARAT(prog->program) != MAGIC) {
X	regerror("damaged regexp fed to regsub");
X	return;
X  }
X  src = source;
X  dst = dest;
X  while ((c = *src++) != '\0') {
X	if (c == '&')
X		no = 0;
X	else if (c == '\\' && '0' <= *src && *src <= '9')
X		no = *src++ - '0';
X	else
X		no = -1;
X
X	if (no < 0) {		/* Ordinary character. */
X		if (c == '\\' && (*src == '\\' || *src == '&')) c = *src++;
X		*dst++ = c;
X	} else
X	if (prog->startp[no] != (char *)NULL && prog->endp[no] != (char *)NULL) {
X		len = (int) (prog->endp[no] - prog->startp[no]);
X		strncpy(dst, prog->startp[no], len);
X		dst += len;
X		if (len != 0 && *(dst - 1) == '\0') {	/* strncpy hit NUL. */
X			regerror("damaged match string");
X			return;
X		}
X	}
X  }
X  *dst++ = '\0';
X}
/
echo x - rewinddir.c
sed '/^X/s///' > rewinddir.c << '/'
X/* rewinddir -- rewind a directory stream	Author: D.A. Gwyn */
X
X/*	last edit:	25-Apr-1987	D A Gwyn
X
X  This is not simply a call to seekdir(), because seekdir()
X  will use the current buffer whenever possible and we need
X  rewinddir() to forget about buffered data.
X*/
X
X#include <lib.h>
X#include <dirent.h>
X#include <unistd.h>
X
X#define	DULL (DIR *) NULL
X#define	CULL (char *) NULL
X
X#ifndef SEEK_SET
X#define	SEEK_SET	0
X#endif
X
Xvoid rewinddir(dirp)
Xregister DIR *dirp;		/* stream from opendir() */
X{
X  if (dirp == DULL || dirp->dd_buf == CULL || dirp->dd_magic != _DIR_MAGIC) {
X	errno = EFAULT;
X	return;			/* invalid pointer */
X  }
X  dirp->dd_loc = dirp->dd_size = 0;	/* invalidate buffer */
X  (void) lseek(dirp->dd_fd, (off_t) 0, SEEK_SET);	/* may set errno */
X}
/
echo x - rindex.c
sed '/^X/s///' > rindex.c << '/'
X#include <lib.h>
X/* rindex - find last occurrence of a character in a string  */
X
X#include <string.h>
X
Xchar *rindex(s, charwanted)	/* found char, or NULL if none */
X_CONST char *s;
Xchar charwanted;
X{
X  return(strrchr(s, charwanted));
X}
/
echo x - seekdir.c
sed '/^X/s///' > seekdir.c << '/'
X#include <lib.h>
X/* seekdir -- reposition a directory stream	Author: D.A. Gwyn */
X
X/*	last edit:	24-May-1987	D A Gwyn	*/
X
X#include	<errno.h>
X#include	<sys/types.h>
X#include	<limits.h>
X#include	<dirent.h>
X#include	<unistd.h>
X
X_PROTOTYPE( void seekdir, (DIR *dirp, off_t loc));
X
X#define DULL (DIR *) 0
X#define DE_NULL (struct dirent *) 0
X
Xtypedef int bool;		/* Boolean data type */
X#define	false	0
X#define	true	1
X
Xvoid seekdir(dirp, loc)
Xregister DIR *dirp;		/* stream from opendir() */
Xregister off_t loc;		/* position from telldir() */
X{
X  register bool rewind;		/* "start over when stymied" flag */
X
X  if (dirp == DULL || dirp->dd_buf == (char *)NULL || dirp->dd_magic != _DIR_MAGIC) {
X	errno = EBADF;
X	return;			/* invalid pointer */
X  }
X
X  /* A (struct dirent)'s d_off is an invented quantity on 4.nBSD
X   * NFS-supporting systems, so it is not safe to lseek() to it. */
X
X  /* Monotonicity of d_off is heavily exploited in the following. */
X
X  /* This algorithm is tuned for modest directory sizes.  For huge
X   * directories, it might be more efficient to read blocks until the
X   * first d_off is too large, then back up one block, or even to use
X   * binary search on the directory blocks.  I doubt that the extra
X   * code for that would be worthwhile. */
X
X  if (dirp->dd_loc >= dirp->dd_size	/* invalid index */
X      || ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off > loc
X  /* Too far along in buffer */
X	)
X	dirp->dd_loc = 0;	/* reset to beginning of buffer */
X  /* Else save time by starting at current dirp->dd_loc */
X
X  for (rewind = true;;) {
X	register struct dirent *dp;
X
X	/* See whether the matching entry is in the current buffer. */
X
X	if ((dirp->dd_loc < dirp->dd_size	/* valid index */
X	     || readdir(dirp) != DE_NULL	/* next buffer read */
X	     && (dirp->dd_loc = 0, true)	/* beginning of buffer set */
X	     )
X	    && (dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off
X	    <= loc		/* match possible in this buffer */
X		) {
X		for ( 	/* dp initialized above */ ;
X		     (char *) dp < &dirp->dd_buf[dirp->dd_size];
X		 dp = (struct dirent *) ((char *) dp + dp->d_reclen)
X			)
X			if (dp->d_off == loc) {	/* found it! */
X				dirp->dd_loc =
X					(char *) dp - dirp->dd_buf;
X				return;
X			}
X		rewind = false;	/* no point in backing up later */
X		dirp->dd_loc = dirp->dd_size;	/* set end of buffer */
X	} else
X	 /* Whole buffer past matching entry */ if (!rewind) {		/* no point in searching
X								 * further */
X		errno = EINVAL;
X		return;		/* no entry at specified loc */
X	} else {		/* rewind directory and start over */
X		rewind = false;	/* but only once! */
X
X		dirp->dd_loc = dirp->dd_size = 0;
X
X		if (lseek(dirp->dd_fd, (off_t) 0, SEEK_SET) != 0
X			)
X			return;	/* errno already set (EBADF) */
X
X		if (loc == 0) return;	/* save time */
X	}
X  }
X}
/
echo x - stderr.c
sed '/^X/s///' > stderr.c << '/'
X#include <lib.h>
X#include <sys/types.h>
X#include <unistd.h>
X
X_PROTOTYPE( void std_err, (char *s));
X
Xvoid std_err(s)
Xchar *s;
X{
X  register char *p = s;
X
X  while (*p != 0) p++;
X  write(2, s, (int) (p - s));
X}
/
echo x - swab.c
sed '/^X/s///' > swab.c << '/'
X#include <lib.h>
X/*  swab(3)
X *
X *  Author: Terrence W. Holm          Sep. 1988
X */
X_PROTOTYPE( void swab, (char *from, char *to, int count));
X
Xvoid swab(from, to, count)
Xchar *from;
Xchar *to;
Xint count;
X{
X  register char temp;
X
X  count >>= 1;
X
X  while (--count >= 0) {
X	temp = *from++;
X	*to++ = *from++;
X	*to++ = temp;
X  }
X}
/
echo x - syscall.c
sed '/^X/s///' > syscall.c << '/'
X#include <lib.h>
X
XPUBLIC int _syscall(who, syscallnr, msgptr)
Xint who;
Xint syscallnr;
Xregister message *msgptr;
X{
X  int status;
X
X  msgptr->m_type = syscallnr;
X  status = _sendrec(who, msgptr);
X  if (status != 0) {
X	/* 'sendrec' itself failed. */
X	/* XXX - strerror doesn't know all the codes */
X	msgptr->m_type = status;
X  }
X  if (msgptr->m_type < 0) {
X	errno = -msgptr->m_type;
X	return(-1);
X  }
X  return(msgptr->m_type);
X}
/
echo x - sysconf.c
sed '/^X/s///' > sysconf.c << '/'
X/* sysconf.c						POSIX 4.8.1
X *	long int sysconf(int name);
X *
X *	POSIX allows some of the values in <limits.h> to be increased at
X *	run time.  The sysconf() function allows such values to be checked
X *	at run time.  MINIX does not use this facility - the run time
X *	limits are those given in <limits.h>.
X */
X
X#include <lib.h>
X#include <unistd.h>
X#include <time.h>
X
XPUBLIC long int sysconf(name)
Xint name;			/* property being inspected */
X{
X  switch(name) {
X	case _SC_ARG_MAX:
X		return (long) ARG_MAX;
X
X	case _SC_CHILD_MAX:
X		return (long) CHILD_MAX;
X
X	case _SC_CLK_TCK:
X		return (long) CLOCKS_PER_SEC;
X
X	case _SC_NGROUPS_MAX:
X		return (long) NGROUPS_MAX;
X
X	case _SC_OPEN_MAX:
X		return (long) OPEN_MAX;
X
X	case _SC_JOB_CONTROL:
X		return -1L;			/* no job control */
X
X	case _SC_SAVED_IDS:
X		return -1L;			/* no saved uid/gid */
X
X	case _SC_VERSION:
X		return (long) _POSIX_VERSION;
X
X	case _SC_STREAM_MAX:
X		return (long) STREAM_MAX;
X
X	case _SC_TZNAME_MAX:
X		return (long) TZNAME_MAX;
X
X	default:
X		errno = EINVAL;
X		return -1L;
X  }
X}
/
echo x - syslib.c
sed '/^X/s///' > syslib.c << '/'
X#include <lib.h>
X#include <minix/com.h>
X#include <minix/syslib.h>
X
X/*----------------------------------------------------------------------------
X		Messages to SYSTASK that are used by both MM and FS
X----------------------------------------------------------------------------*/
X
XPUBLIC void sys_abort()
X{
X/* Something awful has happened.  Abandon ship. */
X
X  message m;
X
X  _taskcall(SYSTASK, SYS_ABORT, &m);
X}
X
XPUBLIC void sys_copy(mptr)
Xmessage *mptr;			/* pointer to message */
X{
X/* A server wants something copied. */
X
X  /* Make this routine better.  Also check other guys' error handling.
X   * DEBUG.
X   */
X  if (_taskcall(SYSTASK, SYS_COPY, mptr) != 0)
X	panic("sys_copy can't send", NO_NUM);
X}
/
echo x - taskcall.c
sed '/^X/s///' > taskcall.c << '/'
X/* _taskcall() is the same as _syscall() except it returns negative error
X * codes directly and not in errno.  This is a better interface for MM and
X * FS.
X */
X
X#include <lib.h>
X#include <minix/syslib.h>
X
XPUBLIC int _taskcall(who, syscallnr, msgptr)
Xint who;
Xint syscallnr;
Xregister message *msgptr;
X{
X  int status;
X
X  msgptr->m_type = syscallnr;
X  status = _sendrec(who, msgptr);
X  if (status != 0) {
X	/* 'sendrec' itself failed.  Consider panicking here.  The sys_*
X	 * functions mostly ignore the return codes!
X	 */
X	msgptr->m_type = status;
X  }
X  return(msgptr->m_type);
X}
/
echo x - telldir.c
sed '/^X/s///' > telldir.c << '/'
X#include <lib.h>
X/* telldir -- report directory stream position	Author: D.A. Gwyn */
X
X/*	last edit:	25-Apr-1987	D A Gwyn	*/
X
X#include	<errno.h>
X#include	<sys/types.h>
X#include	<limits.h>
X#include	<dirent.h>
X#include 	<unistd.h>
X
X_PROTOTYPE( off_t telldir, (DIR *dirp));
X
X#define DULL (DIR *) 0
X
X#ifndef SEEK_CUR
X#define	SEEK_CUR	1
X#endif
X
Xoff_t telldir(dirp)		/* return offset of next entry */
XDIR *dirp;			/* stream from opendir() */
X{
X  if (dirp == DULL || dirp->dd_buf == (char *)NULL || dirp->dd_magic != _DIR_MAGIC)
X	if (dirp == DULL || dirp->dd_buf == (char *) NULL) {
X		errno = EBADF;
X		return(-1);	/* invalid pointer */
X	}
X  if (dirp->dd_loc < dirp->dd_size)	/* valid index */
X	return(((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off);
X  else				/* beginning of next directory block */
X	return(lseek(dirp->dd_fd, (off_t) 0, SEEK_CUR));
X}
/
echo x - termcap.c
sed '/^X/s///' > termcap.c << '/'
X/*
X *	termcap.c	V1.1	20/7/87		agc	Joypace Ltd
X *
X *	Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
X *	This file may be freely distributed provided that this notice
X *	remains attached.
X *
X *	A public domain implementation of the termcap(3) routines.
X *
X *
X *
X *	 Klamer Schutte	      V1.2    Nov. 1988
X *
X *   - Can match multiple terminal names		 [tgetent]
X *   - Removal of **area assignments			 [tgetstr]
X *
X *	 Terrence W. Holm     V1.3    May, Sep, Oct.  1988
X *
X *   - Correct when TERM != name and TERMCAP is defined	 [tgetent]
X *   - Correct the comparison for the terminal name 	 [tgetent]
X *   - Correct the value of ^x escapes              	 [tgetstr]
X *   - Added %r to reverse row/column			 [tgoto]
X *   - Fixed end of definition test			 [tgetnum/flag/str]
X *
X *	 Terrence W. Holm     V1.4    Jan. 1989
X *
X *   - Incorporated Klamer's V1.2 fixes into V1.3
X *   - Added %d, (old %d is now %2)			 [tgoto]
X *   - Allow '#' comments in definition file		 [tgetent]
X */
X
X#include <lib.h>
X#include <termcap.h>
X#include <ctype.h>
X#include <stdlib.h>
X#include <string.h>
X#include <stdio.h>
X
Xchar *capab = (char *)NULL;		/* the capability itself */
X
X#if 0
X/*  The following are not yet used.  */
Xextern short ospeed;		/* output speed */
Xextern char PC;			/* padding character */
Xextern char *BC;		/* back cursor movement */
Xextern char *UP;		/* up cursor movement */
X#endif
X
X/*
X *	tgetent - get the termcap entry for terminal name, and put it
X *	in bp (which must be an array of 1024 chars). Returns 1 if
X *	termcap entry found, 0 if not found, and -1 if file not found.
X */
X
Xint tgetent(bp, name)
Xchar *bp;
Xchar *name;
X{
X  FILE *fp;
X  char *file;
X  char *term;
X  short len = strlen(name);
X
X  capab = bp;
X
X  /* If TERMCAP begins with a '/' then use TERMCAP as the path	 */
X  /* Name of the termcap definitions file. If TERMCAP is a	 */
X  /* Definition and TERM equals "name" then use TERMCAP as the	 */
X  /* Definition. Otherwise use "/etc/termcap" as the path name.	 */
X
X  if ((file = getenv("TERMCAP")) == (char *)NULL)
X	file = "/etc/termcap";
X  else if (*file != '/')
X	if ((term = getenv("TERM")) != (char *)NULL && strcmp(term, name) == 0) {
X		*bp = '\0';
X		strncat(bp, file, 1023);
X		return(1);
X	} else
X		file = "/etc/termcap";
X
X  if ((fp = fopen(file, "r")) == (FILE *) NULL) {
X	capab = (char *)NULL;		/* no valid termcap  */
X	return(-1);
X  }
X  for (;;) {
X	/* Read in each definition */
X	int def_len = 0;
X	char *cp = bp;
X
X	do {
X		if (fgets(&bp[def_len], (unsigned int)(1024 - def_len), fp) == (char *)NULL) {
X			fclose(fp);
X			capab = (char *)NULL;	/* no valid termcap */
X			return(0);
X		}
X		def_len = strlen(bp) - 2;
X	} while (bp[def_len] == '\\');
X
X	while (isspace(*cp)) cp++;
X
X	/* Comment lines start with a '#'  */
X	if (*cp == '#') continue;
X
X	/* See if any of the terminal names in this definition */
X	/* Match "name".						 */
X
X	do {
X		if (strncmp(name, cp, len) == 0 &&
X		    (cp[len] == '|' || cp[len] == ':')) {
X			fclose(fp);
X			return(1);
X		}
X		while ((*cp) && (*cp != '|') && (*cp != ':')) cp++;
X	} while (*cp++ == '|');
X  }
X}
X
X
X/*
X *	tgetnum - get the numeric terminal capability corresponding
X *	to id. Returns the value, -1 if invalid.
X */
X
Xint tgetnum(id)
Xchar *id;
X{
X  register char *cp = capab;
X
X  if (cp == (char *)NULL || id == (char *)NULL) return(-1);
X
X  for (;;) {
X	while (*cp++ != ':')
X		if (cp[-1] == '\0') return(-1);
X
X	while (isspace(*cp)) cp++;
X
X	if (strncmp(cp, id, 2) == 0 && cp[2] == '#') return(atoi(cp + 3));
X  }
X}
X
X
X/*
X *	tgetflag - get the boolean flag corresponding to id. Returns -1
X *	if invalid, 0 if the flag is not in termcap entry, or 1 if it is
X *	present.
X */
X
Xint tgetflag(id)
Xchar *id;
X{
X  register char *cp = capab;
X
X  if (cp == (char *)NULL || id == (char *)NULL) return(-1);
X
X  for (;;) {
X	while (*cp++ != ':')
X		if (cp[-1] == '\0') return(0);
X
X	while (isspace(*cp)) cp++;
X
X	if (strncmp(cp, id, 2) == 0) return(1);
X  }
X}
X
X
X/*
X *	tgetstr - get the string capability corresponding to id and place
X *	it in area (advancing area at same time). Expand escape sequences
X *	etc. Returns the string, or NULL if it can't do it.
X */
X
Xchar *tgetstr(id, area)
Xchar *id;
Xchar **area;
X{
X  register char *cp = capab;
X  register char *wsp = *area;	/* workspace pointer  */
X
X  if (cp == (char *)NULL || id == (char *)NULL) return((char *)NULL);
X
X  for (;;) {
X	while (*cp++ != ':')
X		if (cp[-1] == '\0') return((char *)NULL);
X
X	while (isspace(*cp)) cp++;
X
X	if (strncmp(cp, id, 2) == 0 && cp[2] == '=') {
X		for (cp += 3; *cp && *cp != ':'; wsp++, cp++) switch (*cp) {
X			    case '^':
X				*wsp = *++cp - '@';
X				break;
X
X			    case '\\':
X				switch (*++cp) {
X				    case 'E':
X					*wsp = '\033';
X					break;
X				    case 'n':
X					*wsp = '\n';
X					break;
X				    case 'r':
X					*wsp = '\r';
X					break;
X				    case 't':
X					*wsp = '\t';
X					break;
X				    case 'b':
X					*wsp = '\b';
X					break;
X				    case 'f':
X					*wsp = '\f';
X					break;
X				    case '0':
X				    case '1':
X				    case '2':
X				    case '3':
X					{
X						int i;
X						int t = 0;
X						for (i = 0; i < 3 &&
X						     isdigit(*cp); ++i, ++cp)
X							t = t * 8 + *cp - '0';
X						*wsp = t;
X						cp--;
X						break;
X					}
X				    default:
X					*wsp = *cp;
X				}
X				break;
X
X			    default:	*wsp = *cp;
X  			}
X
X		*wsp++ = '\0';
X
X		{
X			char *ret = *area;
X			*area = wsp;
X			return(ret);
X		}
X	}
X  }				/* end for(;;) */
X}
X
X
X
X/*
X *	tgoto - given the cursor motion string cm, make up the string
X *	for the cursor to go to (destcol, destline), and return the string.
X *	Returns "OOPS" if something's gone wrong, or the string otherwise.
X */
X
Xchar *tgoto(cm, destcol, destline)
Xchar *cm;
Xint destcol;
Xint destline;
X{
X  PRIVATE char ret[24];
X  char *rp = ret;
X  int incr = 0;
X  int argno = 0;
X  int numval;
X
X  for (; *cm; cm++) {
X	if (*cm == '%') {
X		switch (*++cm) {
X		    case 'i':	incr = 1;	  			break;
X
X		    case 'r':	argno = 1;	  			break;
X
X		    case '+':
X			numval = (argno == 0 ? destline : destcol);
X			*rp++ = numval + incr + *++cm;
X			argno = 1 - argno;
X			break;
X
X		    case '2':
X			numval = (argno == 0 ? destline : destcol);
X			numval = (numval + incr) % 100;
X			*rp++ = '0' + (numval / 10);
X			*rp++ = '0' + (numval % 10);
X			argno = 1 - argno;
X			break;
X
X		    case 'd':
X			numval = (argno == 0 ? destline : destcol);
X			numval = (numval + incr) % 1000;
X			if (numval > 99) *rp++ = '0' + (numval / 100);
X			if (numval > 9) *rp++ = '0' + (numval / 10) % 10;
X			*rp++ = '0' + (numval % 10);
X			argno = 1 - argno;
X			break;
X
X		    case '%':	*rp++ = '%';	  			break;
X
X		    default:	return("OOPS");
X  		}
X
X	} else
X		*rp++ = *cm;
X  }
X
X  *rp = '\0';
X  return(ret);
X}
X
X
X
X/*
X *	tputs - put the string cp out onto the terminal, using the function
X *	outc. This should do padding for the terminal, but I can't find a
X *	terminal that needs padding at the moment...
X */
X
Xint tputs(cp, affcnt, outc)
Xregister char *cp;
Xint affcnt;
X_PROTOTYPE( void (*outc), (int ch));
X{
X  if (cp == (char *)NULL) return(1);
X  /* Do any padding interpretation - left null for MINIX just now */
X  while (*cp) (*outc) (*cp++);
X  return(1);
X}
/
echo x - ttyname.c
sed '/^X/s///' > ttyname.c << '/'
X/* ttyname.c						POSIX 4.7.2
X *	char *ttyname(int fildes);
X *
X *	Determines name of a terminal device.
X */
X
X#include <lib.h>
X#include <sys/stat.h>
X#include <dirent.h>
X#include <fcntl.h>
X#include <stddef.h>
X#include <string.h>
X#include <unistd.h>
X
XPRIVATE char base[] = "/dev";
XPRIVATE char path[sizeof(base) + 1 + NAME_MAX];	/* extra 1 for '/' */
X
XPUBLIC char *ttyname(fildes)
Xint fildes;
X{
X  DIR *devices;
X  struct dirent *entry;
X  struct stat tty_stat;
X  struct stat dev_stat;
X
X  /* Simple first test: file descriptor must be a character device */
X  if (fstat(fildes, &tty_stat) < 0 || !S_ISCHR(tty_stat.st_mode))
X	return (char *) NULL;
X
X  /* Open device directory for reading  */
X  if ((devices = opendir(base)) == (DIR *) NULL)
X	return (char *) NULL;
X
X  /* Scan the entries for one that matches perfectly */
X  while ((entry = readdir(devices)) != (struct dirent *) NULL) {
X	if (tty_stat.st_ino != entry->d_ino)
X		continue;
X	strcpy(path, base);
X	strcat(path, "/");
X	strcat(path, entry->d_name);
X	if (stat(path, &dev_stat) < 0 || !S_ISCHR(dev_stat.st_mode))
X		continue;
X	if (tty_stat.st_ino == dev_stat.st_ino &&
X	    tty_stat.st_dev == dev_stat.st_dev &&
X	    tty_stat.st_rdev == dev_stat.st_rdev) {
X		closedir(devices);
X		return path;
X	}
X  }
X
X  closedir(devices);
X  return (char *) NULL;
X}
/
