19666Slinton /* Copyright (c) 1982 Regents of the University of California */ 29666Slinton 3*18221Slinton static char sccsid[] = "@(#)library.c 1.6 (Berkeley) 03/01/85"; 416611Ssam 5*18221Slinton static char rcsid[] = "$Header: library.c,v 1.5 84/12/26 10:39:52 linton Exp $"; 6*18221Slinton 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 /* 400*18221Slinton * Turn off the error catching mechanism completely by having all errors 401*18221Slinton * ignored. This is most useful between a fork and an exec. 402*18221Slinton */ 403*18221Slinton 404*18221Slinton public nocatcherrs() 405*18221Slinton { 406*18221Slinton integer i; 407*18221Slinton 408*18221Slinton for (i = 0; i < sys_nerr; i++) { 409*18221Slinton errinfo[i].func = ERR_IGNORE; 410*18221Slinton } 411*18221Slinton } 412*18221Slinton 413*18221Slinton /* 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 public String sys_siglist[] = { 4349666Slinton "no signal", 4359666Slinton "hangup", 4369666Slinton "interrupt", 4379666Slinton "quit", 4389666Slinton "illegal instruction", 4399666Slinton "trace trap", 4409666Slinton "IOT instruction", 4419666Slinton "EMT instruction", 4429666Slinton "floating point exception", 4439666Slinton "kill", 4449666Slinton "bus error", 4459666Slinton "segmentation violation", 4469666Slinton "bad argument to system call", 4479666Slinton "broken pipe", 4489666Slinton "alarm clock", 4499666Slinton "soft kill", 4509666Slinton "urgent I/O condition", 4519666Slinton "stop signal not from tty", 4529666Slinton "stop signal from tty", 4539666Slinton "continue", 4549666Slinton "child termination", 4559666Slinton "stop (tty input)", 4569666Slinton "stop (tty output)", 4579666Slinton "possible input/output", 4589666Slinton "exceeded CPU time limit", 4599666Slinton "exceeded file size limit", 4609666Slinton nil(String) 4619666Slinton }; 4629666Slinton 46316611Ssam public psignal(s, n) 4649666Slinton String s; 46516611Ssam integer n; 4669666Slinton { 46716611Ssam String msg; 46816611Ssam integer len; 4699666Slinton 47016611Ssam if (n >= 0 and n < sys_nsig) { 47116611Ssam msg = sys_siglist[n]; 47216611Ssam } else { 47316611Ssam msg = "Unknown signal"; 4749666Slinton } 47516611Ssam len = strlen(s); 47616611Ssam if (len > 0) { 47716611Ssam write(2, s, len); 4789666Slinton write(2, ": ", 2); 4799666Slinton } 48016611Ssam write(2, msg, strlen(msg)); 4819666Slinton write(2, "\n", 1); 4829666Slinton } 4839666Slinton 4849666Slinton /* 4859666Slinton * Standard error handling routines. 4869666Slinton */ 4879666Slinton 4889666Slinton private short nerrs; 4899666Slinton private short nwarnings; 4909666Slinton 4919666Slinton /* 4929666Slinton * Main driver of error message reporting. 4939666Slinton */ 4949666Slinton 4959666Slinton /* VARARGS2 */ 4969666Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) 4979666Slinton String errname; 49816611Ssam boolean shouldquit; 4999666Slinton String s; 5009666Slinton { 5019666Slinton fflush(stdout); 5029666Slinton if (shouldquit and cmdname != nil(String)) { 5039666Slinton fprintf(stderr, "%s: ", cmdname); 5049666Slinton } 5059666Slinton if (errfilename != nil(Filename)) { 5069666Slinton fprintf(stderr, "%s: ", errfilename); 5079666Slinton } 5089666Slinton if (errlineno > 0) { 5099666Slinton fprintf(stderr, "%d: ", errlineno); 5109666Slinton } 5119666Slinton if (errname != nil(String)) { 5129666Slinton fprintf(stderr, "%s: ", errname); 5139666Slinton } 5149666Slinton fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 5159666Slinton putc('\n', stderr); 5169666Slinton if (shouldquit) { 5179666Slinton quit(1); 5189666Slinton } 5199666Slinton } 5209666Slinton 5219666Slinton /* 5229666Slinton * For when printf isn't sufficient for printing the error message ... 5239666Slinton */ 5249666Slinton 5259666Slinton public beginerrmsg() 5269666Slinton { 5279666Slinton fflush(stdout); 5289666Slinton if (errfilename != nil(String)) { 5299666Slinton fprintf(stderr, "%s: ", errfilename); 5309666Slinton } 5319666Slinton if (errlineno > 0) { 5329666Slinton fprintf(stderr, "%d: ", errlineno); 5339666Slinton } 5349666Slinton } 5359666Slinton 5369666Slinton public enderrmsg() 5379666Slinton { 5389666Slinton putc('\n', stderr); 5399666Slinton erecover(); 5409666Slinton } 5419666Slinton 5429666Slinton /* 5439666Slinton * The messages are listed in increasing order of seriousness. 5449666Slinton * 5459666Slinton * First are warnings. 5469666Slinton */ 5479666Slinton 5489666Slinton /* VARARGS1 */ 5499666Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 5509666Slinton String s; 5519666Slinton { 5529666Slinton nwarnings++; 5539666Slinton errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 5549666Slinton } 5559666Slinton 5569666Slinton /* 5579666Slinton * Errors are a little worse, they mean something is wrong, 5589666Slinton * but not so bad that processing can't continue. 5599666Slinton * 5609666Slinton * The routine "erecover" is called to recover from the error, 5619666Slinton * a default routine is provided that does nothing. 5629666Slinton */ 5639666Slinton 5649666Slinton /* VARARGS1 */ 5659666Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 5669666Slinton String s; 5679666Slinton { 5689666Slinton extern erecover(); 5699666Slinton 5709666Slinton nerrs++; 5719666Slinton errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 5729666Slinton erecover(); 5739666Slinton } 5749666Slinton 5759666Slinton /* 5769666Slinton * Non-recoverable user error. 5779666Slinton */ 5789666Slinton 5799666Slinton /* VARARGS1 */ 5809666Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 5819666Slinton String s; 5829666Slinton { 5839666Slinton errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 5849666Slinton } 5859666Slinton 5869666Slinton /* 5879666Slinton * Panics indicate an internal program error. 5889666Slinton */ 5899666Slinton 5909666Slinton /* VARARGS1 */ 5919666Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 5929666Slinton String s; 5939666Slinton { 5949666Slinton errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 5959666Slinton } 5969666Slinton 5979666Slinton short numerrors() 5989666Slinton { 5999666Slinton short r; 6009666Slinton 6019666Slinton r = nerrs; 6029666Slinton nerrs = 0; 6039666Slinton return r; 6049666Slinton } 6059666Slinton 6069666Slinton short numwarnings() 6079666Slinton { 6089666Slinton short r; 6099666Slinton 6109666Slinton r = nwarnings; 6119666Slinton nwarnings = 0; 6129666Slinton return r; 6139666Slinton } 6149666Slinton 6159666Slinton /* 6169666Slinton * Recover from an error. 6179666Slinton * 6189666Slinton * This is the default routine which we aren't using since we have our own. 6199666Slinton * 6209666Slinton public erecover() 6219666Slinton { 6229666Slinton } 6239666Slinton * 6249666Slinton */ 6259666Slinton 6269666Slinton /* 6279666Slinton * Default way to quit from a program is just to exit. 6289666Slinton * 6299666Slinton public quit(r) 6309666Slinton int r; 6319666Slinton { 6329666Slinton exit(r); 6339666Slinton } 6349666Slinton * 6359666Slinton */ 6369666Slinton 6379666Slinton /* 6389666Slinton * Compare n-byte areas pointed to by s1 and s2 6399666Slinton * if n is 0 then compare up until one has a null byte. 6409666Slinton */ 6419666Slinton 6429666Slinton public int cmp(s1, s2, n) 6439666Slinton register char *s1, *s2; 6449666Slinton register unsigned int n; 6459666Slinton { 6469666Slinton if (s1 == nil(char *) || s2 == nil(char *)) { 6479666Slinton panic("cmp: nil pointer"); 6489666Slinton } 6499666Slinton if (n == 0) { 6509666Slinton while (*s1 == *s2++) { 6519666Slinton if (*s1++ == '\0') { 6529666Slinton return(0); 6539666Slinton } 6549666Slinton } 6559666Slinton return(*s1 - *(s2-1)); 6569666Slinton } else { 6579666Slinton for (; n != 0; n--) { 6589666Slinton if (*s1++ != *s2++) { 6599666Slinton return(*(s1-1) - *(s2-1)); 6609666Slinton } 6619666Slinton } 6629666Slinton return(0); 6639666Slinton } 6649666Slinton } 6659666Slinton 6669666Slinton /* 6679666Slinton * Move n bytes from src to dest. 6689666Slinton * If n is 0 move until a null is found. 6699666Slinton */ 6709666Slinton 6719666Slinton public mov(src, dest, n) 6729666Slinton register char *src, *dest; 6739666Slinton register unsigned int n; 6749666Slinton { 6759666Slinton if (src == nil(char *)) 6769666Slinton panic("mov: nil source"); 6779666Slinton if (dest == nil(char *)) 6789666Slinton panic("mov: nil destination"); 6799666Slinton if (n != 0) { 6809666Slinton for (; n != 0; n--) { 6819666Slinton *dest++ = *src++; 6829666Slinton } 6839666Slinton } else { 6849666Slinton while ((*dest++ = *src++) != '\0'); 6859666Slinton } 6869666Slinton } 687