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