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