📄 library.c
字号:
/* @(#)library.c 4.1 Ultrix 7/3/90 *//************************************************************************ * * * Copyright (c) 1986 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * * * Modification History * * * * 001 - Merged in 4.3 changes. * * (Victoria Holt, April 29, 1986) * * * * 002 - Added an xdb "magic cookie" to error messages if dbx has * * been called with the -x flag. * * (David Metsky, March 8, 1988) * * * ************************************************************************//* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */#ifndef lintstatic char sccsid[] = "@(#)library.c 5.1 (Berkeley) 5/31/85";#endif not lintstatic char rcsid[] = "$Header: library.c,v 1.5 84/12/26 10:39:52 linton Exp $";/* * General purpose routines. */#include <stdio.h>#include <errno.h>#include <signal.h>#define public#define private static#define and &&#define or ||#define not !#define ord(enumcon) ((int) enumcon)#define nil(type) ((type) 0)#define XDBMARK "xdb"typedef int integer;typedef enum { FALSE, TRUE } boolean;typedef char *String;typedef FILE *File;typedef String Filename;#undef FILEboolean xdb = FALSE; /* xdb specific features */String cmdname; /* name of command for error messages */Filename errfilename; /* current file associated with error */short errlineno; /* line number associated with error *//* * Definitions for doing memory allocation. */extern char *malloc();#define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type)))#define dispose(p) { free((char *) p); p = 0; }/* * Macros for doing freads + fwrites. */#define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp)#define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp)/* * String definitions. */extern String strcpy(), index(), rindex();extern int strlen();#define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s)#define streq(s1, s2) (strcmp(s1, s2) == 0)typedef int INTFUNC();typedef struct { INTFUNC *func;} ERRINFO;#define ERR_IGNORE ((INTFUNC *) 0)#define ERR_CATCH ((INTFUNC *) 1)/* * Call a program. * * Four entries: * * call, callv - call a program and wait for it, returning status * back, backv - call a program and don't wait, returning process id * * The command's standard input and output are passed as FILE's. */#define MAXNARGS 1000 /* unchecked upper limit on max num of arguments */#define BADEXEC 127 /* exec fails */#define ischild(pid) ((pid) == 0)/* VARARGS3 */public int call(name, in, out, args)String name;File in;File out;String args;{ String *ap, *argp; String argv[MAXNARGS]; argp = &argv[0]; *argp++ = name; ap = &args; while (*ap != nil(String)) { *argp++ = *ap++; } *argp = nil(String); return callv(name, in, out, argv);}/* VARARGS3 */public int back(name, in, out, args)String name;File in;File out;String args;{ String *ap, *argp; String argv[MAXNARGS]; argp = &argv[0]; *argp++ = name; ap = &args; while (*ap != nil(String)) { *argp++ = *ap++; } *argp = nil(String); return backv(name, in, out, argv);}public int callv(name, in, out, argv)String name;File in;File out;String *argv;{ int pid, status; pid = backv(name, in, out, argv); pwait(pid, &status); return status;}public int backv(name, in, out, argv)String name;File in;File out;String *argv;{ int pid; fflush(stdout); if (ischild(pid = fork())) { fswap(0, fileno(in)); fswap(1, fileno(out)); onsyserr(EACCES, ERR_IGNORE); execvp(name, argv); _exit(BADEXEC); } return pid;}/* * Swap file numbers so as to redirect standard input and output. */private fswap(oldfd, newfd)int oldfd;int newfd;{ if (oldfd != newfd) { close(oldfd); dup(newfd); close(newfd); }}/* * Invoke a shell on a command line. */#define DEF_SHELL "csh"public shell(s)String s;{ extern String getenv(); String sh; if ((sh = getenv("SHELL")) == nil(String)) { sh = DEF_SHELL; } if (s != nil(String) and *s != '\0') { call(sh, stdin, stdout, "-c", s, 0); } else { call(sh, stdin, stdout, 0); }}/* * Wait for a process the right way. We wait for a particular * process and if any others come along in between, we remember them * in case they are eventually waited for. * * This routine is not very efficient when the number of processes * to be remembered is large. * * To deal with a kernel idiosyncrasy, we keep a list on the side * of "traced" processes, and do not notice them when waiting for * another process. */typedef struct pidlist { int pid; int status; struct pidlist *next;} Pidlist;private Pidlist *pidlist, *ptrclist, *pfind();public ptraced(pid)int pid;{ Pidlist *p; p = alloc(1, Pidlist); p->pid = pid; p->next = ptrclist; ptrclist = p;}public unptraced(pid)int pid;{ register Pidlist *p, *prev; prev = nil(Pidlist *); p = ptrclist; while (p != nil(Pidlist *) and p->pid != pid) { prev = p; p = p->next; } if (p != nil(Pidlist *)) { if (prev == nil(Pidlist *)) { ptrclist = p->next; } else { prev->next = p->next; } dispose(p); }}private boolean isptraced(pid)int pid;{ register Pidlist *p; p = ptrclist; while (p != nil(Pidlist *) and p->pid != pid) { p = p->next; } return (boolean) (p != nil(Pidlist *));}public pwait(pid, statusp)int pid, *statusp;{ Pidlist *p; int pnum, status; p = pfind(pid); if (p != nil(Pidlist *)) { *statusp = p->status; dispose(p); } else { pnum = wait(&status); while (pnum != pid and pnum >= 0) { if (not isptraced(pnum)) { p = alloc(1, Pidlist); p->pid = pnum; p->status = status; p->next = pidlist; pidlist = p; } pnum = wait(&status); } if (pnum < 0) { p = pfind(pid); if (p == nil(Pidlist *)) { panic("pwait: pid %d not found", pid); } *statusp = p->status; dispose(p); } else { *statusp = status; } }}/* * Look for the given process id on the pidlist. * * Unlink it from list if found. */private Pidlist *pfind(pid)int pid;{ register Pidlist *p, *prev; prev = nil(Pidlist *); for (p = pidlist; p != nil(Pidlist *); p = p->next) { if (p->pid == pid) { break; } prev = p; } if (p != nil(Pidlist *)) { if (prev == nil(Pidlist *)) { pidlist = p->next; } else { prev->next = p->next; } } return p;}/* * System call error handler. * * The syserr routine is called when a system call is about to * set the c-bit to report an error. Certain errors are caught * and cause the process to print a message and immediately exit. */extern int sys_nerr;extern char *sys_errlist[]; /* * Before calling syserr, the integer errno is set to contain the * number of the error. The routine "_mycerror" is a dummy which * is used to force the loader to get my version of cerror rather * than the usual one. */extern int errno;extern _mycerror();/* * Initialize error information, setting defaults for handling errors. */private ERRINFO *errinfo;private initErrInfo (){ integer i; errinfo = alloc(sys_nerr, ERRINFO); for (i = 0; i < sys_nerr; i++) { errinfo[i].func = ERR_CATCH; } errinfo[0].func = ERR_IGNORE; errinfo[EPERM].func = ERR_IGNORE; errinfo[ENOENT].func = ERR_IGNORE; errinfo[ESRCH].func = ERR_IGNORE; errinfo[EBADF].func = ERR_IGNORE; errinfo[ENOTTY].func = ERR_IGNORE; errinfo[EOPNOTSUPP].func = ERR_IGNORE;}public syserr(){ ERRINFO *e; if (errno < 0 or errno > sys_nerr) { fatal("errno %d", errno); } else { if (errinfo == nil(ERRINFO *)) { initErrInfo(); } e = &(errinfo[errno]); if (e->func == ERR_CATCH) { fatal(sys_errlist[errno]); } else if (e->func != ERR_IGNORE) { (*e->func)(); } }}/* * Catcherrs' purpose is to initialize the errinfo table, get this module * loaded, and make sure my cerror is loaded (only applicable when this is * in a library). */public catcherrs(){ _mycerror(); initErrInfo();}/* * Turn off the error catching mechanism completely by having all errors * ignored. This is most useful between a fork and an exec. */public nocatcherrs(){ integer i; for (i = 0; i < sys_nerr; i++) { errinfo[i].func = ERR_IGNORE; }}/* * Change the action on receipt of an error. */public onsyserr(n, f)int n;INTFUNC *f;{ if (errinfo == nil(ERRINFO *)) { initErrInfo(); } errinfo[n].func = f;}/* * Print the message associated with the given signal. * Like a "perror" for signals. */public int sys_nsig = NSIG;public psignal(s, n)String s;integer n;{ String msg; integer len; extern String sys_siglist[]; if (n >= 0 and n < sys_nsig) { msg = sys_siglist[n]; } else { msg = "Unknown signal"; } len = strlen(s); if (len > 0) { write(2, s, len); write(2, ": ", 2); } write(2, msg, strlen(msg)); write(2, "\n", 1);}/* * Standard error handling routines. */private short nerrs;private short nwarnings;/* * Main driver of error message reporting. *//* VARARGS2 */private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)String errname;boolean shouldquit;String s;{ if (xdb) { /* 002 - DNM */ fprintf(stderr, XDBMARK); } fflush(stdout); if (shouldquit and cmdname != nil(String)) { fprintf(stderr, "%s: ", cmdname); } if (errfilename != nil(Filename)) { fprintf(stderr, "%s: ", errfilename); } if (errlineno > 0) { fprintf(stderr, "%d: ", errlineno); } if (errname != nil(String)) { fprintf(stderr, "%s: ", errname); } fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); putc('\n', stderr); if (shouldquit) { quit(1); }}/* * For when printf isn't sufficient for printing the error message ... */public beginerrmsg(){ fflush(stdout); if (errfilename != nil(String)) { fprintf(stderr, "%s: ", errfilename); } if (errlineno > 0) { fprintf(stderr, "%d: ", errlineno); }}public enderrmsg(){ putc('\n', stderr); erecover();}/* * The messages are listed in increasing order of seriousness. * * First are warnings. *//* VARARGS1 */public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)String s;{ nwarnings++; errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);}/* * Errors are a little worse, they mean something is wrong, * but not so bad that processing can't continue. * * The routine "erecover" is called to recover from the error, * a default routine is provided that does nothing. *//* VARARGS1 */public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)String s;{ extern erecover(); nerrs++; errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); erecover();}/* * Non-recoverable user error. *//* VARARGS1 */public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)String s;{ errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);}/* * Panics indicate an internal program error. *//* VARARGS1 */public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)String s;{ errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);}short numerrors(){ short r; r = nerrs; nerrs = 0; return r;}short numwarnings(){ short r; r = nwarnings; nwarnings = 0; return r;}/* * Recover from an error. * * This is the default routine which we aren't using since we have our own. *public erecover(){} * *//* * Default way to quit from a program is just to exit. *public quit(r)int r;{ exit(r);} * *//* * Compare n-byte areas pointed to by s1 and s2 * if n is 0 then compare up until one has a null byte. */public int cmp(s1, s2, n)register char *s1, *s2;register unsigned int n;{ if (s1 == nil(char *) || s2 == nil(char *)) { panic("cmp: nil pointer"); } if (n == 0) { while (*s1 == *s2++) { if (*s1++ == '\0') { return(0); } } return(*s1 - *(s2-1)); } else { for (; n != 0; n--) { if (*s1++ != *s2++) { return(*(s1-1) - *(s2-1)); } } return(0); }}/* * Move n bytes from src to dest. * If n is 0 move until a null is found. */public mov(src, dest, n)register char *src, *dest;register unsigned int n;{ if (src == nil(char *)) panic("mov: nil source"); if (dest == nil(char *)) panic("mov: nil destination"); if (n != 0) { for (; n != 0; n--) { *dest++ = *src++; } } else { while ((*dest++ = *src++) != '\0'); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -