]>
Commit | Line | Data |
---|---|---|
48a59f6d | 1 | /* $Header$ |
2 | * | |
3 | * Copyright 1992 by the Massachusetts Institute of Technology. | |
4 | * | |
5 | * For further information on copyright and distribution | |
6 | * see the file mit-copyright.h | |
7 | */ | |
8 | ||
9 | #include <mit-copyright.h> | |
10 | #include <stdio.h> | |
11 | #include <sys/types.h> | |
12 | #include <sys/signal.h> | |
13 | #include <sgtty.h> | |
14 | #include <sys/ioctl.h> | |
15 | #include <ctype.h> | |
16 | #include <strings.h> | |
17 | #include <X11/Intrinsic.h> | |
df52b790 | 18 | #include <moira.h> |
48a59f6d | 19 | #include "mmoira.h" |
df52b790 | 20 | #include "parser.h" |
48a59f6d | 21 | |
22 | static char rcsid[] = "$Header$"; | |
23 | ||
24 | ||
df52b790 | 25 | struct parse_node *TtyCommands = NULL, *TtyRoot = NULL; |
48a59f6d | 26 | |
27 | extern int NumMenus; | |
28 | extern MenuItem MenuRoot; | |
29 | char prompt[] = "moira> "; | |
30 | ||
df52b790 | 31 | static struct sgttyb otty, ntty; |
48a59f6d | 32 | |
33 | ||
34 | TtyMainLoop() | |
35 | { | |
36 | char buf[1024], cbuf[2], c, *p; | |
37 | int arg, i, done; | |
48a59f6d | 38 | |
df52b790 | 39 | if (TtyCommands == NULL) |
40 | parse_menus(); | |
41 | ||
42 | #ifdef DEBUG | |
43 | print_parse_tree(TtyRoot, 0); | |
44 | fflush(stdout); | |
45 | sleep(10); | |
46 | #endif /* DEBUG */ | |
48a59f6d | 47 | |
48 | ioctl(0, TIOCFLUSH, &arg); | |
df52b790 | 49 | ioctl(0, TIOCGETP, &otty); |
50 | ntty = otty; | |
48a59f6d | 51 | ntty.sg_flags |= RAW; |
52 | ntty.sg_flags &= ~ECHO; | |
df52b790 | 53 | raw_mode(); |
48a59f6d | 54 | |
55 | while (1) { | |
df52b790 | 56 | parser(prompt, TtyRoot); |
48a59f6d | 57 | } |
48a59f6d | 58 | } |
59 | ||
df52b790 | 60 | cooked_mode() |
48a59f6d | 61 | { |
df52b790 | 62 | ioctl(0, TIOCSETP, &otty); |
48a59f6d | 63 | } |
64 | ||
df52b790 | 65 | raw_mode() |
48a59f6d | 66 | { |
df52b790 | 67 | ioctl(0, TIOCSETP, &ntty); |
48a59f6d | 68 | } |
69 | ||
48a59f6d | 70 | static NumWords(s) |
71 | char *s; | |
72 | { | |
73 | int ret; | |
74 | ||
75 | for (ret = 1; *s; s++) | |
76 | if (*s == ' ') ret++; | |
77 | return(ret); | |
78 | } | |
79 | ||
80 | ||
df52b790 | 81 | parse_menus() |
48a59f6d | 82 | { |
83 | int arg; | |
df52b790 | 84 | struct parse_node *p; |
48a59f6d | 85 | |
df52b790 | 86 | TtyCommands = (struct parse_node *)malloc(sizeof(struct parse_node) * |
87 | NumMenus * 3); | |
88 | bzero(TtyCommands, sizeof(struct parse_node) * NumMenus * 3); | |
48a59f6d | 89 | arg = 0; |
90 | parse_menu_recursive(&MenuRoot, "", &arg); | |
df52b790 | 91 | TtyCommands[arg].p_word = "help"; |
92 | TtyCommands[arg].p_next = TtyRoot; | |
93 | for (p = TtyRoot; p; p = p->p_peer) | |
94 | if (strcmp(p->p_peer->p_word, "help") > 0) | |
95 | break; | |
96 | TtyCommands[arg].p_peer = p->p_peer->p_peer; | |
97 | p->p_peer = &TtyCommands[arg]; | |
98 | arg++; | |
48a59f6d | 99 | } |
100 | ||
101 | ||
df52b790 | 102 | parse_menu_recursive(m, parent, i) |
48a59f6d | 103 | MenuItem *m; |
104 | char *parent; | |
105 | int *i; | |
106 | { | |
df52b790 | 107 | char buf[64], cmd[64], *word, *s; |
48a59f6d | 108 | struct parse_node *p, **prev; |
df52b790 | 109 | int j, len; |
48a59f6d | 110 | |
111 | if (m->submenu == NULL) { | |
112 | if (!strcmp(parent, "file") || | |
113 | !strcmp(parent, "misc")) | |
114 | parent = ""; | |
df52b790 | 115 | if (NumWords(m->label) > 2 || !*parent) |
48a59f6d | 116 | strcpy(cmd, m->label); |
117 | else | |
118 | sprintf(cmd, "%s %s", m->label, parent); | |
119 | /* insert command into parse tree */ | |
df52b790 | 120 | p = TtyRoot; |
121 | prev = (struct parse_node **) &TtyRoot; | |
122 | for (word = cmd; word; word = index(word, ' ')) { | |
123 | if (*word == ' ') | |
124 | word++; | |
48a59f6d | 125 | s = index(word, ' '); |
126 | if (s) | |
127 | len = s - word; | |
128 | else | |
129 | len = strlen(word); | |
df52b790 | 130 | for (;;) { |
131 | if (!p || !p->p_word || | |
132 | (j = strncmp(p->p_word, word, len)) > 0) { | |
48a59f6d | 133 | strcpy(buf, word); |
134 | buf[len] = 0; | |
df52b790 | 135 | #ifdef DEBUG |
136 | printf("word: %s\n", buf); | |
137 | #endif | |
48a59f6d | 138 | TtyCommands[*i].p_word = strsave(buf); |
df52b790 | 139 | if (len == strlen(word)) |
140 | TtyCommands[*i].p_menu = m; | |
48a59f6d | 141 | TtyCommands[*i].p_peer = p; |
142 | if (prev) | |
df52b790 | 143 | *prev = &TtyCommands[*i]; |
48a59f6d | 144 | TtyCommands[*i].p_next = (struct parse_node *) NULL; |
145 | TtyCommands[*i].p_link = (struct parse_node *) NULL; | |
df52b790 | 146 | prev = &(TtyCommands[*i].p_next); |
147 | p = (struct parse_node *) NULL; | |
148 | *i = *i + 1; | |
48a59f6d | 149 | break; |
150 | } else if (j == 0) { | |
151 | prev = &(p->p_next); | |
152 | if (p->p_next) | |
df52b790 | 153 | p = p->p_next; |
48a59f6d | 154 | else |
155 | p = (struct parse_node *) NULL; | |
156 | break; | |
157 | } else { | |
158 | prev = &(p->p_peer); | |
df52b790 | 159 | p = p->p_peer; |
48a59f6d | 160 | } |
161 | } | |
162 | } | |
48a59f6d | 163 | return; |
164 | } | |
165 | if (!strcmp(m->label, "?help")) return; | |
166 | for (j = 0; m->submenu[j]; j++) { | |
167 | if (m == &MenuRoot) | |
168 | buf[0] = 0; | |
169 | else if (strlen(parent)) | |
170 | sprintf(buf, "%s %s", parent, m->label); | |
171 | else | |
172 | strcpy(buf, m->label); | |
173 | parse_menu_recursive(m->submenu[j], buf, i); | |
174 | } | |
175 | } | |
176 | ||
177 | ||
178 | TtyForm(f) | |
179 | EntryForm *f; | |
180 | { | |
df52b790 | 181 | int i, j, done, best, choice; |
182 | char buf[512], *k; | |
183 | UserPrompt *p; | |
184 | ||
185 | printf("%s\r\n", f->instructions); | |
186 | choice = 0; | |
187 | for (i = 0, p = f->inputlines[i]; p = f->inputlines[i]; i++) | |
188 | if (p->choice) { | |
189 | choice = 1; | |
190 | break; | |
191 | } | |
192 | if (choice) { | |
193 | j = 0; | |
194 | *buf = 0; | |
195 | for (i = 0, p = f->inputlines[i]; p = f->inputlines[i]; i++) { | |
196 | if (p->choice) { | |
197 | printf(" %s\r\n", buf); | |
198 | sprintf(buf, "%d: %s", ++j, p->prompt); | |
199 | } else if (*buf == 0) { | |
200 | sprintf(buf, "%d: %s", ++j, p->prompt); | |
201 | } else { | |
202 | strcat(buf, "/"); | |
203 | strcat(buf, p->prompt); | |
204 | } | |
205 | if (buf[strlen(buf)-1] == ' ') buf[strlen(buf)-1] = 0; | |
206 | } | |
207 | printf(" %s\r\nSelect by [1]: ", buf); | |
208 | if (mgets(buf, sizeof(buf))) | |
209 | return; | |
210 | if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = 0; | |
211 | if (strlen(buf) == 0) | |
212 | choice = 1; | |
213 | else | |
214 | choice = atoi(buf); | |
215 | } else choice = -1; | |
216 | for (i = 0, p = f->inputlines[i]; p = f->inputlines[i]; i++) { | |
217 | if (choice > 0 && p->choice) choice--; | |
218 | if (choice != -1 && choice != 1) continue; | |
219 | if (p->insensitive == True) continue; | |
220 | switch (p->type) { | |
221 | case FT_BOOLEAN: | |
222 | done = 0; | |
223 | while (!done) { | |
224 | done = 1; | |
225 | printf("%s(T/F): ", p->prompt); | |
226 | fflush(stdout); | |
227 | if (mgets(buf, sizeof(buf))) | |
228 | return; | |
229 | if (buf[0] == 'T' || buf[0] == 't' || | |
230 | buf[0] == 'Y' || buf[0] == 'y') | |
231 | p->returnvalue.booleanvalue = True; | |
232 | else if (buf[0] == 'F' || buf[0] == 'f' || | |
233 | buf[0] == 'N' || buf[0] == 'n') | |
234 | p->returnvalue.booleanvalue = False; | |
235 | else { | |
236 | done = 0; | |
237 | printf("Please answer True or False\r\n"); | |
238 | } | |
239 | } | |
240 | break; | |
241 | case FT_STRING: | |
242 | if (*StringValue(f, i)) | |
243 | printf("%s[%s]: ", p->prompt, StringValue(f, i)); | |
244 | else | |
245 | printf("%s: ", p->prompt); | |
246 | fflush(stdout); | |
247 | if (mgets(buf, sizeof(buf))) | |
248 | return; | |
249 | if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = 0; | |
250 | if (strlen(buf) != 0) | |
251 | StoreField(f, i, buf); | |
252 | if (!strcmp(buf, "\"\"")) | |
253 | StoreField(f, i, ""); | |
254 | break; | |
255 | case FT_KEYWORD: | |
256 | k = index(p->prompt, '|'); | |
257 | if (k) *k = 0; | |
258 | done = 0; | |
259 | while (done != 1) { | |
260 | if (*StringValue(f, i)) | |
261 | printf("%s[%s]: ", p->prompt, StringValue(f, i)); | |
262 | else | |
263 | printf("%s: ", p->prompt); | |
264 | fflush(stdout); | |
265 | if (mgets(buf, sizeof(buf))) | |
266 | return; | |
267 | if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = 0; | |
268 | if (strlen(buf) == 0) | |
269 | strcpy(buf, StringValue(f, i)); | |
270 | done = 0; | |
271 | for (j = 0; p->keywords[j]; j++) | |
272 | if (!strncasecmp(p->keywords[j], buf, strlen(buf))) | |
273 | done++, best = j; | |
274 | if (done != 1) { | |
275 | printf("You must enter one of these keywords:\r\n"); | |
276 | for (j = 0; p->keywords[j]; j++) { | |
277 | printf(" %s\r\n", p->keywords[j]); | |
278 | } | |
279 | } else | |
280 | StoreField(f, i, p->keywords[best]); | |
281 | } | |
282 | break; | |
283 | } | |
284 | } | |
285 | process_form(f, TRUE); | |
286 | } | |
287 | ||
288 | ||
289 | int mgets(line, linelen) | |
290 | char *line; | |
291 | int linelen; | |
292 | { | |
293 | char c, *p; | |
294 | ||
295 | raw_mode(); | |
296 | p = &line[0]; | |
297 | *p = 0; | |
298 | for (c = (getchar() & 0x7f); 1; c = (getchar() & 0x7f)) { | |
299 | if (c == 0) continue; | |
300 | switch (c) { | |
301 | case 127: | |
302 | case '\b': | |
303 | if (p == &line[0]) { | |
304 | putchar(7); | |
305 | break; | |
306 | } | |
307 | *(--p) = 0; | |
308 | write(1, "\b \b", 3); | |
309 | break; | |
310 | case 'C' - '@': | |
311 | case 'G' - '@': | |
312 | cooked_mode(); | |
313 | return(-1); | |
314 | case 'Q' - '@': | |
315 | case 'V' - '@': | |
316 | putchar('\\'); | |
317 | c = getchar(); | |
318 | if (c < ' ') | |
319 | printf("\b^%c", c + '@'); | |
320 | else | |
321 | printf("\b%c", c); | |
322 | fflush(stdout); | |
323 | *p++ = c; | |
324 | break; | |
325 | case 'W' - '@': | |
326 | if (p > &line[0]) | |
327 | p--; | |
328 | while ((p >= &line[0]) && isspace(*p)) { | |
329 | write(1, "\b \b", 3); | |
330 | p--; | |
331 | } | |
332 | while ((p >= &line[0]) && !isspace(*p)) { | |
333 | write(1, "\b \b", 3); | |
334 | p--; | |
335 | } | |
336 | if (p > &line[0]) { | |
337 | p++; | |
338 | } else { | |
339 | p = &line[0]; | |
340 | } | |
341 | *p = 0; | |
342 | break; | |
343 | case 'Z' - '@': | |
344 | printf("\r\n"); | |
345 | kill(getpid(), SIGSTOP); | |
346 | /* when continued, fall through to */ | |
347 | case 'R' - '@': | |
348 | *p = 0; | |
349 | printf("\r\n%s", line); | |
350 | fflush(stdout); | |
351 | break; | |
352 | case 'U' - '@': | |
353 | while (p-- > &line[0]) | |
354 | write(1, "\b \b", 3); | |
355 | *(++p) = 0; | |
356 | fflush(stdout); | |
357 | break; | |
358 | case '\n': | |
359 | case '\r': | |
360 | write(1, "\r\n", 2); | |
361 | cooked_mode(); | |
362 | return(0); | |
363 | break; | |
364 | default: | |
365 | putchar(c); | |
366 | *p++ = c; | |
367 | *p = 0; | |
368 | } | |
369 | } | |
370 | } | |
371 | ||
372 | ||
373 | print_parse_tree(n, l) | |
374 | struct parse_node *n; | |
375 | int l; | |
376 | { | |
377 | int i; | |
378 | ||
379 | for (i = l; i > 0; i--) putchar(' '); | |
380 | printf("%s%c\n", n->p_word, n->p_menu ? '*' : ' '); | |
381 | if (n->p_next) | |
382 | print_parse_tree(n->p_next, l+1); | |
383 | if (n->p_peer) | |
384 | return(print_parse_tree(n->p_peer, l)); | |
48a59f6d | 385 | } |