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: while (c == 0); 34: return (c); 35: } 36: 37: /* 38: * Tell whether next keystroke would be a ^@. 39: */ 40: peekbr() 41: { 42: 43: Peekkey = getbr(); 44: return (Peekkey == 0); 45: } 46: 47: short precbksl; 48: 49: /* 50: * Get a keystroke, including a ^@. 51: * If an key was returned with ungetkey, that 52: * comes back first. Next comes unread input (e.g. 53: * from repeating commands with .), and finally new 54: * keystrokes. 55: * 56: * The hard work here is in mapping of \ escaped 57: * characters on upper case only terminals. 58: */ 59: getbr() 60: { 61: char ch; 62: register int c, d; 63: register char *colp; 64: #ifdef BEEHIVE 65: static char Peek2key; 66: #endif 67: 68: getATTN: 69: if (Peekkey) { 70: c = Peekkey; 71: Peekkey = 0; 72: return (c); 73: } 74: #ifdef BEEHIVE 75: if (Peek2key) { 76: c = Peek2key; 77: Peek2key = 0; 78: return (c); 79: } 80: #endif 81: if (vglobp) { 82: if (*vglobp) 83: return (lastvgk = *vglobp++); 84: lastvgk = 0; 85: return (ESCAPE); 86: } 87: #ifdef TRACE 88: if (trace) 89: fflush(trace); 90: #endif 91: flusho(); 92: again: 93: if (read(0, &ch, 1) != 1) { 94: if (errno == EINTR) 95: goto getATTN; 96: error("Input read error"); 97: } 98: c = ch & TRIM; 99: #ifdef BEEHIVE 100: if (XB && c == ESCAPE) { 101: if (read(0, &Peek2key, 1) != 1) 102: goto getATTN; 103: Peek2key &= TRIM; 104: switch (Peek2key) { 105: case 'C': /* in SPOW mode sometimes space sends esc C */ 106: c = ' '; 107: goto clrpeek; 108: case 'q': /* f2 -> ^C */ 109: c = CTRL(c); 110: case 'p': /* f1 -> esc */ 111: clrpeek: 112: Peek2key = 0; 113: break; 114: } 115: } 116: #endif 117: 118: #ifdef UCVISUAL 119: /* 120: * The algorithm here is that of the UNIX kernel. 121: * See the description in the programmers manual. 122: */ 123: if (UPPERCASE) { 124: if (isupper(c)) 125: c = tolower(c); 126: if (c == '\\') { 127: if (precbksl < 2) 128: precbksl++; 129: if (precbksl == 1) 130: goto again; 131: } else if (precbksl) { 132: d = 0; 133: if (islower(c)) 134: d = toupper(c); 135: else { 136: colp = "({)}!|^~'~"; 137: while (d = *colp++) 138: if (d == c) { 139: d = *colp++; 140: break; 141: } else 142: colp++; 143: } 144: if (precbksl == 2) { 145: if (!d) { 146: Peekkey = c; 147: precbksl = 0; 148: c = '\\'; 149: } 150: } else if (d) 151: c = d; 152: else { 153: Peekkey = c; 154: precbksl = 0; 155: c = '\\'; 156: } 157: } 158: if (c != '\\') 159: precbksl = 0; 160: } 161: #endif 162: #ifdef TRACE 163: if (trace) { 164: if (!techoin) { 165: tfixnl(); 166: techoin = 1; 167: fprintf(trace, "*** Input: "); 168: } 169: tracec(c); 170: } 171: #endif 172: lastvgk = 0; 173: return (c); 174: } 175: 176: /* 177: * Get a key, but if a delete, quit or attention 178: * is typed return 0 so we will abort a partial command. 179: */ 180: getesc() 181: { 182: register int c; 183: 184: c = getkey(); 185: switch (c) { 186: 187: case ATTN: 188: case QUIT: 189: ungetkey(c); 190: return (0); 191: case CTRL(v): 192: case CTRL(q): 193: c = getkey(); 194: return (c); 195: 196: case ESCAPE: 197: return (0); 198: } 199: return (c); 200: } 201: 202: /* 203: * Peek at the next keystroke. 204: */ 205: peekkey() 206: { 207: 208: Peekkey = getkey(); 209: return (Peekkey); 210: } 211: 212: /* 213: * Read a line from the echo area, with single character prompt c. 214: * A return value of 1 means the user blewit or blewit away. 215: */ 216: readecho(c) 217: char c; 218: { 219: register char *sc = cursor; 220: register int (*OP)(); 221: bool waste; 222: register int OPeek; 223: 224: if (WBOT == WECHO) 225: vclean(); 226: else 227: vclrech(0); 228: splitw++; 229: vgoto(WECHO, 0); 230: putchar(c); 231: vclreol(); 232: vgoto(WECHO, 1); 233: cursor = linebuf; linebuf[0] = 0; genbuf[0] = c; 234: if (peekbr()) { 235: if (!INS[0] || (INS[0] & (QUOTE|TRIM)) == OVERBUF) 236: goto blewit; 237: vglobp = INS; 238: } 239: OP = Pline; Pline = normline; 240: ignore(vgetline(0, genbuf + 1, &waste)); 241: vscrap(); 242: Pline = OP; 243: if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL(h)) { 244: cursor = sc; 245: vclreol(); 246: return (0); 247: } 248: blewit: 249: OPeek = Peekkey==CTRL(h) ? 0 : Peekkey; Peekkey = 0; 250: splitw = 0; 251: vclean(); 252: vshow(dot, NOLINE); 253: vnline(sc); 254: Peekkey = OPeek; 255: return (1); 256: } 257: 258: /* 259: * A complete command has been defined for 260: * the purposes of repeat, so copy it from 261: * the working to the previous command buffer. 262: */ 263: setLAST() 264: { 265: 266: if (vglobp) 267: return; 268: lastreg = vreg; 269: lasthad = Xhadcnt; 270: lastcnt = Xcnt; 271: *lastcp = 0; 272: CP(lastcmd, workcmd); 273: } 274: 275: /* 276: * Gather up some more text from an insert. 277: * If the insertion buffer oveflows, then destroy 278: * the repeatability of the insert. 279: */ 280: addtext(cp) 281: char *cp; 282: { 283: 284: if (vglobp) 285: return; 286: addto(INS, cp); 287: if ((INS[0] & (QUOTE|TRIM)) == OVERBUF) 288: lastcmd[0] = 0; 289: } 290: 291: setDEL() 292: { 293: 294: setBUF(DEL); 295: } 296: 297: /* 298: * Put text from cursor upto wcursor in BUF. 299: */ 300: setBUF(BUF) 301: register char *BUF; 302: { 303: register int c; 304: register char *wp = wcursor; 305: 306: c = *wp; 307: *wp = 0; 308: BUF[0] = 0; 309: addto(BUF, cursor); 310: *wp = c; 311: } 312: 313: addto(buf, str) 314: register char *buf, *str; 315: { 316: 317: if ((buf[0] & (QUOTE|TRIM)) == OVERBUF) 318: return; 319: if (strlen(buf) + strlen(str) + 1 >= VBSIZE) { 320: buf[0] = OVERBUF; 321: return; 322: } 323: ignore(strcat(buf, str)); 324: } 325: 326: /* 327: * Note a change affecting a lot of lines, or non-visible 328: * lines. If the parameter must is set, then we only want 329: * to do this for open modes now; return and save for later 330: * notification in visual. 331: */ 332: noteit(must) 333: bool must; 334: { 335: register int sdl = destline, sdc = destcol; 336: 337: if (notecnt < 2 || !must 338: #ifdef OPENCODE 339: && state == VISUAL 340: #endif 341: ) 342: return (0); 343: splitw++; 344: if (WBOT == WECHO) 345: vmoveitup(1, 1); 346: vigoto(WECHO, 0); 347: printf("%d %sline", notecnt, notesgn); 348: if (notecnt > 1) 349: putchar('s'); 350: if (*notenam) { 351: printf(" %s", notenam); 352: if (*(strend(notenam) - 1) != 'e') 353: putchar('e'); 354: putchar('d'); 355: } 356: vclreol(); 357: notecnt = 0; 358: #ifdef OPENCODE 359: if (state != VISUAL) 360: vcnt = vcline = 0; 361: #endif 362: splitw = 0; 363: #ifdef OPENCODE 364: if (state == ONEOPEN || state == CRTOPEN) 365: vup1(); 366: #endif 367: destline = sdl; destcol = sdc; 368: return (1); 369: } 370: 371: /* 372: * Rrrrringgggggg. 373: * If possible, use flash (VB). 374: */ 375: beep() 376: { 377: 378: if (VB) 379: vputp(VB, 0); 380: else 381: vputc(CTRL(g)); 382: } 383: 384: /* 385: * Map the command input character c, 386: * for keypads and labelled keys which do cursor 387: * motions. I.e. on an adm3a we might map ^K to ^P. 388: * DM1520 for example has a lot of mappable characters. 389: */ 390: map(c) 391: register int c; 392: { 393: register int d; 394: register char *cp = MA; 395: 396: if (cp == 0) 397: return (c); 398: while (d = *cp++) { 399: if (c == d) 400: return (*cp); 401: if (*cp++ == 0) 402: return (c); 403: } 404: return (c); 405: } 406: 407: /* 408: * Get a count from the keyed input stream. 409: * A zero count is indistinguishable from no count. 410: */ 411: vgetcnt() 412: { 413: register int c, cnt; 414: 415: cnt = 0; 416: for (;;) { 417: c = getkey(); 418: if (!isdigit(c)) 419: break; 420: cnt *= 10, cnt += c - '0'; 421: } 422: ungetkey(c); 423: Xhadcnt = 1; 424: Xcnt = cnt; 425: return(cnt); 426: }