1: /* Copyright (c) 1981 Regents of the University of California */
   2: static char *sccsid = "@(#)ex_vget.c	6.3 7/8/81";
   3: #include "ex.h"
   4: #include "ex_tty.h"
   5: #include "ex_vis.h"
   6: 
   7: /*
   8:  * Input routines for open/visual.
   9:  * We handle upper case only terminals in visual and reading from the
  10:  * echo area here as well as notification on large changes
  11:  * which appears in the echo area.
  12:  */
  13: 
  14: /*
  15:  * Return the key.
  16:  */
  17: ungetkey(c)
  18:     int c;      /* mjm: char --> int */
  19: {
  20: 
  21:     if (Peekkey != ATTN)
  22:         Peekkey = c;
  23: }
  24: 
  25: /*
  26:  * Return a keystroke, but never a ^@.
  27:  */
  28: getkey()
  29: {
  30:     register int c;     /* mjm: char --> int */
  31: 
  32:     do {
  33:         c = getbr();
  34:         if (c==0)
  35:             beep();
  36:     } while (c == 0);
  37:     return (c);
  38: }
  39: 
  40: /*
  41:  * Tell whether next keystroke would be a ^@.
  42:  */
  43: peekbr()
  44: {
  45: 
  46:     Peekkey = getbr();
  47:     return (Peekkey == 0);
  48: }
  49: 
  50: short   precbksl;
  51: 
  52: /*
  53:  * Get a keystroke, including a ^@.
  54:  * If an key was returned with ungetkey, that
  55:  * comes back first.  Next comes unread input (e.g.
  56:  * from repeating commands with .), and finally new
  57:  * keystrokes.
  58:  *
  59:  * The hard work here is in mapping of \ escaped
  60:  * characters on upper case only terminals.
  61:  */
  62: getbr()
  63: {
  64:     char ch;
  65:     register int c, d;
  66:     register char *colp;
  67:     int cnt;
  68: #define BEEHIVE
  69: #ifdef BEEHIVE
  70:     static char Peek2key;
  71: #endif
  72:     extern short slevel, ttyindes;
  73: 
  74: getATTN:
  75:     if (Peekkey) {
  76:         c = Peekkey;
  77:         Peekkey = 0;
  78:         return (c);
  79:     }
  80: #ifdef BEEHIVE
  81:     if (Peek2key) {
  82:         c = Peek2key;
  83:         Peek2key = 0;
  84:         return (c);
  85:     }
  86: #endif
  87:     if (vglobp) {
  88:         if (*vglobp)
  89:             return (lastvgk = *vglobp++);
  90:         lastvgk = 0;
  91:         return (ESCAPE);
  92:     }
  93:     if (vmacp) {
  94:         if (*vmacp)
  95:             return(*vmacp++);
  96:         /* End of a macro or set of nested macros */
  97:         vmacp = 0;
  98:         if (inopen == -1)   /* don't screw up undo for esc esc */
  99:             vundkind = VMANY;
 100:         inopen = 1; /* restore old setting now that macro done */
 101:         vch_mac = VC_NOTINMAC;
 102:     }
 103:     flusho();
 104: again:
 105:     if ((c=read(slevel == 0 ? 0 : ttyindes, &ch, 1)) != 1) {
 106:         if (errno == EINTR)
 107:             goto getATTN;
 108:         error("Input read error");
 109:     }
 110:     c = ch & TRIM;
 111: #ifdef BEEHIVE
 112:     if (XB && slevel==0 && c == ESCAPE) {
 113:         if (read(0, &Peek2key, 1) != 1)
 114:             goto getATTN;
 115:         Peek2key &= TRIM;
 116:         switch (Peek2key) {
 117:         case 'C':   /* SPOW mode sometimes sends \EC for space */
 118:             c = ' ';
 119:             Peek2key = 0;
 120:             break;
 121:         case 'q':   /* f2 -> ^C */
 122:             c = CTRL(c);
 123:             Peek2key = 0;
 124:             break;
 125:         case 'p':   /* f1 -> esc */
 126:             Peek2key = 0;
 127:             break;
 128:         }
 129:     }
 130: #endif
 131: 
 132: #ifdef UCVISUAL
 133:     /*
 134: 	 * The algorithm here is that of the UNIX kernel.
 135: 	 * See the description in the programmers manual.
 136: 	 */
 137:     if (UPPERCASE) {
 138:         if (isupper(c))
 139:             c = tolower(c);
 140:         if (c == '\\') {
 141:             if (precbksl < 2)
 142:                 precbksl++;
 143:             if (precbksl == 1)
 144:                 goto again;
 145:         } else if (precbksl) {
 146:             d = 0;
 147:             if (islower(c))
 148:                 d = toupper(c);
 149:             else {
 150:                 colp = "({)}!|^~'~";
 151:                 while (d = *colp++)
 152:                     if (d == c) {
 153:                         d = *colp++;
 154:                         break;
 155:                     } else
 156:                         colp++;
 157:             }
 158:             if (precbksl == 2) {
 159:                 if (!d) {
 160:                     Peekkey = c;
 161:                     precbksl = 0;
 162:                     c = '\\';
 163:                 }
 164:             } else if (d)
 165:                 c = d;
 166:             else {
 167:                 Peekkey = c;
 168:                 precbksl = 0;
 169:                 c = '\\';
 170:             }
 171:         }
 172:         if (c != '\\')
 173:             precbksl = 0;
 174:     }
 175: #endif
 176: #ifdef TRACE
 177:     if (trace) {
 178:         if (!techoin) {
 179:             tfixnl();
 180:             techoin = 1;
 181:             fprintf(trace, "*** Input: ");
 182:         }
 183:         tracec(c);
 184:     }
 185: #endif
 186:     lastvgk = 0;
 187:     return (c);
 188: }
 189: 
 190: /*
 191:  * Get a key, but if a delete, quit or attention
 192:  * is typed return 0 so we will abort a partial command.
 193:  */
 194: getesc()
 195: {
 196:     register int c;
 197: 
 198:     c = getkey();
 199:     switch (c) {
 200: 
 201:     case CTRL(v):
 202:     case CTRL(q):
 203:         c = getkey();
 204:         return (c);
 205: 
 206:     case ATTN:
 207:     case QUIT:
 208:         ungetkey(c);
 209:         return (0);
 210: 
 211:     case ESCAPE:
 212:         return (0);
 213:     }
 214:     return (c);
 215: }
 216: 
 217: /*
 218:  * Peek at the next keystroke.
 219:  */
 220: peekkey()
 221: {
 222: 
 223:     Peekkey = getkey();
 224:     return (Peekkey);
 225: }
 226: 
 227: /*
 228:  * Read a line from the echo area, with single character prompt c.
 229:  * A return value of 1 means the user blewit or blewit away.
 230:  */
 231: readecho(c)
 232:     char c;
 233: {
 234:     register char *sc = cursor;
 235:     register int (*OP)();
 236:     bool waste;
 237:     register int OPeek;
 238: 
 239:     if (WBOT == WECHO)
 240:         vclean();
 241:     else
 242:         vclrech(0);
 243:     splitw++;
 244:     vgoto(WECHO, 0);
 245:     putchar(c);
 246:     vclreol();
 247:     vgoto(WECHO, 1);
 248:     cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
 249:     if (peekbr()) {
 250:         if (!INS[0] || (INS[0] & (QUOTE|TRIM)) == OVERBUF)
 251:             goto blewit;
 252:         vglobp = INS;
 253:     }
 254:     OP = Pline; Pline = normline;
 255:     ignore(vgetline(0, genbuf + 1, &waste, c));
 256:     if (Outchar == termchar)
 257:         putchar('\n');
 258:     vscrap();
 259:     Pline = OP;
 260:     if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL(h)) {
 261:         cursor = sc;
 262:         vclreol();
 263:         return (0);
 264:     }
 265: blewit:
 266:     OPeek = Peekkey==CTRL(h) ? 0 : Peekkey; Peekkey = 0;
 267:     splitw = 0;
 268:     vclean();
 269:     vshow(dot, NOLINE);
 270:     vnline(sc);
 271:     Peekkey = OPeek;
 272:     return (1);
 273: }
 274: 
 275: /*
 276:  * A complete command has been defined for
 277:  * the purposes of repeat, so copy it from
 278:  * the working to the previous command buffer.
 279:  */
 280: setLAST()
 281: {
 282: 
 283:     if (vglobp || vmacp)
 284:         return;
 285:     lastreg = vreg;
 286:     lasthad = Xhadcnt;
 287:     lastcnt = Xcnt;
 288:     *lastcp = 0;
 289:     CP(lastcmd, workcmd);
 290: }
 291: 
 292: /*
 293:  * Gather up some more text from an insert.
 294:  * If the insertion buffer oveflows, then destroy
 295:  * the repeatability of the insert.
 296:  */
 297: addtext(cp)
 298:     char *cp;
 299: {
 300: 
 301:     if (vglobp)
 302:         return;
 303:     addto(INS, cp);
 304:     if ((INS[0] & (QUOTE|TRIM)) == OVERBUF)
 305:         lastcmd[0] = 0;
 306: }
 307: 
 308: setDEL()
 309: {
 310: 
 311:     setBUF(DEL);
 312: }
 313: 
 314: /*
 315:  * Put text from cursor upto wcursor in BUF.
 316:  */
 317: setBUF(BUF)
 318:     register char *BUF;
 319: {
 320:     register int c;
 321:     register char *wp = wcursor;
 322: 
 323:     c = *wp;
 324:     *wp = 0;
 325:     BUF[0] = 0;
 326:     addto(BUF, cursor);
 327:     *wp = c;
 328: }
 329: 
 330: addto(buf, str)
 331:     register char *buf, *str;
 332: {
 333: 
 334:     if ((buf[0] & (QUOTE|TRIM)) == OVERBUF)
 335:         return;
 336:     if (strlen(buf) + strlen(str) + 1 >= VBSIZE) {
 337:         buf[0] = OVERBUF;
 338:         return;
 339:     }
 340:     ignore(strcat(buf, str));
 341: }
 342: 
 343: /*
 344:  * Note a change affecting a lot of lines, or non-visible
 345:  * lines.  If the parameter must is set, then we only want
 346:  * to do this for open modes now; return and save for later
 347:  * notification in visual.
 348:  */
 349: noteit(must)
 350:     bool must;
 351: {
 352:     register int sdl = destline, sdc = destcol;
 353: 
 354:     if (notecnt < 2 || !must && state == VISUAL)
 355:         return (0);
 356:     splitw++;
 357:     if (WBOT == WECHO)
 358:         vmoveitup(1, 1);
 359:     vigoto(WECHO, 0);
 360:     printf("%d %sline", notecnt, notesgn);
 361:     if (notecnt > 1)
 362:         putchar('s');
 363:     if (*notenam) {
 364:         printf(" %s", notenam);
 365:         if (*(strend(notenam) - 1) != 'e')
 366:             putchar('e');
 367:         putchar('d');
 368:     }
 369:     vclreol();
 370:     notecnt = 0;
 371:     if (state != VISUAL)
 372:         vcnt = vcline = 0;
 373:     splitw = 0;
 374:     if (state == ONEOPEN || state == CRTOPEN)
 375:         vup1();
 376:     destline = sdl; destcol = sdc;
 377:     return (1);
 378: }
 379: 
 380: /*
 381:  * Rrrrringgggggg.
 382:  * If possible, use flash (VB).
 383:  */
 384: beep()
 385: {
 386: 
 387:     if (VB)
 388:         vputp(VB, 0);
 389:     else
 390:         vputc(CTRL(g));
 391: }
 392: 
 393: /*
 394:  * Map the command input character c,
 395:  * for keypads and labelled keys which do cursor
 396:  * motions.  I.e. on an adm3a we might map ^K to ^P.
 397:  * DM1520 for example has a lot of mappable characters.
 398:  */
 399: 
 400: map(c,maps)
 401:     register int c;
 402:     register struct maps *maps;
 403: {
 404:     register int d;
 405:     register char *p, *q;
 406:     char b[10]; /* Assumption: no keypad sends string longer than 10 */
 407: 
 408:     /*
 409: 	 * Mapping for special keys on the terminal only.
 410: 	 * BUG: if there's a long sequence and it matches
 411: 	 * some chars and then misses, we lose some chars.
 412: 	 *
 413: 	 * For this to work, some conditions must be met.
 414: 	 * 1) Keypad sends SHORT (2 or 3 char) strings
 415: 	 * 2) All strings sent are same length & similar
 416: 	 * 3) The user is unlikely to type the first few chars of
 417: 	 *    one of these strings very fast.
 418: 	 * Note: some code has been fixed up since the above was laid out,
 419: 	 * so conditions 1 & 2 are probably not required anymore.
 420: 	 * However, this hasn't been tested with any first char
 421: 	 * that means anything else except escape.
 422: 	 */
 423: #ifdef MDEBUG
 424:     if (trace)
 425:         fprintf(trace,"map(%c): ",c);
 426: #endif
 427:     /*
 428: 	 * If c==0, the char came from getesc typing escape.  Pass it through
 429: 	 * unchanged.  0 messes up the following code anyway.
 430: 	 */
 431:     if (c==0)
 432:         return(0);
 433: 
 434:     b[0] = c;
 435:     b[1] = 0;
 436:     for (d=0; maps[d].mapto; d++) {
 437: #ifdef MDEBUG
 438:         if (trace)
 439:             fprintf(trace,"\ntry '%s', ",maps[d].cap);
 440: #endif
 441:         if (p = maps[d].cap) {
 442:             for (q=b; *p; p++, q++) {
 443: #ifdef MDEBUG
 444:                 if (trace)
 445:                     fprintf(trace,"q->b[%d], ",q-b);
 446: #endif
 447:                 if (*q==0) {
 448:                     /*
 449: 					 * Is there another char waiting?
 450: 					 *
 451: 					 * This test is oversimplified, but
 452: 					 * should work mostly. It handles the
 453: 					 * case where we get an ESCAPE that
 454: 					 * wasn't part of a keypad string.
 455: 					 */
 456:                     if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
 457: #ifdef MDEBUG
 458:                         if (trace)
 459:                             fprintf(trace,"fpk=0: will return '%c'",c);
 460: #endif
 461:                         /*
 462: 						 * Nothing waiting.  Push back
 463: 						 * what we peeked at & return
 464: 						 * failure (c).
 465: 						 *
 466: 						 * We want to be able to undo
 467: 						 * commands, but it's nonsense
 468: 						 * to undo part of an insertion
 469: 						 * so if in input mode don't.
 470: 						 */
 471: #ifdef MDEBUG
 472:                         if (trace)
 473:                             fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
 474: #endif
 475:                         macpush(&b[1],maps == arrows);
 476: #ifdef MDEBUG
 477:                         if (trace)
 478:                             fprintf(trace, "return %d\n", c);
 479: #endif
 480:                         return(c);
 481:                     }
 482:                     *q = getkey();
 483:                     q[1] = 0;
 484:                 }
 485:                 if (*p != *q)
 486:                     goto contin;
 487:             }
 488:             macpush(maps[d].mapto,maps == arrows);
 489:             c = getkey();
 490: #ifdef MDEBUG
 491:             if (trace)
 492:                 fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
 493: #endif
 494:             return(c);  /* first char of map string */
 495:             contin:;
 496:         }
 497:     }
 498: #ifdef MDEBUG
 499:     if (trace)
 500:         fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
 501: #endif
 502:     macpush(&b[1],0);
 503:     return(c);
 504: }
 505: 
 506: /*
 507:  * Push st onto the front of vmacp. This is tricky because we have to
 508:  * worry about where vmacp was previously pointing. We also have to
 509:  * check for overflow (which is typically from a recursive macro)
 510:  * Finally we have to set a flag so the whole thing can be undone.
 511:  * canundo is 1 iff we want to be able to undo the macro.  This
 512:  * is false for, for example, pushing back lookahead from fastpeekkey(),
 513:  * since otherwise two fast escapes can clobber our undo.
 514:  */
 515: macpush(st, canundo)
 516: char *st;
 517: int canundo;
 518: {
 519:     char tmpbuf[BUFSIZ];
 520: 
 521:     if (st==0 || *st==0)
 522:         return;
 523: #ifdef MDEBUG
 524:     if (trace)
 525:         fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
 526: #endif
 527:     if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZ)
 528:         error("Macro too long@ - maybe recursive?");
 529:     if (vmacp) {
 530:         strcpy(tmpbuf, vmacp);
 531:         if (!FIXUNDO)
 532:             canundo = 0;    /* can't undo inside a macro anyway */
 533:     }
 534:     strcpy(vmacbuf, st);
 535:     if (vmacp)
 536:         strcat(vmacbuf, tmpbuf);
 537:     vmacp = vmacbuf;
 538:     /* arrange to be able to undo the whole macro */
 539:     if (canundo) {
 540: #ifdef notdef
 541:         otchng = tchng;
 542:         vsave();
 543:         saveall();
 544:         inopen = -1;    /* no need to save since it had to be 1 or -1 before */
 545:         vundkind = VMANY;
 546: #endif
 547:         vch_mac = VC_NOCHANGE;
 548:     }
 549: }
 550: 
 551: #ifdef TRACE
 552: visdump(s)
 553: char *s;
 554: {
 555:     register int i;
 556: 
 557:     if (!trace) return;
 558: 
 559:     fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n",
 560:         s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO);
 561:     fprintf(trace, "   vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n",
 562:         vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero);
 563:     for (i=0; i<TUBELINES; i++)
 564:         if (vtube[i] && *vtube[i])
 565:             fprintf(trace, "%d: '%s'\n", i, vtube[i]);
 566:     tvliny();
 567: }
 568: 
 569: vudump(s)
 570: char *s;
 571: {
 572:     register line *p;
 573:     char savelb[1024];
 574: 
 575:     if (!trace) return;
 576: 
 577:     fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n",
 578:         s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2));
 579:     fprintf(trace, "  undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n",
 580:         lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol));
 581:     fprintf(trace, "  [\n");
 582:     CP(savelb, linebuf);
 583:     fprintf(trace, "linebuf = '%s'\n", linebuf);
 584:     for (p=zero+1; p<=truedol; p++) {
 585:         fprintf(trace, "%o ", *p);
 586:         getline(*p);
 587:         fprintf(trace, "'%s'\n", linebuf);
 588:     }
 589:     fprintf(trace, "]\n");
 590:     CP(linebuf, savelb);
 591: }
 592: #endif
 593: 
 594: /*
 595:  * Get a count from the keyed input stream.
 596:  * A zero count is indistinguishable from no count.
 597:  */
 598: vgetcnt()
 599: {
 600:     register int c, cnt;
 601: 
 602:     cnt = 0;
 603:     for (;;) {
 604:         c = getkey();
 605:         if (!isdigit(c))
 606:             break;
 607:         cnt *= 10, cnt += c - '0';
 608:     }
 609:     ungetkey(c);
 610:     Xhadcnt = 1;
 611:     Xcnt = cnt;
 612:     return(cnt);
 613: }
 614: 
 615: /*
 616:  * fastpeekkey is just like peekkey but insists the character come in
 617:  * fast (within 1 second). This will succeed if it is the 2nd char of
 618:  * a machine generated sequence (such as a function pad from an escape
 619:  * flavor terminal) but fail for a human hitting escape then waiting.
 620:  */
 621: fastpeekkey()
 622: {
 623:     int trapalarm();
 624:     register int c;
 625: 
 626:     /*
 627: 	 * If the user has set notimeout, we wait forever for a key.
 628: 	 * If we are in a macro we do too, but since it's already
 629: 	 * buffered internally it will return immediately.
 630: 	 * In other cases we force this to die in 1 second.
 631: 	 * This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
 632: 	 * but UNIX truncates it to 0 - 1 secs) but due to system delays
 633: 	 * there are times when arrow keys or very fast typing get counted
 634: 	 * as separate.  notimeout is provided for people who dislike such
 635: 	 * nondeterminism.
 636: 	 */
 637: #ifdef MDEBUG
 638:     if (trace)
 639:         fprintf(trace,"\nfastpeekkey: ",c);
 640: #endif
 641:     if (value(TIMEOUT) && inopen >= 0) {
 642:         signal(SIGALRM, trapalarm);
 643: #ifdef MDEBUG
 644:         alarm(10);
 645:         if (trace)
 646:             fprintf(trace, "set alarm ");
 647: #else
 648:         alarm(1);
 649: #endif
 650:     }
 651:     CATCH
 652:         c = peekkey();
 653: #ifdef MDEBUG
 654:     if (trace)
 655:         fprintf(trace,"[OK]",c);
 656: #endif
 657:         alarm(0);
 658:     ONERR
 659:         c = 0;
 660: #ifdef MDEBUG
 661:     if (trace)
 662:         fprintf(trace,"[TIMEOUT]",c);
 663: #endif
 664:     ENDCATCH
 665: #ifdef MDEBUG
 666:     if (trace)
 667:         fprintf(trace,"[fpk:%o]",c);
 668: #endif
 669:     return(c);
 670: }
 671: 
 672: trapalarm() {
 673:     alarm(0);
 674:     longjmp(vreslab,1);
 675: }

Defined functions

addtext defined in line 297; used 6 times
addto defined in line 330; used 2 times
beep defined in line 384; never used
fastpeekkey defined in line 621; used 1 times
getbr defined in line 62; used 2 times
macpush defined in line 515; used 9 times
peekbr defined in line 43; used 2 times
setBUF defined in line 317; used 2 times
setDEL defined in line 308; used 2 times
trapalarm defined in line 672; used 2 times
vgetcnt defined in line 598; used 3 times
visdump defined in line 552; used 2 times

Defined variables

precbksl defined in line 50; used 8 times
sccsid defined in line 2; never used

Defined macros

BEEHIVE defined in line 68; used 3 times
Last modified: 1981-07-09
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1561
Valid CSS Valid XHTML 1.0 Strict