1 /*
2 	seek.cc		Char Seek Functions
3 	Copyright (c) 1996-8,2000-2,2004 Kriang Lerdsuwanakij
4 	email:		lerdsuwa@users.sourceforge.net
5 
6 	This program is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 2 of the License, or
9 	(at your option) any later version.
10 
11 	This program is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	You should have received a copy of the GNU General Public License
17 	along with this program; if not, write to the Free Software
18 	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 
21 #include "seek.h"
22 #include "cxxlib.h"
23 #include "strmisc.h"
24 
25 /*
26 	Case-sensitive search with escapes and quotes skipped
27 	Returns:	position (always >= 0) if found
28 */
SeekCharIgnoreEscape(char c,const char * buffer,size_t from,size_t length)29 size_t	SeekCharIgnoreEscape(char c, const char *buffer, size_t from, size_t length)
30 {
31 	while (from < length) {
32 		if (buffer[from] == '\\') {
33 					// `\' Escape found
34 
35 			from++;
36 
37 					// Unexpected end of buffer
38 			if (from >= length)
39 				throw ErrorSeek();
40 
41 					// Seek for a `\' and found `\'
42 			if (buffer[from] == '\\' && c == '\\')
43 				return from;		// Return position of
44 							// the last `\'
45 
46 			from++;		// Skip it !
47 		}
48 		else if (buffer[from] == c) {
49 			return from;	// Return index where c is found
50 		}
51 		else {
52 					// Check for opening quotes
53 
54 			switch(buffer[from]) {
55 				case '\"':
56 						// Get position of closing quote
57 
58 					from = SeekCharIgnoreEscape('\"', buffer, from+1,
59 							length);
60 					break;
61 				case '\'':
62 						// Get position of closing quote
63 
64 					from = SeekCharIgnoreEscape('\'', buffer, from+1,
65 							length);
66 					break;
67 				case '`':
68 						// Get position of closing quote
69 
70 					from = SeekCharIgnoreEscape('`', buffer, from+1,
71 							length);
72 					break;
73 			}
74 
75 			from++;		// Skip ordinary char and
76 					// closing quotes
77 		}
78 	}
79 					// Not found
80 	throw ErrorSeek();
81 }
82 
83 
84 /*
85 	Case-sensitive search
86 	nest = 0 no escapes & quotes interpretation
87 	       1 with quotes skipped (quotes can only nested once)
88 	       2 with escapes and quotes skipped (quotes can only nested once)
89 	Returns:	position (always >= 0) if found
90 */
SeekChar(char c,const char * buffer,size_t from,size_t length,int nest)91 size_t	SeekChar(char c, const char *buffer, size_t from, size_t length, int nest)
92 {
93 	if (nest == 2)
94 		return SeekCharIgnoreEscape(c, buffer, from, length);
95 
96 	while (from < length) {
97 		if (buffer[from] == c) {
98 			return from;	// Return index where c is found
99 		}
100 		else if (nest) {
101 					// Check for openning quotes
102 
103 			switch(buffer[from]) {
104 				case '\"':
105 						// Get position of closing quote
106 
107 					from = SeekChar('\"', buffer, from+1,
108 							length);
109 					break;
110 				case '\'':
111 						// Get position of closing quote
112 
113 					from = SeekChar('\'', buffer, from+1,
114 							length);
115 					break;
116 				case '`':
117 						// Get position of closing quote
118 
119 					from = SeekChar('`', buffer, from+1,
120 							length);
121 					break;
122 			}
123 			from++;		// Skip ordinary char and
124 					// closing quotes
125 		}
126 		else
127 			from++;
128 	}
129 					// Not found
130 	throw ErrorSeek();
131 }
132 
133 /*
134 	Case-insensitive search with escapes and quotes skipped
135 	Returns:	position (always >= 0) if found
136 */
SeekCaseCharIgnoreEscape(char c,const char * buffer,size_t from,size_t length)137 size_t	SeekCaseCharIgnoreEscape(char c, const char *buffer, size_t from, size_t length)
138 {
139 	c = toupper(c);
140 	while (from < length) {
141 		if (buffer[from] == '\\') {
142 					// `\' Escape found
143 
144 			from++;
145 
146 					// Unexpected end of buffer
147 			if (from >= length)
148 				throw ErrorSeek();
149 
150 					// Seek for a `\' and found `\'
151 			if (buffer[from] == '\\' && c == '\\')
152 				return from;		// Return position of
153 							// the last `\'
154 
155 			from++;		// Skip it !
156 		}
157 		else if (toupper(buffer[from]) == c) {
158 			return from;	// Return index where c is found
159 		}
160 		else {
161 					// Check for opening quotes
162 
163 			switch(buffer[from]) {
164 				case '\"':
165 						// Get position of closing quote
166 
167 					from = SeekCaseCharIgnoreEscape('\"', buffer, from+1,
168 							length);
169 					break;
170 				case '\'':
171 						// Get position of closing quote
172 
173 					from = SeekCaseCharIgnoreEscape('\'', buffer, from+1,
174 							length);
175 					break;
176 				case '`':
177 						// Get position of closing quote
178 
179 					from = SeekCaseCharIgnoreEscape('`', buffer, from+1,
180 							length);
181 					break;
182 			}
183 
184 			from++;		// Skip ordinary char and
185 					// closing quotes
186 		}
187 	}
188 					// Not found
189 	throw ErrorSeek();
190 }
191 
192 
193 /*
194 	Case-insensitive search
195 	nest = 0 no escapes & quotes interpretation
196 	       1 with quotes skipped (quotes can only nested once)
197 	       2 with escapes and quotes skipped (quotes can only nested once)
198 	Returns:	position (always >= 0) if found
199 */
SeekCaseChar(char c,const char * buffer,size_t from,size_t length,int nest)200 size_t	SeekCaseChar(char c, const char *buffer, size_t from, size_t length, int nest)
201 {
202 	c = toupper(c);
203 	if (nest == 2)
204 		return SeekCaseCharIgnoreEscape(c, buffer, from, length);
205 
206 	while (from < length) {
207 		if (toupper(buffer[from]) == c) {
208 			return from;	// Return index where c is found
209 		}
210 		else if (nest) {
211 					// Check for openning quotes
212 
213 			switch(buffer[from]) {
214 				case '\"':
215 						// Get position of closing quote
216 
217 					from = SeekCaseChar('\"', buffer, from+1,
218 							length);
219 					break;
220 				case '\'':
221 						// Get position of closing quote
222 
223 					from = SeekCaseChar('\'', buffer, from+1,
224 							length);
225 					break;
226 				case '`':
227 						// Get position of closing quote
228 
229 					from = SeekCaseChar('`', buffer, from+1,
230 							length);
231 					break;
232 			}
233 			from++;		// Skip ordinary char and
234 					// closing quotes
235 		}
236 		else
237 			from++;
238 	}
239 					// Not found
240 	throw ErrorSeek();
241 }
242 
243 /*
244 	SeekString - Find str in buffer[from]...buffer[length-1]
245 	str cannot contain any quote or escape
246 	Returns:	position (always >= 0) if found
247 */
248 
SeekString(const char * str,const char * buffer,size_t from,size_t length,int nest)249 size_t	SeekString(const char *str, const char *buffer, size_t from, size_t length, int nest)
250 {
251 	size_t	ret;
252 	size_t	len = strlen(str);
253 	for ( ; ; ) {
254 					// Seek for the first char of the
255 					// string
256 
257 		ret = SeekChar(str[0], buffer, from, length, nest);
258 		if (ret+len <= length) {
259 			if (strncmp(buffer+ret, str, len) == 0)	// Found
260 				return ret;
261 			from = ret+1;	// Seek from next byte
262 		}
263 	}
264 }
265 
266 /*
267 	SeekCaseString - Find str in buffer[from]...buffer[length-1]
268 			(case-insensitive)
269 	str cannot contain any quote or escape
270 	Returns:	position (always >= 0) if found
271 */
272 
SeekCaseString(const char * str,const char * buffer,size_t from,size_t length,int nest)273 size_t	SeekCaseString(const char *str, const char *buffer, size_t from, size_t length, int nest)
274 {
275 	size_t	ret;
276 	size_t	len = strlen(str);
277 	for ( ; ; ) {
278 
279 				// Chars does not have upper/lower case
280 				// representations
281 		if (toupper(str[0]) == tolower(str[0])) {
282 			ret = SeekChar(str[0], buffer, from, length, nest);
283 		}
284 		else {
285 			ret = SeekCaseChar(str[0], buffer, from, length, nest);
286 		}
287 		if (ret+len <= length) {
288 			if (CompareStringCase(buffer+ret, str, len) == 0)	// Found
289 				return ret;
290 			from = ret+1;	// Seek from next byte
291 		}
292 	}
293 }
294 
295 /*
296 	SeekTokenEnd - Return the first position from buffer[from] that
297 			separates/ends tokens inside HTML tags.
298 			<xxx aaa=bbb ccc=ddd>
299 	Returns:	position (always >= 0) if found
300 */
301 
SeekTokenEnd(const char * buffer,size_t from,size_t length)302 size_t	SeekTokenEnd(const char *buffer, size_t from, size_t length)
303 {
304 	while (from < length) {
305 		if (buffer[from] == ' ' || buffer[from] == '=' ||
306 		    buffer[from] == '>' || buffer[from] == '\n' ||
307 		    buffer[from] == '\r' || buffer[from] == '\t')
308 			return from;
309 		from++;
310 	}
311 					// Not found
312 	throw ErrorSeek();
313 }
314 
315 /*
316 	SeekConfigTokenEnd - Return the first position from buffer[from] that
317 			     separates/ends tokens inside configuration file.
318 	Returns:	position (always >= 0)
319 */
320 
SeekConfigTokenEnd(const char * buffer,size_t from,size_t length)321 size_t	SeekConfigTokenEnd(const char *buffer, size_t from, size_t length)
322 {
323 	while (from < length) {
324 		if (buffer[from] == ' ' || buffer[from] == ',' ||
325 		    buffer[from] == '=' || buffer[from] == '\n' ||
326 		    buffer[from] == '\r' || buffer[from] == '\t')
327 			return from;
328 		from++;
329 	}
330 	return from;
331 }
332 
333 /*
334 	SeekNonSpace - Return the first position from buffer[from] that is
335 			not spaces.
336 	Returns:	position (always >= 0) if found
337 */
338 
SeekNonSpace(const char * buffer,size_t from,size_t length)339 size_t	SeekNonSpace(const char *buffer, size_t from, size_t length)
340 {
341 	while (from < length) {
342 		if (buffer[from] != ' ' && buffer[from] != '\t' &&
343 		    buffer[from] != '\n' && buffer[from] != '\r')
344 			return from;
345 		from++;
346 	}
347 					// Not found
348 	return from;
349 }
350 
351 /*
352 	SeekPastEqualSign - Skip spaces, `=' and then spaces
353 	Returns:	position (always >= 0) if found
354 */
355 
SeekPastEqualSign(const char * buffer,size_t from,size_t length)356 size_t	SeekPastEqualSign(const char *buffer, size_t from, size_t length)
357 {
358 	from = SeekNonSpace(buffer, from, length);	// Skip spaces
359 
360 	if (buffer[from] != '=')			// Check for a `='
361 		throw ErrorSeek();
362 	from++;						// Next char
363 
364 	return SeekNonSpace(buffer, from, length);	// Skip spaces
365 }
366 
367 /*
368 	IsEmpty - Check if buffer contains solely spaces and tabs
369 	Returns:	true  buffer empty
370 			false buffer not empty
371 */
372 
IsEmpty(const char * buffer,size_t from,size_t length)373 bool	IsEmpty(const char *buffer, size_t from, size_t length)
374 {
375 	for (size_t i = from; i < length; i++) {
376 		if (buffer[i] != ' ' && buffer[i] != '\t')
377 			return false;
378 	}
379 	return true;
380 }
381