Commit | Line | Data |
---|---|---|
864befdb KB |
1 | /* |
2 | * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. | |
3 | * | |
4 | * Copy permission is hereby granted provided that this notice is | |
5 | * retained on all partial or complete copies. | |
6 | * | |
7 | * For more info on this and all of my stuff, mail edjames@berkeley.edu. | |
8 | */ | |
9 | ||
10 | #ifndef lint | |
e7c6fb2c | 11 | static char sccsid[] = "@(#)input.c 5.2 (Berkeley) %G%"; |
864befdb KB |
12 | #endif not lint |
13 | ||
14 | #include "include.h" | |
15 | ||
16 | #define MAXRULES 6 | |
17 | #define MAXDEPTH 15 | |
18 | ||
19 | #define RETTOKEN '\n' | |
20 | #ifdef SYSV | |
21 | #define CRTOKEN '\r' | |
22 | #endif | |
23 | #define REDRAWTOKEN '\014' /* CTRL(L) */ | |
24 | #define SHELLTOKEN '!' | |
25 | #define HELPTOKEN '?' | |
26 | #define ALPHATOKEN 256 | |
27 | #define NUMTOKEN 257 | |
28 | ||
29 | typedef struct { | |
30 | int token; | |
31 | int to_state; | |
32 | char *str; | |
33 | char *(*func)(); | |
34 | } RULE; | |
35 | ||
36 | typedef struct { | |
37 | int num_rules; | |
38 | RULE *rule; | |
39 | } STATE; | |
40 | ||
41 | typedef struct { | |
42 | char str[20]; | |
43 | int state; | |
44 | int rule; | |
45 | int ch; | |
46 | int pos; | |
47 | } STACK; | |
48 | ||
49 | #define T_RULE stack[level].rule | |
50 | #define T_STATE stack[level].state | |
51 | #define T_STR stack[level].str | |
52 | #define T_POS stack[level].pos | |
53 | #define T_CH stack[level].ch | |
54 | ||
55 | #define NUMELS(a) (sizeof (a) / sizeof (*(a))) | |
56 | ||
57 | #define NUMSTATES NUMELS(st) | |
58 | ||
59 | char *setplane(), *circle(), *left(), *right(), *Left(), *Right(), | |
60 | *beacon(), *ex_it(), *climb(), *descend(), *setalt(), *setrelalt(), | |
61 | *benum(), *to_dir(), *rel_dir(), *delayb(), *mark(), *unmark(), | |
62 | *airport(), *turn(), *ignore(); | |
63 | ||
64 | RULE state0[] = { { ALPHATOKEN, 1, "%c:", setplane}, | |
65 | { RETTOKEN, -1, "", NULL }, | |
66 | #ifdef SYSV | |
67 | { CRTOKEN, -1, "", NULL }, | |
68 | #endif | |
69 | { HELPTOKEN, 12, " [a-z]<ret>", NULL }}, | |
70 | state1[] = { { 't', 2, " turn", turn }, | |
71 | { 'a', 3, " altitude:", NULL }, | |
72 | { 'c', 4, " circle", circle }, | |
73 | { 'm', 7, " mark", mark }, | |
74 | { 'u', 7, " unmark", unmark }, | |
75 | { 'i', 7, " ignore", ignore }, | |
76 | { HELPTOKEN, 12, " tacmui", NULL }}, | |
77 | state2[] = { { 'l', 6, " left", left }, | |
78 | { 'r', 6, " right", right }, | |
79 | { 'L', 4, " left 90", Left }, | |
80 | { 'R', 4, " right 90", Right }, | |
81 | { 't', 11, " towards", NULL }, | |
82 | { 'w', 4, " to 0", to_dir }, | |
83 | { 'e', 4, " to 45", to_dir }, | |
84 | { 'd', 4, " to 90", to_dir }, | |
85 | { 'c', 4, " to 135", to_dir }, | |
86 | { 'x', 4, " to 180", to_dir }, | |
87 | { 'z', 4, " to 225", to_dir }, | |
88 | { 'a', 4, " to 270", to_dir }, | |
89 | { 'q', 4, " to 315", to_dir }, | |
90 | { HELPTOKEN, 12, " lrLRt<dir>", NULL }}, | |
91 | state3[] = { { '+', 10, " climb", climb }, | |
92 | { 'c', 10, " climb", climb }, | |
93 | { '-', 10, " descend", descend }, | |
94 | { 'd', 10, " descend", descend }, | |
95 | { NUMTOKEN, 7, " %c000 feet", setalt }, | |
96 | { HELPTOKEN, 12, " +-cd[0-9]", NULL }}, | |
97 | state4[] = { { '@', 9, " at", NULL }, | |
98 | { 'a', 9, " at", NULL }, | |
99 | { RETTOKEN, -1, "", NULL }, | |
100 | #ifdef SYSV | |
101 | { CRTOKEN, -1, "", NULL }, | |
102 | #endif | |
103 | { HELPTOKEN, 12, " @a<ret>", NULL }}, | |
104 | state5[] = { { NUMTOKEN, 7, "%c", delayb }, | |
105 | { HELPTOKEN, 12, " [0-9]", NULL }}, | |
106 | state6[] = { { '@', 9, " at", NULL }, | |
107 | { 'a', 9, " at", NULL }, | |
108 | { 'w', 4, " 0", rel_dir }, | |
109 | { 'e', 4, " 45", rel_dir }, | |
110 | { 'd', 4, " 90", rel_dir }, | |
111 | { 'c', 4, " 135", rel_dir }, | |
112 | { 'x', 4, " 180", rel_dir }, | |
113 | { 'z', 4, " 225", rel_dir }, | |
114 | { 'a', 4, " 270", rel_dir }, | |
115 | { 'q', 4, " 315", rel_dir }, | |
116 | { RETTOKEN, -1, "", NULL }, | |
117 | #ifdef SYSV | |
118 | { CRTOKEN, -1, "", NULL }, | |
119 | #endif | |
120 | { HELPTOKEN, 12, " @a<dir><ret>",NULL }}, | |
121 | state7[] = { { RETTOKEN, -1, "", NULL }, | |
122 | #ifdef SYSV | |
123 | { CRTOKEN, -1, "", NULL }, | |
124 | #endif | |
125 | { HELPTOKEN, 12, " <ret>", NULL }}, | |
126 | state8[] = { { NUMTOKEN, 4, "%c", benum }, | |
127 | { HELPTOKEN, 12, " [0-9]", NULL }}, | |
128 | state9[] = { { 'b', 5, " beacon #", NULL }, | |
129 | { '*', 5, " beacon #", NULL }, | |
130 | { HELPTOKEN, 12, " b*", NULL }}, | |
131 | state10[] = { { NUMTOKEN, 7, " %c000 ft", setrelalt}, | |
132 | { HELPTOKEN, 12, " [0-9]", NULL }}, | |
133 | state11[] = { { 'b', 8, " beacon #", beacon }, | |
134 | { '*', 8, " beacon #", beacon }, | |
135 | { 'e', 8, " exit #", ex_it }, | |
136 | { 'a', 8, " airport #", airport }, | |
137 | { HELPTOKEN, 12, " b*ea", NULL }}, | |
138 | state12[] = { { -1, -1, "", NULL }}; | |
139 | ||
140 | #define DEF_STATE(s) { NUMELS(s), (s) } | |
141 | ||
142 | STATE st[] = { | |
143 | DEF_STATE(state0), DEF_STATE(state1), DEF_STATE(state2), | |
144 | DEF_STATE(state3), DEF_STATE(state4), DEF_STATE(state5), | |
145 | DEF_STATE(state6), DEF_STATE(state7), DEF_STATE(state8), | |
146 | DEF_STATE(state9), DEF_STATE(state10), DEF_STATE(state11), | |
147 | DEF_STATE(state12) | |
148 | }; | |
149 | ||
150 | PLANE p; | |
151 | STACK stack[MAXDEPTH]; | |
152 | int level; | |
153 | int tval; | |
154 | int dest_type, dest_no, dir; | |
155 | ||
156 | pop() | |
157 | { | |
158 | if (level == 0) | |
159 | return (-1); | |
160 | level--; | |
161 | ||
162 | ioclrtoeol(T_POS); | |
163 | ||
164 | strcpy(T_STR, ""); | |
165 | T_RULE = -1; | |
166 | T_CH = -1; | |
167 | return (0); | |
168 | } | |
169 | ||
170 | rezero() | |
171 | { | |
172 | iomove(0); | |
173 | ||
174 | level = 0; | |
175 | T_STATE = 0; | |
176 | T_RULE = -1; | |
177 | T_CH = -1; | |
178 | T_POS = 0; | |
179 | strcpy(T_STR, ""); | |
180 | } | |
181 | ||
182 | push(ruleno, ch) | |
183 | { | |
184 | int newstate, newpos; | |
185 | ||
e7c6fb2c | 186 | (void)sprintf(T_STR, st[T_STATE].rule[ruleno].str, tval); |
864befdb KB |
187 | T_RULE = ruleno; |
188 | T_CH = ch; | |
189 | newstate = st[T_STATE].rule[ruleno].to_state; | |
190 | newpos = T_POS + strlen(T_STR); | |
191 | ||
192 | ioaddstr(T_POS, T_STR); | |
193 | ||
194 | if (level == 0) | |
195 | ioclrtobot(); | |
196 | level++; | |
197 | T_STATE = newstate; | |
198 | T_POS = newpos; | |
199 | T_RULE = -1; | |
200 | strcpy(T_STR, ""); | |
201 | } | |
202 | ||
203 | getcommand() | |
204 | { | |
205 | int c, i, done; | |
206 | char *s, *(*func)(); | |
207 | PLANE *pp; | |
208 | ||
209 | rezero(); | |
210 | ||
211 | do { | |
212 | c = gettoken(); | |
213 | if (c == tty_new.sg_erase) { | |
214 | if (pop() < 0) | |
215 | noise(); | |
216 | } else if (c == tty_new.sg_kill) { | |
217 | while (pop() >= 0) | |
218 | ; | |
219 | } else { | |
220 | done = 0; | |
221 | for (i = 0; i < st[T_STATE].num_rules; i++) { | |
222 | if (st[T_STATE].rule[i].token == c || | |
223 | st[T_STATE].rule[i].token == tval) { | |
224 | push(i, (c >= ALPHATOKEN) ? tval : c); | |
225 | done = 1; | |
226 | break; | |
227 | } | |
228 | } | |
229 | if (!done) | |
230 | noise(); | |
231 | } | |
232 | } while (T_STATE != -1); | |
233 | ||
234 | if (level == 1) | |
235 | return (1); /* forced update */ | |
236 | ||
237 | dest_type = T_NODEST; | |
238 | ||
239 | for (i = 0; i < level; i++) { | |
240 | func = st[stack[i].state].rule[stack[i].rule].func; | |
241 | if (func != NULL) | |
242 | if ((s = (*func)(stack[i].ch)) != NULL) { | |
243 | ioerror(stack[i].pos, strlen(stack[i].str), s); | |
244 | return (-1); | |
245 | } | |
246 | } | |
247 | ||
248 | pp = findplane(p.plane_no); | |
249 | if (pp->new_altitude != p.new_altitude) | |
250 | pp->new_altitude = p.new_altitude; | |
251 | else if (pp->status != p.status) | |
252 | pp->status = p.status; | |
253 | else { | |
254 | pp->new_dir = p.new_dir; | |
255 | pp->delayd = p.delayd; | |
256 | pp->delayd_no = p.delayd_no; | |
257 | } | |
258 | return (0); | |
259 | } | |
260 | ||
261 | noise() | |
262 | { | |
263 | putchar('\07'); | |
264 | fflush(stdout); | |
265 | } | |
266 | ||
267 | gettoken() | |
268 | { | |
269 | while ((tval = getAChar()) == REDRAWTOKEN || tval == SHELLTOKEN) | |
270 | { | |
271 | if (tval == SHELLTOKEN) | |
272 | { | |
273 | #ifdef BSD | |
274 | struct itimerval itv; | |
275 | itv.it_value.tv_sec = 0; | |
276 | itv.it_value.tv_usec = 0; | |
277 | setitimer(ITIMER_REAL, &itv, NULL); | |
278 | #endif | |
279 | #ifdef SYSV | |
280 | int aval; | |
281 | aval = alarm(0); | |
282 | #endif | |
283 | if (fork() == 0) /* child */ | |
284 | { | |
285 | char *shell, *base, *getenv(), *strrchr(); | |
286 | ||
287 | setuid(getuid()); /* turn off setuid bit */ | |
288 | done_screen(); | |
289 | ||
290 | /* run user's favorite shell */ | |
291 | if ((shell = getenv("SHELL")) != NULL) | |
292 | { | |
293 | base = strrchr(shell, '/'); | |
294 | if (base == NULL) | |
295 | base = shell; | |
296 | else | |
297 | base++; | |
298 | execl(shell, base, 0); | |
299 | } | |
300 | else | |
301 | execl("/bin/sh", "sh", 0); | |
302 | ||
303 | exit(0); /* oops */ | |
304 | } | |
305 | ||
306 | wait(0); | |
307 | #ifdef BSD | |
308 | ioctl(fileno(stdin), TIOCSETP, &tty_new); | |
309 | itv.it_value.tv_sec = 0; | |
310 | itv.it_value.tv_usec = 1; | |
311 | itv.it_interval.tv_sec = sp->update_secs; | |
312 | itv.it_interval.tv_usec = 0; | |
313 | setitimer(ITIMER_REAL, &itv, NULL); | |
314 | #endif | |
315 | #ifdef SYSV | |
316 | ioctl(fileno(stdin), TCSETAW, &tty_new); | |
317 | alarm(aval); | |
318 | #endif | |
319 | } | |
320 | redraw(); | |
321 | } | |
322 | ||
323 | if (isdigit(tval)) | |
324 | return (NUMTOKEN); | |
325 | else if (isalpha(tval)) | |
326 | return (ALPHATOKEN); | |
327 | else | |
328 | return (tval); | |
329 | } | |
330 | ||
331 | char * | |
332 | setplane(c) | |
333 | { | |
334 | PLANE *pp; | |
335 | ||
336 | pp = findplane(number(c)); | |
337 | if (pp == NULL) | |
338 | return ("Unknown Plane"); | |
339 | bcopy(pp, &p, sizeof (p)); | |
340 | p.delayd = 0; | |
341 | return (NULL); | |
342 | } | |
343 | ||
344 | char * | |
345 | turn(c) | |
346 | { | |
347 | if (p.altitude == 0) | |
348 | return ("Planes at airports may not change direction"); | |
349 | return (NULL); | |
350 | } | |
351 | ||
352 | char * | |
353 | circle(c) | |
354 | { | |
355 | if (p.altitude == 0) | |
356 | return ("Planes cannot circle on the ground"); | |
357 | p.new_dir = MAXDIR; | |
358 | return (NULL); | |
359 | } | |
360 | ||
361 | char * | |
362 | left(c) | |
363 | { | |
364 | dir = D_LEFT; | |
365 | p.new_dir = p.dir - 1; | |
366 | if (p.new_dir < 0) | |
367 | p.new_dir += MAXDIR; | |
368 | return (NULL); | |
369 | } | |
370 | ||
371 | char * | |
372 | right(c) | |
373 | { | |
374 | dir = D_RIGHT; | |
375 | p.new_dir = p.dir + 1; | |
376 | if (p.new_dir > MAXDIR) | |
377 | p.new_dir -= MAXDIR; | |
378 | return (NULL); | |
379 | } | |
380 | ||
381 | char * | |
382 | Left(c) | |
383 | { | |
384 | p.new_dir = p.dir - 2; | |
385 | if (p.new_dir < 0) | |
386 | p.new_dir += MAXDIR; | |
387 | return (NULL); | |
388 | } | |
389 | ||
390 | char * | |
391 | Right(c) | |
392 | { | |
393 | p.new_dir = p.dir + 2; | |
394 | if (p.new_dir > MAXDIR) | |
395 | p.new_dir -= MAXDIR; | |
396 | return (NULL); | |
397 | } | |
398 | ||
399 | char * | |
400 | delayb(c) | |
401 | { | |
402 | int xdiff, ydiff; | |
403 | ||
404 | c -= '0'; | |
405 | ||
406 | if (c >= sp->num_beacons) | |
407 | return ("Unknown beacon"); | |
408 | xdiff = sp->beacon[c].x - p.xpos; | |
409 | xdiff = SGN(xdiff); | |
410 | ydiff = sp->beacon[c].y - p.ypos; | |
411 | ydiff = SGN(ydiff); | |
412 | if (xdiff != displacement[p.dir].dx || ydiff != displacement[p.dir].dy) | |
413 | return ("Beacon is not in flight path"); | |
414 | p.delayd = 1; | |
415 | p.delayd_no = c; | |
416 | ||
417 | if (dest_type != T_NODEST) { | |
418 | switch (dest_type) { | |
419 | case T_BEACON: | |
420 | xdiff = sp->beacon[dest_no].x - sp->beacon[c].x; | |
421 | ydiff = sp->beacon[dest_no].y - sp->beacon[c].y; | |
422 | break; | |
423 | case T_EXIT: | |
424 | xdiff = sp->exit[dest_no].x - sp->beacon[c].x; | |
425 | ydiff = sp->exit[dest_no].y - sp->beacon[c].y; | |
426 | break; | |
427 | case T_AIRPORT: | |
428 | xdiff = sp->airport[dest_no].x - sp->beacon[c].x; | |
429 | ydiff = sp->airport[dest_no].y - sp->beacon[c].y; | |
430 | break; | |
431 | default: | |
432 | return ("Bad case in delayb! Get help!"); | |
433 | break; | |
434 | } | |
435 | if (xdiff == 0 && ydiff == 0) | |
436 | return ("Would already be there"); | |
437 | p.new_dir = DIR_FROM_DXDY(xdiff, ydiff); | |
438 | if (p.new_dir == p.dir) | |
439 | return ("Already going in that direction"); | |
440 | } | |
441 | return (NULL); | |
442 | } | |
443 | ||
444 | char * | |
445 | beacon(c) | |
446 | { | |
447 | dest_type = T_BEACON; | |
448 | return (NULL); | |
449 | } | |
450 | ||
451 | char * | |
452 | ex_it(c) | |
453 | { | |
454 | dest_type = T_EXIT; | |
455 | return (NULL); | |
456 | } | |
457 | ||
458 | char * | |
459 | airport(c) | |
460 | { | |
461 | dest_type = T_AIRPORT; | |
462 | return (NULL); | |
463 | } | |
464 | ||
465 | char * | |
466 | climb(c) | |
467 | { | |
468 | dir = D_UP; | |
469 | return (NULL); | |
470 | } | |
471 | ||
472 | char * | |
473 | descend(c) | |
474 | { | |
475 | dir = D_DOWN; | |
476 | return (NULL); | |
477 | } | |
478 | ||
479 | char * | |
480 | setalt(c) | |
481 | { | |
482 | if ((p.altitude == c - '0') && (p.new_altitude == p.altitude)) | |
483 | return ("Already at that altitude"); | |
484 | p.new_altitude = c - '0'; | |
485 | return (NULL); | |
486 | } | |
487 | ||
488 | char * | |
489 | setrelalt(c) | |
490 | { | |
491 | if (c == 0) | |
492 | return ("altitude not changed"); | |
493 | ||
494 | switch (dir) { | |
495 | case D_UP: | |
496 | p.new_altitude = p.altitude + c - '0'; | |
497 | break; | |
498 | case D_DOWN: | |
499 | p.new_altitude = p.altitude - (c - '0'); | |
500 | break; | |
501 | default: | |
502 | return ("Unknown case in setrelalt! Get help!"); | |
503 | break; | |
504 | } | |
505 | if (p.new_altitude < 0) | |
506 | return ("Altitude would be too low"); | |
507 | else if (p.new_altitude > 9) | |
508 | return ("Altitude would be too high"); | |
509 | return (NULL); | |
510 | } | |
511 | ||
512 | char * | |
513 | benum(c) | |
514 | { | |
515 | dest_no = c -= '0'; | |
516 | ||
517 | switch (dest_type) { | |
518 | case T_BEACON: | |
519 | if (c >= sp->num_beacons) | |
520 | return ("Unknown beacon"); | |
521 | p.new_dir = DIR_FROM_DXDY(sp->beacon[c].x - p.xpos, | |
522 | sp->beacon[c].y - p.ypos); | |
523 | break; | |
524 | case T_EXIT: | |
525 | if (c >= sp->num_exits) | |
526 | return ("Unknown exit"); | |
527 | p.new_dir = DIR_FROM_DXDY(sp->exit[c].x - p.xpos, | |
528 | sp->exit[c].y - p.ypos); | |
529 | break; | |
530 | case T_AIRPORT: | |
531 | if (c >= sp->num_airports) | |
532 | return ("Unknown airport"); | |
533 | p.new_dir = DIR_FROM_DXDY(sp->airport[c].x - p.xpos, | |
534 | sp->airport[c].y - p.ypos); | |
535 | break; | |
536 | default: | |
537 | return ("Unknown case in benum! Get help!"); | |
538 | break; | |
539 | } | |
540 | return (NULL); | |
541 | } | |
542 | ||
543 | char * | |
544 | to_dir(c) | |
545 | { | |
546 | p.new_dir = dir_no(c); | |
547 | return (NULL); | |
548 | } | |
549 | ||
550 | char * | |
551 | rel_dir(c) | |
552 | { | |
553 | int angle; | |
554 | ||
555 | angle = dir_no(c); | |
556 | switch (dir) { | |
557 | case D_LEFT: | |
558 | p.new_dir = p.dir - angle; | |
559 | if (p.new_dir < 0) | |
560 | p.new_dir += MAXDIR; | |
561 | break; | |
562 | case D_RIGHT: | |
563 | p.new_dir = p.dir + angle; | |
564 | if (p.new_dir >= MAXDIR) | |
565 | p.new_dir -= MAXDIR; | |
566 | break; | |
567 | default: | |
568 | return ("Bizarre direction in rel_dir! Get help!"); | |
569 | break; | |
570 | } | |
571 | return (NULL); | |
572 | } | |
573 | ||
574 | char * | |
575 | mark(c) | |
576 | { | |
577 | if (p.altitude == 0) | |
578 | return ("Cannot mark planes on the ground"); | |
579 | if (p.status == S_MARKED) | |
580 | return ("Already marked"); | |
581 | p.status = S_MARKED; | |
582 | return (NULL); | |
583 | } | |
584 | ||
585 | char * | |
586 | unmark(c) | |
587 | { | |
588 | if (p.altitude == 0) | |
589 | return ("Cannot unmark planes on the ground"); | |
590 | if (p.status == S_UNMARKED) | |
591 | return ("Already unmarked"); | |
592 | p.status = S_UNMARKED; | |
593 | return (NULL); | |
594 | } | |
595 | ||
596 | char * | |
597 | ignore(c) | |
598 | { | |
599 | if (p.altitude == 0) | |
600 | return ("Cannot ignore planes on the ground"); | |
601 | if (p.status == S_IGNORED) | |
602 | return ("Already ignored"); | |
603 | p.status = S_IGNORED; | |
604 | return (NULL); | |
605 | } | |
606 | ||
607 | dir_no(ch) | |
608 | char ch; | |
609 | { | |
610 | int dir; | |
611 | ||
612 | switch (ch) { | |
613 | case 'w': dir = 0; break; | |
614 | case 'e': dir = 1; break; | |
615 | case 'd': dir = 2; break; | |
616 | case 'c': dir = 3; break; | |
617 | case 'x': dir = 4; break; | |
618 | case 'z': dir = 5; break; | |
619 | case 'a': dir = 6; break; | |
620 | case 'q': dir = 7; break; | |
621 | default: | |
622 | fprintf(stderr, "bad character in dir_no\n"); | |
623 | break; | |
624 | } | |
625 | return (dir); | |
626 | } |