Annotation of parser3/src/main/pa_string.C, revision 1.97
1.45 paf 1: /** @file
1.55 paf 2: Parser: string class. @see untasize_t.C.
1.46 paf 3:
1.36 paf 4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
1.46 paf 5:
1.37 paf 6: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
1.4 paf 7: */
1.97 ! parser 8: static const char *RCSId="$Id: pa_string.C,v 1.96 2001/07/24 15:43:56 parser Exp $";
1.4 paf 9:
1.48 paf 10: #include "pa_config_includes.h"
1.1 paf 11:
1.70 paf 12: #include "pcre.h"
1.82 parser 13: #include "internal.h"
1.70 paf 14:
1.13 paf 15: #include "pa_pool.h"
1.12 paf 16: #include "pa_string.h"
1.5 paf 17: #include "pa_hash.h"
1.22 paf 18: #include "pa_exception.h"
1.53 paf 19: #include "pa_common.h"
1.60 paf 20: #include "pa_array.h"
21: #include "pa_globals.h"
1.61 paf 22: #include "pa_table.h"
1.60 paf 23:
1.75 paf 24: String::String(Pool& apool, const char *src, size_t src_size, bool tainted) :
1.94 parser 25: Pooled(apool),
26: forigins_mode(false) {
1.28 paf 27: last_chunk=&head;
28: head.count=CR_PREALLOCATED_COUNT;
1.5 paf 29: append_here=head.rows;
1.2 paf 30: head.preallocated_link=0;
1.28 paf 31: link_row=&head.rows[head.count];
1.8 paf 32: fused_rows=fsize=0;
1.41 paf 33:
34: if(src)
1.75 paf 35: if(tainted)
36: APPEND_TAINTED(src, src_size, 0, 0);
1.41 paf 37: else
1.75 paf 38: APPEND_CLEAN(src, src_size, 0, 0);
1.1 paf 39: }
40:
1.94 parser 41: String::String(const String& src) :
42: Pooled(src.pool()),
43: forigins_mode(false) {
1.8 paf 44: head.count=CR_PREALLOCATED_COUNT;
45:
1.55 paf 46: size_t src_used_rows=src.fused_rows;
1.8 paf 47: if(src_used_rows<=head.count) {
1.55 paf 48: // all new rows fit size_to preallocated area
49: size_t curr_chunk_rows=head.count;
1.8 paf 50: memcpy(head.rows, src.head.rows, sizeof(Chunk::Row)*src_used_rows);
51: append_here=&head.rows[src_used_rows];
52: link_row=&head.rows[curr_chunk_rows];
53: } else {
54: // warning:
1.10 paf 55: // heavily relies on the fact
56: // "preallocated area is the same for all strings"
1.8 paf 57: //
58: // info:
59: // allocating only enough mem to fit src string rows
60: // next append would allocate a new chunk
61: //
1.55 paf 62: // new rows don't fit size_to preallocated area: splitting size_to two chunks
1.8 paf 63: // preallocated chunk src to constructing head
64: memcpy(head.rows, src.head.rows, sizeof(Chunk::Row)*head.count);
1.55 paf 65: // remaining rows size_to new_chunk
66: size_t curr_chunk_rows=src_used_rows-head.count;
1.8 paf 67: Chunk *new_chunk=static_cast<Chunk *>(
1.55 paf 68: malloc(sizeof(size_t)+sizeof(Chunk::Row)*curr_chunk_rows+sizeof(Chunk *)));
1.8 paf 69: new_chunk->count=curr_chunk_rows;
70: head.preallocated_link=new_chunk;
1.28 paf 71: append_here=link_row=&new_chunk->rows[new_chunk->count];
1.8 paf 72:
73: Chunk *old_chunk=src.head.preallocated_link;
74: Chunk::Row *new_rows=new_chunk->rows;
1.55 paf 75: size_t rows_left_to_copy=new_chunk->count;
1.8 paf 76: while(true) {
1.55 paf 77: size_t old_count=old_chunk->count;
1.8 paf 78: Chunk *next_chunk=old_chunk->rows[old_count].link;
79: if(next_chunk) {
80: // not last source chunk
81: // taking it all
82: memcpy(new_rows, old_chunk->rows, sizeof(Chunk::Row)*old_count);
83: new_rows+=old_count;
84: rows_left_to_copy-=old_count;
85:
86: old_chunk=next_chunk;
87: } else {
88: // the last source chunk
89: // taking only those rows of chunk that _left_to_copy
90: memcpy(new_rows, old_chunk->rows, sizeof(Chunk::Row)*rows_left_to_copy);
91: break;
92: }
93: }
1.5 paf 94: }
1.8 paf 95: link_row->link=0;
96: fused_rows=src_used_rows;
97: fsize=src.fsize;
1.94 parser 98: }
99:
100: void String::expand() {
101: size_t new_chunk_count=last_chunk->count+CR_GROW_COUNT;
102: last_chunk=static_cast<Chunk *>(
103: malloc(sizeof(size_t)+sizeof(Chunk::Row)*new_chunk_count+sizeof(Chunk *)));
104: last_chunk->count=new_chunk_count;
105: link_row->link=last_chunk;
106: append_here=last_chunk->rows;
107: link_row=&last_chunk->rows[last_chunk->count];
108: link_row->link=0;
1.5 paf 109: }
1.28 paf 110:
1.42 paf 111: String& String::append(const String& src, Untaint_lang lang, bool forced) {
1.60 paf 112: const Chunk *chunk=&src.head;
1.40 paf 113: do {
1.60 paf 114: const Chunk::Row *row=chunk->rows;
115: for(size_t i=0; i<chunk->count; i++, row++) {
116: if(row==src.append_here)
1.40 paf 117: goto break2;
1.60 paf 118:
119: APPEND(row->item.ptr, row->item.size,
120: (lang!=UL_PASS_APPENDED && (row->item.lang==UL_TAINTED || forced))?lang:row->item.lang,
121: row->item.origin.file, row->item.origin.line);
1.40 paf 122: }
123: chunk=row->link;
124: } while(chunk);
125: break2:
1.60 paf 126: return *this;
1.34 paf 127: }
1.60 paf 128:
1.13 paf 129: String& String::real_append(STRING_APPEND_PARAMS) {
1.9 paf 130: if(!src)
131: return *this;
1.26 paf 132: if(!size)
133: size=strlen(src);
134: if(!size)
1.9 paf 135: return *this;
136:
1.1 paf 137: if(chunk_is_full())
138: expand();
139:
140: append_here->item.ptr=src;
1.26 paf 141: fsize+=append_here->item.size=size;
1.52 paf 142: append_here->item.lang=lang;
1.13 paf 143: #ifndef NO_STRING_ORIGIN
1.14 paf 144: append_here->item.origin.file=file;
145: append_here->item.origin.line=line;
1.13 paf 146: #endif
1.8 paf 147: append_here++; fused_rows++;
1.1 paf 148:
149: return *this;
1.97 ! parser 150: }
! 151:
! 152: char String::first_char() const {
! 153: if(!fused_rows)
! 154: THROW(0, 0,
! 155: this,
! 156: "getting first char of empty string");
! 157:
! 158: return *head.rows[0].item.ptr;
1.1 paf 159: }
160:
1.16 paf 161: uint String::hash_code() const {
1.7 paf 162: uint result=0;
1.5 paf 163:
1.16 paf 164: const Chunk *chunk=&head;
1.5 paf 165: do {
1.16 paf 166: const Chunk::Row *row=chunk->rows;
1.55 paf 167: for(size_t i=0; i<chunk->count; i++) {
1.5 paf 168: if(row==append_here)
169: goto break2;
170:
1.6 paf 171: result=Hash::generic_code(result, row->item.ptr, row->item.size);
1.5 paf 172: row++;
173: }
174: chunk=row->link;
175: } while(chunk);
176: break2:
177: return result;
178: }
179:
1.60 paf 180: /// @todo move 'lang' skipping to pos
181: int String::cmp(int& partial, const String& src,
182: size_t this_offset, Untaint_lang lang) const {
1.59 paf 183: partial=-1;
1.55 paf 184: this_offset=min(this_offset, size()-1);
185:
1.16 paf 186: const Chunk *a_chunk=&head;
187: const Chunk *b_chunk=&src.head;
188: const Chunk::Row *a_row=a_chunk->rows;
189: const Chunk::Row *b_row=b_chunk->rows;
1.55 paf 190: size_t a_offset=this_offset;
191: size_t b_offset=0;
1.9 paf 192: Chunk::Row *a_end=append_here;
193: Chunk::Row *b_end=src.append_here;
1.55 paf 194: size_t a_countdown=a_chunk->count;
195: size_t b_countdown=b_chunk->count;
196: size_t result;
1.60 paf 197: size_t pos=0;
1.33 paf 198:
1.83 parser 199: bool a_break=size()==0;
1.91 parser 200: bool b_break=src.size()==0;
1.83 parser 201: if(!(a_break || b_break)) while(true) {
1.55 paf 202: if(pos+a_row->item.size > this_offset) {
1.71 paf 203: if(lang!=UL_UNSPECIFIED && a_row->item.lang!=lang)
1.60 paf 204: return -1; // wrong lang -- bail out
205:
1.55 paf 206: int size_diff=
207: (a_row->item.size-a_offset)-
208: (b_row->item.size-b_offset);
209:
210: if(size_diff==0) { // a has same size as b
1.60 paf 211: result=memcmp(a_row->item.ptr+a_offset, b_row->item.ptr+b_offset,
212: a_row->item.size-a_offset);
1.55 paf 213: if(result)
214: return result;
1.60 paf 215: pos+=a_row->item.size;
1.55 paf 216: a_row++; a_countdown--; a_offset=0;
217: b_row++; b_countdown--; b_offset=0;
218: } else if (size_diff>0) { // a longer
1.60 paf 219: result=memcmp(a_row->item.ptr+a_offset, b_row->item.ptr+b_offset,
220: b_row->item.size-b_offset);
1.55 paf 221: if(result)
222: return result;
223: a_offset+=b_row->item.size-b_offset;
224: b_row++; b_countdown--; b_offset=0;
225: } else { // b longer
1.60 paf 226: result=memcmp(a_row->item.ptr+a_offset, b_row->item.ptr+b_offset,
227: a_row->item.size-a_offset);
1.55 paf 228: if(result)
229: return result;
230: b_offset+=a_row->item.size-a_offset;
1.60 paf 231: pos+=a_row->item.size;
1.55 paf 232: a_row++; a_countdown--; a_offset=0;
233: }
1.83 parser 234: if(b_break=b_row==b_end) {
235: a_break=a_row==a_end;
236: break;
237: }
1.55 paf 238: if(!b_countdown) {
239: b_chunk=b_row->link;
240: b_row=b_chunk->rows;
241: b_countdown=b_chunk->count;
242: }
243: } else {
1.60 paf 244: a_offset-=a_row->item.size;
245: pos+=a_row->item.size;
246: a_row++; a_countdown--;
1.9 paf 247: }
248:
1.83 parser 249: if(a_break=a_row==a_end) {
250: b_break=b_row==b_end;
251: break;
252: }
1.11 paf 253: if(!a_countdown) {
1.9 paf 254: a_chunk=a_row->link;
255: a_row=a_chunk->rows;
1.11 paf 256: a_countdown=a_chunk->count;
1.9 paf 257: }
1.27 paf 258: }
1.55 paf 259: if(a_break==b_break) { // ended simultaneously
260: partial=0; return 0;
261: } else if(a_break) { // first bytes equal, but a ended before b
262: partial=1; return -1;
263: } else {
264: partial=2; return +1;
265: }
1.27 paf 266: }
267:
1.60 paf 268: /// @todo move 'lang' skipping to pos
1.59 paf 269: int String::cmp(int& partial, const char* b_ptr, size_t src_size,
1.60 paf 270: size_t this_offset, Untaint_lang lang) const {
1.59 paf 271: partial=-1;
1.50 paf 272: size_t b_size=src_size?src_size:b_ptr?strlen(b_ptr):0;
1.59 paf 273: this_offset=min(this_offset, size()-1);
1.27 paf 274:
275: const Chunk *a_chunk=&head;
276: const Chunk::Row *a_row=a_chunk->rows;
1.59 paf 277: size_t a_offset=this_offset;
1.55 paf 278: size_t b_offset=0;
1.27 paf 279: Chunk::Row *a_end=append_here;
1.55 paf 280: size_t a_countdown=a_chunk->count;
1.60 paf 281: size_t pos=0;
1.52 paf 282:
1.83 parser 283: bool a_break=size()==0;
284: bool b_break=b_size==0;
285: if(!(a_break || b_break)) while(true) {
1.59 paf 286: if(pos+a_row->item.size > this_offset) {
1.71 paf 287: if(lang!=UL_UNSPECIFIED && a_row->item.lang!=lang)
1.60 paf 288: return -1; // wrong lang -- bail out
289:
1.59 paf 290: int size_diff=
291: (a_row->item.size-a_offset)-
292: (b_size-b_offset);
293:
294: if(size_diff==0) { // a has same size as b
295: if(size_t result=memcmp(a_row->item.ptr+a_offset, b_ptr+b_offset,
296: a_row->item.size-a_offset)!=0)
297: return result;
1.60 paf 298: pos+=a_row->item.size;
1.59 paf 299: a_row++; a_countdown--; a_offset=0;
300: b_break=true;
301: } else if (size_diff>0) { // a longer
302: if(size_t result=memcmp(a_row->item.ptr+a_offset, b_ptr+b_offset,
303: b_size-b_offset)!=0)
304: return result;
305: a_offset+=b_size-b_offset;
306: b_break=true;
307: } else { // b longer
308: if(size_t result=memcmp(a_row->item.ptr+a_offset, b_ptr+b_offset,
309: a_row->item.size-a_offset)!=0)
310: return result;
311: b_offset+=a_row->item.size-a_offset;
1.60 paf 312: pos+=a_row->item.size;
1.59 paf 313: a_row++; a_countdown--; a_offset=0;
314: }
315: } else {
1.60 paf 316: a_offset-=a_row->item.size;
317: pos+=a_row->item.size;
318: a_row++; a_countdown--;
1.27 paf 319: }
320:
1.86 parser 321: a_break=a_row==a_end;
322: if(a_break || b_break)
1.83 parser 323: break;
1.27 paf 324: if(!a_countdown) {
325: a_chunk=a_row->link;
326: a_row=a_chunk->rows;
327: a_countdown=a_chunk->count;
1.9 paf 328: }
329: }
1.55 paf 330: if(a_break==b_break) { // ended simultaneously
331: partial=0; return 0;
332: } else if(a_break) { // first bytes equal, but a ended before b
333: partial=1; return -1;
334: } else {
335: partial=2; return +1;
336: }
1.5 paf 337: }
1.46 paf 338:
339: #ifndef NO_STRING_ORIGIN
340: const Origin& String::origin() const {
1.96 parser 341: if(!fused_rows) {
342: static const Origin empty_origin={"empty string"};
343: return empty_origin;
344: }
1.46 paf 345:
1.49 paf 346: // determining origin by last appended piece
1.50 paf 347: // because first one frequently constant.
348: // ex: ^load[/file] "document_root" + "/file"
1.80 paf 349: // when last peice is constant,
350: // ex: parser_root_auto_path{dynamic} / auto.p{const}
351: // using first piece
352: Origin& last_origin=append_here[-1].item.origin;
353: return last_origin.file ? last_origin : head.rows[0].item.origin;
1.46 paf 354: }
355: #endif
1.53 paf 356:
1.69 paf 357: String& String::mid(size_t start, size_t finish) const {
1.53 paf 358: start=max(0, start);
359: finish=min(size(), finish);
1.60 paf 360: if(start==finish)
361: return *empty_string;
1.53 paf 362:
363: String& result=*NEW String(pool());
364:
365: size_t pos=0;
366: const Chunk *chunk=&head;
367: do {
368: const Chunk::Row *row=chunk->rows;
1.55 paf 369: for(size_t i=0; i<chunk->count; pos+=row->item.size, i++, row++) {
1.53 paf 370: if(row==append_here)
371: goto break2;
372:
1.60 paf 373: size_t item_finish=pos+row->item.size;
374: if(item_finish > start) { // started now or already?
375: bool started=result.size()==0; // started now?
376: bool finished=finish <= item_finish; // finished now?
1.53 paf 377: size_t offset=started?start-pos:0;
378: size_t size=finished?finish-pos:row->item.size;
379: result.APPEND(
380: row->item.ptr+offset, size-offset,
381: row->item.lang,
382: row->item.origin.file, row->item.origin.line);
383: if(finished)
384: goto break2;
385: }
386: }
387: chunk=row->link;
388: } while(chunk);
389: break2:
1.60 paf 390: // SAPI::log(pool(), "piece of '%s' from %d to %d is '%s'",
391: //cstr(), start, finish, result.cstr());
1.53 paf 392: return result;
1.54 paf 393: }
394:
1.60 paf 395: int String::pos(const String& substr,
396: size_t result, Untaint_lang lang) const {
1.58 paf 397: for(; result<size(); result++) {
1.60 paf 398: int partial; cmp(partial, substr, result, lang);
1.58 paf 399: if(
400: partial==0 || // full match
401: partial==2) // 'substr' starts 'this'+'result'
402: return result;
403: }
404:
405: return -1;
406: }
407:
1.60 paf 408: int String::pos(const char *substr, size_t substr_size,
409: size_t result, Untaint_lang lang) const {
1.57 paf 410: for(; result<size(); result++) {
1.60 paf 411: int partial; cmp(partial, substr, substr_size, result, lang);
1.55 paf 412: if(
413: partial==0 || // full match
414: partial==2) // 'substr' starts 'this'+'result'
415: return result;
416: }
417:
418: return -1;
1.60 paf 419: }
420:
421: void String::split(Array& result,
422: size_t* pos_after_ref,
423: const char *delim, size_t delim_size,
424: Untaint_lang lang, int limit) const {
425: if(delim_size) {
426: size_t pos_after=pos_after_ref?*pos_after_ref:0;
427: int pos_before;
428: // while we have 'delim'...
429: for(; (pos_before=pos(delim, delim_size, pos_after, lang))>=0 && limit; limit--) {
1.69 paf 430: result+=&mid(pos_after, pos_before);
1.60 paf 431: pos_after=pos_before+delim_size;
432: }
433: // last piece
434: if(pos_after<size() && limit) {
1.69 paf 435: result+=&mid(pos_after, size());
1.60 paf 436: pos_after=size();
437: }
438: if(pos_after_ref)
439: *pos_after_ref=pos_after;
440: } else { // empty delim
441: result+=this;
442: if(pos_after_ref)
443: *pos_after_ref+=size();
444: }
445: }
446:
447: void String::split(Array& result,
448: size_t* pos_after_ref,
449: const String& delim, Untaint_lang lang,
450: int limit) const {
451: if(delim.size()) {
452: size_t pos_after=pos_after_ref?*pos_after_ref:0;
453: int pos_before;
454: // while we have 'delim'...
455: for(; (pos_before=pos(delim, pos_after, lang))>=0 && limit; limit--) {
1.69 paf 456: result+=&mid(pos_after, pos_before);
1.60 paf 457: pos_after=pos_before+delim.size();
458: }
459: // last piece
460: if(pos_after<size() && limit) {
1.69 paf 461: result+=&mid(pos_after, size());
1.60 paf 462: pos_after=size();
463: }
464: if(pos_after_ref)
465: *pos_after_ref=pos_after;
466: } else { // empty delim
467: result+=this;
468: if(pos_after_ref)
469: *pos_after_ref+=size();
470: }
1.61 paf 471: }
472:
1.63 paf 473: static void regex_options(char *options, int *result){
474: struct Regex_option {
475: char key;
476: int clear, set;
477: int *result;
478: } regex_option[]={
479: {'i', 0, PCRE_CASELESS, result}, // a=A
1.79 paf 480: {'s', 0, PCRE_DOTALL, result}, // \n\n$ [default]
1.63 paf 481: {'x', 0, PCRE_EXTENDED, result}, // whitespace in regex ignored
482: {'m', PCRE_DOTALL, PCRE_MULTILINE, result}, // ^aaa\n$^bbb\n$
483: {'g', 0, true, result+1}, // many rows
484: {0},
485: };
486: result[0]=PCRE_EXTRA | PCRE_DOTALL;
487: result[1]=0;
488:
489: if(options)
490: for(Regex_option *o=regex_option; o->key; o++)
491: if(
492: strchr(options, o->key) ||
493: strchr(options, toupper(o->key))) {
494: *(o->result)&=~o->clear;
495: *(o->result)|=o->set;
496: }
497: }
498:
1.88 parser 499: /// @todo maybe need speedup: some option to remove pre/match/post string generation
1.77 paf 500: bool String::match(const unsigned char *pcre_tables,
501: const String *aorigin,
1.62 paf 502: const String& regexp,
1.63 paf 503: const String *options,
1.64 paf 504: Table **table,
1.95 parser 505: Row_action row_action, void *info,
506: bool *was_global) const {
1.64 paf 507:
1.73 paf 508: if(!regexp.size())
509: THROW(0, 0,
510: aorigin,
511: "regexp is empty");
1.68 paf 512: const char *pattern=regexp.cstr(UL_AS_IS);
1.62 paf 513: const char *errptr;
514: int erroffset;
1.63 paf 515: int option_bits[2]; regex_options(options?options->cstr():0, option_bits);
1.95 parser 516: if(was_global)
517: *was_global=option_bits[1]!=0;
1.63 paf 518: pcre *code=pcre_compile(pattern, option_bits[0],
1.62 paf 519: &errptr, &erroffset,
1.74 paf 520: pcre_tables);
1.62 paf 521:
1.67 paf 522: if(!code)
1.62 paf 523: THROW(0, 0,
1.69 paf 524: ®exp.mid(erroffset, regexp.size()),
1.74 paf 525: "regular expression syntax error - %s", errptr);
1.62 paf 526:
1.63 paf 527: int info_substrings=pcre_info(code, 0, 0);
528: if(info_substrings<0) {
529: (*pcre_free)(code);
530: THROW(0, 0,
1.73 paf 531: aorigin,
1.76 paf 532: "pcre_info error (%d)",
1.73 paf 533: info_substrings);
1.63 paf 534: }
535:
536: int startoffset=0;
1.68 paf 537: const char *subject=cstr(UL_AS_IS);
1.62 paf 538: int length=strlen(subject);
1.63 paf 539: int ovecsize;
540: int *ovector=(int *)malloc(sizeof(int)*
1.65 paf 541: (ovecsize=(1/*match*/+info_substrings)*3));
1.62 paf 542:
1.64 paf 543: { // create table
544: Array& columns=*NEW Array(pool());
545: columns+=string_pre_match_name;
546: columns+=string_match_name;
547: columns+=string_post_match_name;
548: for(int i=1; i<=info_substrings; i++) {
549: char *column=(char *)malloc(MAX_NUMBER);
550: snprintf(column, MAX_NUMBER, "%d", i);
551: columns+=NEW String(pool(), column); // .i column name
552: }
553: *table=NEW Table(pool(), aorigin, &columns);
1.62 paf 554: }
1.63 paf 555:
1.64 paf 556: int exec_option_bits=0;
1.63 paf 557: while(true) {
558: int exec_substrings=pcre_exec(code, 0,
559: subject, length, startoffset,
1.64 paf 560: exec_option_bits, ovector, ovecsize);
1.63 paf 561:
562: if(exec_substrings==PCRE_ERROR_NOMATCH) {
563: (*pcre_free)(code);
1.67 paf 564: (*row_action)(**table, 0/*last time, no row*/, 0, 0, info);
1.63 paf 565: return option_bits[1]!=0; // global=true+table, not global=false
566: }
567:
568: if(exec_substrings<0) {
569: (*pcre_free)(code);
570: THROW(0, 0,
571: aorigin,
1.76 paf 572: "regular expression execute error (%d)",
1.63 paf 573: exec_substrings);
574: }
575:
576: Array& row=*NEW Array(pool());
1.81 paf 577: row+=&mid(0, ovector[0]); // .prematch column value
1.69 paf 578: row+=&mid(ovector[0], ovector[1]); // .match
1.81 paf 579: row+=&mid(ovector[1], size()); // .postmatch
1.63 paf 580:
581: for(int i=1; i<exec_substrings; i++) {
1.69 paf 582: // -1:-1 case handled peacefully by mid() itself
583: row+=&mid(ovector[i*2+0], ovector[i*2+1]); // .i column value
1.63 paf 584: }
585:
1.67 paf 586: (*row_action)(**table, &row, startoffset, ovector[0], info);
1.63 paf 587:
1.67 paf 588: if(!option_bits[1] || !(startoffset=ovector[1])) { // not global | going to hang
1.63 paf 589: (*pcre_free)(code);
1.67 paf 590: (*row_action)(**table, 0/*last time, no row*/, 0, 0, info);
1.63 paf 591: return true;
592: }
593:
594: /*
595: if(option_bits[0] & PCRE_MULTILINE)
1.64 paf 596: exec_option_bits|=PCRE_NOTBOL; // start of subject+startoffset not BOL
1.63 paf 597: */
598: }
1.82 parser 599: }
600:
601: String& String::change_case(Pool& pool, const unsigned char *tables,
602: Change_case_kind kind) const {
603: String& result=*new(pool) String(pool);
604:
605: const unsigned char *a;
606: const unsigned char *b;
607: switch(kind) {
608: case CC_UPPER:
609: a=tables+lcc_offset;
610: b=tables+fcc_offset;
611: break;
612: case CC_LOWER:
613: a=tables+lcc_offset;
614: b=0;
615: break;
616: default:
617: PTHROW(0, 0,
618: this,
619: "unknown change case kind #%d",
620: static_cast<int>(kind)); // never
621: a=b=0; // calm, compiler
622: break; // never
623: }
624:
625: const Chunk *chunk=&head;
626: do {
627: const Chunk::Row *row=chunk->rows;
628: for(size_t i=0; i<chunk->count; i++, row++) {
629: if(row==append_here)
630: goto break2;
631:
632: char *new_cstr=(char *)pool.malloc(row->item.size);
633: char *dest=new_cstr;
634: const char *src=row->item.ptr;
635: for(int size=row->item.size; size--; src++) {
636: unsigned char c=a[(unsigned char)*src];
637: if(b)
638: c=b[c];
639:
640: *dest++=(char)c;
641: }
642:
643: result.APPEND(new_cstr, row->item.size,
644: row->item.lang,
645: row->item.origin.file, row->item.origin.line);
646: }
647: chunk=row->link;
648: } while(chunk);
649: break2:
1.89 parser 650:
651: return result;
652: }
653:
1.90 parser 654: double String::as_double() const {
1.89 parser 655: double result;
656: const char *cstr=this->cstr();
657: char *error_pos=0;
658: // 0xABC
659: if(cstr[0]=='0' && (cstr[1]=='x' || cstr[1]=='X'))
660: result=(double)(unsigned long)strtol(cstr, &error_pos, 0);
661: else
662: result=strtod(cstr, &error_pos);
663:
664: if(error_pos && *error_pos)
665: THROW(0, 0,
666: this,
667: "invalid number (double)");
668:
669: return result;
670: }
1.90 parser 671: int String::as_int() const {
1.89 parser 672: int result;
673: const char *cstr=this->cstr();
674: char *error_pos=0;
675: // 0xABC
676: if(cstr[0]=='0' && (cstr[1]=='x' || cstr[1]=='X'))
677: result=(int)(unsigned long)strtol(cstr, &error_pos, 0);
678: else
679: result=(int)strtol(cstr, &error_pos, 0);
680:
681: if(error_pos && *error_pos)
682: THROW(0, 0,
683: this,
684: "invalid number (int)");
1.82 parser 685:
686: return result;
1.61 paf 687: }
E-mail: