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