xref: /csrg-svn/old/dbx/library.c (revision 16611)
19666Slinton /* Copyright (c) 1982 Regents of the University of California */
29666Slinton 
3*16611Ssam static char sccsid[] = "@(#)library.c 1.3 8/7/83";
4*16611Ssam 
5*16611Ssam static char rcsid[] = "$Header: library.c,v 1.3 84/03/27 10:21:12 linton Exp $";
6*16611Ssam 
79666Slinton /*
89666Slinton  * General purpose routines.
99666Slinton  */
109666Slinton 
119666Slinton #include <stdio.h>
129666Slinton #include <errno.h>
139666Slinton #include <signal.h>
149666Slinton 
159666Slinton #define public
169666Slinton #define private static
179666Slinton #define and &&
189666Slinton #define or ||
199666Slinton #define not !
209666Slinton #define ord(enumcon)	((int) enumcon)
219666Slinton #define nil(type)	((type) 0)
229666Slinton 
23*16611Ssam typedef int integer;
24*16611Ssam typedef enum { FALSE, TRUE } boolean;
259666Slinton typedef char *String;
269666Slinton typedef FILE *File;
279666Slinton typedef String Filename;
289666Slinton 
299666Slinton #undef FILE
309666Slinton 
319666Slinton String cmdname;			/* name of command for error messages */
329666Slinton Filename errfilename;		/* current file associated with error */
339666Slinton short errlineno;		/* line number associated with error */
349666Slinton 
359666Slinton /*
369666Slinton  * Definitions for doing memory allocation.
379666Slinton  */
389666Slinton 
399666Slinton extern char *malloc();
409666Slinton 
419666Slinton #define alloc(n, type)	((type *) malloc((unsigned) (n) * sizeof(type)))
429666Slinton #define dispose(p)	{ free((char *) p); p = 0; }
439666Slinton 
449666Slinton /*
459666Slinton  * Macros for doing freads + fwrites.
469666Slinton  */
479666Slinton 
489666Slinton #define get(fp, var)	fread((char *) &(var), sizeof(var), 1, fp)
499666Slinton #define put(fp, var)	fwrite((char *) &(var), sizeof(var), 1, fp)
509666Slinton 
519666Slinton /*
529666Slinton  * String definitions.
539666Slinton  */
549666Slinton 
559666Slinton extern String strcpy(), index(), rindex();
569666Slinton extern int strlen();
579666Slinton 
589666Slinton #define strdup(s)		strcpy(malloc((unsigned) strlen(s) + 1), s)
599666Slinton #define streq(s1, s2)	(strcmp(s1, s2) == 0)
609666Slinton 
619666Slinton typedef int INTFUNC();
629666Slinton 
639666Slinton typedef struct {
649666Slinton     INTFUNC *func;
659666Slinton } ERRINFO;
669666Slinton 
679666Slinton #define ERR_IGNORE ((INTFUNC *) 0)
689666Slinton #define ERR_CATCH  ((INTFUNC *) 1)
699666Slinton 
709666Slinton /*
719666Slinton  * Call a program.
729666Slinton  *
739666Slinton  * Four entries:
749666Slinton  *
759666Slinton  *	call, callv - call a program and wait for it, returning status
769666Slinton  *	back, backv - call a program and don't wait, returning process id
779666Slinton  *
789666Slinton  * The command's standard input and output are passed as FILE's.
799666Slinton  */
809666Slinton 
819666Slinton 
82*16611Ssam #define MAXNARGS 1000    /* unchecked upper limit on max num of arguments */
839666Slinton #define BADEXEC 127	/* exec fails */
849666Slinton 
859666Slinton #define ischild(pid)    ((pid) == 0)
869666Slinton 
879666Slinton /* VARARGS3 */
889666Slinton public int call(name, in, out, args)
899666Slinton String name;
909666Slinton File in;
919666Slinton File out;
929666Slinton String args;
939666Slinton {
949666Slinton     String *ap, *argp;
959666Slinton     String argv[MAXNARGS];
969666Slinton 
979666Slinton     argp = &argv[0];
989666Slinton     *argp++ = name;
999666Slinton     ap = &args;
1009666Slinton     while (*ap != nil(String)) {
1019666Slinton 	*argp++ = *ap++;
1029666Slinton     }
1039666Slinton     *argp = nil(String);
1049666Slinton     return callv(name, in, out, argv);
1059666Slinton }
1069666Slinton 
1079666Slinton /* VARARGS3 */
1089666Slinton public int back(name, in, out, args)
1099666Slinton String name;
1109666Slinton File in;
1119666Slinton File out;
1129666Slinton String args;
1139666Slinton {
1149666Slinton     String *ap, *argp;
1159666Slinton     String argv[MAXNARGS];
1169666Slinton 
1179666Slinton     argp = &argv[0];
1189666Slinton     *argp++ = name;
1199666Slinton     ap = &args;
1209666Slinton     while (*ap != nil(String)) {
1219666Slinton 	*argp++ = *ap++;
1229666Slinton     }
1239666Slinton     *argp = nil(String);
1249666Slinton     return backv(name, in, out, argv);
1259666Slinton }
1269666Slinton 
1279666Slinton public int callv(name, in, out, argv)
1289666Slinton String name;
1299666Slinton File in;
1309666Slinton File out;
1319666Slinton String *argv;
1329666Slinton {
1339666Slinton     int pid, status;
1349666Slinton 
1359666Slinton     pid = backv(name, in, out, argv);
1369666Slinton     pwait(pid, &status);
1379666Slinton     return status;
1389666Slinton }
1399666Slinton 
1409666Slinton public int backv(name, in, out, argv)
1419666Slinton String name;
1429666Slinton File in;
1439666Slinton File out;
1449666Slinton String *argv;
1459666Slinton {
1469666Slinton     int pid;
1479666Slinton 
1489666Slinton     fflush(stdout);
1499666Slinton     if (ischild(pid = fork())) {
1509666Slinton 	fswap(0, fileno(in));
1519666Slinton 	fswap(1, fileno(out));
1529666Slinton 	onsyserr(EACCES, ERR_IGNORE);
1539666Slinton 	execvp(name, argv);
1549666Slinton 	_exit(BADEXEC);
1559666Slinton     }
1569666Slinton     return pid;
1579666Slinton }
1589666Slinton 
1599666Slinton /*
1609666Slinton  * Swap file numbers so as to redirect standard input and output.
1619666Slinton  */
1629666Slinton 
1639666Slinton private fswap(oldfd, newfd)
1649666Slinton int oldfd;
1659666Slinton int newfd;
1669666Slinton {
1679666Slinton     if (oldfd != newfd) {
1689666Slinton 	close(oldfd);
1699666Slinton 	dup(newfd);
1709666Slinton 	close(newfd);
1719666Slinton     }
1729666Slinton }
1739666Slinton 
1749666Slinton /*
1759666Slinton  * Invoke a shell on a command line.
1769666Slinton  */
1779666Slinton 
1789666Slinton #define DEF_SHELL	"csh"
1799666Slinton 
1809666Slinton public shell(s)
1819666Slinton String s;
1829666Slinton {
1839666Slinton     extern String getenv();
1849666Slinton     String sh;
1859666Slinton 
1869666Slinton     if ((sh = getenv("SHELL")) == nil(String)) {
1879666Slinton 	sh = DEF_SHELL;
1889666Slinton     }
1899666Slinton     if (s != nil(String) and *s != '\0') {
1909666Slinton 	call(sh, stdin, stdout, "-c", s, 0);
1919666Slinton     } else {
1929666Slinton 	call(sh, stdin, stdout, 0);
1939666Slinton     }
1949666Slinton }
1959666Slinton 
1969666Slinton /*
1979666Slinton  * Wait for a process the right way.  We wait for a particular
1989666Slinton  * process and if any others come along in between, we remember them
1999666Slinton  * in case they are eventually waited for.
2009666Slinton  *
2019666Slinton  * This routine is not very efficient when the number of processes
2029666Slinton  * to be remembered is large.
20314394Slinton  *
20414394Slinton  * To deal with a kernel idiosyncrasy, we keep a list on the side
20514394Slinton  * of "traced" processes, and do not notice them when waiting for
20614394Slinton  * another process.
2079666Slinton  */
2089666Slinton 
2099666Slinton typedef struct pidlist {
2109666Slinton     int pid;
2119666Slinton     int status;
2129666Slinton     struct pidlist *next;
2139666Slinton } Pidlist;
2149666Slinton 
21514394Slinton private Pidlist *pidlist, *ptrclist, *pfind();
2169666Slinton 
21714394Slinton public ptraced(pid)
21814394Slinton int pid;
21914394Slinton {
22014394Slinton     Pidlist *p;
22114394Slinton 
22214394Slinton     p = alloc(1, Pidlist);
22314394Slinton     p->pid = pid;
22414394Slinton     p->next = ptrclist;
22514394Slinton     ptrclist = p;
22614394Slinton }
22714394Slinton 
22814394Slinton public unptraced(pid)
22914394Slinton int pid;
23014394Slinton {
23114394Slinton     register Pidlist *p, *prev;
23214394Slinton 
23314394Slinton     prev = nil(Pidlist *);
23414394Slinton     p = ptrclist;
23514394Slinton     while (p != nil(Pidlist *) and p->pid != pid) {
23614394Slinton 	prev = p;
23714394Slinton 	p = p->next;
23814394Slinton     }
23914394Slinton     if (p != nil(Pidlist *)) {
24014394Slinton 	if (prev == nil(Pidlist *)) {
24114394Slinton 	    ptrclist = p->next;
24214394Slinton 	} else {
24314394Slinton 	    prev->next = p->next;
24414394Slinton 	}
24514394Slinton 	dispose(p);
24614394Slinton     }
24714394Slinton }
24814394Slinton 
249*16611Ssam private boolean isptraced(pid)
25014394Slinton int pid;
25114394Slinton {
25214394Slinton     register Pidlist *p;
25314394Slinton 
25414394Slinton     p = ptrclist;
25514394Slinton     while (p != nil(Pidlist *) and p->pid != pid) {
25614394Slinton 	p = p->next;
25714394Slinton     }
258*16611Ssam     return (boolean) (p != nil(Pidlist *));
25914394Slinton }
26014394Slinton 
2619666Slinton public pwait(pid, statusp)
2629666Slinton int pid, *statusp;
2639666Slinton {
26414393Slinton     Pidlist *p;
26514393Slinton     int pnum, status;
2669666Slinton 
26714393Slinton     p = pfind(pid);
26814393Slinton     if (p != nil(Pidlist *)) {
26914393Slinton 	*statusp = p->status;
27014393Slinton 	dispose(p);
27114394Slinton     } else {
27214394Slinton 	pnum = wait(&status);
27314394Slinton 	while (pnum != pid and pnum >= 0) {
27414394Slinton 	    if (not isptraced(pnum)) {
27514394Slinton 		p = alloc(1, Pidlist);
27614394Slinton 		p->pid = pnum;
27714394Slinton 		p->status = status;
27814394Slinton 		p->next = pidlist;
27914394Slinton 		pidlist = p;
28014394Slinton 	    }
28114394Slinton 	    pnum = wait(&status);
2829666Slinton 	}
28314394Slinton 	if (pnum < 0) {
28414394Slinton 	    p = pfind(pid);
28514394Slinton 	    if (p == nil(Pidlist *)) {
28614394Slinton 		panic("pwait: pid %d not found", pid);
28714394Slinton 	    }
28814394Slinton 	    *statusp = p->status;
28914394Slinton 	    dispose(p);
29014394Slinton 	} else {
29114394Slinton 	    *statusp = status;
29214394Slinton 	}
29314393Slinton     }
2949666Slinton }
2959666Slinton 
2969666Slinton /*
2979666Slinton  * Look for the given process id on the pidlist.
2989666Slinton  *
2999666Slinton  * Unlink it from list if found.
3009666Slinton  */
3019666Slinton 
3029666Slinton private Pidlist *pfind(pid)
3039666Slinton int pid;
3049666Slinton {
3059666Slinton     register Pidlist *p, *prev;
3069666Slinton 
3079666Slinton     prev = nil(Pidlist *);
3089666Slinton     for (p = pidlist; p != nil(Pidlist *); p = p->next) {
3099666Slinton 	if (p->pid == pid) {
3109666Slinton 	    break;
3119666Slinton 	}
3129666Slinton 	prev = p;
3139666Slinton     }
3149666Slinton     if (p != nil(Pidlist *)) {
3159666Slinton 	if (prev == nil(Pidlist *)) {
3169666Slinton 	    pidlist = p->next;
3179666Slinton 	} else {
3189666Slinton 	    prev->next = p->next;
3199666Slinton 	}
3209666Slinton     }
3219666Slinton     return p;
3229666Slinton }
3239666Slinton 
3249666Slinton /*
3259666Slinton  * System call error handler.
3269666Slinton  *
3279666Slinton  * The syserr routine is called when a system call is about to
3289666Slinton  * set the c-bit to report an error.  Certain errors are caught
3299666Slinton  * and cause the process to print a message and immediately exit.
3309666Slinton  */
3319666Slinton 
3329666Slinton extern int sys_nerr;
3339666Slinton extern char *sys_errlist[];
3349666Slinton 
3359666Slinton /*
3369666Slinton  * Before calling syserr, the integer errno is set to contain the
3379666Slinton  * number of the error.  The routine "_mycerror" is a dummy which
3389666Slinton  * is used to force the loader to get my version of cerror rather
3399666Slinton  * than the usual one.
3409666Slinton  */
3419666Slinton 
3429666Slinton extern int errno;
3439666Slinton extern _mycerror();
3449666Slinton 
3459666Slinton /*
346*16611Ssam  * Initialize error information, setting defaults for handling errors.
3479666Slinton  */
3489666Slinton 
349*16611Ssam private ERRINFO *errinfo;
3509666Slinton 
351*16611Ssam private initErrInfo ()
352*16611Ssam {
353*16611Ssam     integer i;
354*16611Ssam 
355*16611Ssam     errinfo = alloc(sys_nerr, ERRINFO);
356*16611Ssam     for (i = 0; i < sys_nerr; i++) {
357*16611Ssam 	errinfo[i].func = ERR_CATCH;
358*16611Ssam     }
359*16611Ssam     errinfo[0].func = ERR_IGNORE;
360*16611Ssam     errinfo[EPERM].func = ERR_IGNORE;
361*16611Ssam     errinfo[ENOENT].func = ERR_IGNORE;
362*16611Ssam     errinfo[ESRCH].func = ERR_IGNORE;
363*16611Ssam     errinfo[EBADF].func = ERR_IGNORE;
364*16611Ssam     errinfo[ENOTTY].func = ERR_IGNORE;
365*16611Ssam     errinfo[EOPNOTSUPP].func = ERR_IGNORE;
366*16611Ssam }
367*16611Ssam 
3689666Slinton public syserr()
3699666Slinton {
3709666Slinton     ERRINFO *e;
3719666Slinton 
372*16611Ssam     if (errno < 0 or errno > sys_nerr) {
373*16611Ssam 	fatal("errno %d", errno);
374*16611Ssam     } else {
375*16611Ssam 	if (errinfo == nil(ERRINFO *)) {
376*16611Ssam 	    initErrInfo();
377*16611Ssam 	}
378*16611Ssam 	e = &(errinfo[errno]);
379*16611Ssam 	if (e->func == ERR_CATCH) {
3809666Slinton 	    fatal(sys_errlist[errno]);
381*16611Ssam 	} else if (e->func != ERR_IGNORE) {
382*16611Ssam 	    (*e->func)();
3839666Slinton 	}
3849666Slinton     }
3859666Slinton }
3869666Slinton 
3879666Slinton /*
388*16611Ssam  * Catcherrs' purpose is to initialize the errinfo table, get this module
389*16611Ssam  * loaded, and make sure my cerror is loaded (only applicable when this is
390*16611Ssam  * in a library).
3919666Slinton  */
3929666Slinton 
3939666Slinton public catcherrs()
3949666Slinton {
3959666Slinton     _mycerror();
396*16611Ssam     initErrInfo();
3979666Slinton }
3989666Slinton 
3999666Slinton /*
4009666Slinton  * Change the action on receipt of an error.
4019666Slinton  */
4029666Slinton 
4039666Slinton public onsyserr(n, f)
4049666Slinton int n;
4059666Slinton INTFUNC *f;
4069666Slinton {
407*16611Ssam     if (errinfo == nil(ERRINFO *)) {
408*16611Ssam 	initErrInfo();
409*16611Ssam     }
4109666Slinton     errinfo[n].func = f;
4119666Slinton }
4129666Slinton 
4139666Slinton /*
4149666Slinton  * Print the message associated with the given signal.
4159666Slinton  * Like a "perror" for signals.
4169666Slinton  */
4179666Slinton 
4189666Slinton public int sys_nsig = NSIG;
4199666Slinton public String sys_siglist[] = {
4209666Slinton     "no signal",
4219666Slinton     "hangup",
4229666Slinton     "interrupt",
4239666Slinton     "quit",
4249666Slinton     "illegal instruction",
4259666Slinton     "trace trap",
4269666Slinton     "IOT instruction",
4279666Slinton     "EMT instruction",
4289666Slinton     "floating point exception",
4299666Slinton     "kill",
4309666Slinton     "bus error",
4319666Slinton     "segmentation violation",
4329666Slinton     "bad argument to system call",
4339666Slinton     "broken pipe",
4349666Slinton     "alarm clock",
4359666Slinton     "soft kill",
4369666Slinton     "urgent I/O condition",
4379666Slinton     "stop signal not from tty",
4389666Slinton     "stop signal from tty",
4399666Slinton     "continue",
4409666Slinton     "child termination",
4419666Slinton     "stop (tty input)",
4429666Slinton     "stop (tty output)",
4439666Slinton     "possible input/output",
4449666Slinton     "exceeded CPU time limit",
4459666Slinton     "exceeded file size limit",
4469666Slinton     nil(String)
4479666Slinton };
4489666Slinton 
449*16611Ssam public psignal(s, n)
4509666Slinton String s;
451*16611Ssam integer n;
4529666Slinton {
453*16611Ssam     String msg;
454*16611Ssam     integer len;
4559666Slinton 
456*16611Ssam     if (n >= 0 and n < sys_nsig) {
457*16611Ssam 	msg = sys_siglist[n];
458*16611Ssam     } else {
459*16611Ssam 	msg = "Unknown signal";
4609666Slinton     }
461*16611Ssam     len = strlen(s);
462*16611Ssam     if (len > 0) {
463*16611Ssam 	write(2, s, len);
4649666Slinton 	write(2, ": ", 2);
4659666Slinton     }
466*16611Ssam     write(2, msg, strlen(msg));
4679666Slinton     write(2, "\n", 1);
4689666Slinton }
4699666Slinton 
4709666Slinton /*
4719666Slinton  * Standard error handling routines.
4729666Slinton  */
4739666Slinton 
4749666Slinton private short nerrs;
4759666Slinton private short nwarnings;
4769666Slinton 
4779666Slinton /*
4789666Slinton  * Main driver of error message reporting.
4799666Slinton  */
4809666Slinton 
4819666Slinton /* VARARGS2 */
4829666Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
4839666Slinton String errname;
484*16611Ssam boolean shouldquit;
4859666Slinton String s;
4869666Slinton {
4879666Slinton     fflush(stdout);
4889666Slinton     if (shouldquit and cmdname != nil(String)) {
4899666Slinton 	fprintf(stderr, "%s: ", cmdname);
4909666Slinton     }
4919666Slinton     if (errfilename != nil(Filename)) {
4929666Slinton 	fprintf(stderr, "%s: ", errfilename);
4939666Slinton     }
4949666Slinton     if (errlineno > 0) {
4959666Slinton 	fprintf(stderr, "%d: ", errlineno);
4969666Slinton     }
4979666Slinton     if (errname != nil(String)) {
4989666Slinton 	fprintf(stderr, "%s: ", errname);
4999666Slinton     }
5009666Slinton     fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5019666Slinton     putc('\n', stderr);
5029666Slinton     if (shouldquit) {
5039666Slinton 	quit(1);
5049666Slinton     }
5059666Slinton }
5069666Slinton 
5079666Slinton /*
5089666Slinton  * For when printf isn't sufficient for printing the error message ...
5099666Slinton  */
5109666Slinton 
5119666Slinton public beginerrmsg()
5129666Slinton {
5139666Slinton     fflush(stdout);
5149666Slinton     if (errfilename != nil(String)) {
5159666Slinton 	fprintf(stderr, "%s: ", errfilename);
5169666Slinton     }
5179666Slinton     if (errlineno > 0) {
5189666Slinton 	fprintf(stderr, "%d: ", errlineno);
5199666Slinton     }
5209666Slinton }
5219666Slinton 
5229666Slinton public enderrmsg()
5239666Slinton {
5249666Slinton     putc('\n', stderr);
5259666Slinton     erecover();
5269666Slinton }
5279666Slinton 
5289666Slinton /*
5299666Slinton  * The messages are listed in increasing order of seriousness.
5309666Slinton  *
5319666Slinton  * First are warnings.
5329666Slinton  */
5339666Slinton 
5349666Slinton /* VARARGS1 */
5359666Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5369666Slinton String s;
5379666Slinton {
5389666Slinton     nwarnings++;
5399666Slinton     errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5409666Slinton }
5419666Slinton 
5429666Slinton /*
5439666Slinton  * Errors are a little worse, they mean something is wrong,
5449666Slinton  * but not so bad that processing can't continue.
5459666Slinton  *
5469666Slinton  * The routine "erecover" is called to recover from the error,
5479666Slinton  * a default routine is provided that does nothing.
5489666Slinton  */
5499666Slinton 
5509666Slinton /* VARARGS1 */
5519666Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5529666Slinton String s;
5539666Slinton {
5549666Slinton     extern erecover();
5559666Slinton 
5569666Slinton     nerrs++;
5579666Slinton     errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5589666Slinton     erecover();
5599666Slinton }
5609666Slinton 
5619666Slinton /*
5629666Slinton  * Non-recoverable user error.
5639666Slinton  */
5649666Slinton 
5659666Slinton /* VARARGS1 */
5669666Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5679666Slinton String s;
5689666Slinton {
5699666Slinton     errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5709666Slinton }
5719666Slinton 
5729666Slinton /*
5739666Slinton  * Panics indicate an internal program error.
5749666Slinton  */
5759666Slinton 
5769666Slinton /* VARARGS1 */
5779666Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5789666Slinton String s;
5799666Slinton {
5809666Slinton     errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5819666Slinton }
5829666Slinton 
5839666Slinton short numerrors()
5849666Slinton {
5859666Slinton     short r;
5869666Slinton 
5879666Slinton     r = nerrs;
5889666Slinton     nerrs = 0;
5899666Slinton     return r;
5909666Slinton }
5919666Slinton 
5929666Slinton short numwarnings()
5939666Slinton {
5949666Slinton     short r;
5959666Slinton 
5969666Slinton     r = nwarnings;
5979666Slinton     nwarnings = 0;
5989666Slinton     return r;
5999666Slinton }
6009666Slinton 
6019666Slinton /*
6029666Slinton  * Recover from an error.
6039666Slinton  *
6049666Slinton  * This is the default routine which we aren't using since we have our own.
6059666Slinton  *
6069666Slinton public erecover()
6079666Slinton {
6089666Slinton }
6099666Slinton  *
6109666Slinton  */
6119666Slinton 
6129666Slinton /*
6139666Slinton  * Default way to quit from a program is just to exit.
6149666Slinton  *
6159666Slinton public quit(r)
6169666Slinton int r;
6179666Slinton {
6189666Slinton     exit(r);
6199666Slinton }
6209666Slinton  *
6219666Slinton  */
6229666Slinton 
6239666Slinton /*
6249666Slinton  * Compare n-byte areas pointed to by s1 and s2
6259666Slinton  * if n is 0 then compare up until one has a null byte.
6269666Slinton  */
6279666Slinton 
6289666Slinton public int cmp(s1, s2, n)
6299666Slinton register char *s1, *s2;
6309666Slinton register unsigned int n;
6319666Slinton {
6329666Slinton     if (s1 == nil(char *) || s2 == nil(char *)) {
6339666Slinton 	panic("cmp: nil pointer");
6349666Slinton     }
6359666Slinton     if (n == 0) {
6369666Slinton 	while (*s1 == *s2++) {
6379666Slinton 	    if (*s1++ == '\0') {
6389666Slinton 		return(0);
6399666Slinton 	    }
6409666Slinton 	}
6419666Slinton 	return(*s1 - *(s2-1));
6429666Slinton     } else {
6439666Slinton 	for (; n != 0; n--) {
6449666Slinton 	    if (*s1++ != *s2++) {
6459666Slinton 		return(*(s1-1) - *(s2-1));
6469666Slinton 	    }
6479666Slinton 	}
6489666Slinton 	return(0);
6499666Slinton     }
6509666Slinton }
6519666Slinton 
6529666Slinton /*
6539666Slinton  * Move n bytes from src to dest.
6549666Slinton  * If n is 0 move until a null is found.
6559666Slinton  */
6569666Slinton 
6579666Slinton public mov(src, dest, n)
6589666Slinton register char *src, *dest;
6599666Slinton register unsigned int n;
6609666Slinton {
6619666Slinton     if (src == nil(char *))
6629666Slinton 	panic("mov: nil source");
6639666Slinton     if (dest == nil(char *))
6649666Slinton 	panic("mov: nil destination");
6659666Slinton     if (n != 0) {
6669666Slinton 	for (; n != 0; n--) {
6679666Slinton 	    *dest++ = *src++;
6689666Slinton 	}
6699666Slinton     } else {
6709666Slinton 	while ((*dest++ = *src++) != '\0');
6719666Slinton     }
6729666Slinton }
673