1: /* $Header: term.c,v 4.3.1.2 85/05/16 16:45:35 lwall Exp $
   2:  *
   3:  * $Log:	term.c,v $
   4:  * Revision 4.3.1.2  85/05/16  16:45:35  lwall
   5:  * Forced \r to \n on input.
   6:  * Fix for terminfo braindamage regarding bc emulation.
   7:  *
   8:  * Revision 4.3.1.1  85/05/10  11:41:03  lwall
   9:  * Branch for patches.
  10:  *
  11:  * Revision 4.3  85/05/01  11:51:10  lwall
  12:  * Baseline for release with 4.3bsd.
  13:  *
  14:  */
  15: 
  16: #include "EXTERN.h"
  17: #include "common.h"
  18: #include "util.h"
  19: #include "final.h"
  20: #include "help.h"
  21: #include "cheat.h"
  22: #include "intrp.h"
  23: #include "INTERN.h"
  24: #include "term.h"
  25: 
  26: char ERASECH;       /* rubout character */
  27: char KILLCH;        /* line delete character */
  28: char tcarea[TCSIZE];    /* area for "compiled" termcap strings */
  29: 
  30: /* guarantee capability pointer != Nullch */
  31: /* (I believe terminfo will ignore the &tmpaddr argument.) */
  32: 
  33: #define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
  34: 
  35: #ifdef PUSHBACK
  36: struct keymap {
  37:     char km_type[128];
  38:     union km_union {
  39:     struct keymap *km_km;
  40:     char *km_str;
  41:     } km_ptr[128];
  42: };
  43: 
  44: #define KM_NOTHIN 0
  45: #define KM_STRING 1
  46: #define KM_KEYMAP 2
  47: #define KM_BOGUS 3
  48: 
  49: #define KM_TMASK 3
  50: #define KM_GSHIFT 4
  51: #define KM_GMASK 7
  52: 
  53: typedef struct keymap KEYMAP;
  54: 
  55: KEYMAP *topmap INIT(Null(KEYMAP*));
  56: 
  57: void mac_init();
  58: KEYMAP *newkeymap();
  59: void show_keymap();
  60: void pushstring();
  61: #endif
  62: 
  63: /* terminal initialization */
  64: 
  65: void
  66: term_init()
  67: {
  68:     savetty();              /* remember current tty state */
  69: 
  70: #ifdef TERMIO
  71:     ospeed = _tty.c_cflag & CBAUD;  /* for tputs() */
  72:     ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  73:     KILLCH = _tty.c_cc[VKILL];      /* for finish_command() */
  74: #else
  75:     ospeed = _tty.sg_ospeed;        /* for tputs() */
  76:     ERASECH = _tty.sg_erase;        /* for finish_command() */
  77:     KILLCH = _tty.sg_kill;      /* for finish_command() */
  78: #endif
  79: 
  80:     /* The following could be a table but I can't be sure that there isn't */
  81:     /* some degree of sparsity out there in the world. */
  82: 
  83:     switch (ospeed) {           /* 1 second of padding */
  84: #ifdef BEXTA
  85:         case BEXTA:  just_a_sec = 1920; break;
  86: #else
  87: #ifdef B19200
  88:         case B19200: just_a_sec = 1920; break;
  89: #endif
  90: #endif
  91:         case B9600:  just_a_sec =  960; break;
  92:         case B4800:  just_a_sec =  480; break;
  93:         case B2400:  just_a_sec =  240; break;
  94:         case B1800:  just_a_sec =  180; break;
  95:         case B1200:  just_a_sec =  120; break;
  96:         case B600:   just_a_sec =   60; break;
  97:     case B300:   just_a_sec =   30; break;
  98:     /* do I really have to type the rest of this??? */
  99:         case B200:   just_a_sec =   20; break;
 100:         case B150:   just_a_sec =   15; break;
 101:         case B134:   just_a_sec =   13; break;
 102:         case B110:   just_a_sec =   11; break;
 103:         case B75:    just_a_sec =    8; break;
 104:         case B50:    just_a_sec =    5; break;
 105:         default:     just_a_sec =  960; break;
 106:                     /* if we are running detached I */
 107:     }                   /*  don't want to know about it! */
 108: }
 109: 
 110: /* set terminal characteristics */
 111: 
 112: void
 113: term_set(tcbuf)
 114: char *tcbuf;        /* temp area for "uncompiled" termcap entry */
 115: {
 116:     char *tmpaddr;          /* must not be register */
 117:     register char *tmpstr;
 118:     char *tgetstr();
 119:     char *s;
 120:     int status;
 121: 
 122: #ifdef PENDING
 123: #ifndef FIONREAD
 124:     /* do no delay reads on something that always gets closed on exit */
 125: 
 126:     devtty = open("/dev/tty",0);
 127:     if (devtty < 0) {
 128:     printf(cantopen,"/dev/tty") FLUSH;
 129:     finalize(1);
 130:     }
 131:     fcntl(devtty,F_SETFL,O_NDELAY);
 132: #endif
 133: #endif
 134: 
 135:     /* get all that good termcap stuff */
 136: 
 137: #ifdef HAVETERMLIB
 138:     status = tgetent(tcbuf,getenv("TERM")); /* get termcap entry */
 139:     if (status < 1) {
 140: #ifdef VERBOSE
 141:     printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
 142: #else
 143:     fputs("Termcap botch\n",stdout) FLUSH
 144: #endif
 145:     finalize(1);
 146:     }
 147:     tmpaddr = tcarea;           /* set up strange tgetstr pointer */
 148:     s = Tgetstr("pc");          /* get pad character */
 149:     PC = *s;                /* get it where tputs wants it */
 150:     if (!tgetflag("bs")) {      /* is backspace not used? */
 151:     BC = Tgetstr("bc");     /* find out what is */
 152:     if (BC == nullstr)      /* terminfo grok's 'bs' but not 'bc' */
 153:         BC = Tgetstr("le");
 154:     } else
 155:     BC = "\b";          /* make a backspace handy */
 156:     UP = Tgetstr("up");         /* move up a line */
 157:     if (!*UP)               /* no UP string? */
 158:     marking = 0;            /* disable any marking */
 159:     if (muck_up_clear)          /* this is for weird HPs */
 160:     CL = "\n\n\n\n";
 161:     else
 162:     CL = Tgetstr("cl");     /* get clear string */
 163:     CE = Tgetstr("ce");         /* clear to end of line string */
 164: #ifdef CLEAREOL
 165:     CM = Tgetstr("cm");         /* cursor motion - PWP */
 166:     HO = Tgetstr("ho");         /* home cursor if no CM - PWP */
 167:     CD = Tgetstr("cd");         /* clear to end of display - PWP */
 168:     if (!*CE || !*CD || (!*CM && !*HO)) /* can we CE, CD, and home? */
 169:     can_home_clear = FALSE;     /*  no, so disable use of clear eol */
 170: #endif CLEAREOL
 171:     SO = Tgetstr("so");         /* begin standout */
 172:     SE = Tgetstr("se");         /* end standout */
 173:     if ((SG = tgetnum("sg"))<0)
 174:     SG = 0;             /* blanks left by SG, SE */
 175:     US = Tgetstr("us");         /* start underline */
 176:     UE = Tgetstr("ue");         /* end underline */
 177:     if ((UG = tgetnum("ug"))<0)
 178:     UG = 0;             /* blanks left by US, UE */
 179:     if (*US)
 180:     UC = nullstr;           /* UC must not be NULL */
 181:     else
 182:     UC = Tgetstr("uc");     /* underline a character */
 183:     if (!*US && !*UC) {         /* no underline mode? */
 184:     US = SO;            /* substitute standout mode */
 185:     UE = SE;
 186:     UG = SG;
 187:     }
 188:     LINES = tgetnum("li");      /* lines per page */
 189:     COLS = tgetnum("co");       /* columns on page */
 190:     AM = tgetflag("am");        /* terminal wraps automatically? */
 191:     XN = tgetflag("xn");        /* then eats next newline? */
 192:     VB = Tgetstr("vb");
 193:     if (!*VB)
 194:     VB = "\007";
 195:     CR = Tgetstr("cr");
 196:     if (!*CR) {
 197:     if (tgetflag("nc") && *UP) {
 198:         CR = safemalloc((MEM_SIZE)strlen(UP)+2);
 199:         sprintf(CR,"%s\r",UP);
 200:     }
 201:     else
 202:         CR = "\r";
 203:     }
 204: #else
 205:     ??????              /* Roll your own... */
 206: #endif
 207:     if (LINES > 0) {            /* is this a crt? */
 208:     if (!initlines)         /* no -i? */
 209:         if (ospeed >= B9600)    /* whole page at >= 9600 baud */
 210:         initlines = LINES;
 211:         else if (ospeed >= B4800)   /* 16 lines at 4800 */
 212:         initlines = 16;
 213:         else            /* otherwise just header */
 214:         initlines = 8;
 215:     }
 216:     else {              /* not a crt */
 217:     LINES = 30000;          /* so don't page */
 218:     CL = "\n\n";            /* put a couple of lines between */
 219:     if (!initlines)         /* make initlines reasonable */
 220:         initlines = 8;
 221:     }
 222:     if (COLS <= 0)
 223:     COLS = 80;
 224:     noecho();               /* turn off echo */
 225:     crmode();               /* enter cbreak mode */
 226: 
 227: #ifdef PUSHBACK
 228:     mac_init(tcbuf);
 229: #endif
 230: }
 231: 
 232: #ifdef PUSHBACK
 233: void
 234: mac_init(tcbuf)
 235: char *tcbuf;
 236: {
 237:     char tmpbuf[1024];
 238: 
 239:     tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r");
 240:     if (tmpfp != Nullfp) {
 241:     while (fgets(tcbuf,1024,tmpfp) != Nullch) {
 242:         mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
 243:     }
 244:     fclose(tmpfp);
 245:     }
 246: }
 247: 
 248: void
 249: mac_line(line,tmpbuf,tbsize)
 250: char *line;
 251: char *tmpbuf;
 252: int tbsize;
 253: {
 254:     register char *s, *m;
 255:     register KEYMAP *curmap;
 256:     register int ch;
 257:     register int garbage = 0;
 258:     static char override[] = "\nkeymap overrides string\n";
 259: 
 260:     if (topmap == Null(KEYMAP*))
 261:     topmap = newkeymap();
 262:     if (*line == '#' || *line == '\n')
 263:     return;
 264:     if (line[ch = strlen(line)-1] == '\n')
 265:     line[ch] = '\0';
 266:     m = dointerp(tmpbuf,tbsize,line," \t");
 267:     if (!*m)
 268:     return;
 269:     while (*m == ' ' || *m == '\t') m++;
 270:     for (s=tmpbuf,curmap=topmap; *s; s++) {
 271:     ch = *s & 0177;
 272:     if (s[1] == '+' && isdigit(s[2])) {
 273:         s += 2;
 274:         garbage = (*s & KM_GMASK) << KM_GSHIFT;
 275:     }
 276:     else
 277:         garbage = 0;
 278:     if (s[1]) {
 279:         if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
 280:         puts(override,stdout) FLUSH;
 281:         free(curmap->km_ptr[ch].km_str);
 282:         curmap->km_ptr[ch].km_str = Nullch;
 283:         }
 284:         curmap->km_type[ch] = KM_KEYMAP + garbage;
 285:         if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
 286:         curmap->km_ptr[ch].km_km = newkeymap();
 287:         curmap = curmap->km_ptr[ch].km_km;
 288:     }
 289:     else {
 290:         if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
 291:         puts(override,stdout) FLUSH;
 292:         else {
 293:         curmap->km_type[ch] = KM_STRING + garbage;
 294:         curmap->km_ptr[ch].km_str = savestr(m);
 295:         }
 296:     }
 297:     }
 298: }
 299: 
 300: KEYMAP*
 301: newkeymap()
 302: {
 303:     register int i;
 304:     register KEYMAP *map;
 305: 
 306: #ifndef lint
 307:     map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
 308: #else
 309:     map = Null(KEYMAP*);
 310: #endif lint
 311:     for (i=127; i>=0; --i) {
 312:     map->km_ptr[i].km_km = Null(KEYMAP*);
 313:     map->km_type[i] = KM_NOTHIN;
 314:     }
 315:     return map;
 316: }
 317: 
 318: void
 319: show_macros()
 320: {
 321:     char prebuf[64];
 322: 
 323:     if (topmap != Null(KEYMAP*)) {
 324:     print_lines("Macros:\n",STANDOUT);
 325:     *prebuf = '\0';
 326:     show_keymap(topmap,prebuf);
 327:     }
 328: }
 329: 
 330: void
 331: show_keymap(curmap,prefix)
 332: register KEYMAP *curmap;
 333: char *prefix;
 334: {
 335:     register int i;
 336:     register char *next = prefix + strlen(prefix);
 337:     register int kt;
 338: 
 339:     for (i=0; i<128; i++) {
 340:     if (kt = curmap->km_type[i]) {
 341:         if (i < ' ')
 342:         sprintf(next,"^%c",i+64);
 343:         else if (i == ' ')
 344:         strcpy(next,"\\040");
 345:         else if (i == 127)
 346:         strcpy(next,"^?");
 347:         else
 348:         sprintf(next,"%c",i);
 349:         if ((kt >> KM_GSHIFT) & KM_GMASK) {
 350:         sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
 351:         strcat(next,cmd_buf);
 352:         }
 353:         switch (kt & KM_TMASK) {
 354:         case KM_NOTHIN:
 355:         sprintf(cmd_buf,"%s	%c\n",prefix,i);
 356:         print_lines(cmd_buf,NOMARKING);
 357:         break;
 358:         case KM_KEYMAP:
 359:         show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
 360:         break;
 361:         case KM_STRING:
 362:         sprintf(cmd_buf,"%s	%s\n",prefix,curmap->km_ptr[i].km_str);
 363:         print_lines(cmd_buf,NOMARKING);
 364:         break;
 365:         case KM_BOGUS:
 366:         sprintf(cmd_buf,"%s	BOGUS\n",prefix);
 367:         print_lines(cmd_buf,STANDOUT);
 368:         break;
 369:         }
 370:     }
 371:     }
 372: }
 373: 
 374: #endif
 375: 
 376: /* routine to pass to tputs */
 377: 
 378: char
 379: putchr(ch)
 380: register char ch;
 381: {
 382:     putchar(ch);
 383: #ifdef lint
 384:     ch = Null(char);
 385:     ch = ch;
 386: #endif
 387: }
 388: 
 389: /* input the 2nd and succeeding characters of a multi-character command */
 390: /* returns TRUE if command finished, FALSE if they rubbed out first character */
 391: 
 392: bool
 393: finish_command(donewline)
 394: int donewline;
 395: {
 396:     register char *s;
 397:     register bool quoteone = FALSE;
 398: 
 399:     s = buf;
 400:     if (s[1] != FINISHCMD)      /* someone faking up a command? */
 401:     return TRUE;
 402:     do {
 403:       top:
 404:     if (*s < ' ') {
 405:         putchar('^');
 406:         putchar(*s | 64);
 407:     }
 408:     else if (*s == '\177') {
 409:         putchar('^');
 410:         putchar('?');
 411:     }
 412:     else
 413:         putchar(*s);        /* echo previous character */
 414:     s++;
 415: re_read:
 416:     fflush(stdout);
 417:     getcmd(s);
 418:     if (quoteone) {
 419:         quoteone = FALSE;
 420:         continue;
 421:     }
 422:     if (errno || *s == Ctl('l')) {
 423:         *s = Ctl('r');      /* force rewrite on CONT */
 424:     }
 425:     if (*s == '\033') {     /* substitution desired? */
 426: #ifdef ESCSUBS
 427:         char tmpbuf[4], *cpybuf;
 428: 
 429:         tmpbuf[0] = '%';
 430:         read_tty(&tmpbuf[1],1);
 431: #ifdef RAWONLY
 432:         tmpbuf[1] &= 0177;
 433: #endif
 434:         tmpbuf[2] = '\0';
 435:         if (tmpbuf[1] == 'h') {
 436:         (void) help_subs();
 437:         *s = '\0';
 438:         reprint();
 439:         goto re_read;
 440:         }
 441:         else if (tmpbuf[1] == '\033') {
 442:         *s = '\0';
 443:         cpybuf = savestr(buf);
 444:         interp(buf, (sizeof buf), cpybuf);
 445:         free(cpybuf);
 446:         s = buf + strlen(buf);
 447:         reprint();
 448:         goto re_read;
 449:         }
 450:         else {
 451:         interp(s,(sizeof buf) - (s-buf),tmpbuf);
 452:         fputs(s,stdout);
 453:         s += strlen(s);
 454:         }
 455:         goto re_read;
 456: #else
 457:         notincl("^[");
 458:         *s = '\0';
 459:         reprint();
 460:         goto re_read;
 461: #endif
 462:     }
 463:     else if (*s == ERASECH) {   /* they want to rubout a char? */
 464:         rubout();
 465:         s--;            /* discount the char rubbed out */
 466:         if (*s < ' ' || *s == '\177')
 467:         rubout();
 468:         if (s == buf) {     /* entire string gone? */
 469:         fflush(stdout);     /* return to single char command mode */
 470:         return FALSE;
 471:         }
 472:         else
 473:         goto re_read;
 474:     }
 475:     else if (*s == KILLCH) {    /* wipe out the whole line? */
 476:         while (s-- != buf) {    /* emulate that many ERASEs */
 477:         rubout();
 478:         if (*s < ' ' || *s == '\177')
 479:             rubout();
 480:         }
 481:         fflush(stdout);
 482:         return FALSE;       /* return to single char mode */
 483:     }
 484: #ifdef WORDERASE
 485:     else if (*s == Ctl('w')) {  /* wipe out one word? */
 486:         *s-- = ' ';
 487:         while (!isspace(*s) || isspace(s[1])) {
 488:         rubout();
 489:         if (s-- == buf) {
 490:             fflush(stdout);
 491:             return FALSE;   /* return to single char mode */
 492:         }
 493:         if (*s < ' ' || *s == '\177')
 494:             rubout();
 495:         }
 496:         s++;
 497:         goto re_read;
 498:     }
 499: #endif
 500:     else if (*s == Ctl('r')) {
 501:         *s = '\0';
 502:         reprint();
 503:         goto re_read;
 504:     }
 505:     else if (*s == Ctl('v')) {
 506:         putchar('^');
 507:         backspace();
 508:         fflush(stdout);
 509:         getcmd(s);
 510:         goto top;
 511:     }
 512:     else if (*s == '\\') {
 513:         quoteone = TRUE;
 514:     }
 515:     } while (*s != '\n');       /* till a newline (not echoed) */
 516:     *s = '\0';              /* terminate the string nicely */
 517:     if (donewline)
 518:     putchar('\n') FLUSH;
 519:     return TRUE;            /* say we succeeded */
 520: }
 521: 
 522: /* discard any characters typed ahead */
 523: 
 524: void
 525: eat_typeahead()
 526: {
 527: #ifdef PUSHBACK
 528:     if (!typeahead && nextin==nextout)  /* cancel only keyboard stuff */
 529: #else
 530:     if (!typeahead)
 531: #endif
 532:     {
 533: #ifdef PENDING
 534:     while (input_pending())
 535:         read_tty(buf,sizeof(buf));
 536: #else /* this is probably v7 */
 537:     ioctl(_tty_ch,TIOCSETP,&_tty);
 538: #endif
 539:     }
 540: }
 541: 
 542: void
 543: settle_down()
 544: {
 545:     dingaling();
 546:     fflush(stdout);
 547:     sleep(1);
 548: #ifdef PUSHBACK
 549:     nextout = nextin;           /* empty circlebuf */
 550: #endif
 551:     eat_typeahead();
 552: }
 553: 
 554: #ifdef PUSHBACK
 555: /* read a character from the terminal, with multi-character pushback */
 556: 
 557: int
 558: read_tty(addr,size)
 559: char *addr;
 560: int size;
 561: {
 562:     if (nextout != nextin) {
 563:     *addr = circlebuf[nextout++];
 564:     nextout %= PUSHSIZE;
 565:     return 1;
 566:     }
 567:     else {
 568:     size = read(0,addr,size);
 569: #ifdef RAWONLY
 570:     *addr &= 0177;
 571: #endif
 572:     return size;
 573:     }
 574: }
 575: 
 576: #ifdef PENDING
 577: #ifndef FIONREAD
 578: int
 579: circfill()
 580: {
 581:     register int howmany = read(devtty,circlebuf+nextin,1);
 582: 
 583:     if (howmany) {
 584:     nextin += howmany;
 585:     nextin %= PUSHSIZE;
 586:     }
 587:     return howmany;
 588: }
 589: #endif PENDING
 590: #endif FIONREAD
 591: 
 592: void
 593: pushchar(c)
 594: char c;
 595: {
 596:     nextout--;
 597:     if (nextout < 0)
 598:     nextout = PUSHSIZE - 1;
 599:     if (nextout == nextin) {
 600:     fputs("\npushback buffer overflow\n",stdout) FLUSH;
 601:     sig_catcher(0);
 602:     }
 603:     circlebuf[nextout] = c;
 604: }
 605: 
 606: #else PUSHBACK
 607: #ifndef read_tty
 608: /* read a character from the terminal, with hacks for O_NDELAY reads */
 609: 
 610: int
 611: read_tty(addr,size)
 612: char *addr;
 613: int size;
 614: {
 615:     if (is_input) {
 616:     *addr = pending_ch;
 617:     is_input = FALSE;
 618:     return 1;
 619:     }
 620:     else {
 621:     size = read(0,addr,size)
 622: #ifdef RAWONLY
 623:     *addr &= 0177;
 624: #endif
 625:     return size;
 626:     }
 627: }
 628: #endif read_tty
 629: #endif PUSHBACK
 630: 
 631: /* print an underlined string, one way or another */
 632: 
 633: void
 634: underprint(s)
 635: register char *s;
 636: {
 637:     assert(UC);
 638:     if (*UC) {      /* char by char underline? */
 639:     while (*s) {
 640:         if (*s < ' ') {
 641:         putchar('^');
 642:         backspace();/* back up over it */
 643:         underchar();/* and do the underline */
 644:         putchar(*s+64);
 645:         backspace();/* back up over it */
 646:         underchar();/* and do the underline */
 647:         }
 648:         else {
 649:         putchar(*s);
 650:         backspace();/* back up over it */
 651:         underchar();/* and do the underline */
 652:         }
 653:         s++;
 654:     }
 655:     }
 656:     else {      /* start and stop underline */
 657:     underline();    /* start underlining */
 658:     while (*s) {
 659:         if (*s < ' ') {
 660:         putchar('^');
 661:         putchar(*s+64);
 662:         }
 663:         else
 664:         putchar(*s);
 665:         s++;
 666:     }
 667:     un_underline(); /* stop underlining */
 668:     }
 669: }
 670: 
 671: /* keep screen from flashing strangely on magic cookie terminals */
 672: 
 673: #ifdef NOFIREWORKS
 674: void
 675: no_sofire()
 676: {
 677:     if (*UP && *SE) {       /* should we disable fireworks? */
 678:     putchar('\n');
 679:     un_standout();
 680:     up_line();
 681:     carriage_return();
 682:     }
 683: }
 684: 
 685: void
 686: no_ulfire()
 687: {
 688:     if (*UP && *US) {       /* should we disable fireworks? */
 689:     putchar('\n');
 690:     un_underline();
 691:     up_line();
 692:     carriage_return();
 693:     }
 694: }
 695: #endif
 696: 
 697: /* get a character into a buffer */
 698: 
 699: void
 700: getcmd(whatbuf)
 701: register char *whatbuf;
 702: {
 703: #ifdef PUSHBACK
 704:     register KEYMAP *curmap;
 705:     register int i;
 706:     bool no_macros;
 707:     int times = 0;          /* loop detector */
 708:     char scrchar;
 709: 
 710: tryagain:
 711:     curmap = topmap;
 712:     no_macros = (whatbuf != buf && nextin == nextout);
 713: #endif
 714:     for (;;) {
 715:     int_count = 0;
 716:     errno = 0;
 717:     if (read_tty(whatbuf,1) < 0 && !errno)
 718:         errno = EINTR;
 719:     if (errno && errno != EINTR) {
 720:         perror(readerr);
 721:         sig_catcher(0);
 722:     }
 723: #ifdef PUSHBACK
 724:     if (*whatbuf & 0200 || no_macros) {
 725:         *whatbuf &= 0177;
 726:         goto got_canonical;
 727:     }
 728:     if (curmap == Null(KEYMAP*))
 729:         goto got_canonical;
 730:     for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
 731:         read_tty(&scrchar,1);
 732:     }
 733:     switch (curmap->km_type[*whatbuf] & KM_TMASK) {
 734:     case KM_NOTHIN:         /* no entry? */
 735:         if (curmap == topmap)   /* unmapped canonical */
 736:         goto got_canonical;
 737:         settle_down();
 738:         goto tryagain;
 739:     case KM_KEYMAP:         /* another keymap? */
 740:         curmap = curmap->km_ptr[*whatbuf].km_km;
 741:         assert(curmap != Null(KEYMAP*));
 742:         break;
 743:     case KM_STRING:         /* a string? */
 744:         pushstring(curmap->km_ptr[*whatbuf].km_str);
 745:         if (++times > 20) {     /* loop? */
 746:         fputs("\nmacro loop?\n",stdout);
 747:         settle_down();
 748:         }
 749:         no_macros = FALSE;
 750:         goto tryagain;
 751:     }
 752: #else
 753: #ifdef RAWONLY
 754:     *whatbuf &= 0177;
 755: #endif
 756:     break;
 757: #endif
 758:     }
 759: 
 760: got_canonical:
 761: #ifndef TERMIO
 762:     if (*whatbuf == '\r')
 763:     *whatbuf = '\n';
 764: #endif
 765:     if (whatbuf == buf)
 766:     whatbuf[1] = FINISHCMD;     /* tell finish_command to work */
 767: }
 768: 
 769: #ifdef PUSHBACK
 770: void
 771: pushstring(str)
 772: char *str;
 773: {
 774:     register int i;
 775:     char tmpbuf[PUSHSIZE];
 776:     register char *s = tmpbuf;
 777: 
 778:     assert(str != Nullch);
 779:     interp(s,PUSHSIZE,str);
 780:     for (i = strlen(s)-1; i >= 0; --i) {
 781:     s[i] ^= 0200;
 782:     pushchar(s[i]);
 783:     }
 784: }
 785: #endif
 786: 
 787: int
 788: get_anything()
 789: {
 790:     char tmpbuf[2];
 791: 
 792: reask_anything:
 793:     unflush_output();           /* disable any ^O in effect */
 794:     standout();
 795: #ifdef VERBOSE
 796:     IF(verbose)
 797:     fputs("[Type space to continue] ",stdout);
 798:     ELSE
 799: #endif
 800: #ifdef TERSE
 801:     fputs("[MORE] ",stdout);
 802: #endif
 803:     un_standout();
 804:     fflush(stdout);
 805:     eat_typeahead();
 806:     if (int_count) {
 807:     return -1;
 808:     }
 809:     collect_subjects();         /* loads subject cache until */
 810:                     /* input is pending */
 811:     getcmd(tmpbuf);
 812:     if (errno || *tmpbuf == '\f') {
 813:     putchar('\n') FLUSH;        /* if return from stop signal */
 814:     goto reask_anything;        /* give them a prompt again */
 815:     }
 816:     if (*tmpbuf == 'h') {
 817: #ifdef VERBOSE
 818:     IF(verbose)
 819:         fputs("\nType q to quit or space to continue.\n",stdout) FLUSH;
 820:     ELSE
 821: #endif
 822: #ifdef TERSE
 823:         fputs("\nq to quit, space to continue.\n",stdout) FLUSH;
 824: #endif
 825:     goto reask_anything;
 826:     }
 827:     else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
 828:     carriage_return();
 829:     erase_eol();    /* erase the prompt */
 830:     return *tmpbuf == 'q' ? -1 : *tmpbuf;
 831:     }
 832:     if (*tmpbuf == '\n') {
 833:     page_line = LINES - 1;
 834:     carriage_return();
 835:     erase_eol();
 836:     }
 837:     else {
 838:     page_line = 1;
 839:     if (erase_screen)       /* -e? */
 840:         clear();            /* clear screen */
 841:     else {
 842:         carriage_return();
 843:         erase_eol();        /* erase the prompt */
 844:     }
 845:     }
 846:     return 0;
 847: }
 848: 
 849: void
 850: in_char(prompt)
 851: char *prompt;
 852: {
 853:     char oldmode = mode;
 854: 
 855: reask_in_char:
 856:     unflush_output();           /* disable any ^O in effect */
 857:     fputs(prompt,stdout);
 858:     fflush(stdout);
 859:     eat_typeahead();
 860:     mode = 'm';
 861:     getcmd(buf);
 862:     if (errno || *buf == '\f') {
 863:     putchar('\n') FLUSH;        /* if return from stop signal */
 864:     goto reask_in_char;     /* give them a prompt again */
 865:     }
 866:     mode = oldmode;
 867: }
 868: 
 869: int
 870: print_lines(what_to_print,hilite)
 871: char *what_to_print;
 872: int hilite;
 873: {
 874:     register char *s;
 875:     register int i;
 876: 
 877:     if (page_line < 0)          /* they do not want to see this? */
 878:     return -1;
 879:     for (s=what_to_print; *s; ) {
 880:     if (page_line >= LINES || int_count) {
 881:         if (i = -1, int_count || (i = get_anything())) {
 882:         page_line = -1;     /* disable further print_lines */
 883:         return i;
 884:         }
 885:     }
 886:     page_line++;
 887:     if (hilite == STANDOUT) {
 888: #ifdef NOFIREWORKS
 889:         if (erase_screen)
 890:         no_sofire();
 891: #endif
 892:         standout();
 893:     }
 894:     else if (hilite == UNDERLINE) {
 895: #ifdef NOFIREWORKS
 896:         if (erase_screen)
 897:         no_ulfire();
 898: #endif
 899:         underline();
 900:     }
 901:     for (i=0; i<COLS; i++) {
 902:         if (!*s)
 903:         break;
 904:         if (*s >= ' ')
 905:         putchar(*s);
 906:         else if (*s == '\t') {
 907:         putchar(*s);
 908:         i = ((i+8) & ~7) - 1;
 909:         }
 910:         else if (*s == '\n') {
 911:         i = 32000;
 912:         }
 913:         else {
 914:         i++;
 915:         putchar('^');
 916:         putchar(*s + 64);
 917:         }
 918:         s++;
 919:     }
 920:     if (i) {
 921:         if (hilite == STANDOUT)
 922:         un_standout();
 923:         else if (hilite == UNDERLINE)
 924:         un_underline();
 925:         if (AM && i == COLS)
 926:         fflush(stdout);
 927:         else
 928:         putchar('\n') FLUSH;
 929:     }
 930:     }
 931:     return 0;
 932: }
 933: 
 934: void
 935: page_init()
 936: {
 937:     page_line = 1;
 938:     if (erase_screen)
 939:     clear();
 940:     else
 941:     putchar('\n') FLUSH;
 942: }
 943: 
 944: void
 945: pad(num)
 946: int num;
 947: {
 948:     register int i;
 949: 
 950:     for (i = num; i; --i)
 951:     putchar(PC);
 952:     fflush(stdout);
 953: }
 954: 
 955: /* echo the command just typed */
 956: 
 957: #ifdef VERIFY
 958: void
 959: printcmd()
 960: {
 961:     if (verify && buf[1] == FINISHCMD) {
 962:     if (*buf < ' ') {
 963:         putchar('^');
 964:         putchar(*buf | 64);
 965:         backspace();
 966:         backspace();
 967:     }
 968:     else {
 969:         putchar(*buf);
 970:         backspace();
 971:     }
 972:     fflush(stdout);
 973:     }
 974: }
 975: #endif
 976: 
 977: void
 978: rubout()
 979: {
 980:     backspace();            /* do the old backspace, */
 981:     putchar(' ');           /*   space, */
 982:     backspace();            /*     backspace trick */
 983: }
 984: 
 985: void
 986: reprint()
 987: {
 988:     register char *s;
 989: 
 990:     fputs("^R\n",stdout) FLUSH;
 991:     for (s = buf; *s; s++) {
 992:     if (*s < ' ') {
 993:         putchar('^');
 994:         putchar(*s | 64);
 995:     }
 996:     else
 997:         putchar(*s);
 998:     }
 999: }
