xref: /csrg-svn/usr.bin/pascal/pdx/library.c (revision 22759)
1*22759Smckusick /*
2*22759Smckusick  * Copyright (c) 1982 Regents of the University of California.
3*22759Smckusick  * All rights reserved.  The Berkeley software License Agreement
4*22759Smckusick  * specifies the terms and conditions for redistribution.
5*22759Smckusick  */
68020Slinton 
7*22759Smckusick #ifndef lint
8*22759Smckusick static char sccsid[] = "@(#)library.c	5.1 (Berkeley) 06/07/85";
9*22759Smckusick #endif not lint
108020Slinton 
118020Slinton /*
128020Slinton  * General purpose routines.
138020Slinton  */
148020Slinton 
158020Slinton #include <stdio.h>
168020Slinton #include <errno.h>
178020Slinton 
188020Slinton #define public
198020Slinton #define private static
208020Slinton #define and &&
218020Slinton #define or ||
228020Slinton #define not !
238020Slinton #define ord(enumcon)	((int) enumcon)
248020Slinton #define nil(type)	((type) 0)
258020Slinton 
268020Slinton typedef enum { FALSE, TRUE } Boolean;
278020Slinton typedef char *String;
288020Slinton typedef FILE *File;
298020Slinton typedef String Filename;
308020Slinton 
318020Slinton #undef FILE
328020Slinton 
338020Slinton /*
348020Slinton  * Definitions of standard C library routines that aren't in the
358020Slinton  * standard I/O library, but which are generally useful.
368020Slinton  */
378020Slinton 
388020Slinton extern long atol();		/* ascii to long */
398020Slinton extern double atof();		/* ascii to floating point */
408020Slinton extern char *mktemp();		/* make a temporary file name */
418020Slinton 
428020Slinton String cmdname;			/* name of command for error messages */
438020Slinton Filename errfilename;		/* current file associated with error */
448020Slinton short errlineno;		/* line number associated with error */
458020Slinton 
468020Slinton /*
478020Slinton  * Definitions for doing memory allocation.
488020Slinton  */
498020Slinton 
508020Slinton extern char *malloc();
518020Slinton 
528020Slinton #define alloc(n, type)	((type *) malloc((unsigned) (n) * sizeof(type)))
538020Slinton #define dispose(p)	{ free((char *) p); p = 0; }
548020Slinton 
558020Slinton /*
568020Slinton  * Macros for doing freads + fwrites.
578020Slinton  */
588020Slinton 
598020Slinton #define get(fp, var)	fread((char *) &(var), sizeof(var), 1, fp)
608020Slinton #define put(fp, var)	fwrite((char *) &(var), sizeof(var), 1, fp)
618020Slinton 
628020Slinton /*
638020Slinton  * String definitions.
648020Slinton  */
658020Slinton 
668020Slinton extern String strcpy(), index(), rindex();
678020Slinton extern int strlen();
688020Slinton 
698020Slinton #define strdup(s)		strcpy(malloc((unsigned) strlen(s) + 1), s)
708020Slinton #define streq(s1, s2)	(strcmp(s1, s2) == 0)
718020Slinton 
728020Slinton typedef int INTFUNC();
738020Slinton 
748020Slinton typedef struct {
758020Slinton     INTFUNC *func;
768020Slinton } ERRINFO;
778020Slinton 
788020Slinton #define ERR_IGNORE ((INTFUNC *) 0)
798020Slinton #define ERR_CATCH  ((INTFUNC *) 1)
808020Slinton 
818020Slinton /*
828020Slinton  * Call a program.
838020Slinton  *
848020Slinton  * Four entries:
858020Slinton  *
868020Slinton  *	call, callv - call a program and wait for it, returning status
878020Slinton  *	back, backv - call a program and don't wait, returning process id
888020Slinton  *
898020Slinton  * The command's standard input and output are passed as FILE's.
908020Slinton  */
918020Slinton 
928020Slinton 
938020Slinton #define MAXNARGS 100    /* unchecked upper limit on max num of arguments */
948020Slinton #define BADEXEC 127	/* exec fails */
958020Slinton 
968020Slinton #define ischild(pid)    ((pid) == 0)
978020Slinton 
988020Slinton /* VARARGS3 */
998020Slinton public int call(name, in, out, args)
1008020Slinton String name;
1018020Slinton File in;
1028020Slinton File out;
1038020Slinton String args;
1048020Slinton {
1058020Slinton     String *ap, *argp;
1068020Slinton     String argv[MAXNARGS];
1078020Slinton 
1088020Slinton     argp = &argv[0];
1098020Slinton     *argp++ = name;
1108020Slinton     ap = &args;
1118020Slinton     while (*ap != nil(String)) {
1128020Slinton 	*argp++ = *ap++;
1138020Slinton     }
1148020Slinton     *argp = nil(String);
1158020Slinton     return callv(name, in, out, argv);
1168020Slinton }
1178020Slinton 
1188020Slinton /* VARARGS3 */
1198020Slinton public int back(name, in, out, args)
1208020Slinton String name;
1218020Slinton File in;
1228020Slinton File out;
1238020Slinton String args;
1248020Slinton {
1258020Slinton     String *ap, *argp;
1268020Slinton     String argv[MAXNARGS];
1278020Slinton 
1288020Slinton     argp = &argv[0];
1298020Slinton     *argp++ = name;
1308020Slinton     ap = &args;
1318020Slinton     while (*ap != nil(String)) {
1328020Slinton 	*argp++ = *ap++;
1338020Slinton     }
1348020Slinton     *argp = nil(String);
1358020Slinton     return backv(name, in, out, argv);
1368020Slinton }
1378020Slinton 
1388020Slinton public int callv(name, in, out, argv)
1398020Slinton String name;
1408020Slinton File in;
1418020Slinton File out;
1428020Slinton String *argv;
1438020Slinton {
1448020Slinton     int pid, status;
1458020Slinton 
1468020Slinton     pid = backv(name, in, out, argv);
1478020Slinton     pwait(pid, &status);
1488020Slinton     return status;
1498020Slinton }
1508020Slinton 
1518020Slinton public int backv(name, in, out, argv)
1528020Slinton String name;
1538020Slinton File in;
1548020Slinton File out;
1558020Slinton String *argv;
1568020Slinton {
1578020Slinton     int pid;
1588020Slinton 
1598020Slinton     fflush(stdout);
1608020Slinton     if (ischild(pid = fork())) {
1618020Slinton 	fswap(0, fileno(in));
1628020Slinton 	fswap(1, fileno(out));
1638020Slinton 	onsyserr(EACCES, ERR_IGNORE);
1648020Slinton 	execvp(name, argv);
1658020Slinton 	_exit(BADEXEC);
1668020Slinton     }
1678020Slinton     return pid;
1688020Slinton }
1698020Slinton 
1708020Slinton /*
1718020Slinton  * Swap file numbers so as to redirect standard input and output.
1728020Slinton  */
1738020Slinton 
1748020Slinton private fswap(oldfd, newfd)
1758020Slinton int oldfd;
1768020Slinton int newfd;
1778020Slinton {
1788020Slinton     if (oldfd != newfd) {
1798020Slinton 	close(oldfd);
1808020Slinton 	dup(newfd);
1818020Slinton 	close(newfd);
1828020Slinton     }
1838020Slinton }
1848020Slinton 
1858020Slinton /*
1868020Slinton  * Invoke a shell on a command line.
1878020Slinton  */
1888020Slinton 
1898020Slinton #define DEF_SHELL	"csh"
1908020Slinton 
1918020Slinton public shell(s)
1928020Slinton String s;
1938020Slinton {
1948020Slinton     extern String getenv();
1958020Slinton     String sh;
1968020Slinton 
1978020Slinton     if ((sh = getenv("SHELL")) == nil(String)) {
1988020Slinton 	sh = DEF_SHELL;
1998020Slinton     }
2008020Slinton     call(sh, stdin, stdout, "-c", s, 0);
2018020Slinton }
2028020Slinton 
2038020Slinton /*
2048020Slinton  * Wait for a process the right way.  We wait for a particular
2058020Slinton  * process and if any others come along in between, we remember them
2068020Slinton  * in case they are eventually waited for.
2078020Slinton  *
2088020Slinton  * This routine is not very efficient when the number of processes
2098020Slinton  * to be remembered is large.
2108020Slinton  */
2118020Slinton 
2128020Slinton typedef struct pidlist {
2138020Slinton     int pid;
2148020Slinton     int status;
2158020Slinton     struct pidlist *next;
2168020Slinton } Pidlist;
2178020Slinton 
2188020Slinton private Pidlist *pidlist, *pfind();
2198020Slinton 
2208020Slinton public pwait(pid, statusp)
2218020Slinton int pid, *statusp;
2228020Slinton {
2238020Slinton 	Pidlist *p;
2248020Slinton 	int pnum, status;
2258020Slinton 
2268020Slinton 	p = pfind(pid);
2278020Slinton 	if (p != nil(Pidlist *)) {
2288020Slinton 	    *statusp = p->status;
2298020Slinton 	    dispose(p);
2308020Slinton 	    return;
2318020Slinton 	}
2328020Slinton 	while ((pnum = wait(&status)) != pid && pnum >= 0) {
2338020Slinton 	    p = alloc(1, Pidlist);
2348020Slinton 	    p->pid = pnum;
2358020Slinton 	    p->status = status;
2368020Slinton 	    p->next = pidlist;
2378020Slinton 	    pidlist = p;
2388020Slinton 	}
2398020Slinton 	if (pnum < 0) {
2408020Slinton 	    p = pfind(pid);
2418020Slinton 	    if (p == nil(Pidlist *)) {
2428020Slinton 		panic("pwait: pid %d not found", pid);
2438020Slinton 	    }
2448020Slinton 	    *statusp = p->status;
2458020Slinton 	    dispose(p);
2468020Slinton 	} else {
2478020Slinton 		*statusp = status;
2488020Slinton 	}
2498020Slinton }
2508020Slinton 
2518020Slinton /*
2528020Slinton  * Look for the given process id on the pidlist.
2538020Slinton  *
2548020Slinton  * Unlink it from list if found.
2558020Slinton  */
2568020Slinton 
2578020Slinton private Pidlist *pfind(pid)
2588020Slinton int pid;
2598020Slinton {
2608020Slinton     register Pidlist *p, *prev;
2618020Slinton 
2628020Slinton     prev = nil(Pidlist *);
2638020Slinton     for (p = pidlist; p != nil(Pidlist *); p = p->next) {
2648020Slinton 	if (p->pid == pid) {
2658020Slinton 	    break;
2668020Slinton 	}
2678020Slinton 	prev = p;
2688020Slinton     }
2698020Slinton     if (p != nil(Pidlist *)) {
2708020Slinton 	if (prev == nil(Pidlist *)) {
2718020Slinton 		pidlist = p->next;
2728020Slinton 	} else {
2738020Slinton 		prev->next = p->next;
2748020Slinton 	}
2758020Slinton     }
2768020Slinton     return p;
2778020Slinton }
2788020Slinton 
2798020Slinton /*
2808020Slinton  * System call error handler.
2818020Slinton  *
2828020Slinton  * The syserr routine is called when a system call is about to
2838020Slinton  * set the c-bit to report an error.  Certain errors are caught
2848020Slinton  * and cause the process to print a message and immediately exit.
2858020Slinton  */
2868020Slinton 
2878020Slinton extern int sys_nerr;
2888020Slinton extern char *sys_errlist[];
2898020Slinton 
2908020Slinton /*
2918020Slinton  * Before calling syserr, the integer errno is set to contain the
2928020Slinton  * number of the error.  The routine "_mycerror" is a dummy which
2938020Slinton  * is used to force the loader to get my version of cerror rather
2948020Slinton  * than the usual one.
2958020Slinton  */
2968020Slinton 
2978020Slinton extern int errno;
2988020Slinton extern _mycerror();
2998020Slinton 
3008020Slinton /*
3018020Slinton  * default error handling
3028020Slinton  */
3038020Slinton 
3048020Slinton private ERRINFO errinfo[] ={
3058020Slinton /* no error */	ERR_IGNORE,
3068020Slinton /* EPERM */	ERR_IGNORE,
3078020Slinton /* ENOENT */	ERR_IGNORE,
3088020Slinton /* ESRCH */	ERR_IGNORE,
3098020Slinton /* EINTR */	ERR_CATCH,
3108020Slinton /* EIO */	ERR_CATCH,
3118020Slinton /* ENXIO */	ERR_CATCH,
3128020Slinton /* E2BIG */	ERR_CATCH,
3138020Slinton /* ENOEXEC */	ERR_CATCH,
3148020Slinton /* EBADF */	ERR_IGNORE,
3158020Slinton /* ECHILD */	ERR_CATCH,
3168020Slinton /* EAGAIN */	ERR_CATCH,
3178020Slinton /* ENOMEM */	ERR_CATCH,
3188020Slinton /* EACCES */	ERR_CATCH,
3198020Slinton /* EFAULT */	ERR_CATCH,
3208020Slinton /* ENOTBLK */	ERR_CATCH,
3218020Slinton /* EBUSY */	ERR_CATCH,
3228020Slinton /* EEXIST */	ERR_CATCH,
3238020Slinton /* EXDEV */	ERR_CATCH,
3248020Slinton /* ENODEV */	ERR_CATCH,
3258020Slinton /* ENOTDIR */	ERR_CATCH,
3268020Slinton /* EISDIR */	ERR_CATCH,
3278020Slinton /* EINVAL */	ERR_CATCH,
3288020Slinton /* ENFILE */	ERR_CATCH,
3298020Slinton /* EMFILE */	ERR_CATCH,
3308020Slinton /* ENOTTY */	ERR_IGNORE,
3318020Slinton /* ETXTBSY */	ERR_CATCH,
3328020Slinton /* EFBIG */	ERR_CATCH,
3338020Slinton /* ENOSPC */	ERR_CATCH,
3348020Slinton /* ESPIPE */	ERR_CATCH,
3358020Slinton /* EROFS */	ERR_CATCH,
3368020Slinton /* EMLINK */	ERR_CATCH,
3378020Slinton /* EPIPE */	ERR_CATCH,
3388020Slinton /* EDOM */	ERR_CATCH,
3398020Slinton /* ERANGE */	ERR_CATCH,
3408020Slinton /* EQUOT */	ERR_CATCH,
3418020Slinton };
3428020Slinton 
3438020Slinton public syserr()
3448020Slinton {
3458020Slinton     ERRINFO *e;
3468020Slinton 
3478020Slinton     e = &errinfo[errno];
3488020Slinton     if (e->func == ERR_CATCH) {
3498020Slinton 	if (errno < sys_nerr) {
3508020Slinton 	    panic(sys_errlist[errno]);
3518020Slinton 	} else {
3528020Slinton 	    panic("errno %d", errno);
3538020Slinton 	}
3548020Slinton     } else if (e->func != ERR_IGNORE) {
3558020Slinton 	(*e->func)();
3568020Slinton     }
3578020Slinton }
3588020Slinton 
3598020Slinton /*
3608020Slinton  * Catcherrs only purpose is to get this module loaded and make
3618020Slinton  * sure my cerror is loaded (only applicable when this is in a library).
3628020Slinton  */
3638020Slinton 
3648020Slinton public catcherrs()
3658020Slinton {
3668020Slinton     _mycerror();
3678020Slinton }
3688020Slinton 
3698020Slinton /*
3708020Slinton  * Change the action on receipt of an error.
3718020Slinton  */
3728020Slinton 
3738020Slinton public onsyserr(n, f)
3748020Slinton int n;
3758020Slinton INTFUNC *f;
3768020Slinton {
3778020Slinton     errinfo[n].func = f;
3788020Slinton }
3798020Slinton 
3808020Slinton /*
3818020Slinton  * Standard error handling routines.
3828020Slinton  */
3838020Slinton 
3848020Slinton private short nerrs;
3858020Slinton private short nwarnings;
3868020Slinton 
3878020Slinton /*
3888020Slinton  * Main driver of error message reporting.
3898020Slinton  */
3908020Slinton 
3918020Slinton /* VARARGS2 */
3928020Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
3938020Slinton String errname;
3948020Slinton Boolean shouldquit;
3958020Slinton String s;
3968020Slinton {
3978020Slinton     fflush(stdout);
3988020Slinton     if (shouldquit and cmdname != nil(String)) {
3998020Slinton 	fprintf(stderr, "%s: ", cmdname);
4008020Slinton     }
4018020Slinton     if (errfilename != nil(Filename)) {
4028020Slinton 	fprintf(stderr, "%s: ", errfilename);
4038020Slinton     }
4048020Slinton     if (errlineno > 0) {
4058020Slinton 	fprintf(stderr, "%d: ", errlineno);
4068020Slinton     }
4078020Slinton     if (errname != nil(String)) {
4088020Slinton 	fprintf(stderr, "%s: ", errname);
4098020Slinton     }
4108020Slinton     fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
4118020Slinton     putc('\n', stderr);
4128020Slinton     if (shouldquit) {
4138020Slinton 	quit(1);
4148020Slinton     }
4158020Slinton }
4168020Slinton 
4178020Slinton /*
4188020Slinton  * The messages are listed in increasing order of seriousness.
4198020Slinton  *
4208020Slinton  * First are warnings.
4218020Slinton  */
4228020Slinton 
4238020Slinton /* VARARGS1 */
4248020Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
4258020Slinton String s;
4268020Slinton {
4278020Slinton     nwarnings++;
4288020Slinton     errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
4298020Slinton }
4308020Slinton 
4318020Slinton /*
4328020Slinton  * Errors are a little worse, they mean something is wrong,
4338020Slinton  * but not so bad that processing can't continue.
4348020Slinton  *
4358020Slinton  * The routine "erecover" is called to recover from the error,
4368020Slinton  * a default routine is provided that does nothing.
4378020Slinton  */
4388020Slinton 
4398020Slinton /* VARARGS1 */
4408020Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
4418020Slinton String s;
4428020Slinton {
4438020Slinton     extern erecover();
4448020Slinton 
4458020Slinton     nerrs++;
4468020Slinton     errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
4478020Slinton     erecover();
4488020Slinton }
4498020Slinton 
4508020Slinton /*
4518020Slinton  * Non-recoverable user error.
4528020Slinton  */
4538020Slinton 
4548020Slinton /* VARARGS1 */
4558020Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
4568020Slinton String s;
4578020Slinton {
4588020Slinton     errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
4598020Slinton }
4608020Slinton 
4618020Slinton /*
4628020Slinton  * Panics indicate an internal program error.
4638020Slinton  */
4648020Slinton 
4658020Slinton /* VARARGS1 */
4668020Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
4678020Slinton String s;
4688020Slinton {
4698020Slinton     errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
4708020Slinton }
4718020Slinton 
4728020Slinton short numerrors()
4738020Slinton {
4748020Slinton     short r;
4758020Slinton 
4768020Slinton     r = nerrs;
4778020Slinton     nerrs = 0;
4788020Slinton     return r;
4798020Slinton }
4808020Slinton 
4818020Slinton short numwarnings()
4828020Slinton {
4838020Slinton     short r;
4848020Slinton 
4858020Slinton     r = nwarnings;
4868020Slinton     nwarnings = 0;
4878020Slinton     return r;
4888020Slinton }
4898020Slinton 
4908020Slinton /*
4918020Slinton  * Recover from an error.
4928020Slinton  *
4938020Slinton  * This is the default routine which we aren't using since we have our own.
4948020Slinton  *
4958020Slinton public erecover()
4968020Slinton {
4978020Slinton }
4988020Slinton  *
4998020Slinton  */
5008020Slinton 
5018020Slinton /*
5028020Slinton  * Default way to quit from a program is just to exit.
5038020Slinton  *
5048020Slinton public quit(r)
5058020Slinton int r;
5068020Slinton {
5078020Slinton     exit(r);
5088020Slinton }
5098020Slinton  *
5108020Slinton  */
5118020Slinton 
5128020Slinton /*
5138020Slinton  * Compare n-byte areas pointed to by s1 and s2
5148020Slinton  * if n is 0 then compare up until one has a null byte.
5158020Slinton  */
5168020Slinton 
5178020Slinton public int cmp(s1, s2, n)
5188020Slinton register char *s1, *s2;
5198020Slinton register unsigned int n;
5208020Slinton {
5218020Slinton     if (s1 == nil(char *) || s2 == nil(char *)) {
5228020Slinton 	panic("cmp: nil pointer");
5238020Slinton     }
5248020Slinton     if (n == 0) {
5258020Slinton 	while (*s1 == *s2++) {
5268020Slinton 	    if (*s1++ == '\0') {
5278020Slinton 		return(0);
5288020Slinton 	    }
5298020Slinton 	}
5308020Slinton 	return(*s1 - *(s2-1));
5318020Slinton     } else {
5328020Slinton 	for (; n != 0; n--) {
5338020Slinton 	    if (*s1++ != *s2++) {
5348020Slinton 		return(*(s1-1) - *(s2-1));
5358020Slinton 	    }
5368020Slinton 	}
5378020Slinton 	return(0);
5388020Slinton     }
5398020Slinton }
5408020Slinton 
5418020Slinton /*
5428020Slinton  * Move n bytes from src to dest.
5438020Slinton  * If n is 0 move until a null is found.
5448020Slinton  */
5458020Slinton 
5468020Slinton public mov(src, dest, n)
5478020Slinton register char *src, *dest;
5488020Slinton register unsigned int n;
5498020Slinton {
5508020Slinton     if (src == nil(char *))
5518020Slinton 	panic("mov: nil source");
5528020Slinton     if (dest == nil(char *))
5538020Slinton 	panic("mov: nil destination");
5548020Slinton     if (n > 0) {
5558020Slinton 	for (; n != 0; n--) {
5568020Slinton 	    *dest++ = *src++;
5578020Slinton 	}
5588020Slinton     } else {
5598020Slinton 	while ((*dest++ = *src++) != '\0');
5608020Slinton     }
5618020Slinton }
562