Commit | Line | Data |
---|---|---|
2ae9f53f | 1 | #ifndef lint |
46053c99 | 2 | static char *sccsid = "@(#)lex.c 2.17 (Berkeley) %G%"; |
2ae9f53f | 3 | #endif |
ac72cd41 KS |
4 | |
5 | #include "rcv.h" | |
fb4186f8 | 6 | #include <sys/stat.h> |
ac72cd41 KS |
7 | |
8 | /* | |
9 | * Mail -- a mail program | |
10 | * | |
11 | * Lexical processing of commands. | |
12 | */ | |
13 | ||
07c257b5 | 14 | char *prompt = "& "; |
e5717bff KS |
15 | |
16 | /* | |
17 | * Set up editing on the given file name. | |
18 | * If isedit is true, we are considered to be editing the file, | |
19 | * otherwise we are reading our mail which has signficance for | |
20 | * mbox and so forth. | |
21 | */ | |
22 | ||
23 | setfile(name, isedit) | |
24 | char *name; | |
25 | { | |
26 | FILE *ibuf; | |
27 | int i; | |
fb4186f8 | 28 | struct stat stb; |
e5717bff KS |
29 | static int shudclob; |
30 | static char efile[128]; | |
31 | extern char tempMesg[]; | |
e5717bff | 32 | |
531fa87e | 33 | if ((ibuf = fopen(name, "r")) == NULL) |
e5717bff | 34 | return(-1); |
fb4186f8 RC |
35 | if (!edit) { |
36 | if (fstat(fileno(ibuf), &stb) < 0) { | |
37 | perror(name); | |
38 | exit(1); | |
39 | } | |
40 | if (stb.st_size == 0) | |
41 | return(-1); | |
42 | } | |
e5717bff KS |
43 | |
44 | /* | |
45 | * Looks like all will be well. We must now relinquish our | |
177b7a73 | 46 | * hold on the current set of stuff. Must hold signals |
e5717bff KS |
47 | * while we are reading the new file, else we will ruin |
48 | * the message[] data structure. | |
49 | */ | |
50 | ||
177b7a73 | 51 | holdsigs(); |
e5717bff KS |
52 | if (shudclob) { |
53 | if (edit) | |
54 | edstop(); | |
55 | else | |
56 | quit(); | |
57 | } | |
58 | ||
59 | /* | |
60 | * Copy the messages into /tmp | |
61 | * and set pointers. | |
62 | */ | |
63 | ||
64 | readonly = 0; | |
65 | if ((i = open(name, 1)) < 0) | |
66 | readonly++; | |
67 | else | |
68 | close(i); | |
69 | if (shudclob) { | |
70 | fclose(itf); | |
71 | fclose(otf); | |
72 | } | |
73 | shudclob = 1; | |
74 | edit = isedit; | |
75 | strncpy(efile, name, 128); | |
76 | editfile = efile; | |
128ec005 KS |
77 | if (name != mailname) |
78 | strcpy(mailname, name); | |
e5717bff KS |
79 | mailsize = fsize(ibuf); |
80 | if ((otf = fopen(tempMesg, "w")) == NULL) { | |
81 | perror(tempMesg); | |
82 | exit(1); | |
83 | } | |
84 | if ((itf = fopen(tempMesg, "r")) == NULL) { | |
85 | perror(tempMesg); | |
86 | exit(1); | |
87 | } | |
88 | remove(tempMesg); | |
89 | setptr(ibuf); | |
90 | setmsize(msgCount); | |
91 | fclose(ibuf); | |
177b7a73 | 92 | relsesigs(); |
335704ca | 93 | sawcom = 0; |
e5717bff KS |
94 | return(0); |
95 | } | |
ac72cd41 KS |
96 | |
97 | /* | |
98 | * Interpret user commands one by one. If standard input is not a tty, | |
99 | * print no prompt. | |
100 | */ | |
101 | ||
102 | int *msgvec; | |
103 | ||
104 | commands() | |
105 | { | |
7a05656e | 106 | int eofloop, shudprompt, stop(); |
ac72cd41 KS |
107 | register int n; |
108 | char linebuf[LINESIZE]; | |
de274ec3 | 109 | int hangup(), contin(); |
ac72cd41 | 110 | |
ea394d88 | 111 | # ifdef VMUNIX |
d28ecfdf | 112 | sigset(SIGCONT, SIG_DFL); |
ea394d88 | 113 | # endif VMUNIX |
7a05656e | 114 | if (rcvmode && !sourcing) { |
726c3356 KS |
115 | if (sigset(SIGINT, SIG_IGN) != SIG_IGN) |
116 | sigset(SIGINT, stop); | |
117 | if (sigset(SIGHUP, SIG_IGN) != SIG_IGN) | |
118 | sigset(SIGHUP, hangup); | |
119 | } | |
7a05656e | 120 | shudprompt = intty && !sourcing; |
ac72cd41 KS |
121 | for (;;) { |
122 | setexit(); | |
ac72cd41 KS |
123 | |
124 | /* | |
125 | * Print the prompt, if needed. Clear out | |
126 | * string space, and flush the output. | |
127 | */ | |
128 | ||
129 | if (!rcvmode && !sourcing) | |
130 | return; | |
853e9d55 | 131 | eofloop = 0; |
73f94fab | 132 | top: |
7a05656e | 133 | if (shudprompt) { |
28bcd25d | 134 | printf(prompt); |
80187484 | 135 | fflush(stdout); |
6c85fa2a | 136 | # ifdef VMUNIX |
d28ecfdf | 137 | sigset(SIGCONT, contin); |
ea394d88 | 138 | # endif VMUNIX |
28bcd25d | 139 | } else |
80187484 | 140 | fflush(stdout); |
ac72cd41 KS |
141 | sreset(); |
142 | ||
143 | /* | |
144 | * Read a line of commands from the current input | |
145 | * and handle end of file specially. | |
146 | */ | |
147 | ||
148 | n = 0; | |
149 | for (;;) { | |
150 | if (readline(input, &linebuf[n]) <= 0) { | |
151 | if (n != 0) | |
152 | break; | |
7a05656e KS |
153 | if (loading) |
154 | return; | |
ac72cd41 KS |
155 | if (sourcing) { |
156 | unstack(); | |
157 | goto more; | |
158 | } | |
07c257b5 | 159 | if (value("ignoreeof") != NOSTR && shudprompt) { |
853e9d55 KS |
160 | if (++eofloop < 25) { |
161 | printf("Use \"quit\" to quit.\n"); | |
162 | goto top; | |
163 | } | |
73f94fab | 164 | } |
7a05656e KS |
165 | if (edit) |
166 | edstop(); | |
ac72cd41 KS |
167 | return; |
168 | } | |
169 | if ((n = strlen(linebuf)) == 0) | |
170 | break; | |
171 | n--; | |
172 | if (linebuf[n] != '\\') | |
173 | break; | |
174 | linebuf[n++] = ' '; | |
175 | } | |
ea394d88 | 176 | # ifdef VMUNIX |
d28ecfdf | 177 | sigset(SIGCONT, SIG_DFL); |
ea394d88 | 178 | # endif VMUNIX |
2cd8e0a9 | 179 | if (execute(linebuf, 0)) |
ac72cd41 KS |
180 | return; |
181 | more: ; | |
182 | } | |
183 | } | |
184 | ||
185 | /* | |
186 | * Execute a single command. If the command executed | |
187 | * is "quit," then return non-zero so that the caller | |
188 | * will know to return back to main, if he cares. | |
2cd8e0a9 | 189 | * Contxt is non-zero if called while composing mail. |
ac72cd41 KS |
190 | */ |
191 | ||
2cd8e0a9 | 192 | execute(linebuf, contxt) |
ac72cd41 KS |
193 | char linebuf[]; |
194 | { | |
195 | char word[LINESIZE]; | |
196 | char *arglist[MAXARGC]; | |
197 | struct cmd *com; | |
198 | register char *cp, *cp2; | |
199 | register int c; | |
e5717bff | 200 | int muvec[2]; |
ac72cd41 KS |
201 | int edstop(), e; |
202 | ||
203 | /* | |
204 | * Strip the white space away from the beginning | |
205 | * of the command, then scan out a word, which | |
206 | * consists of anything except digits and white space. | |
207 | * | |
208 | * Handle ! escapes differently to get the correct | |
209 | * lexical conventions. | |
210 | */ | |
211 | ||
212 | cp = linebuf; | |
213 | while (any(*cp, " \t")) | |
214 | cp++; | |
215 | if (*cp == '!') { | |
216 | if (sourcing) { | |
217 | printf("Can't \"!\" while sourcing\n"); | |
218 | unstack(); | |
219 | return(0); | |
220 | } | |
221 | shell(cp+1); | |
222 | return(0); | |
223 | } | |
224 | cp2 = word; | |
c0132ef0 | 225 | while (*cp && !any(*cp, " \t0123456789$^.:/-+*'\"")) |
ac72cd41 KS |
226 | *cp2++ = *cp++; |
227 | *cp2 = '\0'; | |
228 | ||
229 | /* | |
230 | * Look up the command; if not found, bitch. | |
231 | * Normally, a blank command would map to the | |
232 | * first command in the table; while sourcing, | |
233 | * however, we ignore blank lines to eliminate | |
234 | * confusion. | |
235 | */ | |
236 | ||
237 | if (sourcing && equal(word, "")) | |
238 | return(0); | |
239 | com = lex(word); | |
240 | if (com == NONE) { | |
7a05656e KS |
241 | printf("Unknown command: \"%s\"\n", word); |
242 | if (loading) | |
243 | return(1); | |
ac72cd41 KS |
244 | if (sourcing) |
245 | unstack(); | |
246 | return(0); | |
247 | } | |
248 | ||
128ec005 KS |
249 | /* |
250 | * See if we should execute the command -- if a conditional | |
251 | * we always execute it, otherwise, check the state of cond. | |
252 | */ | |
253 | ||
989e19a2 | 254 | if ((com->c_argtype & F) == 0) |
128ec005 KS |
255 | if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode) |
256 | return(0); | |
257 | ||
ac72cd41 KS |
258 | /* |
259 | * Special case so that quit causes a return to | |
260 | * main, who will call the quit code directly. | |
261 | * If we are in a source file, just unstack. | |
262 | */ | |
263 | ||
264 | if (com->c_func == edstop && sourcing) { | |
7a05656e KS |
265 | if (loading) |
266 | return(1); | |
ac72cd41 KS |
267 | unstack(); |
268 | return(0); | |
269 | } | |
270 | if (!edit && com->c_func == edstop) { | |
726c3356 | 271 | sigset(SIGINT, SIG_IGN); |
ac72cd41 KS |
272 | return(1); |
273 | } | |
274 | ||
275 | /* | |
276 | * Process the arguments to the command, depending | |
277 | * on the type he expects. Default to an error. | |
278 | * If we are sourcing an interactive command, it's | |
279 | * an error. | |
280 | */ | |
281 | ||
282 | if (!rcvmode && (com->c_argtype & M) == 0) { | |
283 | printf("May not execute \"%s\" while sending\n", | |
284 | com->c_name); | |
7a05656e KS |
285 | if (loading) |
286 | return(1); | |
2cd8e0a9 KS |
287 | if (sourcing) |
288 | unstack(); | |
ac72cd41 KS |
289 | return(0); |
290 | } | |
291 | if (sourcing && com->c_argtype & I) { | |
292 | printf("May not execute \"%s\" while sourcing\n", | |
293 | com->c_name); | |
7a05656e KS |
294 | if (loading) |
295 | return(1); | |
ac72cd41 KS |
296 | unstack(); |
297 | return(0); | |
298 | } | |
e5717bff KS |
299 | if (readonly && com->c_argtype & W) { |
300 | printf("May not execute \"%s\" -- message file is read only\n", | |
301 | com->c_name); | |
7a05656e KS |
302 | if (loading) |
303 | return(1); | |
e5717bff KS |
304 | if (sourcing) |
305 | unstack(); | |
306 | return(0); | |
307 | } | |
2cd8e0a9 KS |
308 | if (contxt && com->c_argtype & R) { |
309 | printf("Cannot recursively invoke \"%s\"\n", com->c_name); | |
310 | return(0); | |
311 | } | |
ac72cd41 | 312 | e = 1; |
2cd8e0a9 | 313 | switch (com->c_argtype & ~(F|P|I|M|T|W|R)) { |
ac72cd41 KS |
314 | case MSGLIST: |
315 | /* | |
316 | * A message list defaulting to nearest forward | |
317 | * legal message. | |
318 | */ | |
7a05656e KS |
319 | if (msgvec == 0) { |
320 | printf("Illegal use of \"message list\"\n"); | |
321 | return(-1); | |
322 | } | |
ac72cd41 KS |
323 | if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0) |
324 | break; | |
325 | if (c == 0) { | |
326 | *msgvec = first(com->c_msgflag, | |
327 | com->c_msgmask); | |
328 | msgvec[1] = NULL; | |
329 | } | |
330 | if (*msgvec == NULL) { | |
331 | printf("No applicable messages\n"); | |
332 | break; | |
333 | } | |
334 | e = (*com->c_func)(msgvec); | |
335 | break; | |
336 | ||
337 | case NDMLIST: | |
338 | /* | |
339 | * A message list with no defaults, but no error | |
340 | * if none exist. | |
341 | */ | |
7a05656e KS |
342 | if (msgvec == 0) { |
343 | printf("Illegal use of \"message list\"\n"); | |
344 | return(-1); | |
345 | } | |
ac72cd41 KS |
346 | if (getmsglist(cp, msgvec, com->c_msgflag) < 0) |
347 | break; | |
348 | e = (*com->c_func)(msgvec); | |
349 | break; | |
350 | ||
351 | case STRLIST: | |
352 | /* | |
353 | * Just the straight string, with | |
354 | * leading blanks removed. | |
355 | */ | |
356 | while (any(*cp, " \t")) | |
357 | cp++; | |
358 | e = (*com->c_func)(cp); | |
359 | break; | |
360 | ||
361 | case RAWLIST: | |
362 | /* | |
363 | * A vector of strings, in shell style. | |
364 | */ | |
365 | if ((c = getrawlist(cp, arglist)) < 0) | |
366 | break; | |
367 | if (c < com->c_minargs) { | |
368 | printf("%s requires at least %d arg(s)\n", | |
369 | com->c_name, com->c_minargs); | |
370 | break; | |
371 | } | |
372 | if (c > com->c_maxargs) { | |
373 | printf("%s takes no more than %d arg(s)\n", | |
374 | com->c_name, com->c_maxargs); | |
375 | break; | |
376 | } | |
377 | e = (*com->c_func)(arglist); | |
378 | break; | |
379 | ||
380 | case NOLIST: | |
381 | /* | |
382 | * Just the constant zero, for exiting, | |
383 | * eg. | |
384 | */ | |
385 | e = (*com->c_func)(0); | |
386 | break; | |
387 | ||
388 | default: | |
389 | panic("Unknown argtype"); | |
390 | } | |
391 | ||
392 | /* | |
393 | * Exit the current source file on | |
394 | * error. | |
395 | */ | |
396 | ||
7a05656e KS |
397 | if (e && loading) |
398 | return(1); | |
ac72cd41 KS |
399 | if (e && sourcing) |
400 | unstack(); | |
401 | if (com->c_func == edstop) | |
402 | return(1); | |
403 | if (value("autoprint") != NOSTR && com->c_argtype & P) | |
e5717bff KS |
404 | if ((dot->m_flag & MDELETED) == 0) { |
405 | muvec[0] = dot - &message[0] + 1; | |
406 | muvec[1] = 0; | |
407 | type(muvec); | |
408 | } | |
128ec005 | 409 | if (!sourcing && (com->c_argtype & T) == 0) |
ac72cd41 KS |
410 | sawcom = 1; |
411 | return(0); | |
412 | } | |
413 | ||
de274ec3 KS |
414 | /* |
415 | * When we wake up after ^Z, reprint the prompt. | |
416 | */ | |
417 | contin(s) | |
418 | { | |
419 | ||
07c257b5 | 420 | printf(prompt); |
de274ec3 KS |
421 | fflush(stdout); |
422 | } | |
423 | ||
726c3356 KS |
424 | /* |
425 | * Branch here on hangup signal and simulate quit. | |
426 | */ | |
427 | hangup() | |
428 | { | |
726c3356 | 429 | |
177b7a73 | 430 | holdsigs(); |
726c3356 KS |
431 | if (edit) { |
432 | if (setexit()) | |
433 | exit(0); | |
434 | edstop(); | |
435 | } | |
436 | else | |
437 | quit(); | |
438 | exit(0); | |
439 | } | |
440 | ||
e5717bff KS |
441 | /* |
442 | * Set the size of the message vector used to construct argument | |
443 | * lists to message list functions. | |
444 | */ | |
445 | ||
446 | setmsize(sz) | |
447 | { | |
448 | ||
449 | if (msgvec != (int *) 0) | |
450 | cfree(msgvec); | |
451 | msgvec = (int *) calloc((unsigned) (sz + 1), sizeof *msgvec); | |
452 | } | |
453 | ||
ac72cd41 KS |
454 | /* |
455 | * Find the correct command in the command table corresponding | |
456 | * to the passed command "word" | |
457 | */ | |
458 | ||
459 | struct cmd * | |
460 | lex(word) | |
461 | char word[]; | |
462 | { | |
463 | register struct cmd *cp; | |
464 | extern struct cmd cmdtab[]; | |
465 | ||
466 | for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++) | |
467 | if (isprefix(word, cp->c_name)) | |
468 | return(cp); | |
469 | return(NONE); | |
470 | } | |
471 | ||
472 | /* | |
473 | * Determine if as1 is a valid prefix of as2. | |
474 | * Return true if yep. | |
475 | */ | |
476 | ||
477 | isprefix(as1, as2) | |
478 | char *as1, *as2; | |
479 | { | |
480 | register char *s1, *s2; | |
481 | ||
482 | s1 = as1; | |
483 | s2 = as2; | |
484 | while (*s1++ == *s2) | |
485 | if (*s2++ == '\0') | |
486 | return(1); | |
487 | return(*--s1 == '\0'); | |
488 | } | |
489 | ||
490 | /* | |
491 | * The following gets called on receipt of a rubout. This is | |
492 | * to abort printout of a command, mainly. | |
493 | * Dispatching here when command() is inactive crashes rcv. | |
494 | * Close all open files except 0, 1, 2, and the temporary. | |
495 | * The special call to getuserid() is needed so it won't get | |
496 | * annoyed about losing its open file. | |
497 | * Also, unstack all source files. | |
498 | */ | |
499 | ||
e39b1d85 KS |
500 | int inithdr; /* am printing startup headers */ |
501 | ||
46053c99 S |
502 | #ifdef _NFILE |
503 | static | |
504 | _fwalk(function) | |
505 | register int (*function)(); | |
506 | { | |
507 | register FILE *iop; | |
508 | ||
509 | for (iop = _iob; iop < _iob + _NFILE; iop++) | |
510 | (*function)(iop); | |
511 | } | |
512 | #endif | |
513 | ||
514 | static | |
515 | xclose(iop) | |
516 | register FILE *iop; | |
517 | { | |
518 | if (iop == stdin || iop == stdout || | |
519 | iop == stderr || iop == itf || iop == otf) | |
520 | return; | |
521 | ||
522 | if (iop != pipef) | |
523 | fclose(iop); | |
524 | else { | |
525 | pclose(pipef); | |
526 | pipef = NULL; | |
527 | } | |
528 | } | |
529 | ||
726c3356 | 530 | stop(s) |
ac72cd41 KS |
531 | { |
532 | register FILE *fp; | |
533 | ||
ea394d88 KS |
534 | # ifndef VMUNIX |
535 | s = SIGINT; | |
536 | # endif VMUNIX | |
ac72cd41 | 537 | noreset = 0; |
e39b1d85 KS |
538 | if (!inithdr) |
539 | sawcom++; | |
540 | inithdr = 0; | |
ac72cd41 KS |
541 | while (sourcing) |
542 | unstack(); | |
543 | getuserid((char *) -1); | |
46053c99 S |
544 | |
545 | /* | |
546 | * Walk through all the open FILEs, applying xclose() to them | |
547 | */ | |
548 | _fwalk(xclose); | |
549 | ||
ac72cd41 KS |
550 | if (image >= 0) { |
551 | close(image); | |
552 | image = -1; | |
553 | } | |
80187484 | 554 | fprintf(stderr, "Interrupt\n"); |
4bc721c3 | 555 | # ifndef VMUNIX |
ea394d88 KS |
556 | signal(s, stop); |
557 | # endif | |
ac72cd41 KS |
558 | reset(0); |
559 | } | |
560 | ||
561 | /* | |
562 | * Announce the presence of the current Mail version, | |
563 | * give the message count, and print a header listing. | |
564 | */ | |
565 | ||
a0aaf589 | 566 | char *greeting = "Mail version %s. Type ? for help.\n"; |
ac72cd41 | 567 | |
e5717bff | 568 | announce(pr) |
ac72cd41 | 569 | { |
f3bfa857 | 570 | int vec[2], mdot; |
ac72cd41 | 571 | extern char *version; |
74745497 | 572 | |
125e424c CL |
573 | if (pr && value("quiet") == NOSTR) |
574 | printf(greeting, version); | |
74745497 KS |
575 | mdot = newfileinfo(); |
576 | vec[0] = mdot; | |
577 | vec[1] = 0; | |
74745497 | 578 | dot = &message[mdot - 1]; |
e39b1d85 KS |
579 | if (msgCount > 0 && !noheader) { |
580 | inithdr++; | |
74745497 | 581 | headers(vec); |
e39b1d85 KS |
582 | inithdr = 0; |
583 | } | |
74745497 KS |
584 | } |
585 | ||
586 | /* | |
587 | * Announce information about the file we are editing. | |
588 | * Return a likely place to set dot. | |
589 | */ | |
74745497 KS |
590 | newfileinfo() |
591 | { | |
ac72cd41 | 592 | register struct message *mp; |
83be1edb | 593 | register int u, n, mdot, d, s; |
46d3d6df | 594 | char fname[BUFSIZ], zname[BUFSIZ], *ename; |
ac72cd41 | 595 | |
c52f0860 KS |
596 | for (mp = &message[0]; mp < &message[msgCount]; mp++) |
597 | if (mp->m_flag & MNEW) | |
598 | break; | |
f3bfa857 KS |
599 | if (mp >= &message[msgCount]) |
600 | for (mp = &message[0]; mp < &message[msgCount]; mp++) | |
601 | if ((mp->m_flag & MREAD) == 0) | |
602 | break; | |
c52f0860 | 603 | if (mp < &message[msgCount]) |
f3bfa857 | 604 | mdot = mp - &message[0] + 1; |
c52f0860 | 605 | else |
f3bfa857 | 606 | mdot = 1; |
83be1edb | 607 | s = d = 0; |
128ec005 KS |
608 | for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) { |
609 | if (mp->m_flag & MNEW) | |
610 | n++; | |
611 | if ((mp->m_flag & MREAD) == 0) | |
612 | u++; | |
83be1edb KS |
613 | if (mp->m_flag & MDELETED) |
614 | d++; | |
615 | if (mp->m_flag & MSAVED) | |
616 | s++; | |
128ec005 | 617 | } |
46d3d6df KS |
618 | ename = mailname; |
619 | if (getfold(fname) >= 0) { | |
620 | strcat(fname, "/"); | |
621 | if (strncmp(fname, mailname, strlen(fname)) == 0) { | |
622 | sprintf(zname, "+%s", mailname + strlen(fname)); | |
623 | ename = zname; | |
624 | } | |
625 | } | |
626 | printf("\"%s\": ", ename); | |
74745497 KS |
627 | if (msgCount == 1) |
628 | printf("1 message"); | |
629 | else | |
630 | printf("%d messages", msgCount); | |
128ec005 KS |
631 | if (n > 0) |
632 | printf(" %d new", n); | |
633 | if (u-n > 0) | |
634 | printf(" %d unread", u); | |
83be1edb KS |
635 | if (d > 0) |
636 | printf(" %d deleted", d); | |
637 | if (s > 0) | |
638 | printf(" %d saved", s); | |
74745497 KS |
639 | if (readonly) |
640 | printf(" [Read only]"); | |
e5717bff | 641 | printf("\n"); |
74745497 | 642 | return(mdot); |
ac72cd41 KS |
643 | } |
644 | ||
645 | strace() {} | |
646 | ||
647 | /* | |
648 | * Print the current version number. | |
649 | */ | |
650 | ||
651 | pversion(e) | |
652 | { | |
a0aaf589 | 653 | printf("Version %s\n", version); |
ac72cd41 KS |
654 | return(0); |
655 | } | |
7a05656e KS |
656 | |
657 | /* | |
658 | * Load a file of user definitions. | |
659 | */ | |
660 | load(name) | |
661 | char *name; | |
662 | { | |
663 | register FILE *in, *oldin; | |
664 | ||
665 | if ((in = fopen(name, "r")) == NULL) | |
666 | return; | |
667 | oldin = input; | |
668 | input = in; | |
669 | loading = 1; | |
670 | sourcing = 1; | |
671 | commands(); | |
672 | loading = 0; | |
673 | sourcing = 0; | |
674 | input = oldin; | |
675 | fclose(in); | |
676 | } |