xref: /csrg-svn/old/dbx/library.c (revision 21606)
1*21606Sdist /*
2*21606Sdist  * Copyright (c) 1983 Regents of the University of California.
3*21606Sdist  * All rights reserved.  The Berkeley software License Agreement
4*21606Sdist  * specifies the terms and conditions for redistribution.
5*21606Sdist  */
69666Slinton 
7*21606Sdist #ifndef lint
8*21606Sdist static char sccsid[] = "@(#)library.c	5.1 (Berkeley) 05/31/85";
9*21606Sdist #endif not lint
1016611Ssam 
1118221Slinton static char rcsid[] = "$Header: library.c,v 1.5 84/12/26 10:39:52 linton Exp $";
1218221Slinton 
139666Slinton /*
149666Slinton  * General purpose routines.
159666Slinton  */
169666Slinton 
179666Slinton #include <stdio.h>
189666Slinton #include <errno.h>
199666Slinton #include <signal.h>
209666Slinton 
219666Slinton #define public
229666Slinton #define private static
239666Slinton #define and &&
249666Slinton #define or ||
259666Slinton #define not !
269666Slinton #define ord(enumcon)	((int) enumcon)
279666Slinton #define nil(type)	((type) 0)
289666Slinton 
2916611Ssam typedef int integer;
3016611Ssam typedef enum { FALSE, TRUE } boolean;
319666Slinton typedef char *String;
329666Slinton typedef FILE *File;
339666Slinton typedef String Filename;
349666Slinton 
359666Slinton #undef FILE
369666Slinton 
379666Slinton String cmdname;			/* name of command for error messages */
389666Slinton Filename errfilename;		/* current file associated with error */
399666Slinton short errlineno;		/* line number associated with error */
409666Slinton 
419666Slinton /*
429666Slinton  * Definitions for doing memory allocation.
439666Slinton  */
449666Slinton 
459666Slinton extern char *malloc();
469666Slinton 
479666Slinton #define alloc(n, type)	((type *) malloc((unsigned) (n) * sizeof(type)))
489666Slinton #define dispose(p)	{ free((char *) p); p = 0; }
499666Slinton 
509666Slinton /*
519666Slinton  * Macros for doing freads + fwrites.
529666Slinton  */
539666Slinton 
549666Slinton #define get(fp, var)	fread((char *) &(var), sizeof(var), 1, fp)
559666Slinton #define put(fp, var)	fwrite((char *) &(var), sizeof(var), 1, fp)
569666Slinton 
579666Slinton /*
589666Slinton  * String definitions.
599666Slinton  */
609666Slinton 
619666Slinton extern String strcpy(), index(), rindex();
629666Slinton extern int strlen();
639666Slinton 
649666Slinton #define strdup(s)		strcpy(malloc((unsigned) strlen(s) + 1), s)
659666Slinton #define streq(s1, s2)	(strcmp(s1, s2) == 0)
669666Slinton 
679666Slinton typedef int INTFUNC();
689666Slinton 
699666Slinton typedef struct {
709666Slinton     INTFUNC *func;
719666Slinton } ERRINFO;
729666Slinton 
739666Slinton #define ERR_IGNORE ((INTFUNC *) 0)
749666Slinton #define ERR_CATCH  ((INTFUNC *) 1)
759666Slinton 
769666Slinton /*
779666Slinton  * Call a program.
789666Slinton  *
799666Slinton  * Four entries:
809666Slinton  *
819666Slinton  *	call, callv - call a program and wait for it, returning status
829666Slinton  *	back, backv - call a program and don't wait, returning process id
839666Slinton  *
849666Slinton  * The command's standard input and output are passed as FILE's.
859666Slinton  */
869666Slinton 
879666Slinton 
8816611Ssam #define MAXNARGS 1000    /* unchecked upper limit on max num of arguments */
899666Slinton #define BADEXEC 127	/* exec fails */
909666Slinton 
919666Slinton #define ischild(pid)    ((pid) == 0)
929666Slinton 
939666Slinton /* VARARGS3 */
949666Slinton public int call(name, in, out, args)
959666Slinton String name;
969666Slinton File in;
979666Slinton File out;
989666Slinton String args;
999666Slinton {
1009666Slinton     String *ap, *argp;
1019666Slinton     String argv[MAXNARGS];
1029666Slinton 
1039666Slinton     argp = &argv[0];
1049666Slinton     *argp++ = name;
1059666Slinton     ap = &args;
1069666Slinton     while (*ap != nil(String)) {
1079666Slinton 	*argp++ = *ap++;
1089666Slinton     }
1099666Slinton     *argp = nil(String);
1109666Slinton     return callv(name, in, out, argv);
1119666Slinton }
1129666Slinton 
1139666Slinton /* VARARGS3 */
1149666Slinton public int back(name, in, out, args)
1159666Slinton String name;
1169666Slinton File in;
1179666Slinton File out;
1189666Slinton String args;
1199666Slinton {
1209666Slinton     String *ap, *argp;
1219666Slinton     String argv[MAXNARGS];
1229666Slinton 
1239666Slinton     argp = &argv[0];
1249666Slinton     *argp++ = name;
1259666Slinton     ap = &args;
1269666Slinton     while (*ap != nil(String)) {
1279666Slinton 	*argp++ = *ap++;
1289666Slinton     }
1299666Slinton     *argp = nil(String);
1309666Slinton     return backv(name, in, out, argv);
1319666Slinton }
1329666Slinton 
1339666Slinton public int callv(name, in, out, argv)
1349666Slinton String name;
1359666Slinton File in;
1369666Slinton File out;
1379666Slinton String *argv;
1389666Slinton {
1399666Slinton     int pid, status;
1409666Slinton 
1419666Slinton     pid = backv(name, in, out, argv);
1429666Slinton     pwait(pid, &status);
1439666Slinton     return status;
1449666Slinton }
1459666Slinton 
1469666Slinton public int backv(name, in, out, argv)
1479666Slinton String name;
1489666Slinton File in;
1499666Slinton File out;
1509666Slinton String *argv;
1519666Slinton {
1529666Slinton     int pid;
1539666Slinton 
1549666Slinton     fflush(stdout);
1559666Slinton     if (ischild(pid = fork())) {
1569666Slinton 	fswap(0, fileno(in));
1579666Slinton 	fswap(1, fileno(out));
1589666Slinton 	onsyserr(EACCES, ERR_IGNORE);
1599666Slinton 	execvp(name, argv);
1609666Slinton 	_exit(BADEXEC);
1619666Slinton     }
1629666Slinton     return pid;
1639666Slinton }
1649666Slinton 
1659666Slinton /*
1669666Slinton  * Swap file numbers so as to redirect standard input and output.
1679666Slinton  */
1689666Slinton 
1699666Slinton private fswap(oldfd, newfd)
1709666Slinton int oldfd;
1719666Slinton int newfd;
1729666Slinton {
1739666Slinton     if (oldfd != newfd) {
1749666Slinton 	close(oldfd);
1759666Slinton 	dup(newfd);
1769666Slinton 	close(newfd);
1779666Slinton     }
1789666Slinton }
1799666Slinton 
1809666Slinton /*
1819666Slinton  * Invoke a shell on a command line.
1829666Slinton  */
1839666Slinton 
1849666Slinton #define DEF_SHELL	"csh"
1859666Slinton 
1869666Slinton public shell(s)
1879666Slinton String s;
1889666Slinton {
1899666Slinton     extern String getenv();
1909666Slinton     String sh;
1919666Slinton 
1929666Slinton     if ((sh = getenv("SHELL")) == nil(String)) {
1939666Slinton 	sh = DEF_SHELL;
1949666Slinton     }
1959666Slinton     if (s != nil(String) and *s != '\0') {
1969666Slinton 	call(sh, stdin, stdout, "-c", s, 0);
1979666Slinton     } else {
1989666Slinton 	call(sh, stdin, stdout, 0);
1999666Slinton     }
2009666Slinton }
2019666Slinton 
2029666Slinton /*
2039666Slinton  * Wait for a process the right way.  We wait for a particular
2049666Slinton  * process and if any others come along in between, we remember them
2059666Slinton  * in case they are eventually waited for.
2069666Slinton  *
2079666Slinton  * This routine is not very efficient when the number of processes
2089666Slinton  * to be remembered is large.
20914394Slinton  *
21014394Slinton  * To deal with a kernel idiosyncrasy, we keep a list on the side
21114394Slinton  * of "traced" processes, and do not notice them when waiting for
21214394Slinton  * another process.
2139666Slinton  */
2149666Slinton 
2159666Slinton typedef struct pidlist {
2169666Slinton     int pid;
2179666Slinton     int status;
2189666Slinton     struct pidlist *next;
2199666Slinton } Pidlist;
2209666Slinton 
22114394Slinton private Pidlist *pidlist, *ptrclist, *pfind();
2229666Slinton 
22314394Slinton public ptraced(pid)
22414394Slinton int pid;
22514394Slinton {
22614394Slinton     Pidlist *p;
22714394Slinton 
22814394Slinton     p = alloc(1, Pidlist);
22914394Slinton     p->pid = pid;
23014394Slinton     p->next = ptrclist;
23114394Slinton     ptrclist = p;
23214394Slinton }
23314394Slinton 
23414394Slinton public unptraced(pid)
23514394Slinton int pid;
23614394Slinton {
23714394Slinton     register Pidlist *p, *prev;
23814394Slinton 
23914394Slinton     prev = nil(Pidlist *);
24014394Slinton     p = ptrclist;
24114394Slinton     while (p != nil(Pidlist *) and p->pid != pid) {
24214394Slinton 	prev = p;
24314394Slinton 	p = p->next;
24414394Slinton     }
24514394Slinton     if (p != nil(Pidlist *)) {
24614394Slinton 	if (prev == nil(Pidlist *)) {
24714394Slinton 	    ptrclist = p->next;
24814394Slinton 	} else {
24914394Slinton 	    prev->next = p->next;
25014394Slinton 	}
25114394Slinton 	dispose(p);
25214394Slinton     }
25314394Slinton }
25414394Slinton 
25516611Ssam private boolean isptraced(pid)
25614394Slinton int pid;
25714394Slinton {
25814394Slinton     register Pidlist *p;
25914394Slinton 
26014394Slinton     p = ptrclist;
26114394Slinton     while (p != nil(Pidlist *) and p->pid != pid) {
26214394Slinton 	p = p->next;
26314394Slinton     }
26416611Ssam     return (boolean) (p != nil(Pidlist *));
26514394Slinton }
26614394Slinton 
2679666Slinton public pwait(pid, statusp)
2689666Slinton int pid, *statusp;
2699666Slinton {
27014393Slinton     Pidlist *p;
27114393Slinton     int pnum, status;
2729666Slinton 
27314393Slinton     p = pfind(pid);
27414393Slinton     if (p != nil(Pidlist *)) {
27514393Slinton 	*statusp = p->status;
27614393Slinton 	dispose(p);
27714394Slinton     } else {
27814394Slinton 	pnum = wait(&status);
27914394Slinton 	while (pnum != pid and pnum >= 0) {
28014394Slinton 	    if (not isptraced(pnum)) {
28114394Slinton 		p = alloc(1, Pidlist);
28214394Slinton 		p->pid = pnum;
28314394Slinton 		p->status = status;
28414394Slinton 		p->next = pidlist;
28514394Slinton 		pidlist = p;
28614394Slinton 	    }
28714394Slinton 	    pnum = wait(&status);
2889666Slinton 	}
28914394Slinton 	if (pnum < 0) {
29014394Slinton 	    p = pfind(pid);
29114394Slinton 	    if (p == nil(Pidlist *)) {
29214394Slinton 		panic("pwait: pid %d not found", pid);
29314394Slinton 	    }
29414394Slinton 	    *statusp = p->status;
29514394Slinton 	    dispose(p);
29614394Slinton 	} else {
29714394Slinton 	    *statusp = status;
29814394Slinton 	}
29914393Slinton     }
3009666Slinton }
3019666Slinton 
3029666Slinton /*
3039666Slinton  * Look for the given process id on the pidlist.
3049666Slinton  *
3059666Slinton  * Unlink it from list if found.
3069666Slinton  */
3079666Slinton 
3089666Slinton private Pidlist *pfind(pid)
3099666Slinton int pid;
3109666Slinton {
3119666Slinton     register Pidlist *p, *prev;
3129666Slinton 
3139666Slinton     prev = nil(Pidlist *);
3149666Slinton     for (p = pidlist; p != nil(Pidlist *); p = p->next) {
3159666Slinton 	if (p->pid == pid) {
3169666Slinton 	    break;
3179666Slinton 	}
3189666Slinton 	prev = p;
3199666Slinton     }
3209666Slinton     if (p != nil(Pidlist *)) {
3219666Slinton 	if (prev == nil(Pidlist *)) {
3229666Slinton 	    pidlist = p->next;
3239666Slinton 	} else {
3249666Slinton 	    prev->next = p->next;
3259666Slinton 	}
3269666Slinton     }
3279666Slinton     return p;
3289666Slinton }
3299666Slinton 
3309666Slinton /*
3319666Slinton  * System call error handler.
3329666Slinton  *
3339666Slinton  * The syserr routine is called when a system call is about to
3349666Slinton  * set the c-bit to report an error.  Certain errors are caught
3359666Slinton  * and cause the process to print a message and immediately exit.
3369666Slinton  */
3379666Slinton 
3389666Slinton extern int sys_nerr;
3399666Slinton extern char *sys_errlist[];
3409666Slinton 
3419666Slinton /*
3429666Slinton  * Before calling syserr, the integer errno is set to contain the
3439666Slinton  * number of the error.  The routine "_mycerror" is a dummy which
3449666Slinton  * is used to force the loader to get my version of cerror rather
3459666Slinton  * than the usual one.
3469666Slinton  */
3479666Slinton 
3489666Slinton extern int errno;
3499666Slinton extern _mycerror();
3509666Slinton 
3519666Slinton /*
35216611Ssam  * Initialize error information, setting defaults for handling errors.
3539666Slinton  */
3549666Slinton 
35516611Ssam private ERRINFO *errinfo;
3569666Slinton 
35716611Ssam private initErrInfo ()
35816611Ssam {
35916611Ssam     integer i;
36016611Ssam 
36116611Ssam     errinfo = alloc(sys_nerr, ERRINFO);
36216611Ssam     for (i = 0; i < sys_nerr; i++) {
36316611Ssam 	errinfo[i].func = ERR_CATCH;
36416611Ssam     }
36516611Ssam     errinfo[0].func = ERR_IGNORE;
36616611Ssam     errinfo[EPERM].func = ERR_IGNORE;
36716611Ssam     errinfo[ENOENT].func = ERR_IGNORE;
36816611Ssam     errinfo[ESRCH].func = ERR_IGNORE;
36916611Ssam     errinfo[EBADF].func = ERR_IGNORE;
37016611Ssam     errinfo[ENOTTY].func = ERR_IGNORE;
37116611Ssam     errinfo[EOPNOTSUPP].func = ERR_IGNORE;
37216611Ssam }
37316611Ssam 
3749666Slinton public syserr()
3759666Slinton {
3769666Slinton     ERRINFO *e;
3779666Slinton 
37816611Ssam     if (errno < 0 or errno > sys_nerr) {
37916611Ssam 	fatal("errno %d", errno);
38016611Ssam     } else {
38116611Ssam 	if (errinfo == nil(ERRINFO *)) {
38216611Ssam 	    initErrInfo();
38316611Ssam 	}
38416611Ssam 	e = &(errinfo[errno]);
38516611Ssam 	if (e->func == ERR_CATCH) {
3869666Slinton 	    fatal(sys_errlist[errno]);
38716611Ssam 	} else if (e->func != ERR_IGNORE) {
38816611Ssam 	    (*e->func)();
3899666Slinton 	}
3909666Slinton     }
3919666Slinton }
3929666Slinton 
3939666Slinton /*
39416611Ssam  * Catcherrs' purpose is to initialize the errinfo table, get this module
39516611Ssam  * loaded, and make sure my cerror is loaded (only applicable when this is
39616611Ssam  * in a library).
3979666Slinton  */
3989666Slinton 
3999666Slinton public catcherrs()
4009666Slinton {
4019666Slinton     _mycerror();
40216611Ssam     initErrInfo();
4039666Slinton }
4049666Slinton 
4059666Slinton /*
40618221Slinton  * Turn off the error catching mechanism completely by having all errors
40718221Slinton  * ignored.  This is most useful between a fork and an exec.
40818221Slinton  */
40918221Slinton 
41018221Slinton public nocatcherrs()
41118221Slinton {
41218221Slinton     integer i;
41318221Slinton 
41418221Slinton     for (i = 0; i < sys_nerr; i++) {
41518221Slinton 	errinfo[i].func = ERR_IGNORE;
41618221Slinton     }
41718221Slinton }
41818221Slinton 
41918221Slinton /*
4209666Slinton  * Change the action on receipt of an error.
4219666Slinton  */
4229666Slinton 
4239666Slinton public onsyserr(n, f)
4249666Slinton int n;
4259666Slinton INTFUNC *f;
4269666Slinton {
42716611Ssam     if (errinfo == nil(ERRINFO *)) {
42816611Ssam 	initErrInfo();
42916611Ssam     }
4309666Slinton     errinfo[n].func = f;
4319666Slinton }
4329666Slinton 
4339666Slinton /*
4349666Slinton  * Print the message associated with the given signal.
4359666Slinton  * Like a "perror" for signals.
4369666Slinton  */
4379666Slinton 
4389666Slinton public int sys_nsig = NSIG;
4399666Slinton 
44016611Ssam public psignal(s, n)
4419666Slinton String s;
44216611Ssam integer n;
4439666Slinton {
44416611Ssam     String msg;
44516611Ssam     integer len;
44618538Sralph     extern String sys_siglist[];
4479666Slinton 
44816611Ssam     if (n >= 0 and n < sys_nsig) {
44916611Ssam 	msg = sys_siglist[n];
45016611Ssam     } else {
45116611Ssam 	msg = "Unknown signal";
4529666Slinton     }
45316611Ssam     len = strlen(s);
45416611Ssam     if (len > 0) {
45516611Ssam 	write(2, s, len);
4569666Slinton 	write(2, ": ", 2);
4579666Slinton     }
45816611Ssam     write(2, msg, strlen(msg));
4599666Slinton     write(2, "\n", 1);
4609666Slinton }
4619666Slinton 
4629666Slinton /*
4639666Slinton  * Standard error handling routines.
4649666Slinton  */
4659666Slinton 
4669666Slinton private short nerrs;
4679666Slinton private short nwarnings;
4689666Slinton 
4699666Slinton /*
4709666Slinton  * Main driver of error message reporting.
4719666Slinton  */
4729666Slinton 
4739666Slinton /* VARARGS2 */
4749666Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
4759666Slinton String errname;
47616611Ssam boolean shouldquit;
4779666Slinton String s;
4789666Slinton {
4799666Slinton     fflush(stdout);
4809666Slinton     if (shouldquit and cmdname != nil(String)) {
4819666Slinton 	fprintf(stderr, "%s: ", cmdname);
4829666Slinton     }
4839666Slinton     if (errfilename != nil(Filename)) {
4849666Slinton 	fprintf(stderr, "%s: ", errfilename);
4859666Slinton     }
4869666Slinton     if (errlineno > 0) {
4879666Slinton 	fprintf(stderr, "%d: ", errlineno);
4889666Slinton     }
4899666Slinton     if (errname != nil(String)) {
4909666Slinton 	fprintf(stderr, "%s: ", errname);
4919666Slinton     }
4929666Slinton     fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
4939666Slinton     putc('\n', stderr);
4949666Slinton     if (shouldquit) {
4959666Slinton 	quit(1);
4969666Slinton     }
4979666Slinton }
4989666Slinton 
4999666Slinton /*
5009666Slinton  * For when printf isn't sufficient for printing the error message ...
5019666Slinton  */
5029666Slinton 
5039666Slinton public beginerrmsg()
5049666Slinton {
5059666Slinton     fflush(stdout);
5069666Slinton     if (errfilename != nil(String)) {
5079666Slinton 	fprintf(stderr, "%s: ", errfilename);
5089666Slinton     }
5099666Slinton     if (errlineno > 0) {
5109666Slinton 	fprintf(stderr, "%d: ", errlineno);
5119666Slinton     }
5129666Slinton }
5139666Slinton 
5149666Slinton public enderrmsg()
5159666Slinton {
5169666Slinton     putc('\n', stderr);
5179666Slinton     erecover();
5189666Slinton }
5199666Slinton 
5209666Slinton /*
5219666Slinton  * The messages are listed in increasing order of seriousness.
5229666Slinton  *
5239666Slinton  * First are warnings.
5249666Slinton  */
5259666Slinton 
5269666Slinton /* VARARGS1 */
5279666Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5289666Slinton String s;
5299666Slinton {
5309666Slinton     nwarnings++;
5319666Slinton     errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5329666Slinton }
5339666Slinton 
5349666Slinton /*
5359666Slinton  * Errors are a little worse, they mean something is wrong,
5369666Slinton  * but not so bad that processing can't continue.
5379666Slinton  *
5389666Slinton  * The routine "erecover" is called to recover from the error,
5399666Slinton  * a default routine is provided that does nothing.
5409666Slinton  */
5419666Slinton 
5429666Slinton /* VARARGS1 */
5439666Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5449666Slinton String s;
5459666Slinton {
5469666Slinton     extern erecover();
5479666Slinton 
5489666Slinton     nerrs++;
5499666Slinton     errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5509666Slinton     erecover();
5519666Slinton }
5529666Slinton 
5539666Slinton /*
5549666Slinton  * Non-recoverable user error.
5559666Slinton  */
5569666Slinton 
5579666Slinton /* VARARGS1 */
5589666Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5599666Slinton String s;
5609666Slinton {
5619666Slinton     errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5629666Slinton }
5639666Slinton 
5649666Slinton /*
5659666Slinton  * Panics indicate an internal program error.
5669666Slinton  */
5679666Slinton 
5689666Slinton /* VARARGS1 */
5699666Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
5709666Slinton String s;
5719666Slinton {
5729666Slinton     errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
5739666Slinton }
5749666Slinton 
5759666Slinton short numerrors()
5769666Slinton {
5779666Slinton     short r;
5789666Slinton 
5799666Slinton     r = nerrs;
5809666Slinton     nerrs = 0;
5819666Slinton     return r;
5829666Slinton }
5839666Slinton 
5849666Slinton short numwarnings()
5859666Slinton {
5869666Slinton     short r;
5879666Slinton 
5889666Slinton     r = nwarnings;
5899666Slinton     nwarnings = 0;
5909666Slinton     return r;
5919666Slinton }
5929666Slinton 
5939666Slinton /*
5949666Slinton  * Recover from an error.
5959666Slinton  *
5969666Slinton  * This is the default routine which we aren't using since we have our own.
5979666Slinton  *
5989666Slinton public erecover()
5999666Slinton {
6009666Slinton }
6019666Slinton  *
6029666Slinton  */
6039666Slinton 
6049666Slinton /*
6059666Slinton  * Default way to quit from a program is just to exit.
6069666Slinton  *
6079666Slinton public quit(r)
6089666Slinton int r;
6099666Slinton {
6109666Slinton     exit(r);
6119666Slinton }
6129666Slinton  *
6139666Slinton  */
6149666Slinton 
6159666Slinton /*
6169666Slinton  * Compare n-byte areas pointed to by s1 and s2
6179666Slinton  * if n is 0 then compare up until one has a null byte.
6189666Slinton  */
6199666Slinton 
6209666Slinton public int cmp(s1, s2, n)
6219666Slinton register char *s1, *s2;
6229666Slinton register unsigned int n;
6239666Slinton {
6249666Slinton     if (s1 == nil(char *) || s2 == nil(char *)) {
6259666Slinton 	panic("cmp: nil pointer");
6269666Slinton     }
6279666Slinton     if (n == 0) {
6289666Slinton 	while (*s1 == *s2++) {
6299666Slinton 	    if (*s1++ == '\0') {
6309666Slinton 		return(0);
6319666Slinton 	    }
6329666Slinton 	}
6339666Slinton 	return(*s1 - *(s2-1));
6349666Slinton     } else {
6359666Slinton 	for (; n != 0; n--) {
6369666Slinton 	    if (*s1++ != *s2++) {
6379666Slinton 		return(*(s1-1) - *(s2-1));
6389666Slinton 	    }
6399666Slinton 	}
6409666Slinton 	return(0);
6419666Slinton     }
6429666Slinton }
6439666Slinton 
6449666Slinton /*
6459666Slinton  * Move n bytes from src to dest.
6469666Slinton  * If n is 0 move until a null is found.
6479666Slinton  */
6489666Slinton 
6499666Slinton public mov(src, dest, n)
6509666Slinton register char *src, *dest;
6519666Slinton register unsigned int n;
6529666Slinton {
6539666Slinton     if (src == nil(char *))
6549666Slinton 	panic("mov: nil source");
6559666Slinton     if (dest == nil(char *))
6569666Slinton 	panic("mov: nil destination");
6579666Slinton     if (n != 0) {
6589666Slinton 	for (; n != 0; n--) {
6599666Slinton 	    *dest++ = *src++;
6609666Slinton 	}
6619666Slinton     } else {
6629666Slinton 	while ((*dest++ = *src++) != '\0');
6639666Slinton     }
6649666Slinton }
665