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