|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.