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