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 55static int process(const struct lookfor *, char *); 56static int match(char *, const struct lookfor *, size_t); 57static int finddata(const struct lookfor *, char *, struct data *, size_t *); 58 59/* 60 * Walk the buffer, call match for each line. 61 */ 62int 63walk(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 */ 99static int 100match(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. */ 124static int 125process(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 */ 200static int 201finddata(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