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