xref: /csrg-svn/old/dbx/library.c (revision 18538)
19666Slinton /* Copyright (c) 1982 Regents of the University of California */
29666Slinton 
3*18538Sralph static	char sccsid[] = "@(#)library.c	1.7 (Berkeley) 03/28/85";
416611Ssam 
518221Slinton static char rcsid[] = "$Header: library.c,v 1.5 84/12/26 10:39:52 linton Exp $";
618221Slinton 
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 
2316611Ssam typedef int integer;
2416611Ssam 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 
8216611Ssam #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 
24916611Ssam 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     }
25816611Ssam     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 /*
34616611Ssam  * Initialize error information, setting defaults for handling errors.
3479666Slinton  */
3489666Slinton 
34916611Ssam private ERRINFO *errinfo;
3509666Slinton 
35116611Ssam private initErrInfo ()
35216611Ssam {
35316611Ssam     integer i;
35416611Ssam 
35516611Ssam     errinfo = alloc(sys_nerr, ERRINFO);
35616611Ssam     for (i = 0; i < sys_nerr; i++) {
35716611Ssam 	errinfo[i].func = ERR_CATCH;
35816611Ssam     }
35916611Ssam     errinfo[0].func = ERR_IGNORE;
36016611Ssam     errinfo[EPERM].func = ERR_IGNORE;
36116611Ssam     errinfo[ENOENT].func = ERR_IGNORE;
36216611Ssam     errinfo[ESRCH].func = ERR_IGNORE;
36316611Ssam     errinfo[EBADF].func = ERR_IGNORE;
36416611Ssam     errinfo[ENOTTY].func = ERR_IGNORE;
36516611Ssam     errinfo[EOPNOTSUPP].func = ERR_IGNORE;
36616611Ssam }
36716611Ssam 
3689666Slinton public syserr()
3699666Slinton {
3709666Slinton     ERRINFO *e;
3719666Slinton 
37216611Ssam     if (errno < 0 or errno > sys_nerr) {
37316611Ssam 	fatal("errno %d", errno);
37416611Ssam     } else {
37516611Ssam 	if (errinfo == nil(ERRINFO *)) {
37616611Ssam 	    initErrInfo();
37716611Ssam 	}
37816611Ssam 	e = &(errinfo[errno]);
37916611Ssam 	if (e->func == ERR_CATCH) {
3809666Slinton 	    fatal(sys_errlist[errno]);
38116611Ssam 	} else if (e->func != ERR_IGNORE) {
38216611Ssam 	    (*e->func)();
3839666Slinton 	}
3849666Slinton     }
3859666Slinton }
3869666Slinton 
3879666Slinton /*
38816611Ssam  * Catcherrs' purpose is to initialize the errinfo table, get this module
38916611Ssam  * loaded, and make sure my cerror is loaded (only applicable when this is
39016611Ssam  * in a library).
3919666Slinton  */
3929666Slinton 
3939666Slinton public catcherrs()
3949666Slinton {
3959666Slinton     _mycerror();
39616611Ssam     initErrInfo();
3979666Slinton }
3989666Slinton 
3999666Slinton /*
40018221Slinton  * Turn off the error catching mechanism completely by having all errors
40118221Slinton  * ignored.  This is most useful between a fork and an exec.
40218221Slinton  */
40318221Slinton 
40418221Slinton public nocatcherrs()
40518221Slinton {
40618221Slinton     integer i;
40718221Slinton 
40818221Slinton     for (i = 0; i < sys_nerr; i++) {
40918221Slinton 	errinfo[i].func = ERR_IGNORE;
41018221Slinton     }
41118221Slinton }
41218221Slinton 
41318221Slinton /*
4149666Slinton  * Change the action on receipt of an error.
4159666Slinton  */
4169666Slinton 
4179666Slinton public onsyserr(n, f)
4189666Slinton int n;
4199666Slinton INTFUNC *f;
4209666Slinton {
42116611Ssam     if (errinfo == nil(ERRINFO *)) {
42216611Ssam 	initErrInfo();
42316611Ssam     }
4249666Slinton     errinfo[n].func = f;
4259666Slinton }
4269666Slinton 
4279666Slinton /*
4289666Slinton  * Print the message associated with the given signal.
4299666Slinton  * Like a "perror" for signals.
4309666Slinton  */
4319666Slinton 
4329666Slinton public int sys_nsig = NSIG;
4339666Slinton 
43416611Ssam public psignal(s, n)
4359666Slinton String s;
43616611Ssam integer n;
4379666Slinton {
43816611Ssam     String msg;
43916611Ssam     integer len;
440*18538Sralph     extern String sys_siglist[];
4419666Slinton 
44216611Ssam     if (n >= 0 and n < sys_nsig) {
44316611Ssam 	msg = sys_siglist[n];
44416611Ssam     } else {
44516611Ssam 	msg = "Unknown signal";
4469666Slinton     }
44716611Ssam     len = strlen(s);
44816611Ssam     if (len > 0) {
44916611Ssam 	write(2, s, len);
4509666Slinton 	write(2, ": ", 2);
4519666Slinton     }
45216611Ssam     write(2, msg, strlen(msg));
4539666Slinton     write(2, "\n", 1);
4549666Slinton }
4559666Slinton 
4569666Slinton /*
4579666Slinton  * Standard error handling routines.
4589666Slinton  */
4599666Slinton 
4609666Slinton private short nerrs;
4619666Slinton private short nwarnings;
4629666Slinton 
4639666Slinton /*
4649666Slinton  * Main driver of error message reporting.
4659666Slinton  */
4669666Slinton 
4679666Slinton /* VARARGS2 */
4689666Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
4699666Slinton String errname;
47016611Ssam boolean shouldquit;
4719666Slinton String s;
4729666Slinton {
4739666Slinton     fflush(stdout);
4749666Slinton     if (shouldquit and cmdname != nil(String)) {
4759666Slinton 	fprintf(stderr, "%s: ", cmdname);
4769666Slinton     }
4779666Slinton     if (errfilename != nil(Filename)) {
4789666Slinton 	fprintf(stderr, "%s: ", errfilename);
4799666Slinton     }
4809666Slinton     if (errlineno > 0) {
4819666Slinton 	fprintf(stderr, "%d: ", errlineno);
4829666Slinton     }
4839666Slinton     if (errname != nil(String)) {
4849666Slinton 	fprintf(stderr, "%s: ", errname);
4859666Slinton     }
4869666Slinton     fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
4879666Slinton     putc('\n', stderr);
4889666Slinton     if (shouldquit) {
4899666Slinton 	quit(1);
4909666Slinton     }
4919666Slinton }
4929666Slinton 
4939666Slinton /*
4949666Slinton  * For when printf isn't sufficient for printing the error message ...
4959666Slinton  */
4969666Slinton 
4979666Slinton public beginerrmsg()
4989666Slinton {
4999666Slinton     fflush(stdout);
5009666Slinton     if (errfilename != nil(String)) {
5019666Slinton 	fprintf(stderr, "%s: ", errfilename);
5029666Slinton     }
5039666Slinton     if (errlineno > 0) {
5049666Slinton 	fprintf(stderr, "%d: ", errlineno);
5059666Slinton     }
5069666Slinton }
5079666Slinton 
5089666Slinton public enderrmsg()
5099666Slinton {
5109666Slinton     putc('\n', stderr);
5119666Slinton     erecover();
5129666Slinton }
5139666Slinton 
5149666Slinton /*
5159666Slinton  * The messages are listed in increasing order of seriousness.
5169666Slinton  *
5179666Slinton  * First are warnings.
5189666Slinton  */
5199666Slinton 
5209666Slinton /* VARARGS1 */
5219666Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5229666Slinton String s;
5239666Slinton {
5249666Slinton     nwarnings++;
5259666Slinton     errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5269666Slinton }
5279666Slinton 
5289666Slinton /*
5299666Slinton  * Errors are a little worse, they mean something is wrong,
5309666Slinton  * but not so bad that processing can't continue.
5319666Slinton  *
5329666Slinton  * The routine "erecover" is called to recover from the error,
5339666Slinton  * a default routine is provided that does nothing.
5349666Slinton  */
5359666Slinton 
5369666Slinton /* VARARGS1 */
5379666Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5389666Slinton String s;
5399666Slinton {
5409666Slinton     extern erecover();
5419666Slinton 
5429666Slinton     nerrs++;
5439666Slinton     errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5449666Slinton     erecover();
5459666Slinton }
5469666Slinton 
5479666Slinton /*
5489666Slinton  * Non-recoverable user error.
5499666Slinton  */
5509666Slinton 
5519666Slinton /* VARARGS1 */
5529666Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5539666Slinton String s;
5549666Slinton {
5559666Slinton     errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5569666Slinton }
5579666Slinton 
5589666Slinton /*
5599666Slinton  * Panics indicate an internal program error.
5609666Slinton  */
5619666Slinton 
5629666Slinton /* VARARGS1 */
5639666Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5649666Slinton String s;
5659666Slinton {
5669666Slinton     errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5679666Slinton }
5689666Slinton 
5699666Slinton short numerrors()
5709666Slinton {
5719666Slinton     short r;
5729666Slinton 
5739666Slinton     r = nerrs;
5749666Slinton     nerrs = 0;
5759666Slinton     return r;
5769666Slinton }
5779666Slinton 
5789666Slinton short numwarnings()
5799666Slinton {
5809666Slinton     short r;
5819666Slinton 
5829666Slinton     r = nwarnings;
5839666Slinton     nwarnings = 0;
5849666Slinton     return r;
5859666Slinton }
5869666Slinton 
5879666Slinton /*
5889666Slinton  * Recover from an error.
5899666Slinton  *
5909666Slinton  * This is the default routine which we aren't using since we have our own.
5919666Slinton  *
5929666Slinton public erecover()
5939666Slinton {
5949666Slinton }
5959666Slinton  *
5969666Slinton  */
5979666Slinton 
5989666Slinton /*
5999666Slinton  * Default way to quit from a program is just to exit.
6009666Slinton  *
6019666Slinton public quit(r)
6029666Slinton int r;
6039666Slinton {
6049666Slinton     exit(r);
6059666Slinton }
6069666Slinton  *
6079666Slinton  */
6089666Slinton 
6099666Slinton /*
6109666Slinton  * Compare n-byte areas pointed to by s1 and s2
6119666Slinton  * if n is 0 then compare up until one has a null byte.
6129666Slinton  */
6139666Slinton 
6149666Slinton public int cmp(s1, s2, n)
6159666Slinton register char *s1, *s2;
6169666Slinton register unsigned int n;
6179666Slinton {
6189666Slinton     if (s1 == nil(char *) || s2 == nil(char *)) {
6199666Slinton 	panic("cmp: nil pointer");
6209666Slinton     }
6219666Slinton     if (n == 0) {
6229666Slinton 	while (*s1 == *s2++) {
6239666Slinton 	    if (*s1++ == '\0') {
6249666Slinton 		return(0);
6259666Slinton 	    }
6269666Slinton 	}
6279666Slinton 	return(*s1 - *(s2-1));
6289666Slinton     } else {
6299666Slinton 	for (; n != 0; n--) {
6309666Slinton 	    if (*s1++ != *s2++) {
6319666Slinton 		return(*(s1-1) - *(s2-1));
6329666Slinton 	    }
6339666Slinton 	}
6349666Slinton 	return(0);
6359666Slinton     }
6369666Slinton }
6379666Slinton 
6389666Slinton /*
6399666Slinton  * Move n bytes from src to dest.
6409666Slinton  * If n is 0 move until a null is found.
6419666Slinton  */
6429666Slinton 
6439666Slinton public mov(src, dest, n)
6449666Slinton register char *src, *dest;
6459666Slinton register unsigned int n;
6469666Slinton {
6479666Slinton     if (src == nil(char *))
6489666Slinton 	panic("mov: nil source");
6499666Slinton     if (dest == nil(char *))
6509666Slinton 	panic("mov: nil destination");
6519666Slinton     if (n != 0) {
6529666Slinton 	for (; n != 0; n--) {
6539666Slinton 	    *dest++ = *src++;
6549666Slinton 	}
6559666Slinton     } else {
6569666Slinton 	while ((*dest++ = *src++) != '\0');
6579666Slinton     }
6589666Slinton }
659