Annotation of src/usr.bin/mail/lex.c, Revision 1.23
1.23 ! millert 1: /* $OpenBSD: lex.c,v 1.22 2001/01/16 05:36:08 millert Exp $ */
1.6 millert 2: /* $NetBSD: lex.c,v 1.10 1997/05/17 19:55:13 pk Exp $ */
1.2 niklas 3:
1.1 deraadt 4: /*
5: * Copyright (c) 1980, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
1.3 deraadt 38: #if 0
1.6 millert 39: static char sccsid[] = "@(#)lex.c 8.2 (Berkeley) 4/20/95";
1.3 deraadt 40: #else
1.23 ! millert 41: static char rcsid[] = "$OpenBSD: lex.c,v 1.22 2001/01/16 05:36:08 millert Exp $";
1.3 deraadt 42: #endif
1.1 deraadt 43: #endif /* not lint */
44:
45: #include "rcv.h"
46: #include <errno.h>
47: #include <fcntl.h>
48: #include "extern.h"
49:
50: /*
51: * Mail -- a mail program
52: *
53: * Lexical processing of commands.
54: */
55:
56: char *prompt = "& ";
57:
1.22 millert 58: const struct cmd *com; /* command we are running */
59:
1.1 deraadt 60: /*
61: * Set up editing on the given file name.
62: * If the first character of name is %, we are considered to be
63: * editing the file, otherwise we are reading our mail which has
64: * signficance for mbox and so forth.
65: */
66: int
67: setfile(name)
68: char *name;
69: {
70: FILE *ibuf;
1.11 millert 71: int i, fd;
1.1 deraadt 72: struct stat stb;
73: char isedit = *name != '%';
74: char *who = name[1] ? name + 1 : myname;
1.12 millert 75: char tempname[PATHSIZE];
1.1 deraadt 76: static int shudclob;
77:
1.8 millert 78: if ((name = expand(name)) == NULL)
1.6 millert 79: return(-1);
1.1 deraadt 80:
81: if ((ibuf = Fopen(name, "r")) == NULL) {
82: if (!isedit && errno == ENOENT)
83: goto nomail;
1.20 millert 84: warn("%s", name);
1.1 deraadt 85: return(-1);
86: }
87:
88: if (fstat(fileno(ibuf), &stb) < 0) {
1.6 millert 89: warn("fstat");
90: (void)Fclose(ibuf);
91: return(-1);
1.1 deraadt 92: }
93:
94: switch (stb.st_mode & S_IFMT) {
95: case S_IFDIR:
1.6 millert 96: (void)Fclose(ibuf);
1.1 deraadt 97: errno = EISDIR;
1.20 millert 98: warn("%s", name);
1.6 millert 99: return(-1);
1.1 deraadt 100:
101: case S_IFREG:
102: break;
103:
104: default:
1.6 millert 105: (void)Fclose(ibuf);
1.1 deraadt 106: errno = EINVAL;
1.20 millert 107: warn("%s", name);
1.6 millert 108: return(-1);
1.1 deraadt 109: }
110:
111: /*
112: * Looks like all will be well. We must now relinquish our
113: * hold on the current set of stuff. Must hold signals
114: * while we are reading the new file, else we will ruin
115: * the message[] data structure.
116: */
117:
118: holdsigs();
119: if (shudclob)
120: quit();
121:
122: /*
123: * Copy the messages into /tmp
124: * and set pointers.
125: */
126:
127: readonly = 0;
128: if ((i = open(name, 1)) < 0)
129: readonly++;
130: else
1.6 millert 131: (void)close(i);
1.1 deraadt 132: if (shudclob) {
1.6 millert 133: (void)fclose(itf);
134: (void)fclose(otf);
1.1 deraadt 135: }
136: shudclob = 1;
137: edit = isedit;
138: strcpy(prevfile, mailname);
1.14 millert 139: if (name != mailname) {
140: strncpy(mailname, name, sizeof(mailname) - 1);
141: mailname[sizeof(mailname) - 1] = '\0';
142: }
1.1 deraadt 143: mailsize = fsize(ibuf);
1.11 millert 144: (void)snprintf(tempname, sizeof(tempname),
145: "%s/mail.RxXXXXXXXXXX", tmpdir);
146: if ((fd = mkstemp(tempname)) == -1 ||
147: (otf = fdopen(fd, "w")) == NULL)
1.20 millert 148: err(1, "%s", tempname);
1.7 millert 149: (void)fcntl(fileno(otf), F_SETFD, 1);
1.11 millert 150: if ((itf = fopen(tempname, "r")) == NULL)
1.20 millert 151: err(1, "%s", tempname);
1.7 millert 152: (void)fcntl(fileno(itf), F_SETFD, 1);
1.12 millert 153: (void)rm(tempname);
1.6 millert 154: setptr(ibuf, 0);
1.1 deraadt 155: setmsize(msgCount);
1.6 millert 156: /*
157: * New mail may have arrived while we were reading
158: * the mail file, so reset mailsize to be where
159: * we really are in the file...
160: */
161: mailsize = ftell(ibuf);
162: (void)Fclose(ibuf);
1.1 deraadt 163: relsesigs();
164: sawcom = 0;
165: if (!edit && msgCount == 0) {
166: nomail:
167: fprintf(stderr, "No mail for %s\n", who);
1.6 millert 168: return(-1);
1.1 deraadt 169: }
170: return(0);
171: }
172:
1.6 millert 173: /*
174: * Incorporate any new mail that has arrived since we first
175: * started reading mail.
176: */
177: int
178: incfile()
179: {
180: int newsize;
181: int omsgCount = msgCount;
182: FILE *ibuf;
183:
184: ibuf = Fopen(mailname, "r");
185: if (ibuf == NULL)
186: return(-1);
187: holdsigs();
1.10 millert 188: if (!spool_lock())
189: return(-1);
1.6 millert 190: newsize = fsize(ibuf);
1.9 millert 191: /* make sure mail box has grown and is non-empty */
192: if (newsize == 0 || newsize <= mailsize) {
1.10 millert 193: spool_unlock();
1.9 millert 194: relsesigs();
195: return(newsize == mailsize ? 0 : -1);
196: }
1.6 millert 197: setptr(ibuf, mailsize);
198: setmsize(msgCount);
199: mailsize = ftell(ibuf);
200: (void)Fclose(ibuf);
1.10 millert 201: spool_unlock();
1.6 millert 202: relsesigs();
203: return(msgCount - omsgCount);
204: }
205:
206:
1.1 deraadt 207: int *msgvec;
208: int reset_on_stop; /* do a reset() if stopped */
209:
210: /*
211: * Interpret user commands one by one. If standard input is not a tty,
212: * print no prompt.
213: */
214: void
215: commands()
216: {
1.23 ! millert 217: int n;
! 218: volatile int eofloop = 0;
1.1 deraadt 219: char linebuf[LINESIZE];
220:
221: if (!sourcing) {
222: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1.13 millert 223: (void)signal(SIGINT, intr);
1.1 deraadt 224: if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1.13 millert 225: (void)signal(SIGHUP, hangup);
226: (void)signal(SIGTSTP, stop);
227: (void)signal(SIGTTOU, stop);
228: (void)signal(SIGTTIN, stop);
1.1 deraadt 229: }
230: setexit();
231: for (;;) {
232: /*
233: * Print the prompt, if needed. Clear out
234: * string space, and flush the output.
235: */
1.8 millert 236: if (!sourcing && value("interactive") != NULL) {
237: if ((value("autoinc") != NULL) && (incfile() > 0))
1.6 millert 238: puts("New mail has arrived.");
1.1 deraadt 239: reset_on_stop = 1;
1.21 deraadt 240: printf("%s", prompt);
1.1 deraadt 241: }
242: fflush(stdout);
243: sreset();
244: /*
245: * Read a line of commands from the current input
246: * and handle end of file specially.
247: */
248: n = 0;
249: for (;;) {
250: if (readline(input, &linebuf[n], LINESIZE - n) < 0) {
251: if (n == 0)
252: n = -1;
253: break;
254: }
255: if ((n = strlen(linebuf)) == 0)
256: break;
257: n--;
258: if (linebuf[n] != '\\')
259: break;
260: linebuf[n++] = ' ';
261: }
262: reset_on_stop = 0;
263: if (n < 0) {
264: /* eof */
265: if (loading)
266: break;
267: if (sourcing) {
268: unstack();
269: continue;
270: }
1.8 millert 271: if (value("interactive") != NULL &&
272: value("ignoreeof") != NULL &&
1.1 deraadt 273: ++eofloop < 25) {
1.6 millert 274: puts("Use \"quit\" to quit.");
1.1 deraadt 275: continue;
276: }
277: break;
278: }
279: eofloop = 0;
280: if (execute(linebuf, 0))
281: break;
282: }
283: }
284:
285: /*
286: * Execute a single command.
287: * Command functions return 0 for success, 1 for error, and -1
288: * for abort. A 1 or -1 aborts a load or source. A -1 aborts
289: * the interactive command loop.
290: * Contxt is non-zero if called while composing mail.
291: */
292: int
293: execute(linebuf, contxt)
294: char linebuf[];
295: int contxt;
296: {
297: char word[LINESIZE];
298: char *arglist[MAXARGC];
1.15 millert 299: char *cp, *cp2;
300: int c, muvec[2];
1.1 deraadt 301: int e = 1;
302:
1.22 millert 303: com = NULL;
304:
1.1 deraadt 305: /*
306: * Strip the white space away from the beginning
307: * of the command, then scan out a word, which
308: * consists of anything except digits and white space.
309: *
310: * Handle ! escapes differently to get the correct
311: * lexical conventions.
312: */
313:
314: for (cp = linebuf; isspace(*cp); cp++)
315: ;
316: if (*cp == '!') {
317: if (sourcing) {
1.6 millert 318: puts("Can't \"!\" while sourcing");
1.1 deraadt 319: goto out;
320: }
321: shell(cp+1);
322: return(0);
323: }
324: cp2 = word;
1.8 millert 325: while (*cp && strchr(" \t0123456789$^.:/-+*'\"", *cp) == NULL)
1.1 deraadt 326: *cp2++ = *cp++;
327: *cp2 = '\0';
328:
329: /*
330: * Look up the command; if not found, bitch.
331: * Normally, a blank command would map to the
332: * first command in the table; while sourcing,
333: * however, we ignore blank lines to eliminate
334: * confusion.
335: */
336:
337: if (sourcing && *word == '\0')
338: return(0);
339: com = lex(word);
340: if (com == NONE) {
341: printf("Unknown command: \"%s\"\n", word);
342: goto out;
343: }
344:
345: /*
346: * See if we should execute the command -- if a conditional
347: * we always execute it, otherwise, check the state of cond.
348: */
349:
350: if ((com->c_argtype & F) == 0)
1.3 deraadt 351: if ((cond == CRCV && !rcvmode) || (cond == CSEND && rcvmode))
1.1 deraadt 352: return(0);
353:
354: /*
355: * Process the arguments to the command, depending
356: * on the type he expects. Default to an error.
357: * If we are sourcing an interactive command, it's
358: * an error.
359: */
360:
361: if (!rcvmode && (com->c_argtype & M) == 0) {
362: printf("May not execute \"%s\" while sending\n",
363: com->c_name);
364: goto out;
365: }
366: if (sourcing && com->c_argtype & I) {
367: printf("May not execute \"%s\" while sourcing\n",
368: com->c_name);
369: goto out;
370: }
371: if (readonly && com->c_argtype & W) {
372: printf("May not execute \"%s\" -- message file is read only\n",
373: com->c_name);
374: goto out;
375: }
376: if (contxt && com->c_argtype & R) {
377: printf("Cannot recursively invoke \"%s\"\n", com->c_name);
378: goto out;
379: }
380: switch (com->c_argtype & ~(F|P|I|M|T|W|R)) {
1.22 millert 381: case MSGLIST|STRLIST:
382: /*
383: * A message list defaulting to nearest forward
384: * legal message.
385: */
386: if (msgvec == 0) {
387: puts("Illegal use of \"message list\"");
388: break;
389: }
390: /*
391: * remove leading blanks.
392: */
393: while (isspace(*cp))
394: cp++;
395:
396: if (isdigit(*cp) || *cp == ':') {
397: if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
398: break;
399: /* position to next space - past the message list */
400: while (!isspace(*cp))
401: cp++;
402: /* position to next non-space */
403: while (isspace(*cp))
404: cp++;
405: } else {
406: c = 0; /* no message list */
407: }
408:
409: if (c == 0) {
410: *msgvec = first(com->c_msgflag,
411: com->c_msgmask);
412: msgvec[1] = NULL;
413: }
414: if (*msgvec == NULL) {
415: puts("No applicable messages");
416: break;
417: }
418: /*
419: * Just the straight string, with
420: * leading blanks removed.
421: */
422: while (isspace(*cp))
423: cp++;
424:
425: e = (*com->c_func2)(msgvec, cp);
426: break;
427:
1.1 deraadt 428: case MSGLIST:
429: /*
430: * A message list defaulting to nearest forward
431: * legal message.
432: */
433: if (msgvec == 0) {
1.6 millert 434: puts("Illegal use of \"message list\"");
1.1 deraadt 435: break;
436: }
437: if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
438: break;
439: if (c == 0) {
440: *msgvec = first(com->c_msgflag,
441: com->c_msgmask);
442: msgvec[1] = NULL;
443: }
444: if (*msgvec == NULL) {
1.6 millert 445: puts("No applicable messages");
1.1 deraadt 446: break;
447: }
448: e = (*com->c_func)(msgvec);
449: break;
450:
451: case NDMLIST:
452: /*
453: * A message list with no defaults, but no error
454: * if none exist.
455: */
456: if (msgvec == 0) {
1.6 millert 457: puts("Illegal use of \"message list\"");
1.1 deraadt 458: break;
459: }
460: if (getmsglist(cp, msgvec, com->c_msgflag) < 0)
461: break;
462: e = (*com->c_func)(msgvec);
463: break;
464:
465: case STRLIST:
466: /*
467: * Just the straight string, with
468: * leading blanks removed.
469: */
470: while (isspace(*cp))
471: cp++;
472: e = (*com->c_func)(cp);
473: break;
474:
475: case RAWLIST:
476: /*
477: * A vector of strings, in shell style.
478: */
479: if ((c = getrawlist(cp, arglist,
1.6 millert 480: sizeof(arglist) / sizeof(*arglist))) < 0)
1.1 deraadt 481: break;
482: if (c < com->c_minargs) {
483: printf("%s requires at least %d arg(s)\n",
484: com->c_name, com->c_minargs);
485: break;
486: }
487: if (c > com->c_maxargs) {
488: printf("%s takes no more than %d arg(s)\n",
489: com->c_name, com->c_maxargs);
490: break;
491: }
492: e = (*com->c_func)(arglist);
493: break;
494:
495: case NOLIST:
496: /*
497: * Just the constant zero, for exiting,
498: * eg.
499: */
500: e = (*com->c_func)(0);
501: break;
502:
503: default:
1.15 millert 504: errx(1, "Unknown argtype");
1.1 deraadt 505: }
506:
507: out:
508: /*
509: * Exit the current source file on
510: * error.
511: */
512: if (e) {
513: if (e < 0)
1.6 millert 514: return(1);
1.1 deraadt 515: if (loading)
1.6 millert 516: return(1);
1.1 deraadt 517: if (sourcing)
518: unstack();
1.6 millert 519: return(0);
1.1 deraadt 520: }
1.3 deraadt 521: if (com == NULL)
522: return(0);
1.8 millert 523: if (value("autoprint") != NULL && com->c_argtype & P)
1.1 deraadt 524: if ((dot->m_flag & MDELETED) == 0) {
525: muvec[0] = dot - &message[0] + 1;
526: muvec[1] = 0;
527: type(muvec);
528: }
529: if (!sourcing && (com->c_argtype & T) == 0)
530: sawcom = 1;
531: return(0);
532: }
533:
534: /*
535: * Set the size of the message vector used to construct argument
536: * lists to message list functions.
537: */
538: void
539: setmsize(sz)
540: int sz;
541: {
542:
543: if (msgvec != 0)
1.7 millert 544: (void)free(msgvec);
545: msgvec = (int *)calloc(sz + 1, sizeof(*msgvec));
1.1 deraadt 546: }
547:
548: /*
549: * Find the correct command in the command table corresponding
550: * to the passed command "word"
551: */
552:
1.2 niklas 553: const struct cmd *
1.1 deraadt 554: lex(word)
555: char word[];
556: {
1.2 niklas 557: extern const struct cmd cmdtab[];
1.15 millert 558: const struct cmd *cp;
1.1 deraadt 559:
1.18 millert 560: if (word[0] == '#')
561: word = "#";
1.8 millert 562: for (cp = &cmdtab[0]; cp->c_name != NULL; cp++)
1.1 deraadt 563: if (isprefix(word, cp->c_name))
564: return(cp);
565: return(NONE);
566: }
567:
568: /*
569: * Determine if as1 is a valid prefix of as2.
570: * Return true if yep.
571: */
572: int
573: isprefix(as1, as2)
574: char *as1, *as2;
575: {
1.15 millert 576: char *s1, *s2;
1.1 deraadt 577:
578: s1 = as1;
579: s2 = as2;
580: while (*s1++ == *s2)
581: if (*s2++ == '\0')
582: return(1);
583: return(*--s1 == '\0');
584: }
585:
586: /*
587: * The following gets called on receipt of an interrupt. This is
588: * to abort printout of a command, mainly.
589: * Dispatching here when command() is inactive crashes rcv.
590: * Close all open files except 0, 1, 2, and the temporary.
591: * Also, unstack all source files.
592: */
593:
594: int inithdr; /* am printing startup headers */
595:
596: /*ARGSUSED*/
597: void
598: intr(s)
599: int s;
600: {
601:
602: noreset = 0;
603: if (!inithdr)
604: sawcom++;
605: inithdr = 0;
606: while (sourcing)
607: unstack();
608:
609: close_all_files();
610:
611: if (image >= 0) {
1.6 millert 612: (void)close(image);
1.1 deraadt 613: image = -1;
614: }
1.6 millert 615: fputs("Interrupt\n", stderr);
1.1 deraadt 616: reset(0);
617: }
618:
619: /*
620: * When we wake up after ^Z, reprint the prompt.
621: */
622: void
623: stop(s)
624: int s;
625: {
626: sig_t old_action = signal(s, SIG_DFL);
1.3 deraadt 627: sigset_t nset;
1.1 deraadt 628:
1.13 millert 629: (void)sigemptyset(&nset);
630: (void)sigaddset(&nset, s);
631: (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
632: (void)kill(0, s);
633: (void)sigprocmask(SIG_BLOCK, &nset, NULL);
634: (void)signal(s, old_action);
1.1 deraadt 635: if (reset_on_stop) {
636: reset_on_stop = 0;
637: reset(0);
638: }
639: }
640:
641: /*
642: * Branch here on hangup signal and simulate "exit".
643: */
644: /*ARGSUSED*/
645: void
646: hangup(s)
647: int s;
648: {
649:
650: /* nothing to do? */
651: exit(1);
652: }
653:
654: /*
655: * Announce the presence of the current Mail version,
656: * give the message count, and print a header listing.
657: */
658: void
659: announce()
660: {
661: int vec[2], mdot;
662:
1.6 millert 663: mdot = newfileinfo(0);
1.1 deraadt 664: vec[0] = mdot;
665: vec[1] = 0;
666: dot = &message[mdot - 1];
1.8 millert 667: if (msgCount > 0 && value("noheader") == NULL) {
1.1 deraadt 668: inithdr++;
669: headers(vec);
670: inithdr = 0;
671: }
672: }
673:
674: /*
675: * Announce information about the file we are editing.
676: * Return a likely place to set dot.
677: */
678: int
1.6 millert 679: newfileinfo(omsgCount)
680: int omsgCount;
1.1 deraadt 681: {
1.15 millert 682: struct message *mp;
683: int u, n, mdot, d, s;
1.6 millert 684: char fname[PATHSIZE], zname[PATHSIZE], *ename;
1.1 deraadt 685:
1.6 millert 686: for (mp = &message[omsgCount]; mp < &message[msgCount]; mp++)
1.1 deraadt 687: if (mp->m_flag & MNEW)
688: break;
689: if (mp >= &message[msgCount])
1.6 millert 690: for (mp = &message[omsgCount]; mp < &message[msgCount]; mp++)
1.1 deraadt 691: if ((mp->m_flag & MREAD) == 0)
692: break;
693: if (mp < &message[msgCount])
694: mdot = mp - &message[0] + 1;
695: else
1.6 millert 696: mdot = omsgCount + 1;
1.1 deraadt 697: s = d = 0;
698: for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) {
699: if (mp->m_flag & MNEW)
700: n++;
701: if ((mp->m_flag & MREAD) == 0)
702: u++;
703: if (mp->m_flag & MDELETED)
704: d++;
705: if (mp->m_flag & MSAVED)
706: s++;
707: }
708: ename = mailname;
1.6 millert 709: if (getfold(fname, sizeof(fname)) >= 0) {
710: strncat(fname, "/", sizeof(fname) - strlen(fname) - 1);
1.1 deraadt 711: if (strncmp(fname, mailname, strlen(fname)) == 0) {
1.12 millert 712: (void)snprintf(zname, sizeof(zname), "+%s",
1.6 millert 713: mailname + strlen(fname));
1.1 deraadt 714: ename = zname;
715: }
716: }
717: printf("\"%s\": ", ename);
718: if (msgCount == 1)
1.6 millert 719: fputs("1 message", stdout);
1.1 deraadt 720: else
721: printf("%d messages", msgCount);
722: if (n > 0)
723: printf(" %d new", n);
724: if (u-n > 0)
725: printf(" %d unread", u);
726: if (d > 0)
727: printf(" %d deleted", d);
728: if (s > 0)
729: printf(" %d saved", s);
730: if (readonly)
1.6 millert 731: fputs(" [Read only]", stdout);
732: putchar('\n');
1.1 deraadt 733: return(mdot);
734: }
735:
736: /*
737: * Print the current version number.
738: */
739:
740: /*ARGSUSED*/
741: int
1.3 deraadt 742: pversion(v)
743: void *v;
1.1 deraadt 744: {
745: extern char *version;
746:
747: printf("Version %s\n", version);
748: return(0);
749: }
750:
751: /*
752: * Load a file of user definitions.
753: */
754: void
755: load(name)
756: char *name;
757: {
1.15 millert 758: FILE *in, *oldin;
1.1 deraadt 759:
760: if ((in = Fopen(name, "r")) == NULL)
761: return;
762: oldin = input;
763: input = in;
764: loading = 1;
765: sourcing = 1;
766: commands();
767: loading = 0;
768: sourcing = 0;
769: input = oldin;
1.6 millert 770: (void)Fclose(in);
1.1 deraadt 771: }