xref: /netbsd-src/games/warp/term.c (revision 1182a44c59cae4d586117d55eca24b4b8b173211)
1 /* Header: term.c,v 7.0.1.2 86/12/12 17:04:09 lwall Exp */
2 
3 /* Log:	term.c,v
4  * Revision 7.0.1.2  86/12/12  17:04:09  lwall
5  * Baseline for net release.
6  *
7  * Revision 7.0.1.1  86/10/16  10:53:20  lwall
8  * Added Damage.  Fixed random bugs.
9  *
10  * Revision 7.0  86/10/08  15:14:02  lwall
11  * Split into separate files.  Added amoebas and pirates.
12  *
13  */
14 
15 #include "EXTERN.h"
16 #include "warp.h"
17 #include "bang.h"
18 #include "intrp.h"
19 #include "object.h"
20 #include "play.h"
21 #include "score.h"
22 #include "sig.h"
23 #include "us.h"
24 #include "util.h"
25 #include "weapon.h"
26 #include "INTERN.h"
27 #include "term.h"
28 
29 int typeahead = false;
30 
31 char tcarea[TCSIZE];	/* area for "compiled" termcap strings */
32 
33 /* guarantee capability pointer != NULL */
34 /* (I believe terminfo will ignore the &tmpaddr argument.) */
35 
36 #define Tgetstr(key) ((tstr = tgetstr(key,&tmpaddr)) ? tstr : nullstr)
37 
38 #ifdef PUSHBACK
39 struct keymap {
40     char km_type[128];
41     union km_union {
42 	struct keymap *km_km;
43 	char *km_str;
44     } km_ptr[128];
45 };
46 
47 #define KM_NOTHIN 0
48 #define KM_STRING 1
49 #define KM_KEYMAP 2
50 #define KM_BOGUS 3
51 
52 #define KM_TMASK 3
53 #define KM_GSHIFT 4
54 #define KM_GMASK 7
55 
56 typedef struct keymap KEYMAP;
57 
58 KEYMAP *topmap INIT(NULL);
59 
60 void mac_init(char *);
61 static KEYMAP *newkeymap(void);
62 void pushstring(char *);
63 #endif
64 
65 /* terminal initialization */
66 
67 void
term_init(void)68 term_init(void)
69 {
70     savetty();				/* remember current tty state */
71 
72 #if defined(TERMIO) || defined(TERMIOS)
73     ospeed = cfgetospeed(&_tty);
74     ERASECH = _tty.c_cc[VERASE];	/* for finish_command() */
75     KILLCH = _tty.c_cc[VKILL];		/* for finish_command() */
76 #else
77     ospeed = _tty.sg_ospeed;		/* for tputs() */
78     ERASECH = _tty.sg_erase;		/* for finish_command() */
79     KILLCH = _tty.sg_kill;		/* for finish_command() */
80 #endif
81 
82     /* The following could be a table but I can't be sure that there isn't */
83     /* some degree of sparsity out there in the world. */
84 
85     switch (ospeed) {			/* 1 second of padding */
86 #ifdef BEXTA
87         case BEXTA:  just_a_sec = 1920; break;
88 #else
89 #ifdef B19200
90         case B19200: just_a_sec = 1920; break;
91 #endif
92 #endif
93         case B9600:  just_a_sec =  960; break;
94         case B4800:  just_a_sec =  480; break;
95         case B2400:  just_a_sec =  240; break;
96         case B1800:  just_a_sec =  180; break;
97         case B1200:  just_a_sec =  120; break;
98         case B600:   just_a_sec =   60; break;
99 	case B300:   just_a_sec =   30; break;
100 	/* do I really have to type the rest of this??? */
101         case B200:   just_a_sec =   20; break;
102         case B150:   just_a_sec =   15; break;
103         case B134:   just_a_sec =   13; break;
104         case B110:   just_a_sec =   11; break;
105         case B75:    just_a_sec =    8; break;
106         case B50:    just_a_sec =    5; break;
107         default:     just_a_sec =  960; break;
108 					/* if we are running detached I */
109     }					/*  don't want to know about it! */
110 }
111 
112 /* set terminal characteristics */
113 
114 void
term_set(char * tcbuf)115 term_set(char *tcbuf) /* temp area for "uncompiled" termcap entry */
116 {
117     char *tmpaddr;			/* must not be register */
118     char *tstr;
119     char *s;
120     int retval;
121 
122 #ifdef PENDING
123 #ifndef FIONREAD
124 #ifndef RDCHK
125     /* do no delay reads on something that always gets closed on exit */
126 
127     devtty = open("/dev/tty",0);
128     if (devtty < 0) {
129 	printf(cantopen,"/dev/tty");
130 	finalize(1);
131     }
132     fcntl(devtty,F_SETFL,O_NDELAY);
133 #endif
134 #endif
135 #endif
136 
137     /* get all that good termcap stuff */
138 
139     retval = tgetent(tcbuf,getenv("TERM"));	/* get termcap entry */
140     if (retval < 1) {
141 #ifdef VERBOSE
142 	printf("No termcap %s found.\n", retval ? "file" : "entry");
143 #else
144 	fputs("Termcap botch\n",stdout);
145 #endif
146 	finalize(1);
147     }
148     tmpaddr = tcarea;			/* set up strange tgetstr pointer */
149     s = Tgetstr("pc");			/* get pad character */
150     PC = *s;				/* get it where tputs wants it */
151     if (!tgetflag("bs")) {		/* is backspace not used? */
152 	BC = Tgetstr("bc");		/* find out what is */
153 	if (BC == nullstr) 		/* terminfo grok's 'bs' but not 'bc' */
154 	    BC = Tgetstr("le");
155     } else
156 	BC = __UNCONST("\b");		/* make a backspace handy */
157     UP = Tgetstr("up");			/* move up a line */
158     ND = Tgetstr("nd");			/* non-destructive move cursor right */
159     DO = Tgetstr("do");			/* move cursor down */
160     if (!*DO)
161 	DO = Tgetstr("nl");
162     CL = Tgetstr("cl");			/* get clear string */
163     CE = Tgetstr("ce");			/* clear to end of line string */
164     CM = Tgetstr("cm");			/* cursor motion - PWP */
165     HO = Tgetstr("ho");			/* home cursor if no CM - PWP */
166     CD = Tgetstr("cd");			/* clear to end of display - PWP */
167     SO = Tgetstr("so");			/* begin standout */
168     SE = Tgetstr("se");			/* end standout */
169     if ((SG = tgetnum("sg"))<0)
170 	SG = 0;				/* blanks left by SG, SE */
171     US = Tgetstr("us");			/* start underline */
172     UE = Tgetstr("ue");			/* end underline */
173     if ((UG = tgetnum("ug"))<0)
174 	UG = 0;				/* blanks left by US, UE */
175     if (*US)
176 	UC = nullstr;			/* UC must not be NULL */
177     else
178 	UC = Tgetstr("uc");		/* underline a character */
179     if (!*US && !*UC) {			/* no underline mode? */
180 	US = SO;			/* substitute standout mode */
181 	UE = SE;
182 	UG = SG;
183     }
184     LINES = tgetnum("li");		/* lines per page */
185     COLS = tgetnum("co");		/* columns on page */
186     AM = tgetflag("am");		/* terminal wraps automatically? */
187     XN = tgetflag("xn");		/* then eats next newline? */
188     VB = Tgetstr("vb");
189     if (!*VB)
190 	VB = __UNCONST("\007");
191     CR = Tgetstr("cr");
192     if (!*CR) {
193 	if (tgetflag("nc") && *UP) {
194 	    size_t l = strlen(UP) + 2;
195 	    CR = safemalloc(l);
196 	    snprintf(CR, l, "%s\r",UP);
197 	}
198 	else
199 	    CR = __UNCONST("\r");
200     }
201     if (LINES <= 0)
202 	LINES = 24;
203     if (COLS <= 0)
204 	COLS = 80;
205 
206     BCsize = comp_tc(bsptr,BC,1);
207     BC = bsptr;
208 
209     if (!*ND)				/* not defined? */
210 	NDsize = 1000;			/* force cursor addressing */
211     else {
212 	NDsize = comp_tc(cmbuffer,ND,1);
213 	myND = malloc((unsigned)NDsize);
214 	movc3(NDsize,cmbuffer,myND);
215 	if (debugging) {
216 	    int scr;
217 
218 	    printf("ND");
219 	    for (scr=0; scr<NDsize; scr++)
220 		printf(" %d",myND[scr]);
221 	    printf("\n");
222 	}
223     }
224 
225     if (!*UP)				/* not defined? */
226 	UPsize = 1000;			/* force cursor addressing */
227     else {
228 	UPsize = comp_tc(cmbuffer,UP,1);
229 	myUP = malloc((unsigned)UPsize);
230 	movc3(UPsize,cmbuffer,myUP);
231 	if (debugging) {
232 	    int scr;
233 
234 	    printf("UP");
235 	    for (scr=0; scr<UPsize; scr++)
236 		printf(" %d",myUP[scr]);
237 	    printf("\n");
238 	}
239     }
240 
241     if (!*DO) {				/* not defined? */
242 	myDO = DO = __UNCONST("\n");		/* assume a newline */
243 	DOsize = 1;
244     }
245     else {
246 	DOsize = comp_tc(cmbuffer,DO,1);
247 	myDO = malloc((unsigned)DOsize);
248 	movc3(DOsize,cmbuffer,myDO);
249 	if (debugging) {
250 	    int scr;
251 
252 	    printf("DO");
253 	    for (scr=0; scr<DOsize; scr++)
254 		printf(" %d",myDO[scr]);
255 	    printf("\n");
256 	}
257     }
258     if (debugging)
259 	fgets(cmbuffer,(sizeof cmbuffer),stdin);
260 
261     CMsize = comp_tc(cmbuffer,tgoto(CM,20,20),0);
262     if (PC != '\0') {
263 	char *p;
264 
265 	for (p=filler+(sizeof filler)-1;!*p;--p)
266 	    *p = PC;
267     }
268     charsperhalfsec = (speed_t)ospeed >= B9600 ? (speed_t)480 :
269 		      (speed_t)ospeed == B4800 ? (speed_t)240 :
270 		      (speed_t)ospeed == B2400 ? (speed_t)120 :
271 		      (speed_t)ospeed == B1200 ? (speed_t)60 :
272 		      (speed_t)ospeed == B600 ? (speed_t)30 :
273 	      /* speed is 300 (?) */   (speed_t)15;
274 
275     gfillen = (speed_t)ospeed >= B9600 ? (speed_t)(sizeof filler) :
276 	      (speed_t)ospeed == B4800 ? (speed_t)13 :
277 	      (speed_t)ospeed == B2400 ? (speed_t)7 :
278 	      (speed_t)ospeed == B1200 ? (speed_t)4 :
279 				(speed_t)(1+BCsize);
280     if ((speed_t)ospeed < B2400)
281 	lowspeed = true;
282 
283     strcpy(term,ttyname(2));
284 
285     if (!*CM || !BCsize)
286 	no_can_do("dumb");
287     if (!scorespec && (LINES < 24 || COLS < 80))
288 	no_can_do("puny");
289 //    if (LINES > 25)
290 //	no_can_do("humongous");
291 
292     crmode();
293     raw();
294     noecho();				/* turn off echo */
295     nonl();
296 
297 #ifdef PUSHBACK
298     mac_init(tcbuf);
299 #endif
300 }
301 
302 #ifdef PUSHBACK
303 void
mac_init(char * tcbuf)304 mac_init(char *tcbuf)
305 {
306     char tmpbuf[1024];
307 
308     tmpfp = fopen(filexp(getval("WARPMACRO",WARPMACRO)),"r");
309     if (tmpfp != NULL) {
310 	while (fgets(tcbuf,1024,tmpfp) != NULL) {
311 	    mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
312 	}
313 	fclose(tmpfp);
314     }
315 }
316 
317 void
mac_line(char * line,char * tmpbuf,size_t tbsize)318 mac_line(char *line, char *tmpbuf, size_t tbsize)
319 {
320     char *s;
321     char *m;
322     KEYMAP *curmap;
323     int ch;
324     int garbage = 0;
325     static const char override[] = "\r\nkeymap overrides string\r\n";
326 
327     if (topmap == NULL)
328 	topmap = newkeymap();
329     if (*line == '#' || *line == '\n')
330 	return;
331     if (line[ch = strlen(line)-1] == '\n')
332 	line[ch] = '\0';
333     m = dointerp(tmpbuf,tbsize,line," \t");
334     if (!*m)
335 	return;
336     while (*m == ' ' || *m == '\t') m++;
337     for (s=tmpbuf,curmap=topmap; *s; s++) {
338 	ch = *s & 0177;
339 	if (s[1] == '+' && isdigit((unsigned char)s[2])) {
340 	    s += 2;
341 	    garbage = (*s & KM_GMASK) << KM_GSHIFT;
342 	}
343 	else
344 	    garbage = 0;
345 	if (s[1]) {
346 	    if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
347 		puts(override);
348 		free(curmap->km_ptr[ch].km_str);
349 		curmap->km_ptr[ch].km_str = NULL;
350 	    }
351 	    curmap->km_type[ch] = KM_KEYMAP + garbage;
352 	    if (curmap->km_ptr[ch].km_km == NULL)
353 		curmap->km_ptr[ch].km_km = newkeymap();
354 	    curmap = curmap->km_ptr[ch].km_km;
355 	}
356 	else {
357 	    if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
358 		puts(override);
359 	    else {
360 		curmap->km_type[ch] = KM_STRING + garbage;
361 		curmap->km_ptr[ch].km_str = savestr(m);
362 	    }
363 	}
364     }
365 }
366 
367 static KEYMAP*
newkeymap(void)368 newkeymap(void)
369 {
370     int i;
371     KEYMAP *map;
372 
373 #ifndef lint
374     map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
375 #else
376     map = Null(KEYMAP*);
377 #endif /* lint */
378     for (i=127; i>=0; --i) {
379 	map->km_ptr[i].km_km = NULL;
380 	map->km_type[i] = KM_NOTHIN;
381     }
382     return map;
383 }
384 
385 #endif
386 
387 /* print out a file, stopping at form feeds */
388 
389 void
page(const char * filename,size_t num)390 page(const char *filename, size_t num)
391 {
392     int linenum = 1;
393 
394     tmpfp = fopen(filename,"r");
395     if (tmpfp != NULL) {
396 	while (fgets(spbuf,(sizeof spbuf),tmpfp) != NULL) {
397 	    if (*spbuf == '\f') {
398 		printf("[Type anything to continue] ");
399 		fflush(stdout);
400 		getcmd(spbuf);
401 		printf("\r\n");
402 		if (*spbuf == INTRCH)
403 		    finalize(0);
404 		if (*spbuf == 'q' || *spbuf == 'Q')
405 		    break;
406 	    }
407 	    else {
408 		if (num)
409 		    printf("%3d   %s\r",linenum++,spbuf);
410 		else
411 		    printf("%s\r",spbuf);
412 	    }
413 	}
414 	fclose(tmpfp);
415     }
416 }
417 
418 void
move(int y,int x,int chadd)419 move(int y, int x, int chadd)
420 {
421     int ydist;
422     int xdist;
423     int i;
424     char *s;
425 
426     ydist = y - real_y;
427     xdist = x - real_x;
428     i = ydist * (ydist < 0 ? -UPsize : DOsize) +
429         xdist * (xdist < 0 ? -BCsize : NDsize);
430     beg_qwrite();
431     if (i <= CMsize) {
432 	if (ydist < 0)
433 	    for (; ydist; ydist++)
434 		for (i=UPsize,s=myUP; i; i--)
435 		    qaddch(*s++);
436 	else
437 	    for (; ydist; ydist--)
438 		for (i=DOsize,s=myDO; i; i--)
439 		    qaddch(*s++);
440 	if (xdist < 0)
441 	    for (; xdist; xdist++)
442 		for (i=BCsize,s=BC; i; i--)
443 		    qaddch(*s++);
444 	else
445 	    for (; xdist; xdist--)
446 		for (i=NDsize,s=myND; i; i--)
447 		    qaddch(*s++);
448     }
449     else {
450 	tputs(tgoto(CM,x,y),0,cmstore);
451     }
452     real_y = y;
453     real_x = x;
454     if (chadd) {
455 	qaddch(chadd);
456     }
457     if (maxcmstring != cmbuffer)
458 	end_qwrite();
459 }
460 
461 void
do_tc(const char * s,int l)462 do_tc(const char *s, int l)
463 {
464     beg_qwrite();
465     tputs(s,l,cmstore);
466     end_qwrite();
467 }
468 
469 int
comp_tc(char * dest,const char * s,int l)470 comp_tc(char *dest, const char *s, int l)
471 {
472     maxcmstring = dest;
473     tputs(s,l,cmstore);
474     return(maxcmstring-dest);
475 }
476 
477 void
helper(void)478 helper(void)
479 {
480     clear();
481     mvaddstr(0,4,"h or 4          left");
482     mvaddstr(1,4,"j or 2          down                Use with SHIFT to fire torpedoes.");
483     mvaddstr(2,4,"k or 8          up                  Use with CTRL or FUNCT to fire");
484     mvaddstr(3,4,"l or 6          right                   phasers or turbolasers.");
485     mvaddstr(4,4,"b or 1          down and left       Use preceded by 'a' or 'r' for");
486     mvaddstr(5,4,"n or 3          down and right          attractors or repulsors.");
487     mvaddstr(6,4,"y or 7          up and left         Use normally for E or B motion.");
488     mvaddstr(7,4,"u or 9          up and right");
489     mvaddstr(8,4,"");
490     mvaddstr(9,4,"del or %        fire photon torpedoes in every (reasonable) direction.");
491     mvaddstr(10,4,"s               stop all torpedoes.");
492     mvaddstr(11,4,"S or 0          stop the Enterprise when in warp mode.");
493     mvaddstr(12,4,"d/D             destruct all torpedoes/current vessel.");
494     mvaddstr(13,4,"i/w             switch to Enterprise & put into impulse/warp mode.");
495     mvaddstr(14,4,"c/v             switch to Enterprise & make cloaked/visible.");
496     mvaddstr(15,4,"p               switch to Base.");
497     mvaddstr(16,4,"o               toggle to other vessel (from E to B, or vice versa.)");
498     mvaddstr(17,4,"z               zap (suppress) blasts near Enterprise next cycle");
499     mvaddstr(18,4,"");
500     mvaddstr(19,4,"^R      refresh the screen.              ^Z      suspend the game.");
501     mvaddstr(20,4,"q       exit this round (if you haven't typed q within 10 cycles).");
502     mvaddstr(21,4,"Q       exit this game.");
503     mvaddstr(22,4,"");
504     mvaddstr(23,4,"                   [Hit space to continue]");
505     fflush(stdout);
506     do {
507 	getcmd(spbuf);
508     } while (*spbuf != ' ');
509     rewrite();
510 
511 }
512 
513 void
rewrite(void)514 rewrite(void)
515 {
516     int x;
517     int y;
518     OBJECT *obj;
519 
520     clear();
521     for (y=0; y<YSIZE; y++) {
522 	for (x=0; x<XSIZE; x++) {
523 	    if (numamoebas && amb[y][x] != ' ')
524 		mvaddc(y+1,x*2,amb[y][x]);
525 	    if ((obj = occupant[y][x]) != NULL) {
526 		if (obj->image != ' ')
527 		    mvaddc(y+1,x*2,obj->image);
528 	    }
529 	}
530     }
531     snprintf(spbuf, sizeof(spbuf),
532      "%-4s E: %4d %2d B: %5d %3d Enemies: %-3d Stars: %-3d Stardate%5d.%1d %9ld",
533 	"   ", 0, 0, 0, 0, 0, 0, timer/10+smarts*100, timer%10, 0L);
534     mvaddstr(0,0,spbuf);
535     oldeenergy = oldbenergy = oldcurscore =
536     oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1;
537 					/* force everything to fill in */
538     if (damage)
539 	olddamage = 0;
540     if (!ent)
541 	etorp = 0;
542     if (!base)
543 	btorp = 0;
544     display_status();
545 }
546 
547 int
cmstore(int ch)548 cmstore(int ch)
549 {
550     *maxcmstring++ = ch;
551     return 0;
552 }
553 
554 /* discard any characters typed ahead */
555 
556 void
eat_typeahead(void)557 eat_typeahead(void)
558 {
559 #ifdef PUSHBACK
560     if (!typeahead && nextin==nextout)	/* cancel only keyboard stuff */
561 #else
562     if (!typeahead)
563 #endif
564     {
565 #ifdef PENDING
566 	while (input_pending())
567 	    read_tty(buf,sizeof(buf));
568 #else /* this is probably v7, with no rdchk() */
569 	ioctl(_tty_ch,TIOCSETP,&_tty);
570 #endif
571     }
572 }
573 
574 void
settle_down(void)575 settle_down(void)
576 {
577     dingaling();
578     fflush(stdout);
579     sleep(1);
580 #ifdef PUSHBACK
581     nextout = nextin;			/* empty circlebuf */
582 #endif
583     eat_typeahead();
584 }
585 
586 #ifdef PUSHBACK
587 /* read a character from the terminal, with multi-character pushback */
588 
589 int
read_tty(char * addr,ssize_t size)590 read_tty(char *addr, ssize_t size)	/* ignored for now */
591 {
592     if (nextout != nextin) {
593 	*addr = circlebuf[nextout++];
594 	nextout %= PUSHSIZE;
595 	return 1;
596     }
597     else {
598 	size = read(0,addr,1);
599 	if (size < 0)
600 	    sig_catcher(SIGHUP);
601 	if (metakey) {
602 	    if (*addr & 0200) {
603 		pushchar(*addr & 0177);
604 		*addr = '\001';
605 	    }
606 	}
607 	else
608 	    *addr &= 0177;
609 	return 1;
610     }
611 }
612 
613 #ifdef PENDING
614 #ifndef FIONREAD
615 #ifndef RDCHK
616 int
circfill()617 circfill()
618 {
619     int howmany;
620     int i;
621 
622     assert (nextin == nextout);
623     howmany = read(devtty,circlebuf+nextin,metakey?1:PUSHSIZE-nextin);
624     if (howmany > 0) {
625 	if (metakey) {
626 	    if (circlebuf[nextin] & 0200) {
627 		circlebuf[nextin] &= 0177;
628 		pushchar('\001');
629 	    }
630 	}
631 	else
632 	    for (i = howmany+nextin-1; i >= nextin; i--)
633 		circlebuf[i] &= 0177;
634 	nextin += howmany;
635 	nextin %= PUSHSIZE;	/* may end up 1 if metakey */
636     }
637     return howmany;
638 }
639 #endif /* RDCHK */
640 #endif /* FIONREAD */
641 #endif /* PENDING */
642 
643 void
pushchar(int ch)644 pushchar(int ch)
645 {
646     nextout--;
647     if (nextout < 0)
648 	nextout = PUSHSIZE - 1;
649     if (nextout == nextin) {
650 	fputs("\r\npushback buffer overflow\r\n",stdout);
651 	sig_catcher(0);
652     }
653     circlebuf[nextout] = ch;
654 }
655 
656 #else /* PUSHBACK */
657 #ifndef read_tty
658 /* read a character from the terminal, with hacks for O_NDELAY reads */
659 
660 int
read_tty(addr,size)661 read_tty(addr,size)
662 char *addr;
663 int size;
664 {
665     if (is_input) {
666 	*addr = pending_ch;
667 	is_input = false;
668 	return 1;
669     }
670     else {
671 	size = read(0,addr,size);
672 	if (size < 0)
673 	    sig_catcher(SIGHUP);
674 	if (metakey) {
675 	    if (*addr & 0200) {
676 		pending_ch = *addr & 0177;
677 		is_input = true;
678 		*addr = '\001';
679 	    }
680 	}
681 	else
682 	    *addr &= 0177;
683 	return size;
684     }
685 }
686 #endif /* read_tty */
687 #endif /* PUSHBACK */
688 
689 int
read_nd(char * buff,size_t siz)690 read_nd(char *buff, size_t siz)
691 {
692     if (!input_pending())
693 	return 0;
694 
695     getcmd(buff);
696     return 1;
697 }
698 
699 /* get a character into a buffer */
700 
701 void
getcmd(char * wbuf)702 getcmd(char *wbuf)
703 {
704 #ifdef PUSHBACK
705     KEYMAP *curmap;
706     int i;
707     bool no_macros;
708     int times = 0;			/* loop detector */
709     char scrchar;
710     unsigned char *whatbuf = (void *)wbuf;
711 
712 tryagain:
713     curmap = topmap;
714 /*    no_macros = (whatbuf != buf && nextin == nextout);  */
715     no_macros = false;
716 #endif
717     for (;;) {
718 	errno = 0;
719 	if (read_tty(wbuf,1) < 0 && !errno)
720 	    errno = EINTR;
721 #ifdef read_tty
722 	if (metakey) {
723 	    if (*whatbuf & 0200) {
724 		*what_buf &= 037;	/* punt and hope they don't notice */
725 	    }
726 	}
727 	else
728 	    *whatbuf &= 0177;
729 #endif /* read_tty */
730 	if (errno && errno != EINTR) {
731 	    perror(readerr);
732 	    sig_catcher(0);
733 	}
734 #ifdef PUSHBACK
735 	if (*whatbuf & 0200 || no_macros) {
736 	    *whatbuf &= 0177;
737 	    goto got_canonical;
738 	}
739 	if (curmap == NULL)
740 	    goto got_canonical;
741 	for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
742 	    read_tty(&scrchar,1);
743 	}
744 	switch (curmap->km_type[*whatbuf] & KM_TMASK) {
745 	case KM_NOTHIN:			/* no entry? */
746 	    if (curmap == topmap)	/* unmapped canonical */
747 		goto got_canonical;
748 	    settle_down();
749 	    goto tryagain;
750 	case KM_KEYMAP:			/* another keymap? */
751 	    curmap = curmap->km_ptr[*whatbuf].km_km;
752 	    assert(curmap != NULL);
753 	    break;
754 	case KM_STRING:			/* a string? */
755 	    pushstring(curmap->km_ptr[*whatbuf].km_str);
756 	    if (++times > 20) {		/* loop? */
757 		fputs("\r\nmacro loop?\r\n",stdout);
758 		settle_down();
759 	    }
760 	    no_macros = false;
761 	    goto tryagain;
762 	}
763 #else
764 	*whatbuf &= 0177;
765 	break;
766 #endif
767     }
768 
769 got_canonical:
770 #if !defined(TERMIO) && !defined(TERMIOS)
771     if (*whatbuf == '\r')
772 	*whatbuf = '\n';
773 #endif
774     if (wbuf == buf)
775 	whatbuf[1] = FINISHCMD;		/* tell finish_command to work */
776 }
777 
778 #ifdef PUSHBACK
779 void
pushstring(char * str)780 pushstring(char *str)
781 {
782     int i;
783     char tmpbuf[PUSHSIZE];
784     char *s = tmpbuf;
785 
786     assert(str != NULL);
787     interp(s,PUSHSIZE,str);
788     for (i = strlen(s)-1; i >= 0; --i) {
789 	s[i] ^= 0200;
790 	pushchar(s[i]);
791     }
792 }
793 #endif
794