port to tahoe by Nir peleg of CCI
[unix-history] / usr / src / usr.bin / pascal / pdx / library.c
CommitLineData
f6f0d0bf
KM
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 */
5bbc6432 6
f6f0d0bf 7#ifndef lint
35bf0218 8static char sccsid[] = "@(#)library.c 5.2 (Berkeley) %G%";
f6f0d0bf 9#endif not lint
5bbc6432
ML
10
11/*
12 * General purpose routines.
13 */
14
15#include <stdio.h>
16#include <errno.h>
35bf0218 17#include "defs.h"
5bbc6432
ML
18
19#define public
20#define private static
21#define and &&
5bbc6432
ML
22#define nil(type) ((type) 0)
23
5bbc6432
ML
24typedef char *String;
25typedef FILE *File;
26typedef String Filename;
35bf0218 27typedef char Boolean;
5bbc6432
ML
28
29#undef FILE
30
5bbc6432
ML
31String cmdname; /* name of command for error messages */
32Filename errfilename; /* current file associated with error */
33short errlineno; /* line number associated with error */
34
5bbc6432
ML
35typedef int INTFUNC();
36
37typedef struct {
38 INTFUNC *func;
39} ERRINFO;
40
41#define ERR_IGNORE ((INTFUNC *) 0)
42#define ERR_CATCH ((INTFUNC *) 1)
43
35bf0218
KM
44public INTFUNC *onsyserr();
45
5bbc6432
ML
46/*
47 * Call a program.
48 *
35bf0218 49 * Three entries:
5bbc6432
ML
50 *
51 * call, callv - call a program and wait for it, returning status
35bf0218 52 * backv - call a program and don't wait, returning process id
5bbc6432
ML
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 */
64public int call(name, in, out, args)
65String name;
66File in;
67File out;
68String 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
5bbc6432
ML
83public int callv(name, in, out, argv)
84String name;
85File in;
86File out;
87String *argv;
88{
89 int pid, status;
90
91 pid = backv(name, in, out, argv);
92 pwait(pid, &status);
93 return status;
94}
95
96public int backv(name, in, out, argv)
97String name;
98File in;
99File out;
100String *argv;
101{
102 int pid;
103
104 fflush(stdout);
105 if (ischild(pid = fork())) {
106 fswap(0, fileno(in));
107 fswap(1, fileno(out));
35bf0218 108 (void) onsyserr(EACCES, ERR_IGNORE);
5bbc6432
ML
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
119private fswap(oldfd, newfd)
120int oldfd;
121int 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
136public shell(s)
137String 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
157typedef struct pidlist {
158 int pid;
159 int status;
160 struct pidlist *next;
161} Pidlist;
162
163private Pidlist *pidlist, *pfind();
164
165public pwait(pid, statusp)
166int 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 {
35bf0218 192 *statusp = status;
5bbc6432 193 }
35bf0218
KM
194#ifdef tahoe
195 chkret(p, status);
196#endif
5bbc6432
ML
197}
198
199/*
200 * Look for the given process id on the pidlist.
201 *
202 * Unlink it from list if found.
203 */
204
205private Pidlist *pfind(pid)
206int 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 *)) {
35bf0218 219 pidlist = p->next;
5bbc6432 220 } else {
35bf0218 221 prev->next = p->next;
5bbc6432
ML
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
235extern int sys_nerr;
236extern char *sys_errlist[];
237
238/*
239 * Before calling syserr, the integer errno is set to contain the
35bf0218 240 * number of the error.
5bbc6432
ML
241 */
242
243extern int errno;
5bbc6432
ML
244
245/*
246 * default error handling
247 */
248
249private 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
288public 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
5bbc6432
ML
304/*
305 * Change the action on receipt of an error.
306 */
307
35bf0218 308public INTFUNC *onsyserr(n, f)
5bbc6432
ML
309int n;
310INTFUNC *f;
311{
35bf0218
KM
312 INTFUNC *g = errinfo[n].func;
313
5bbc6432 314 errinfo[n].func = f;
35bf0218 315 return(g);
5bbc6432
ML
316}
317
5bbc6432
ML
318/*
319 * Main driver of error message reporting.
320 */
321
322/* VARARGS2 */
323private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
324String errname;
325Boolean shouldquit;
326String 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
5bbc6432
ML
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 */
357public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
358String s;
359{
360 extern erecover();
361
5bbc6432
ML
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 */
371public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
372String 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 */
382public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
383String s;
384{
385 errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
386}
387
5bbc6432
ML
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
393public int cmp(s1, s2, n)
394register char *s1, *s2;
395register 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
422public mov(src, dest, n)
423register char *src, *dest;
35bf0218 424register int n;
5bbc6432 425{
35bf0218 426 if (src == nil(char *)) {
5bbc6432 427 panic("mov: nil source");
35bf0218
KM
428 }
429 if (dest == nil(char *)) {
5bbc6432 430 panic("mov: nil destination");
35bf0218 431 }
5bbc6432
ML
432 if (n > 0) {
433 for (; n != 0; n--) {
434 *dest++ = *src++;
435 }
436 } else {
437 while ((*dest++ = *src++) != '\0');
438 }
439}