Annotation of 43BSD/ucb/dbx/library.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1983 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) 5/31/85";
        !             9: #endif not lint
        !            10: 
        !            11: static char rcsid[] = "$Header: library.c,v 1.5 84/12/26 10:39:52 linton Exp $";
        !            12: 
        !            13: /*
        !            14:  * General purpose routines.
        !            15:  */
        !            16: 
        !            17: #include <stdio.h>
        !            18: #include <errno.h>
        !            19: #include <signal.h>
        !            20: 
        !            21: #define public
        !            22: #define private static
        !            23: #define and &&
        !            24: #define or ||
        !            25: #define not !
        !            26: #define ord(enumcon)   ((int) enumcon)
        !            27: #define nil(type)      ((type) 0)
        !            28: 
        !            29: typedef int integer;
        !            30: typedef enum { FALSE, TRUE } boolean;
        !            31: typedef char *String;
        !            32: typedef FILE *File;
        !            33: typedef String Filename;
        !            34: 
        !            35: #undef FILE
        !            36: 
        !            37: String cmdname;                        /* name of command for error messages */
        !            38: Filename errfilename;          /* current file associated with error */
        !            39: short errlineno;               /* line number associated with error */
        !            40: 
        !            41: /*
        !            42:  * Definitions for doing memory allocation.
        !            43:  */
        !            44: 
        !            45: extern char *malloc();
        !            46: 
        !            47: #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type)))
        !            48: #define dispose(p)     { free((char *) p); p = 0; }
        !            49: 
        !            50: /*
        !            51:  * Macros for doing freads + fwrites.
        !            52:  */
        !            53: 
        !            54: #define get(fp, var)   fread((char *) &(var), sizeof(var), 1, fp)
        !            55: #define put(fp, var)   fwrite((char *) &(var), sizeof(var), 1, fp)
        !            56: 
        !            57: /*
        !            58:  * String definitions.
        !            59:  */
        !            60: 
        !            61: extern String strcpy(), index(), rindex();
        !            62: extern int strlen();
        !            63: 
        !            64: #define strdup(s)              strcpy(malloc((unsigned) strlen(s) + 1), s)
        !            65: #define streq(s1, s2)  (strcmp(s1, s2) == 0)
        !            66: 
        !            67: typedef int INTFUNC();
        !            68: 
        !            69: typedef struct {
        !            70:     INTFUNC *func;
        !            71: } ERRINFO;
        !            72: 
        !            73: #define ERR_IGNORE ((INTFUNC *) 0)
        !            74: #define ERR_CATCH  ((INTFUNC *) 1)
        !            75: 
        !            76: /*
        !            77:  * Call a program.
        !            78:  *
        !            79:  * Four entries:
        !            80:  *
        !            81:  *     call, callv - call a program and wait for it, returning status
        !            82:  *     back, backv - call a program and don't wait, returning process id
        !            83:  *
        !            84:  * The command's standard input and output are passed as FILE's.
        !            85:  */
        !            86: 
        !            87: 
        !            88: #define MAXNARGS 1000    /* unchecked upper limit on max num of arguments */
        !            89: #define BADEXEC 127    /* exec fails */
        !            90: 
        !            91: #define ischild(pid)    ((pid) == 0)
        !            92: 
        !            93: /* VARARGS3 */
        !            94: public int call(name, in, out, args)
        !            95: String name;
        !            96: File in;
        !            97: File out;
        !            98: String args;
        !            99: {
        !           100:     String *ap, *argp;
        !           101:     String argv[MAXNARGS];
        !           102: 
        !           103:     argp = &argv[0];
        !           104:     *argp++ = name;
        !           105:     ap = &args;
        !           106:     while (*ap != nil(String)) {
        !           107:        *argp++ = *ap++;
        !           108:     }
        !           109:     *argp = nil(String);
        !           110:     return callv(name, in, out, argv);
        !           111: }
        !           112: 
        !           113: /* VARARGS3 */
        !           114: public int back(name, in, out, args)
        !           115: String name;
        !           116: File in;
        !           117: File out;
        !           118: String args;
        !           119: {
        !           120:     String *ap, *argp;
        !           121:     String argv[MAXNARGS];
        !           122: 
        !           123:     argp = &argv[0];
        !           124:     *argp++ = name;
        !           125:     ap = &args;
        !           126:     while (*ap != nil(String)) {
        !           127:        *argp++ = *ap++;
        !           128:     }
        !           129:     *argp = nil(String);
        !           130:     return backv(name, in, out, argv);
        !           131: }
        !           132: 
        !           133: public int callv(name, in, out, argv)
        !           134: String name;
        !           135: File in;
        !           136: File out;
        !           137: String *argv;
        !           138: {
        !           139:     int pid, status;
        !           140: 
        !           141:     pid = backv(name, in, out, argv);
        !           142:     pwait(pid, &status);
        !           143:     return status;
        !           144: }
        !           145: 
        !           146: public int backv(name, in, out, argv)
        !           147: String name;
        !           148: File in;
        !           149: File out;
        !           150: String *argv;
        !           151: {
        !           152:     int pid;
        !           153: 
        !           154:     fflush(stdout);
        !           155:     if (ischild(pid = fork())) {
        !           156:        fswap(0, fileno(in));
        !           157:        fswap(1, fileno(out));
        !           158:        onsyserr(EACCES, ERR_IGNORE);
        !           159:        execvp(name, argv);
        !           160:        _exit(BADEXEC);
        !           161:     }
        !           162:     return pid;
        !           163: }
        !           164: 
        !           165: /*
        !           166:  * Swap file numbers so as to redirect standard input and output.
        !           167:  */
        !           168: 
        !           169: private fswap(oldfd, newfd)
        !           170: int oldfd;
        !           171: int newfd;
        !           172: {
        !           173:     if (oldfd != newfd) {
        !           174:        close(oldfd);
        !           175:        dup(newfd);
        !           176:        close(newfd);
        !           177:     }
        !           178: }
        !           179: 
        !           180: /*
        !           181:  * Invoke a shell on a command line.
        !           182:  */
        !           183: 
        !           184: #define DEF_SHELL      "csh"
        !           185: 
        !           186: public shell(s)
        !           187: String s;
        !           188: {
        !           189:     extern String getenv();
        !           190:     String sh;
        !           191: 
        !           192:     if ((sh = getenv("SHELL")) == nil(String)) {
        !           193:        sh = DEF_SHELL;
        !           194:     }
        !           195:     if (s != nil(String) and *s != '\0') {
        !           196:        call(sh, stdin, stdout, "-c", s, 0);
        !           197:     } else {
        !           198:        call(sh, stdin, stdout, 0);
        !           199:     }
        !           200: }
        !           201: 
        !           202: /*
        !           203:  * Wait for a process the right way.  We wait for a particular
        !           204:  * process and if any others come along in between, we remember them
        !           205:  * in case they are eventually waited for.
        !           206:  *
        !           207:  * This routine is not very efficient when the number of processes
        !           208:  * to be remembered is large.
        !           209:  *
        !           210:  * To deal with a kernel idiosyncrasy, we keep a list on the side
        !           211:  * of "traced" processes, and do not notice them when waiting for
        !           212:  * another process.
        !           213:  */
        !           214: 
        !           215: typedef struct pidlist {
        !           216:     int pid;
        !           217:     int status;
        !           218:     struct pidlist *next;
        !           219: } Pidlist;
        !           220: 
        !           221: private Pidlist *pidlist, *ptrclist, *pfind();
        !           222: 
        !           223: public ptraced(pid)
        !           224: int pid;
        !           225: {
        !           226:     Pidlist *p;
        !           227: 
        !           228:     p = alloc(1, Pidlist);
        !           229:     p->pid = pid;
        !           230:     p->next = ptrclist;
        !           231:     ptrclist = p;
        !           232: }
        !           233: 
        !           234: public unptraced(pid)
        !           235: int pid;
        !           236: {
        !           237:     register Pidlist *p, *prev;
        !           238: 
        !           239:     prev = nil(Pidlist *);
        !           240:     p = ptrclist;
        !           241:     while (p != nil(Pidlist *) and p->pid != pid) {
        !           242:        prev = p;
        !           243:        p = p->next;
        !           244:     }
        !           245:     if (p != nil(Pidlist *)) {
        !           246:        if (prev == nil(Pidlist *)) {
        !           247:            ptrclist = p->next;
        !           248:        } else {
        !           249:            prev->next = p->next;
        !           250:        }
        !           251:        dispose(p);
        !           252:     }
        !           253: }
        !           254: 
        !           255: private boolean isptraced(pid)
        !           256: int pid;
        !           257: {
        !           258:     register Pidlist *p;
        !           259: 
        !           260:     p = ptrclist;
        !           261:     while (p != nil(Pidlist *) and p->pid != pid) {
        !           262:        p = p->next;
        !           263:     }
        !           264:     return (boolean) (p != nil(Pidlist *));
        !           265: }
        !           266: 
        !           267: public pwait(pid, statusp)
        !           268: int pid, *statusp;
        !           269: {
        !           270:     Pidlist *p;
        !           271:     int pnum, status;
        !           272: 
        !           273:     p = pfind(pid);
        !           274:     if (p != nil(Pidlist *)) {
        !           275:        *statusp = p->status;
        !           276:        dispose(p);
        !           277:     } else {
        !           278:        pnum = wait(&status);
        !           279:        while (pnum != pid and pnum >= 0) {
        !           280:            if (not isptraced(pnum)) {
        !           281:                p = alloc(1, Pidlist);
        !           282:                p->pid = pnum;
        !           283:                p->status = status;
        !           284:                p->next = pidlist;
        !           285:                pidlist = p;
        !           286:            }
        !           287:            pnum = wait(&status);
        !           288:        }
        !           289:        if (pnum < 0) {
        !           290:            p = pfind(pid);
        !           291:            if (p == nil(Pidlist *)) {
        !           292:                panic("pwait: pid %d not found", pid);
        !           293:            }
        !           294:            *statusp = p->status;
        !           295:            dispose(p);
        !           296:        } else {
        !           297:            *statusp = status;
        !           298:        }
        !           299:     }
        !           300: }
        !           301: 
        !           302: /*
        !           303:  * Look for the given process id on the pidlist.
        !           304:  *
        !           305:  * Unlink it from list if found.
        !           306:  */
        !           307: 
        !           308: private Pidlist *pfind(pid)
        !           309: int pid;
        !           310: {
        !           311:     register Pidlist *p, *prev;
        !           312: 
        !           313:     prev = nil(Pidlist *);
        !           314:     for (p = pidlist; p != nil(Pidlist *); p = p->next) {
        !           315:        if (p->pid == pid) {
        !           316:            break;
        !           317:        }
        !           318:        prev = p;
        !           319:     }
        !           320:     if (p != nil(Pidlist *)) {
        !           321:        if (prev == nil(Pidlist *)) {
        !           322:            pidlist = p->next;
        !           323:        } else {
        !           324:            prev->next = p->next;
        !           325:        }
        !           326:     }
        !           327:     return p;
        !           328: }
        !           329: 
        !           330: /*
        !           331:  * System call error handler.
        !           332:  *
        !           333:  * The syserr routine is called when a system call is about to
        !           334:  * set the c-bit to report an error.  Certain errors are caught
        !           335:  * and cause the process to print a message and immediately exit.
        !           336:  */
        !           337: 
        !           338: extern int sys_nerr;
        !           339: extern char *sys_errlist[];
        !           340:  
        !           341: /*
        !           342:  * Before calling syserr, the integer errno is set to contain the
        !           343:  * number of the error.  The routine "_mycerror" is a dummy which
        !           344:  * is used to force the loader to get my version of cerror rather
        !           345:  * than the usual one.
        !           346:  */
        !           347: 
        !           348: extern int errno;
        !           349: extern _mycerror();
        !           350: 
        !           351: /*
        !           352:  * Initialize error information, setting defaults for handling errors.
        !           353:  */
        !           354: 
        !           355: private ERRINFO *errinfo;
        !           356: 
        !           357: private initErrInfo ()
        !           358: {
        !           359:     integer i;
        !           360: 
        !           361:     errinfo = alloc(sys_nerr, ERRINFO);
        !           362:     for (i = 0; i < sys_nerr; i++) {
        !           363:        errinfo[i].func = ERR_CATCH;
        !           364:     }
        !           365:     errinfo[0].func = ERR_IGNORE;
        !           366:     errinfo[EPERM].func = ERR_IGNORE;
        !           367:     errinfo[ENOENT].func = ERR_IGNORE;
        !           368:     errinfo[ESRCH].func = ERR_IGNORE;
        !           369:     errinfo[EBADF].func = ERR_IGNORE;
        !           370:     errinfo[ENOTTY].func = ERR_IGNORE;
        !           371:     errinfo[EOPNOTSUPP].func = ERR_IGNORE;
        !           372: }
        !           373: 
        !           374: public syserr()
        !           375: {
        !           376:     ERRINFO *e;
        !           377: 
        !           378:     if (errno < 0 or errno > sys_nerr) {
        !           379:        fatal("errno %d", errno);
        !           380:     } else {
        !           381:        if (errinfo == nil(ERRINFO *)) {
        !           382:            initErrInfo();
        !           383:        }
        !           384:        e = &(errinfo[errno]);
        !           385:        if (e->func == ERR_CATCH) {
        !           386:            fatal(sys_errlist[errno]);
        !           387:        } else if (e->func != ERR_IGNORE) {
        !           388:            (*e->func)();
        !           389:        }
        !           390:     }
        !           391: }
        !           392: 
        !           393: /*
        !           394:  * Catcherrs' purpose is to initialize the errinfo table, get this module
        !           395:  * loaded, and make sure my cerror is loaded (only applicable when this is
        !           396:  * in a library).
        !           397:  */
        !           398: 
        !           399: public catcherrs()
        !           400: {
        !           401:     _mycerror();
        !           402:     initErrInfo();
        !           403: }
        !           404: 
        !           405: /*
        !           406:  * Turn off the error catching mechanism completely by having all errors
        !           407:  * ignored.  This is most useful between a fork and an exec.
        !           408:  */
        !           409: 
        !           410: public nocatcherrs()
        !           411: {
        !           412:     integer i;
        !           413: 
        !           414:     for (i = 0; i < sys_nerr; i++) {
        !           415:        errinfo[i].func = ERR_IGNORE;
        !           416:     }
        !           417: }
        !           418: 
        !           419: /*
        !           420:  * Change the action on receipt of an error.
        !           421:  */
        !           422: 
        !           423: public onsyserr(n, f)
        !           424: int n;
        !           425: INTFUNC *f;
        !           426: {
        !           427:     if (errinfo == nil(ERRINFO *)) {
        !           428:        initErrInfo();
        !           429:     }
        !           430:     errinfo[n].func = f;
        !           431: }
        !           432: 
        !           433: /*
        !           434:  * Print the message associated with the given signal.
        !           435:  * Like a "perror" for signals.
        !           436:  */
        !           437: 
        !           438: public int sys_nsig = NSIG;
        !           439: 
        !           440: public psignal(s, n)
        !           441: String s;
        !           442: integer n;
        !           443: {
        !           444:     String msg;
        !           445:     integer len;
        !           446:     extern String sys_siglist[];
        !           447: 
        !           448:     if (n >= 0 and n < sys_nsig) {
        !           449:        msg = sys_siglist[n];
        !           450:     } else {
        !           451:        msg = "Unknown signal";
        !           452:     }
        !           453:     len = strlen(s);
        !           454:     if (len > 0) {
        !           455:        write(2, s, len);
        !           456:        write(2, ": ", 2);
        !           457:     }
        !           458:     write(2, msg, strlen(msg));
        !           459:     write(2, "\n", 1);
        !           460: }
        !           461: 
        !           462: /*
        !           463:  * Standard error handling routines.
        !           464:  */
        !           465: 
        !           466: private short nerrs;
        !           467: private short nwarnings;
        !           468: 
        !           469: /*
        !           470:  * Main driver of error message reporting.
        !           471:  */
        !           472: 
        !           473: /* VARARGS2 */
        !           474: private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
        !           475: String errname;
        !           476: boolean shouldquit;
        !           477: String s;
        !           478: {
        !           479:     fflush(stdout);
        !           480:     if (shouldquit and cmdname != nil(String)) {
        !           481:        fprintf(stderr, "%s: ", cmdname);
        !           482:     }
        !           483:     if (errfilename != nil(Filename)) {
        !           484:        fprintf(stderr, "%s: ", errfilename);
        !           485:     }
        !           486:     if (errlineno > 0) {
        !           487:        fprintf(stderr, "%d: ", errlineno);
        !           488:     }
        !           489:     if (errname != nil(String)) {
        !           490:        fprintf(stderr, "%s: ", errname);
        !           491:     }
        !           492:     fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
        !           493:     putc('\n', stderr);
        !           494:     if (shouldquit) {
        !           495:        quit(1);
        !           496:     }
        !           497: }
        !           498: 
        !           499: /*
        !           500:  * For when printf isn't sufficient for printing the error message ...
        !           501:  */
        !           502: 
        !           503: public beginerrmsg()
        !           504: {
        !           505:     fflush(stdout);
        !           506:     if (errfilename != nil(String)) {
        !           507:        fprintf(stderr, "%s: ", errfilename);
        !           508:     }
        !           509:     if (errlineno > 0) {
        !           510:        fprintf(stderr, "%d: ", errlineno);
        !           511:     }
        !           512: }
        !           513: 
        !           514: public enderrmsg()
        !           515: {
        !           516:     putc('\n', stderr);
        !           517:     erecover();
        !           518: }
        !           519: 
        !           520: /*
        !           521:  * The messages are listed in increasing order of seriousness.
        !           522:  *
        !           523:  * First are warnings.
        !           524:  */
        !           525: 
        !           526: /* VARARGS1 */
        !           527: public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
        !           528: String s;
        !           529: {
        !           530:     nwarnings++;
        !           531:     errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
        !           532: }
        !           533: 
        !           534: /*
        !           535:  * Errors are a little worse, they mean something is wrong,
        !           536:  * but not so bad that processing can't continue.
        !           537:  *
        !           538:  * The routine "erecover" is called to recover from the error,
        !           539:  * a default routine is provided that does nothing.
        !           540:  */
        !           541: 
        !           542: /* VARARGS1 */
        !           543: public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
        !           544: String s;
        !           545: {
        !           546:     extern erecover();
        !           547: 
        !           548:     nerrs++;
        !           549:     errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
        !           550:     erecover();
        !           551: }
        !           552: 
        !           553: /*
        !           554:  * Non-recoverable user error.
        !           555:  */
        !           556: 
        !           557: /* VARARGS1 */
        !           558: public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
        !           559: String s;
        !           560: {
        !           561:     errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
        !           562: }
        !           563: 
        !           564: /*
        !           565:  * Panics indicate an internal program error.
        !           566:  */
        !           567: 
        !           568: /* VARARGS1 */
        !           569: public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
        !           570: String s;
        !           571: {
        !           572:     errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
        !           573: }
        !           574: 
        !           575: short numerrors()
        !           576: {
        !           577:     short r;
        !           578: 
        !           579:     r = nerrs;
        !           580:     nerrs = 0;
        !           581:     return r;
        !           582: }
        !           583: 
        !           584: short numwarnings()
        !           585: {
        !           586:     short r;
        !           587: 
        !           588:     r = nwarnings;
        !           589:     nwarnings = 0;
        !           590:     return r;
        !           591: }
        !           592: 
        !           593: /*
        !           594:  * Recover from an error.
        !           595:  *
        !           596:  * This is the default routine which we aren't using since we have our own.
        !           597:  *
        !           598: public erecover()
        !           599: {
        !           600: }
        !           601:  *
        !           602:  */
        !           603: 
        !           604: /*
        !           605:  * Default way to quit from a program is just to exit.
        !           606:  *
        !           607: public quit(r)
        !           608: int r;
        !           609: {
        !           610:     exit(r);
        !           611: }
        !           612:  *
        !           613:  */
        !           614: 
        !           615: /*
        !           616:  * Compare n-byte areas pointed to by s1 and s2
        !           617:  * if n is 0 then compare up until one has a null byte.
        !           618:  */
        !           619: 
        !           620: public int cmp(s1, s2, n)
        !           621: register char *s1, *s2;
        !           622: register unsigned int n;
        !           623: {
        !           624:     if (s1 == nil(char *) || s2 == nil(char *)) {
        !           625:        panic("cmp: nil pointer");
        !           626:     }
        !           627:     if (n == 0) {
        !           628:        while (*s1 == *s2++) {
        !           629:            if (*s1++ == '\0') {
        !           630:                return(0);
        !           631:            }
        !           632:        }
        !           633:        return(*s1 - *(s2-1));
        !           634:     } else {
        !           635:        for (; n != 0; n--) {
        !           636:            if (*s1++ != *s2++) {
        !           637:                return(*(s1-1) - *(s2-1));
        !           638:            }
        !           639:        }
        !           640:        return(0);
        !           641:     }
        !           642: }
        !           643: 
        !           644: /*
        !           645:  * Move n bytes from src to dest.
        !           646:  * If n is 0 move until a null is found.
        !           647:  */
        !           648: 
        !           649: public mov(src, dest, n)
        !           650: register char *src, *dest;
        !           651: register unsigned int n;
        !           652: {
        !           653:     if (src == nil(char *))
        !           654:        panic("mov: nil source");
        !           655:     if (dest == nil(char *))
        !           656:        panic("mov: nil destination");
        !           657:     if (n != 0) {
        !           658:        for (; n != 0; n--) {
        !           659:            *dest++ = *src++;
        !           660:        }
        !           661:     } else {
        !           662:        while ((*dest++ = *src++) != '\0');
        !           663:     }
        !           664: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.