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