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