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