1000: 
1001: #ifdef CLEAREOL
1002: /* start of additions by Paul Placeway (PWP) */
1003: 
1004: void
1005: home_cursor()
1006: {
1007:     char *tgoto();
1008: 
1009:     if (!*HO) {         /* no home sequence? */
1010:     if (!*CM) {     /* no cursor motion either? */
1011:         fputs ("\n\n\n", stdout);
1012:         return;     /* forget it. */
1013:     }
1014:     tputs (tgoto (CM, 0, 0), 1, putchr);    /* go to home via CM */
1015:     return;
1016:     }
1017:     else {          /* we have home sequence */
1018:     tputs (HO, 1, putchr);  /* home via HO */
1019:     }
1020: }
1021: #endif CLEAREOL

Defined functions

circfill defined in line 578; used 2 times
home_cursor defined in line 1004; used 3 times
mac_init defined in line 233; used 3 times
mac_line defined in line 248; used 3 times
newkeymap defined in line 300; used 3 times
no_ulfire defined in line 685; used 4 times
print_lines defined in line 869; used 43 times
pushstring defined in line 770; used 2 times
putchr defined in line 378; used 3 times
read_tty defined in line 610; never used
reprint defined in line 985; used 5 times
rubout defined in line 977; used 7 times
show_keymap defined in line 330; used 3 times
term_init defined in line 65; used 2 times
term_set defined in line 112; used 2 times
underprint defined in line 633; used 2 times

Defined variables

ERASECH defined in line 26; used 3 times
KILLCH defined in line 27; used 3 times
tcarea defined in line 28; used 1 times
topmap defined in line 55; used 7 times

Defined struct's

keymap defined in line 36; used 4 times
  • in line 39(2), 53(2)

Defined union's

km_union defined in line 38; never used

Defined typedef's

KEYMAP defined in line 53; used 17 times

Defined macros

KM_BOGUS defined in line 47; used 1 times
KM_GMASK defined in line 51; used 4 times
KM_GSHIFT defined in line 50; used 4 times
KM_KEYMAP defined in line 46; used 3 times
KM_NOTHIN defined in line 44; used 2 times
KM_STRING defined in line 45; used 3 times
KM_TMASK defined in line 49; used 4 times
Tgetstr defined in line 33; used 16 times
Last modified: 1986-03-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4185
Valid CSS Valid XHTML 1.0 Strict