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