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