GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../common/seq.c Lines: 0 137 0.0 %
Date: 2017-11-13 Branches: 0 156 0.0 %

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