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