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