--- /dev/null
+.include <bsd.own.mk>
+
+LIB= compat_minix
+CPPFLAGS+= -D_MINIX_COMPAT
+
+.PATH: ${.CURDIR}
+
+# std_err()
+SRCS+= stderr.c
+
+# V8 regexp (incompatible with BSD regexp)
+SRCS+= v8regerror.c v8regexp.c v8regsub.c
+
+# Configfile Library.
+SRCS+= configfile.c
+
+# ACK a.out format.
+SRCS+= nlist.c
+
+# Minix 'mtab' handling functions.
+#
+# These should be changed when we switch to
+# NetBSD's 'mtab' format.
+SRCS+= mtab.c
+
+# Termcap.
+# Included in the Minix libc.
+#
+# Should be removed once we switch to terminfo.
+SRCS+= termcap.c
+
+# Minix legacy passwd format
+# These should be removed when we switch to
+# NetBSD's 'passwd' db-based format.
+SRCS+= crypt.c getpwent.c
+
+# fttyslot(fd), a Minix-specific extension
+SRCS+= fttyslot.c
+
+# cuserid()
+# Now considered "compat" feature in NetBSD.
+SRCS+= cuserid.c
+
+.include "include/Makefile.inc"
+
+.include <bsd.lib.mk>
--- /dev/null
+/* config_read(), _delete(), _length() - Generic config file routines.
+ * Author: Kees J. Bot
+ * 5 Jun 1999
+ */
+#define nil ((void*)0)
+#if __minix_vmd
+#include <minix/stubs.h>
+#else
+#define fstat _fstat
+#define stat _stat
+#endif
+#include <sys/types.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <sys/stat.h>
+#if __minix_vmd
+#include <minix/asciictype.h>
+#else
+#include <ctype.h>
+#endif
+#define _c /* not const */
+#include <configfile.h>
+
+typedef struct configfile { /* List of (included) configuration files. */
+ struct configfile *next; /* A list indeed. */
+ time_t ctime; /* Last changed time, -1 if no file. */
+ char name[1]; /* File name. */
+} configfile_t;
+
+/* Size of a configfile_t given a file name of length 'len'. */
+#define configfilesize(len) (offsetof(configfile_t, name) + 1 + (len))
+
+typedef struct firstconfig { /* First file and first word share a slot. */
+ configfile_t *filelist;
+ char new; /* Set when created. */
+ config_t config1;
+} firstconfig_t;
+
+/* Size of a config_t given a word of lenght 'len'. Same for firstconfig_t. */
+#define config0size() (offsetof(config_t, word))
+#define configsize(len) (config0size() + 1 + (len))
+#define firstconfigsize(len) \
+ (offsetof(firstconfig_t, config1) + configsize(len))
+
+/* Translate address of first config word to enclosing firstconfig_t and vv. */
+#define cfg2fcfg(p) \
+ ((firstconfig_t *) ((char *) (p) - offsetof(firstconfig_t, config1)))
+#define fcfg2cfg(p) (&(p)->config1)
+
+/* Variables used while building data. */
+static configfile_t *c_files; /* List of (included) config files. */
+static int c_flags; /* Flags argument of config_read(). */
+static FILE *c_fp; /* Current open file. */
+static char *c_file; /* Current open file name. */
+static unsigned c_line; /* Current line number. */
+static int c; /* Next character. */
+
+static void *allocate(void *mem, size_t size)
+/* Like realloc(), but checked. */
+{
+ if ((mem= realloc(mem, size)) == nil) {
+ fprintf(stderr, "\"%s\", line %u: Out of memory\n", c_file, c_line);
+ exit(1);
+ }
+ return mem;
+}
+
+#define deallocate(mem) free(mem)
+
+static void delete_filelist(configfile_t *cfgf)
+/* Delete configuration file list. */
+{
+ void *junk;
+
+ while (cfgf != nil) {
+ junk= cfgf;
+ cfgf= cfgf->next;
+ deallocate(junk);
+ }
+}
+
+static void delete_config(config_t *cfg)
+/* Delete configuration file data. */
+{
+ config_t *next, *list, *junk;
+
+ next= cfg;
+ list= nil;
+ for (;;) {
+ if (next != nil) {
+ /* Push the 'next' chain in reverse on the 'list' chain, putting
+ * a leaf cell (next == nil) on top of 'list'.
+ */
+ junk= next;
+ next= next->next;
+ junk->next= list;
+ list= junk;
+ } else
+ if (list != nil) {
+ /* Delete the leaf cell. If it has a sublist then that becomes
+ * the 'next' chain.
+ */
+ junk= list;
+ next= list->list;
+ list= list->next;
+ deallocate(junk);
+ } else {
+ /* Both chains are gone. */
+ break;
+ }
+ }
+}
+
+void config_delete(config_t *cfg1)
+/* Delete configuration file data, being careful with the odd first one. */
+{
+ firstconfig_t *fcfg= cfg2fcfg(cfg1);
+
+ delete_filelist(fcfg->filelist);
+ delete_config(fcfg->config1.next);
+ delete_config(fcfg->config1.list);
+ deallocate(fcfg);
+}
+
+static void nextc(void)
+/* Read the next character of the current file into 'c'. */
+{
+ if (c == '\n') c_line++;
+ c= getc(c_fp);
+ if (c == EOF && ferror(c_fp)) {
+ fprintf(stderr, "\"%s\", line %u: %s\n",
+ c_file, c_line, strerror(errno));
+ exit(1);
+ }
+}
+
+static void skipwhite(void)
+/* Skip whitespace and comments. */
+{
+ while (isspace(c)) {
+ nextc();
+ if (c == '#') {
+ do nextc(); while (c != EOF && c != '\n');
+ }
+ }
+}
+
+static void parse_err(void)
+/* Tell user that you can't parse past the current character. */
+{
+ char sc[2];
+
+ sc[0]= c;
+ sc[1]= 0;
+ fprintf(stderr, "\"%s\", line %u: parse error at '%s'\n",
+ c_file, c_line, c == EOF ? "EOF" : sc);
+ exit(1);
+}
+
+static config_t *read_word(void)
+/* Read a word or string. */
+{
+ config_t *w;
+ size_t i, len;
+ int q;
+ static char SPECIAL[] = "!#$%&*+-./:<=>?[\\]^_|~";
+
+ i= 0;
+ len= 32;
+ w= allocate(nil, configsize(32));
+ w->next= nil;
+ w->list= nil;
+ w->file= c_file;
+ w->line= c_line;
+ w->flags= 0;
+
+ /* Is it a quoted string? */
+ if (c == '\'' || c == '"') {
+ q= c; /* yes */
+ nextc();
+ } else {
+ q= -1; /* no */
+ }
+
+ for (;;) {
+ if (i == len) {
+ len+= 32;
+ w= allocate(w, configsize(len));
+ }
+
+ if (q == -1) {
+ /* A word consists of letters, numbers and a few special chars. */
+ if (!isalnum(c) && c < 0x80 && strchr(SPECIAL, c) == nil) break;
+ } else {
+ /* Strings are made up of anything except newlines. */
+ if (c == EOF || c == '\n') {
+ fprintf(stderr,
+ "\"%s\", line %u: string at line %u not closed\n",
+ c_file, c_line, w->line);
+ exit(1);
+ break;
+ }
+ if (c == q) { /* Closing quote? */
+ nextc();
+ break;
+ }
+ }
+
+ if (c != '\\') { /* Simply add non-escapes. */
+ w->word[i++]= c;
+ nextc();
+ } else { /* Interpret an escape. */
+ nextc();
+ if (isspace(c)) {
+ skipwhite();
+ continue;
+ }
+
+ if (c_flags & CFG_ESCAPED) {
+ w->word[i++]= '\\'; /* Keep the \ for the caller. */
+ if (i == len) {
+ len+= 32;
+ w= allocate(w, configsize(len));
+ }
+ w->flags |= CFG_ESCAPED;
+ }
+
+ if (isdigit(c)) { /* Octal escape */
+ int n= 3;
+ int d= 0;
+
+ do {
+ d= d * 010 + (c - '0');
+ nextc();
+ } while (--n > 0 && isdigit(c));
+ w->word[i++]= d;
+ } else
+ if (c == 'x' || c == 'X') { /* Hex escape */
+ int n= 2;
+ int d= 0;
+
+ nextc();
+ if (!isxdigit(c)) {
+ fprintf(stderr, "\"%s\", line %u: bad hex escape\n",
+ c_file, c_line);
+ exit(1);
+ }
+ do {
+ d= d * 0x10 + (islower(c) ? (c - 'a' + 0xa) :
+ isupper(c) ? (c - 'A' + 0xA) :
+ (c - '0'));
+ nextc();
+ } while (--n > 0 && isxdigit(c));
+ w->word[i++]= d;
+ } else {
+ switch (c) {
+ case 'a': c= '\a'; break;
+ case 'b': c= '\b'; break;
+ case 'e': c= '\033'; break;
+ case 'f': c= '\f'; break;
+ case 'n': c= '\n'; break;
+ case 'r': c= '\r'; break;
+ case 's': c= ' '; break;
+ case 't': c= '\t'; break;
+ case 'v': c= '\v'; break;
+ default: /* Anything else is kept as-is. */;
+ }
+ w->word[i++]= c;
+ nextc();
+ }
+ }
+ }
+ w->word[i]= 0;
+ if (q != -1) {
+ w->flags |= CFG_STRING;
+ } else {
+ int f;
+ char *end;
+ static char base[]= { 0, 010, 10, 0x10 };
+
+ if (i == 0) parse_err();
+
+ /* Can the word be used as a number? */
+ for (f= 0; f < 4; f++) {
+ (void) strtol(w->word, &end, base[f]);
+ if (*end == 0) w->flags |= 1 << (f + 0);
+ (void) strtoul(w->word, &end, base[f]);
+ if (*end == 0) w->flags |= 1 << (f + 4);
+ }
+ }
+ return allocate(w, configsize(i));
+}
+
+static config_t *read_file(const char *file);
+static config_t *read_list(void);
+
+static config_t *read_line(void)
+/* Read and return one line of the config file. */
+{
+ config_t *cline, **pcline, *clist;
+
+ cline= nil;
+ pcline= &cline;
+
+ for (;;) {
+ skipwhite();
+
+ if (c == EOF || c == '}') {
+if(0) if (cline != nil) parse_err();
+ break;
+ } else
+ if (c == ';') {
+ nextc();
+ if (cline != nil) break;
+ } else
+ if (cline != nil && c == '{') {
+ /* A sublist. */
+ nextc();
+ clist= allocate(nil, config0size());
+ clist->next= nil;
+ clist->file= c_file;
+ clist->line= c_line;
+ clist->list= read_list();
+ clist->flags= CFG_SUBLIST;
+ *pcline= clist;
+ pcline= &clist->next;
+ if (c != '}') parse_err();
+ nextc();
+ } else {
+ *pcline= read_word();
+ pcline= &(*pcline)->next;
+ }
+ }
+ return cline;
+}
+
+static config_t *read_list(void)
+/* Read and return a list of config file commands. */
+{
+ config_t *clist, **pclist, *cline;
+
+ clist= nil;
+ pclist= &clist;
+
+ while ((cline= read_line()) != nil) {
+ if (strcmp(cline->word, "include") == 0) {
+ config_t *file= cline->next;
+ if (file == nil || file->next != nil || !config_isatom(file)) {
+ fprintf(stderr,
+ "\"%s\", line %u: 'include' command requires an argument\n",
+ c_file, cline->line);
+ exit(1);
+ }
+ if (file->flags & CFG_ESCAPED) {
+ char *p, *q;
+ p= q= file->word;
+ for (;;) {
+ if ((*q = *p) == '\\') *q = *++p;
+ if (*q == 0) break;
+ p++;
+ q++;
+ }
+ }
+ file= read_file(file->word);
+ delete_config(cline);
+ *pclist= file;
+ while (*pclist != nil) pclist= &(*pclist)->next;
+ } else {
+ config_t *cfg= allocate(nil, config0size());
+ cfg->next= nil;
+ cfg->list= cline;
+ cfg->file= cline->file;
+ cfg->line= cline->line;
+ cfg->flags= CFG_SUBLIST;
+ *pclist= cfg;
+ pclist= &cfg->next;
+ }
+ }
+ return clist;
+}
+
+static config_t *read_file(const char *file)
+/* Read and return a configuration file. */
+{
+ configfile_t *cfgf;
+ config_t *cfg;
+ struct stat st;
+ FILE *old_fp; /* old_* variables store current file context. */
+ char *old_file;
+ unsigned old_line;
+ int old_c;
+ size_t n;
+ char *slash;
+
+ old_fp= c_fp;
+ old_file= c_file;
+ old_line= c_line;
+ old_c= c;
+
+ n= 0;
+ if (file[0] != '/' && old_file != nil
+ && (slash= strrchr(old_file, '/')) != nil) {
+ n= slash - old_file + 1;
+ }
+ cfgf= allocate(nil, configfilesize(n + strlen(file)));
+ memcpy(cfgf->name, old_file, n);
+ strcpy(cfgf->name + n, file);
+ cfgf->next= c_files;
+ c_files= cfgf;
+
+ c_file= cfgf->name;
+ c_line= 0;
+
+ if ((c_fp= fopen(file, "r")) == nil || fstat(fileno(c_fp), &st) < 0) {
+ if (errno != ENOENT) {
+ fprintf(stderr, "\"%s\", line 1: %s\n", file, strerror(errno));
+ exit(1);
+ }
+ cfgf->ctime= -1;
+ c= EOF;
+ } else {
+ cfgf->ctime= st.st_ctime;
+ c= '\n';
+ }
+
+ cfg= read_list();
+ if (c != EOF) parse_err();
+
+ if (c_fp != nil) fclose(c_fp);
+ c_fp= old_fp;
+ c_file= old_file;
+ c_line= old_line;
+ c= old_c;
+ return cfg;
+}
+
+config_t *config_read(const char *file, int flags, config_t *cfg)
+/* Read and parse a configuration file. */
+{
+ if (cfg != nil) {
+ /* First check if any of the involved files has changed. */
+ firstconfig_t *fcfg;
+ configfile_t *cfgf;
+ struct stat st;
+
+ fcfg= cfg2fcfg(cfg);
+ for (cfgf= fcfg->filelist; cfgf != nil; cfgf= cfgf->next) {
+ if (stat(cfgf->name, &st) < 0) {
+ if (errno != ENOENT) break;
+ st.st_ctime= -1;
+ }
+ if (st.st_ctime != cfgf->ctime) break;
+ }
+
+ if (cfgf == nil) return cfg; /* Everything as it was. */
+ config_delete(cfg); /* Otherwise delete and reread. */
+ }
+
+ errno= 0;
+ c_files= nil;
+ c_flags= flags;
+ cfg= read_file(file);
+
+ if (cfg != nil) {
+ /* Change first word to have a hidden pointer to a file list. */
+ size_t len= strlen(cfg->word);
+ firstconfig_t *fcfg;
+
+ fcfg= allocate(cfg, firstconfigsize(len));
+ memmove(&fcfg->config1, fcfg, configsize(len));
+ fcfg->filelist= c_files;
+ fcfg->new= 1;
+ return fcfg2cfg(fcfg);
+ }
+ /* Couldn't read (errno != 0) of nothing read (errno == 0). */
+ delete_filelist(c_files);
+ delete_config(cfg);
+ return nil;
+}
+
+int config_renewed(config_t *cfg)
+{
+ int new;
+
+ if (cfg == nil) {
+ new= 1;
+ } else {
+ new= cfg2fcfg(cfg)->new;
+ cfg2fcfg(cfg)->new= 0;
+ }
+ return new;
+}
+
+size_t config_length(config_t *cfg)
+/* Count the number of items on a list. */
+{
+ size_t n= 0;
+
+ while (cfg != nil) {
+ n++;
+ cfg= cfg->next;
+ }
+ return n;
+}
+
+#if TEST
+#include <unistd.h>
+
+static void print_list(int indent, config_t *cfg);
+
+static void print_words(int indent, config_t *cfg)
+{
+ while (cfg != nil) {
+ if (config_isatom(cfg)) {
+ if (config_isstring(cfg)) fputc('"', stdout);
+ printf("%s", cfg->word);
+ if (config_isstring(cfg)) fputc('"', stdout);
+ } else {
+ printf("{\n");
+ print_list(indent+4, cfg->list);
+ printf("%*s}", indent, "");
+ }
+ cfg= cfg->next;
+ if (cfg != nil) fputc(' ', stdout);
+ }
+ printf(";\n");
+}
+
+static void print_list(int indent, config_t *cfg)
+{
+ while (cfg != nil) {
+ if (!config_issub(cfg)) {
+ fprintf(stderr, "Cell at \"%s\", line %u is not a sublist\n");
+ break;
+ }
+ printf("%*s", indent, "");
+ print_words(indent, cfg->list);
+ cfg= cfg->next;
+ }
+}
+
+static void print_config(config_t *cfg)
+{
+ if (!config_renewed(cfg)) {
+ printf("# Config didn't change\n");
+ } else {
+ print_list(0, cfg);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ config_t *cfg;
+ int c;
+
+ if (argc != 2) {
+ fprintf(stderr, "One config file name please\n");
+ exit(1);
+ }
+
+ cfg= nil;
+ do {
+ cfg= config_read(argv[1], CFG_ESCAPED, cfg);
+ print_config(cfg);
+ if (!isatty(0)) break;
+ while ((c= getchar()) != EOF && c != '\n') {}
+ } while (c != EOF);
+ return 0;
+}
+#endif /* TEST */
--- /dev/null
+/* crypt() - one-way password encryption function Author: Kees J. Bot
+ * 7 Feb 1994
+ * This routine does not encrypt anything, it uses the pwdauth
+ * program to do the hard work.
+ */
+#define nil ((void*)0)
+#define pipe _pipe
+#define fork _fork
+#define close _close
+#define dup2 _dup2
+#define execl _execl
+#define read _read
+#define _exit __exit
+#define write _write
+#define waitpid _waitpid
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/wait.h>
+
+/* Set-uid root program to read /etc/shadow or encrypt passwords. */
+static char PWDAUTH[] = "/usr/lib/pwdauth";
+#define LEN 1024
+
+static void tell(const char *s0, ...)
+{
+ va_list ap;
+ const char *s;
+
+ va_start(ap, s0);
+ s= s0;
+ while (s != nil) {
+ (void) write(2, s, strlen(s));
+ s= va_arg(ap, const char *);
+ }
+ va_end(ap);
+}
+
+char *crypt(const char *key, const char *salt)
+{
+ pid_t pid;
+ int status;
+ int pfd[2];
+ static char pwdata[LEN];
+ char *p= pwdata;
+ const char *k= key;
+ const char *s= salt;
+ int n;
+
+ /* Fill pwdata[] with the key and salt. */
+ while ((*p++ = *k++) != 0) if (p == pwdata+LEN-1) goto fail;
+ while ((*p++ = *s++) != 0) if (p == pwdata+LEN-0) goto fail;
+
+ if (pipe(pfd) < 0) goto fail;
+
+ /* Prefill the pipe. */
+ (void) write(pfd[1], pwdata, p - pwdata);
+
+ switch ((pid= fork())) {
+ case -1:
+ close(pfd[0]);
+ close(pfd[1]);
+ goto fail;
+ case 0:
+ /* Connect both input and output to the pipe. */
+ if (pfd[0] != 0) {
+ dup2(pfd[0], 0);
+ close(pfd[0]);
+ }
+ if (pfd[1] != 1) {
+ dup2(pfd[1], 1);
+ close(pfd[1]);
+ }
+
+ execl(PWDAUTH, PWDAUTH, (char *) nil);
+
+ tell("crypt(): ", PWDAUTH, ": ", strerror(errno), "\r\n",
+ (char *) nil);
+ /* No pwdauth? Fail! */
+ (void) read(0, pwdata, LEN);
+ _exit(1);
+ }
+ close(pfd[1]);
+
+ status= -1;
+ while (waitpid(pid, &status, 0) == -1 && errno == EINTR) {}
+ if (status != 0) {
+ close(pfd[0]);
+ goto fail;
+ }
+
+ /* Read and return the result. Check if it contains exactly one
+ * string.
+ */
+ n= read(pfd[0], pwdata, LEN);
+ close(pfd[0]);
+ if (n < 0) goto fail;
+ p = pwdata + n;
+ n = 0;
+ while (p > pwdata) if (*--p == 0) n++;
+ if (n != 1) goto fail;
+ return pwdata;
+
+fail:
+ pwdata[0] = salt[0] ^ 1; /* make result != salt */
+ pwdata[1] = 0;
+ return pwdata;
+}
+
+/*
+ * $PchId: crypt.c,v 1.5 1996/04/11 07:46:11 philip Exp $
+ */
--- /dev/null
+/* cuserid(3)
+ *
+ * Author: Terrence W. Holm Sept. 1987
+ */
+
+#include <lib.h>
+#include <pwd.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#ifndef L_cuserid
+#define L_cuserid 9
+#endif
+
+char *cuserid(user_name)
+char *user_name;
+{
+ PRIVATE char userid[L_cuserid];
+ struct passwd *pw_entry;
+
+ if (user_name == (char *)NULL) user_name = userid;
+
+ pw_entry = getpwuid(geteuid());
+
+ if (pw_entry == (struct passwd *)NULL) {
+ *user_name = '\0';
+ return((char *)NULL);
+ }
+ strcpy(user_name, pw_entry->pw_name);
+
+ return(user_name);
+}
--- /dev/null
+/*
+ttyslot.c
+
+Return the index in the utmp file for the current user's terminal. The
+current user's terminal is the first file descriptor in the range 0..2
+for which ttyname() returns a name. The index is the line number in the
+/etc/ttytab file. 0 will be returned in case of an error.
+
+Created: Oct 11, 1992 by Philip Homburg
+*/
+
+#include <sys/types.h>
+#include <ttyent.h>
+#include <string.h>
+#include <unistd.h>
+
+int fttyslot(fd)
+int fd;
+{
+ char *tname;
+ int lineno;
+ struct ttyent *ttyp;
+
+ tname= ttyname(fd);
+ if (tname == NULL) return 0;
+
+ /* Assume that tty devices are in /dev */
+ if (strncmp(tname, "/dev/", 5) != 0)
+ return 0; /* Malformed tty name. */
+ tname += 5;
+
+ /* Scan /etc/ttytab. */
+ lineno= 1;
+ while ((ttyp= getttyent()) != NULL)
+ {
+ if (strcmp(tname, ttyp->ty_name) == 0)
+ {
+ endttyent();
+ return lineno;
+ }
+ lineno++;
+ }
+ /* No match */
+ endttyent();
+ return 0;
+}
+
+/*
+ * $PchHeader: /mount/hd2/minix/lib/misc/RCS/ttyslot.c,v 1.3 1994/12/22 13:49:12 philip Exp $
+ */
--- /dev/null
+/* getpwent(), getpwuid(), getpwnam() - password file routines
+ *
+ * Author: Kees J. Bot
+ * 31 Jan 1994
+ */
+#include <sys/types.h>
+#include <compat/pwd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
+#define arraylimit(a) ((a) + arraysize(a))
+
+static char PASSWD[]= "/etc/passwd"; /* The password file. */
+static const char *pwfile; /* Current password file. */
+
+static char buf[1024]; /* Read buffer. */
+static char pwline[256]; /* One line from the password file. */
+static struct passwd entry; /* Entry to fill and return. */
+static int pwfd= -1; /* Filedescriptor to the file. */
+static char *bufptr; /* Place in buf. */
+static ssize_t buflen= 0; /* Remaining characters in buf. */
+static char *lineptr; /* Place in the line. */
+
+void endpwent(void)
+/* Close the password file. */
+{
+ if (pwfd >= 0) {
+ (void) close(pwfd);
+ pwfd= -1;
+ buflen= 0;
+ }
+}
+
+int setpwent(void)
+/* Open the password file. */
+{
+ if (pwfd >= 0) endpwent();
+
+ if (pwfile == NULL) pwfile= PASSWD;
+
+ if ((pwfd= open(pwfile, O_RDONLY)) < 0) return -1;
+ (void) fcntl(pwfd, F_SETFD, fcntl(pwfd, F_GETFD) | FD_CLOEXEC);
+ return 0;
+}
+
+void setpwfile(const char *file)
+/* Prepare for reading an alternate password file. */
+{
+ endpwent();
+ pwfile= file;
+}
+
+static int getline(void)
+/* Get one line from the password file, return 0 if bad or EOF. */
+{
+ lineptr= pwline;
+
+ do {
+ if (buflen == 0) {
+ if ((buflen= read(pwfd, buf, sizeof(buf))) <= 0)
+ return 0;
+ bufptr= buf;
+ }
+
+ if (lineptr == arraylimit(pwline)) return 0;
+ buflen--;
+ } while ((*lineptr++ = *bufptr++) != '\n');
+
+ lineptr= pwline;
+ return 1;
+}
+
+static char *scan_colon(void)
+/* Scan for a field separator in a line, return the start of the field. */
+{
+ char *field= lineptr;
+ char *last;
+
+ for (;;) {
+ last= lineptr;
+ if (*lineptr == 0) return NULL;
+ if (*lineptr == '\n') break;
+ if (*lineptr++ == ':') break;
+ }
+ *last= 0;
+ return field;
+}
+
+struct passwd *getpwent(void)
+/* Read one entry from the password file. */
+{
+ char *p;
+
+ /* Open the file if not yet open. */
+ if (pwfd < 0 && setpwent() < 0) return NULL;
+
+ /* Until a good line is read. */
+ for (;;) {
+ if (!getline()) return NULL; /* EOF or corrupt. */
+
+ if ((entry.pw_name= scan_colon()) == NULL) continue;
+ if ((entry.pw_passwd= scan_colon()) == NULL) continue;
+ if ((p= scan_colon()) == NULL) continue;
+ entry.pw_uid= strtol(p, NULL, 0);
+ if ((p= scan_colon()) == NULL) continue;
+ entry.pw_gid= strtol(p, NULL, 0);
+ if ((entry.pw_gecos= scan_colon()) == NULL) continue;
+ if ((entry.pw_dir= scan_colon()) == NULL) continue;
+ if ((entry.pw_shell= scan_colon()) == NULL) continue;
+
+ if (*lineptr == 0) return &entry;
+ }
+}
+
+struct passwd *getpwuid(uid_t uid)
+/* Return the password file entry belonging to the user-id. */
+{
+ struct passwd *pw;
+
+ endpwent();
+ while ((pw= getpwent()) != NULL && pw->pw_uid != uid) {}
+ endpwent();
+ return pw;
+}
+
+struct passwd *getpwnam(const char *name)
+/* Return the password file entry belonging to the user name. */
+{
+ struct passwd *pw;
+
+ endpwent();
+ while ((pw= getpwent()) != NULL && strcmp(pw->pw_name, name) != 0) {}
+ endpwent();
+ return pw;
+}
+
+#ifndef L_cuserid
+#define L_cuserid 9
+#endif
+
+char *getlogin()
+{
+ static char userid[L_cuserid];
+ struct passwd *pw_entry;
+
+ pw_entry = getpwuid(getuid());
+
+ if (pw_entry == (struct passwd *)NULL) return((char *)NULL);
+
+ strcpy(userid, pw_entry->pw_name);
+
+ return(userid);
+}
--- /dev/null
+.PATH: ${MINIXSRCDIR}/lib/nbsd_libcompat_minix/include
+
+INCSDIR= /usr/netbsd/include
+
+INCS+= configfile.h termcap.h
+INCS+= compat/a.out.h compat/regexp.h compat/syslog.h \
+ compat/pwd.h
+
--- /dev/null
+/* The <a.out> header file describes the format of executable files. */
+
+#ifndef _AOUT_H
+#define _AOUT_H
+
+struct exec { /* a.out header */
+ unsigned char a_magic[2]; /* magic number */
+ unsigned char a_flags; /* flags, see below */
+ unsigned char a_cpu; /* cpu id */
+ unsigned char a_hdrlen; /* length of header */
+ unsigned char a_unused; /* reserved for future use */
+ unsigned short a_version; /* version stamp (not used at present) */
+ long a_text; /* size of text segement in bytes */
+ long a_data; /* size of data segment in bytes */
+ long a_bss; /* size of bss segment in bytes */
+ long a_entry; /* entry point */
+ long a_total; /* total memory allocated */
+ long a_syms; /* size of symbol table */
+
+ /* SHORT FORM ENDS HERE */
+ long a_trsize; /* text relocation size */
+ long a_drsize; /* data relocation size */
+ long a_tbase; /* text relocation base */
+ long a_dbase; /* data relocation base */
+};
+
+#define A_MAGIC0 (unsigned char) 0x01
+#define A_MAGIC1 (unsigned char) 0x03
+#define BADMAG(X) ((X).a_magic[0] != A_MAGIC0 ||(X).a_magic[1] != A_MAGIC1)
+
+/* CPU Id of TARGET machine (byte order coded in low order two bits) */
+#define A_NONE 0x00 /* unknown */
+#define A_I8086 0x04 /* intel i8086/8088 */
+#define A_M68K 0x0B /* motorola m68000 */
+#define A_NS16K 0x0C /* national semiconductor 16032 */
+#define A_I80386 0x10 /* intel i80386 */
+#define A_SPARC 0x17 /* Sun SPARC */
+
+#define A_BLR(cputype) ((cputype&0x01)!=0) /* TRUE if bytes left-to-right */
+#define A_WLR(cputype) ((cputype&0x02)!=0) /* TRUE if words left-to-right */
+
+/* Flags. */
+#define A_UZP 0x01 /* unmapped zero page (pages) */
+#define A_PAL 0x02 /* page aligned executable */
+#define A_NSYM 0x04 /* new style symbol table */
+#define A_IMG 0x08 /* image instead of executable (e.g. root FS) */
+#define A_EXEC 0x10 /* executable */
+#define A_SEP 0x20 /* separate I/D */
+#define A_PURE 0x40 /* pure text */ /* not used */
+#define A_TOVLY 0x80 /* text overlay */ /* not used */
+
+/* Offsets of various things. */
+#define A_MINHDR 32
+#define A_TEXTPOS(X) ((long)(X).a_hdrlen)
+#define A_DATAPOS(X) (A_TEXTPOS(X) + (X).a_text)
+#define A_HASRELS(X) ((X).a_hdrlen > (unsigned char) A_MINHDR)
+#define A_HASEXT(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 8))
+#define A_HASLNS(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 16))
+#define A_HASTOFF(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 24))
+#define A_TRELPOS(X) (A_DATAPOS(X) + (X).a_data)
+#define A_DRELPOS(X) (A_TRELPOS(X) + (X).a_trsize)
+#define A_SYMPOS(X) (A_TRELPOS(X) + (A_HASRELS(X) ? \
+ ((X).a_trsize + (X).a_drsize) : 0))
+
+struct reloc {
+ long r_vaddr; /* virtual address of reference */
+ unsigned short r_symndx; /* internal segnum or extern symbol num */
+ unsigned short r_type; /* relocation type */
+};
+
+/* r_type values: */
+#define R_ABBS 0
+#define R_RELLBYTE 2
+#define R_PCRBYTE 3
+#define R_RELWORD 4
+#define R_PCRWORD 5
+#define R_RELLONG 6
+#define R_PCRLONG 7
+#define R_REL3BYTE 8
+#define R_KBRANCHE 9
+
+/* r_symndx for internal segments */
+#define S_ABS ((unsigned short)-1)
+#define S_TEXT ((unsigned short)-2)
+#define S_DATA ((unsigned short)-3)
+#define S_BSS ((unsigned short)-4)
+
+struct nlist { /* symbol table entry */
+ char n_name[8]; /* symbol name */
+ long n_value; /* value */
+ unsigned char n_sclass; /* storage class */
+ unsigned char n_numaux; /* number of auxiliary entries (not used) */
+ unsigned short n_type; /* language base and derived type (not used) */
+};
+
+/* Low bits of storage class (section). */
+#define N_SECT 07 /* section mask */
+#define N_UNDF 00 /* undefined */
+#define N_ABS 01 /* absolute */
+#define N_TEXT 02 /* text */
+#define N_DATA 03 /* data */
+#define N_BSS 04 /* bss */
+#define N_COMM 05 /* (common) */
+
+/* High bits of storage class. */
+#define N_CLASS 0370 /* storage class mask */
+#define C_NULL
+#define C_EXT 0020 /* external symbol */
+#define C_STAT 0030 /* static */
+
+/* Function prototypes. */
+#ifndef _MINIX_ANSI_H
+#include <minix/ansi.h>
+#endif
+
+_PROTOTYPE( int nlist, (char *_file, struct nlist *_nl) );
+
+#endif /* _AOUT_H */
--- /dev/null
+/* The <pwd.h> header defines the items in the password file. */
+
+#ifndef _PWD_H
+#define _PWD_H
+
+#ifndef _TYPES_H
+#include <minix/types.h>
+#endif
+
+struct passwd {
+ char *pw_name; /* login name */
+ uid_t pw_uid; /* uid corresponding to the name */
+ gid_t pw_gid; /* gid corresponding to the name */
+ char *pw_dir; /* user's home directory */
+ char *pw_shell; /* name of the user's shell */
+
+ /* The following members are not defined by POSIX. */
+ char *pw_passwd; /* password information */
+ char *pw_gecos; /* just in case you have a GE 645 around */
+};
+
+/* Function Prototypes. */
+_PROTOTYPE( struct passwd *getpwnam, (const char *_name) );
+_PROTOTYPE( struct passwd *getpwuid, (uid_t _uid) );
+
+#ifdef _MINIX
+_PROTOTYPE( void endpwent, (void) );
+_PROTOTYPE( struct passwd *getpwent, (void) );
+_PROTOTYPE( int setpwent, (void) );
+_PROTOTYPE( void setpwfile, (const char *_file) );
+_PROTOTYPE( const char *user_from_uid, (uid_t, int) );
+#endif
+
+#endif /* _PWD_H */
--- /dev/null
+/* The <regexp.h> header is used by the (V8-compatible) regexp(3) routines. */
+/* NOTE: Obsoleted by the POSIX regex(3) library. */
+
+#ifndef _REGEXP_H
+#define _REGEXP_H
+
+#include <sys/cdefs.h>
+
+#define CHARBITS 0377
+#define NSUBEXP 10
+typedef struct regexp {
+ const char *startp[NSUBEXP];
+ const char *endp[NSUBEXP];
+ char regstart; /* Internal use only. */
+ char reganch; /* Internal use only. */
+ char *regmust; /* Internal use only. */
+ int regmlen; /* Internal use only. */
+ char program[1]; /* Unwarranted chumminess with compiler. */
+} regexp;
+
+/* Keep these functions away from the POSIX versions. */
+#define regcomp _v8_regcomp
+#define regexec _v8_regexec
+#define regsub _v8_regsub
+#define regerror _v8_regerror
+
+/* Function Prototypes. */
+regexp *regcomp(const char *_exp);
+int regexec(regexp *_prog, const char *_string, int _bolflag);
+void regsub(regexp *_prog, char *_source, char *_dest);
+void regerror(const char *_message) ;
+
+#endif /* _REGEXP_H */
+
+/*
+ * $PchId: regexp.h,v 1.4 1996/04/10 21:43:17 philip Exp $
+ */
--- /dev/null
+#ifndef _COMPAT_SYSLOG_H
+#define _COMPAT_SYSLOG_H
+
+#include <syslog.h>
+#define FacNames facilitynames
+#define PriNames prioritynames
+
+#endif
--- /dev/null
+/* configfile.h - Generic configuration file format.
+ * Author: Kees J. Bot
+ * 5 Jun 1999
+ */
+#ifndef _CONFIGFILE_H
+#define _CONFIGFILE_H
+
+/* Data can only be modified inside the library. */
+#ifndef _c
+#define _c const
+#endif
+
+typedef _c struct config { /* Contents of a generic configuration file. */
+_c struct config *next; /* Next configuration file thing. */
+_c struct config *list; /* For a { sublist }. */
+ const char *file; /* File and line where this is found. */
+ unsigned line;
+ int flags; /* Special flags. */
+ char word[1]; /* Payload. */
+} config_t;
+
+#define CFG_CLONG 0x0001 /* strtol(word, &end, 0) is valid. */
+#define CFG_OLONG 0x0002 /* strtol(word, &end, 010). */
+#define CFG_DLONG 0x0004 /* strtol(word, &end, 10). */
+#define CFG_XLONG 0x0008 /* strtol(word, &end, 0x10). */
+#define CFG_CULONG 0x0010 /* strtoul(word, &end, 0). */
+#define CFG_OULONG 0x0020 /* strtoul(word, &end, 010). */
+#define CFG_DULONG 0x0040 /* strtoul(word, &end, 10). */
+#define CFG_XULONG 0x0080 /* strtoul(word, &end, 0x10). */
+#define CFG_STRING 0x0100 /* The word is enclosed in quotes. */
+#define CFG_SUBLIST 0x0200 /* This is a sublist, so no word. */
+#define CFG_ESCAPED 0x0400 /* Escapes are still marked with \. */
+
+config_t *config_read(const char *_file, int flags, config_t *_cfg);
+void config_delete(config_t *_cfg);
+int config_renewed(config_t *_cfg);
+size_t config_length(config_t *_cfg);
+#define config_issub(cfg) (!!((cfg)->flags & CFG_SUBLIST))
+#define config_isatom(cfg) (!config_issub(cfg))
+#define config_isstring(cfg) (!!((cfg)->flags & CFG_STRING))
+
+#undef _c
+
+#endif /* _CONFIGFILE_H */
--- /dev/null
+#ifndef _TERMCAP_H
+#define _TERMCAP_H
+
+#include <minix/ansi.h>
+
+_PROTOTYPE( int tgetent, (char *_bp, char *_name) );
+_PROTOTYPE( int tgetflag, (char *_id) );
+_PROTOTYPE( int tgetnum, (char *_id) );
+_PROTOTYPE( char *tgetstr, (char *_id, char **_area) );
+_PROTOTYPE( char *tgoto, (char *_cm, int _destcol, int _destline) );
+_PROTOTYPE( int tputs, (char *_cp, int _affcnt, void (*_outc)(int)) );
+
+#endif /* _TERMCAP_H */
--- /dev/null
+/* This package consists of 4 routines for handling the /etc/mtab file.
+ * The /etc/mtab file contains information about the root and mounted file
+ * systems as a series of lines, each one with exactly four fields separated
+ * by one space as follows:
+ *
+ * special mounted_on version rw_flag
+ *
+ * where
+ * special is the name of the block special file
+ * mounted_on is the directory on which it is mounted
+ * version is either 1 or 2 for MINIX V1 and V2 file systems
+ * rw_flag is rw or ro for read/write or read only
+ *
+ * An example /etc/mtab:
+ *
+ * /dev/ram / 2 rw
+ * /dev/hd1 /usr 2 rw
+ * /dev/fd0 /user 1 ro
+ *
+ *
+ * The four routines for handling /etc/mtab are as follows. They use two
+ * (hidden) internal buffers, mtab_in for input and mtab_out for output.
+ *
+ * load_mtab(&prog_name) - read /etc/mtab into mtab_in
+ * get_mtab_entry(&s1, &s2, &s3, &s4) - arrays that are filled in
+ * put_mtab_entry(&s1, &s2, &s3, &s4) - append a line to mtab_out
+ * rewrite_mtab(&prog_name) - write mtab_out to /etc/mtab
+ *
+ * If load_mtab and rewrite_mtab work, they return 0. If they fail, they
+ * print their own error messages on stderr and return -1. When get_mtab_entry
+ * runs out of entries to return, it sets the first pointer to NULL and returns
+ * -1 instead of 0. Also, rewrite_mtab returns -1 if it fails.
+ */
+
+#include <sys/types.h>
+#include <minix/minlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define BUF_SIZE 512 /* size of the /etc/mtab buffer */
+
+char *etc_mtab = "/etc/mtab"; /* name of the /etc/mtab file */
+static char mtab_in[BUF_SIZE+1]; /* holds /etc/mtab when it is read in */
+static char mtab_out[BUF_SIZE+1]; /* buf to build /etc/mtab for output later */
+static char *iptr = mtab_in; /* pointer to next line to feed out. */
+static char *optr = mtab_out; /* pointer to place where next line goes */
+
+_PROTOTYPE(int load_mtab, (char *prog_name ));
+_PROTOTYPE(int rewrite_mtab, (char *prog_name ));
+_PROTOTYPE(int get_mtab_entry, (char *special, char *mounted_on,
+ char *version, char *rw_flag));
+_PROTOTYPE(int put_mtab_entry, (char *special, char *mounted_on,
+ char *version, char *rw_flag));
+_PROTOTYPE(void err, (char *prog_name, char *str ));
+
+
+int load_mtab(prog_name)
+char *prog_name;
+{
+/* Read in /etc/mtab and store it in /etc/mtab. */
+
+ int fd, n;
+ char *ptr;
+
+ /* Open the file. */
+ fd = open(etc_mtab, O_RDONLY);
+ if (fd < 0) {
+ err(prog_name, ": cannot open ");
+ return(-1);
+ }
+
+ /* File opened. Read it in. */
+ n = read(fd, mtab_in, BUF_SIZE);
+ if (n <= 0) {
+ /* Read failed. */
+ err(prog_name, ": cannot read ");
+ return(-1);
+ }
+ if (n == BUF_SIZE) {
+ /* Some nut has mounted 50 file systems or something like that. */
+ std_err(prog_name);
+ std_err(": file too large: ");
+ std_err(etc_mtab);
+ return(-1);
+ }
+
+ close(fd);
+
+ /* Replace all the whitespace by '\0'. */
+ ptr = mtab_in;
+ while (*ptr != '\0') {
+ if (isspace(*ptr)) *ptr = '\0';
+ ptr++;
+ }
+ return(0);
+}
+
+
+int rewrite_mtab(prog_name)
+char *prog_name;
+{
+/* Write mtab_out to /etc/mtab. */
+
+ int fd, n;
+
+ /* Do a creat to truncate the file. */
+ fd = creat(etc_mtab, 0777);
+ if (fd < 0) {
+ err(prog_name, ": cannot overwrite ");
+ return(-1);
+ }
+
+ /* File created. Write it. */
+ n = write(fd, mtab_out, (unsigned int)(optr - mtab_out));
+ if (n <= 0) {
+ /* Write failed. */
+ err(prog_name, " could not write ");
+ return(-1);
+ }
+
+ close(fd);
+ return(0);
+}
+
+
+int get_mtab_entry(special, mounted_on, version, rw_flag)
+char *special;
+char *mounted_on;
+char *version;
+char *rw_flag;
+{
+/* Return the next entry from mtab_in. */
+
+ if (iptr >= &mtab_in[BUF_SIZE]) {
+ special[0] = '\0';
+ return(-1);
+ }
+
+ strcpy(special, iptr);
+ while (isprint(*iptr)) iptr++;
+ while (*iptr == '\0'&& iptr < &mtab_in[BUF_SIZE]) iptr++;
+
+ strcpy(mounted_on, iptr);
+ while (isprint(*iptr)) iptr++;
+ while (*iptr == '\0'&& iptr < &mtab_in[BUF_SIZE]) iptr++;
+
+ strcpy(version, iptr);
+ while (isprint(*iptr)) iptr++;
+ while (*iptr == '\0'&& iptr < &mtab_in[BUF_SIZE]) iptr++;
+
+ strcpy(rw_flag, iptr);
+ while (isprint(*iptr)) iptr++;
+ while (*iptr == '\0'&& iptr < &mtab_in[BUF_SIZE]) iptr++;
+ return(0);
+}
+
+
+int put_mtab_entry(special, mounted_on, version, rw_flag)
+char *special;
+char *mounted_on;
+char *version;
+char *rw_flag;
+{
+/* Append an entry to the mtab_out buffer. */
+
+ int n1, n2, n3, n4;
+
+ n1 = strlen(special);
+ n2 = strlen(mounted_on);
+ n3 = strlen(version);
+ n4 = strlen(rw_flag);
+
+ if (optr + n1 + n2 + n3 + n4 + 5 >= &mtab_out[BUF_SIZE]) return(-1);
+ strcpy(optr, special);
+ optr += n1;
+ *optr++ = ' ';
+
+ strcpy(optr, mounted_on);
+ optr += n2;
+ *optr++ = ' ';
+
+ strcpy(optr, version);
+ optr += n3;
+ *optr++ = ' ';
+
+ strcpy(optr, rw_flag);
+ optr += n4;
+ *optr++ = '\n';
+ return(0);
+}
+
+
+void
+err(prog_name, str)
+char *prog_name, *str;
+{
+ std_err(prog_name);
+ std_err(str);
+ std_err(etc_mtab);
+ perror(" ");
+}
--- /dev/null
+/*
+ * "nlist.c", Peter Valkenburg, january 1989.
+ */
+
+#include <lib.h>
+#include <string.h>
+#include <a.out.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define fail(fp) (fclose(fp), -1) /* ret. exp. when nlist fails */
+
+_PROTOTYPE( int nlist, (char *file, struct nlist nl[]));
+
+/*
+ * Nlist fills fields n_sclass and n_value of array nl with values found in
+ * non-stripped executable file. Entries that are not found have their
+ * n_value/n_sclass fields set to 0. Nl ends with a 0 or nul string n_name.
+ * The return value is -1 on failure, else the number of entries not found.
+ */
+int nlist(file, nl)
+char *file;
+struct nlist nl[];
+{
+ int nents, nsrch, nfound, i;
+ struct nlist nlent;
+ FILE *fp;
+ struct exec hd;
+
+ /* open executable with namelist */
+ if ((fp = fopen(file, "r")) == NULL)
+ return -1;
+
+ /* get header and seek to start of namelist */
+ if (fread((char *) &hd, sizeof(struct exec), 1, fp) != 1 ||
+ BADMAG(hd) || fseek(fp, A_SYMPOS(hd), SEEK_SET) != 0)
+ return fail(fp);
+
+ /* determine number of entries searched for & reset fields */
+ nsrch = 0;
+ while (nl[nsrch].n_name != NULL && *(nl[nsrch].n_name) != '\0') {
+ nl[nsrch].n_sclass = 0;
+ nl[nsrch].n_value = 0;
+ nl[nsrch].n_type = 0; /* for compatability */
+ nsrch++;
+ }
+
+ /* loop through namelist & fill in user array */
+ nfound = 0;
+ for (nents = (hd.a_syms & 0xFFFF) / sizeof(struct nlist);
+ nents > 0; nents--) {
+ if (nsrch == nfound)
+ break; /* no need to look further */
+ if (fread((char *) &nlent, sizeof(struct nlist), 1, fp) != 1)
+ return fail(fp);
+ for (i = 0; i < nsrch; i++)
+ if (nl[i].n_sclass == 0 &&
+ strncmp(nl[i].n_name, nlent.n_name,
+ sizeof(nlent.n_name)) == 0) {
+ nl[i] = nlent;
+ nfound++;
+ break;
+ }
+ }
+
+ (void) fclose(fp);
+
+ return nsrch - nfound;
+}
--- /dev/null
+#include <lib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+void std_err(const char *s)
+{
+ register const char *p = s;
+
+ while (*p != 0) p++;
+ write(2, s, (int) (p - s));
+}
--- /dev/null
+/*
+ * termcap.c V1.1 20/7/87 agc Joypace Ltd
+ *
+ * Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
+ * This file may be freely distributed provided that this notice
+ * remains attached.
+ *
+ * A public domain implementation of the termcap(3) routines.
+ *
+ *
+ *
+ * Klamer Schutte V1.2 Nov. 1988
+ *
+ * - Can match multiple terminal names [tgetent]
+ * - Removal of **area assignments [tgetstr]
+ *
+ * Terrence W. Holm V1.3 May, Sep, Oct. 1988
+ *
+ * - Correct when TERM != name and TERMCAP is defined [tgetent]
+ * - Correct the comparison for the terminal name [tgetent]
+ * - Correct the value of ^x escapes [tgetstr]
+ * - Added %r to reverse row/column [tgoto]
+ * - Fixed end of definition test [tgetnum/flag/str]
+ *
+ * Terrence W. Holm V1.4 Jan. 1989
+ *
+ * - Incorporated Klamer's V1.2 fixes into V1.3
+ * - Added %d, (old %d is now %2) [tgoto]
+ * - Allow '#' comments in definition file [tgetent]
+ */
+
+#include <sys/cdefs.h>
+#include <lib.h>
+#include <termcap.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+char *capab = (char *)NULL; /* the capability itself */
+
+#if 0
+/* The following are not yet used. */
+extern short ospeed; /* output speed */
+extern char PC; /* padding character */
+extern char *BC; /* back cursor movement */
+extern char *UP; /* up cursor movement */
+#endif
+
+/*
+ * tgetent - get the termcap entry for terminal name, and put it
+ * in bp (which must be an array of 1024 chars). Returns 1 if
+ * termcap entry found, 0 if not found, and -1 if file not found.
+ */
+
+int tgetent(bp, name)
+char *bp;
+char *name;
+{
+ FILE *fp;
+ char *file;
+ char *term;
+ short len = strlen(name);
+
+ capab = bp;
+
+ /* If TERMCAP begins with a '/' then use TERMCAP as the path */
+ /* Name of the termcap definitions file. If TERMCAP is a */
+ /* Definition and TERM equals "name" then use TERMCAP as the */
+ /* Definition. Otherwise use "/etc/termcap" as the path name. */
+
+ if ((file = getenv("TERMCAP")) == (char *)NULL)
+ file = "/etc/termcap";
+ else if (*file != '/')
+ if ((term = getenv("TERM")) != (char *)NULL && strcmp(term, name) == 0) {
+ *bp = '\0';
+ strncat(bp, file, 1023);
+ return(1);
+ } else
+ file = "/etc/termcap";
+
+ if ((fp = fopen(file, "r")) == (FILE *) NULL) {
+ capab = (char *)NULL; /* no valid termcap */
+ return(-1);
+ }
+ for (;;) {
+ /* Read in each definition */
+ int def_len = 0;
+ char *cp = bp;
+
+ do {
+ if (fgets(&bp[def_len], (unsigned int)(1024 - def_len), fp) == (char *)NULL) {
+ fclose(fp);
+ capab = (char *)NULL; /* no valid termcap */
+ return(0);
+ }
+ def_len = strlen(bp) - 2;
+ } while (bp[def_len] == '\\');
+
+ while (isspace(*cp)) cp++;
+
+ /* Comment lines start with a '#' */
+ if (*cp == '#') continue;
+
+ /* See if any of the terminal names in this definition */
+ /* Match "name". */
+
+ do {
+ if (strncmp(name, cp, len) == 0 &&
+ (cp[len] == '|' || cp[len] == ':')) {
+ fclose(fp);
+ return(1);
+ }
+ while ((*cp) && (*cp != '|') && (*cp != ':')) cp++;
+ } while (*cp++ == '|');
+ }
+}
+
+
+/*
+ * tgetnum - get the numeric terminal capability corresponding
+ * to id. Returns the value, -1 if invalid.
+ */
+
+int tgetnum(id)
+char *id;
+{
+ register char *cp = capab;
+
+ if (cp == (char *)NULL || id == (char *)NULL) return(-1);
+
+ for (;;) {
+ while (*cp++ != ':')
+ if (cp[-1] == '\0') return(-1);
+
+ while (isspace(*cp)) cp++;
+
+ if (strncmp(cp, id, 2) == 0 && cp[2] == '#') return(atoi(cp + 3));
+ }
+}
+
+
+/*
+ * tgetflag - get the boolean flag corresponding to id. Returns -1
+ * if invalid, 0 if the flag is not in termcap entry, or 1 if it is
+ * present.
+ */
+
+int tgetflag(id)
+char *id;
+{
+ register char *cp = capab;
+
+ if (cp == (char *)NULL || id == (char *)NULL) return(-1);
+
+ for (;;) {
+ while (*cp++ != ':')
+ if (cp[-1] == '\0') return(0);
+
+ while (isspace(*cp)) cp++;
+
+ if (strncmp(cp, id, 2) == 0) return(1);
+ }
+}
+
+
+/*
+ * tgetstr - get the string capability corresponding to id and place
+ * it in area (advancing area at same time). Expand escape sequences
+ * etc. Returns the string, or NULL if it can't do it.
+ */
+
+char *tgetstr(id, area)
+char *id;
+char **area;
+{
+ register char *cp = capab;
+ register char *wsp = *area; /* workspace pointer */
+
+ if (cp == (char *)NULL || id == (char *)NULL) return((char *)NULL);
+
+ for (;;) {
+ while (*cp++ != ':')
+ if (cp[-1] == '\0') return((char *)NULL);
+
+ while (isspace(*cp)) cp++;
+
+ if (strncmp(cp, id, 2) == 0 && cp[2] == '=') {
+ for (cp += 3; *cp && *cp != ':'; wsp++, cp++) switch (*cp) {
+ case '^':
+ *wsp = *++cp - '@';
+ break;
+
+ case '\\':
+ switch (*++cp) {
+ case 'E':
+ *wsp = '\033';
+ break;
+ case 'n':
+ *wsp = '\n';
+ break;
+ case 'r':
+ *wsp = '\r';
+ break;
+ case 't':
+ *wsp = '\t';
+ break;
+ case 'b':
+ *wsp = '\b';
+ break;
+ case 'f':
+ *wsp = '\f';
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ {
+ int i;
+ int t = 0;
+ for (i = 0; i < 3 &&
+ isdigit(*cp); ++i, ++cp)
+ t = t * 8 + *cp - '0';
+ *wsp = t;
+ cp--;
+ break;
+ }
+ default:
+ *wsp = *cp;
+ }
+ break;
+
+ default: *wsp = *cp;
+ }
+
+ *wsp++ = '\0';
+
+ {
+ char *ret = *area;
+ *area = wsp;
+ return(ret);
+ }
+ }
+ } /* end for(;;) */
+}
+
+
+
+/*
+ * tgoto - given the cursor motion string cm, make up the string
+ * for the cursor to go to (destcol, destline), and return the string.
+ * Returns "OOPS" if something's gone wrong, or the string otherwise.
+ */
+
+char *tgoto(cm, destcol, destline)
+char *cm;
+int destcol;
+int destline;
+{
+ PRIVATE char ret[24];
+ char *rp = ret;
+ int incr = 0;
+ int argno = 0;
+ int numval;
+
+ for (; *cm; cm++) {
+ if (*cm == '%') {
+ switch (*++cm) {
+ case 'i': incr = 1; break;
+
+ case 'r': argno = 1; break;
+
+ case '+':
+ numval = (argno == 0 ? destline : destcol);
+ *rp++ = numval + incr + *++cm;
+ argno = 1 - argno;
+ break;
+
+ case '2':
+ numval = (argno == 0 ? destline : destcol);
+ numval = (numval + incr) % 100;
+ *rp++ = '0' + (numval / 10);
+ *rp++ = '0' + (numval % 10);
+ argno = 1 - argno;
+ break;
+
+ case 'd':
+ numval = (argno == 0 ? destline : destcol);
+ numval = (numval + incr) % 1000;
+ if (numval > 99) *rp++ = '0' + (numval / 100);
+ if (numval > 9) *rp++ = '0' + (numval / 10) % 10;
+ *rp++ = '0' + (numval % 10);
+ argno = 1 - argno;
+ break;
+
+ case '%': *rp++ = '%'; break;
+
+ default: return("OOPS");
+ }
+
+ } else
+ *rp++ = *cm;
+ }
+
+ *rp = '\0';
+ return(ret);
+}
+
+
+
+/*
+ * tputs - put the string cp out onto the terminal, using the function
+ * outc. This should do padding for the terminal, but I can't find a
+ * terminal that needs padding at the moment...
+ */
+
+int tputs(cp, affcnt, outc)
+register char *cp;
+int affcnt;
+_PROTOTYPE( void (*outc), (int ch));
+{
+ if (cp == (char *)NULL) return(1);
+ /* Do any padding interpretation - left null for MINIX just now */
+ while (*cp) (*outc) (*cp++);
+ return(1);
+}
--- /dev/null
+/* regerror() - Default regexp error report Author: Kees J. Bot
+ * 12 Jun 1999
+ *
+ * A better version of this routine should be supplied by the user in
+ * the program using regexps.
+ */
+#include <stdio.h>
+#define const /* avoid "const poisoning" */
+#include <compat/regexp.h>
+#undef const
+
+void regerror(char *message)
+{
+ fprintf(stderr, "regexp error: %s\n", message);
+}
--- /dev/null
+/* regcomp and regexec -- regsub and regerror are elsewhere
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ *
+ * The third parameter to regexec was added by Martin C. Atkins.
+ * Andy Tanenbaum also made some changes.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#define const /* avoid "const poisoning" */
+#include <compat/regexp.h>
+#undef const
+
+/* The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
+
+/* The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart char that must begin a match; '\0' if none obvious
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * regmlen length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+/* Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives. (Here we
+ * have one of the subtle syntax dependencies: an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.) The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM. In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects
+ * to the thing following the set of BRANCHes.) The opcodes are:
+ */
+
+/* Definition number opnd? meaning */
+#define END 0 /* no End of program. */
+#define BOL 1 /* no Match "" at beginning of line. */
+#define EOL 2 /* no Match "" at end of line. */
+#define ANY 3 /* no Match any one character. */
+#define ANYOF 4 /* str Match any character in this string. */
+#define ANYBUT 5 /* str Match any character not in this
+ * string. */
+#define BRANCH 6 /* node Match this alternative, or the
+ * next... */
+#define BACK 7 /* no Match "", "next" ptr points backward. */
+#define EXACTLY 8 /* str Match this string. */
+#define NOTHING 9 /* no Match empty string. */
+#define STAR 10 /* node Match this (simple) thing 0 or more
+ * times. */
+#define PLUS 11 /* node Match this (simple) thing 1 or more
+ * times. */
+#define OPEN 20 /* no Mark this point in input as start of
+ * #n. */
+ /* OPEN+1 is number 1, etc. */
+#define CLOSE 30 /* no Analogous to OPEN. */
+
+/* Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "next" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "next" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "next" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "next" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
+ * BRANCH structures using BACK. Simple cases (one character
+ * per match) are implemented with STAR and PLUS for speed
+ * and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE ...are numbered at compile time.
+ */
+
+/* A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define OP(p) (*(p))
+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define OPERAND(p) ((p) + 3)
+
+/* Utility definitions.
+ */
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+#define CFAIL(m) { regerror(m); return((char *)NULL); }
+#define RFAIL(m) { regerror(m); return((regexp *)NULL); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
+#define META "^$.[()|?+*\\"
+
+/* Flags to be passed up and down.
+ */
+#define HASWIDTH 01 /* Known never to match null string. */
+#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
+#define SPSTART 04 /* Starts with * or +. */
+#define WORST 0 /* Worst case. */
+
+/* Global work variables for regcomp().
+ */
+static char *regparse; /* Input-scan pointer. */
+static int regnpar; /* () count. */
+static char regdummy;
+static char *regcode; /* Code-emit pointer; ®dummy = don't. */
+static long regsize; /* Code size. */
+
+/* Forward declarations for regcomp()'s friends.
+ */
+static char *reg(int paren, int *flagp);
+static char *regbranch(int *flagp);
+static char *regpiece(int *flagp);
+static char *regatom(int *flagp);
+static char *regnode(int op);
+static char *regnext(char *p);
+static void regc(int b);
+static void reginsert(int op, char *opnd);
+static void regtail(char *p, char *val);
+static void regoptail(char *p, char *val);
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *regcomp(exp)
+char *exp;
+{
+ register regexp *r;
+ register char *scan;
+ register char *longest;
+ register int len;
+ int flags;
+
+ if (exp == (char *)NULL) RFAIL("NULL argument");
+
+ /* First pass: determine size, legality. */
+ regparse = exp;
+ regnpar = 1;
+ regsize = 0L;
+ regcode = ®dummy;
+ regc(MAGIC);
+ if (reg(0, &flags) == (char *)NULL) return((regexp *)NULL);
+
+ /* Small enough for pointer-storage convention? */
+ if (regsize >= 32767L) /* Probably could be 65535L. */
+ RFAIL("regexp too big");
+
+ /* Allocate space. */
+ r = (regexp *) malloc(sizeof(regexp) + (unsigned) regsize);
+ if (r == (regexp *)NULL) RFAIL("out of space");
+
+ /* Second pass: emit code. */
+ regparse = exp;
+ regnpar = 1;
+ regcode = r->program;
+ regc(MAGIC);
+ if (reg(0, &flags) == (char *)NULL) return((regexp *)NULL);
+
+ /* Dig out information for optimizations. */
+ r->regstart = '\0'; /* Worst-case defaults. */
+ r->reganch = 0;
+ r->regmust = (char *)NULL;
+ r->regmlen = 0;
+ scan = r->program + 1; /* First BRANCH. */
+ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
+ scan = OPERAND(scan);
+
+ /* Starting-point info. */
+ if (OP(scan) == EXACTLY)
+ r->regstart = *OPERAND(scan);
+ else if (OP(scan) == BOL)
+ r->reganch++;
+
+ /* If there's something expensive in the r.e., find the
+ * longest literal string that must appear and make it the
+ * regmust. Resolve ties in favor of later strings, since
+ * the regstart check works with the beginning of the r.e.
+ * and avoiding duplication strengthens checking. Not a
+ * strong reason, but sufficient in the absence of others. */
+ if (flags & SPSTART) {
+ longest = (char *)NULL;
+ len = 0;
+ for (; scan != (char *)NULL; scan = regnext(scan))
+ if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+ longest = OPERAND(scan);
+ len = strlen(OPERAND(scan));
+ }
+ r->regmust = longest;
+ r->regmlen = len;
+ }
+ }
+ return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *reg(paren, flagp)
+int paren; /* Parenthesized? */
+int *flagp;
+{
+ register char *ret;
+ register char *br;
+ register char *ender;
+ register int parno;
+ int flags;
+
+ *flagp = HASWIDTH; /* Tentatively. */
+
+ /* Make an OPEN node, if parenthesized. */
+ if (paren) {
+ if (regnpar >= NSUBEXP) CFAIL("too many ()");
+ parno = regnpar;
+ regnpar++;
+ ret = regnode(OPEN + parno);
+ } else {
+ parno = 0; /* not actually used, keep compiler quiet */
+ ret = (char *)NULL;
+ }
+
+ /* Pick up the branches, linking them together. */
+ br = regbranch(&flags);
+ if (br == (char *)NULL) return((char *)NULL);
+ if (ret != (char *)NULL)
+ regtail(ret, br); /* OPEN -> first. */
+ else
+ ret = br;
+ if (!(flags & HASWIDTH)) *flagp &= ~HASWIDTH;
+ *flagp |= flags & SPSTART;
+ while (*regparse == '|') {
+ regparse++;
+ br = regbranch(&flags);
+ if (br == (char *)NULL) return((char *)NULL);
+ regtail(ret, br); /* BRANCH -> BRANCH. */
+ if (!(flags & HASWIDTH)) *flagp &= ~HASWIDTH;
+ *flagp |= flags & SPSTART;
+ }
+
+ /* Make a closing node, and hook it on the end. */
+ ender = regnode((paren) ? CLOSE + parno : END);
+ regtail(ret, ender);
+
+ /* Hook the tails of the branches to the closing node. */
+ for (br = ret; br != (char *)NULL; br = regnext(br)) regoptail(br, ender);
+
+ /* Check for proper termination. */
+ if (paren && *regparse++ != ')') {
+ CFAIL("unmatched ()");
+ } else if (!paren && *regparse != '\0') {
+ if (*regparse == ')') {
+ CFAIL("unmatched ()");
+ } else
+ CFAIL("junk on end"); /* "Can't happen". */
+ /* NOTREACHED */
+ }
+ return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *regbranch(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char *chain;
+ register char *latest;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ ret = regnode(BRANCH);
+ chain = (char *)NULL;
+ while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
+ latest = regpiece(&flags);
+ if (latest == (char *)NULL) return((char *)NULL);
+ *flagp |= flags & HASWIDTH;
+ if (chain == (char *)NULL) /* First piece. */
+ *flagp |= flags & SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ }
+ if (chain == (char *)NULL) /* Loop ran zero times. */
+ regnode(NOTHING);
+
+ return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized: they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *regpiece(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char op;
+ register char *next;
+ int flags;
+
+ ret = regatom(&flags);
+ if (ret == (char *)NULL) return((char *)NULL);
+
+ op = *regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+ if (!(flags & HASWIDTH) && op != '?') CFAIL("*+ operand could be empty");
+ *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
+
+ if (op == '*' && (flags & SIMPLE))
+ reginsert(STAR, ret);
+ else if (op == '*') {
+ /* Emit x* as (x&|), where & means "self". */
+ reginsert(BRANCH, ret); /* Either x */
+ regoptail(ret, regnode(BACK)); /* and loop */
+ regoptail(ret, ret); /* back */
+ regtail(ret, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '+' && (flags & SIMPLE))
+ reginsert(PLUS, ret);
+ else if (op == '+') {
+ /* Emit x+ as x(&|), where & means "self". */
+ next = regnode(BRANCH); /* Either */
+ regtail(ret, next);
+ regtail(regnode(BACK), ret); /* loop back */
+ regtail(next, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '?') {
+ /* Emit x? as (x|) */
+ reginsert(BRANCH, ret); /* Either x */
+ regtail(ret, regnode(BRANCH)); /* or */
+ next = regnode(NOTHING);/* null. */
+ regtail(ret, next);
+ regoptail(ret, next);
+ }
+ regparse++;
+ if (ISMULT(*regparse)) CFAIL("nested *?+");
+
+ return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run. Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char *regatom(flagp)
+int *flagp;
+{
+ register char *ret;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ switch (*regparse++) {
+ case '^': ret = regnode(BOL); break;
+ case '$': ret = regnode(EOL); break;
+ case '.':
+ ret = regnode(ANY);
+ *flagp |= HASWIDTH | SIMPLE;
+ break;
+ case '[':{
+ register int class;
+ register int classend;
+
+ if (*regparse == '^') { /* Complement of range. */
+ ret = regnode(ANYBUT);
+ regparse++;
+ } else
+ ret = regnode(ANYOF);
+ if (*regparse == ']' || *regparse == '-') regc(*regparse++);
+ while (*regparse != '\0' && *regparse != ']') {
+ if (*regparse == '-') {
+ regparse++;
+ if (*regparse == ']' || *regparse == '\0')
+ regc('-');
+ else {
+ class = UCHARAT(regparse - 2) + 1;
+ classend = UCHARAT(regparse);
+ if (class > classend + 1)
+ CFAIL("invalid [] range");
+ for (; class <= classend; class++)
+ regc(class);
+ regparse++;
+ }
+ } else
+ regc(*regparse++);
+ }
+ regc('\0');
+ if (*regparse != ']') CFAIL("unmatched []");
+ regparse++;
+ *flagp |= HASWIDTH | SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(1, &flags);
+ if (ret == (char *)NULL) return((char *)NULL);
+ *flagp |= flags & (HASWIDTH | SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case ')':
+ CFAIL("internal urp"); /* Supposed to be caught earlier. */
+ break;
+ case '?':
+ case '+':
+ case '*': CFAIL("?+* follows nothing"); break;
+ case '\\':
+ if (*regparse == '\0') CFAIL("trailing \\");
+ ret = regnode(EXACTLY);
+ regc(*regparse++);
+ regc('\0');
+ *flagp |= HASWIDTH | SIMPLE;
+ break;
+ default:{
+ register int len;
+ register char ender;
+
+ regparse--;
+ len = strcspn(regparse, META);
+ if (len <= 0) CFAIL("internal disaster");
+ ender = *(regparse + len);
+ if (len > 1 && ISMULT(ender))
+ len--; /* Back off clear of ?+* operand. */
+ *flagp |= HASWIDTH;
+ if (len == 1) *flagp |= SIMPLE;
+ ret = regnode(EXACTLY);
+ while (len > 0) {
+ regc(*regparse++);
+ len--;
+ }
+ regc('\0');
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char *regnode(op)
+char op;
+{
+ register char *ret;
+ register char *ptr;
+
+ ret = regcode;
+ if (ret == ®dummy) {
+ regsize += 3;
+ return(ret);
+ }
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; /* Null "next" pointer. */
+ *ptr++ = '\0';
+ regcode = ptr;
+
+ return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void regc(b)
+char b;
+{
+ if (regcode != ®dummy)
+ *regcode++ = b;
+ else
+ regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void reginsert(op, opnd)
+char op;
+char *opnd;
+{
+ register char *src;
+ register char *dst;
+ register char *place;
+
+ if (regcode == ®dummy) {
+ regsize += 3;
+ return;
+ }
+ src = regcode;
+ regcode += 3;
+ dst = regcode;
+ while (src > opnd) *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = '\0';
+ *place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void regtail(p, val)
+char *p;
+char *val;
+{
+ register char *scan;
+ register char *temp;
+ register int offset;
+
+ if (p == ®dummy) return;
+
+ /* Find last node. */
+ scan = p;
+ for (;;) {
+ temp = (char *)regnext(scan);
+ if (temp == (char *)NULL) break;
+ scan = temp;
+ }
+
+ if (OP(scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+ *(scan + 1) = (offset >> 8) & 0377;
+ *(scan + 2) = offset & 0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void regoptail(p, val)
+char *p;
+char *val;
+{
+ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+ if (p == (char *)NULL || p == ®dummy || OP(p) != BRANCH) return;
+ regtail(OPERAND(p), val);
+}
+
+/* regexec and friends
+ */
+
+/* Global work variables for regexec().
+ */
+static char *reginput; /* String-input pointer. */
+static char *regbol; /* Beginning of input, for ^ check. */
+static char **regstartp; /* Pointer to startp array. */
+static char **regendp; /* Ditto for endp. */
+
+/* Forwards.
+ */
+static int regtry(regexp *prog, char *string);
+static int regmatch(char *prog);
+static int regrepeat(char *p);
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump();
+static char *regprop(char *op);
+#endif
+
+/*
+ - regexec - match a regexp against a string
+ */
+int regexec(prog, string, bolflag)
+register regexp *prog;
+register char *string;
+int bolflag;
+{
+ register char *s;
+
+ /* Be paranoid... */
+ if (prog == (regexp *)NULL || string == (char *)NULL) {
+ regerror("NULL parameter");
+ return(0);
+ }
+
+ /* Check validity of program. */
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("corrupted program");
+ return(0);
+ }
+
+ /* If there is a "must appear" string, look for it. */
+ if (prog->regmust != (char *)NULL) {
+ s = string;
+ while ((s = strchr(s, prog->regmust[0])) != (char *)NULL) {
+ if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+ break; /* Found it. */
+ s++;
+ }
+ if (s == (char *)NULL) /* Not present. */
+ return(0);
+ }
+
+ /* Mark beginning of line for ^ . */
+ if (bolflag)
+ regbol = string;
+ else
+ regbol = (char *)NULL;
+
+ /* Simplest case: anchored match need be tried only once. */
+ if (prog->reganch) return(regtry(prog, string));
+
+ /* Messy cases: unanchored match. */
+ s = string;
+ if (prog->regstart != '\0') /* We know what char it must start with. */
+ while ((s = strchr(s, prog->regstart)) != (char *)NULL) {
+ if (regtry(prog, s)) return(1);
+ s++;
+ }
+ else
+ /* We don't -- general case. */
+ do {
+ if (regtry(prog, s)) return(1);
+ } while (*s++ != '\0');
+
+ /* Failure. */
+ return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int regtry(prog, string) /* 0 failure, 1 success */
+regexp *prog;
+char *string;
+{
+ register int i;
+ register char **sp;
+ register char **ep;
+
+ reginput = string;
+ regstartp = prog->startp;
+ regendp = prog->endp;
+
+ sp = prog->startp;
+ ep = prog->endp;
+ for (i = NSUBEXP; i > 0; i--) {
+ *sp++ = (char *)NULL;
+ *ep++ = (char *)NULL;
+ }
+ if (regmatch(prog->program + 1)) {
+ prog->startp[0] = string;
+ prog->endp[0] = reginput;
+ return(1);
+ } else
+ return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly. In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+static int regmatch(prog) /* 0 failure, 1 success */
+char *prog;
+{
+ register char *scan; /* Current node. */
+ char *next; /* Next node. */
+
+ scan = prog;
+#ifdef DEBUG
+ if (scan != (char *)NULL && regnarrate) fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != (char *)NULL) {
+#ifdef DEBUG
+ if (regnarrate) fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+ next = regnext(scan);
+
+ switch (OP(scan)) {
+ case BOL:
+ if (reginput != regbol) return(0);
+ break;
+ case EOL:
+ if (*reginput != '\0') return(0);
+ break;
+ case ANY:
+ if (*reginput == '\0') return(0);
+ reginput++;
+ break;
+ case EXACTLY:{
+ register int len;
+ register char *opnd;
+
+ opnd = OPERAND(scan);
+ /* Inline the first character, for speed. */
+ if (*opnd != *reginput) return(0);
+ len = strlen(opnd);
+ if (len > 1 && strncmp(opnd, reginput, len) != 0)
+ return(0);
+ reginput += len;
+ }
+ break;
+ case ANYOF:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == (char *)NULL)
+ return(0);
+ reginput++;
+ break;
+ case ANYBUT:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != (char *)NULL)
+ return(0);
+ reginput++;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case OPEN + 1:
+ case OPEN + 2:
+ case OPEN + 3:
+ case OPEN + 4:
+ case OPEN + 5:
+ case OPEN + 6:
+ case OPEN + 7:
+ case OPEN + 8:
+ case OPEN + 9:{
+ register int no;
+ register char *save;
+
+ no = OP(scan) - OPEN;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /* Don't set startp if some later
+ * invocation of the same parentheses
+ * already has. */
+ if (regstartp[no] == (char *)NULL)
+ regstartp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case CLOSE + 1:
+ case CLOSE + 2:
+ case CLOSE + 3:
+ case CLOSE + 4:
+ case CLOSE + 5:
+ case CLOSE + 6:
+ case CLOSE + 7:
+ case CLOSE + 8:
+ case CLOSE + 9:{
+ register int no;
+ register char *save;
+
+ no = OP(scan) - CLOSE;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /* Don't set endp if some later
+ * invocation of the same parentheses
+ * already has. */
+ if (regendp[no] == (char *)NULL) regendp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case BRANCH:{
+ register char *save;
+
+ if (OP(next) != BRANCH) /* No choice. */
+ next = OPERAND(scan); /* Avoid recursion. */
+ else {
+ do {
+ save = reginput;
+ if (regmatch(OPERAND(scan)))
+ return(1);
+ reginput = save;
+ scan = regnext(scan);
+ } while (scan != (char *)NULL && OP(scan) == BRANCH);
+ return(0);
+ /* NOTREACHED */
+ }
+ }
+ break;
+ case STAR:
+ case PLUS:{
+ register char nextch;
+ register int no;
+ register char *save;
+ register int min;
+
+ /* Lookahead to avoid useless match attempts
+ * when we know what character comes next. */
+ nextch = '\0';
+ if (OP(next) == EXACTLY) nextch = *OPERAND(next);
+ min = (OP(scan) == STAR) ? 0 : 1;
+ save = reginput;
+ no = regrepeat(OPERAND(scan));
+ while (no >= min) {
+ /* If it could work, try it. */
+ if (nextch == '\0' || *reginput == nextch)
+ if (regmatch(next)) return(1);
+ /* Couldn't or didn't -- back up. */
+ no--;
+ reginput = save + no;
+ }
+ return(0);
+ }
+ break;
+ case END:
+ return(1); /* Success! */
+ break;
+ default:
+ regerror("memory corruption");
+ return(0);
+ break;
+ }
+
+ scan = next;
+ }
+
+ /* We get here only if there's trouble -- normally "case END" is the
+ * terminating point. */
+ regerror("corrupted pointers");
+ return(0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int regrepeat(p)
+char *p;
+{
+ register int count = 0;
+ register char *scan;
+ register char *opnd;
+
+ scan = reginput;
+ opnd = OPERAND(p);
+ switch (OP(p)) {
+ case ANY:
+ count = strlen(scan);
+ scan += count;
+ break;
+ case EXACTLY:
+ while (*opnd == *scan) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYOF:
+ while (*scan != '\0' && strchr(opnd, *scan) != (char *)NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYBUT:
+ while (*scan != '\0' && strchr(opnd, *scan) == (char *)NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ default: /* Oh dear. Called inappropriately. */
+ regerror("internal foulup");
+ count = 0; /* Best compromise. */
+ break;
+ }
+ reginput = scan;
+
+ return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static char *regnext(p)
+register char *p;
+{
+ register int offset;
+
+ if (p == ®dummy) return((char *)NULL);
+
+ offset = NEXT(p);
+ if (offset == 0) return((char *)NULL);
+
+ if (OP(p) == BACK)
+ return(p - offset);
+ else
+ return(p + offset);
+}
+
+#ifdef DEBUG
+
+static char *regprop();
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void regdump(r)
+regexp *r;
+{
+ register char *s;
+ register char op = EXACTLY; /* Arbitrary non-END op. */
+ register char *next;
+
+ s = r->program + 1;
+ while (op != END) { /* While that wasn't END last time... */
+ op = OP(s);
+ printf("%2d%s", (int) (s - r->program), regprop(s)); /* Where, what. */
+ next = regnext(s);
+ if (next == (char *)NULL) /* Next ptr. */
+ printf("(0)");
+ else
+ printf("(%d)", (int) (s - r->program) + (int) (next - s));
+ s += 3;
+ if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+ /* Literal string, where present. */
+ while (*s != '\0') {
+ putchar(*s);
+ s++;
+ }
+ s++;
+ }
+ putchar('\n');
+ }
+
+ /* Header fields of interest. */
+ if (r->regstart != '\0') printf("start `%c' ", r->regstart);
+ if (r->reganch) printf("anchored ");
+ if (r->regmust != (char *)NULL) printf("must have \"%s\"", r->regmust);
+ printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static char *regprop(op)
+char *op;
+{
+ register char *p;
+ static char buf[50];
+
+ (void) strcpy(buf, ":");
+
+ switch (OP(op)) {
+ case BOL: p = "BOL"; break;
+ case EOL: p = "EOL"; break;
+ case ANY: p = "ANY"; break;
+ case ANYOF: p = "ANYOF"; break;
+ case ANYBUT: p = "ANYBUT"; break;
+ case BRANCH: p = "BRANCH"; break;
+ case EXACTLY: p = "EXACTLY"; break;
+ case NOTHING: p = "NOTHING"; break;
+ case BACK: p = "BACK"; break;
+ case END: p = "END"; break;
+ case OPEN + 1:
+ case OPEN + 2:
+ case OPEN + 3:
+ case OPEN + 4:
+ case OPEN + 5:
+ case OPEN + 6:
+ case OPEN + 7:
+ case OPEN + 8:
+ case OPEN + 9:
+ sprintf(buf + strlen(buf), "OPEN%d", OP(op) - OPEN);
+ p = (char *)NULL;
+ break;
+ case CLOSE + 1:
+ case CLOSE + 2:
+ case CLOSE + 3:
+ case CLOSE + 4:
+ case CLOSE + 5:
+ case CLOSE + 6:
+ case CLOSE + 7:
+ case CLOSE + 8:
+ case CLOSE + 9:
+ sprintf(buf + strlen(buf), "CLOSE%d", OP(op) - CLOSE);
+ p = (char *)NULL;
+ break;
+ case STAR: p = "STAR"; break;
+ case PLUS: p = "PLUS"; break;
+ default: regerror("corrupted opcode"); p = (char *) NULL; break;
+ }
+ if (p != (char *)NULL) (void) strcat(buf, p);
+ return(buf);
+}
+
+#endif
+
+/*
+ * $PchId: regexp.c,v 1.4 1996/02/22 09:03:07 philip Exp $
+ */
--- /dev/null
+/* regsub
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#define const /* avoid "const poisoning" */
+#include <compat/regexp.h>
+#undef const
+
+/* The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
+
+#define CHARBITS 0377
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+/*
+ - regsub - perform substitutions after a regexp match
+ */
+void regsub(prog, source, dest)
+regexp *prog;
+char *source;
+char *dest;
+{
+ register char *src;
+ register char *dst;
+ register char c;
+ register int no;
+ register int len;
+
+ if (prog == (regexp *)NULL || source == (char *)NULL || dest == (char *)NULL) {
+ regerror("NULL parm to regsub");
+ return;
+ }
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("damaged regexp fed to regsub");
+ return;
+ }
+ src = source;
+ dst = dest;
+ while ((c = *src++) != '\0') {
+ if (c == '&')
+ no = 0;
+ else if (c == '\\' && '0' <= *src && *src <= '9')
+ no = *src++ - '0';
+ else
+ no = -1;
+
+ if (no < 0) { /* Ordinary character. */
+ if (c == '\\' && (*src == '\\' || *src == '&')) c = *src++;
+ *dst++ = c;
+ } else
+ if (prog->startp[no] != (char *)NULL && prog->endp[no] != (char *)NULL) {
+ len = (int) (prog->endp[no] - prog->startp[no]);
+ strncpy(dst, prog->startp[no], len);
+ dst += len;
+ if (len != 0 && *(dst - 1) == '\0') { /* strncpy hit NUL. */
+ regerror("damaged match string");
+ return;
+ }
+ }
+ }
+ *dst++ = '\0';
+}
+
+/*
+ * $PchId: regsub.c,v 1.3 1995/11/27 20:18:16 philip Exp $
+ */