|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.