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