xref: /csrg-svn/usr.bin/pascal/pdx/library.c (revision 67254)
148104Sbostic /*-
262131Sbostic  * Copyright (c) 1982, 1993
362131Sbostic  *	The Regents of the University of California.  All rights reserved.
448104Sbostic  *
548104Sbostic  * %sccs.include.redist.c%
622759Smckusick  */
78020Slinton 
822759Smckusick #ifndef lint
9*67254Smckusick static char sccsid[] = "@(#)library.c	8.2 (Berkeley) 05/27/94";
1048104Sbostic #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 */
call(name,in,out,args)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 
callv(name,in,out,argv)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 
backv(name,in,out,argv)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 
fswap(oldfd,newfd)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 
shell(s)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 
pwait(pid,statusp)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 
pfind(pid)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 
2388020Slinton /*
2398020Slinton  * Before calling syserr, the integer errno is set to contain the
24030842Smckusick  * 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 
syserr()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 
onsyserr(n,f)30830842Smckusick public INTFUNC *onsyserr(n, f)
3098020Slinton int n;
3108020Slinton INTFUNC *f;
3118020Slinton {
31230842Smckusick     INTFUNC *g = errinfo[n].func;
31330842Smckusick 
3148020Slinton     errinfo[n].func = f;
31530842Smckusick     return(g);
3168020Slinton }
3178020Slinton 
3188020Slinton /*
3198020Slinton  * Main driver of error message reporting.
3208020Slinton  */
3218020Slinton 
3228020Slinton /* VARARGS2 */
errmsg(errname,shouldquit,s,a,b,c,d,e,f,g,h,i,j,k,l,m)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 */
error(s,a,b,c,d,e,f,g,h,i,j,k,l,m)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 */
fatal(s,a,b,c,d,e,f,g,h,i,j,k,l,m)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 */
panic(s,a,b,c,d,e,f,g,h,i,j,k,l,m)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 
cmp(s1,s2,n)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 
mov(src,dest,n)4228020Slinton public mov(src, dest, n)
4238020Slinton register char *src, *dest;
42430842Smckusick register int n;
4258020Slinton {
42630842Smckusick     if (src == nil(char *)) {
4278020Slinton 	panic("mov: nil source");
42830842Smckusick     }
42930842Smckusick     if (dest == nil(char *)) {
4308020Slinton 	panic("mov: nil destination");
43130842Smckusick     }
4328020Slinton     if (n > 0) {
4338020Slinton 	for (; n != 0; n--) {
4348020Slinton 	    *dest++ = *src++;
4358020Slinton 	}
4368020Slinton     } else {
4378020Slinton 	while ((*dest++ = *src++) != '\0');
4388020Slinton     }
4398020Slinton }
440