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