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