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