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