xref: /netbsd-src/usr.sbin/sysinst/txtwalk.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: txtwalk.c,v 1.1 2014/07/26 19:30:44 dholland Exp $	*/
2 
3 /*
4  * Copyright 1997 Piermont Information Systems Inc.
5  * All rights reserved.
6  *
7  * Written by Philip A. Nelson for Piermont Information Systems Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, item list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, item list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of Piermont Information Systems Inc. may not be used to endorse
18  *    or promote products derived from item software without specific prior
19  *    written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 /*
36  *	walk a text buffer, processing matched lines
37  *
38  *	Written by Philip A. Nelson.
39  *	7/29/97
40  *
41  */
42 
43 #undef DEBUG
44 
45 #include <stdio.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 
51 #include "txtwalk.h"
52 
53 /* prototypes */
54 
55 static int process(const struct lookfor *, char *);
56 static int match(char *, const struct lookfor *, size_t);
57 static int finddata(const struct lookfor *, char *, struct data *, size_t *);
58 
59 /*
60  * Walk the buffer, call match for each line.
61  */
62 int
63 walk(char *buffer, size_t size, const struct lookfor *these, size_t numthese)
64 {
65 	size_t i = 0;
66 	size_t len;
67 	int line = 1;
68 	int error;
69 
70 	while (i < size) {
71 		/* Ignore zero characters. */
72 		if (*buffer == '\0') {
73 			buffer++;
74 			i++;
75 		} else {
76 			/* Assume item starts a line. */
77 			len = 0;
78 			while (buffer[len] != '\n' && buffer[len] != '\0')
79 				len++;
80 			buffer[len] = '\0';
81 #ifdef DEBUG
82 			printf ("%5d: %s\n", line, buffer);
83 #endif
84 			error = match(buffer, these, numthese);
85 			if (error != 0)
86 				return error;
87 			buffer += len+1;
88 			i += len+1;
89 			line++;
90 		}
91 	}
92 	return 0;
93 }
94 
95 /*
96  * Match the current line with a string of interest.
97  * For each match in these, process the match.
98  */
99 static int
100 match(char *line, const struct lookfor *these, size_t numthese)
101 {
102 	size_t linelen;		/* Line length */
103 	size_t patlen;		/* Pattern length */
104 	size_t which;		/* Which pattern we are using */
105 	int error;
106 
107 	linelen = strlen(line);
108 
109 	for (which = 0; which < numthese; which++) {
110 		patlen = strlen(these[which].head);
111 		if (linelen < patlen)
112 			continue;
113 		if (strncmp(these[which].head, line, patlen) == 0) {
114 			error = process(&these[which], line);
115 			if (error != 0)
116 				return error;
117 		}
118 	}
119 	return 0;
120 }
121 
122 
123 /* process the matched line. */
124 static int
125 process(const struct lookfor *item, char *line)
126 {
127 	struct data found[MAXDATA];
128 	size_t numfound = 0;
129 	const char *p;
130 	char *np;
131 	size_t  i, j;
132 	int error;
133 
134 	if (finddata(item, line, found, &numfound)) {
135 #ifdef DEBUG
136 		printf("process: \"%s\"\n", line);
137 		for (i = 0; i < numfound; i++) {
138 			printf ("\t%d: ", i);
139 			switch (found[i].what) {
140 			case INT:
141 				printf ("%d\n", found[i].u.i_val);
142 				break;
143 			case STR:
144 				printf ("'%s'\n", found[i].u.s_val);
145 				break;
146 			}
147 		}
148 #endif
149 		/* Process the stuff. */
150 		switch (item->todo[0]) {
151 		case 'a':  /* Assign data */
152 			p = item->todo;
153 			j = 0;
154 			while (*p && *p != '$')
155 				p++;
156 			if (*p)
157 				p++;
158 			for (;;) {
159 				i = strtoul(p, &np, 10);
160 				if (p == np)
161 				    break;
162 				p = np;
163 				switch (found[i].what) {
164 				case INT:
165 					*((int *)item->var+j)
166 						= found[i].u.i_val;
167 					break;
168 				case STR:
169 					strlcpy(*((char **)item->var+j),
170 					        found[i].u.s_val,
171 						item->size);
172 					break;
173 				}
174 				while (*p && *p != '$')
175 					p++;
176 				if (*p)
177 					p++;
178 				j++;
179 				if (j >= item->nument)
180 					break;
181 			}
182 			break;
183 		case 'c':  /* Call a function with data. */
184 			error = (*item->func)(found, numfound);
185 			if (error != 0)
186 				return error;
187 			break;
188 		}
189 	}
190 	return 0;
191 }
192 
193 /*
194  * find the expected data.  Return 1 if successful, return 0 if not.
195  * Successful means running into the end of the expect string before
196  * running out of line data or encountering other bad data.
197  *
198  * Side Effect -- sets numfound and found.
199  */
200 static int
201 finddata(const struct lookfor *item, char *line, struct data *found, size_t *numfound)
202 {
203 	const char *fmt;
204 	size_t len;
205 	char *np;
206 	int i;
207 
208 	*numfound = 0;
209 	for (fmt = item->fmt; *fmt; fmt++) {
210 		if (!*line && *fmt)
211 			return 0;
212 		if (*fmt == '%') {
213 			fmt++;
214 			if (!*fmt)
215 				return 0;
216 			switch (*fmt) {
217 			case '%':  /* The char %. */
218 				if (*line != '%')
219 					return 0;
220 				line++;
221 				break;
222 			case 'i':  /* Ignore characters */
223 				if (!fmt[1])
224 					return 1;
225 				if (fmt[1] == ' ')
226 					while (*line && !isspace((unsigned char)*line))
227 						line++;
228 				else
229 					while (*line && *line != fmt[1])
230 						line++;
231 				break;
232 			case 'd':  /* Nextoken should be an integer. */
233 				i = strtoul(line, &np, 10);
234 				if (line == np)
235 					return 0;
236 				found[*numfound].what = INT;
237 				found[(*numfound)++].u.i_val = i;
238 				line = np;
239 				break;
240 			case 's':  /* Matches a 'space' separated string. */
241 				len = 0;
242 				while (line[len] && !isspace((unsigned char)line[len])
243 				    && line[len] != fmt[1])
244 					len++;
245 				found[*numfound].what = STR;
246 				found[(*numfound)++].u.s_val = line;
247 				line[len] = 0;
248 				line += len + 1;
249 				break;
250 			default:
251 				return 0;
252 			}
253 			continue;
254 
255 		}
256 		if (*fmt == ' ') {
257 			while (isspace((unsigned char)*line))
258 				line++;
259 			continue;
260 		}
261 		if (*line == *fmt) {
262 			line++;
263 			continue;
264 		}
265 		/* Mis match! */
266 		return 0;
267 	}
268 
269 	/* Ran out of fmt. */
270 	return 1;
271 }
272