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