date and time created 83/08/05 13:34:37 by sam
[unix-history] / usr / src / old / dbx / library.c
CommitLineData
536150a4
ML
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#include <signal.h>
12
13#define public
14#define private static
15#define and &&
16#define or ||
17#define not !
18#define ord(enumcon) ((int) enumcon)
19#define nil(type) ((type) 0)
20
21typedef enum { FALSE, TRUE } Boolean;
22typedef char *String;
23typedef FILE *File;
24typedef String Filename;
25
26#undef FILE
27
28/*
29 * Definitions of standard C library routines that aren't in the
30 * standard I/O library, but which are generally useful.
31 */
32
33extern long atol(); /* ascii to long */
34extern double atof(); /* ascii to floating point */
35extern char *mktemp(); /* make a temporary file name */
36
37String cmdname; /* name of command for error messages */
38Filename errfilename; /* current file associated with error */
39short errlineno; /* line number associated with error */
40
41/*
42 * Definitions for doing memory allocation.
43 */
44
45extern 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
61extern String strcpy(), index(), rindex();
62extern int strlen();
63
64#define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s)
65#define streq(s1, s2) (strcmp(s1, s2) == 0)
66
67typedef int INTFUNC();
68
69typedef 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 100 /* unchecked upper limit on max num of arguments */
89#define BADEXEC 127 /* exec fails */
90
91#define ischild(pid) ((pid) == 0)
92
93/* VARARGS3 */
94public int call(name, in, out, args)
95String name;
96File in;
97File out;
98String 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 */
114public int back(name, in, out, args)
115String name;
116File in;
117File out;
118String 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
133public int callv(name, in, out, argv)
134String name;
135File in;
136File out;
137String *argv;
138{
139 int pid, status;
140
141 pid = backv(name, in, out, argv);
142 pwait(pid, &status);
143 return status;
144}
145
146public int backv(name, in, out, argv)
147String name;
148File in;
149File out;
150String *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
169private fswap(oldfd, newfd)
170int oldfd;
171int 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
186public shell(s)
187String 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
211typedef struct pidlist {
212 int pid;
213 int status;
214 struct pidlist *next;
215} Pidlist;
216
217private Pidlist *pidlist, *pfind();
218
219public pwait(pid, statusp)
220int pid, *statusp;
221{
222 Pidlist *p;
223 int pnum, status;
224
225 p = pfind(pid);
226 if (p != nil(Pidlist *)) {
227 *statusp = p->status;
228 dispose(p);
229 return;
230 }
231 while ((pnum = wait(&status)) != pid && pnum >= 0) {
232 p = alloc(1, Pidlist);
233 p->pid = pnum;
234 p->status = status;
235 p->next = pidlist;
236 pidlist = p;
237 }
238 if (pnum < 0) {
239 p = pfind(pid);
240 if (p == nil(Pidlist *)) {
241 panic("pwait: pid %d not found", pid);
242 }
243 *statusp = p->status;
244 dispose(p);
245 } else {
246 *statusp = status;
247 }
248}
249
250/*
251 * Look for the given process id on the pidlist.
252 *
253 * Unlink it from list if found.
254 */
255
256private Pidlist *pfind(pid)
257int pid;
258{
259 register Pidlist *p, *prev;
260
261 prev = nil(Pidlist *);
262 for (p = pidlist; p != nil(Pidlist *); p = p->next) {
263 if (p->pid == pid) {
264 break;
265 }
266 prev = p;
267 }
268 if (p != nil(Pidlist *)) {
269 if (prev == nil(Pidlist *)) {
270 pidlist = p->next;
271 } else {
272 prev->next = p->next;
273 }
274 }
275 return p;
276}
277
278/*
279 * System call error handler.
280 *
281 * The syserr routine is called when a system call is about to
282 * set the c-bit to report an error. Certain errors are caught
283 * and cause the process to print a message and immediately exit.
284 */
285
286extern int sys_nerr;
287extern char *sys_errlist[];
288
289/*
290 * Before calling syserr, the integer errno is set to contain the
291 * number of the error. The routine "_mycerror" is a dummy which
292 * is used to force the loader to get my version of cerror rather
293 * than the usual one.
294 */
295
296extern int errno;
297extern _mycerror();
298
299/*
300 * Default error handling.
301 */
302
303private ERRINFO errinfo[] ={
304/* no error */ ERR_IGNORE,
305/* EPERM */ ERR_IGNORE,
306/* ENOENT */ ERR_IGNORE,
307/* ESRCH */ ERR_IGNORE,
308/* EINTR */ ERR_CATCH,
309/* EIO */ ERR_CATCH,
310/* ENXIO */ ERR_CATCH,
311/* E2BIG */ ERR_CATCH,
312/* ENOEXEC */ ERR_CATCH,
313/* EBADF */ ERR_IGNORE,
314/* ECHILD */ ERR_CATCH,
315/* EAGAIN */ ERR_CATCH,
316/* ENOMEM */ ERR_CATCH,
317/* EACCES */ ERR_CATCH,
318/* EFAULT */ ERR_CATCH,
319/* ENOTBLK */ ERR_CATCH,
320/* EBUSY */ ERR_CATCH,
321/* EEXIST */ ERR_CATCH,
322/* EXDEV */ ERR_CATCH,
323/* ENODEV */ ERR_CATCH,
324/* ENOTDIR */ ERR_CATCH,
325/* EISDIR */ ERR_CATCH,
326/* EINVAL */ ERR_CATCH,
327/* ENFILE */ ERR_CATCH,
328/* EMFILE */ ERR_CATCH,
329/* ENOTTY */ ERR_IGNORE,
330/* ETXTBSY */ ERR_CATCH,
331/* EFBIG */ ERR_CATCH,
332/* ENOSPC */ ERR_CATCH,
333/* ESPIPE */ ERR_CATCH,
334/* EROFS */ ERR_CATCH,
335/* EMLINK */ ERR_CATCH,
336/* EPIPE */ ERR_CATCH,
337/* EDOM */ ERR_CATCH,
338/* ERANGE */ ERR_CATCH,
339/* EQUOT */ ERR_CATCH,
340};
341
342public syserr()
343{
344 ERRINFO *e;
345
346 e = &errinfo[errno];
347 if (e->func == ERR_CATCH) {
348 if (errno < sys_nerr) {
349 fatal(sys_errlist[errno]);
350 } else {
351 fatal("errno %d", errno);
352 }
353 } else if (e->func != ERR_IGNORE) {
354 (*e->func)();
355 }
356}
357
358/*
359 * Catcherrs only purpose is to get this module loaded and make
360 * sure my cerror is loaded (only applicable when this is in a library).
361 */
362
363public catcherrs()
364{
365 _mycerror();
366}
367
368/*
369 * Change the action on receipt of an error.
370 */
371
372public onsyserr(n, f)
373int n;
374INTFUNC *f;
375{
376 errinfo[n].func = f;
377}
378
379/*
380 * Print the message associated with the given signal.
381 * Like a "perror" for signals.
382 */
383
384public int sys_nsig = NSIG;
385public String sys_siglist[] = {
386 "no signal",
387 "hangup",
388 "interrupt",
389 "quit",
390 "illegal instruction",
391 "trace trap",
392 "IOT instruction",
393 "EMT instruction",
394 "floating point exception",
395 "kill",
396 "bus error",
397 "segmentation violation",
398 "bad argument to system call",
399 "broken pipe",
400 "alarm clock",
401 "soft kill",
402 "urgent I/O condition",
403 "stop signal not from tty",
404 "stop signal from tty",
405 "continue",
406 "child termination",
407 "stop (tty input)",
408 "stop (tty output)",
409 "possible input/output",
410 "exceeded CPU time limit",
411 "exceeded file size limit",
412 nil(String)
413};
414
415public psig(s)
416String s;
417{
418 String c;
419 int n;
420
421 c = "Unknown signal";
422 if (errno < sys_nsig) {
423 c = sys_errlist[errno];
424 }
425 n = strlen(s);
426 if (n > 0) {
427 write(2, s, n);
428 write(2, ": ", 2);
429 }
430 write(2, c, strlen(c));
431 write(2, "\n", 1);
432}
433
434/*
435 * Standard error handling routines.
436 */
437
438private short nerrs;
439private short nwarnings;
440
441/*
442 * Main driver of error message reporting.
443 */
444
445/* VARARGS2 */
446private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
447String errname;
448Boolean shouldquit;
449String s;
450{
451 fflush(stdout);
452 if (shouldquit and cmdname != nil(String)) {
453 fprintf(stderr, "%s: ", cmdname);
454 }
455 if (errfilename != nil(Filename)) {
456 fprintf(stderr, "%s: ", errfilename);
457 }
458 if (errlineno > 0) {
459 fprintf(stderr, "%d: ", errlineno);
460 }
461 if (errname != nil(String)) {
462 fprintf(stderr, "%s: ", errname);
463 }
464 fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
465 putc('\n', stderr);
466 if (shouldquit) {
467 quit(1);
468 }
469}
470
471/*
472 * For when printf isn't sufficient for printing the error message ...
473 */
474
475public beginerrmsg()
476{
477 fflush(stdout);
478 if (errfilename != nil(String)) {
479 fprintf(stderr, "%s: ", errfilename);
480 }
481 if (errlineno > 0) {
482 fprintf(stderr, "%d: ", errlineno);
483 }
484}
485
486public enderrmsg()
487{
488 putc('\n', stderr);
489 erecover();
490}
491
492/*
493 * The messages are listed in increasing order of seriousness.
494 *
495 * First are warnings.
496 */
497
498/* VARARGS1 */
499public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
500String s;
501{
502 nwarnings++;
503 errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
504}
505
506/*
507 * Errors are a little worse, they mean something is wrong,
508 * but not so bad that processing can't continue.
509 *
510 * The routine "erecover" is called to recover from the error,
511 * a default routine is provided that does nothing.
512 */
513
514/* VARARGS1 */
515public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
516String s;
517{
518 extern erecover();
519
520 nerrs++;
521 errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
522 erecover();
523}
524
525/*
526 * Non-recoverable user error.
527 */
528
529/* VARARGS1 */
530public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
531String s;
532{
533 errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
534}
535
536/*
537 * Panics indicate an internal program error.
538 */
539
540/* VARARGS1 */
541public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
542String s;
543{
544 errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
545}
546
547short numerrors()
548{
549 short r;
550
551 r = nerrs;
552 nerrs = 0;
553 return r;
554}
555
556short numwarnings()
557{
558 short r;
559
560 r = nwarnings;
561 nwarnings = 0;
562 return r;
563}
564
565/*
566 * Recover from an error.
567 *
568 * This is the default routine which we aren't using since we have our own.
569 *
570public erecover()
571{
572}
573 *
574 */
575
576/*
577 * Default way to quit from a program is just to exit.
578 *
579public quit(r)
580int r;
581{
582 exit(r);
583}
584 *
585 */
586
587/*
588 * Compare n-byte areas pointed to by s1 and s2
589 * if n is 0 then compare up until one has a null byte.
590 */
591
592public int cmp(s1, s2, n)
593register char *s1, *s2;
594register unsigned int n;
595{
596 if (s1 == nil(char *) || s2 == nil(char *)) {
597 panic("cmp: nil pointer");
598 }
599 if (n == 0) {
600 while (*s1 == *s2++) {
601 if (*s1++ == '\0') {
602 return(0);
603 }
604 }
605 return(*s1 - *(s2-1));
606 } else {
607 for (; n != 0; n--) {
608 if (*s1++ != *s2++) {
609 return(*(s1-1) - *(s2-1));
610 }
611 }
612 return(0);
613 }
614}
615
616/*
617 * Move n bytes from src to dest.
618 * If n is 0 move until a null is found.
619 */
620
621public mov(src, dest, n)
622register char *src, *dest;
623register unsigned int n;
624{
625 if (src == nil(char *))
626 panic("mov: nil source");
627 if (dest == nil(char *))
628 panic("mov: nil destination");
629 if (n != 0) {
630 for (; n != 0; n--) {
631 *dest++ = *src++;
632 }
633 } else {
634 while ((*dest++ = *src++) != '\0');
635 }
636}