1*8020Slinton /* Copyright (c) 1982 Regents of the University of California */ 2*8020Slinton 3*8020Slinton /* static char sccsid[] = "@(#)library.c 1.1 09/02/82"; */ 4*8020Slinton 5*8020Slinton /* 6*8020Slinton * General purpose routines. 7*8020Slinton */ 8*8020Slinton 9*8020Slinton #include <stdio.h> 10*8020Slinton #include <errno.h> 11*8020Slinton 12*8020Slinton #define public 13*8020Slinton #define private static 14*8020Slinton #define and && 15*8020Slinton #define or || 16*8020Slinton #define not ! 17*8020Slinton #define ord(enumcon) ((int) enumcon) 18*8020Slinton #define nil(type) ((type) 0) 19*8020Slinton 20*8020Slinton typedef enum { FALSE, TRUE } Boolean; 21*8020Slinton typedef char *String; 22*8020Slinton typedef FILE *File; 23*8020Slinton typedef String Filename; 24*8020Slinton 25*8020Slinton #undef FILE 26*8020Slinton 27*8020Slinton /* 28*8020Slinton * Definitions of standard C library routines that aren't in the 29*8020Slinton * standard I/O library, but which are generally useful. 30*8020Slinton */ 31*8020Slinton 32*8020Slinton extern long atol(); /* ascii to long */ 33*8020Slinton extern double atof(); /* ascii to floating point */ 34*8020Slinton extern char *mktemp(); /* make a temporary file name */ 35*8020Slinton 36*8020Slinton String cmdname; /* name of command for error messages */ 37*8020Slinton Filename errfilename; /* current file associated with error */ 38*8020Slinton short errlineno; /* line number associated with error */ 39*8020Slinton 40*8020Slinton /* 41*8020Slinton * Definitions for doing memory allocation. 42*8020Slinton */ 43*8020Slinton 44*8020Slinton extern char *malloc(); 45*8020Slinton 46*8020Slinton #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type))) 47*8020Slinton #define dispose(p) { free((char *) p); p = 0; } 48*8020Slinton 49*8020Slinton /* 50*8020Slinton * Macros for doing freads + fwrites. 51*8020Slinton */ 52*8020Slinton 53*8020Slinton #define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp) 54*8020Slinton #define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp) 55*8020Slinton 56*8020Slinton /* 57*8020Slinton * String definitions. 58*8020Slinton */ 59*8020Slinton 60*8020Slinton extern String strcpy(), index(), rindex(); 61*8020Slinton extern int strlen(); 62*8020Slinton 63*8020Slinton #define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s) 64*8020Slinton #define streq(s1, s2) (strcmp(s1, s2) == 0) 65*8020Slinton 66*8020Slinton typedef int INTFUNC(); 67*8020Slinton 68*8020Slinton typedef struct { 69*8020Slinton INTFUNC *func; 70*8020Slinton } ERRINFO; 71*8020Slinton 72*8020Slinton #define ERR_IGNORE ((INTFUNC *) 0) 73*8020Slinton #define ERR_CATCH ((INTFUNC *) 1) 74*8020Slinton 75*8020Slinton /* 76*8020Slinton * Call a program. 77*8020Slinton * 78*8020Slinton * Four entries: 79*8020Slinton * 80*8020Slinton * call, callv - call a program and wait for it, returning status 81*8020Slinton * back, backv - call a program and don't wait, returning process id 82*8020Slinton * 83*8020Slinton * The command's standard input and output are passed as FILE's. 84*8020Slinton */ 85*8020Slinton 86*8020Slinton 87*8020Slinton #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */ 88*8020Slinton #define BADEXEC 127 /* exec fails */ 89*8020Slinton 90*8020Slinton #define ischild(pid) ((pid) == 0) 91*8020Slinton 92*8020Slinton /* VARARGS3 */ 93*8020Slinton public int call(name, in, out, args) 94*8020Slinton String name; 95*8020Slinton File in; 96*8020Slinton File out; 97*8020Slinton String args; 98*8020Slinton { 99*8020Slinton String *ap, *argp; 100*8020Slinton String argv[MAXNARGS]; 101*8020Slinton 102*8020Slinton argp = &argv[0]; 103*8020Slinton *argp++ = name; 104*8020Slinton ap = &args; 105*8020Slinton while (*ap != nil(String)) { 106*8020Slinton *argp++ = *ap++; 107*8020Slinton } 108*8020Slinton *argp = nil(String); 109*8020Slinton return callv(name, in, out, argv); 110*8020Slinton } 111*8020Slinton 112*8020Slinton /* VARARGS3 */ 113*8020Slinton public int back(name, in, out, args) 114*8020Slinton String name; 115*8020Slinton File in; 116*8020Slinton File out; 117*8020Slinton String args; 118*8020Slinton { 119*8020Slinton String *ap, *argp; 120*8020Slinton String argv[MAXNARGS]; 121*8020Slinton 122*8020Slinton argp = &argv[0]; 123*8020Slinton *argp++ = name; 124*8020Slinton ap = &args; 125*8020Slinton while (*ap != nil(String)) { 126*8020Slinton *argp++ = *ap++; 127*8020Slinton } 128*8020Slinton *argp = nil(String); 129*8020Slinton return backv(name, in, out, argv); 130*8020Slinton } 131*8020Slinton 132*8020Slinton public int callv(name, in, out, argv) 133*8020Slinton String name; 134*8020Slinton File in; 135*8020Slinton File out; 136*8020Slinton String *argv; 137*8020Slinton { 138*8020Slinton int pid, status; 139*8020Slinton 140*8020Slinton pid = backv(name, in, out, argv); 141*8020Slinton pwait(pid, &status); 142*8020Slinton return status; 143*8020Slinton } 144*8020Slinton 145*8020Slinton public int backv(name, in, out, argv) 146*8020Slinton String name; 147*8020Slinton File in; 148*8020Slinton File out; 149*8020Slinton String *argv; 150*8020Slinton { 151*8020Slinton int pid; 152*8020Slinton 153*8020Slinton fflush(stdout); 154*8020Slinton if (ischild(pid = fork())) { 155*8020Slinton fswap(0, fileno(in)); 156*8020Slinton fswap(1, fileno(out)); 157*8020Slinton onsyserr(EACCES, ERR_IGNORE); 158*8020Slinton execvp(name, argv); 159*8020Slinton _exit(BADEXEC); 160*8020Slinton } 161*8020Slinton return pid; 162*8020Slinton } 163*8020Slinton 164*8020Slinton /* 165*8020Slinton * Swap file numbers so as to redirect standard input and output. 166*8020Slinton */ 167*8020Slinton 168*8020Slinton private fswap(oldfd, newfd) 169*8020Slinton int oldfd; 170*8020Slinton int newfd; 171*8020Slinton { 172*8020Slinton if (oldfd != newfd) { 173*8020Slinton close(oldfd); 174*8020Slinton dup(newfd); 175*8020Slinton close(newfd); 176*8020Slinton } 177*8020Slinton } 178*8020Slinton 179*8020Slinton /* 180*8020Slinton * Invoke a shell on a command line. 181*8020Slinton */ 182*8020Slinton 183*8020Slinton #define DEF_SHELL "csh" 184*8020Slinton 185*8020Slinton public shell(s) 186*8020Slinton String s; 187*8020Slinton { 188*8020Slinton extern String getenv(); 189*8020Slinton String sh; 190*8020Slinton 191*8020Slinton if ((sh = getenv("SHELL")) == nil(String)) { 192*8020Slinton sh = DEF_SHELL; 193*8020Slinton } 194*8020Slinton call(sh, stdin, stdout, "-c", s, 0); 195*8020Slinton } 196*8020Slinton 197*8020Slinton /* 198*8020Slinton * Wait for a process the right way. We wait for a particular 199*8020Slinton * process and if any others come along in between, we remember them 200*8020Slinton * in case they are eventually waited for. 201*8020Slinton * 202*8020Slinton * This routine is not very efficient when the number of processes 203*8020Slinton * to be remembered is large. 204*8020Slinton */ 205*8020Slinton 206*8020Slinton typedef struct pidlist { 207*8020Slinton int pid; 208*8020Slinton int status; 209*8020Slinton struct pidlist *next; 210*8020Slinton } Pidlist; 211*8020Slinton 212*8020Slinton private Pidlist *pidlist, *pfind(); 213*8020Slinton 214*8020Slinton public pwait(pid, statusp) 215*8020Slinton int pid, *statusp; 216*8020Slinton { 217*8020Slinton Pidlist *p; 218*8020Slinton int pnum, status; 219*8020Slinton 220*8020Slinton p = pfind(pid); 221*8020Slinton if (p != nil(Pidlist *)) { 222*8020Slinton *statusp = p->status; 223*8020Slinton dispose(p); 224*8020Slinton return; 225*8020Slinton } 226*8020Slinton while ((pnum = wait(&status)) != pid && pnum >= 0) { 227*8020Slinton p = alloc(1, Pidlist); 228*8020Slinton p->pid = pnum; 229*8020Slinton p->status = status; 230*8020Slinton p->next = pidlist; 231*8020Slinton pidlist = p; 232*8020Slinton } 233*8020Slinton if (pnum < 0) { 234*8020Slinton p = pfind(pid); 235*8020Slinton if (p == nil(Pidlist *)) { 236*8020Slinton panic("pwait: pid %d not found", pid); 237*8020Slinton } 238*8020Slinton *statusp = p->status; 239*8020Slinton dispose(p); 240*8020Slinton } else { 241*8020Slinton *statusp = status; 242*8020Slinton } 243*8020Slinton } 244*8020Slinton 245*8020Slinton /* 246*8020Slinton * Look for the given process id on the pidlist. 247*8020Slinton * 248*8020Slinton * Unlink it from list if found. 249*8020Slinton */ 250*8020Slinton 251*8020Slinton private Pidlist *pfind(pid) 252*8020Slinton int pid; 253*8020Slinton { 254*8020Slinton register Pidlist *p, *prev; 255*8020Slinton 256*8020Slinton prev = nil(Pidlist *); 257*8020Slinton for (p = pidlist; p != nil(Pidlist *); p = p->next) { 258*8020Slinton if (p->pid == pid) { 259*8020Slinton break; 260*8020Slinton } 261*8020Slinton prev = p; 262*8020Slinton } 263*8020Slinton if (p != nil(Pidlist *)) { 264*8020Slinton if (prev == nil(Pidlist *)) { 265*8020Slinton pidlist = p->next; 266*8020Slinton } else { 267*8020Slinton prev->next = p->next; 268*8020Slinton } 269*8020Slinton } 270*8020Slinton return p; 271*8020Slinton } 272*8020Slinton 273*8020Slinton /* 274*8020Slinton * System call error handler. 275*8020Slinton * 276*8020Slinton * The syserr routine is called when a system call is about to 277*8020Slinton * set the c-bit to report an error. Certain errors are caught 278*8020Slinton * and cause the process to print a message and immediately exit. 279*8020Slinton */ 280*8020Slinton 281*8020Slinton extern int sys_nerr; 282*8020Slinton extern char *sys_errlist[]; 283*8020Slinton 284*8020Slinton /* 285*8020Slinton * Before calling syserr, the integer errno is set to contain the 286*8020Slinton * number of the error. The routine "_mycerror" is a dummy which 287*8020Slinton * is used to force the loader to get my version of cerror rather 288*8020Slinton * than the usual one. 289*8020Slinton */ 290*8020Slinton 291*8020Slinton extern int errno; 292*8020Slinton extern _mycerror(); 293*8020Slinton 294*8020Slinton /* 295*8020Slinton * default error handling 296*8020Slinton */ 297*8020Slinton 298*8020Slinton private ERRINFO errinfo[] ={ 299*8020Slinton /* no error */ ERR_IGNORE, 300*8020Slinton /* EPERM */ ERR_IGNORE, 301*8020Slinton /* ENOENT */ ERR_IGNORE, 302*8020Slinton /* ESRCH */ ERR_IGNORE, 303*8020Slinton /* EINTR */ ERR_CATCH, 304*8020Slinton /* EIO */ ERR_CATCH, 305*8020Slinton /* ENXIO */ ERR_CATCH, 306*8020Slinton /* E2BIG */ ERR_CATCH, 307*8020Slinton /* ENOEXEC */ ERR_CATCH, 308*8020Slinton /* EBADF */ ERR_IGNORE, 309*8020Slinton /* ECHILD */ ERR_CATCH, 310*8020Slinton /* EAGAIN */ ERR_CATCH, 311*8020Slinton /* ENOMEM */ ERR_CATCH, 312*8020Slinton /* EACCES */ ERR_CATCH, 313*8020Slinton /* EFAULT */ ERR_CATCH, 314*8020Slinton /* ENOTBLK */ ERR_CATCH, 315*8020Slinton /* EBUSY */ ERR_CATCH, 316*8020Slinton /* EEXIST */ ERR_CATCH, 317*8020Slinton /* EXDEV */ ERR_CATCH, 318*8020Slinton /* ENODEV */ ERR_CATCH, 319*8020Slinton /* ENOTDIR */ ERR_CATCH, 320*8020Slinton /* EISDIR */ ERR_CATCH, 321*8020Slinton /* EINVAL */ ERR_CATCH, 322*8020Slinton /* ENFILE */ ERR_CATCH, 323*8020Slinton /* EMFILE */ ERR_CATCH, 324*8020Slinton /* ENOTTY */ ERR_IGNORE, 325*8020Slinton /* ETXTBSY */ ERR_CATCH, 326*8020Slinton /* EFBIG */ ERR_CATCH, 327*8020Slinton /* ENOSPC */ ERR_CATCH, 328*8020Slinton /* ESPIPE */ ERR_CATCH, 329*8020Slinton /* EROFS */ ERR_CATCH, 330*8020Slinton /* EMLINK */ ERR_CATCH, 331*8020Slinton /* EPIPE */ ERR_CATCH, 332*8020Slinton /* EDOM */ ERR_CATCH, 333*8020Slinton /* ERANGE */ ERR_CATCH, 334*8020Slinton /* EQUOT */ ERR_CATCH, 335*8020Slinton }; 336*8020Slinton 337*8020Slinton public syserr() 338*8020Slinton { 339*8020Slinton ERRINFO *e; 340*8020Slinton 341*8020Slinton e = &errinfo[errno]; 342*8020Slinton if (e->func == ERR_CATCH) { 343*8020Slinton if (errno < sys_nerr) { 344*8020Slinton panic(sys_errlist[errno]); 345*8020Slinton } else { 346*8020Slinton panic("errno %d", errno); 347*8020Slinton } 348*8020Slinton } else if (e->func != ERR_IGNORE) { 349*8020Slinton (*e->func)(); 350*8020Slinton } 351*8020Slinton } 352*8020Slinton 353*8020Slinton /* 354*8020Slinton * Catcherrs only purpose is to get this module loaded and make 355*8020Slinton * sure my cerror is loaded (only applicable when this is in a library). 356*8020Slinton */ 357*8020Slinton 358*8020Slinton public catcherrs() 359*8020Slinton { 360*8020Slinton _mycerror(); 361*8020Slinton } 362*8020Slinton 363*8020Slinton /* 364*8020Slinton * Change the action on receipt of an error. 365*8020Slinton */ 366*8020Slinton 367*8020Slinton public onsyserr(n, f) 368*8020Slinton int n; 369*8020Slinton INTFUNC *f; 370*8020Slinton { 371*8020Slinton errinfo[n].func = f; 372*8020Slinton } 373*8020Slinton 374*8020Slinton /* 375*8020Slinton * Standard error handling routines. 376*8020Slinton */ 377*8020Slinton 378*8020Slinton private short nerrs; 379*8020Slinton private short nwarnings; 380*8020Slinton 381*8020Slinton /* 382*8020Slinton * Main driver of error message reporting. 383*8020Slinton */ 384*8020Slinton 385*8020Slinton /* VARARGS2 */ 386*8020Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) 387*8020Slinton String errname; 388*8020Slinton Boolean shouldquit; 389*8020Slinton String s; 390*8020Slinton { 391*8020Slinton fflush(stdout); 392*8020Slinton if (shouldquit and cmdname != nil(String)) { 393*8020Slinton fprintf(stderr, "%s: ", cmdname); 394*8020Slinton } 395*8020Slinton if (errfilename != nil(Filename)) { 396*8020Slinton fprintf(stderr, "%s: ", errfilename); 397*8020Slinton } 398*8020Slinton if (errlineno > 0) { 399*8020Slinton fprintf(stderr, "%d: ", errlineno); 400*8020Slinton } 401*8020Slinton if (errname != nil(String)) { 402*8020Slinton fprintf(stderr, "%s: ", errname); 403*8020Slinton } 404*8020Slinton fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 405*8020Slinton putc('\n', stderr); 406*8020Slinton if (shouldquit) { 407*8020Slinton quit(1); 408*8020Slinton } 409*8020Slinton } 410*8020Slinton 411*8020Slinton /* 412*8020Slinton * The messages are listed in increasing order of seriousness. 413*8020Slinton * 414*8020Slinton * First are warnings. 415*8020Slinton */ 416*8020Slinton 417*8020Slinton /* VARARGS1 */ 418*8020Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 419*8020Slinton String s; 420*8020Slinton { 421*8020Slinton nwarnings++; 422*8020Slinton errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 423*8020Slinton } 424*8020Slinton 425*8020Slinton /* 426*8020Slinton * Errors are a little worse, they mean something is wrong, 427*8020Slinton * but not so bad that processing can't continue. 428*8020Slinton * 429*8020Slinton * The routine "erecover" is called to recover from the error, 430*8020Slinton * a default routine is provided that does nothing. 431*8020Slinton */ 432*8020Slinton 433*8020Slinton /* VARARGS1 */ 434*8020Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 435*8020Slinton String s; 436*8020Slinton { 437*8020Slinton extern erecover(); 438*8020Slinton 439*8020Slinton nerrs++; 440*8020Slinton errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 441*8020Slinton erecover(); 442*8020Slinton } 443*8020Slinton 444*8020Slinton /* 445*8020Slinton * Non-recoverable user error. 446*8020Slinton */ 447*8020Slinton 448*8020Slinton /* VARARGS1 */ 449*8020Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 450*8020Slinton String s; 451*8020Slinton { 452*8020Slinton errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 453*8020Slinton } 454*8020Slinton 455*8020Slinton /* 456*8020Slinton * Panics indicate an internal program error. 457*8020Slinton */ 458*8020Slinton 459*8020Slinton /* VARARGS1 */ 460*8020Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 461*8020Slinton String s; 462*8020Slinton { 463*8020Slinton errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 464*8020Slinton } 465*8020Slinton 466*8020Slinton short numerrors() 467*8020Slinton { 468*8020Slinton short r; 469*8020Slinton 470*8020Slinton r = nerrs; 471*8020Slinton nerrs = 0; 472*8020Slinton return r; 473*8020Slinton } 474*8020Slinton 475*8020Slinton short numwarnings() 476*8020Slinton { 477*8020Slinton short r; 478*8020Slinton 479*8020Slinton r = nwarnings; 480*8020Slinton nwarnings = 0; 481*8020Slinton return r; 482*8020Slinton } 483*8020Slinton 484*8020Slinton /* 485*8020Slinton * Recover from an error. 486*8020Slinton * 487*8020Slinton * This is the default routine which we aren't using since we have our own. 488*8020Slinton * 489*8020Slinton public erecover() 490*8020Slinton { 491*8020Slinton } 492*8020Slinton * 493*8020Slinton */ 494*8020Slinton 495*8020Slinton /* 496*8020Slinton * Default way to quit from a program is just to exit. 497*8020Slinton * 498*8020Slinton public quit(r) 499*8020Slinton int r; 500*8020Slinton { 501*8020Slinton exit(r); 502*8020Slinton } 503*8020Slinton * 504*8020Slinton */ 505*8020Slinton 506*8020Slinton /* 507*8020Slinton * Compare n-byte areas pointed to by s1 and s2 508*8020Slinton * if n is 0 then compare up until one has a null byte. 509*8020Slinton */ 510*8020Slinton 511*8020Slinton public int cmp(s1, s2, n) 512*8020Slinton register char *s1, *s2; 513*8020Slinton register unsigned int n; 514*8020Slinton { 515*8020Slinton if (s1 == nil(char *) || s2 == nil(char *)) { 516*8020Slinton panic("cmp: nil pointer"); 517*8020Slinton } 518*8020Slinton if (n == 0) { 519*8020Slinton while (*s1 == *s2++) { 520*8020Slinton if (*s1++ == '\0') { 521*8020Slinton return(0); 522*8020Slinton } 523*8020Slinton } 524*8020Slinton return(*s1 - *(s2-1)); 525*8020Slinton } else { 526*8020Slinton for (; n != 0; n--) { 527*8020Slinton if (*s1++ != *s2++) { 528*8020Slinton return(*(s1-1) - *(s2-1)); 529*8020Slinton } 530*8020Slinton } 531*8020Slinton return(0); 532*8020Slinton } 533*8020Slinton } 534*8020Slinton 535*8020Slinton /* 536*8020Slinton * Move n bytes from src to dest. 537*8020Slinton * If n is 0 move until a null is found. 538*8020Slinton */ 539*8020Slinton 540*8020Slinton public mov(src, dest, n) 541*8020Slinton register char *src, *dest; 542*8020Slinton register unsigned int n; 543*8020Slinton { 544*8020Slinton if (src == nil(char *)) 545*8020Slinton panic("mov: nil source"); 546*8020Slinton if (dest == nil(char *)) 547*8020Slinton panic("mov: nil destination"); 548*8020Slinton if (n > 0) { 549*8020Slinton for (; n != 0; n--) { 550*8020Slinton *dest++ = *src++; 551*8020Slinton } 552*8020Slinton } else { 553*8020Slinton while ((*dest++ = *src++) != '\0'); 554*8020Slinton } 555*8020Slinton } 556