1*22759Smckusick /* 2*22759Smckusick * Copyright (c) 1982 Regents of the University of California. 3*22759Smckusick * All rights reserved. The Berkeley software License Agreement 4*22759Smckusick * specifies the terms and conditions for redistribution. 5*22759Smckusick */ 68020Slinton 7*22759Smckusick #ifndef lint 8*22759Smckusick static char sccsid[] = "@(#)library.c 5.1 (Berkeley) 06/07/85"; 9*22759Smckusick #endif not lint 108020Slinton 118020Slinton /* 128020Slinton * General purpose routines. 138020Slinton */ 148020Slinton 158020Slinton #include <stdio.h> 168020Slinton #include <errno.h> 178020Slinton 188020Slinton #define public 198020Slinton #define private static 208020Slinton #define and && 218020Slinton #define or || 228020Slinton #define not ! 238020Slinton #define ord(enumcon) ((int) enumcon) 248020Slinton #define nil(type) ((type) 0) 258020Slinton 268020Slinton typedef enum { FALSE, TRUE } Boolean; 278020Slinton typedef char *String; 288020Slinton typedef FILE *File; 298020Slinton typedef String Filename; 308020Slinton 318020Slinton #undef FILE 328020Slinton 338020Slinton /* 348020Slinton * Definitions of standard C library routines that aren't in the 358020Slinton * standard I/O library, but which are generally useful. 368020Slinton */ 378020Slinton 388020Slinton extern long atol(); /* ascii to long */ 398020Slinton extern double atof(); /* ascii to floating point */ 408020Slinton extern char *mktemp(); /* make a temporary file name */ 418020Slinton 428020Slinton String cmdname; /* name of command for error messages */ 438020Slinton Filename errfilename; /* current file associated with error */ 448020Slinton short errlineno; /* line number associated with error */ 458020Slinton 468020Slinton /* 478020Slinton * Definitions for doing memory allocation. 488020Slinton */ 498020Slinton 508020Slinton extern char *malloc(); 518020Slinton 528020Slinton #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type))) 538020Slinton #define dispose(p) { free((char *) p); p = 0; } 548020Slinton 558020Slinton /* 568020Slinton * Macros for doing freads + fwrites. 578020Slinton */ 588020Slinton 598020Slinton #define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp) 608020Slinton #define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp) 618020Slinton 628020Slinton /* 638020Slinton * String definitions. 648020Slinton */ 658020Slinton 668020Slinton extern String strcpy(), index(), rindex(); 678020Slinton extern int strlen(); 688020Slinton 698020Slinton #define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s) 708020Slinton #define streq(s1, s2) (strcmp(s1, s2) == 0) 718020Slinton 728020Slinton typedef int INTFUNC(); 738020Slinton 748020Slinton typedef struct { 758020Slinton INTFUNC *func; 768020Slinton } ERRINFO; 778020Slinton 788020Slinton #define ERR_IGNORE ((INTFUNC *) 0) 798020Slinton #define ERR_CATCH ((INTFUNC *) 1) 808020Slinton 818020Slinton /* 828020Slinton * Call a program. 838020Slinton * 848020Slinton * Four entries: 858020Slinton * 868020Slinton * call, callv - call a program and wait for it, returning status 878020Slinton * back, backv - call a program and don't wait, returning process id 888020Slinton * 898020Slinton * The command's standard input and output are passed as FILE's. 908020Slinton */ 918020Slinton 928020Slinton 938020Slinton #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */ 948020Slinton #define BADEXEC 127 /* exec fails */ 958020Slinton 968020Slinton #define ischild(pid) ((pid) == 0) 978020Slinton 988020Slinton /* VARARGS3 */ 998020Slinton public int call(name, in, out, args) 1008020Slinton String name; 1018020Slinton File in; 1028020Slinton File out; 1038020Slinton String args; 1048020Slinton { 1058020Slinton String *ap, *argp; 1068020Slinton String argv[MAXNARGS]; 1078020Slinton 1088020Slinton argp = &argv[0]; 1098020Slinton *argp++ = name; 1108020Slinton ap = &args; 1118020Slinton while (*ap != nil(String)) { 1128020Slinton *argp++ = *ap++; 1138020Slinton } 1148020Slinton *argp = nil(String); 1158020Slinton return callv(name, in, out, argv); 1168020Slinton } 1178020Slinton 1188020Slinton /* VARARGS3 */ 1198020Slinton public int back(name, in, out, args) 1208020Slinton String name; 1218020Slinton File in; 1228020Slinton File out; 1238020Slinton String args; 1248020Slinton { 1258020Slinton String *ap, *argp; 1268020Slinton String argv[MAXNARGS]; 1278020Slinton 1288020Slinton argp = &argv[0]; 1298020Slinton *argp++ = name; 1308020Slinton ap = &args; 1318020Slinton while (*ap != nil(String)) { 1328020Slinton *argp++ = *ap++; 1338020Slinton } 1348020Slinton *argp = nil(String); 1358020Slinton return backv(name, in, out, argv); 1368020Slinton } 1378020Slinton 1388020Slinton public int callv(name, in, out, argv) 1398020Slinton String name; 1408020Slinton File in; 1418020Slinton File out; 1428020Slinton String *argv; 1438020Slinton { 1448020Slinton int pid, status; 1458020Slinton 1468020Slinton pid = backv(name, in, out, argv); 1478020Slinton pwait(pid, &status); 1488020Slinton return status; 1498020Slinton } 1508020Slinton 1518020Slinton public int backv(name, in, out, argv) 1528020Slinton String name; 1538020Slinton File in; 1548020Slinton File out; 1558020Slinton String *argv; 1568020Slinton { 1578020Slinton int pid; 1588020Slinton 1598020Slinton fflush(stdout); 1608020Slinton if (ischild(pid = fork())) { 1618020Slinton fswap(0, fileno(in)); 1628020Slinton fswap(1, fileno(out)); 1638020Slinton onsyserr(EACCES, ERR_IGNORE); 1648020Slinton execvp(name, argv); 1658020Slinton _exit(BADEXEC); 1668020Slinton } 1678020Slinton return pid; 1688020Slinton } 1698020Slinton 1708020Slinton /* 1718020Slinton * Swap file numbers so as to redirect standard input and output. 1728020Slinton */ 1738020Slinton 1748020Slinton private fswap(oldfd, newfd) 1758020Slinton int oldfd; 1768020Slinton int newfd; 1778020Slinton { 1788020Slinton if (oldfd != newfd) { 1798020Slinton close(oldfd); 1808020Slinton dup(newfd); 1818020Slinton close(newfd); 1828020Slinton } 1838020Slinton } 1848020Slinton 1858020Slinton /* 1868020Slinton * Invoke a shell on a command line. 1878020Slinton */ 1888020Slinton 1898020Slinton #define DEF_SHELL "csh" 1908020Slinton 1918020Slinton public shell(s) 1928020Slinton String s; 1938020Slinton { 1948020Slinton extern String getenv(); 1958020Slinton String sh; 1968020Slinton 1978020Slinton if ((sh = getenv("SHELL")) == nil(String)) { 1988020Slinton sh = DEF_SHELL; 1998020Slinton } 2008020Slinton call(sh, stdin, stdout, "-c", s, 0); 2018020Slinton } 2028020Slinton 2038020Slinton /* 2048020Slinton * Wait for a process the right way. We wait for a particular 2058020Slinton * process and if any others come along in between, we remember them 2068020Slinton * in case they are eventually waited for. 2078020Slinton * 2088020Slinton * This routine is not very efficient when the number of processes 2098020Slinton * to be remembered is large. 2108020Slinton */ 2118020Slinton 2128020Slinton typedef struct pidlist { 2138020Slinton int pid; 2148020Slinton int status; 2158020Slinton struct pidlist *next; 2168020Slinton } Pidlist; 2178020Slinton 2188020Slinton private Pidlist *pidlist, *pfind(); 2198020Slinton 2208020Slinton public pwait(pid, statusp) 2218020Slinton int pid, *statusp; 2228020Slinton { 2238020Slinton Pidlist *p; 2248020Slinton int pnum, status; 2258020Slinton 2268020Slinton p = pfind(pid); 2278020Slinton if (p != nil(Pidlist *)) { 2288020Slinton *statusp = p->status; 2298020Slinton dispose(p); 2308020Slinton return; 2318020Slinton } 2328020Slinton while ((pnum = wait(&status)) != pid && pnum >= 0) { 2338020Slinton p = alloc(1, Pidlist); 2348020Slinton p->pid = pnum; 2358020Slinton p->status = status; 2368020Slinton p->next = pidlist; 2378020Slinton pidlist = p; 2388020Slinton } 2398020Slinton if (pnum < 0) { 2408020Slinton p = pfind(pid); 2418020Slinton if (p == nil(Pidlist *)) { 2428020Slinton panic("pwait: pid %d not found", pid); 2438020Slinton } 2448020Slinton *statusp = p->status; 2458020Slinton dispose(p); 2468020Slinton } else { 2478020Slinton *statusp = status; 2488020Slinton } 2498020Slinton } 2508020Slinton 2518020Slinton /* 2528020Slinton * Look for the given process id on the pidlist. 2538020Slinton * 2548020Slinton * Unlink it from list if found. 2558020Slinton */ 2568020Slinton 2578020Slinton private Pidlist *pfind(pid) 2588020Slinton int pid; 2598020Slinton { 2608020Slinton register Pidlist *p, *prev; 2618020Slinton 2628020Slinton prev = nil(Pidlist *); 2638020Slinton for (p = pidlist; p != nil(Pidlist *); p = p->next) { 2648020Slinton if (p->pid == pid) { 2658020Slinton break; 2668020Slinton } 2678020Slinton prev = p; 2688020Slinton } 2698020Slinton if (p != nil(Pidlist *)) { 2708020Slinton if (prev == nil(Pidlist *)) { 2718020Slinton pidlist = p->next; 2728020Slinton } else { 2738020Slinton prev->next = p->next; 2748020Slinton } 2758020Slinton } 2768020Slinton return p; 2778020Slinton } 2788020Slinton 2798020Slinton /* 2808020Slinton * System call error handler. 2818020Slinton * 2828020Slinton * The syserr routine is called when a system call is about to 2838020Slinton * set the c-bit to report an error. Certain errors are caught 2848020Slinton * and cause the process to print a message and immediately exit. 2858020Slinton */ 2868020Slinton 2878020Slinton extern int sys_nerr; 2888020Slinton extern char *sys_errlist[]; 2898020Slinton 2908020Slinton /* 2918020Slinton * Before calling syserr, the integer errno is set to contain the 2928020Slinton * number of the error. The routine "_mycerror" is a dummy which 2938020Slinton * is used to force the loader to get my version of cerror rather 2948020Slinton * than the usual one. 2958020Slinton */ 2968020Slinton 2978020Slinton extern int errno; 2988020Slinton extern _mycerror(); 2998020Slinton 3008020Slinton /* 3018020Slinton * default error handling 3028020Slinton */ 3038020Slinton 3048020Slinton private ERRINFO errinfo[] ={ 3058020Slinton /* no error */ ERR_IGNORE, 3068020Slinton /* EPERM */ ERR_IGNORE, 3078020Slinton /* ENOENT */ ERR_IGNORE, 3088020Slinton /* ESRCH */ ERR_IGNORE, 3098020Slinton /* EINTR */ ERR_CATCH, 3108020Slinton /* EIO */ ERR_CATCH, 3118020Slinton /* ENXIO */ ERR_CATCH, 3128020Slinton /* E2BIG */ ERR_CATCH, 3138020Slinton /* ENOEXEC */ ERR_CATCH, 3148020Slinton /* EBADF */ ERR_IGNORE, 3158020Slinton /* ECHILD */ ERR_CATCH, 3168020Slinton /* EAGAIN */ ERR_CATCH, 3178020Slinton /* ENOMEM */ ERR_CATCH, 3188020Slinton /* EACCES */ ERR_CATCH, 3198020Slinton /* EFAULT */ ERR_CATCH, 3208020Slinton /* ENOTBLK */ ERR_CATCH, 3218020Slinton /* EBUSY */ ERR_CATCH, 3228020Slinton /* EEXIST */ ERR_CATCH, 3238020Slinton /* EXDEV */ ERR_CATCH, 3248020Slinton /* ENODEV */ ERR_CATCH, 3258020Slinton /* ENOTDIR */ ERR_CATCH, 3268020Slinton /* EISDIR */ ERR_CATCH, 3278020Slinton /* EINVAL */ ERR_CATCH, 3288020Slinton /* ENFILE */ ERR_CATCH, 3298020Slinton /* EMFILE */ ERR_CATCH, 3308020Slinton /* ENOTTY */ ERR_IGNORE, 3318020Slinton /* ETXTBSY */ ERR_CATCH, 3328020Slinton /* EFBIG */ ERR_CATCH, 3338020Slinton /* ENOSPC */ ERR_CATCH, 3348020Slinton /* ESPIPE */ ERR_CATCH, 3358020Slinton /* EROFS */ ERR_CATCH, 3368020Slinton /* EMLINK */ ERR_CATCH, 3378020Slinton /* EPIPE */ ERR_CATCH, 3388020Slinton /* EDOM */ ERR_CATCH, 3398020Slinton /* ERANGE */ ERR_CATCH, 3408020Slinton /* EQUOT */ ERR_CATCH, 3418020Slinton }; 3428020Slinton 3438020Slinton public syserr() 3448020Slinton { 3458020Slinton ERRINFO *e; 3468020Slinton 3478020Slinton e = &errinfo[errno]; 3488020Slinton if (e->func == ERR_CATCH) { 3498020Slinton if (errno < sys_nerr) { 3508020Slinton panic(sys_errlist[errno]); 3518020Slinton } else { 3528020Slinton panic("errno %d", errno); 3538020Slinton } 3548020Slinton } else if (e->func != ERR_IGNORE) { 3558020Slinton (*e->func)(); 3568020Slinton } 3578020Slinton } 3588020Slinton 3598020Slinton /* 3608020Slinton * Catcherrs only purpose is to get this module loaded and make 3618020Slinton * sure my cerror is loaded (only applicable when this is in a library). 3628020Slinton */ 3638020Slinton 3648020Slinton public catcherrs() 3658020Slinton { 3668020Slinton _mycerror(); 3678020Slinton } 3688020Slinton 3698020Slinton /* 3708020Slinton * Change the action on receipt of an error. 3718020Slinton */ 3728020Slinton 3738020Slinton public onsyserr(n, f) 3748020Slinton int n; 3758020Slinton INTFUNC *f; 3768020Slinton { 3778020Slinton errinfo[n].func = f; 3788020Slinton } 3798020Slinton 3808020Slinton /* 3818020Slinton * Standard error handling routines. 3828020Slinton */ 3838020Slinton 3848020Slinton private short nerrs; 3858020Slinton private short nwarnings; 3868020Slinton 3878020Slinton /* 3888020Slinton * Main driver of error message reporting. 3898020Slinton */ 3908020Slinton 3918020Slinton /* VARARGS2 */ 3928020Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) 3938020Slinton String errname; 3948020Slinton Boolean shouldquit; 3958020Slinton String s; 3968020Slinton { 3978020Slinton fflush(stdout); 3988020Slinton if (shouldquit and cmdname != nil(String)) { 3998020Slinton fprintf(stderr, "%s: ", cmdname); 4008020Slinton } 4018020Slinton if (errfilename != nil(Filename)) { 4028020Slinton fprintf(stderr, "%s: ", errfilename); 4038020Slinton } 4048020Slinton if (errlineno > 0) { 4058020Slinton fprintf(stderr, "%d: ", errlineno); 4068020Slinton } 4078020Slinton if (errname != nil(String)) { 4088020Slinton fprintf(stderr, "%s: ", errname); 4098020Slinton } 4108020Slinton fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 4118020Slinton putc('\n', stderr); 4128020Slinton if (shouldquit) { 4138020Slinton quit(1); 4148020Slinton } 4158020Slinton } 4168020Slinton 4178020Slinton /* 4188020Slinton * The messages are listed in increasing order of seriousness. 4198020Slinton * 4208020Slinton * First are warnings. 4218020Slinton */ 4228020Slinton 4238020Slinton /* VARARGS1 */ 4248020Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 4258020Slinton String s; 4268020Slinton { 4278020Slinton nwarnings++; 4288020Slinton errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 4298020Slinton } 4308020Slinton 4318020Slinton /* 4328020Slinton * Errors are a little worse, they mean something is wrong, 4338020Slinton * but not so bad that processing can't continue. 4348020Slinton * 4358020Slinton * The routine "erecover" is called to recover from the error, 4368020Slinton * a default routine is provided that does nothing. 4378020Slinton */ 4388020Slinton 4398020Slinton /* VARARGS1 */ 4408020Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 4418020Slinton String s; 4428020Slinton { 4438020Slinton extern erecover(); 4448020Slinton 4458020Slinton nerrs++; 4468020Slinton errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 4478020Slinton erecover(); 4488020Slinton } 4498020Slinton 4508020Slinton /* 4518020Slinton * Non-recoverable user error. 4528020Slinton */ 4538020Slinton 4548020Slinton /* VARARGS1 */ 4558020Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 4568020Slinton String s; 4578020Slinton { 4588020Slinton errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 4598020Slinton } 4608020Slinton 4618020Slinton /* 4628020Slinton * Panics indicate an internal program error. 4638020Slinton */ 4648020Slinton 4658020Slinton /* VARARGS1 */ 4668020Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 4678020Slinton String s; 4688020Slinton { 4698020Slinton errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 4708020Slinton } 4718020Slinton 4728020Slinton short numerrors() 4738020Slinton { 4748020Slinton short r; 4758020Slinton 4768020Slinton r = nerrs; 4778020Slinton nerrs = 0; 4788020Slinton return r; 4798020Slinton } 4808020Slinton 4818020Slinton short numwarnings() 4828020Slinton { 4838020Slinton short r; 4848020Slinton 4858020Slinton r = nwarnings; 4868020Slinton nwarnings = 0; 4878020Slinton return r; 4888020Slinton } 4898020Slinton 4908020Slinton /* 4918020Slinton * Recover from an error. 4928020Slinton * 4938020Slinton * This is the default routine which we aren't using since we have our own. 4948020Slinton * 4958020Slinton public erecover() 4968020Slinton { 4978020Slinton } 4988020Slinton * 4998020Slinton */ 5008020Slinton 5018020Slinton /* 5028020Slinton * Default way to quit from a program is just to exit. 5038020Slinton * 5048020Slinton public quit(r) 5058020Slinton int r; 5068020Slinton { 5078020Slinton exit(r); 5088020Slinton } 5098020Slinton * 5108020Slinton */ 5118020Slinton 5128020Slinton /* 5138020Slinton * Compare n-byte areas pointed to by s1 and s2 5148020Slinton * if n is 0 then compare up until one has a null byte. 5158020Slinton */ 5168020Slinton 5178020Slinton public int cmp(s1, s2, n) 5188020Slinton register char *s1, *s2; 5198020Slinton register unsigned int n; 5208020Slinton { 5218020Slinton if (s1 == nil(char *) || s2 == nil(char *)) { 5228020Slinton panic("cmp: nil pointer"); 5238020Slinton } 5248020Slinton if (n == 0) { 5258020Slinton while (*s1 == *s2++) { 5268020Slinton if (*s1++ == '\0') { 5278020Slinton return(0); 5288020Slinton } 5298020Slinton } 5308020Slinton return(*s1 - *(s2-1)); 5318020Slinton } else { 5328020Slinton for (; n != 0; n--) { 5338020Slinton if (*s1++ != *s2++) { 5348020Slinton return(*(s1-1) - *(s2-1)); 5358020Slinton } 5368020Slinton } 5378020Slinton return(0); 5388020Slinton } 5398020Slinton } 5408020Slinton 5418020Slinton /* 5428020Slinton * Move n bytes from src to dest. 5438020Slinton * If n is 0 move until a null is found. 5448020Slinton */ 5458020Slinton 5468020Slinton public mov(src, dest, n) 5478020Slinton register char *src, *dest; 5488020Slinton register unsigned int n; 5498020Slinton { 5508020Slinton if (src == nil(char *)) 5518020Slinton panic("mov: nil source"); 5528020Slinton if (dest == nil(char *)) 5538020Slinton panic("mov: nil destination"); 5548020Slinton if (n > 0) { 5558020Slinton for (; n != 0; n--) { 5568020Slinton *dest++ = *src++; 5578020Slinton } 5588020Slinton } else { 5598020Slinton while ((*dest++ = *src++) != '\0'); 5608020Slinton } 5618020Slinton } 562