From: Gianluca Guida Date: Fri, 18 Mar 2011 16:08:26 +0000 (+0000) Subject: Add libcompat_minix for NBSD libc X-Git-Tag: v3.2.0~608 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/host.html?a=commitdiff_plain;h=6bcf58bab8e866ab40498818c4a38fb3748d53d1;p=minix.git Add libcompat_minix for NBSD libc libcompat_minix is a compatibility layer meant to let existing commands to work with the new libc. --- diff --git a/lib/nbsd_libcompat_minix/Makefile b/lib/nbsd_libcompat_minix/Makefile new file mode 100644 index 000000000..db9425e7c --- /dev/null +++ b/lib/nbsd_libcompat_minix/Makefile @@ -0,0 +1,46 @@ +.include + +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 diff --git a/lib/nbsd_libcompat_minix/configfile.c b/lib/nbsd_libcompat_minix/configfile.c new file mode 100644 index 000000000..4c6300fea --- /dev/null +++ b/lib/nbsd_libcompat_minix/configfile.c @@ -0,0 +1,574 @@ +/* config_read(), _delete(), _length() - Generic config file routines. + * Author: Kees J. Bot + * 5 Jun 1999 + */ +#define nil ((void*)0) +#if __minix_vmd +#include +#else +#define fstat _fstat +#define stat _stat +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#if __minix_vmd +#include +#else +#include +#endif +#define _c /* not const */ +#include + +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 + +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 */ diff --git a/lib/nbsd_libcompat_minix/crypt.c b/lib/nbsd_libcompat_minix/crypt.c new file mode 100644 index 000000000..a82b3b0c2 --- /dev/null +++ b/lib/nbsd_libcompat_minix/crypt.c @@ -0,0 +1,115 @@ +/* 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 +#include +#include +#include +#include +#include +#include + +/* 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 $ + */ diff --git a/lib/nbsd_libcompat_minix/cuserid.c b/lib/nbsd_libcompat_minix/cuserid.c new file mode 100644 index 000000000..47640e751 --- /dev/null +++ b/lib/nbsd_libcompat_minix/cuserid.c @@ -0,0 +1,33 @@ +/* cuserid(3) + * + * Author: Terrence W. Holm Sept. 1987 + */ + +#include +#include +#include +#include +#include + +#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); +} diff --git a/lib/nbsd_libcompat_minix/fttyslot.c b/lib/nbsd_libcompat_minix/fttyslot.c new file mode 100644 index 000000000..8afb84856 --- /dev/null +++ b/lib/nbsd_libcompat_minix/fttyslot.c @@ -0,0 +1,50 @@ +/* +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 +#include +#include +#include + +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 $ + */ diff --git a/lib/nbsd_libcompat_minix/getpwent.c b/lib/nbsd_libcompat_minix/getpwent.c new file mode 100644 index 000000000..22598b4e5 --- /dev/null +++ b/lib/nbsd_libcompat_minix/getpwent.c @@ -0,0 +1,156 @@ +/* getpwent(), getpwuid(), getpwnam() - password file routines + * + * Author: Kees J. Bot + * 31 Jan 1994 + */ +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/lib/nbsd_libcompat_minix/include/Makefile.inc b/lib/nbsd_libcompat_minix/include/Makefile.inc new file mode 100644 index 000000000..69c0e1158 --- /dev/null +++ b/lib/nbsd_libcompat_minix/include/Makefile.inc @@ -0,0 +1,8 @@ +.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 + diff --git a/lib/nbsd_libcompat_minix/include/compat/a.out.h b/lib/nbsd_libcompat_minix/include/compat/a.out.h new file mode 100644 index 000000000..5e66faca6 --- /dev/null +++ b/lib/nbsd_libcompat_minix/include/compat/a.out.h @@ -0,0 +1,118 @@ +/* The 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 +#endif + +_PROTOTYPE( int nlist, (char *_file, struct nlist *_nl) ); + +#endif /* _AOUT_H */ diff --git a/lib/nbsd_libcompat_minix/include/compat/pwd.h b/lib/nbsd_libcompat_minix/include/compat/pwd.h new file mode 100644 index 000000000..a53497598 --- /dev/null +++ b/lib/nbsd_libcompat_minix/include/compat/pwd.h @@ -0,0 +1,34 @@ +/* The header defines the items in the password file. */ + +#ifndef _PWD_H +#define _PWD_H + +#ifndef _TYPES_H +#include +#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 */ diff --git a/lib/nbsd_libcompat_minix/include/compat/regexp.h b/lib/nbsd_libcompat_minix/include/compat/regexp.h new file mode 100644 index 000000000..06338f816 --- /dev/null +++ b/lib/nbsd_libcompat_minix/include/compat/regexp.h @@ -0,0 +1,37 @@ +/* The 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 + +#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 $ + */ diff --git a/lib/nbsd_libcompat_minix/include/compat/syslog.h b/lib/nbsd_libcompat_minix/include/compat/syslog.h new file mode 100644 index 000000000..990087a5c --- /dev/null +++ b/lib/nbsd_libcompat_minix/include/compat/syslog.h @@ -0,0 +1,8 @@ +#ifndef _COMPAT_SYSLOG_H +#define _COMPAT_SYSLOG_H + +#include +#define FacNames facilitynames +#define PriNames prioritynames + +#endif diff --git a/lib/nbsd_libcompat_minix/include/configfile.h b/lib/nbsd_libcompat_minix/include/configfile.h new file mode 100644 index 000000000..f3801807b --- /dev/null +++ b/lib/nbsd_libcompat_minix/include/configfile.h @@ -0,0 +1,44 @@ +/* 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 */ diff --git a/lib/nbsd_libcompat_minix/include/termcap.h b/lib/nbsd_libcompat_minix/include/termcap.h new file mode 100644 index 000000000..5dfc50ff3 --- /dev/null +++ b/lib/nbsd_libcompat_minix/include/termcap.h @@ -0,0 +1,13 @@ +#ifndef _TERMCAP_H +#define _TERMCAP_H + +#include + +_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 */ diff --git a/lib/nbsd_libcompat_minix/mtab.c b/lib/nbsd_libcompat_minix/mtab.c new file mode 100644 index 000000000..69b91b823 --- /dev/null +++ b/lib/nbsd_libcompat_minix/mtab.c @@ -0,0 +1,205 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include + +#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(" "); +} diff --git a/lib/nbsd_libcompat_minix/nlist.c b/lib/nbsd_libcompat_minix/nlist.c new file mode 100644 index 000000000..4901032f1 --- /dev/null +++ b/lib/nbsd_libcompat_minix/nlist.c @@ -0,0 +1,71 @@ +/* + * "nlist.c", Peter Valkenburg, january 1989. + */ + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/lib/nbsd_libcompat_minix/stderr.c b/lib/nbsd_libcompat_minix/stderr.c new file mode 100644 index 000000000..fd7f65b4b --- /dev/null +++ b/lib/nbsd_libcompat_minix/stderr.c @@ -0,0 +1,11 @@ +#include +#include +#include + +void std_err(const char *s) +{ + register const char *p = s; + + while (*p != 0) p++; + write(2, s, (int) (p - s)); +} diff --git a/lib/nbsd_libcompat_minix/termcap.c b/lib/nbsd_libcompat_minix/termcap.c new file mode 100644 index 000000000..2f08af286 --- /dev/null +++ b/lib/nbsd_libcompat_minix/termcap.c @@ -0,0 +1,326 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/lib/nbsd_libcompat_minix/v8regerror.c b/lib/nbsd_libcompat_minix/v8regerror.c new file mode 100644 index 000000000..6f4e11fd8 --- /dev/null +++ b/lib/nbsd_libcompat_minix/v8regerror.c @@ -0,0 +1,15 @@ +/* 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 +#define const /* avoid "const poisoning" */ +#include +#undef const + +void regerror(char *message) +{ + fprintf(stderr, "regexp error: %s\n", message); +} diff --git a/lib/nbsd_libcompat_minix/v8regexp.c b/lib/nbsd_libcompat_minix/v8regexp.c new file mode 100644 index 000000000..1bed2b50f --- /dev/null +++ b/lib/nbsd_libcompat_minix/v8regexp.c @@ -0,0 +1,1075 @@ +/* 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 +#include +#include +#define const /* avoid "const poisoning" */ +#include +#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 $ + */ diff --git a/lib/nbsd_libcompat_minix/v8regsub.c b/lib/nbsd_libcompat_minix/v8regsub.c new file mode 100644 index 000000000..36f8c03f0 --- /dev/null +++ b/lib/nbsd_libcompat_minix/v8regsub.c @@ -0,0 +1,90 @@ +/* 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 +#include +#define const /* avoid "const poisoning" */ +#include +#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 $ + */