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