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