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