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 } 696