Subversion Repositories planix.SVN

Rev

Rev 115 | Details | Compare with Previous | Last modification | View Log | RSS feed

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