term.c revision 1.4 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 #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(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 = ospeed >= B9600 ? 480 :
269 ospeed == B4800 ? 240 :
270 ospeed == B2400 ? 120 :
271 ospeed == B1200 ? 60 :
272 ospeed == B600 ? 30 :
273 /* speed is 300 (?) */ 15;
274
275 gfillen = ospeed >= B9600 ? (int /*XXX: speed_t*/)(sizeof filler) :
276 ospeed == B4800 ? 13 :
277 ospeed == B2400 ? 7 :
278 ospeed == B1200 ? 4 :
279 (1+BCsize);
280 if (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
290 crmode();
291 raw();
292 noecho(); /* turn off echo */
293 nonl();
294
295 #ifdef PUSHBACK
296 mac_init(tcbuf);
297 #endif
298 }
299
300 #ifdef PUSHBACK
301 void
302 mac_init(char *tcbuf)
303 {
304 char tmpbuf[1024];
305
306 tmpfp = fopen(filexp(getval("WARPMACRO",WARPMACRO)),"r");
307 if (tmpfp != NULL) {
308 while (fgets(tcbuf,1024,tmpfp) != NULL) {
309 mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
310 }
311 fclose(tmpfp);
312 }
313 }
314
315 void
316 mac_line(char *line, char *tmpbuf, size_t tbsize)
317 {
318 char *s;
319 char *m;
320 KEYMAP *curmap;
321 int ch;
322 int garbage = 0;
323 static const char override[] = "\r\nkeymap overrides string\r\n";
324
325 if (topmap == NULL)
326 topmap = newkeymap();
327 if (*line == '#' || *line == '\n')
328 return;
329 if (line[ch = strlen(line)-1] == '\n')
330 line[ch] = '\0';
331 m = dointerp(tmpbuf,tbsize,line," \t");
332 if (!*m)
333 return;
334 while (*m == ' ' || *m == '\t') m++;
335 for (s=tmpbuf,curmap=topmap; *s; s++) {
336 ch = *s & 0177;
337 if (s[1] == '+' && isdigit((unsigned char)s[2])) {
338 s += 2;
339 garbage = (*s & KM_GMASK) << KM_GSHIFT;
340 }
341 else
342 garbage = 0;
343 if (s[1]) {
344 if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
345 puts(override);
346 free(curmap->km_ptr[ch].km_str);
347 curmap->km_ptr[ch].km_str = NULL;
348 }
349 curmap->km_type[ch] = KM_KEYMAP + garbage;
350 if (curmap->km_ptr[ch].km_km == NULL)
351 curmap->km_ptr[ch].km_km = newkeymap();
352 curmap = curmap->km_ptr[ch].km_km;
353 }
354 else {
355 if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
356 puts(override);
357 else {
358 curmap->km_type[ch] = KM_STRING + garbage;
359 curmap->km_ptr[ch].km_str = savestr(m);
360 }
361 }
362 }
363 }
364
365 static KEYMAP*
366 newkeymap(void)
367 {
368 int i;
369 KEYMAP *map;
370
371 #ifndef lint
372 map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
373 #else
374 map = Null(KEYMAP*);
375 #endif /* lint */
376 for (i=127; i>=0; --i) {
377 map->km_ptr[i].km_km = NULL;
378 map->km_type[i] = KM_NOTHIN;
379 }
380 return map;
381 }
382
383 #endif
384
385 /* print out a file, stopping at form feeds */
386
387 void
388 page(const char *filename, size_t num)
389 {
390 int linenum = 1;
391
392 tmpfp = fopen(filename,"r");
393 if (tmpfp != NULL) {
394 while (fgets(spbuf,(sizeof spbuf),tmpfp) != NULL) {
395 if (*spbuf == '\f') {
396 printf("[Type anything to continue] ");
397 fflush(stdout);
398 getcmd(spbuf);
399 printf("\r\n");
400 if (*spbuf == INTRCH)
401 finalize(0);
402 if (*spbuf == 'q' || *spbuf == 'Q')
403 break;
404 }
405 else {
406 if (num)
407 printf("%3d %s\r",linenum++,spbuf);
408 else
409 printf("%s\r",spbuf);
410 }
411 }
412 fclose(tmpfp);
413 }
414 }
415
416 void
417 move(int y, int x, int chadd)
418 {
419 int ydist;
420 int xdist;
421 int i;
422 char *s;
423
424 ydist = y - real_y;
425 xdist = x - real_x;
426 i = ydist * (ydist < 0 ? -UPsize : DOsize) +
427 xdist * (xdist < 0 ? -BCsize : NDsize);
428 beg_qwrite();
429 if (i <= CMsize) {
430 if (ydist < 0)
431 for (; ydist; ydist++)
432 for (i=UPsize,s=myUP; i; i--)
433 qaddch(*s++);
434 else
435 for (; ydist; ydist--)
436 for (i=DOsize,s=myDO; i; i--)
437 qaddch(*s++);
438 if (xdist < 0)
439 for (; xdist; xdist++)
440 for (i=BCsize,s=BC; i; i--)
441 qaddch(*s++);
442 else
443 for (; xdist; xdist--)
444 for (i=NDsize,s=myND; i; i--)
445 qaddch(*s++);
446 }
447 else {
448 tputs(tgoto(CM,x,y),0,cmstore);
449 }
450 real_y = y;
451 real_x = x;
452 if (chadd) {
453 qaddch(chadd);
454 }
455 if (maxcmstring != cmbuffer)
456 end_qwrite();
457 }
458
459 void
460 do_tc(const char *s, int l)
461 {
462 beg_qwrite();
463 tputs(s,l,cmstore);
464 end_qwrite();
465 }
466
467 int
468 comp_tc(char *dest, const char *s, int l)
469 {
470 maxcmstring = dest;
471 tputs(s,l,cmstore);
472 return(maxcmstring-dest);
473 }
474
475 void
476 helper(void)
477 {
478 clear();
479 mvaddstr(0,4,"h or 4 left");
480 mvaddstr(1,4,"j or 2 down Use with SHIFT to fire torpedoes.");
481 mvaddstr(2,4,"k or 8 up Use with CTRL or FUNCT to fire");
482 mvaddstr(3,4,"l or 6 right phasers or turbolasers.");
483 mvaddstr(4,4,"b or 1 down and left Use preceded by 'a' or 'r' for");
484 mvaddstr(5,4,"n or 3 down and right attractors or repulsors.");
485 mvaddstr(6,4,"y or 7 up and left Use normally for E or B motion.");
486 mvaddstr(7,4,"u or 9 up and right");
487 mvaddstr(8,4,"");
488 mvaddstr(9,4,"del or % fire photon torpedoes in every (reasonable) direction.");
489 mvaddstr(10,4,"s stop all torpedoes.");
490 mvaddstr(11,4,"S or 0 stop the Enterprise when in warp mode.");
491 mvaddstr(12,4,"d/D destruct all torpedoes/current vessel.");
492 mvaddstr(13,4,"i/w switch to Enterprise & put into impulse/warp mode.");
493 mvaddstr(14,4,"c/v switch to Enterprise & make cloaked/visible.");
494 mvaddstr(15,4,"p switch to Base.");
495 mvaddstr(16,4,"o toggle to other vessel (from E to B, or vice versa.)");
496 mvaddstr(17,4,"z zap (suppress) blasts near Enterprise next cycle");
497 mvaddstr(18,4,"");
498 mvaddstr(19,4,"^R refresh the screen. ^Z suspend the game.");
499 mvaddstr(20,4,"q exit this round (if you haven't typed q within 10 cycles).");
500 mvaddstr(21,4,"Q exit this game.");
501 mvaddstr(22,4,"");
502 mvaddstr(23,4," [Hit space to continue]");
503 fflush(stdout);
504 do {
505 getcmd(spbuf);
506 } while (*spbuf != ' ');
507 rewrite();
508
509 }
510
511 void
512 rewrite(void)
513 {
514 int x;
515 int y;
516 OBJECT *obj;
517
518 clear();
519 for (y=0; y<YSIZE; y++) {
520 for (x=0; x<XSIZE; x++) {
521 if (numamoebas && amb[y][x] != ' ')
522 mvaddc(y+1,x*2,amb[y][x]);
523 if ((obj = occupant[y][x]) != NULL) {
524 if (obj->image != ' ')
525 mvaddc(y+1,x*2,obj->image);
526 }
527 }
528 }
529 snprintf(spbuf, sizeof(spbuf),
530 "%-4s E: %4d %2d B: %5d %3d Enemies: %-3d Stars: %-3d Stardate%5d.%1d %9ld",
531 " ", 0, 0, 0, 0, 0, 0, timer/10+smarts*100, timer%10, 0L);
532 mvaddstr(0,0,spbuf);
533 oldeenergy = oldbenergy = oldcurscore =
534 oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1;
535 /* force everything to fill in */
536 if (damage)
537 olddamage = 0;
538 if (!ent)
539 etorp = 0;
540 if (!base)
541 btorp = 0;
542 display_status();
543 }
544
545 int
546 cmstore(int ch)
547 {
548 *maxcmstring++ = ch;
549 return 0;
550 }
551
552 /* discard any characters typed ahead */
553
554 void
555 eat_typeahead(void)
556 {
557 #ifdef PUSHBACK
558 if (!typeahead && nextin==nextout) /* cancel only keyboard stuff */
559 #else
560 if (!typeahead)
561 #endif
562 {
563 #ifdef PENDING
564 while (input_pending())
565 read_tty(buf,sizeof(buf));
566 #else /* this is probably v7, with no rdchk() */
567 ioctl(_tty_ch,TIOCSETP,&_tty);
568 #endif
569 }
570 }
571
572 void
573 settle_down(void)
574 {
575 dingaling();
576 fflush(stdout);
577 sleep(1);
578 #ifdef PUSHBACK
579 nextout = nextin; /* empty circlebuf */
580 #endif
581 eat_typeahead();
582 }
583
584 #ifdef PUSHBACK
585 /* read a character from the terminal, with multi-character pushback */
586
587 int
588 read_tty(char *addr, ssize_t size) /* ignored for now */
589 {
590 if (nextout != nextin) {
591 *addr = circlebuf[nextout++];
592 nextout %= PUSHSIZE;
593 return 1;
594 }
595 else {
596 size = read(0,addr,1);
597 if (size < 0)
598 sig_catcher(SIGHUP);
599 if (metakey) {
600 if (*addr & 0200) {
601 pushchar(*addr & 0177);
602 *addr = '\001';
603 }
604 }
605 else
606 *addr &= 0177;
607 return 1;
608 }
609 }
610
611 #ifdef PENDING
612 #ifndef FIONREAD
613 #ifndef RDCHK
614 int
615 circfill()
616 {
617 int howmany;
618 int i;
619
620 assert (nextin == nextout);
621 howmany = read(devtty,circlebuf+nextin,metakey?1:PUSHSIZE-nextin);
622 if (howmany > 0) {
623 if (metakey) {
624 if (circlebuf[nextin] & 0200) {
625 circlebuf[nextin] &= 0177;
626 pushchar('\001');
627 }
628 }
629 else
630 for (i = howmany+nextin-1; i >= nextin; i--)
631 circlebuf[i] &= 0177;
632 nextin += howmany;
633 nextin %= PUSHSIZE; /* may end up 1 if metakey */
634 }
635 return howmany;
636 }
637 #endif /* RDCHK */
638 #endif /* FIONREAD */
639 #endif /* PENDING */
640
641 void
642 pushchar(int ch)
643 {
644 nextout--;
645 if (nextout < 0)
646 nextout = PUSHSIZE - 1;
647 if (nextout == nextin) {
648 fputs("\r\npushback buffer overflow\r\n",stdout);
649 sig_catcher(0);
650 }
651 circlebuf[nextout] = ch;
652 }
653
654 #else /* PUSHBACK */
655 #ifndef read_tty
656 /* read a character from the terminal, with hacks for O_NDELAY reads */
657
658 int
659 read_tty(addr,size)
660 char *addr;
661 int size;
662 {
663 if (is_input) {
664 *addr = pending_ch;
665 is_input = false;
666 return 1;
667 }
668 else {
669 size = read(0,addr,size);
670 if (size < 0)
671 sig_catcher(SIGHUP);
672 if (metakey) {
673 if (*addr & 0200) {
674 pending_ch = *addr & 0177;
675 is_input = true;
676 *addr = '\001';
677 }
678 }
679 else
680 *addr &= 0177;
681 return size;
682 }
683 }
684 #endif /* read_tty */
685 #endif /* PUSHBACK */
686
687 int
688 read_nd(char *buff, size_t siz)
689 {
690 if (!input_pending())
691 return 0;
692
693 getcmd(buff);
694 return 1;
695 }
696
697 /* get a character into a buffer */
698
699 void
700 getcmd(char *wbuf)
701 {
702 #ifdef PUSHBACK
703 KEYMAP *curmap;
704 int i;
705 bool no_macros;
706 int times = 0; /* loop detector */
707 char scrchar;
708 unsigned char *whatbuf = (void *)wbuf;
709
710 tryagain:
711 curmap = topmap;
712 /* no_macros = (whatbuf != buf && nextin == nextout); */
713 no_macros = false;
714 #endif
715 for (;;) {
716 errno = 0;
717 if (read_tty(wbuf,1) < 0 && !errno)
718 errno = EINTR;
719 #ifdef read_tty
720 if (metakey) {
721 if (*whatbuf & 0200) {
722 *what_buf &= 037; /* punt and hope they don't notice */
723 }
724 }
725 else
726 *whatbuf &= 0177;
727 #endif /* read_tty */
728 if (errno && errno != EINTR) {
729 perror(readerr);
730 sig_catcher(0);
731 }
732 #ifdef PUSHBACK
733 if (*whatbuf & 0200 || no_macros) {
734 *whatbuf &= 0177;
735 goto got_canonical;
736 }
737 if (curmap == NULL)
738 goto got_canonical;
739 for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
740 read_tty(&scrchar,1);
741 }
742 switch (curmap->km_type[*whatbuf] & KM_TMASK) {
743 case KM_NOTHIN: /* no entry? */
744 if (curmap == topmap) /* unmapped canonical */
745 goto got_canonical;
746 settle_down();
747 goto tryagain;
748 case KM_KEYMAP: /* another keymap? */
749 curmap = curmap->km_ptr[*whatbuf].km_km;
750 assert(curmap != NULL);
751 break;
752 case KM_STRING: /* a string? */
753 pushstring(curmap->km_ptr[*whatbuf].km_str);
754 if (++times > 20) { /* loop? */
755 fputs("\r\nmacro loop?\r\n",stdout);
756 settle_down();
757 }
758 no_macros = false;
759 goto tryagain;
760 }
761 #else
762 *whatbuf &= 0177;
763 break;
764 #endif
765 }
766
767 got_canonical:
768 #ifndef TERMIO
769 if (*whatbuf == '\r')
770 *whatbuf = '\n';
771 #endif
772 if (wbuf == buf)
773 whatbuf[1] = FINISHCMD; /* tell finish_command to work */
774 }
775
776 #ifdef PUSHBACK
777 void
778 pushstring(char *str)
779 {
780 int i;
781 char tmpbuf[PUSHSIZE];
782 char *s = tmpbuf;
783
784 assert(str != NULL);
785 interp(s,PUSHSIZE,str);
786 for (i = strlen(s)-1; i >= 0; --i) {
787 s[i] ^= 0200;
788 pushchar(s[i]);
789 }
790 }
791 #endif
792