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