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