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