include sys/select.h before ex/extern.h
[nvi.git] / common / seq.c
blob8a43f8a13bb1ca8feddde9a1296d31a7c77d5ab0
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.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 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 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
19 #include <bitstring.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "common.h"
30 * seq_set --
31 * Internal version to enter a sequence.
33 * PUBLIC: int seq_set __P((SCR *, CHAR_T *,
34 * PUBLIC: size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int));
36 int
37 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 CHAR_T *p;
40 SEQ *lastqp, *qp;
41 int sv_errno;
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.
48 * Just replace the output field if the string already set.
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_wstrdup(sp, output, olen)) == NULL) {
58 sv_errno = errno;
59 goto mem1;
61 if (qp->output != NULL)
62 free(qp->output);
63 qp->olen = olen;
64 qp->output = p;
65 return (0);
68 /* Allocate and initialize SEQ structure. */
69 CALLOC(sp, qp, SEQ *, 1, sizeof(SEQ));
70 if (qp == NULL) {
71 sv_errno = errno;
72 goto mem1;
75 /* Name. */
76 if (name == NULL || nlen == 0)
77 qp->name = NULL;
78 else if ((qp->name = v_wstrdup(sp, name, nlen)) == NULL) {
79 sv_errno = errno;
80 goto mem2;
82 qp->nlen = nlen;
84 /* Input. */
85 if ((qp->input = v_wstrdup(sp, input, ilen)) == NULL) {
86 sv_errno = errno;
87 goto mem3;
89 qp->ilen = ilen;
91 /* Output. */
92 if (output == NULL) {
93 qp->output = NULL;
94 olen = 0;
95 } else if ((qp->output = v_wstrdup(sp, output, olen)) == NULL) {
96 sv_errno = errno;
97 free(qp->input);
98 mem3: if (qp->name != NULL)
99 free(qp->name);
100 mem2: free(qp);
101 mem1: errno = sv_errno;
102 msgq(sp, M_SYSERR, NULL);
103 return (1);
105 qp->olen = olen;
107 /* Type, flags. */
108 qp->stype = stype;
109 qp->flags = flags;
111 /* Link into the chain. */
112 if (lastqp == NULL) {
113 LIST_INSERT_HEAD(&sp->gp->seqq, qp, q);
114 } else {
115 LIST_INSERT_AFTER(lastqp, qp, q);
118 /* Set the fast lookup bit. */
119 if ((UCHAR_T)qp->input[0] < MAX_BIT_SEQ)
120 bit_set(sp->gp->seqb, qp->input[0]);
122 return (0);
126 * seq_delete --
127 * Delete a sequence.
129 * PUBLIC: int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t));
132 seq_delete(SCR *sp, CHAR_T *input, size_t ilen, seq_t stype)
134 SEQ *qp;
136 if ((qp = seq_find(sp, NULL, NULL, input, ilen, stype, NULL)) == NULL)
137 return (1);
138 return (seq_mdel(qp));
142 * seq_mdel --
143 * Delete a map entry, without lookup.
145 * PUBLIC: int seq_mdel __P((SEQ *));
148 seq_mdel(SEQ *qp)
150 LIST_REMOVE(qp, q);
151 if (qp->name != NULL)
152 free(qp->name);
153 free(qp->input);
154 if (qp->output != NULL)
155 free(qp->output);
156 free(qp);
157 return (0);
161 * seq_find --
162 * Search the sequence list for a match to a buffer, if ispartial
163 * isn't NULL, partial matches count.
165 * PUBLIC: SEQ *seq_find
166 * PUBLIC: __P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *));
168 SEQ *
169 seq_find(SCR *sp, SEQ **lastqp, EVENT *e_input, CHAR_T *c_input, size_t ilen, seq_t stype, int *ispartialp)
171 SEQ *lqp, *qp;
172 int diff;
175 * Ispartialp is a location where we return if there was a
176 * partial match, i.e. if the string were extended it might
177 * match something.
179 * XXX
180 * Overload the meaning of ispartialp; only the terminal key
181 * search doesn't want the search limited to complete matches,
182 * i.e. ilen may be longer than the match.
184 if (ispartialp != NULL)
185 *ispartialp = 0;
186 for (lqp = NULL, qp = sp->gp->seqq.lh_first;
187 qp != NULL; lqp = qp, qp = qp->q.le_next) {
189 * Fast checks on the first character and type, and then
190 * a real comparison.
192 if (e_input == NULL) {
193 if (qp->input[0] > c_input[0])
194 break;
195 if (qp->input[0] < c_input[0] ||
196 qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
197 continue;
198 diff = MEMCMP(qp->input, c_input, MIN(qp->ilen, ilen));
199 } else {
200 if (qp->input[0] > e_input->e_c)
201 break;
202 if (qp->input[0] < e_input->e_c ||
203 qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
204 continue;
205 diff =
206 e_memcmp(qp->input, e_input, MIN(qp->ilen, ilen));
208 if (diff > 0)
209 break;
210 if (diff < 0)
211 continue;
213 * If the entry is the same length as the string, return a
214 * match. If the entry is shorter than the string, return a
215 * match if called from the terminal key routine. Otherwise,
216 * keep searching for a complete match.
218 if (qp->ilen <= ilen) {
219 if (qp->ilen == ilen || ispartialp != NULL) {
220 if (lastqp != NULL)
221 *lastqp = lqp;
222 return (qp);
224 continue;
227 * If the entry longer than the string, return partial match
228 * if called from the terminal key routine. Otherwise, no
229 * match.
231 if (ispartialp != NULL)
232 *ispartialp = 1;
233 break;
235 if (lastqp != NULL)
236 *lastqp = lqp;
237 return (NULL);
241 * seq_close --
242 * Discard all sequences.
244 * PUBLIC: void seq_close __P((GS *));
246 void
247 seq_close(GS *gp)
249 SEQ *qp;
251 while ((qp = gp->seqq.lh_first) != NULL) {
252 if (qp->name != NULL)
253 free(qp->name);
254 if (qp->input != NULL)
255 free(qp->input);
256 if (qp->output != NULL)
257 free(qp->output);
258 LIST_REMOVE(qp, q);
259 free(qp);
264 * seq_dump --
265 * Display the sequence entries of a specified type.
267 * PUBLIC: int seq_dump __P((SCR *, seq_t, int));
270 seq_dump(SCR *sp, seq_t stype, int isname)
272 CHAR_T *p;
273 GS *gp;
274 SEQ *qp;
275 int cnt, len, olen;
277 cnt = 0;
278 gp = sp->gp;
279 for (qp = gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
280 if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP))
281 continue;
282 ++cnt;
283 for (p = qp->input,
284 olen = qp->ilen, len = 0; olen > 0; --olen, ++p)
285 len += ex_puts(sp, KEY_NAME(sp, *p));
286 for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
287 len -= ex_puts(sp, " ");
289 if (qp->output != NULL)
290 for (p = qp->output,
291 olen = qp->olen, len = 0; olen > 0; --olen, ++p)
292 len += ex_puts(sp, KEY_NAME(sp, *p));
293 else
294 len = 0;
296 if (isname && qp->name != NULL) {
297 for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
298 len -= ex_puts(sp, " ");
299 for (p = qp->name,
300 olen = qp->nlen; olen > 0; --olen, ++p)
301 (void)ex_puts(sp, KEY_NAME(sp, *p));
303 (void)ex_puts(sp, "\n");
305 return (cnt);
309 * seq_save --
310 * Save the sequence entries to a file.
312 * PUBLIC: int seq_save __P((SCR *, FILE *, char *, seq_t));
315 seq_save(SCR *sp, FILE *fp, char *prefix, seq_t stype)
317 CHAR_T *p;
318 SEQ *qp;
319 size_t olen;
320 int ch;
322 /* Write a sequence command for all keys the user defined. */
323 for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
324 if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF))
325 continue;
326 if (prefix)
327 (void)fprintf(fp, "%s", prefix);
328 for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
329 ch = *p++;
330 if (ch == CH_LITERAL || ch == '|' ||
331 isblank(ch) || KEY_VAL(sp, ch) == K_NL)
332 (void)putc(CH_LITERAL, fp);
333 (void)putc(ch, fp);
335 (void)putc(' ', fp);
336 if (qp->output != NULL)
337 for (p = qp->output,
338 olen = qp->olen; olen > 0; --olen) {
339 ch = *p++;
340 if (ch == CH_LITERAL || ch == '|' ||
341 KEY_VAL(sp, ch) == K_NL)
342 (void)putc(CH_LITERAL, fp);
343 (void)putc(ch, fp);
345 (void)putc('\n', fp);
347 return (0);
351 * e_memcmp --
352 * Compare a string of EVENT's to a string of CHAR_T's.
354 * PUBLIC: int e_memcmp __P((CHAR_T *, EVENT *, size_t));
357 e_memcmp(CHAR_T *p1, EVENT *ep, size_t n)
359 if (n != 0) {
360 do {
361 if (*p1++ != ep->e_c)
362 return (*--p1 - ep->e_c);
363 ++ep;
364 } while (--n != 0);
366 return (0);