1 /*
2  *      int KeyInit (map, flushproc)
3  *      struct KeyMap *map;
4  *      void (*flushproc) (void);
5  *
6  *              - set key map table.
7  *              Flushproc is called before actual reading from terminal.
8  *              Returns 1 if ok else 0.
9  *
10  *      int KeyGet ()
11  *
12  *              - reads key from terminal.
13  *              Returns key (always >= 0).
14  *
15  *      int KeyGetChar ()
16  *
17  *              - reads char from terminal.
18  *              Returns char (always >= 0).
19  */
20 
21 #include <stdlib.h>
22 #include <string.h>
23 #if HAVE_UNISTD_H
24 #   include <unistd.h>
25 #endif
26 #include "scr.h"
27 
28 static struct KeyMap *km;
29 static void (*flush) (void);
30 
31 #include <setjmp.h>
32 #include <signal.h>
33 
34 #define NKEY   100
35 
36 static jmp_buf wakeup;
37 static keyback;
38 static unsigned oldalarm;
39 
40 static cyrinput;
41 extern char VCyrInputTable [];
42 
43 /*
44  *      Compare keys. Used in call to qsort.
45  *      Return -1, 0, 1 iff a is less, equal or greater than b.
46  *      First, check if there is ->str.
47  *      Then compare lengths, then strings.
48  *      If equal, check ->tcap field.
49  */
compkeys(const void * arg1,const void * arg2)50 static int compkeys (const void *arg1, const void *arg2)
51 {
52 	const struct KeyMap *a = arg1;
53 	const struct KeyMap *b = arg2;
54 	register cmp;
55 
56 	if (! a->str) {
57 		if (! b->str)
58 			return (0);
59 		return (1);
60 	}
61 	if (! b->str)
62 		return (-1);
63 	cmp = strcmp (a->str, b->str);
64 	if (cmp)
65 		return (cmp);
66 	if (! a->tcap) {
67 		if (! b->tcap)
68 			return (0);
69 		return (1);
70 	}
71 	if (! b->tcap)
72 		return (-1);
73 	return (0);
74 }
75 
KeyInit(struct KeyMap * map,void (* flushproc)(void))76 void KeyInit (struct KeyMap *map, void (*flushproc) (void))
77 {
78 	struct CapTab tab [NKEY];
79 	register struct KeyMap *kp;
80 	register struct CapTab *t;
81 
82 	km = map;
83 	flush = flushproc;
84 	for (t=tab, kp=km; kp->val && t<tab+NKEY-1; ++kp, ++t) {
85 		if (! kp->tcap)
86 			continue;
87 		memcpy (t->tname, kp->tcap, sizeof (t->tname));
88 		t->ttype = CAPSTR;
89 		t->tdef = 0;
90 		t->tc = 0;
91 		t->ti = 0;
92 		t->ts = &kp->str;
93 	}
94 	kp->val = 0;
95 	t->tname[0] = 0;
96 	CapGet (tab);
97 	qsort ((char *) km, (unsigned) (kp - km), sizeof (km[0]), compkeys);
98 #ifdef notdef
99 	{
100 		register struct KeyMap *p;
101 		for (p=km; p<kp; ++p)
102 			if (kp->str)
103 				printf ("'\\%03o%s' -> %x\n", p->str[0], p->str+1, p->val);
104 	}
105 #endif
106 }
107 
KeyGetChar()108 int KeyGetChar ()
109 {
110 	char c;
111 
112 	while (read (0, &c, 1) != 1)
113 		if (! isatty (0))
114 			exit (0);
115 	return (c & 0377);
116 }
117 
badkey()118 static RETSIGTYPE badkey ()
119 {
120 	alarm (oldalarm);
121 	longjmp (wakeup, -1);
122 }
123 
nmgetch(struct KeyMap * kp)124 static int nmgetch (struct KeyMap *kp)
125 {
126 	register match, c;
127 	register struct KeyMap *lp;
128 
129 	for (match=1; ; ++match) {
130 		if (! kp->str [match])
131 			return (kp->val);
132 		c = KeyGetChar ();
133 		if (kp->str [match] == c)
134 			continue;
135 		lp = kp;
136 		do {
137 			++kp;
138 			if (! kp->str)
139 				goto unknown;
140 		} while (kp->str [match] != c);
141 		if (lp->str [match-1] != kp->str [match-1])
142 			goto unknown;
143 		if (match>1 && strncmp (lp->str, kp->str, match-1))
144 			goto unknown;
145 	}
146 unknown:
147 	alarm (oldalarm);
148 	longjmp (wakeup, 1);
149 	/* NOTREACHED */
150 }
151 
KeyGet()152 int KeyGet ()
153 {
154 	static struct KeyMap *kp;
155 	static int c, j;
156 
157 	if (keyback) {
158 		c = keyback;
159 		keyback = 0;
160 		return (c);
161 	}
162 	if (flush)
163 		(*flush) ();
164 nextkey:
165 	c = KeyGetChar ();
166 	for (kp=km; kp->str; ++kp)
167 		if ((char) c == kp->str[0])
168 			break;
169 	if (! kp->str) {
170 #ifdef DOC
171 		if (c == cntrl ('_')) {
172 			_prscreen ();
173 			goto nextkey;
174 		}
175 #endif
176 		/*
177 		 * Handle cyrillic input.
178 		 * ^N turns on cyrillic input mode,
179 		 * after that all input characters
180 		 * in range ' '...'~' must be recoded
181 		 * by special cyrillic input table.
182 		 * It is specified by Ct termcap descriptor.
183 		 * ^O turns off cyrillic input mode.
184 		 */
185 		if (c == cntrl ('N')) {
186 			cyrinput = 1;
187 			goto nextkey;
188 		} else if (c == cntrl ('O')) {
189 			cyrinput = 0;
190 			goto nextkey;
191 		} else if (cyrinput && c>=' ' && c<='~')
192 			c = VCyrInputTable [c - ' '] & 0xff;
193 
194 		return (c);
195 	}
196 	if (! kp->str [1])
197 		return (kp->val);
198 	/* look for escape sequence */
199 	if ((j = setjmp (wakeup))) {
200 		/* time out or unknown escape sequence */
201 		TtyFlushInput ();
202 		if (j < 0)
203 			return (c);
204 		goto nextkey;
205 	}
206 	signal (SIGALRM, badkey);
207 	oldalarm = alarm (2);
208 	c = nmgetch (kp);
209 	alarm (oldalarm);
210 	return (c);
211 }
212 
KeyUnget(int key)213 void KeyUnget (int key)
214 {
215 	keyback = key;
216 }
217