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