1 /*-
2 * Copyright (c) 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 * Keith Bostic. All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10 #include "config.h"
11
12 #include <sys/types.h>
13 #include <sys/queue.h>
14 #include <sys/time.h>
15
16 #include <bitstring.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "common.h"
25
26 /*
27 * seq_set --
28 * Internal version to enter a sequence.
29 *
30 * PUBLIC: int seq_set(SCR *, CHAR_T *,
31 * PUBLIC: size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int);
32 */
33 int
seq_set(SCR * sp,CHAR_T * name,size_t nlen,CHAR_T * input,size_t ilen,CHAR_T * output,size_t olen,seq_t stype,int flags)34 seq_set(SCR *sp, CHAR_T *name, size_t nlen, CHAR_T *input, size_t ilen,
35 CHAR_T *output, size_t olen, seq_t stype, int flags)
36 {
37 CHAR_T *p;
38 SEQ *lastqp, *qp;
39 int sv_errno;
40
41 /*
42 * An input string must always be present. The output string
43 * can be NULL, when set internally, that's how we throw away
44 * input.
45 *
46 * Just replace the output field if the string already set.
47 */
48 if ((qp =
49 seq_find(sp, &lastqp, NULL, input, ilen, stype, NULL)) != NULL) {
50 if (LF_ISSET(SEQ_NOOVERWRITE))
51 return (0);
52 if (output == NULL || olen == 0) {
53 p = NULL;
54 olen = 0;
55 } else if ((p = v_wstrdup(sp, output, olen)) == NULL) {
56 sv_errno = errno;
57 goto mem1;
58 }
59 free(qp->output);
60 qp->olen = olen;
61 qp->output = p;
62 return (0);
63 }
64
65 /* Allocate and initialize SEQ structure. */
66 CALLOC(sp, qp, 1, sizeof(SEQ));
67 if (qp == NULL) {
68 sv_errno = errno;
69 goto mem1;
70 }
71
72 /* Name. */
73 if (name == NULL || nlen == 0)
74 qp->name = NULL;
75 else if ((qp->name = v_wstrdup(sp, name, nlen)) == NULL) {
76 sv_errno = errno;
77 goto mem2;
78 }
79 qp->nlen = nlen;
80
81 /* Input. */
82 if ((qp->input = v_wstrdup(sp, input, ilen)) == NULL) {
83 sv_errno = errno;
84 goto mem3;
85 }
86 qp->ilen = ilen;
87
88 /* Output. */
89 if (output == NULL) {
90 qp->output = NULL;
91 olen = 0;
92 } else if ((qp->output = v_wstrdup(sp, output, olen)) == NULL) {
93 sv_errno = errno;
94 free(qp->input);
95 mem3: free(qp->name);
96 mem2: free(qp);
97 mem1: errno = sv_errno;
98 msgq(sp, M_SYSERR, NULL);
99 return (1);
100 }
101 qp->olen = olen;
102
103 /* Type, flags. */
104 qp->stype = stype;
105 qp->flags = flags;
106
107 /* Link into the chain. */
108 if (lastqp == NULL) {
109 SLIST_INSERT_HEAD(sp->gp->seqq, qp, q);
110 } else {
111 SLIST_INSERT_AFTER(lastqp, qp, q);
112 }
113
114 /* Set the fast lookup bit. */
115 if ((qp->input[0] & ~MAX_BIT_SEQ) == 0)
116 bit_set(sp->gp->seqb, qp->input[0]);
117
118 return (0);
119 }
120
121 /*
122 * seq_delete --
123 * Delete a sequence.
124 *
125 * PUBLIC: int seq_delete(SCR *, CHAR_T *, size_t, seq_t);
126 */
127 int
seq_delete(SCR * sp,CHAR_T * input,size_t ilen,seq_t stype)128 seq_delete(SCR *sp, CHAR_T *input, size_t ilen, seq_t stype)
129 {
130 SEQ *qp, *pre_qp = NULL;
131 int diff;
132
133 SLIST_FOREACH(qp, sp->gp->seqq, q) {
134 if (qp->stype == stype && qp->ilen == ilen) {
135 diff = MEMCMP(qp->input, input, ilen);
136 if (!diff) {
137 if (F_ISSET(qp, SEQ_FUNCMAP))
138 break;
139 if (qp == SLIST_FIRST(sp->gp->seqq))
140 SLIST_REMOVE_HEAD(sp->gp->seqq, q);
141 else
142 SLIST_REMOVE_AFTER(pre_qp, q);
143 return (seq_free(qp));
144 }
145 if (diff > 0)
146 break;
147 }
148 pre_qp = qp;
149 }
150 return (1);
151 }
152
153 /*
154 * seq_free --
155 * Free a map entry.
156 *
157 * PUBLIC: int seq_free(SEQ *);
158 */
159 int
seq_free(SEQ * qp)160 seq_free(SEQ *qp)
161 {
162 free(qp->name);
163 free(qp->input);
164 free(qp->output);
165 free(qp);
166 return (0);
167 }
168
169 /*
170 * seq_find --
171 * Search the sequence list for a match to a buffer, if ispartial
172 * isn't NULL, partial matches count.
173 *
174 * PUBLIC: SEQ *seq_find
175 * PUBLIC: (SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *);
176 */
177 SEQ *
seq_find(SCR * sp,SEQ ** lastqp,EVENT * e_input,CHAR_T * c_input,size_t ilen,seq_t stype,int * ispartialp)178 seq_find(SCR *sp, SEQ **lastqp, EVENT *e_input, CHAR_T *c_input, size_t ilen,
179 seq_t stype, int *ispartialp)
180 {
181 SEQ *lqp = NULL, *qp;
182 int diff;
183
184 /*
185 * Ispartialp is a location where we return if there was a
186 * partial match, i.e. if the string were extended it might
187 * match something.
188 *
189 * XXX
190 * Overload the meaning of ispartialp; only the terminal key
191 * search doesn't want the search limited to complete matches,
192 * i.e. ilen may be longer than the match.
193 */
194 if (ispartialp != NULL)
195 *ispartialp = 0;
196 for (qp = SLIST_FIRST(sp->gp->seqq); qp != NULL;
197 lqp = qp, qp = SLIST_NEXT(qp, q)) {
198 /*
199 * Fast checks on the first character and type, and then
200 * a real comparison.
201 */
202 if (e_input == NULL) {
203 if (qp->input[0] > c_input[0])
204 break;
205 if (qp->input[0] < c_input[0] ||
206 qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
207 continue;
208 diff = MEMCMP(qp->input, c_input, MIN(qp->ilen, ilen));
209 } else {
210 if (qp->input[0] > e_input->e_c)
211 break;
212 if (qp->input[0] < e_input->e_c ||
213 qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
214 continue;
215 diff =
216 e_memcmp(qp->input, e_input, MIN(qp->ilen, ilen));
217 }
218 if (diff > 0)
219 break;
220 if (diff < 0)
221 continue;
222 /*
223 * If the entry is the same length as the string, return a
224 * match. If the entry is shorter than the string, return a
225 * match if called from the terminal key routine. Otherwise,
226 * keep searching for a complete match.
227 */
228 if (qp->ilen <= ilen) {
229 if (qp->ilen == ilen || ispartialp != NULL) {
230 if (lastqp != NULL)
231 *lastqp = lqp;
232 return (qp);
233 }
234 continue;
235 }
236 /*
237 * If the entry longer than the string, return partial match
238 * if called from the terminal key routine. Otherwise, no
239 * match.
240 */
241 if (ispartialp != NULL)
242 *ispartialp = 1;
243 break;
244 }
245 if (lastqp != NULL)
246 *lastqp = lqp;
247 return (NULL);
248 }
249
250 /*
251 * seq_close --
252 * Discard all sequences.
253 *
254 * PUBLIC: void seq_close(GS *);
255 */
256 void
seq_close(GS * gp)257 seq_close(GS *gp)
258 {
259 SEQ *qp;
260
261 while ((qp = SLIST_FIRST(gp->seqq)) != NULL) {
262 SLIST_REMOVE_HEAD(gp->seqq, q);
263 (void)seq_free(qp);
264 }
265 }
266
267 /*
268 * seq_dump --
269 * Display the sequence entries of a specified type.
270 *
271 * PUBLIC: int seq_dump(SCR *, seq_t, int);
272 */
273 int
seq_dump(SCR * sp,seq_t stype,int isname)274 seq_dump(SCR *sp, seq_t stype, int isname)
275 {
276 CHAR_T *p;
277 GS *gp;
278 SEQ *qp;
279 int cnt, len, olen;
280
281 cnt = 0;
282 gp = sp->gp;
283 SLIST_FOREACH(qp, sp->gp->seqq, q) {
284 if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP))
285 continue;
286 ++cnt;
287 for (p = qp->input,
288 olen = qp->ilen, len = 0; olen > 0; --olen, ++p)
289 len += ex_puts(sp, KEY_NAME(sp, *p));
290 for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
291 len -= ex_puts(sp, " ");
292
293 if (qp->output != NULL)
294 for (p = qp->output,
295 olen = qp->olen, len = 0; olen > 0; --olen, ++p)
296 len += ex_puts(sp, KEY_NAME(sp, *p));
297 else
298 len = 0;
299
300 if (isname && qp->name != NULL) {
301 for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
302 len -= ex_puts(sp, " ");
303 for (p = qp->name,
304 olen = qp->nlen; olen > 0; --olen, ++p)
305 (void)ex_puts(sp, KEY_NAME(sp, *p));
306 }
307 (void)ex_puts(sp, "\n");
308 }
309 return (cnt);
310 }
311
312 /*
313 * seq_save --
314 * Save the sequence entries to a file.
315 *
316 * PUBLIC: int seq_save(SCR *, FILE *, char *, seq_t);
317 */
318 int
seq_save(SCR * sp,FILE * fp,char * prefix,seq_t stype)319 seq_save(SCR *sp, FILE *fp, char *prefix, seq_t stype)
320 {
321 CHAR_T *p;
322 SEQ *qp;
323 size_t olen;
324 int ch;
325
326 /* Write a sequence command for all keys the user defined. */
327 SLIST_FOREACH(qp, sp->gp->seqq, q) {
328 if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF))
329 continue;
330 if (prefix)
331 (void)fprintf(fp, "%s", prefix);
332 for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
333 ch = *p++;
334 if (ch == CH_LITERAL || ch == '|' ||
335 cmdskip(ch) || KEY_VAL(sp, ch) == K_NL)
336 (void)putc(CH_LITERAL, fp);
337 (void)putc(ch, fp);
338 }
339 (void)putc(' ', fp);
340 if (qp->output != NULL)
341 for (p = qp->output,
342 olen = qp->olen; olen > 0; --olen) {
343 ch = *p++;
344 if (ch == CH_LITERAL || ch == '|' ||
345 KEY_VAL(sp, ch) == K_NL)
346 (void)putc(CH_LITERAL, fp);
347 (void)putc(ch, fp);
348 }
349 (void)putc('\n', fp);
350 }
351 return (0);
352 }
353
354 /*
355 * e_memcmp --
356 * Compare a string of EVENT's to a string of CHAR_T's.
357 *
358 * PUBLIC: int e_memcmp(CHAR_T *, EVENT *, size_t);
359 */
360 int
e_memcmp(CHAR_T * p1,EVENT * ep,size_t n)361 e_memcmp(CHAR_T *p1, EVENT *ep, size_t n)
362 {
363 if (n != 0) {
364 do {
365 if (*p1++ != ep->e_c)
366 return (*--p1 - ep->e_c);
367 ++ep;
368 } while (--n != 0);
369 }
370 return (0);
371 }
372