1 /* $NetBSD: txtwalk.c,v 1.5 2021/01/31 22:45:47 rillig 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
walk(char * buffer,size_t size,const struct lookfor * these,size_t numthese)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
match(char * line,const struct lookfor * these,size_t numthese)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
process(const struct lookfor * item,char * line)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, item);
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
finddata(const struct lookfor * item,char * line,struct data * found,size_t * numfound)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]
243 && !isspace((unsigned char)line[len])
244 && line[len] != fmt[1]) {
245 if (line[len] == '\\'
246 && line[len+1] != 0)
247 len++;
248 len++;
249 }
250 found[*numfound].what = STR;
251 found[(*numfound)++].u.s_val = line;
252 line[len] = 0;
253 line += len + 1;
254 break;
255 default:
256 return 0;
257 }
258 continue;
259
260 }
261 if (*fmt == ' ') {
262 while (isspace((unsigned char)*line))
263 line++;
264 continue;
265 }
266 if (*line == *fmt) {
267 line++;
268 continue;
269 }
270 /* Mis match! */
271 return 0;
272 }
273
274 /* Ran out of fmt. */
275 return 1;
276 }
277