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: }

Defined functions

addtext defined in line 264; used 6 times
addto defined in line 297; used 2 times
beep defined in line 351; never used
fastpeekkey defined in line 588; used 1 times
getbr defined in line 68; used 2 times
macpush defined in line 482; used 9 times
map defined in line 367; used 3 times
noteit defined in line 316; used 8 times
peekbr defined in line 50; used 2 times
peekkey defined in line 187; used 14 times
setBUF defined in line 284; used 2 times
setDEL defined in line 275; used 2 times
trapalarm defined in line 642; used 3 times
vgetcnt defined in line 565; used 3 times
visdump defined in line 519; used 2 times

Defined variables

doingread defined in line 59; used 2 times
precbksl defined in line 57; never used
readbuf defined in line 58; used 1 times
sccsid defined in line 8; never used

Defined macros

BEEHIVE defined in line 74; used 3 times
Last modified: 1994-12-10
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4999
Valid CSS Valid XHTML 1.0 Strict