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