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