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