1*9666Slinton /* Copyright (c) 1982 Regents of the University of California */ 2*9666Slinton 3*9666Slinton /* static char sccsid[] = "@(#)library.c 1.1 9/2/82"; */ 4*9666Slinton 5*9666Slinton /* 6*9666Slinton * General purpose routines. 7*9666Slinton */ 8*9666Slinton 9*9666Slinton #include <stdio.h> 10*9666Slinton #include <errno.h> 11*9666Slinton #include <signal.h> 12*9666Slinton 13*9666Slinton #define public 14*9666Slinton #define private static 15*9666Slinton #define and && 16*9666Slinton #define or || 17*9666Slinton #define not ! 18*9666Slinton #define ord(enumcon) ((int) enumcon) 19*9666Slinton #define nil(type) ((type) 0) 20*9666Slinton 21*9666Slinton typedef enum { FALSE, TRUE } Boolean; 22*9666Slinton typedef char *String; 23*9666Slinton typedef FILE *File; 24*9666Slinton typedef String Filename; 25*9666Slinton 26*9666Slinton #undef FILE 27*9666Slinton 28*9666Slinton /* 29*9666Slinton * Definitions of standard C library routines that aren't in the 30*9666Slinton * standard I/O library, but which are generally useful. 31*9666Slinton */ 32*9666Slinton 33*9666Slinton extern long atol(); /* ascii to long */ 34*9666Slinton extern double atof(); /* ascii to floating point */ 35*9666Slinton extern char *mktemp(); /* make a temporary file name */ 36*9666Slinton 37*9666Slinton String cmdname; /* name of command for error messages */ 38*9666Slinton Filename errfilename; /* current file associated with error */ 39*9666Slinton short errlineno; /* line number associated with error */ 40*9666Slinton 41*9666Slinton /* 42*9666Slinton * Definitions for doing memory allocation. 43*9666Slinton */ 44*9666Slinton 45*9666Slinton extern char *malloc(); 46*9666Slinton 47*9666Slinton #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type))) 48*9666Slinton #define dispose(p) { free((char *) p); p = 0; } 49*9666Slinton 50*9666Slinton /* 51*9666Slinton * Macros for doing freads + fwrites. 52*9666Slinton */ 53*9666Slinton 54*9666Slinton #define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp) 55*9666Slinton #define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp) 56*9666Slinton 57*9666Slinton /* 58*9666Slinton * String definitions. 59*9666Slinton */ 60*9666Slinton 61*9666Slinton extern String strcpy(), index(), rindex(); 62*9666Slinton extern int strlen(); 63*9666Slinton 64*9666Slinton #define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s) 65*9666Slinton #define streq(s1, s2) (strcmp(s1, s2) == 0) 66*9666Slinton 67*9666Slinton typedef int INTFUNC(); 68*9666Slinton 69*9666Slinton typedef struct { 70*9666Slinton INTFUNC *func; 71*9666Slinton } ERRINFO; 72*9666Slinton 73*9666Slinton #define ERR_IGNORE ((INTFUNC *) 0) 74*9666Slinton #define ERR_CATCH ((INTFUNC *) 1) 75*9666Slinton 76*9666Slinton /* 77*9666Slinton * Call a program. 78*9666Slinton * 79*9666Slinton * Four entries: 80*9666Slinton * 81*9666Slinton * call, callv - call a program and wait for it, returning status 82*9666Slinton * back, backv - call a program and don't wait, returning process id 83*9666Slinton * 84*9666Slinton * The command's standard input and output are passed as FILE's. 85*9666Slinton */ 86*9666Slinton 87*9666Slinton 88*9666Slinton #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */ 89*9666Slinton #define BADEXEC 127 /* exec fails */ 90*9666Slinton 91*9666Slinton #define ischild(pid) ((pid) == 0) 92*9666Slinton 93*9666Slinton /* VARARGS3 */ 94*9666Slinton public int call(name, in, out, args) 95*9666Slinton String name; 96*9666Slinton File in; 97*9666Slinton File out; 98*9666Slinton String args; 99*9666Slinton { 100*9666Slinton String *ap, *argp; 101*9666Slinton String argv[MAXNARGS]; 102*9666Slinton 103*9666Slinton argp = &argv[0]; 104*9666Slinton *argp++ = name; 105*9666Slinton ap = &args; 106*9666Slinton while (*ap != nil(String)) { 107*9666Slinton *argp++ = *ap++; 108*9666Slinton } 109*9666Slinton *argp = nil(String); 110*9666Slinton return callv(name, in, out, argv); 111*9666Slinton } 112*9666Slinton 113*9666Slinton /* VARARGS3 */ 114*9666Slinton public int back(name, in, out, args) 115*9666Slinton String name; 116*9666Slinton File in; 117*9666Slinton File out; 118*9666Slinton String args; 119*9666Slinton { 120*9666Slinton String *ap, *argp; 121*9666Slinton String argv[MAXNARGS]; 122*9666Slinton 123*9666Slinton argp = &argv[0]; 124*9666Slinton *argp++ = name; 125*9666Slinton ap = &args; 126*9666Slinton while (*ap != nil(String)) { 127*9666Slinton *argp++ = *ap++; 128*9666Slinton } 129*9666Slinton *argp = nil(String); 130*9666Slinton return backv(name, in, out, argv); 131*9666Slinton } 132*9666Slinton 133*9666Slinton public int callv(name, in, out, argv) 134*9666Slinton String name; 135*9666Slinton File in; 136*9666Slinton File out; 137*9666Slinton String *argv; 138*9666Slinton { 139*9666Slinton int pid, status; 140*9666Slinton 141*9666Slinton pid = backv(name, in, out, argv); 142*9666Slinton pwait(pid, &status); 143*9666Slinton return status; 144*9666Slinton } 145*9666Slinton 146*9666Slinton public int backv(name, in, out, argv) 147*9666Slinton String name; 148*9666Slinton File in; 149*9666Slinton File out; 150*9666Slinton String *argv; 151*9666Slinton { 152*9666Slinton int pid; 153*9666Slinton 154*9666Slinton fflush(stdout); 155*9666Slinton if (ischild(pid = fork())) { 156*9666Slinton fswap(0, fileno(in)); 157*9666Slinton fswap(1, fileno(out)); 158*9666Slinton onsyserr(EACCES, ERR_IGNORE); 159*9666Slinton execvp(name, argv); 160*9666Slinton _exit(BADEXEC); 161*9666Slinton } 162*9666Slinton return pid; 163*9666Slinton } 164*9666Slinton 165*9666Slinton /* 166*9666Slinton * Swap file numbers so as to redirect standard input and output. 167*9666Slinton */ 168*9666Slinton 169*9666Slinton private fswap(oldfd, newfd) 170*9666Slinton int oldfd; 171*9666Slinton int newfd; 172*9666Slinton { 173*9666Slinton if (oldfd != newfd) { 174*9666Slinton close(oldfd); 175*9666Slinton dup(newfd); 176*9666Slinton close(newfd); 177*9666Slinton } 178*9666Slinton } 179*9666Slinton 180*9666Slinton /* 181*9666Slinton * Invoke a shell on a command line. 182*9666Slinton */ 183*9666Slinton 184*9666Slinton #define DEF_SHELL "csh" 185*9666Slinton 186*9666Slinton public shell(s) 187*9666Slinton String s; 188*9666Slinton { 189*9666Slinton extern String getenv(); 190*9666Slinton String sh; 191*9666Slinton 192*9666Slinton if ((sh = getenv("SHELL")) == nil(String)) { 193*9666Slinton sh = DEF_SHELL; 194*9666Slinton } 195*9666Slinton if (s != nil(String) and *s != '\0') { 196*9666Slinton call(sh, stdin, stdout, "-c", s, 0); 197*9666Slinton } else { 198*9666Slinton call(sh, stdin, stdout, 0); 199*9666Slinton } 200*9666Slinton } 201*9666Slinton 202*9666Slinton /* 203*9666Slinton * Wait for a process the right way. We wait for a particular 204*9666Slinton * process and if any others come along in between, we remember them 205*9666Slinton * in case they are eventually waited for. 206*9666Slinton * 207*9666Slinton * This routine is not very efficient when the number of processes 208*9666Slinton * to be remembered is large. 209*9666Slinton */ 210*9666Slinton 211*9666Slinton typedef struct pidlist { 212*9666Slinton int pid; 213*9666Slinton int status; 214*9666Slinton struct pidlist *next; 215*9666Slinton } Pidlist; 216*9666Slinton 217*9666Slinton private Pidlist *pidlist, *pfind(); 218*9666Slinton 219*9666Slinton public pwait(pid, statusp) 220*9666Slinton int pid, *statusp; 221*9666Slinton { 222*9666Slinton Pidlist *p; 223*9666Slinton int pnum, status; 224*9666Slinton 225*9666Slinton p = pfind(pid); 226*9666Slinton if (p != nil(Pidlist *)) { 227*9666Slinton *statusp = p->status; 228*9666Slinton dispose(p); 229*9666Slinton return; 230*9666Slinton } 231*9666Slinton while ((pnum = wait(&status)) != pid && pnum >= 0) { 232*9666Slinton p = alloc(1, Pidlist); 233*9666Slinton p->pid = pnum; 234*9666Slinton p->status = status; 235*9666Slinton p->next = pidlist; 236*9666Slinton pidlist = p; 237*9666Slinton } 238*9666Slinton if (pnum < 0) { 239*9666Slinton p = pfind(pid); 240*9666Slinton if (p == nil(Pidlist *)) { 241*9666Slinton panic("pwait: pid %d not found", pid); 242*9666Slinton } 243*9666Slinton *statusp = p->status; 244*9666Slinton dispose(p); 245*9666Slinton } else { 246*9666Slinton *statusp = status; 247*9666Slinton } 248*9666Slinton } 249*9666Slinton 250*9666Slinton /* 251*9666Slinton * Look for the given process id on the pidlist. 252*9666Slinton * 253*9666Slinton * Unlink it from list if found. 254*9666Slinton */ 255*9666Slinton 256*9666Slinton private Pidlist *pfind(pid) 257*9666Slinton int pid; 258*9666Slinton { 259*9666Slinton register Pidlist *p, *prev; 260*9666Slinton 261*9666Slinton prev = nil(Pidlist *); 262*9666Slinton for (p = pidlist; p != nil(Pidlist *); p = p->next) { 263*9666Slinton if (p->pid == pid) { 264*9666Slinton break; 265*9666Slinton } 266*9666Slinton prev = p; 267*9666Slinton } 268*9666Slinton if (p != nil(Pidlist *)) { 269*9666Slinton if (prev == nil(Pidlist *)) { 270*9666Slinton pidlist = p->next; 271*9666Slinton } else { 272*9666Slinton prev->next = p->next; 273*9666Slinton } 274*9666Slinton } 275*9666Slinton return p; 276*9666Slinton } 277*9666Slinton 278*9666Slinton /* 279*9666Slinton * System call error handler. 280*9666Slinton * 281*9666Slinton * The syserr routine is called when a system call is about to 282*9666Slinton * set the c-bit to report an error. Certain errors are caught 283*9666Slinton * and cause the process to print a message and immediately exit. 284*9666Slinton */ 285*9666Slinton 286*9666Slinton extern int sys_nerr; 287*9666Slinton extern char *sys_errlist[]; 288*9666Slinton 289*9666Slinton /* 290*9666Slinton * Before calling syserr, the integer errno is set to contain the 291*9666Slinton * number of the error. The routine "_mycerror" is a dummy which 292*9666Slinton * is used to force the loader to get my version of cerror rather 293*9666Slinton * than the usual one. 294*9666Slinton */ 295*9666Slinton 296*9666Slinton extern int errno; 297*9666Slinton extern _mycerror(); 298*9666Slinton 299*9666Slinton /* 300*9666Slinton * Default error handling. 301*9666Slinton */ 302*9666Slinton 303*9666Slinton private ERRINFO errinfo[] ={ 304*9666Slinton /* no error */ ERR_IGNORE, 305*9666Slinton /* EPERM */ ERR_IGNORE, 306*9666Slinton /* ENOENT */ ERR_IGNORE, 307*9666Slinton /* ESRCH */ ERR_IGNORE, 308*9666Slinton /* EINTR */ ERR_CATCH, 309*9666Slinton /* EIO */ ERR_CATCH, 310*9666Slinton /* ENXIO */ ERR_CATCH, 311*9666Slinton /* E2BIG */ ERR_CATCH, 312*9666Slinton /* ENOEXEC */ ERR_CATCH, 313*9666Slinton /* EBADF */ ERR_IGNORE, 314*9666Slinton /* ECHILD */ ERR_CATCH, 315*9666Slinton /* EAGAIN */ ERR_CATCH, 316*9666Slinton /* ENOMEM */ ERR_CATCH, 317*9666Slinton /* EACCES */ ERR_CATCH, 318*9666Slinton /* EFAULT */ ERR_CATCH, 319*9666Slinton /* ENOTBLK */ ERR_CATCH, 320*9666Slinton /* EBUSY */ ERR_CATCH, 321*9666Slinton /* EEXIST */ ERR_CATCH, 322*9666Slinton /* EXDEV */ ERR_CATCH, 323*9666Slinton /* ENODEV */ ERR_CATCH, 324*9666Slinton /* ENOTDIR */ ERR_CATCH, 325*9666Slinton /* EISDIR */ ERR_CATCH, 326*9666Slinton /* EINVAL */ ERR_CATCH, 327*9666Slinton /* ENFILE */ ERR_CATCH, 328*9666Slinton /* EMFILE */ ERR_CATCH, 329*9666Slinton /* ENOTTY */ ERR_IGNORE, 330*9666Slinton /* ETXTBSY */ ERR_CATCH, 331*9666Slinton /* EFBIG */ ERR_CATCH, 332*9666Slinton /* ENOSPC */ ERR_CATCH, 333*9666Slinton /* ESPIPE */ ERR_CATCH, 334*9666Slinton /* EROFS */ ERR_CATCH, 335*9666Slinton /* EMLINK */ ERR_CATCH, 336*9666Slinton /* EPIPE */ ERR_CATCH, 337*9666Slinton /* EDOM */ ERR_CATCH, 338*9666Slinton /* ERANGE */ ERR_CATCH, 339*9666Slinton /* EQUOT */ ERR_CATCH, 340*9666Slinton }; 341*9666Slinton 342*9666Slinton public syserr() 343*9666Slinton { 344*9666Slinton ERRINFO *e; 345*9666Slinton 346*9666Slinton e = &errinfo[errno]; 347*9666Slinton if (e->func == ERR_CATCH) { 348*9666Slinton if (errno < sys_nerr) { 349*9666Slinton fatal(sys_errlist[errno]); 350*9666Slinton } else { 351*9666Slinton fatal("errno %d", errno); 352*9666Slinton } 353*9666Slinton } else if (e->func != ERR_IGNORE) { 354*9666Slinton (*e->func)(); 355*9666Slinton } 356*9666Slinton } 357*9666Slinton 358*9666Slinton /* 359*9666Slinton * Catcherrs only purpose is to get this module loaded and make 360*9666Slinton * sure my cerror is loaded (only applicable when this is in a library). 361*9666Slinton */ 362*9666Slinton 363*9666Slinton public catcherrs() 364*9666Slinton { 365*9666Slinton _mycerror(); 366*9666Slinton } 367*9666Slinton 368*9666Slinton /* 369*9666Slinton * Change the action on receipt of an error. 370*9666Slinton */ 371*9666Slinton 372*9666Slinton public onsyserr(n, f) 373*9666Slinton int n; 374*9666Slinton INTFUNC *f; 375*9666Slinton { 376*9666Slinton errinfo[n].func = f; 377*9666Slinton } 378*9666Slinton 379*9666Slinton /* 380*9666Slinton * Print the message associated with the given signal. 381*9666Slinton * Like a "perror" for signals. 382*9666Slinton */ 383*9666Slinton 384*9666Slinton public int sys_nsig = NSIG; 385*9666Slinton public String sys_siglist[] = { 386*9666Slinton "no signal", 387*9666Slinton "hangup", 388*9666Slinton "interrupt", 389*9666Slinton "quit", 390*9666Slinton "illegal instruction", 391*9666Slinton "trace trap", 392*9666Slinton "IOT instruction", 393*9666Slinton "EMT instruction", 394*9666Slinton "floating point exception", 395*9666Slinton "kill", 396*9666Slinton "bus error", 397*9666Slinton "segmentation violation", 398*9666Slinton "bad argument to system call", 399*9666Slinton "broken pipe", 400*9666Slinton "alarm clock", 401*9666Slinton "soft kill", 402*9666Slinton "urgent I/O condition", 403*9666Slinton "stop signal not from tty", 404*9666Slinton "stop signal from tty", 405*9666Slinton "continue", 406*9666Slinton "child termination", 407*9666Slinton "stop (tty input)", 408*9666Slinton "stop (tty output)", 409*9666Slinton "possible input/output", 410*9666Slinton "exceeded CPU time limit", 411*9666Slinton "exceeded file size limit", 412*9666Slinton nil(String) 413*9666Slinton }; 414*9666Slinton 415*9666Slinton public psig(s) 416*9666Slinton String s; 417*9666Slinton { 418*9666Slinton String c; 419*9666Slinton int n; 420*9666Slinton 421*9666Slinton c = "Unknown signal"; 422*9666Slinton if (errno < sys_nsig) { 423*9666Slinton c = sys_errlist[errno]; 424*9666Slinton } 425*9666Slinton n = strlen(s); 426*9666Slinton if (n > 0) { 427*9666Slinton write(2, s, n); 428*9666Slinton write(2, ": ", 2); 429*9666Slinton } 430*9666Slinton write(2, c, strlen(c)); 431*9666Slinton write(2, "\n", 1); 432*9666Slinton } 433*9666Slinton 434*9666Slinton /* 435*9666Slinton * Standard error handling routines. 436*9666Slinton */ 437*9666Slinton 438*9666Slinton private short nerrs; 439*9666Slinton private short nwarnings; 440*9666Slinton 441*9666Slinton /* 442*9666Slinton * Main driver of error message reporting. 443*9666Slinton */ 444*9666Slinton 445*9666Slinton /* VARARGS2 */ 446*9666Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) 447*9666Slinton String errname; 448*9666Slinton Boolean shouldquit; 449*9666Slinton String s; 450*9666Slinton { 451*9666Slinton fflush(stdout); 452*9666Slinton if (shouldquit and cmdname != nil(String)) { 453*9666Slinton fprintf(stderr, "%s: ", cmdname); 454*9666Slinton } 455*9666Slinton if (errfilename != nil(Filename)) { 456*9666Slinton fprintf(stderr, "%s: ", errfilename); 457*9666Slinton } 458*9666Slinton if (errlineno > 0) { 459*9666Slinton fprintf(stderr, "%d: ", errlineno); 460*9666Slinton } 461*9666Slinton if (errname != nil(String)) { 462*9666Slinton fprintf(stderr, "%s: ", errname); 463*9666Slinton } 464*9666Slinton fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 465*9666Slinton putc('\n', stderr); 466*9666Slinton if (shouldquit) { 467*9666Slinton quit(1); 468*9666Slinton } 469*9666Slinton } 470*9666Slinton 471*9666Slinton /* 472*9666Slinton * For when printf isn't sufficient for printing the error message ... 473*9666Slinton */ 474*9666Slinton 475*9666Slinton public beginerrmsg() 476*9666Slinton { 477*9666Slinton fflush(stdout); 478*9666Slinton if (errfilename != nil(String)) { 479*9666Slinton fprintf(stderr, "%s: ", errfilename); 480*9666Slinton } 481*9666Slinton if (errlineno > 0) { 482*9666Slinton fprintf(stderr, "%d: ", errlineno); 483*9666Slinton } 484*9666Slinton } 485*9666Slinton 486*9666Slinton public enderrmsg() 487*9666Slinton { 488*9666Slinton putc('\n', stderr); 489*9666Slinton erecover(); 490*9666Slinton } 491*9666Slinton 492*9666Slinton /* 493*9666Slinton * The messages are listed in increasing order of seriousness. 494*9666Slinton * 495*9666Slinton * First are warnings. 496*9666Slinton */ 497*9666Slinton 498*9666Slinton /* VARARGS1 */ 499*9666Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 500*9666Slinton String s; 501*9666Slinton { 502*9666Slinton nwarnings++; 503*9666Slinton errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 504*9666Slinton } 505*9666Slinton 506*9666Slinton /* 507*9666Slinton * Errors are a little worse, they mean something is wrong, 508*9666Slinton * but not so bad that processing can't continue. 509*9666Slinton * 510*9666Slinton * The routine "erecover" is called to recover from the error, 511*9666Slinton * a default routine is provided that does nothing. 512*9666Slinton */ 513*9666Slinton 514*9666Slinton /* VARARGS1 */ 515*9666Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 516*9666Slinton String s; 517*9666Slinton { 518*9666Slinton extern erecover(); 519*9666Slinton 520*9666Slinton nerrs++; 521*9666Slinton errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 522*9666Slinton erecover(); 523*9666Slinton } 524*9666Slinton 525*9666Slinton /* 526*9666Slinton * Non-recoverable user error. 527*9666Slinton */ 528*9666Slinton 529*9666Slinton /* VARARGS1 */ 530*9666Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 531*9666Slinton String s; 532*9666Slinton { 533*9666Slinton errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 534*9666Slinton } 535*9666Slinton 536*9666Slinton /* 537*9666Slinton * Panics indicate an internal program error. 538*9666Slinton */ 539*9666Slinton 540*9666Slinton /* VARARGS1 */ 541*9666Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 542*9666Slinton String s; 543*9666Slinton { 544*9666Slinton errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 545*9666Slinton } 546*9666Slinton 547*9666Slinton short numerrors() 548*9666Slinton { 549*9666Slinton short r; 550*9666Slinton 551*9666Slinton r = nerrs; 552*9666Slinton nerrs = 0; 553*9666Slinton return r; 554*9666Slinton } 555*9666Slinton 556*9666Slinton short numwarnings() 557*9666Slinton { 558*9666Slinton short r; 559*9666Slinton 560*9666Slinton r = nwarnings; 561*9666Slinton nwarnings = 0; 562*9666Slinton return r; 563*9666Slinton } 564*9666Slinton 565*9666Slinton /* 566*9666Slinton * Recover from an error. 567*9666Slinton * 568*9666Slinton * This is the default routine which we aren't using since we have our own. 569*9666Slinton * 570*9666Slinton public erecover() 571*9666Slinton { 572*9666Slinton } 573*9666Slinton * 574*9666Slinton */ 575*9666Slinton 576*9666Slinton /* 577*9666Slinton * Default way to quit from a program is just to exit. 578*9666Slinton * 579*9666Slinton public quit(r) 580*9666Slinton int r; 581*9666Slinton { 582*9666Slinton exit(r); 583*9666Slinton } 584*9666Slinton * 585*9666Slinton */ 586*9666Slinton 587*9666Slinton /* 588*9666Slinton * Compare n-byte areas pointed to by s1 and s2 589*9666Slinton * if n is 0 then compare up until one has a null byte. 590*9666Slinton */ 591*9666Slinton 592*9666Slinton public int cmp(s1, s2, n) 593*9666Slinton register char *s1, *s2; 594*9666Slinton register unsigned int n; 595*9666Slinton { 596*9666Slinton if (s1 == nil(char *) || s2 == nil(char *)) { 597*9666Slinton panic("cmp: nil pointer"); 598*9666Slinton } 599*9666Slinton if (n == 0) { 600*9666Slinton while (*s1 == *s2++) { 601*9666Slinton if (*s1++ == '\0') { 602*9666Slinton return(0); 603*9666Slinton } 604*9666Slinton } 605*9666Slinton return(*s1 - *(s2-1)); 606*9666Slinton } else { 607*9666Slinton for (; n != 0; n--) { 608*9666Slinton if (*s1++ != *s2++) { 609*9666Slinton return(*(s1-1) - *(s2-1)); 610*9666Slinton } 611*9666Slinton } 612*9666Slinton return(0); 613*9666Slinton } 614*9666Slinton } 615*9666Slinton 616*9666Slinton /* 617*9666Slinton * Move n bytes from src to dest. 618*9666Slinton * If n is 0 move until a null is found. 619*9666Slinton */ 620*9666Slinton 621*9666Slinton public mov(src, dest, n) 622*9666Slinton register char *src, *dest; 623*9666Slinton register unsigned int n; 624*9666Slinton { 625*9666Slinton if (src == nil(char *)) 626*9666Slinton panic("mov: nil source"); 627*9666Slinton if (dest == nil(char *)) 628*9666Slinton panic("mov: nil destination"); 629*9666Slinton if (n != 0) { 630*9666Slinton for (; n != 0; n--) { 631*9666Slinton *dest++ = *src++; 632*9666Slinton } 633*9666Slinton } else { 634*9666Slinton while ((*dest++ = *src++) != '\0'); 635*9666Slinton } 636*9666Slinton } 637