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

Defined functions

circfill defined in line 591; used 2 times
get_anything defined in line 802; used 6 times
getcmd defined in line 714; used 9 times
home_cursor defined in line 1020; used 3 times
mac_init defined in line 246; used 3 times
mac_line defined in line 261; used 3 times
newkeymap defined in line 313; used 3 times
no_sofire defined in line 689; used 4 times
no_ulfire defined in line 700; used 4 times
pad defined in line 960; used 6 times
print_lines defined in line 885; used 43 times
pushstring defined in line 785; used 2 times
putchr defined in line 391; used 3 times
read_tty defined in line 623; never used
reprint defined in line 1001; used 5 times
rubout defined in line 993; used 7 times
show_keymap defined in line 343; used 3 times
show_macros defined in line 331; used 3 times
term_init defined in line 68; used 2 times
term_set defined in line 115; used 2 times
underprint defined in line 648; used 2 times

Defined variables

ERASECH defined in line 29; used 3 times
KILLCH defined in line 30; used 3 times
tcarea defined in line 31; used 1 times
topmap defined in line 58; used 7 times

Defined struct's

keymap defined in line 39; used 4 times
  • in line 42(2), 56(2)

Defined union's

km_union defined in line 41; never used

Defined typedef's

KEYMAP defined in line 56; used 17 times

Defined macros

KM_BOGUS defined in line 50; used 1 times
KM_GMASK defined in line 54; used 4 times
KM_GSHIFT defined in line 53; used 4 times
KM_KEYMAP defined in line 49; used 3 times
KM_NOTHIN defined in line 47; used 2 times
KM_STRING defined in line 48; used 3 times
KM_TMASK defined in line 52; used 4 times
Tgetstr defined in line 36; used 16 times
Last modified: 1989-04-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6111
Valid CSS Valid XHTML 1.0 Strict