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

Defined functions

addtext defined in line 312; used 6 times
addto defined in line 345; used 2 times
beep defined in line 399; never used
fastpeekkey defined in line 636; used 1 times
getbr defined in line 72; used 2 times
macpush defined in line 530; used 9 times
map defined in line 415; used 3 times
noteit defined in line 364; used 8 times
peekbr defined in line 51; used 2 times
peekkey defined in line 235; used 14 times
setBUF defined in line 332; used 2 times
setDEL defined in line 323; used 2 times
trapalarm defined in line 690; used 3 times
vgetcnt defined in line 613; used 3 times
visdump defined in line 567; used 2 times

Defined variables

doingread defined in line 60; used 2 times
precbksl defined in line 58; used 8 times
readbuf defined in line 59; used 1 times
sccsid defined in line 8; never used

Defined macros

BEEHIVE defined in line 78; used 3 times
Last modified: 1985-06-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2127
Valid CSS Valid XHTML 1.0 Strict