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