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