1 /*
2 * This code contains changes by
3 * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4 *
5 * Conditions 1, 2, and 4 and the no-warranty notice below apply
6 * to these changes.
7 *
8 *
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *
41 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * Redistributions of source code and documentation must retain the
47 * above copyright notice, this list of conditions and the following
48 * disclaimer.
49 * Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed or owned by Caldera
55 * International, Inc.
56 * Neither the name of Caldera International, Inc. nor the names of
57 * other contributors may be used to endorse or promote products
58 * derived from this software without specific prior written permission.
59 *
60 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72 */
73
74 #ifndef lint
75 #ifdef DOSCCS
76 static char sccsid[] = "@(#)ex_vget.c 1.29 (gritter) 2/15/05";
77 #endif
78 #endif
79
80 /* from ex_vget.c 6.8.1 (2.11BSD GTE) 12/9/94 */
81
82 #include "ex.h"
83 #include "ex_tty.h"
84 #include "ex_vis.h"
85
86 /*
87 * Input routines for open/visual.
88 * We handle reading from the echo area here as well as notification on
89 * large changes which appears in the echo area.
90 */
91
92 /*
93 * Return the key.
94 */
95 void
ungetkey(int c)96 ungetkey (
97 int c /* mjm: char --> int */
98 )
99 {
100
101 if (Peekkey != ATTN)
102 Peekkey = c;
103 }
104
105 /*
106 * Return a keystroke, but never a ^@.
107 */
108 int
getkey(void)109 getkey(void)
110 {
111 register int c; /* mjm: char --> int */
112
113 do {
114 c = getbr();
115 if (c==0)
116 beep();
117 } while (c == 0);
118 return (c);
119 }
120
121 /*
122 * Tell whether next keystroke would be a ^@.
123 */
124 int
peekbr(void)125 peekbr(void)
126 {
127
128 Peekkey = getbr();
129 return (Peekkey == 0);
130 }
131
132 short precbksl;
133 JMP_BUF readbuf;
134 int doingread = 0;
135
136 static int
readwc(int fd,int * cp)137 readwc(int fd, int *cp)
138 {
139 int c;
140 char b;
141
142 #ifdef MB
143 if (mb_cur_max > 1) {
144 static char pbuf[2][MB_LEN_MAX], *pend[2], *pcur[2];
145 static mbstate_t state[2];
146 static int incompl[2];
147 int i, rest;
148 int idx = fd ? 1 : 0;
149 wchar_t wc;
150 size_t sz;
151
152 i = 0;
153 rest = pend[idx] - pcur[idx];
154 if (rest && pcur[idx] > pbuf[idx]) {
155 do
156 pbuf[idx][i] = pcur[idx][i];
157 while (i++, --rest);
158 } else if (incompl[idx]) {
159 pend[idx] = pcur[idx] = NULL;
160 return -1;
161 }
162 if (i == 0) {
163 if ((c = read(fd, &b, 1)) <= 0) {
164 pend[idx] = pcur[idx] = NULL;
165 return c;
166 }
167 pbuf[idx][i++] = b;
168 }
169 if (pbuf[idx][0] & 0200) {
170 sz = 1;
171 while ((sz = mbrtowc(&wc, pbuf[idx], i, &state[idx]))
172 == (size_t)-2 && i < mb_cur_max) {
173 if ((c = read(fd, &b, 1)) <= 0) {
174 incompl[idx] = 1;
175 break;
176 } else
177 pbuf[idx][i++] = b;
178 memset(&state[idx], 0, sizeof state[idx]);
179 }
180 if (sz == (size_t)-2 || sz == (size_t)-1 ||
181 !widthok(wc)) {
182 memset(&state[idx], 0, sizeof state[idx]);
183 c = 1;
184 *cp = pbuf[idx][0] | INVBIT;
185 } else if (sz == 0) {
186 c = 1;
187 *cp = wc;
188 } else {
189 c = sz;
190 *cp = wc;
191 }
192 } else {
193 c = 1;
194 *cp = pbuf[idx][0];
195 }
196 pcur[idx] = &pbuf[idx][c];
197 pend[idx] = &pcur[idx][i-c];
198 return c;
199 } else
200 #endif /* MB */
201 {
202 c = read(fd, &b, 1);
203 *cp = b;
204 return c;
205 }
206 }
207
208 /*
209 * Get a keystroke, including a ^@.
210 * If an key was returned with ungetkey, that
211 * comes back first. Next comes unread input (e.g.
212 * from repeating commands with .), and finally new
213 * keystrokes.
214 */
215 int
getbr(void)216 getbr(void)
217 {
218 int ch;
219 register int c;
220 #ifdef UCVISUAL
221 register int d;
222 register char *colp;
223 #endif
224 #ifdef BEEHIVE
225 int cnt;
226 static char Peek2key;
227 #endif
228 extern short slevel, ttyindes;
229
230 getATTN:
231 if (Peekkey) {
232 c = Peekkey;
233 Peekkey = 0;
234 return (c);
235 }
236 #ifdef BEEHIVE
237 if (Peek2key) {
238 c = Peek2key;
239 Peek2key = 0;
240 return (c);
241 }
242 #endif
243 if (vglobp) {
244 if (*vglobp)
245 return (lastvgk = *vglobp++);
246 lastvgk = 0;
247 return (ESCAPE);
248 }
249 if (vmacp) {
250 if (*vmacp) {
251 int n;
252 nextc(ch, vmacp, n);
253 vmacp += n;
254 return (ch);
255 }
256 /* End of a macro or set of nested macros */
257 vmacp = 0;
258 if (inopen == -1) /* don't screw up undo for esc esc */
259 vundkind = VMANY;
260 inopen = 1; /* restore old setting now that macro done */
261 vch_mac = VC_NOTINMAC;
262 }
263 flusho();
264 for (c =0; abbrevs[c].mapto; c++)
265 abbrevs[c].hadthis = 0;
266 #ifdef UCVISUAL
267 again:
268 #endif
269 if (SETJMP(readbuf))
270 goto getATTN;
271 doingread = 1;
272 c = readwc(slevel == 0 ? 0 : ttyindes, &ch);
273 doingread = 0;
274 if (c < 1) {
275 if (errno == EINTR)
276 goto getATTN;
277 error(catgets(catd, 1, 222, "Input read error"));
278 }
279 c = ch & TRIM;
280 #ifdef BEEHIVE
281 if (XB && slevel==0 && c == ESCAPE) {
282 if (readwc(0, &Peek2key) < 1)
283 goto getATTN;
284 Peek2key &= TRIM;
285 switch (Peek2key) {
286 case 'C': /* SPOW mode sometimes sends \EC for space */
287 c = ' ';
288 Peek2key = 0;
289 break;
290 case 'q': /* f2 -> ^C */
291 c = CTRL('c');
292 Peek2key = 0;
293 break;
294 case 'p': /* f1 -> esc */
295 Peek2key = 0;
296 break;
297 }
298 }
299 #endif
300
301 #ifdef UCVISUAL
302 /*
303 * The algorithm here is that of the UNIX kernel.
304 * See the description in the programmers manual.
305 */
306 if (UPPERCASE) {
307 if (xisupper(c))
308 c = xtolower(c);
309 if (c == '\\') {
310 if (precbksl < 2)
311 precbksl++;
312 if (precbksl == 1)
313 goto again;
314 } else if (precbksl) {
315 d = 0;
316 if (xislower(c))
317 d = xtoupper(c);
318 else {
319 colp = "({)}!|^~'~";
320 while (d = *colp++)
321 if (d == c) {
322 d = *colp++;
323 break;
324 } else
325 colp++;
326 }
327 if (precbksl == 2) {
328 if (!d) {
329 Peekkey = c;
330 precbksl = 0;
331 c = '\\';
332 }
333 } else if (d)
334 c = d;
335 else {
336 Peekkey = c;
337 precbksl = 0;
338 c = '\\';
339 }
340 }
341 if (c != '\\')
342 precbksl = 0;
343 }
344 #endif
345
346 #ifdef TRACE
347 if (trace) {
348 if (!techoin) {
349 tfixnl();
350 techoin = 1;
351 fprintf(trace, "*** Input: ");
352 }
353 tracec(c);
354 }
355 #endif
356 lastvgk = 0;
357 return (c);
358 }
359
360 /*
361 * Get a key, but if a delete, quit or attention
362 * is typed return 0 so we will abort a partial command.
363 */
364 int
getesc(void)365 getesc(void)
366 {
367 register int c;
368
369 c = getkey();
370 if (c == ATTN)
371 goto case_ATTN;
372 switch (c) {
373
374 case CTRL('v'):
375 case CTRL('q'):
376 c = getkey();
377 return (c);
378
379 case QUIT:
380 case_ATTN:
381 ungetkey(c);
382 return (0);
383
384 case ESCAPE:
385 return (0);
386 }
387 return (c);
388 }
389
390 /*
391 * Peek at the next keystroke.
392 */
393 int
peekkey(void)394 peekkey(void)
395 {
396
397 Peekkey = getkey();
398 return (Peekkey);
399 }
400
401 /*
402 * Read a line from the echo area, with single character prompt c.
403 * A return value of 1 means the user blewit or blewit away.
404 */
405 int
readecho(int c)406 readecho(int c)
407 {
408 register char *sc = cursor;
409 register void (*OP)(int);
410 bool waste;
411 register int OPeek;
412
413 if (WBOT == WECHO)
414 vclean();
415 else
416 vclrech(0);
417 splitw++;
418 vgoto(WECHO, 0);
419 putchar(c);
420 vclreol();
421 vgoto(WECHO, 1);
422 cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
423 if (peekbr()) {
424 if (!INS[0] || (INS[0] & (QUOTE|TRIM)) == OVERBUF)
425 goto blewit;
426 vglobp = INS;
427 }
428 OP = Pline; Pline = normline;
429 ignore(vgetline(0, genbuf + 1, &waste, c));
430 if (Outchar == termchar)
431 putchar('\n');
432 vscrap();
433 Pline = OP;
434 if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL('h')) {
435 cursor = sc;
436 vclreol();
437 return (0);
438 }
439 blewit:
440 OPeek = Peekkey==CTRL('h') ? 0 : Peekkey; Peekkey = 0;
441 splitw = 0;
442 vclean();
443 vshow(dot, NOLINE);
444 vnline(sc);
445 Peekkey = OPeek;
446 return (1);
447 }
448
449 /*
450 * A complete command has been defined for
451 * the purposes of repeat, so copy it from
452 * the working to the previous command buffer.
453 */
454 void
setLAST(void)455 setLAST(void)
456 {
457
458 if (vglobp || vmacp)
459 return;
460 lastreg = vreg;
461 lasthad = Xhadcnt;
462 lastcnt = Xcnt;
463 *lastcp = 0;
464 cellcpy(lastcmd, workcmd);
465 }
466
467 /*
468 * Gather up some more text from an insert.
469 * If the insertion buffer oveflows, then destroy
470 * the repeatability of the insert.
471 */
472 void
addtext(char * cp)473 addtext(char *cp)
474 {
475
476 if (vglobp)
477 return;
478 addto(INS, cp);
479 if ((INS[0] & (QUOTE|TRIM)) == OVERBUF)
480 lastcmd[0] = 0;
481 }
482
483 void
setDEL(void)484 setDEL(void)
485 {
486
487 setBUF(DEL);
488 }
489
490 /*
491 * Put text from cursor upto wcursor in BUF.
492 */
493 void
setBUF(register cell * BUF)494 setBUF(register cell *BUF)
495 {
496 register int c;
497 register char *wp = wcursor;
498
499 c = *wp;
500 *wp = 0;
501 BUF[0] = 0;
502 addto(BUF, cursor);
503 *wp = c;
504 }
505
506 void
addto(register cell * buf,register char * str)507 addto(register cell *buf, register char *str)
508 {
509
510 if ((buf[0] & (QUOTE|TRIM)) == OVERBUF)
511 return;
512 if (cellen(buf) + strlen(str) + 1 >= VBSIZE) {
513 buf[0] = OVERBUF;
514 return;
515 }
516 while (*buf)
517 buf++;
518 str2cell(buf, str);
519 }
520
521 /*
522 * Note a change affecting a lot of lines, or non-visible
523 * lines. If the parameter must is set, then we only want
524 * to do this for open modes now; return and save for later
525 * notification in visual.
526 */
527 int
noteit(int must)528 noteit(int must)
529 {
530 register int sdl = destline, sdc = destcol;
531
532 if (notecnt < 2 || !must && state == VISUAL)
533 return (0);
534 splitw++;
535 if (WBOT == WECHO)
536 vmoveitup(1, 1);
537 vigoto(WECHO, 0);
538 printf(catgets(catd, 1, 223, "%d %sline"), notecnt, notesgn);
539 if (notecnt > 1)
540 putchar('s');
541 if (*notenam) {
542 printf(" %s", notenam);
543 if (*(strend(notenam) - 1) != 'e')
544 putchar('e');
545 putchar('d');
546 }
547 vclreol();
548 notecnt = 0;
549 if (state != VISUAL)
550 vcnt = vcline = 0;
551 splitw = 0;
552 if (state == ONEOPEN || state == CRTOPEN)
553 vup1();
554 destline = sdl; destcol = sdc;
555 return (1);
556 }
557
558 /*
559 * Rrrrringgggggg.
560 * If possible, use flash (VB).
561 */
562 void
beep(void)563 beep(void)
564 {
565
566 if (VB && value(FLASH))
567 vputp(VB, 0);
568 else
569 vputc(CTRL('g'));
570 }
571
572 /*
573 * Push an integer string as a macro.
574 */
575 static void
imacpush(int * ip,int canundo)576 imacpush(int *ip, int canundo)
577 {
578 char buf[BUFSIZ], *bp = buf;
579
580 #ifdef MB
581 do {
582 int n;
583 n = wctomb(bp, *ip&TRIM);
584 bp += n;
585 } while (*ip++);
586 #else /* !MB */
587 while (*bp++ = *ip++);
588 #endif /* !MB */
589 macpush(buf, canundo);
590 }
591
592 /*
593 * Map the command input character c,
594 * for keypads and labelled keys which do cursor
595 * motions. I.e. on an adm3a we might map ^K to ^P.
596 * DM1520 for example has a lot of mappable characters.
597 */
598
599 int
map(register int c,register struct maps * maps)600 map(register int c, register struct maps *maps)
601 {
602 register int d;
603 register int *p, *q;
604 int b[10+MB_LEN_MAX]; /* Assumption: no keypad sends string longer than 10 */
605
606 /*
607 * Mapping for special keys on the terminal only.
608 * BUG: if there's a long sequence and it matches
609 * some chars and then misses, we lose some chars.
610 *
611 * For this to work, some conditions must be met.
612 * 1) Keypad sends SHORT (2 or 3 char) strings
613 * 2) All strings sent are same length & similar
614 * 3) The user is unlikely to type the first few chars of
615 * one of these strings very fast.
616 * Note: some code has been fixed up since the above was laid out,
617 * so conditions 1 & 2 are probably not required anymore.
618 * However, this hasn't been tested with any first char
619 * that means anything else except escape.
620 */
621 #ifdef MDEBUG
622 if (trace)
623 fprintf(trace,"map(%c): ",c);
624 #endif
625 /*
626 * If c==0, the char came from getesc typing escape. Pass it through
627 * unchanged. 0 messes up the following code anyway.
628 */
629 if (c==0)
630 return(0);
631
632 b[0] = c;
633 b[1] = 0;
634 for (d=0; maps[d].mapto; d++) {
635 #ifdef MDEBUG
636 if (trace)
637 fprintf(trace,"\ntry '%s', ",maps[d].cap);
638 #endif
639 if (p = maps[d].icap) {
640 for (q=b; *p; p++, q++) {
641 #ifdef MDEBUG
642 if (trace)
643 fprintf(trace,"q->b[%d], ",q-b);
644 #endif
645 if (*q==0) {
646 /*
647 * Is there another char waiting?
648 *
649 * This test is oversimplified, but
650 * should work mostly. It handles the
651 * case where we get an ESCAPE that
652 * wasn't part of a keypad string.
653 */
654 if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
655 #ifdef MDEBUG
656 if (trace)
657 fprintf(trace,"fpk=0: will return '%c'",c);
658 #endif
659 /*
660 * Nothing waiting. Push back
661 * what we peeked at & return
662 * failure (c).
663 *
664 * We want to be able to undo
665 * commands, but it's nonsense
666 * to undo part of an insertion
667 * so if in input mode don't.
668 */
669 #ifdef MDEBUG
670 if (trace)
671 fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
672 #endif
673 imacpush(&b[1],maps == arrows);
674 #ifdef MDEBUG
675 if (trace)
676 fprintf(trace, "return %d\n", c);
677 #endif
678 return(c);
679 }
680 *q = getkey();
681 q[1] = 0;
682 }
683 if (*p != *q)
684 goto contin;
685 }
686 macpush(maps[d].mapto,maps == arrows);
687 c = getkey();
688 #ifdef MDEBUG
689 if (trace)
690 fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
691 #endif
692 return(c); /* first char of map string */
693 contin:;
694 }
695 }
696 #ifdef MDEBUG
697 if (trace)
698 fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
699 #endif
700 imacpush(&b[1],0);
701 return(c);
702 }
703
704 /*
705 * Push st onto the front of vmacp. This is tricky because we have to
706 * worry about where vmacp was previously pointing. We also have to
707 * check for overflow (which is typically from a recursive macro)
708 * Finally we have to set a flag so the whole thing can be undone.
709 * canundo is 1 iff we want to be able to undo the macro. This
710 * is false for, for example, pushing back lookahead from fastpeekkey(),
711 * since otherwise two fast escapes can clobber our undo.
712 */
713 void
macpush(char * st,int canundo)714 macpush(char *st, int canundo)
715 {
716 char tmpbuf[BUFSIZ];
717
718 if (st==0 || *st==0)
719 return;
720 #ifdef MDEBUG
721 if (trace)
722 fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
723 #endif
724 if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZ)
725 error(catgets(catd, 1, 224,
726 "Macro too long@ - maybe recursive?"));
727 if (vmacp) {
728 strcpy(tmpbuf, vmacp);
729 if (!FIXUNDO)
730 canundo = 0; /* can't undo inside a macro anyway */
731 }
732 strcpy(vmacbuf, st);
733 if (vmacp)
734 strcat(vmacbuf, tmpbuf);
735 vmacp = vmacbuf;
736 /* arrange to be able to undo the whole macro */
737 if (canundo) {
738 #ifdef notdef
739 otchng = tchng;
740 vsave();
741 saveall();
742 inopen = -1; /* no need to save since it had to be 1 or -1 before */
743 vundkind = VMANY;
744 #endif
745 vch_mac = VC_NOCHANGE;
746 }
747 }
748
749 #ifdef TRACE
750 void
visdump(char * s)751 visdump(char *s)
752 {
753 register int i;
754
755 if (!trace) return;
756
757 fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n",
758 s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO);
759 fprintf(trace, " vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n",
760 vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero);
761 for (i=0; i<TUBELINES; i++)
762 if (vtube[i] && *vtube[i])
763 fprintf(trace, "%d: '%s'\n", i, vtube[i]);
764 tvliny();
765 }
766
767 void
vudump(char * s)768 vudump(char *s)
769 {
770 register line *p;
771 char savelb[1024];
772
773 if (!trace) return;
774
775 fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n",
776 s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2));
777 fprintf(trace, " undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n",
778 lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol));
779 fprintf(trace, " [\n");
780 CP(savelb, linebuf);
781 fprintf(trace, "linebuf = '%s'\n", linebuf);
782 for (p=zero+1; p<=truedol; p++) {
783 fprintf(trace, "%o ", *p);
784 getline(*p);
785 fprintf(trace, "'%s'\n", linebuf);
786 }
787 fprintf(trace, "]\n");
788 CP(linebuf, savelb);
789 }
790 #endif
791
792 /*
793 * Get a count from the keyed input stream.
794 * A zero count is indistinguishable from no count.
795 */
796 int
vgetcnt(void)797 vgetcnt(void)
798 {
799 register int c, cnt;
800
801 cnt = 0;
802 for (;;) {
803 c = getkey();
804 if (!xisdigit(c))
805 break;
806 cnt *= 10, cnt += c - '0';
807 }
808 ungetkey(c);
809 Xhadcnt = 1;
810 Xcnt = cnt;
811 return(cnt);
812 }
813
814 void
trapalarm(int signum)815 trapalarm(int signum) {
816 alarm(0);
817 if (vcatch)
818 LONGJMP(vreslab,1);
819 }
820
821 /*
822 * fastpeekkey is just like peekkey but insists the character come in
823 * fast (within 1 second). This will succeed if it is the 2nd char of
824 * a machine generated sequence (such as a function pad from an escape
825 * flavor terminal) but fail for a human hitting escape then waiting.
826 */
827 int
fastpeekkey(void)828 fastpeekkey(void)
829 {
830 shand Oint;
831 register int c;
832
833 /*
834 * If the user has set notimeout, we wait forever for a key.
835 * If we are in a macro we do too, but since it's already
836 * buffered internally it will return immediately.
837 * In other cases we force this to die in 1 second.
838 * This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
839 * but UNIX truncates it to 0 - 1 secs) but due to system delays
840 * there are times when arrow keys or very fast typing get counted
841 * as separate. notimeout is provided for people who dislike such
842 * nondeterminism.
843 */
844 #ifdef MDEBUG
845 if (trace)
846 fprintf(trace,"\nfastpeekkey: ",c);
847 #endif
848 Oint = signal(SIGINT, trapalarm);
849 if (value(TIMEOUT) && inopen >= 0) {
850 signal(SIGALRM, trapalarm);
851 #ifdef MDEBUG
852 alarm(10);
853 if (trace)
854 fprintf(trace, "set alarm ");
855 #else
856 alarm(1);
857 #endif
858 }
859 CATCH
860 c = peekkey();
861 #ifdef MDEBUG
862 if (trace)
863 fprintf(trace,"[OK]",c);
864 #endif
865 alarm(0);
866 ONERR
867 c = 0;
868 #ifdef MDEBUG
869 if (trace)
870 fprintf(trace,"[TIMEOUT]",c);
871 #endif
872 ENDCATCH
873 #ifdef MDEBUG
874 if (trace)
875 fprintf(trace,"[fpk:%o]",c);
876 #endif
877 signal(SIGINT,Oint);
878 return(c);
879 }
880