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