|
|
1.1 root 1: #
2:
3: #include "rcv.h"
4:
5: /*
6: * Mail -- a mail program
7: *
8: * Lexical processing of commands.
9: */
10:
11: /*
12: * Interpret user commands one by one. If standard input is not a tty,
13: * print no prompt.
14: */
15:
16: int *msgvec;
17:
18: commands()
19: {
20: int prompt, firstsw, stop();
21: char linebuf[LINESIZE];
22:
23: msgvec = (int *) calloc((unsigned) (msgCount + 1), sizeof *msgvec);
24: if (rcvmode)
25: if (signal(SIGINT, SIG_IGN) == SIG_DFL)
26: signal(SIGINT, stop);
27: input = stdin;
28: prompt = 1;
29: if (!intty)
30: prompt = 0;
31: firstsw = 1;
32: for (;;) {
33: setexit();
34: if (firstsw > 0) {
35: firstsw = 0;
36: source1(mailrc);
37: source1(MASTER);
38: source1(AUX);
39: }
40:
41: /*
42: * How's this for obscure: after we
43: * finish sourcing for the first time,
44: * go off and print the headers!
45: */
46:
47: if (firstsw == 0 && !sourcing) {
48: firstsw = -1;
49: if (rcvmode)
50: announce();
51: }
52:
53: /*
54: * Print the prompt, if needed. Clear out
55: * string space, and flush the output.
56: */
57:
58: if (!rcvmode && !sourcing)
59: return;
60: if (prompt && !sourcing)
61: printf("_\r");
62: flush();
63: sreset();
64:
65: /*
66: * Read a line of commands from the current input
67: * and handle end of file specially.
68: */
69:
70: if (readline(input, linebuf) <= 0) {
71: if (sourcing) {
72: unstack();
73: continue;
74: }
75: if (!edit) {
76: signal(SIGINT, SIG_IGN);
77: return;
78: }
79: edstop();
80: return;
81: }
82: if (execute(linebuf))
83: return;
84: }
85: }
86:
87: /*
88: * Execute a single command. If the command executed
89: * is "quit," then return non-zero so that the caller
90: * will know to return back to main, if he cares.
91: */
92:
93: execute(linebuf)
94: char linebuf[];
95: {
96: char word[LINESIZE];
97: char *arglist[MAXARGC];
98: struct cmd *com;
99: register char *cp, *cp2;
100: register int c;
101: int edstop(), e;
102:
103: /*
104: * Strip the white space away from the beginning
105: * of the command, then scan out a word, which
106: * consists of anything except digits and white space.
107: *
108: * Handle ! escapes differently to get the correct
109: * lexical conventions.
110: */
111:
112: cp = linebuf;
113: while (any(*cp, " \t"))
114: cp++;
115: if (*cp == '!') {
116: if (sourcing) {
117: printf("Can't \"!\" while sourcing\n");
118: unstack();
119: return(0);
120: }
121: shell(cp+1);
122: return(0);
123: }
124: cp2 = word;
125: while (*cp && !any(*cp, " \t0123456789$^.+*'\""))
126: *cp2++ = *cp++;
127: *cp2 = '\0';
128:
129: /*
130: * Look up the command; if not found, bitch.
131: * Normally, a blank command would map to the
132: * first command in the table; while sourcing,
133: * however, we ignore blank lines to eliminate
134: * confusion.
135: */
136:
137: if (sourcing && equal(word, ""))
138: return(0);
139: com = lex(word);
140: if (com == NONE) {
141: printf("What?\n");
142: if (sourcing)
143: unstack();
144: return(0);
145: }
146:
147: /*
148: * Special case so that quit causes a return to
149: * main, who will call the quit code directly.
150: * If we are in a source file, just unstack.
151: */
152:
153: if (com->c_func == edstop && sourcing) {
154: unstack();
155: return(0);
156: }
157: if (!edit && com->c_func == edstop) {
158: signal(SIGINT, SIG_IGN);
159: return(1);
160: }
161:
162: /*
163: * Process the arguments to the command, depending
164: * on the type he expects. Default to an error.
165: * If we are sourcing an interactive command, it's
166: * an error.
167: */
168:
169: if (!rcvmode && (com->c_argtype & M) == 0) {
170: printf("May not execute \"%s\" while sending\n",
171: com->c_name);
172: unstack();
173: return(0);
174: }
175: if (sourcing && com->c_argtype & I) {
176: printf("May not execute \"%s\" while sourcing\n",
177: com->c_name);
178: unstack();
179: return(0);
180: }
181: e = 1;
182: switch (com->c_argtype & ~(P|I|M)) {
183: case MSGLIST:
184: /*
185: * A message list defaulting to nearest forward
186: * legal message.
187: */
188: if ((c = getmsglist(cp, msgvec, com->c_msgflags)) < 0)
189: break;
190: if (c == 0) {
191: *msgvec = first(com->c_msgflags,
192: com->c_msgmask);
193: msgvec[1] = NULL;
194: }
195: if (*msgvec == NULL) {
196: printf("No applicable messages\n");
197: break;
198: }
199: e = (*com->c_func)(msgvec);
200: break;
201:
202: case NDMLIST:
203: /*
204: * A message list with no defaults, but no error
205: * if none exist.
206: */
207: if (getmsglist(cp, msgvec, com->c_msgflags) < 0)
208: break;
209: e = (*com->c_func)(msgvec);
210: break;
211:
212: case STRLIST:
213: /*
214: * Just the straight string, with
215: * leading blanks removed.
216: */
217: while (any(*cp, " \t"))
218: cp++;
219: e = (*com->c_func)(cp);
220: break;
221:
222: case RAWLIST:
223: /*
224: * A vector of strings, in shell style.
225: */
226: if ((c = getrawlist(cp, arglist)) < 0)
227: break;
228: if (c < com->c_minargs) {
229: printf("%s requires at least %d arg(s)\n",
230: com->c_name, com->c_minargs);
231: break;
232: }
233: if (c > com->c_maxargs) {
234: printf("%s takes no more than %d arg(s)\n",
235: com->c_name, com->c_maxargs);
236: break;
237: }
238: e = (*com->c_func)(arglist);
239: break;
240:
241: case NOLIST:
242: /*
243: * Just the constant zero, for exiting,
244: * eg.
245: */
246: e = (*com->c_func)(0);
247: break;
248:
249: default:
250: panic("Unknown argtype");
251: }
252:
253: /*
254: * Exit the current source file on
255: * error.
256: */
257:
258: if (e && sourcing)
259: unstack();
260: if (com->c_func == edstop)
261: return(1);
262: if (value("autoprint") != NOSTR && com->c_argtype & P)
263: if ((dot->m_flag & MDELETED) == 0)
264: print(dot);
265: if (!sourcing)
266: sawcom = 1;
267: return(0);
268: }
269:
270: /*
271: * Find the correct command in the command table corresponding
272: * to the passed command "word"
273: */
274:
275: struct cmd *
276: lex(word)
277: char word[];
278: {
279: register struct cmd *cp;
280: extern struct cmd cmdtab[];
281:
282: for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++)
283: if (isprefix(word, cp->c_name))
284: return(cp);
285: return(NONE);
286: }
287:
288: /*
289: * Determine if as1 is a valid prefix of as2.
290: * Return true if yep.
291: */
292:
293: isprefix(as1, as2)
294: char *as1, *as2;
295: {
296: register char *s1, *s2;
297:
298: s1 = as1;
299: s2 = as2;
300: while (*s1++ == *s2)
301: if (*s2++ == '\0')
302: return(1);
303: return(*--s1 == '\0');
304: }
305:
306: /*
307: * The following gets called on receipt of a rubout. This is
308: * to abort printout of a command, mainly.
309: * Dispatching here when command() is inactive crashes rcv.
310: * Close all open files except 0, 1, 2, and the temporary.
311: * The special call to getuserid() is needed so it won't get
312: * annoyed about losing its open file.
313: * Also, unstack all source files.
314: */
315:
316: stop()
317: {
318: register FILE *fp;
319:
320: signal(SIGINT, SIG_IGN);
321: sawcom++;
322: while (sourcing)
323: unstack();
324: getuserid((char *) -1);
325: for (fp = &_iob[0]; fp < &_iob[_NFILE]; fp++) {
326: if (fp == stdin || fp == stdout)
327: continue;
328: if (fp == itf || fp == otf)
329: continue;
330: if (fp == stderr)
331: continue;
332: fclose(fp);
333: }
334: if (image >= 0) {
335: close(image);
336: image = -1;
337: }
338: clrbuf(stdout);
339: printf("Interrupt\n");
340: signal(SIGINT, stop);
341: reset(0);
342: }
343:
344: /*
345: * Announce the presence of the current Mail version,
346: * give the message count, and print a header listing.
347: */
348:
349: char *greeting = "Mail version 1.3 %s. Type ? for help.\n";
350:
351: announce()
352: {
353: char *vec[2];
354: extern char *version;
355:
356: vec[0] = "0";
357: vec[1] = NULL;
358: if (value("quiet") == NOSTR)
359: printf(greeting, version);
360: if (msgCount == 1)
361: printf("1 message:\n");
362: else
363: printf("%d messages:\n", msgCount);
364: headers(vec);
365: }
366:
367: strace() {}
368:
369: /*
370: * Print the current version number.
371: */
372:
373: pversion(e)
374: {
375: printf(greeting, version);
376: return(0);
377: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.