From: Mark Linton Date: Fri, 3 Sep 1982 11:30:58 +0000 (-0800) Subject: date and time created 82/09/02 20:30:58 by linton X-Git-Tag: BSD-4_1c_2-Snapshot-Development~2560 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/5bbc6432cc00273ae970c01efbfa73fe12816220?ds=inline date and time created 82/09/02 20:30:58 by linton SCCS-vsn: usr.bin/pascal/pdx/library.c 1.1 --- diff --git a/usr/src/usr.bin/pascal/pdx/library.c b/usr/src/usr.bin/pascal/pdx/library.c new file mode 100644 index 0000000000..9bb1ffbe86 --- /dev/null +++ b/usr/src/usr.bin/pascal/pdx/library.c @@ -0,0 +1,555 @@ +/* Copyright (c) 1982 Regents of the University of California */ + +/* static char sccsid[] = "@(#)library.c 1.1 %G%"; */ + +/* + * General purpose routines. + */ + +#include +#include + +#define public +#define private static +#define and && +#define or || +#define not ! +#define ord(enumcon) ((int) enumcon) +#define nil(type) ((type) 0) + +typedef enum { FALSE, TRUE } Boolean; +typedef char *String; +typedef FILE *File; +typedef String Filename; + +#undef FILE + +/* + * Definitions of standard C library routines that aren't in the + * standard I/O library, but which are generally useful. + */ + +extern long atol(); /* ascii to long */ +extern double atof(); /* ascii to floating point */ +extern char *mktemp(); /* make a temporary file name */ + +String cmdname; /* name of command for error messages */ +Filename errfilename; /* current file associated with error */ +short errlineno; /* line number associated with error */ + +/* + * Definitions for doing memory allocation. + */ + +extern char *malloc(); + +#define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type))) +#define dispose(p) { free((char *) p); p = 0; } + +/* + * Macros for doing freads + fwrites. + */ + +#define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp) +#define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp) + +/* + * String definitions. + */ + +extern String strcpy(), index(), rindex(); +extern int strlen(); + +#define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s) +#define streq(s1, s2) (strcmp(s1, s2) == 0) + +typedef int INTFUNC(); + +typedef struct { + INTFUNC *func; +} ERRINFO; + +#define ERR_IGNORE ((INTFUNC *) 0) +#define ERR_CATCH ((INTFUNC *) 1) + +/* + * Call a program. + * + * Four entries: + * + * call, callv - call a program and wait for it, returning status + * back, backv - call a program and don't wait, returning process id + * + * The command's standard input and output are passed as FILE's. + */ + + +#define MAXNARGS 100 /* unchecked upper limit on max num of arguments */ +#define BADEXEC 127 /* exec fails */ + +#define ischild(pid) ((pid) == 0) + +/* VARARGS3 */ +public int call(name, in, out, args) +String name; +File in; +File out; +String args; +{ + String *ap, *argp; + String argv[MAXNARGS]; + + argp = &argv[0]; + *argp++ = name; + ap = &args; + while (*ap != nil(String)) { + *argp++ = *ap++; + } + *argp = nil(String); + return callv(name, in, out, argv); +} + +/* VARARGS3 */ +public int back(name, in, out, args) +String name; +File in; +File out; +String args; +{ + String *ap, *argp; + String argv[MAXNARGS]; + + argp = &argv[0]; + *argp++ = name; + ap = &args; + while (*ap != nil(String)) { + *argp++ = *ap++; + } + *argp = nil(String); + return backv(name, in, out, argv); +} + +public int callv(name, in, out, argv) +String name; +File in; +File out; +String *argv; +{ + int pid, status; + + pid = backv(name, in, out, argv); + pwait(pid, &status); + return status; +} + +public int backv(name, in, out, argv) +String name; +File in; +File out; +String *argv; +{ + int pid; + + fflush(stdout); + if (ischild(pid = fork())) { + fswap(0, fileno(in)); + fswap(1, fileno(out)); + onsyserr(EACCES, ERR_IGNORE); + execvp(name, argv); + _exit(BADEXEC); + } + return pid; +} + +/* + * Swap file numbers so as to redirect standard input and output. + */ + +private fswap(oldfd, newfd) +int oldfd; +int newfd; +{ + if (oldfd != newfd) { + close(oldfd); + dup(newfd); + close(newfd); + } +} + +/* + * Invoke a shell on a command line. + */ + +#define DEF_SHELL "csh" + +public shell(s) +String s; +{ + extern String getenv(); + String sh; + + if ((sh = getenv("SHELL")) == nil(String)) { + sh = DEF_SHELL; + } + call(sh, stdin, stdout, "-c", s, 0); +} + +/* + * Wait for a process the right way. We wait for a particular + * process and if any others come along in between, we remember them + * in case they are eventually waited for. + * + * This routine is not very efficient when the number of processes + * to be remembered is large. + */ + +typedef struct pidlist { + int pid; + int status; + struct pidlist *next; +} Pidlist; + +private Pidlist *pidlist, *pfind(); + +public pwait(pid, statusp) +int pid, *statusp; +{ + Pidlist *p; + int pnum, status; + + p = pfind(pid); + if (p != nil(Pidlist *)) { + *statusp = p->status; + dispose(p); + return; + } + while ((pnum = wait(&status)) != pid && pnum >= 0) { + p = alloc(1, Pidlist); + p->pid = pnum; + p->status = status; + p->next = pidlist; + pidlist = p; + } + if (pnum < 0) { + p = pfind(pid); + if (p == nil(Pidlist *)) { + panic("pwait: pid %d not found", pid); + } + *statusp = p->status; + dispose(p); + } else { + *statusp = status; + } +} + +/* + * Look for the given process id on the pidlist. + * + * Unlink it from list if found. + */ + +private Pidlist *pfind(pid) +int pid; +{ + register Pidlist *p, *prev; + + prev = nil(Pidlist *); + for (p = pidlist; p != nil(Pidlist *); p = p->next) { + if (p->pid == pid) { + break; + } + prev = p; + } + if (p != nil(Pidlist *)) { + if (prev == nil(Pidlist *)) { + pidlist = p->next; + } else { + prev->next = p->next; + } + } + return p; +} + +/* + * System call error handler. + * + * The syserr routine is called when a system call is about to + * set the c-bit to report an error. Certain errors are caught + * and cause the process to print a message and immediately exit. + */ + +extern int sys_nerr; +extern char *sys_errlist[]; + +/* + * Before calling syserr, the integer errno is set to contain the + * number of the error. The routine "_mycerror" is a dummy which + * is used to force the loader to get my version of cerror rather + * than the usual one. + */ + +extern int errno; +extern _mycerror(); + +/* + * default error handling + */ + +private ERRINFO errinfo[] ={ +/* no error */ ERR_IGNORE, +/* EPERM */ ERR_IGNORE, +/* ENOENT */ ERR_IGNORE, +/* ESRCH */ ERR_IGNORE, +/* EINTR */ ERR_CATCH, +/* EIO */ ERR_CATCH, +/* ENXIO */ ERR_CATCH, +/* E2BIG */ ERR_CATCH, +/* ENOEXEC */ ERR_CATCH, +/* EBADF */ ERR_IGNORE, +/* ECHILD */ ERR_CATCH, +/* EAGAIN */ ERR_CATCH, +/* ENOMEM */ ERR_CATCH, +/* EACCES */ ERR_CATCH, +/* EFAULT */ ERR_CATCH, +/* ENOTBLK */ ERR_CATCH, +/* EBUSY */ ERR_CATCH, +/* EEXIST */ ERR_CATCH, +/* EXDEV */ ERR_CATCH, +/* ENODEV */ ERR_CATCH, +/* ENOTDIR */ ERR_CATCH, +/* EISDIR */ ERR_CATCH, +/* EINVAL */ ERR_CATCH, +/* ENFILE */ ERR_CATCH, +/* EMFILE */ ERR_CATCH, +/* ENOTTY */ ERR_IGNORE, +/* ETXTBSY */ ERR_CATCH, +/* EFBIG */ ERR_CATCH, +/* ENOSPC */ ERR_CATCH, +/* ESPIPE */ ERR_CATCH, +/* EROFS */ ERR_CATCH, +/* EMLINK */ ERR_CATCH, +/* EPIPE */ ERR_CATCH, +/* EDOM */ ERR_CATCH, +/* ERANGE */ ERR_CATCH, +/* EQUOT */ ERR_CATCH, +}; + +public syserr() +{ + ERRINFO *e; + + e = &errinfo[errno]; + if (e->func == ERR_CATCH) { + if (errno < sys_nerr) { + panic(sys_errlist[errno]); + } else { + panic("errno %d", errno); + } + } else if (e->func != ERR_IGNORE) { + (*e->func)(); + } +} + +/* + * Catcherrs only purpose is to get this module loaded and make + * sure my cerror is loaded (only applicable when this is in a library). + */ + +public catcherrs() +{ + _mycerror(); +} + +/* + * Change the action on receipt of an error. + */ + +public onsyserr(n, f) +int n; +INTFUNC *f; +{ + errinfo[n].func = f; +} + +/* + * Standard error handling routines. + */ + +private short nerrs; +private short nwarnings; + +/* + * Main driver of error message reporting. + */ + +/* VARARGS2 */ +private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) +String errname; +Boolean shouldquit; +String s; +{ + fflush(stdout); + if (shouldquit and cmdname != nil(String)) { + fprintf(stderr, "%s: ", cmdname); + } + if (errfilename != nil(Filename)) { + fprintf(stderr, "%s: ", errfilename); + } + if (errlineno > 0) { + fprintf(stderr, "%d: ", errlineno); + } + if (errname != nil(String)) { + fprintf(stderr, "%s: ", errname); + } + fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); + putc('\n', stderr); + if (shouldquit) { + quit(1); + } +} + +/* + * The messages are listed in increasing order of seriousness. + * + * First are warnings. + */ + +/* VARARGS1 */ +public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m) +String s; +{ + nwarnings++; + errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); +} + +/* + * Errors are a little worse, they mean something is wrong, + * but not so bad that processing can't continue. + * + * The routine "erecover" is called to recover from the error, + * a default routine is provided that does nothing. + */ + +/* VARARGS1 */ +public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) +String s; +{ + extern erecover(); + + nerrs++; + errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); + erecover(); +} + +/* + * Non-recoverable user error. + */ + +/* VARARGS1 */ +public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) +String s; +{ + errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); +} + +/* + * Panics indicate an internal program error. + */ + +/* VARARGS1 */ +public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) +String s; +{ + errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); +} + +short numerrors() +{ + short r; + + r = nerrs; + nerrs = 0; + return r; +} + +short numwarnings() +{ + short r; + + r = nwarnings; + nwarnings = 0; + return r; +} + +/* + * Recover from an error. + * + * This is the default routine which we aren't using since we have our own. + * +public erecover() +{ +} + * + */ + +/* + * Default way to quit from a program is just to exit. + * +public quit(r) +int r; +{ + exit(r); +} + * + */ + +/* + * Compare n-byte areas pointed to by s1 and s2 + * if n is 0 then compare up until one has a null byte. + */ + +public int cmp(s1, s2, n) +register char *s1, *s2; +register unsigned int n; +{ + if (s1 == nil(char *) || s2 == nil(char *)) { + panic("cmp: nil pointer"); + } + if (n == 0) { + while (*s1 == *s2++) { + if (*s1++ == '\0') { + return(0); + } + } + return(*s1 - *(s2-1)); + } else { + for (; n != 0; n--) { + if (*s1++ != *s2++) { + return(*(s1-1) - *(s2-1)); + } + } + return(0); + } +} + +/* + * Move n bytes from src to dest. + * If n is 0 move until a null is found. + */ + +public mov(src, dest, n) +register char *src, *dest; +register unsigned int n; +{ + if (src == nil(char *)) + panic("mov: nil source"); + if (dest == nil(char *)) + panic("mov: nil destination"); + if (n > 0) { + for (; n != 0; n--) { + *dest++ = *src++; + } + } else { + while ((*dest++ = *src++) != '\0'); + } +}