xref: /minix/external/bsd/nvi/dist/common/seq.c (revision 0a6a1f1d)
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