1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * 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 37 /* 38 * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. 39 * 40 * Copy permission is hereby granted provided that this notice is 41 * retained on all partial or complete copies. 42 * 43 * For more info on this and all of my stuff, mail edjames@berkeley.edu. 44 */ 45 46 #ifndef lint 47 /*static char sccsid[] = "from: @(#)input.c 5.4 (Berkeley) 4/30/90";*/ 48 static char rcsid[] = "$Id: input.c,v 1.2 1993/08/01 18:57:08 mycroft Exp $"; 49 #endif not lint 50 51 #include "include.h" 52 #include "pathnames.h" 53 54 #define MAXRULES 6 55 #define MAXDEPTH 15 56 57 #define RETTOKEN '\n' 58 #ifdef SYSV 59 #define CRTOKEN '\r' 60 #endif 61 #define REDRAWTOKEN '\014' /* CTRL(L) */ 62 #define SHELLTOKEN '!' 63 #define HELPTOKEN '?' 64 #define ALPHATOKEN 256 65 #define NUMTOKEN 257 66 67 typedef struct { 68 int token; 69 int to_state; 70 char *str; 71 char *(*func)(); 72 } RULE; 73 74 typedef struct { 75 int num_rules; 76 RULE *rule; 77 } STATE; 78 79 typedef struct { 80 char str[20]; 81 int state; 82 int rule; 83 int ch; 84 int pos; 85 } STACK; 86 87 #define T_RULE stack[level].rule 88 #define T_STATE stack[level].state 89 #define T_STR stack[level].str 90 #define T_POS stack[level].pos 91 #define T_CH stack[level].ch 92 93 #define NUMELS(a) (sizeof (a) / sizeof (*(a))) 94 95 #define NUMSTATES NUMELS(st) 96 97 char *setplane(), *circle(), *left(), *right(), *Left(), *Right(), 98 *beacon(), *ex_it(), *climb(), *descend(), *setalt(), *setrelalt(), 99 *benum(), *to_dir(), *rel_dir(), *delayb(), *mark(), *unmark(), 100 *airport(), *turn(), *ignore(); 101 102 RULE state0[] = { { ALPHATOKEN, 1, "%c:", setplane}, 103 { RETTOKEN, -1, "", NULL }, 104 #ifdef SYSV 105 { CRTOKEN, -1, "", NULL }, 106 #endif 107 { HELPTOKEN, 12, " [a-z]<ret>", NULL }}, 108 state1[] = { { 't', 2, " turn", turn }, 109 { 'a', 3, " altitude:", NULL }, 110 { 'c', 4, " circle", circle }, 111 { 'm', 7, " mark", mark }, 112 { 'u', 7, " unmark", unmark }, 113 { 'i', 7, " ignore", ignore }, 114 { HELPTOKEN, 12, " tacmui", NULL }}, 115 state2[] = { { 'l', 6, " left", left }, 116 { 'r', 6, " right", right }, 117 { 'L', 4, " left 90", Left }, 118 { 'R', 4, " right 90", Right }, 119 { 't', 11, " towards", NULL }, 120 { 'w', 4, " to 0", to_dir }, 121 { 'e', 4, " to 45", to_dir }, 122 { 'd', 4, " to 90", to_dir }, 123 { 'c', 4, " to 135", to_dir }, 124 { 'x', 4, " to 180", to_dir }, 125 { 'z', 4, " to 225", to_dir }, 126 { 'a', 4, " to 270", to_dir }, 127 { 'q', 4, " to 315", to_dir }, 128 { HELPTOKEN, 12, " lrLRt<dir>", NULL }}, 129 state3[] = { { '+', 10, " climb", climb }, 130 { 'c', 10, " climb", climb }, 131 { '-', 10, " descend", descend }, 132 { 'd', 10, " descend", descend }, 133 { NUMTOKEN, 7, " %c000 feet", setalt }, 134 { HELPTOKEN, 12, " +-cd[0-9]", NULL }}, 135 state4[] = { { '@', 9, " at", NULL }, 136 { 'a', 9, " at", NULL }, 137 { RETTOKEN, -1, "", NULL }, 138 #ifdef SYSV 139 { CRTOKEN, -1, "", NULL }, 140 #endif 141 { HELPTOKEN, 12, " @a<ret>", NULL }}, 142 state5[] = { { NUMTOKEN, 7, "%c", delayb }, 143 { HELPTOKEN, 12, " [0-9]", NULL }}, 144 state6[] = { { '@', 9, " at", NULL }, 145 { 'a', 9, " at", NULL }, 146 { 'w', 4, " 0", rel_dir }, 147 { 'e', 4, " 45", rel_dir }, 148 { 'd', 4, " 90", rel_dir }, 149 { 'c', 4, " 135", rel_dir }, 150 { 'x', 4, " 180", rel_dir }, 151 { 'z', 4, " 225", rel_dir }, 152 { 'a', 4, " 270", rel_dir }, 153 { 'q', 4, " 315", rel_dir }, 154 { RETTOKEN, -1, "", NULL }, 155 #ifdef SYSV 156 { CRTOKEN, -1, "", NULL }, 157 #endif 158 { HELPTOKEN, 12, " @a<dir><ret>",NULL }}, 159 state7[] = { { RETTOKEN, -1, "", NULL }, 160 #ifdef SYSV 161 { CRTOKEN, -1, "", NULL }, 162 #endif 163 { HELPTOKEN, 12, " <ret>", NULL }}, 164 state8[] = { { NUMTOKEN, 4, "%c", benum }, 165 { HELPTOKEN, 12, " [0-9]", NULL }}, 166 state9[] = { { 'b', 5, " beacon #", NULL }, 167 { '*', 5, " beacon #", NULL }, 168 { HELPTOKEN, 12, " b*", NULL }}, 169 state10[] = { { NUMTOKEN, 7, " %c000 ft", setrelalt}, 170 { HELPTOKEN, 12, " [0-9]", NULL }}, 171 state11[] = { { 'b', 8, " beacon #", beacon }, 172 { '*', 8, " beacon #", beacon }, 173 { 'e', 8, " exit #", ex_it }, 174 { 'a', 8, " airport #", airport }, 175 { HELPTOKEN, 12, " b*ea", NULL }}, 176 state12[] = { { -1, -1, "", NULL }}; 177 178 #define DEF_STATE(s) { NUMELS(s), (s) } 179 180 STATE st[] = { 181 DEF_STATE(state0), DEF_STATE(state1), DEF_STATE(state2), 182 DEF_STATE(state3), DEF_STATE(state4), DEF_STATE(state5), 183 DEF_STATE(state6), DEF_STATE(state7), DEF_STATE(state8), 184 DEF_STATE(state9), DEF_STATE(state10), DEF_STATE(state11), 185 DEF_STATE(state12) 186 }; 187 188 PLANE p; 189 STACK stack[MAXDEPTH]; 190 int level; 191 int tval; 192 int dest_type, dest_no, dir; 193 194 pop() 195 { 196 if (level == 0) 197 return (-1); 198 level--; 199 200 ioclrtoeol(T_POS); 201 202 strcpy(T_STR, ""); 203 T_RULE = -1; 204 T_CH = -1; 205 return (0); 206 } 207 208 rezero() 209 { 210 iomove(0); 211 212 level = 0; 213 T_STATE = 0; 214 T_RULE = -1; 215 T_CH = -1; 216 T_POS = 0; 217 strcpy(T_STR, ""); 218 } 219 220 push(ruleno, ch) 221 { 222 int newstate, newpos; 223 224 (void)sprintf(T_STR, st[T_STATE].rule[ruleno].str, tval); 225 T_RULE = ruleno; 226 T_CH = ch; 227 newstate = st[T_STATE].rule[ruleno].to_state; 228 newpos = T_POS + strlen(T_STR); 229 230 ioaddstr(T_POS, T_STR); 231 232 if (level == 0) 233 ioclrtobot(); 234 level++; 235 T_STATE = newstate; 236 T_POS = newpos; 237 T_RULE = -1; 238 strcpy(T_STR, ""); 239 } 240 241 getcommand() 242 { 243 int c, i, done; 244 char *s, *(*func)(); 245 PLANE *pp; 246 247 rezero(); 248 249 do { 250 c = gettoken(); 251 if (c == tty_new.sg_erase) { 252 if (pop() < 0) 253 noise(); 254 } else if (c == tty_new.sg_kill) { 255 while (pop() >= 0) 256 ; 257 } else { 258 done = 0; 259 for (i = 0; i < st[T_STATE].num_rules; i++) { 260 if (st[T_STATE].rule[i].token == c || 261 st[T_STATE].rule[i].token == tval) { 262 push(i, (c >= ALPHATOKEN) ? tval : c); 263 done = 1; 264 break; 265 } 266 } 267 if (!done) 268 noise(); 269 } 270 } while (T_STATE != -1); 271 272 if (level == 1) 273 return (1); /* forced update */ 274 275 dest_type = T_NODEST; 276 277 for (i = 0; i < level; i++) { 278 func = st[stack[i].state].rule[stack[i].rule].func; 279 if (func != NULL) 280 if ((s = (*func)(stack[i].ch)) != NULL) { 281 ioerror(stack[i].pos, strlen(stack[i].str), s); 282 return (-1); 283 } 284 } 285 286 pp = findplane(p.plane_no); 287 if (pp->new_altitude != p.new_altitude) 288 pp->new_altitude = p.new_altitude; 289 else if (pp->status != p.status) 290 pp->status = p.status; 291 else { 292 pp->new_dir = p.new_dir; 293 pp->delayd = p.delayd; 294 pp->delayd_no = p.delayd_no; 295 } 296 return (0); 297 } 298 299 noise() 300 { 301 putchar('\07'); 302 fflush(stdout); 303 } 304 305 gettoken() 306 { 307 while ((tval = getAChar()) == REDRAWTOKEN || tval == SHELLTOKEN) 308 { 309 if (tval == SHELLTOKEN) 310 { 311 #ifdef BSD 312 struct itimerval itv; 313 itv.it_value.tv_sec = 0; 314 itv.it_value.tv_usec = 0; 315 setitimer(ITIMER_REAL, &itv, NULL); 316 #endif 317 #ifdef SYSV 318 int aval; 319 aval = alarm(0); 320 #endif 321 if (fork() == 0) /* child */ 322 { 323 char *shell, *base, *getenv(), *strrchr(); 324 325 setuid(getuid()); /* turn off setuid bit */ 326 done_screen(); 327 328 /* run user's favorite shell */ 329 if ((shell = getenv("SHELL")) != NULL) 330 { 331 base = strrchr(shell, '/'); 332 if (base == NULL) 333 base = shell; 334 else 335 base++; 336 execl(shell, base, 0); 337 } 338 else 339 execl(_PATH_BSHELL, "sh", 0); 340 341 exit(0); /* oops */ 342 } 343 344 wait(0); 345 #ifdef BSD 346 ioctl(fileno(stdin), TIOCSETP, &tty_new); 347 itv.it_value.tv_sec = 0; 348 itv.it_value.tv_usec = 1; 349 itv.it_interval.tv_sec = sp->update_secs; 350 itv.it_interval.tv_usec = 0; 351 setitimer(ITIMER_REAL, &itv, NULL); 352 #endif 353 #ifdef SYSV 354 ioctl(fileno(stdin), TCSETAW, &tty_new); 355 alarm(aval); 356 #endif 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 char * 370 setplane(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 char * 383 turn(c) 384 { 385 if (p.altitude == 0) 386 return ("Planes at airports may not change direction"); 387 return (NULL); 388 } 389 390 char * 391 circle(c) 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 char * 400 left(c) 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 char * 410 right(c) 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 char * 420 Left(c) 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 char * 429 Right(c) 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 char * 438 delayb(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 char * 483 beacon(c) 484 { 485 dest_type = T_BEACON; 486 return (NULL); 487 } 488 489 char * 490 ex_it(c) 491 { 492 dest_type = T_EXIT; 493 return (NULL); 494 } 495 496 char * 497 airport(c) 498 { 499 dest_type = T_AIRPORT; 500 return (NULL); 501 } 502 503 char * 504 climb(c) 505 { 506 dir = D_UP; 507 return (NULL); 508 } 509 510 char * 511 descend(c) 512 { 513 dir = D_DOWN; 514 return (NULL); 515 } 516 517 char * 518 setalt(c) 519 { 520 if ((p.altitude == c - '0') && (p.new_altitude == p.altitude)) 521 return ("Already at that altitude"); 522 p.new_altitude = c - '0'; 523 return (NULL); 524 } 525 526 char * 527 setrelalt(c) 528 { 529 if (c == 0) 530 return ("altitude not changed"); 531 532 switch (dir) { 533 case D_UP: 534 p.new_altitude = p.altitude + c - '0'; 535 break; 536 case D_DOWN: 537 p.new_altitude = p.altitude - (c - '0'); 538 break; 539 default: 540 return ("Unknown case in setrelalt! Get help!"); 541 break; 542 } 543 if (p.new_altitude < 0) 544 return ("Altitude would be too low"); 545 else if (p.new_altitude > 9) 546 return ("Altitude would be too high"); 547 return (NULL); 548 } 549 550 char * 551 benum(c) 552 { 553 dest_no = c -= '0'; 554 555 switch (dest_type) { 556 case T_BEACON: 557 if (c >= sp->num_beacons) 558 return ("Unknown beacon"); 559 p.new_dir = DIR_FROM_DXDY(sp->beacon[c].x - p.xpos, 560 sp->beacon[c].y - p.ypos); 561 break; 562 case T_EXIT: 563 if (c >= sp->num_exits) 564 return ("Unknown exit"); 565 p.new_dir = DIR_FROM_DXDY(sp->exit[c].x - p.xpos, 566 sp->exit[c].y - p.ypos); 567 break; 568 case T_AIRPORT: 569 if (c >= sp->num_airports) 570 return ("Unknown airport"); 571 p.new_dir = DIR_FROM_DXDY(sp->airport[c].x - p.xpos, 572 sp->airport[c].y - p.ypos); 573 break; 574 default: 575 return ("Unknown case in benum! Get help!"); 576 break; 577 } 578 return (NULL); 579 } 580 581 char * 582 to_dir(c) 583 { 584 p.new_dir = dir_no(c); 585 return (NULL); 586 } 587 588 char * 589 rel_dir(c) 590 { 591 int angle; 592 593 angle = dir_no(c); 594 switch (dir) { 595 case D_LEFT: 596 p.new_dir = p.dir - angle; 597 if (p.new_dir < 0) 598 p.new_dir += MAXDIR; 599 break; 600 case D_RIGHT: 601 p.new_dir = p.dir + angle; 602 if (p.new_dir >= MAXDIR) 603 p.new_dir -= MAXDIR; 604 break; 605 default: 606 return ("Bizarre direction in rel_dir! Get help!"); 607 break; 608 } 609 return (NULL); 610 } 611 612 char * 613 mark(c) 614 { 615 if (p.altitude == 0) 616 return ("Cannot mark planes on the ground"); 617 if (p.status == S_MARKED) 618 return ("Already marked"); 619 p.status = S_MARKED; 620 return (NULL); 621 } 622 623 char * 624 unmark(c) 625 { 626 if (p.altitude == 0) 627 return ("Cannot unmark planes on the ground"); 628 if (p.status == S_UNMARKED) 629 return ("Already unmarked"); 630 p.status = S_UNMARKED; 631 return (NULL); 632 } 633 634 char * 635 ignore(c) 636 { 637 if (p.altitude == 0) 638 return ("Cannot ignore planes on the ground"); 639 if (p.status == S_IGNORED) 640 return ("Already ignored"); 641 p.status = S_IGNORED; 642 return (NULL); 643 } 644 645 dir_no(ch) 646 char ch; 647 { 648 int dir; 649 650 switch (ch) { 651 case 'w': dir = 0; break; 652 case 'e': dir = 1; break; 653 case 'd': dir = 2; break; 654 case 'c': dir = 3; break; 655 case 'x': dir = 4; break; 656 case 'z': dir = 5; break; 657 case 'a': dir = 6; break; 658 case 'q': dir = 7; break; 659 default: 660 fprintf(stderr, "bad character in dir_no\n"); 661 break; 662 } 663 return (dir); 664 } 665