Home | History | Annotate | Line # | Download | only in warp
      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
     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
    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
    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
    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*
    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
    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
    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
    462 do_tc(const char *s, int l)
    463 {
    464     beg_qwrite();
    465     tputs(s,l,cmstore);
    466     end_qwrite();
    467 }
    468 
    469 int
    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
    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
    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
    548 cmstore(int ch)
    549 {
    550     *maxcmstring++ = ch;
    551     return 0;
    552 }
    553 
    554 /* discard any characters typed ahead */
    555 
    556 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
    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
    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
    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
    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
    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
    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
    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
    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