1 /* $NetBSD: input.c,v 1.14 2001/01/16 02:50:28 cgd Exp $ */ 2 3 /*- 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Ed James. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. 41 * 42 * Copy permission is hereby granted provided that this notice is 43 * retained on all partial or complete copies. 44 * 45 * For more info on this and all of my stuff, mail edjames@berkeley.edu. 46 */ 47 48 #include <sys/cdefs.h> 49 #ifndef lint 50 #if 0 51 static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 5/31/93"; 52 #else 53 __RCSID("$NetBSD: input.c,v 1.14 2001/01/16 02:50:28 cgd Exp $"); 54 #endif 55 #endif /* not lint */ 56 57 #include "include.h" 58 #include "pathnames.h" 59 60 #define MAXRULES 6 61 #define MAXDEPTH 15 62 63 #define RETTOKEN '\n' 64 #define REDRAWTOKEN '\014' /* CTRL(L) */ 65 #define SHELLTOKEN '!' 66 #define HELPTOKEN '?' 67 #define ALPHATOKEN 256 68 #define NUMTOKEN 257 69 70 typedef struct { 71 int token; 72 int to_state; 73 const char *str; 74 const char *(*func) __P((char)); 75 } RULE; 76 77 typedef struct { 78 int num_rules; 79 RULE *rule; 80 } STATE; 81 82 typedef struct { 83 char str[20]; 84 int state; 85 int rule; 86 int ch; 87 int pos; 88 } STACK; 89 90 #define T_RULE stack[level].rule 91 #define T_STATE stack[level].state 92 #define T_STR stack[level].str 93 #define T_POS stack[level].pos 94 #define T_CH stack[level].ch 95 96 #define NUMELS(a) (sizeof (a) / sizeof (*(a))) 97 98 #define NUMSTATES NUMELS(st) 99 100 101 RULE state0[] = { { ALPHATOKEN, 1, "%c:", setplane}, 102 { RETTOKEN, -1, "", NULL }, 103 { HELPTOKEN, 12, " [a-z]<ret>", NULL }}, 104 state1[] = { { 't', 2, " turn", turn }, 105 { 'a', 3, " altitude:", NULL }, 106 { 'c', 4, " circle", circle }, 107 { 'm', 7, " mark", mark }, 108 { 'u', 7, " unmark", unmark }, 109 { 'i', 7, " ignore", ignore }, 110 { HELPTOKEN, 12, " tacmui", NULL }}, 111 state2[] = { { 'l', 6, " left", left }, 112 { 'r', 6, " right", right }, 113 { 'L', 4, " left 90", Left }, 114 { 'R', 4, " right 90", Right }, 115 { 't', 11, " towards", NULL }, 116 { 'w', 4, " to 0", to_dir }, 117 { 'e', 4, " to 45", to_dir }, 118 { 'd', 4, " to 90", to_dir }, 119 { 'c', 4, " to 135", to_dir }, 120 { 'x', 4, " to 180", to_dir }, 121 { 'z', 4, " to 225", to_dir }, 122 { 'a', 4, " to 270", to_dir }, 123 { 'q', 4, " to 315", to_dir }, 124 { HELPTOKEN, 12, " lrLRt<dir>", NULL }}, 125 state3[] = { { '+', 10, " climb", climb }, 126 { 'c', 10, " climb", climb }, 127 { '-', 10, " descend", descend }, 128 { 'd', 10, " descend", descend }, 129 { NUMTOKEN, 7, " %c000 feet", setalt }, 130 { HELPTOKEN, 12, " +-cd[0-9]", NULL }}, 131 state4[] = { { '@', 9, " at", NULL }, 132 { 'a', 9, " at", NULL }, 133 { RETTOKEN, -1, "", NULL }, 134 { HELPTOKEN, 12, " @a<ret>", NULL }}, 135 state5[] = { { NUMTOKEN, 7, "%c", delayb }, 136 { HELPTOKEN, 12, " [0-9]", NULL }}, 137 state6[] = { { '@', 9, " at", NULL }, 138 { 'a', 9, " at", NULL }, 139 { 'w', 4, " 0", rel_dir }, 140 { 'e', 4, " 45", rel_dir }, 141 { 'd', 4, " 90", rel_dir }, 142 { 'c', 4, " 135", rel_dir }, 143 { 'x', 4, " 180", rel_dir }, 144 { 'z', 4, " 225", rel_dir }, 145 { 'a', 4, " 270", rel_dir }, 146 { 'q', 4, " 315", rel_dir }, 147 { RETTOKEN, -1, "", NULL }, 148 { HELPTOKEN, 12, " @a<dir><ret>",NULL }}, 149 state7[] = { { RETTOKEN, -1, "", NULL }, 150 { HELPTOKEN, 12, " <ret>", NULL }}, 151 state8[] = { { NUMTOKEN, 4, "%c", benum }, 152 { HELPTOKEN, 12, " [0-9]", NULL }}, 153 state9[] = { { 'b', 5, " beacon #", NULL }, 154 { '*', 5, " beacon #", NULL }, 155 { HELPTOKEN, 12, " b*", NULL }}, 156 state10[] = { { NUMTOKEN, 7, " %c000 ft", setrelalt}, 157 { HELPTOKEN, 12, " [0-9]", NULL }}, 158 state11[] = { { 'b', 8, " beacon #", beacon }, 159 { '*', 8, " beacon #", beacon }, 160 { 'e', 8, " exit #", ex_it }, 161 { 'a', 8, " airport #", airport }, 162 { HELPTOKEN, 12, " b*ea", NULL }}, 163 state12[] = { { -1, -1, "", NULL }}; 164 165 #define DEF_STATE(s) { NUMELS(s), (s) } 166 167 STATE st[] = { 168 DEF_STATE(state0), DEF_STATE(state1), DEF_STATE(state2), 169 DEF_STATE(state3), DEF_STATE(state4), DEF_STATE(state5), 170 DEF_STATE(state6), DEF_STATE(state7), DEF_STATE(state8), 171 DEF_STATE(state9), DEF_STATE(state10), DEF_STATE(state11), 172 DEF_STATE(state12) 173 }; 174 175 PLANE p; 176 STACK stack[MAXDEPTH]; 177 int level; 178 int tval; 179 int dest_type, dest_no, dir; 180 181 int 182 pop() 183 { 184 if (level == 0) 185 return (-1); 186 level--; 187 188 ioclrtoeol(T_POS); 189 190 strcpy(T_STR, ""); 191 T_RULE = -1; 192 T_CH = -1; 193 return (0); 194 } 195 196 void 197 rezero() 198 { 199 iomove(0); 200 201 level = 0; 202 T_STATE = 0; 203 T_RULE = -1; 204 T_CH = -1; 205 T_POS = 0; 206 strcpy(T_STR, ""); 207 } 208 209 void 210 push(ruleno, ch) 211 int ruleno, ch; 212 { 213 int newstate, newpos; 214 215 (void)sprintf(T_STR, st[T_STATE].rule[ruleno].str, tval); 216 T_RULE = ruleno; 217 T_CH = ch; 218 newstate = st[T_STATE].rule[ruleno].to_state; 219 newpos = T_POS + strlen(T_STR); 220 221 ioaddstr(T_POS, T_STR); 222 223 if (level == 0) 224 ioclrtobot(); 225 level++; 226 T_STATE = newstate; 227 T_POS = newpos; 228 T_RULE = -1; 229 strcpy(T_STR, ""); 230 } 231 232 int 233 getcommand() 234 { 235 int c, i, done; 236 const char *s, *(*func) __P((char)); 237 PLANE *pp; 238 239 rezero(); 240 241 do { 242 c = gettoken(); 243 if (c == tty_new.c_cc[VERASE]) { 244 if (pop() < 0) 245 noise(); 246 } else if (c == tty_new.c_cc[VKILL]) { 247 while (pop() >= 0) 248 ; 249 } else { 250 done = 0; 251 for (i = 0; i < st[T_STATE].num_rules; i++) { 252 if (st[T_STATE].rule[i].token == c || 253 st[T_STATE].rule[i].token == tval) { 254 push(i, (c >= ALPHATOKEN) ? tval : c); 255 done = 1; 256 break; 257 } 258 } 259 if (!done) 260 noise(); 261 } 262 } while (T_STATE != -1); 263 264 if (level == 1) 265 return (1); /* forced update */ 266 267 dest_type = T_NODEST; 268 269 for (i = 0; i < level; i++) { 270 func = st[stack[i].state].rule[stack[i].rule].func; 271 if (func != NULL) 272 if ((s = (*func)(stack[i].ch)) != NULL) { 273 ioerror(stack[i].pos, strlen(stack[i].str), s); 274 return (-1); 275 } 276 } 277 278 pp = findplane(p.plane_no); 279 if (pp->new_altitude != p.new_altitude) 280 pp->new_altitude = p.new_altitude; 281 else if (pp->status != p.status) 282 pp->status = p.status; 283 else { 284 pp->new_dir = p.new_dir; 285 pp->delayd = p.delayd; 286 pp->delayd_no = p.delayd_no; 287 } 288 return (0); 289 } 290 291 void 292 noise() 293 { 294 putchar('\07'); 295 fflush(stdout); 296 } 297 298 int 299 gettoken() 300 { 301 while ((tval = getAChar()) == REDRAWTOKEN || tval == SHELLTOKEN) 302 { 303 if (tval == SHELLTOKEN) 304 { 305 #ifdef BSD 306 struct itimerval itv; 307 itv.it_value.tv_sec = 0; 308 itv.it_value.tv_usec = 0; 309 setitimer(ITIMER_REAL, &itv, NULL); 310 #endif 311 #ifdef SYSV 312 int aval; 313 aval = alarm(0); 314 #endif 315 if (fork() == 0) /* child */ 316 { 317 char *shell, *base; 318 319 done_screen(); 320 321 /* run user's favorite shell */ 322 if ((shell = getenv("SHELL")) != NULL) 323 { 324 base = strrchr(shell, '/'); 325 if (base == NULL) 326 base = shell; 327 else 328 base++; 329 execl(shell, base, 0); 330 } 331 else 332 execl(_PATH_BSHELL, "sh", 0); 333 334 exit(0); /* oops */ 335 } 336 337 wait(0); 338 tcsetattr(fileno(stdin), TCSADRAIN, &tty_new); 339 #ifdef BSD 340 itv.it_value.tv_sec = 0; 341 itv.it_value.tv_usec = 1; 342 itv.it_interval.tv_sec = sp->update_secs; 343 itv.it_interval.tv_usec = 0; 344 setitimer(ITIMER_REAL, &itv, NULL); 345 #endif 346 #ifdef SYSV 347 alarm(aval); 348 #endif 349 } 350 redraw(); 351 } 352 353 if (isdigit(tval)) 354 return (NUMTOKEN); 355 else if (isalpha(tval)) 356 return (ALPHATOKEN); 357 else 358 return (tval); 359 } 360 361 const char * 362 setplane(c) 363 char c; 364 { 365 PLANE *pp; 366 367 pp = findplane(number(c)); 368 if (pp == NULL) 369 return ("Unknown Plane"); 370 memcpy(&p, pp, sizeof (p)); 371 p.delayd = 0; 372 return (NULL); 373 } 374 375 const char * 376 turn(c) 377 char c __attribute__((__unused__)); 378 { 379 if (p.altitude == 0) 380 return ("Planes at airports may not change direction"); 381 return (NULL); 382 } 383 384 const char * 385 circle(c) 386 char c __attribute__((__unused__)); 387 { 388 if (p.altitude == 0) 389 return ("Planes cannot circle on the ground"); 390 p.new_dir = MAXDIR; 391 return (NULL); 392 } 393 394 const char * 395 left(c) 396 char c __attribute__((__unused__)); 397 { 398 dir = D_LEFT; 399 p.new_dir = p.dir - 1; 400 if (p.new_dir < 0) 401 p.new_dir += MAXDIR; 402 return (NULL); 403 } 404 405 const char * 406 right(c) 407 char c __attribute__((__unused__)); 408 { 409 dir = D_RIGHT; 410 p.new_dir = p.dir + 1; 411 if (p.new_dir >= MAXDIR) 412 p.new_dir -= MAXDIR; 413 return (NULL); 414 } 415 416 const char * 417 Left(c) 418 char c __attribute__((__unused__)); 419 { 420 p.new_dir = p.dir - 2; 421 if (p.new_dir < 0) 422 p.new_dir += MAXDIR; 423 return (NULL); 424 } 425 426 const char * 427 Right(c) 428 char c __attribute__((__unused__)); 429 { 430 p.new_dir = p.dir + 2; 431 if (p.new_dir >= MAXDIR) 432 p.new_dir -= MAXDIR; 433 return (NULL); 434 } 435 436 const char * 437 delayb(c) 438 char 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[(int)c].x - p.xpos; 447 xdiff = SGN(xdiff); 448 ydiff = sp->beacon[(int)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[(int)c].x; 459 ydiff = sp->beacon[dest_no].y - sp->beacon[(int)c].y; 460 break; 461 case T_EXIT: 462 xdiff = sp->exit[dest_no].x - sp->beacon[(int)c].x; 463 ydiff = sp->exit[dest_no].y - sp->beacon[(int)c].y; 464 break; 465 case T_AIRPORT: 466 xdiff = sp->airport[dest_no].x - sp->beacon[(int)c].x; 467 ydiff = sp->airport[dest_no].y - sp->beacon[(int)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 const char * 483 beacon(c) 484 char c __attribute__((__unused__)); 485 { 486 dest_type = T_BEACON; 487 return (NULL); 488 } 489 490 const char * 491 ex_it(c) 492 char c __attribute__((__unused__)); 493 { 494 dest_type = T_EXIT; 495 return (NULL); 496 } 497 498 const char * 499 airport(c) 500 char c __attribute__((__unused__)); 501 { 502 dest_type = T_AIRPORT; 503 return (NULL); 504 } 505 506 const char * 507 climb(c) 508 char c __attribute__((__unused__)); 509 { 510 dir = D_UP; 511 return (NULL); 512 } 513 514 const char * 515 descend(c) 516 char c __attribute__((__unused__)); 517 { 518 dir = D_DOWN; 519 return (NULL); 520 } 521 522 const char * 523 setalt(c) 524 char c; 525 { 526 if ((p.altitude == c - '0') && (p.new_altitude == p.altitude)) 527 return ("Already at that altitude"); 528 p.new_altitude = c - '0'; 529 return (NULL); 530 } 531 532 const char * 533 setrelalt(c) 534 char c; 535 { 536 if (c == 0) 537 return ("altitude not changed"); 538 539 switch (dir) { 540 case D_UP: 541 p.new_altitude = p.altitude + c - '0'; 542 break; 543 case D_DOWN: 544 p.new_altitude = p.altitude - (c - '0'); 545 break; 546 default: 547 return ("Unknown case in setrelalt! Get help!"); 548 break; 549 } 550 if (p.new_altitude < 0) 551 return ("Altitude would be too low"); 552 else if (p.new_altitude > 9) 553 return ("Altitude would be too high"); 554 return (NULL); 555 } 556 557 const char * 558 benum(c) 559 char c; 560 { 561 dest_no = c -= '0'; 562 563 switch (dest_type) { 564 case T_BEACON: 565 if (c >= sp->num_beacons) 566 return ("Unknown beacon"); 567 p.new_dir = DIR_FROM_DXDY(sp->beacon[(int)c].x - p.xpos, 568 sp->beacon[(int)c].y - p.ypos); 569 break; 570 case T_EXIT: 571 if (c >= sp->num_exits) 572 return ("Unknown exit"); 573 p.new_dir = DIR_FROM_DXDY(sp->exit[(int)c].x - p.xpos, 574 sp->exit[(int)c].y - p.ypos); 575 break; 576 case T_AIRPORT: 577 if (c >= sp->num_airports) 578 return ("Unknown airport"); 579 p.new_dir = DIR_FROM_DXDY(sp->airport[(int)c].x - p.xpos, 580 sp->airport[(int)c].y - p.ypos); 581 break; 582 default: 583 return ("Unknown case in benum! Get help!"); 584 break; 585 } 586 return (NULL); 587 } 588 589 const char * 590 to_dir(c) 591 char c; 592 { 593 p.new_dir = dir_no(c); 594 return (NULL); 595 } 596 597 const char * 598 rel_dir(c) 599 char c; 600 { 601 int angle; 602 603 angle = dir_no(c); 604 switch (dir) { 605 case D_LEFT: 606 p.new_dir = p.dir - angle; 607 if (p.new_dir < 0) 608 p.new_dir += MAXDIR; 609 break; 610 case D_RIGHT: 611 p.new_dir = p.dir + angle; 612 if (p.new_dir >= MAXDIR) 613 p.new_dir -= MAXDIR; 614 break; 615 default: 616 return ("Bizarre direction in rel_dir! Get help!"); 617 break; 618 } 619 return (NULL); 620 } 621 622 const char * 623 mark(c) 624 char c __attribute__((__unused__)); 625 { 626 if (p.altitude == 0) 627 return ("Cannot mark planes on the ground"); 628 if (p.status == S_MARKED) 629 return ("Already marked"); 630 p.status = S_MARKED; 631 return (NULL); 632 } 633 634 const char * 635 unmark(c) 636 char c __attribute__((__unused__)); 637 { 638 if (p.altitude == 0) 639 return ("Cannot unmark planes on the ground"); 640 if (p.status == S_UNMARKED) 641 return ("Already unmarked"); 642 p.status = S_UNMARKED; 643 return (NULL); 644 } 645 646 const char * 647 ignore(c) 648 char c __attribute__((__unused__)); 649 { 650 if (p.altitude == 0) 651 return ("Cannot ignore planes on the ground"); 652 if (p.status == S_IGNORED) 653 return ("Already ignored"); 654 p.status = S_IGNORED; 655 return (NULL); 656 } 657 658 int 659 dir_no(ch) 660 char ch; 661 { 662 int dir; 663 664 dir = -1; 665 switch (ch) { 666 case 'w': dir = 0; break; 667 case 'e': dir = 1; break; 668 case 'd': dir = 2; break; 669 case 'c': dir = 3; break; 670 case 'x': dir = 4; break; 671 case 'z': dir = 5; break; 672 case 'a': dir = 6; break; 673 case 'q': dir = 7; break; 674 default: 675 fprintf(stderr, "bad character in dir_no\n"); 676 break; 677 } 678 return (dir); 679 } 680