Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 7u83 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 
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 
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 
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
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 
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 
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 
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 
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 
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 
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 
484
setDEL(void)
485
{
486
 
487
	setBUF(DEL);
488
}
489
 
490
/*
491
 * Put text from cursor upto wcursor in BUF.
492
 */
493
void 
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 
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 
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
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
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 
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 
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 
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 
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 
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 
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 
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
}