xref: /original-bsd/usr.bin/pascal/pdx/library.c (revision deff14a8)
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.2 (Berkeley) 05/27/94";
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 
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