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