|
|
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.