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