xref: /original-bsd/usr.bin/pascal/pdx/library.c (revision 262b24ac)
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.2 (Berkeley) 04/07/87";
9 #endif not lint
10 
11 /*
12  * General purpose routines.
13  */
14 
15 #include <stdio.h>
16 #include <errno.h>
17 #include "defs.h"
18 
19 #define public
20 #define private static
21 #define and &&
22 #define nil(type)	((type) 0)
23 
24 typedef char *String;
25 typedef FILE *File;
26 typedef String Filename;
27 typedef char Boolean;
28 
29 #undef FILE
30 
31 String cmdname;			/* name of command for error messages */
32 Filename errfilename;		/* current file associated with error */
33 short errlineno;		/* line number associated with error */
34 
35 typedef int INTFUNC();
36 
37 typedef struct {
38     INTFUNC *func;
39 } ERRINFO;
40 
41 #define ERR_IGNORE ((INTFUNC *) 0)
42 #define ERR_CATCH  ((INTFUNC *) 1)
43 
44 public INTFUNC *onsyserr();
45 
46 /*
47  * Call a program.
48  *
49  * Three entries:
50  *
51  *	call, callv - call a program and wait for it, returning status
52  *	backv - call a program and don't wait, returning process id
53  *
54  * The command's standard input and output are passed as FILE's.
55  */
56 
57 
58 #define MAXNARGS 100    /* unchecked upper limit on max num of arguments */
59 #define BADEXEC 127	/* exec fails */
60 
61 #define ischild(pid)    ((pid) == 0)
62 
63 /* VARARGS3 */
64 public int call(name, in, out, args)
65 String name;
66 File in;
67 File out;
68 String args;
69 {
70     String *ap, *argp;
71     String argv[MAXNARGS];
72 
73     argp = &argv[0];
74     *argp++ = name;
75     ap = &args;
76     while (*ap != nil(String)) {
77 	*argp++ = *ap++;
78     }
79     *argp = nil(String);
80     return callv(name, in, out, argv);
81 }
82 
83 public int callv(name, in, out, argv)
84 String name;
85 File in;
86 File out;
87 String *argv;
88 {
89     int pid, status;
90 
91     pid = backv(name, in, out, argv);
92     pwait(pid, &status);
93     return status;
94 }
95 
96 public int backv(name, in, out, argv)
97 String name;
98 File in;
99 File out;
100 String *argv;
101 {
102     int pid;
103 
104     fflush(stdout);
105     if (ischild(pid = fork())) {
106 	fswap(0, fileno(in));
107 	fswap(1, fileno(out));
108 	(void) onsyserr(EACCES, ERR_IGNORE);
109 	execvp(name, argv);
110 	_exit(BADEXEC);
111     }
112     return pid;
113 }
114 
115 /*
116  * Swap file numbers so as to redirect standard input and output.
117  */
118 
119 private fswap(oldfd, newfd)
120 int oldfd;
121 int newfd;
122 {
123     if (oldfd != newfd) {
124 	close(oldfd);
125 	dup(newfd);
126 	close(newfd);
127     }
128 }
129 
130 /*
131  * Invoke a shell on a command line.
132  */
133 
134 #define DEF_SHELL	"csh"
135 
136 public shell(s)
137 String s;
138 {
139     extern String getenv();
140     String sh;
141 
142     if ((sh = getenv("SHELL")) == nil(String)) {
143 	sh = DEF_SHELL;
144     }
145     call(sh, stdin, stdout, "-c", s, 0);
146 }
147 
148 /*
149  * Wait for a process the right way.  We wait for a particular
150  * process and if any others come along in between, we remember them
151  * in case they are eventually waited for.
152  *
153  * This routine is not very efficient when the number of processes
154  * to be remembered is large.
155  */
156 
157 typedef struct pidlist {
158     int pid;
159     int status;
160     struct pidlist *next;
161 } Pidlist;
162 
163 private Pidlist *pidlist, *pfind();
164 
165 public pwait(pid, statusp)
166 int pid, *statusp;
167 {
168 	Pidlist *p;
169 	int pnum, status;
170 
171 	p = pfind(pid);
172 	if (p != nil(Pidlist *)) {
173 	    *statusp = p->status;
174 	    dispose(p);
175 	    return;
176 	}
177 	while ((pnum = wait(&status)) != pid && pnum >= 0) {
178 	    p = alloc(1, Pidlist);
179 	    p->pid = pnum;
180 	    p->status = status;
181 	    p->next = pidlist;
182 	    pidlist = p;
183 	}
184 	if (pnum < 0) {
185 	    p = pfind(pid);
186 	    if (p == nil(Pidlist *)) {
187 		panic("pwait: pid %d not found", pid);
188 	    }
189 	    *statusp = p->status;
190 	    dispose(p);
191 	} else {
192 	    *statusp = status;
193 	}
194 #ifdef tahoe
195 	chkret(p, status);
196 #endif
197 }
198 
199 /*
200  * Look for the given process id on the pidlist.
201  *
202  * Unlink it from list if found.
203  */
204 
205 private Pidlist *pfind(pid)
206 int pid;
207 {
208     register Pidlist *p, *prev;
209 
210     prev = nil(Pidlist *);
211     for (p = pidlist; p != nil(Pidlist *); p = p->next) {
212 	if (p->pid == pid) {
213 	    break;
214 	}
215 	prev = p;
216     }
217     if (p != nil(Pidlist *)) {
218 	if (prev == nil(Pidlist *)) {
219 	    pidlist = p->next;
220 	} else {
221 	    prev->next = p->next;
222 	}
223     }
224     return p;
225 }
226 
227 /*
228  * System call error handler.
229  *
230  * The syserr routine is called when a system call is about to
231  * set the c-bit to report an error.  Certain errors are caught
232  * and cause the process to print a message and immediately exit.
233  */
234 
235 extern int sys_nerr;
236 extern char *sys_errlist[];
237 
238 /*
239  * Before calling syserr, the integer errno is set to contain the
240  * number of the error.
241  */
242 
243 extern int errno;
244 
245 /*
246  * default error handling
247  */
248 
249 private ERRINFO errinfo[] ={
250 /* no error */	ERR_IGNORE,
251 /* EPERM */	ERR_IGNORE,
252 /* ENOENT */	ERR_IGNORE,
253 /* ESRCH */	ERR_IGNORE,
254 /* EINTR */	ERR_CATCH,
255 /* EIO */	ERR_CATCH,
256 /* ENXIO */	ERR_CATCH,
257 /* E2BIG */	ERR_CATCH,
258 /* ENOEXEC */	ERR_CATCH,
259 /* EBADF */	ERR_IGNORE,
260 /* ECHILD */	ERR_CATCH,
261 /* EAGAIN */	ERR_CATCH,
262 /* ENOMEM */	ERR_CATCH,
263 /* EACCES */	ERR_CATCH,
264 /* EFAULT */	ERR_CATCH,
265 /* ENOTBLK */	ERR_CATCH,
266 /* EBUSY */	ERR_CATCH,
267 /* EEXIST */	ERR_CATCH,
268 /* EXDEV */	ERR_CATCH,
269 /* ENODEV */	ERR_CATCH,
270 /* ENOTDIR */	ERR_CATCH,
271 /* EISDIR */	ERR_CATCH,
272 /* EINVAL */	ERR_CATCH,
273 /* ENFILE */	ERR_CATCH,
274 /* EMFILE */	ERR_CATCH,
275 /* ENOTTY */	ERR_IGNORE,
276 /* ETXTBSY */	ERR_CATCH,
277 /* EFBIG */	ERR_CATCH,
278 /* ENOSPC */	ERR_CATCH,
279 /* ESPIPE */	ERR_CATCH,
280 /* EROFS */	ERR_CATCH,
281 /* EMLINK */	ERR_CATCH,
282 /* EPIPE */	ERR_CATCH,
283 /* EDOM */	ERR_CATCH,
284 /* ERANGE */	ERR_CATCH,
285 /* EQUOT */	ERR_CATCH,
286 };
287 
288 public syserr()
289 {
290     ERRINFO *e;
291 
292     e = &errinfo[errno];
293     if (e->func == ERR_CATCH) {
294 	if (errno < sys_nerr) {
295 	    panic(sys_errlist[errno]);
296 	} else {
297 	    panic("errno %d", errno);
298 	}
299     } else if (e->func != ERR_IGNORE) {
300 	(*e->func)();
301     }
302 }
303 
304 /*
305  * Change the action on receipt of an error.
306  */
307 
308 public INTFUNC *onsyserr(n, f)
309 int n;
310 INTFUNC *f;
311 {
312     INTFUNC *g = errinfo[n].func;
313 
314     errinfo[n].func = f;
315     return(g);
316 }
317 
318 /*
319  * Main driver of error message reporting.
320  */
321 
322 /* VARARGS2 */
323 private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
324 String errname;
325 Boolean shouldquit;
326 String s;
327 {
328     fflush(stdout);
329     if (shouldquit and cmdname != nil(String)) {
330 	fprintf(stderr, "%s: ", cmdname);
331     }
332     if (errfilename != nil(Filename)) {
333 	fprintf(stderr, "%s: ", errfilename);
334     }
335     if (errlineno > 0) {
336 	fprintf(stderr, "%d: ", errlineno);
337     }
338     if (errname != nil(String)) {
339 	fprintf(stderr, "%s: ", errname);
340     }
341     fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
342     putc('\n', stderr);
343     if (shouldquit) {
344 	quit(1);
345     }
346 }
347 
348 /*
349  * Errors are a little worse, they mean something is wrong,
350  * but not so bad that processing can't continue.
351  *
352  * The routine "erecover" is called to recover from the error,
353  * a default routine is provided that does nothing.
354  */
355 
356 /* VARARGS1 */
357 public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
358 String s;
359 {
360     extern erecover();
361 
362     errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
363     erecover();
364 }
365 
366 /*
367  * Non-recoverable user error.
368  */
369 
370 /* VARARGS1 */
371 public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
372 String s;
373 {
374     errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
375 }
376 
377 /*
378  * Panics indicate an internal program error.
379  */
380 
381 /* VARARGS1 */
382 public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
383 String s;
384 {
385     errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
386 }
387 
388 /*
389  * Compare n-byte areas pointed to by s1 and s2
390  * if n is 0 then compare up until one has a null byte.
391  */
392 
393 public int cmp(s1, s2, n)
394 register char *s1, *s2;
395 register unsigned int n;
396 {
397     if (s1 == nil(char *) || s2 == nil(char *)) {
398 	panic("cmp: nil pointer");
399     }
400     if (n == 0) {
401 	while (*s1 == *s2++) {
402 	    if (*s1++ == '\0') {
403 		return(0);
404 	    }
405 	}
406 	return(*s1 - *(s2-1));
407     } else {
408 	for (; n != 0; n--) {
409 	    if (*s1++ != *s2++) {
410 		return(*(s1-1) - *(s2-1));
411 	    }
412 	}
413 	return(0);
414     }
415 }
416 
417 /*
418  * Move n bytes from src to dest.
419  * If n is 0 move until a null is found.
420  */
421 
422 public mov(src, dest, n)
423 register char *src, *dest;
424 register int n;
425 {
426     if (src == nil(char *)) {
427 	panic("mov: nil source");
428     }
429     if (dest == nil(char *)) {
430 	panic("mov: nil destination");
431     }
432     if (n > 0) {
433 	for (; n != 0; n--) {
434 	    *dest++ = *src++;
435 	}
436     } else {
437 	while ((*dest++ = *src++) != '\0');
438     }
439 }
440