xref: /csrg-svn/usr.bin/pascal/pdx/library.c (revision 30842)
122759Smckusick /*
222759Smckusick  * Copyright (c) 1982 Regents of the University of California.
322759Smckusick  * All rights reserved.  The Berkeley software License Agreement
422759Smckusick  * specifies the terms and conditions for redistribution.
522759Smckusick  */
68020Slinton 
722759Smckusick #ifndef lint
8*30842Smckusick static char sccsid[] = "@(#)library.c	5.2 (Berkeley) 04/07/87";
922759Smckusick #endif not lint
108020Slinton 
118020Slinton /*
128020Slinton  * General purpose routines.
138020Slinton  */
148020Slinton 
158020Slinton #include <stdio.h>
168020Slinton #include <errno.h>
17*30842Smckusick #include "defs.h"
188020Slinton 
198020Slinton #define public
208020Slinton #define private static
218020Slinton #define and &&
228020Slinton #define nil(type)	((type) 0)
238020Slinton 
248020Slinton typedef char *String;
258020Slinton typedef FILE *File;
268020Slinton typedef String Filename;
27*30842Smckusick typedef char Boolean;
288020Slinton 
298020Slinton #undef FILE
308020Slinton 
318020Slinton String cmdname;			/* name of command for error messages */
328020Slinton Filename errfilename;		/* current file associated with error */
338020Slinton short errlineno;		/* line number associated with error */
348020Slinton 
358020Slinton typedef int INTFUNC();
368020Slinton 
378020Slinton typedef struct {
388020Slinton     INTFUNC *func;
398020Slinton } ERRINFO;
408020Slinton 
418020Slinton #define ERR_IGNORE ((INTFUNC *) 0)
428020Slinton #define ERR_CATCH  ((INTFUNC *) 1)
438020Slinton 
44*30842Smckusick public INTFUNC *onsyserr();
45*30842Smckusick 
468020Slinton /*
478020Slinton  * Call a program.
488020Slinton  *
49*30842Smckusick  * Three entries:
508020Slinton  *
518020Slinton  *	call, callv - call a program and wait for it, returning status
52*30842Smckusick  *	backv - call a program and don't wait, returning process id
538020Slinton  *
548020Slinton  * The command's standard input and output are passed as FILE's.
558020Slinton  */
568020Slinton 
578020Slinton 
588020Slinton #define MAXNARGS 100    /* unchecked upper limit on max num of arguments */
598020Slinton #define BADEXEC 127	/* exec fails */
608020Slinton 
618020Slinton #define ischild(pid)    ((pid) == 0)
628020Slinton 
638020Slinton /* VARARGS3 */
648020Slinton public int call(name, in, out, args)
658020Slinton String name;
668020Slinton File in;
678020Slinton File out;
688020Slinton String args;
698020Slinton {
708020Slinton     String *ap, *argp;
718020Slinton     String argv[MAXNARGS];
728020Slinton 
738020Slinton     argp = &argv[0];
748020Slinton     *argp++ = name;
758020Slinton     ap = &args;
768020Slinton     while (*ap != nil(String)) {
778020Slinton 	*argp++ = *ap++;
788020Slinton     }
798020Slinton     *argp = nil(String);
808020Slinton     return callv(name, in, out, argv);
818020Slinton }
828020Slinton 
838020Slinton public int callv(name, in, out, argv)
848020Slinton String name;
858020Slinton File in;
868020Slinton File out;
878020Slinton String *argv;
888020Slinton {
898020Slinton     int pid, status;
908020Slinton 
918020Slinton     pid = backv(name, in, out, argv);
928020Slinton     pwait(pid, &status);
938020Slinton     return status;
948020Slinton }
958020Slinton 
968020Slinton public int backv(name, in, out, argv)
978020Slinton String name;
988020Slinton File in;
998020Slinton File out;
1008020Slinton String *argv;
1018020Slinton {
1028020Slinton     int pid;
1038020Slinton 
1048020Slinton     fflush(stdout);
1058020Slinton     if (ischild(pid = fork())) {
1068020Slinton 	fswap(0, fileno(in));
1078020Slinton 	fswap(1, fileno(out));
108*30842Smckusick 	(void) onsyserr(EACCES, ERR_IGNORE);
1098020Slinton 	execvp(name, argv);
1108020Slinton 	_exit(BADEXEC);
1118020Slinton     }
1128020Slinton     return pid;
1138020Slinton }
1148020Slinton 
1158020Slinton /*
1168020Slinton  * Swap file numbers so as to redirect standard input and output.
1178020Slinton  */
1188020Slinton 
1198020Slinton private fswap(oldfd, newfd)
1208020Slinton int oldfd;
1218020Slinton int newfd;
1228020Slinton {
1238020Slinton     if (oldfd != newfd) {
1248020Slinton 	close(oldfd);
1258020Slinton 	dup(newfd);
1268020Slinton 	close(newfd);
1278020Slinton     }
1288020Slinton }
1298020Slinton 
1308020Slinton /*
1318020Slinton  * Invoke a shell on a command line.
1328020Slinton  */
1338020Slinton 
1348020Slinton #define DEF_SHELL	"csh"
1358020Slinton 
1368020Slinton public shell(s)
1378020Slinton String s;
1388020Slinton {
1398020Slinton     extern String getenv();
1408020Slinton     String sh;
1418020Slinton 
1428020Slinton     if ((sh = getenv("SHELL")) == nil(String)) {
1438020Slinton 	sh = DEF_SHELL;
1448020Slinton     }
1458020Slinton     call(sh, stdin, stdout, "-c", s, 0);
1468020Slinton }
1478020Slinton 
1488020Slinton /*
1498020Slinton  * Wait for a process the right way.  We wait for a particular
1508020Slinton  * process and if any others come along in between, we remember them
1518020Slinton  * in case they are eventually waited for.
1528020Slinton  *
1538020Slinton  * This routine is not very efficient when the number of processes
1548020Slinton  * to be remembered is large.
1558020Slinton  */
1568020Slinton 
1578020Slinton typedef struct pidlist {
1588020Slinton     int pid;
1598020Slinton     int status;
1608020Slinton     struct pidlist *next;
1618020Slinton } Pidlist;
1628020Slinton 
1638020Slinton private Pidlist *pidlist, *pfind();
1648020Slinton 
1658020Slinton public pwait(pid, statusp)
1668020Slinton int pid, *statusp;
1678020Slinton {
1688020Slinton 	Pidlist *p;
1698020Slinton 	int pnum, status;
1708020Slinton 
1718020Slinton 	p = pfind(pid);
1728020Slinton 	if (p != nil(Pidlist *)) {
1738020Slinton 	    *statusp = p->status;
1748020Slinton 	    dispose(p);
1758020Slinton 	    return;
1768020Slinton 	}
1778020Slinton 	while ((pnum = wait(&status)) != pid && pnum >= 0) {
1788020Slinton 	    p = alloc(1, Pidlist);
1798020Slinton 	    p->pid = pnum;
1808020Slinton 	    p->status = status;
1818020Slinton 	    p->next = pidlist;
1828020Slinton 	    pidlist = p;
1838020Slinton 	}
1848020Slinton 	if (pnum < 0) {
1858020Slinton 	    p = pfind(pid);
1868020Slinton 	    if (p == nil(Pidlist *)) {
1878020Slinton 		panic("pwait: pid %d not found", pid);
1888020Slinton 	    }
1898020Slinton 	    *statusp = p->status;
1908020Slinton 	    dispose(p);
1918020Slinton 	} else {
192*30842Smckusick 	    *statusp = status;
1938020Slinton 	}
194*30842Smckusick #ifdef tahoe
195*30842Smckusick 	chkret(p, status);
196*30842Smckusick #endif
1978020Slinton }
1988020Slinton 
1998020Slinton /*
2008020Slinton  * Look for the given process id on the pidlist.
2018020Slinton  *
2028020Slinton  * Unlink it from list if found.
2038020Slinton  */
2048020Slinton 
2058020Slinton private Pidlist *pfind(pid)
2068020Slinton int pid;
2078020Slinton {
2088020Slinton     register Pidlist *p, *prev;
2098020Slinton 
2108020Slinton     prev = nil(Pidlist *);
2118020Slinton     for (p = pidlist; p != nil(Pidlist *); p = p->next) {
2128020Slinton 	if (p->pid == pid) {
2138020Slinton 	    break;
2148020Slinton 	}
2158020Slinton 	prev = p;
2168020Slinton     }
2178020Slinton     if (p != nil(Pidlist *)) {
2188020Slinton 	if (prev == nil(Pidlist *)) {
219*30842Smckusick 	    pidlist = p->next;
2208020Slinton 	} else {
221*30842Smckusick 	    prev->next = p->next;
2228020Slinton 	}
2238020Slinton     }
2248020Slinton     return p;
2258020Slinton }
2268020Slinton 
2278020Slinton /*
2288020Slinton  * System call error handler.
2298020Slinton  *
2308020Slinton  * The syserr routine is called when a system call is about to
2318020Slinton  * set the c-bit to report an error.  Certain errors are caught
2328020Slinton  * and cause the process to print a message and immediately exit.
2338020Slinton  */
2348020Slinton 
2358020Slinton extern int sys_nerr;
2368020Slinton extern char *sys_errlist[];
2378020Slinton 
2388020Slinton /*
2398020Slinton  * Before calling syserr, the integer errno is set to contain the
240*30842Smckusick  * number of the error.
2418020Slinton  */
2428020Slinton 
2438020Slinton extern int errno;
2448020Slinton 
2458020Slinton /*
2468020Slinton  * default error handling
2478020Slinton  */
2488020Slinton 
2498020Slinton private ERRINFO errinfo[] ={
2508020Slinton /* no error */	ERR_IGNORE,
2518020Slinton /* EPERM */	ERR_IGNORE,
2528020Slinton /* ENOENT */	ERR_IGNORE,
2538020Slinton /* ESRCH */	ERR_IGNORE,
2548020Slinton /* EINTR */	ERR_CATCH,
2558020Slinton /* EIO */	ERR_CATCH,
2568020Slinton /* ENXIO */	ERR_CATCH,
2578020Slinton /* E2BIG */	ERR_CATCH,
2588020Slinton /* ENOEXEC */	ERR_CATCH,
2598020Slinton /* EBADF */	ERR_IGNORE,
2608020Slinton /* ECHILD */	ERR_CATCH,
2618020Slinton /* EAGAIN */	ERR_CATCH,
2628020Slinton /* ENOMEM */	ERR_CATCH,
2638020Slinton /* EACCES */	ERR_CATCH,
2648020Slinton /* EFAULT */	ERR_CATCH,
2658020Slinton /* ENOTBLK */	ERR_CATCH,
2668020Slinton /* EBUSY */	ERR_CATCH,
2678020Slinton /* EEXIST */	ERR_CATCH,
2688020Slinton /* EXDEV */	ERR_CATCH,
2698020Slinton /* ENODEV */	ERR_CATCH,
2708020Slinton /* ENOTDIR */	ERR_CATCH,
2718020Slinton /* EISDIR */	ERR_CATCH,
2728020Slinton /* EINVAL */	ERR_CATCH,
2738020Slinton /* ENFILE */	ERR_CATCH,
2748020Slinton /* EMFILE */	ERR_CATCH,
2758020Slinton /* ENOTTY */	ERR_IGNORE,
2768020Slinton /* ETXTBSY */	ERR_CATCH,
2778020Slinton /* EFBIG */	ERR_CATCH,
2788020Slinton /* ENOSPC */	ERR_CATCH,
2798020Slinton /* ESPIPE */	ERR_CATCH,
2808020Slinton /* EROFS */	ERR_CATCH,
2818020Slinton /* EMLINK */	ERR_CATCH,
2828020Slinton /* EPIPE */	ERR_CATCH,
2838020Slinton /* EDOM */	ERR_CATCH,
2848020Slinton /* ERANGE */	ERR_CATCH,
2858020Slinton /* EQUOT */	ERR_CATCH,
2868020Slinton };
2878020Slinton 
2888020Slinton public syserr()
2898020Slinton {
2908020Slinton     ERRINFO *e;
2918020Slinton 
2928020Slinton     e = &errinfo[errno];
2938020Slinton     if (e->func == ERR_CATCH) {
2948020Slinton 	if (errno < sys_nerr) {
2958020Slinton 	    panic(sys_errlist[errno]);
2968020Slinton 	} else {
2978020Slinton 	    panic("errno %d", errno);
2988020Slinton 	}
2998020Slinton     } else if (e->func != ERR_IGNORE) {
3008020Slinton 	(*e->func)();
3018020Slinton     }
3028020Slinton }
3038020Slinton 
3048020Slinton /*
3058020Slinton  * Change the action on receipt of an error.
3068020Slinton  */
3078020Slinton 
308*30842Smckusick public INTFUNC *onsyserr(n, f)
3098020Slinton int n;
3108020Slinton INTFUNC *f;
3118020Slinton {
312*30842Smckusick     INTFUNC *g = errinfo[n].func;
313*30842Smckusick 
3148020Slinton     errinfo[n].func = f;
315*30842Smckusick     return(g);
3168020Slinton }
3178020Slinton 
3188020Slinton /*
3198020Slinton  * Main driver of error message reporting.
3208020Slinton  */
3218020Slinton 
3228020Slinton /* VARARGS2 */
3238020Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
3248020Slinton String errname;
3258020Slinton Boolean shouldquit;
3268020Slinton String s;
3278020Slinton {
3288020Slinton     fflush(stdout);
3298020Slinton     if (shouldquit and cmdname != nil(String)) {
3308020Slinton 	fprintf(stderr, "%s: ", cmdname);
3318020Slinton     }
3328020Slinton     if (errfilename != nil(Filename)) {
3338020Slinton 	fprintf(stderr, "%s: ", errfilename);
3348020Slinton     }
3358020Slinton     if (errlineno > 0) {
3368020Slinton 	fprintf(stderr, "%d: ", errlineno);
3378020Slinton     }
3388020Slinton     if (errname != nil(String)) {
3398020Slinton 	fprintf(stderr, "%s: ", errname);
3408020Slinton     }
3418020Slinton     fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
3428020Slinton     putc('\n', stderr);
3438020Slinton     if (shouldquit) {
3448020Slinton 	quit(1);
3458020Slinton     }
3468020Slinton }
3478020Slinton 
3488020Slinton /*
3498020Slinton  * Errors are a little worse, they mean something is wrong,
3508020Slinton  * but not so bad that processing can't continue.
3518020Slinton  *
3528020Slinton  * The routine "erecover" is called to recover from the error,
3538020Slinton  * a default routine is provided that does nothing.
3548020Slinton  */
3558020Slinton 
3568020Slinton /* VARARGS1 */
3578020Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
3588020Slinton String s;
3598020Slinton {
3608020Slinton     extern erecover();
3618020Slinton 
3628020Slinton     errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
3638020Slinton     erecover();
3648020Slinton }
3658020Slinton 
3668020Slinton /*
3678020Slinton  * Non-recoverable user error.
3688020Slinton  */
3698020Slinton 
3708020Slinton /* VARARGS1 */
3718020Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
3728020Slinton String s;
3738020Slinton {
3748020Slinton     errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
3758020Slinton }
3768020Slinton 
3778020Slinton /*
3788020Slinton  * Panics indicate an internal program error.
3798020Slinton  */
3808020Slinton 
3818020Slinton /* VARARGS1 */
3828020Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
3838020Slinton String s;
3848020Slinton {
3858020Slinton     errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
3868020Slinton }
3878020Slinton 
3888020Slinton /*
3898020Slinton  * Compare n-byte areas pointed to by s1 and s2
3908020Slinton  * if n is 0 then compare up until one has a null byte.
3918020Slinton  */
3928020Slinton 
3938020Slinton public int cmp(s1, s2, n)
3948020Slinton register char *s1, *s2;
3958020Slinton register unsigned int n;
3968020Slinton {
3978020Slinton     if (s1 == nil(char *) || s2 == nil(char *)) {
3988020Slinton 	panic("cmp: nil pointer");
3998020Slinton     }
4008020Slinton     if (n == 0) {
4018020Slinton 	while (*s1 == *s2++) {
4028020Slinton 	    if (*s1++ == '\0') {
4038020Slinton 		return(0);
4048020Slinton 	    }
4058020Slinton 	}
4068020Slinton 	return(*s1 - *(s2-1));
4078020Slinton     } else {
4088020Slinton 	for (; n != 0; n--) {
4098020Slinton 	    if (*s1++ != *s2++) {
4108020Slinton 		return(*(s1-1) - *(s2-1));
4118020Slinton 	    }
4128020Slinton 	}
4138020Slinton 	return(0);
4148020Slinton     }
4158020Slinton }
4168020Slinton 
4178020Slinton /*
4188020Slinton  * Move n bytes from src to dest.
4198020Slinton  * If n is 0 move until a null is found.
4208020Slinton  */
4218020Slinton 
4228020Slinton public mov(src, dest, n)
4238020Slinton register char *src, *dest;
424*30842Smckusick register int n;
4258020Slinton {
426*30842Smckusick     if (src == nil(char *)) {
4278020Slinton 	panic("mov: nil source");
428*30842Smckusick     }
429*30842Smckusick     if (dest == nil(char *)) {
4308020Slinton 	panic("mov: nil destination");
431*30842Smckusick     }
4328020Slinton     if (n > 0) {
4338020Slinton 	for (; n != 0; n--) {
4348020Slinton 	    *dest++ = *src++;
4358020Slinton 	}
4368020Slinton     } else {
4378020Slinton 	while ((*dest++ = *src++) != '\0');
4388020Slinton     }
4398020Slinton }
440