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