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