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