seq.c revision 1.2 1 1.2 christos /* $NetBSD: seq.c,v 1.2 2013/11/22 15:52:05 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.1 christos for (lqp = NULL, qp = sp->gp->seqq.lh_first;
188 1.1 christos qp != NULL; lqp = qp, qp = qp->q.le_next) {
189 1.1 christos /*
190 1.1 christos * Fast checks on the first character and type, and then
191 1.1 christos * a real comparison.
192 1.1 christos */
193 1.1 christos if (e_input == NULL) {
194 1.1 christos if (qp->input[0] > c_input[0])
195 1.1 christos break;
196 1.1 christos if (qp->input[0] < c_input[0] ||
197 1.1 christos qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
198 1.1 christos continue;
199 1.1 christos diff = MEMCMP(qp->input, c_input, MIN(qp->ilen, ilen));
200 1.1 christos } else {
201 1.1 christos if (qp->input[0] > e_input->e_c)
202 1.1 christos break;
203 1.1 christos if (qp->input[0] < e_input->e_c ||
204 1.1 christos qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
205 1.1 christos continue;
206 1.1 christos diff =
207 1.1 christos e_memcmp(qp->input, e_input, MIN(qp->ilen, ilen));
208 1.1 christos }
209 1.1 christos if (diff > 0)
210 1.1 christos break;
211 1.1 christos if (diff < 0)
212 1.1 christos continue;
213 1.1 christos /*
214 1.1 christos * If the entry is the same length as the string, return a
215 1.1 christos * match. If the entry is shorter than the string, return a
216 1.1 christos * match if called from the terminal key routine. Otherwise,
217 1.1 christos * keep searching for a complete match.
218 1.1 christos */
219 1.1 christos if (qp->ilen <= ilen) {
220 1.1 christos if (qp->ilen == ilen || ispartialp != NULL) {
221 1.1 christos if (lastqp != NULL)
222 1.1 christos *lastqp = lqp;
223 1.1 christos return (qp);
224 1.1 christos }
225 1.1 christos continue;
226 1.1 christos }
227 1.1 christos /*
228 1.1 christos * If the entry longer than the string, return partial match
229 1.1 christos * if called from the terminal key routine. Otherwise, no
230 1.1 christos * match.
231 1.1 christos */
232 1.1 christos if (ispartialp != NULL)
233 1.1 christos *ispartialp = 1;
234 1.1 christos break;
235 1.1 christos }
236 1.1 christos if (lastqp != NULL)
237 1.1 christos *lastqp = lqp;
238 1.1 christos return (NULL);
239 1.1 christos }
240 1.1 christos
241 1.1 christos /*
242 1.1 christos * seq_close --
243 1.1 christos * Discard all sequences.
244 1.1 christos *
245 1.1 christos * PUBLIC: void seq_close __P((GS *));
246 1.1 christos */
247 1.1 christos void
248 1.1 christos seq_close(GS *gp)
249 1.1 christos {
250 1.1 christos SEQ *qp;
251 1.1 christos
252 1.1 christos while ((qp = gp->seqq.lh_first) != NULL) {
253 1.1 christos if (qp->name != NULL)
254 1.1 christos free(qp->name);
255 1.1 christos if (qp->input != NULL)
256 1.1 christos free(qp->input);
257 1.1 christos if (qp->output != NULL)
258 1.1 christos free(qp->output);
259 1.1 christos LIST_REMOVE(qp, q);
260 1.1 christos free(qp);
261 1.1 christos }
262 1.1 christos }
263 1.1 christos
264 1.1 christos /*
265 1.1 christos * seq_dump --
266 1.1 christos * Display the sequence entries of a specified type.
267 1.1 christos *
268 1.1 christos * PUBLIC: int seq_dump __P((SCR *, seq_t, int));
269 1.1 christos */
270 1.1 christos int
271 1.1 christos seq_dump(SCR *sp, seq_t stype, int isname)
272 1.1 christos {
273 1.1 christos CHAR_T *p;
274 1.1 christos GS *gp;
275 1.1 christos SEQ *qp;
276 1.1 christos int cnt, len, olen;
277 1.1 christos
278 1.1 christos cnt = 0;
279 1.1 christos gp = sp->gp;
280 1.1 christos for (qp = gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
281 1.1 christos if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP))
282 1.1 christos continue;
283 1.1 christos ++cnt;
284 1.1 christos for (p = qp->input,
285 1.1 christos olen = qp->ilen, len = 0; olen > 0; --olen, ++p)
286 1.2 christos len += ex_puts(sp, (char *)KEY_NAME(sp, *p));
287 1.1 christos for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
288 1.1 christos len -= ex_puts(sp, " ");
289 1.1 christos
290 1.1 christos if (qp->output != NULL)
291 1.1 christos for (p = qp->output,
292 1.1 christos olen = qp->olen, len = 0; olen > 0; --olen, ++p)
293 1.2 christos len += ex_puts(sp, (char *)KEY_NAME(sp, *p));
294 1.1 christos else
295 1.1 christos len = 0;
296 1.1 christos
297 1.1 christos if (isname && qp->name != NULL) {
298 1.1 christos for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
299 1.1 christos len -= ex_puts(sp, " ");
300 1.1 christos for (p = qp->name,
301 1.1 christos olen = qp->nlen; olen > 0; --olen, ++p)
302 1.2 christos (void)ex_puts(sp, (char *)KEY_NAME(sp, *p));
303 1.1 christos }
304 1.1 christos (void)ex_puts(sp, "\n");
305 1.1 christos }
306 1.1 christos return (cnt);
307 1.1 christos }
308 1.1 christos
309 1.1 christos /*
310 1.1 christos * seq_save --
311 1.1 christos * Save the sequence entries to a file.
312 1.1 christos *
313 1.2 christos * PUBLIC: int seq_save __P((SCR *, FILE *, const char *, seq_t));
314 1.1 christos */
315 1.1 christos int
316 1.2 christos seq_save(SCR *sp, FILE *fp, const char *prefix, seq_t stype)
317 1.1 christos {
318 1.1 christos CHAR_T *p;
319 1.1 christos SEQ *qp;
320 1.1 christos size_t olen;
321 1.2 christos ARG_CHAR_T ch;
322 1.1 christos
323 1.1 christos /* Write a sequence command for all keys the user defined. */
324 1.1 christos for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
325 1.1 christos if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF))
326 1.1 christos continue;
327 1.1 christos if (prefix)
328 1.1 christos (void)fprintf(fp, "%s", prefix);
329 1.1 christos for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
330 1.2 christos ch = (UCHAR_T)*p++;
331 1.1 christos if (ch == CH_LITERAL || ch == '|' ||
332 1.2 christos ISBLANK(ch) || KEY_VAL(sp, ch) == K_NL)
333 1.1 christos (void)putc(CH_LITERAL, fp);
334 1.2 christos (void)fprintf(fp, WC, ch);
335 1.1 christos }
336 1.1 christos (void)putc(' ', fp);
337 1.1 christos if (qp->output != NULL)
338 1.1 christos for (p = qp->output,
339 1.1 christos olen = qp->olen; olen > 0; --olen) {
340 1.2 christos ch = (UCHAR_T)*p++;
341 1.1 christos if (ch == CH_LITERAL || ch == '|' ||
342 1.1 christos KEY_VAL(sp, ch) == K_NL)
343 1.1 christos (void)putc(CH_LITERAL, fp);
344 1.2 christos (void)fprintf(fp, WC, ch);
345 1.1 christos }
346 1.1 christos (void)putc('\n', fp);
347 1.1 christos }
348 1.1 christos return (0);
349 1.1 christos }
350 1.1 christos
351 1.1 christos /*
352 1.1 christos * e_memcmp --
353 1.1 christos * Compare a string of EVENT's to a string of CHAR_T's.
354 1.1 christos *
355 1.1 christos * PUBLIC: int e_memcmp __P((CHAR_T *, EVENT *, size_t));
356 1.1 christos */
357 1.1 christos int
358 1.1 christos e_memcmp(CHAR_T *p1, EVENT *ep, size_t n)
359 1.1 christos {
360 1.1 christos if (n != 0) {
361 1.1 christos do {
362 1.1 christos if (*p1++ != ep->e_c)
363 1.1 christos return (*--p1 - ep->e_c);
364 1.1 christos ++ep;
365 1.1 christos } while (--n != 0);
366 1.1 christos }
367 1.1 christos return (0);
368 1.1 christos }
369