xref: /csrg-svn/usr.bin/pascal/pdx/library.c (revision 8020)
1*8020Slinton /* Copyright (c) 1982 Regents of the University of California */
2*8020Slinton 
3*8020Slinton /* static char sccsid[] = "@(#)library.c 1.1 09/02/82"; */
4*8020Slinton 
5*8020Slinton /*
6*8020Slinton  * General purpose routines.
7*8020Slinton  */
8*8020Slinton 
9*8020Slinton #include <stdio.h>
10*8020Slinton #include <errno.h>
11*8020Slinton 
12*8020Slinton #define public
13*8020Slinton #define private static
14*8020Slinton #define and &&
15*8020Slinton #define or ||
16*8020Slinton #define not !
17*8020Slinton #define ord(enumcon)	((int) enumcon)
18*8020Slinton #define nil(type)	((type) 0)
19*8020Slinton 
20*8020Slinton typedef enum { FALSE, TRUE } Boolean;
21*8020Slinton typedef char *String;
22*8020Slinton typedef FILE *File;
23*8020Slinton typedef String Filename;
24*8020Slinton 
25*8020Slinton #undef FILE
26*8020Slinton 
27*8020Slinton /*
28*8020Slinton  * Definitions of standard C library routines that aren't in the
29*8020Slinton  * standard I/O library, but which are generally useful.
30*8020Slinton  */
31*8020Slinton 
32*8020Slinton extern long atol();		/* ascii to long */
33*8020Slinton extern double atof();		/* ascii to floating point */
34*8020Slinton extern char *mktemp();		/* make a temporary file name */
35*8020Slinton 
36*8020Slinton String cmdname;			/* name of command for error messages */
37*8020Slinton Filename errfilename;		/* current file associated with error */
38*8020Slinton short errlineno;		/* line number associated with error */
39*8020Slinton 
40*8020Slinton /*
41*8020Slinton  * Definitions for doing memory allocation.
42*8020Slinton  */
43*8020Slinton 
44*8020Slinton extern char *malloc();
45*8020Slinton 
46*8020Slinton #define alloc(n, type)	((type *) malloc((unsigned) (n) * sizeof(type)))
47*8020Slinton #define dispose(p)	{ free((char *) p); p = 0; }
48*8020Slinton 
49*8020Slinton /*
50*8020Slinton  * Macros for doing freads + fwrites.
51*8020Slinton  */
52*8020Slinton 
53*8020Slinton #define get(fp, var)	fread((char *) &(var), sizeof(var), 1, fp)
54*8020Slinton #define put(fp, var)	fwrite((char *) &(var), sizeof(var), 1, fp)
55*8020Slinton 
56*8020Slinton /*
57*8020Slinton  * String definitions.
58*8020Slinton  */
59*8020Slinton 
60*8020Slinton extern String strcpy(), index(), rindex();
61*8020Slinton extern int strlen();
62*8020Slinton 
63*8020Slinton #define strdup(s)		strcpy(malloc((unsigned) strlen(s) + 1), s)
64*8020Slinton #define streq(s1, s2)	(strcmp(s1, s2) == 0)
65*8020Slinton 
66*8020Slinton typedef int INTFUNC();
67*8020Slinton 
68*8020Slinton typedef struct {
69*8020Slinton     INTFUNC *func;
70*8020Slinton } ERRINFO;
71*8020Slinton 
72*8020Slinton #define ERR_IGNORE ((INTFUNC *) 0)
73*8020Slinton #define ERR_CATCH  ((INTFUNC *) 1)
74*8020Slinton 
75*8020Slinton /*
76*8020Slinton  * Call a program.
77*8020Slinton  *
78*8020Slinton  * Four entries:
79*8020Slinton  *
80*8020Slinton  *	call, callv - call a program and wait for it, returning status
81*8020Slinton  *	back, backv - call a program and don't wait, returning process id
82*8020Slinton  *
83*8020Slinton  * The command's standard input and output are passed as FILE's.
84*8020Slinton  */
85*8020Slinton 
86*8020Slinton 
87*8020Slinton #define MAXNARGS 100    /* unchecked upper limit on max num of arguments */
88*8020Slinton #define BADEXEC 127	/* exec fails */
89*8020Slinton 
90*8020Slinton #define ischild(pid)    ((pid) == 0)
91*8020Slinton 
92*8020Slinton /* VARARGS3 */
93*8020Slinton public int call(name, in, out, args)
94*8020Slinton String name;
95*8020Slinton File in;
96*8020Slinton File out;
97*8020Slinton String args;
98*8020Slinton {
99*8020Slinton     String *ap, *argp;
100*8020Slinton     String argv[MAXNARGS];
101*8020Slinton 
102*8020Slinton     argp = &argv[0];
103*8020Slinton     *argp++ = name;
104*8020Slinton     ap = &args;
105*8020Slinton     while (*ap != nil(String)) {
106*8020Slinton 	*argp++ = *ap++;
107*8020Slinton     }
108*8020Slinton     *argp = nil(String);
109*8020Slinton     return callv(name, in, out, argv);
110*8020Slinton }
111*8020Slinton 
112*8020Slinton /* VARARGS3 */
113*8020Slinton public int back(name, in, out, args)
114*8020Slinton String name;
115*8020Slinton File in;
116*8020Slinton File out;
117*8020Slinton String args;
118*8020Slinton {
119*8020Slinton     String *ap, *argp;
120*8020Slinton     String argv[MAXNARGS];
121*8020Slinton 
122*8020Slinton     argp = &argv[0];
123*8020Slinton     *argp++ = name;
124*8020Slinton     ap = &args;
125*8020Slinton     while (*ap != nil(String)) {
126*8020Slinton 	*argp++ = *ap++;
127*8020Slinton     }
128*8020Slinton     *argp = nil(String);
129*8020Slinton     return backv(name, in, out, argv);
130*8020Slinton }
131*8020Slinton 
132*8020Slinton public int callv(name, in, out, argv)
133*8020Slinton String name;
134*8020Slinton File in;
135*8020Slinton File out;
136*8020Slinton String *argv;
137*8020Slinton {
138*8020Slinton     int pid, status;
139*8020Slinton 
140*8020Slinton     pid = backv(name, in, out, argv);
141*8020Slinton     pwait(pid, &status);
142*8020Slinton     return status;
143*8020Slinton }
144*8020Slinton 
145*8020Slinton public int backv(name, in, out, argv)
146*8020Slinton String name;
147*8020Slinton File in;
148*8020Slinton File out;
149*8020Slinton String *argv;
150*8020Slinton {
151*8020Slinton     int pid;
152*8020Slinton 
153*8020Slinton     fflush(stdout);
154*8020Slinton     if (ischild(pid = fork())) {
155*8020Slinton 	fswap(0, fileno(in));
156*8020Slinton 	fswap(1, fileno(out));
157*8020Slinton 	onsyserr(EACCES, ERR_IGNORE);
158*8020Slinton 	execvp(name, argv);
159*8020Slinton 	_exit(BADEXEC);
160*8020Slinton     }
161*8020Slinton     return pid;
162*8020Slinton }
163*8020Slinton 
164*8020Slinton /*
165*8020Slinton  * Swap file numbers so as to redirect standard input and output.
166*8020Slinton  */
167*8020Slinton 
168*8020Slinton private fswap(oldfd, newfd)
169*8020Slinton int oldfd;
170*8020Slinton int newfd;
171*8020Slinton {
172*8020Slinton     if (oldfd != newfd) {
173*8020Slinton 	close(oldfd);
174*8020Slinton 	dup(newfd);
175*8020Slinton 	close(newfd);
176*8020Slinton     }
177*8020Slinton }
178*8020Slinton 
179*8020Slinton /*
180*8020Slinton  * Invoke a shell on a command line.
181*8020Slinton  */
182*8020Slinton 
183*8020Slinton #define DEF_SHELL	"csh"
184*8020Slinton 
185*8020Slinton public shell(s)
186*8020Slinton String s;
187*8020Slinton {
188*8020Slinton     extern String getenv();
189*8020Slinton     String sh;
190*8020Slinton 
191*8020Slinton     if ((sh = getenv("SHELL")) == nil(String)) {
192*8020Slinton 	sh = DEF_SHELL;
193*8020Slinton     }
194*8020Slinton     call(sh, stdin, stdout, "-c", s, 0);
195*8020Slinton }
196*8020Slinton 
197*8020Slinton /*
198*8020Slinton  * Wait for a process the right way.  We wait for a particular
199*8020Slinton  * process and if any others come along in between, we remember them
200*8020Slinton  * in case they are eventually waited for.
201*8020Slinton  *
202*8020Slinton  * This routine is not very efficient when the number of processes
203*8020Slinton  * to be remembered is large.
204*8020Slinton  */
205*8020Slinton 
206*8020Slinton typedef struct pidlist {
207*8020Slinton     int pid;
208*8020Slinton     int status;
209*8020Slinton     struct pidlist *next;
210*8020Slinton } Pidlist;
211*8020Slinton 
212*8020Slinton private Pidlist *pidlist, *pfind();
213*8020Slinton 
214*8020Slinton public pwait(pid, statusp)
215*8020Slinton int pid, *statusp;
216*8020Slinton {
217*8020Slinton 	Pidlist *p;
218*8020Slinton 	int pnum, status;
219*8020Slinton 
220*8020Slinton 	p = pfind(pid);
221*8020Slinton 	if (p != nil(Pidlist *)) {
222*8020Slinton 	    *statusp = p->status;
223*8020Slinton 	    dispose(p);
224*8020Slinton 	    return;
225*8020Slinton 	}
226*8020Slinton 	while ((pnum = wait(&status)) != pid && pnum >= 0) {
227*8020Slinton 	    p = alloc(1, Pidlist);
228*8020Slinton 	    p->pid = pnum;
229*8020Slinton 	    p->status = status;
230*8020Slinton 	    p->next = pidlist;
231*8020Slinton 	    pidlist = p;
232*8020Slinton 	}
233*8020Slinton 	if (pnum < 0) {
234*8020Slinton 	    p = pfind(pid);
235*8020Slinton 	    if (p == nil(Pidlist *)) {
236*8020Slinton 		panic("pwait: pid %d not found", pid);
237*8020Slinton 	    }
238*8020Slinton 	    *statusp = p->status;
239*8020Slinton 	    dispose(p);
240*8020Slinton 	} else {
241*8020Slinton 		*statusp = status;
242*8020Slinton 	}
243*8020Slinton }
244*8020Slinton 
245*8020Slinton /*
246*8020Slinton  * Look for the given process id on the pidlist.
247*8020Slinton  *
248*8020Slinton  * Unlink it from list if found.
249*8020Slinton  */
250*8020Slinton 
251*8020Slinton private Pidlist *pfind(pid)
252*8020Slinton int pid;
253*8020Slinton {
254*8020Slinton     register Pidlist *p, *prev;
255*8020Slinton 
256*8020Slinton     prev = nil(Pidlist *);
257*8020Slinton     for (p = pidlist; p != nil(Pidlist *); p = p->next) {
258*8020Slinton 	if (p->pid == pid) {
259*8020Slinton 	    break;
260*8020Slinton 	}
261*8020Slinton 	prev = p;
262*8020Slinton     }
263*8020Slinton     if (p != nil(Pidlist *)) {
264*8020Slinton 	if (prev == nil(Pidlist *)) {
265*8020Slinton 		pidlist = p->next;
266*8020Slinton 	} else {
267*8020Slinton 		prev->next = p->next;
268*8020Slinton 	}
269*8020Slinton     }
270*8020Slinton     return p;
271*8020Slinton }
272*8020Slinton 
273*8020Slinton /*
274*8020Slinton  * System call error handler.
275*8020Slinton  *
276*8020Slinton  * The syserr routine is called when a system call is about to
277*8020Slinton  * set the c-bit to report an error.  Certain errors are caught
278*8020Slinton  * and cause the process to print a message and immediately exit.
279*8020Slinton  */
280*8020Slinton 
281*8020Slinton extern int sys_nerr;
282*8020Slinton extern char *sys_errlist[];
283*8020Slinton 
284*8020Slinton /*
285*8020Slinton  * Before calling syserr, the integer errno is set to contain the
286*8020Slinton  * number of the error.  The routine "_mycerror" is a dummy which
287*8020Slinton  * is used to force the loader to get my version of cerror rather
288*8020Slinton  * than the usual one.
289*8020Slinton  */
290*8020Slinton 
291*8020Slinton extern int errno;
292*8020Slinton extern _mycerror();
293*8020Slinton 
294*8020Slinton /*
295*8020Slinton  * default error handling
296*8020Slinton  */
297*8020Slinton 
298*8020Slinton private ERRINFO errinfo[] ={
299*8020Slinton /* no error */	ERR_IGNORE,
300*8020Slinton /* EPERM */	ERR_IGNORE,
301*8020Slinton /* ENOENT */	ERR_IGNORE,
302*8020Slinton /* ESRCH */	ERR_IGNORE,
303*8020Slinton /* EINTR */	ERR_CATCH,
304*8020Slinton /* EIO */	ERR_CATCH,
305*8020Slinton /* ENXIO */	ERR_CATCH,
306*8020Slinton /* E2BIG */	ERR_CATCH,
307*8020Slinton /* ENOEXEC */	ERR_CATCH,
308*8020Slinton /* EBADF */	ERR_IGNORE,
309*8020Slinton /* ECHILD */	ERR_CATCH,
310*8020Slinton /* EAGAIN */	ERR_CATCH,
311*8020Slinton /* ENOMEM */	ERR_CATCH,
312*8020Slinton /* EACCES */	ERR_CATCH,
313*8020Slinton /* EFAULT */	ERR_CATCH,
314*8020Slinton /* ENOTBLK */	ERR_CATCH,
315*8020Slinton /* EBUSY */	ERR_CATCH,
316*8020Slinton /* EEXIST */	ERR_CATCH,
317*8020Slinton /* EXDEV */	ERR_CATCH,
318*8020Slinton /* ENODEV */	ERR_CATCH,
319*8020Slinton /* ENOTDIR */	ERR_CATCH,
320*8020Slinton /* EISDIR */	ERR_CATCH,
321*8020Slinton /* EINVAL */	ERR_CATCH,
322*8020Slinton /* ENFILE */	ERR_CATCH,
323*8020Slinton /* EMFILE */	ERR_CATCH,
324*8020Slinton /* ENOTTY */	ERR_IGNORE,
325*8020Slinton /* ETXTBSY */	ERR_CATCH,
326*8020Slinton /* EFBIG */	ERR_CATCH,
327*8020Slinton /* ENOSPC */	ERR_CATCH,
328*8020Slinton /* ESPIPE */	ERR_CATCH,
329*8020Slinton /* EROFS */	ERR_CATCH,
330*8020Slinton /* EMLINK */	ERR_CATCH,
331*8020Slinton /* EPIPE */	ERR_CATCH,
332*8020Slinton /* EDOM */	ERR_CATCH,
333*8020Slinton /* ERANGE */	ERR_CATCH,
334*8020Slinton /* EQUOT */	ERR_CATCH,
335*8020Slinton };
336*8020Slinton 
337*8020Slinton public syserr()
338*8020Slinton {
339*8020Slinton     ERRINFO *e;
340*8020Slinton 
341*8020Slinton     e = &errinfo[errno];
342*8020Slinton     if (e->func == ERR_CATCH) {
343*8020Slinton 	if (errno < sys_nerr) {
344*8020Slinton 	    panic(sys_errlist[errno]);
345*8020Slinton 	} else {
346*8020Slinton 	    panic("errno %d", errno);
347*8020Slinton 	}
348*8020Slinton     } else if (e->func != ERR_IGNORE) {
349*8020Slinton 	(*e->func)();
350*8020Slinton     }
351*8020Slinton }
352*8020Slinton 
353*8020Slinton /*
354*8020Slinton  * Catcherrs only purpose is to get this module loaded and make
355*8020Slinton  * sure my cerror is loaded (only applicable when this is in a library).
356*8020Slinton  */
357*8020Slinton 
358*8020Slinton public catcherrs()
359*8020Slinton {
360*8020Slinton     _mycerror();
361*8020Slinton }
362*8020Slinton 
363*8020Slinton /*
364*8020Slinton  * Change the action on receipt of an error.
365*8020Slinton  */
366*8020Slinton 
367*8020Slinton public onsyserr(n, f)
368*8020Slinton int n;
369*8020Slinton INTFUNC *f;
370*8020Slinton {
371*8020Slinton     errinfo[n].func = f;
372*8020Slinton }
373*8020Slinton 
374*8020Slinton /*
375*8020Slinton  * Standard error handling routines.
376*8020Slinton  */
377*8020Slinton 
378*8020Slinton private short nerrs;
379*8020Slinton private short nwarnings;
380*8020Slinton 
381*8020Slinton /*
382*8020Slinton  * Main driver of error message reporting.
383*8020Slinton  */
384*8020Slinton 
385*8020Slinton /* VARARGS2 */
386*8020Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
387*8020Slinton String errname;
388*8020Slinton Boolean shouldquit;
389*8020Slinton String s;
390*8020Slinton {
391*8020Slinton     fflush(stdout);
392*8020Slinton     if (shouldquit and cmdname != nil(String)) {
393*8020Slinton 	fprintf(stderr, "%s: ", cmdname);
394*8020Slinton     }
395*8020Slinton     if (errfilename != nil(Filename)) {
396*8020Slinton 	fprintf(stderr, "%s: ", errfilename);
397*8020Slinton     }
398*8020Slinton     if (errlineno > 0) {
399*8020Slinton 	fprintf(stderr, "%d: ", errlineno);
400*8020Slinton     }
401*8020Slinton     if (errname != nil(String)) {
402*8020Slinton 	fprintf(stderr, "%s: ", errname);
403*8020Slinton     }
404*8020Slinton     fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
405*8020Slinton     putc('\n', stderr);
406*8020Slinton     if (shouldquit) {
407*8020Slinton 	quit(1);
408*8020Slinton     }
409*8020Slinton }
410*8020Slinton 
411*8020Slinton /*
412*8020Slinton  * The messages are listed in increasing order of seriousness.
413*8020Slinton  *
414*8020Slinton  * First are warnings.
415*8020Slinton  */
416*8020Slinton 
417*8020Slinton /* VARARGS1 */
418*8020Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
419*8020Slinton String s;
420*8020Slinton {
421*8020Slinton     nwarnings++;
422*8020Slinton     errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
423*8020Slinton }
424*8020Slinton 
425*8020Slinton /*
426*8020Slinton  * Errors are a little worse, they mean something is wrong,
427*8020Slinton  * but not so bad that processing can't continue.
428*8020Slinton  *
429*8020Slinton  * The routine "erecover" is called to recover from the error,
430*8020Slinton  * a default routine is provided that does nothing.
431*8020Slinton  */
432*8020Slinton 
433*8020Slinton /* VARARGS1 */
434*8020Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
435*8020Slinton String s;
436*8020Slinton {
437*8020Slinton     extern erecover();
438*8020Slinton 
439*8020Slinton     nerrs++;
440*8020Slinton     errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
441*8020Slinton     erecover();
442*8020Slinton }
443*8020Slinton 
444*8020Slinton /*
445*8020Slinton  * Non-recoverable user error.
446*8020Slinton  */
447*8020Slinton 
448*8020Slinton /* VARARGS1 */
449*8020Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
450*8020Slinton String s;
451*8020Slinton {
452*8020Slinton     errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
453*8020Slinton }
454*8020Slinton 
455*8020Slinton /*
456*8020Slinton  * Panics indicate an internal program error.
457*8020Slinton  */
458*8020Slinton 
459*8020Slinton /* VARARGS1 */
460*8020Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
461*8020Slinton String s;
462*8020Slinton {
463*8020Slinton     errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
464*8020Slinton }
465*8020Slinton 
466*8020Slinton short numerrors()
467*8020Slinton {
468*8020Slinton     short r;
469*8020Slinton 
470*8020Slinton     r = nerrs;
471*8020Slinton     nerrs = 0;
472*8020Slinton     return r;
473*8020Slinton }
474*8020Slinton 
475*8020Slinton short numwarnings()
476*8020Slinton {
477*8020Slinton     short r;
478*8020Slinton 
479*8020Slinton     r = nwarnings;
480*8020Slinton     nwarnings = 0;
481*8020Slinton     return r;
482*8020Slinton }
483*8020Slinton 
484*8020Slinton /*
485*8020Slinton  * Recover from an error.
486*8020Slinton  *
487*8020Slinton  * This is the default routine which we aren't using since we have our own.
488*8020Slinton  *
489*8020Slinton public erecover()
490*8020Slinton {
491*8020Slinton }
492*8020Slinton  *
493*8020Slinton  */
494*8020Slinton 
495*8020Slinton /*
496*8020Slinton  * Default way to quit from a program is just to exit.
497*8020Slinton  *
498*8020Slinton public quit(r)
499*8020Slinton int r;
500*8020Slinton {
501*8020Slinton     exit(r);
502*8020Slinton }
503*8020Slinton  *
504*8020Slinton  */
505*8020Slinton 
506*8020Slinton /*
507*8020Slinton  * Compare n-byte areas pointed to by s1 and s2
508*8020Slinton  * if n is 0 then compare up until one has a null byte.
509*8020Slinton  */
510*8020Slinton 
511*8020Slinton public int cmp(s1, s2, n)
512*8020Slinton register char *s1, *s2;
513*8020Slinton register unsigned int n;
514*8020Slinton {
515*8020Slinton     if (s1 == nil(char *) || s2 == nil(char *)) {
516*8020Slinton 	panic("cmp: nil pointer");
517*8020Slinton     }
518*8020Slinton     if (n == 0) {
519*8020Slinton 	while (*s1 == *s2++) {
520*8020Slinton 	    if (*s1++ == '\0') {
521*8020Slinton 		return(0);
522*8020Slinton 	    }
523*8020Slinton 	}
524*8020Slinton 	return(*s1 - *(s2-1));
525*8020Slinton     } else {
526*8020Slinton 	for (; n != 0; n--) {
527*8020Slinton 	    if (*s1++ != *s2++) {
528*8020Slinton 		return(*(s1-1) - *(s2-1));
529*8020Slinton 	    }
530*8020Slinton 	}
531*8020Slinton 	return(0);
532*8020Slinton     }
533*8020Slinton }
534*8020Slinton 
535*8020Slinton /*
536*8020Slinton  * Move n bytes from src to dest.
537*8020Slinton  * If n is 0 move until a null is found.
538*8020Slinton  */
539*8020Slinton 
540*8020Slinton public mov(src, dest, n)
541*8020Slinton register char *src, *dest;
542*8020Slinton register unsigned int n;
543*8020Slinton {
544*8020Slinton     if (src == nil(char *))
545*8020Slinton 	panic("mov: nil source");
546*8020Slinton     if (dest == nil(char *))
547*8020Slinton 	panic("mov: nil destination");
548*8020Slinton     if (n > 0) {
549*8020Slinton 	for (; n != 0; n--) {
550*8020Slinton 	    *dest++ = *src++;
551*8020Slinton 	}
552*8020Slinton     } else {
553*8020Slinton 	while ((*dest++ = *src++) != '\0');
554*8020Slinton     }
555*8020Slinton }
556