1 /* $Id$ */
2 /*
3 * Copyright (c) 1990-1996 Sam Leffler
4 * Copyright (c) 1991-1996 Silicon Graphics, Inc.
5 * HylaFAX is a trademark of Silicon Graphics
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that (i) the above copyright notices and this permission notice appear in
10 * all copies of the software and related documentation, and (ii) the names of
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or
12 * publicity relating to the software without the specific, prior written
13 * permission of Sam Leffler and Silicon Graphics.
14 *
15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18 *
19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 */
26 #include "Str.h"
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <stdarg.h>
30 #include <errno.h>
31
32 #define DEFAULT_FORMAT_BUFFER 4096
33
34 char fxStr::emptyString = '\0';
35 fxStr fxStr::null;
36
fxStr(u_int l)37 fxStr::fxStr(u_int l)
38 {
39 slength = l+1;
40 if (l>0) {
41 data = (char*) malloc(slength);
42 memset(data,0,slength);
43 } else
44 data = &emptyString;
45 }
46
fxStr(const char * s)47 fxStr::fxStr(const char *s)
48 {
49 u_int l = strlen(s)+1;
50 if (l>1) {
51 data = (char*) malloc(l);
52 memcpy(data,s,l);
53 } else {
54 data = &emptyString;
55 }
56 slength = l;
57 }
58
fxStr(const char * s,u_int len)59 fxStr::fxStr(const char *s, u_int len)
60 {
61 if (len>0) {
62 data = (char*) malloc(len+1);
63 memcpy(data,s,len);
64 data[len] = 0;
65 } else
66 data = &emptyString;
67 slength = len+1;
68 }
69
fxStr(const fxStr & s)70 fxStr::fxStr(const fxStr& s)
71 {
72 slength = s.slength;
73 if (slength > 1) {
74 data = (char*) malloc(slength);
75 memcpy(data,s.data,slength);
76 } else {
77 data = &emptyString;
78 }
79 }
80
fxStr(const fxTempStr & t)81 fxStr::fxStr(const fxTempStr& t)
82 {
83 slength = t.slength;
84 if (t.slength>1) {
85 data = (char*) malloc(slength);
86 memcpy(data,t.data,slength);
87 } else {
88 data = &emptyString;
89 }
90 }
91
fxStr(int a,const char * format)92 fxStr::fxStr(int a, const char * format)
93 {
94 fxStr s = fxStr::format((format) ? format : "%d", a);
95 slength = s.slength;
96 if (slength > 1) {
97 data = (char*) malloc(slength);
98 memcpy(data, s.data, slength);
99 } else {
100 data = &emptyString;
101 }
102 }
103
fxStr(long a,const char * format)104 fxStr::fxStr(long a, const char * format)
105 {
106 fxStr s = fxStr::format((format) ? format : "%ld", a);
107 slength = s.slength;
108 if (slength > 1) {
109 data = (char*) malloc(slength);
110 memcpy(data, s.data, slength);
111 } else {
112 data = &emptyString;
113 }
114 }
115
fxStr(float a,const char * format)116 fxStr::fxStr(float a, const char * format)
117 {
118 fxStr s = fxStr::format((format) ? format : "%g", a);
119 slength = s.slength;
120 if (slength > 1) {
121 data = (char*) malloc(slength);
122 memcpy(data, s.data, slength);
123 } else {
124 data = &emptyString;
125 }
126 }
127
fxStr(double a,const char * format)128 fxStr::fxStr(double a, const char * format)
129 {
130 fxStr s = fxStr::format((format) ? format : "%lg", a);
131 slength = s.slength;
132 if (slength > 1) {
133 data = (char*) malloc(slength);
134 memcpy(data, s.data, slength);
135 } else {
136 data = &emptyString;
137 }
138 }
139
~fxStr()140 fxStr::~fxStr()
141 {
142 assert(data);
143 if (data != &emptyString) free(data);
144 }
145
146 fxStr
format(const char * fmt...)147 fxStr::format(const char* fmt ...)
148 {
149 int size = DEFAULT_FORMAT_BUFFER;
150 fxStr s;
151 va_list ap;
152 va_start(ap, fmt);
153 s.data = (char*)malloc(size);
154 int len = vsnprintf(s.data, size, fmt, ap);
155 va_end(ap);
156 while (len < 0 || len >= size) {
157 if (len < 0 && errno != 0)
158 return s;
159 if (len >= size) {
160 size = len + 1;
161 } else {
162 size *= 2;
163 }
164 s.data = (char*)realloc(s.data, size);
165 va_start(ap, fmt);
166 len = vsnprintf(s.data, size, fmt, ap);
167 va_end(ap);
168 }
169 if (size > len + 1) {
170 s.data = (char*) realloc(s.data, len + 1);
171 }
172 s.slength = len + 1;
173 return s; //XXX this is return by value which is inefficient
174 }
175
176 fxStr
vformat(const char * fmt,va_list ap)177 fxStr::vformat(const char* fmt, va_list ap)
178 {
179 //XXX can truncate but cant do much about it without va_copy
180 int size = DEFAULT_FORMAT_BUFFER;
181 fxStr s;
182 char* tmp = NULL;
183
184 int len = 0;
185
186 do
187 {
188 if (len)
189 size *= 2;
190 tmp = (char*)realloc(tmp, size);
191 va_list ac;
192 va_copy(ac, ap);
193 len = vsnprintf(tmp, size, fmt, ac);
194 va_end(ac);
195 fxAssert(len >= 0, "Str::vformat() error in vsnprintf");
196 } while (len > size);
197
198 if (size > len + 1) {
199 tmp = (char*) realloc(tmp, len + 1);
200 }
201
202 s.data = tmp;
203 s.slength = len + 1;
204 return s; //XXX this is return by value which is inefficient
205 }
206
extract(u_int start,u_int chars) const207 fxStr fxStr::extract(u_int start, u_int chars) const
208 {
209 fxAssert(start+chars<slength, "Str::extract: Invalid range");
210 return fxStr(data+start,chars);
211 }
212
head(u_int chars) const213 fxStr fxStr::head(u_int chars) const
214 {
215 fxAssert(chars<slength, "Str::head: Invalid size");
216 return fxStr(data,chars);
217 }
218
tail(u_int chars) const219 fxStr fxStr::tail(u_int chars) const
220 {
221 fxAssert(chars<slength, "Str::tail: Invalid size");
222 return fxStr(data+slength-chars-1,chars);
223 }
224
lowercase(u_int posn,u_int chars)225 void fxStr::lowercase(u_int posn, u_int chars)
226 {
227 if (!chars) chars = slength-1-posn;
228 fxAssert(posn+chars<slength, "Str::lowercase: Invalid range");
229 while (chars--) {
230 #if defined(hpux) || defined(__hpux) || defined(__hpux__)
231 /*
232 * HPUX (10.x at least) is seriously busted. According
233 * to the manual page, when compiling in ANSI C mode tolower
234 * is defined as a macro that expands to a function that
235 * is undefined. It is necessary to #undef tolower before
236 * using it! (sigh)
237 */
238 #ifdef tolower
239 #undef tolower
240 #endif
241 data[posn] = tolower(data[posn]);
242 #elif defined(_tolower)
243 char c = data[posn];
244 if (isupper(c))
245 data[posn] = _tolower(c);
246 #else
247 data[posn] = tolower(data[posn]);
248 #endif
249 posn++;
250 }
251 }
252
raisecase(u_int posn,u_int chars)253 void fxStr::raisecase(u_int posn, u_int chars)
254 {
255 if (!chars) chars = slength-1-posn;
256 fxAssert(posn+chars<slength, "Str::raisecase: Invalid range");
257 while (chars--) {
258 #ifdef hpux // HPUX bogosity; see above
259 #ifdef toupper
260 #undef toupper
261 #endif
262 data[posn] = toupper(data[posn]);
263 #elif defined(_toupper)
264 char c = data[posn];
265 if (islower(c))
266 data[posn] = _toupper(c);
267 #else
268 data[posn] = toupper(data[posn]);
269 #endif
270 posn++;
271 }
272 }
273
274 /*
275 * Although T.32 6.1.1 and T.31 6.1 may lead a DCE to not
276 * distinguish between lower case and upper case, many DCEs
277 * actually support lower case characters in quoted strings.
278 * Thus, we don't rasecase quoted strings.
279 */
raiseatcmd(u_int posn,u_int chars)280 void fxStr::raiseatcmd(u_int posn, u_int chars)
281 {
282 if (!chars) chars = slength-1-posn;
283 fxAssert(posn+chars<slength, "Str::raiseatcmd: Invalid range");
284 bool quoted = false;
285 while (chars--) {
286 #ifdef hpux // HPUX bogosity; see above
287 #ifdef toupper
288 #undef toupper
289 #endif
290 if (!quoted)
291 data[posn] = toupper(data[posn]);
292 #elif defined(_toupper)
293 char c = data[posn];
294 if (islower(c) && !quoted)
295 data[posn] = _toupper(c);
296 #else
297 if (!quoted)
298 data[posn] = toupper(data[posn]);
299 #endif
300 if (data[posn] == '\"')
301 quoted = !quoted;
302 posn++;
303 }
304 }
305
copy() const306 fxStr fxStr::copy() const
307 {
308 return fxStr(data,slength-1);
309 }
310
remove(u_int start,u_int chars)311 void fxStr::remove(u_int start, u_int chars)
312 {
313 fxAssert(start+chars<slength, "Str::remove: Invalid range");
314 long move = slength-start-chars; // we always move at least 1
315 assert(move > 0);
316 if (slength - chars <= 1) {
317 resizeInternal(0);
318 slength = 1;
319 } else {
320 memmove(data+start, data+start+chars, (u_int)move);
321 slength -= chars;
322 }
323 }
324
cut(u_int start,u_int chars)325 fxStr fxStr::cut(u_int start, u_int chars)
326 {
327 fxAssert(start+chars<slength, "Str::cut: Invalid range");
328 fxStr a(data+start, chars);
329 remove(start, chars);
330 return a;
331 }
332
insert(const char * v,u_int posn,u_int len)333 void fxStr::insert(const char * v, u_int posn, u_int len)
334 {
335 if (!len) len = strlen(v);
336 if (!len) return;
337 fxAssert(posn<slength, "Str::insert: Invalid index");
338 u_int move = slength - posn;
339 u_int nl = slength + len;
340 resizeInternal(nl);
341 /*
342 * When move is one we are always moving \0; but beware
343 * that the previous string might have been null before
344 * the call to resizeInternal; so set the byte explicitly.
345 */
346 if (move == 1)
347 data[posn+len] = '\0';
348 else
349 memmove(data+posn+len, data+posn, move);
350 memcpy(data+posn, v, len);
351 slength = nl;
352 }
353
insert(char a,u_int posn)354 void fxStr::insert(char a, u_int posn)
355 {
356 u_int nl = slength + 1;
357 resizeInternal(nl);
358 long move = (long)slength - (long)posn;
359 fxAssert(move>0, "Str::insert(char): Invalid index");
360 /*
361 * When move is one we are always moving \0; but beware
362 * that the previous string might have been null before
363 * the call to resizeInternal; so set the byte explicitly.
364 */
365 if (move == 1)
366 data[posn+1] = '\0';
367 else
368 memmove(data+posn+1, data+posn, (size_t) move); // move string tail
369 data[posn] = a;
370 slength = nl;
371 }
372
replace(char a,char b)373 u_int fxStr::replace(char a, char b)
374 {
375 u_int count = 0;
376 char * buf = data;
377 u_int counter = slength-1;
378 while (counter--) {
379 if (*buf == a) {
380 *buf = b;
381 count++;
382 }
383 buf++;
384 }
385 return count;
386 }
387
resizeInternal(u_int chars)388 void fxStr::resizeInternal(u_int chars)
389 {
390 if (slength > 1) {
391 if (chars > 0) {
392 if (chars >= slength) {
393 data = (char*) realloc(data,chars+1);
394 }
395 } else {
396 assert(data != &emptyString);
397 free(data);
398 data = &emptyString;
399 }
400 } else {
401 assert(data == &emptyString);
402 if (chars) {
403 data = (char*) malloc(chars+1);
404 }
405 }
406 }
407
408
resize(u_int chars,bool)409 void fxStr::resize(u_int chars, bool)
410 {
411 resizeInternal(chars);
412 if (chars != 0) {
413 if (slength == 1) // NB: special case for emptyString
414 memset(data, 0, chars+1);
415 else {
416 if (chars >= slength) // zero expanded data segment
417 memset(data+slength, 0, chars+1-slength);
418 else // null terminate shortened string
419 data[chars] = 0;
420 }
421 } else
422 ; // now points to emptyString
423 slength = chars+1;
424 }
425
setMaxLength(u_int len)426 void fxStr::setMaxLength(u_int len)
427 {
428 if (slength>1) resizeInternal(fxmax(len,slength-1));
429 }
430
operator =(const fxTempStr & s)431 void fxStr::operator=(const fxTempStr& s)
432 {
433 resizeInternal(s.slength-1);
434 memcpy(data,s.data,s.slength);
435 slength = s.slength;
436 }
437
operator =(const fxStr & s)438 void fxStr::operator=(const fxStr& s)
439 {
440 if (data == s.data && slength == s.slength)
441 return;
442 resizeInternal(s.slength-1);
443 memcpy(data,s.data,s.slength);
444 slength = s.slength;
445 }
446
operator =(const char * s)447 void fxStr::operator=(const char *s)
448 {
449 u_int nl = strlen(s) + 1;
450 resizeInternal(nl-1);
451 slength = nl;
452 memcpy(data,s,slength);
453 }
454
append(const char * s,u_int l)455 void fxStr::append(const char * s, u_int l)
456 {
457 if (!l) l = strlen(s);
458 if (!l) return;
459 u_int nl = slength + l;
460 resizeInternal(nl-1);
461 memcpy(data+slength-1, s, l);
462 slength = nl;
463 data[slength-1] = 0;
464 }
465
append(char a)466 void fxStr::append(char a)
467 {
468 resizeInternal(slength);
469 slength++;
470 data[slength-2] = a;
471 data[slength-1] = 0;
472 }
473
operator ==(const fxStr & a,const fxStr & b)474 bool operator==(const fxStr& a,const fxStr& b)
475 {
476 return (a.slength == b.slength) && (memcmp(a.data,b.data,a.slength) == 0);
477 }
478
operator ==(const fxStr & a,const char * b)479 bool operator==(const fxStr& a,const char* b)
480 {
481 return (a.slength == strlen(b)+1) && (memcmp(a.data,b,a.slength) == 0);
482 }
483
operator ==(const char * b,const fxStr & a)484 bool operator==(const char* b, const fxStr& a)
485 {
486 return (a.slength == strlen(b)+1) && (memcmp(a.data,b,a.slength) == 0);
487 }
488
operator !=(const fxStr & a,const fxStr & b)489 bool operator!=(const fxStr& a,const fxStr& b)
490 {
491 return (a.slength != b.slength) || (memcmp(a.data,b.data,a.slength) != 0);
492 }
493
operator !=(const fxStr & a,const char * b)494 bool operator!=(const fxStr& a,const char* b)
495 {
496 return (a.slength != strlen(b)+1) || (memcmp(a.data,b,a.slength) != 0);
497 }
498
operator !=(const char * b,const fxStr & a)499 bool operator!=(const char* b, const fxStr& a)
500 {
501 return (a.slength != strlen(b)+1) || (memcmp(a.data,b,a.slength) != 0);
502 }
503
operator >=(const fxStr & a,const fxStr & b)504 bool operator>=(const fxStr& a,const fxStr& b)
505 {
506 return strcmp(a,b) >= 0;
507 }
508
operator >=(const fxStr & a,const char * b)509 bool operator>=(const fxStr& a,const char* b)
510 {
511 return strcmp(a,b) >= 0;
512 }
513
operator >=(const char * a,const fxStr & b)514 bool operator>=(const char* a, const fxStr& b)
515 {
516 return strcmp(a,b) >= 0;
517 }
518
operator >(const fxStr & a,const fxStr & b)519 bool operator>(const fxStr& a,const fxStr& b)
520 {
521 return strcmp(a,b) > 0;
522 }
523
operator >(const fxStr & a,const char * b)524 bool operator>(const fxStr& a,const char* b)
525 {
526 return strcmp(a,b) > 0;
527 }
528
operator >(const char * a,const fxStr & b)529 bool operator>(const char* a, const fxStr& b)
530 {
531 return strcmp(a,b) > 0;
532 }
533
operator <=(const fxStr & a,const fxStr & b)534 bool operator<=(const fxStr& a,const fxStr& b)
535 {
536 return strcmp(a,b) <= 0;
537 }
538
operator <=(const fxStr & a,const char * b)539 bool operator<=(const fxStr& a,const char* b)
540 {
541 return strcmp(a,b) <= 0;
542 }
543
operator <=(const char * a,const fxStr & b)544 bool operator<=(const char* a, const fxStr& b)
545 {
546 return strcmp(a,b) <= 0;
547 }
548
operator <(const fxStr & a,const fxStr & b)549 bool operator<(const fxStr& a,const fxStr& b)
550 {
551 return strcmp(a,b) < 0;
552 }
553
operator <(const fxStr & a,const char * b)554 bool operator<(const fxStr& a,const char* b)
555 {
556 return strcmp(a,b) < 0;
557 }
558
operator <(const char * a,const fxStr & b)559 bool operator<(const char* a, const fxStr& b)
560 {
561 return strcmp(a,b) < 0;
562 }
563
compare(const fxStr & a,const fxStr & b)564 int compare(const fxStr&a, const fxStr&b)
565 {
566 return strcmp(a,b);
567 }
568
compare(const fxStr & a,const char * b)569 int compare(const fxStr&a, const char*b)
570 {
571 return strcmp(a,b);
572 }
573
compare(const char * a,const char * b)574 int compare(const char *a, const char *b)
575 {
576 return strcmp(a,b);
577 }
578
579
quickFind(char a,const char * buf,u_int buflen)580 static int quickFind(char a, const char * buf, u_int buflen)
581 {
582 while (buflen--)
583 if (*buf++ == a) return 1;
584 return 0;
585 }
586
next(u_int posn,char a) const587 u_int fxStr::next(u_int posn, char a) const
588 {
589 fxAssert(posn<slength, "Str::next: invalid index");
590 char * buf = data+posn;
591 u_int counter = slength-1-posn;
592 while (counter--) {
593 if (*buf == a) return (buf-data);
594 buf++;
595 }
596 return slength-1;
597 }
598
next(u_int posn,const char * c,u_int clen) const599 u_int fxStr::next(u_int posn, const char * c, u_int clen) const
600 {
601 fxAssert(posn<slength, "Str::next: invalid index");
602 char * buf = data + posn;
603 u_int counter = slength-1-posn;
604 if (!clen) clen = strlen(c);
605 while (counter--) {
606 if (quickFind(*buf,c,clen)) return (buf-data);
607 buf++;
608 }
609 return slength-1;
610 }
611
nextR(u_int posn,char a) const612 u_int fxStr::nextR(u_int posn, char a) const
613 {
614 fxAssert(posn<slength, "Str::nextR: invalid index");
615 char * buf = data + posn - 1;
616 u_int counter = posn;
617 while (counter--) {
618 if (*buf == a) return (buf-data+1);
619 buf--;
620 }
621 return 0;
622 }
623
nextR(u_int posn,const char * c,u_int clen) const624 u_int fxStr::nextR(u_int posn, const char * c, u_int clen) const
625 {
626 fxAssert(posn<slength, "Str::nextR: invalid index");
627 char * buf = data + posn - 1;
628 u_int counter = posn;
629 if (!clen) clen = strlen(c);
630 while (counter--) {
631 if (quickFind(*buf,c,clen)) return (buf-data+1);
632 buf--;
633 }
634 return 0;
635 }
636
find(u_int posn,const char * c,u_int clen) const637 u_int fxStr::find(u_int posn, const char * c, u_int clen) const
638 {
639 fxAssert(posn<slength, "Str::find: invalid index");
640 char * buf = data + posn;
641 u_int counter = slength-1-posn;
642 if (!clen) clen = strlen(c);
643 while (counter--) {
644 if (quickFind(*buf,c,clen) && strncmp(buf,c,clen) == 0)
645 return (buf-data);
646 buf++;
647 }
648 return slength-1;
649 }
650
findR(u_int posn,const char * c,u_int clen) const651 u_int fxStr::findR(u_int posn, const char * c, u_int clen) const
652 {
653 fxAssert(posn<slength, "Str::findR: invalid index");
654 char * buf = data + posn - 1;
655 u_int counter = posn;
656 if (!clen) clen = strlen(c);
657 while (counter--) {
658 if (quickFind(*buf,c,clen) && strncmp(buf,c,clen) == 0)
659 return (buf-data+1);
660 buf--;
661 }
662 return 0;
663 }
664
skip(u_int posn,char a) const665 u_int fxStr::skip(u_int posn, char a) const
666 {
667 fxAssert(posn<slength, "Str::skip: invalid index");
668 char * buf = data+posn;
669 u_int counter = slength-1-posn;
670 while (counter--) {
671 if (*buf != a) return (buf-data);
672 buf++;
673 }
674 return slength-1;
675 }
676
skip(u_int posn,const char * c,u_int clen) const677 u_int fxStr::skip(u_int posn, const char * c, u_int clen) const
678 {
679 fxAssert(posn<slength, "Str::skip: invalid index");
680 char * buf = data + posn;
681 u_int counter = slength-1-posn;
682 if (!clen) clen = strlen(c);
683 while (counter--) {
684 if (!quickFind(*buf,c,clen)) return (buf-data);
685 buf++;
686 }
687 return slength-1;
688 }
689
skipR(u_int posn,char a) const690 u_int fxStr::skipR(u_int posn, char a) const
691 {
692 fxAssert(posn<slength, "Str::skipR: invalid index");
693 char * buf = data + posn - 1;
694 u_int counter = posn;
695 while (counter--) {
696 if (*buf != a) return (buf-data+1);
697 buf--;
698 }
699 return 0;
700 }
701
skipR(u_int posn,const char * c,u_int clen) const702 u_int fxStr::skipR(u_int posn, const char * c, u_int clen) const
703 {
704 fxAssert(posn<slength, "Str::skipR: invalid index");
705 char * buf = data + posn - 1;
706 u_int counter = posn;
707 if (!clen) clen = strlen(c);
708 while (counter--) {
709 if (!quickFind(*buf,c,clen)) return (buf-data+1);
710 buf--;
711 }
712 return 0;
713 }
714
token(u_int & posn,const char * delim,u_int dlen) const715 fxStr fxStr::token(u_int & posn, const char * delim, u_int dlen) const
716 {
717 fxAssert(posn<slength, "Str::token: invalid index");
718 if (!dlen) dlen = strlen(delim);
719 u_int end = next(posn, delim, dlen);
720 u_int old = posn;
721 posn = skip(end, delim, dlen);
722 return extract(old,end-old);
723 }
724
token(u_int & posn,char a) const725 fxStr fxStr::token(u_int & posn, char a) const
726 {
727 fxAssert(posn<slength, "Str::token: invalid index");
728 u_int end = next(posn, a);
729 u_int old = posn;
730 posn = skip(end, a);
731 return extract(old,end-old);
732 }
733
tokenR(u_int & posn,const char * delim,u_int dlen) const734 fxStr fxStr::tokenR(u_int & posn, const char * delim, u_int dlen) const
735 {
736 fxAssert(posn<slength, "Str::tokenR: invalid index");
737 if (!dlen) dlen = strlen(delim);
738 u_int begin = nextR(posn, delim, dlen);
739 u_int old = posn;
740 posn = skipR(begin, delim, dlen);
741 return extract(begin, old-begin);
742 }
743
tokenR(u_int & posn,char a) const744 fxStr fxStr::tokenR(u_int & posn, char a) const
745 {
746 fxAssert(posn<slength, "Str::tokenR: invalid index");
747 u_int begin = nextR(posn, a);
748 u_int old = posn;
749 posn = skipR(begin, a);
750 return extract(begin,old-begin);
751 }
752
hash() const753 u_long fxStr::hash() const
754 {
755 char * elementc = data;
756 u_int slen = slength - 1;
757 u_long k = 0;
758 if (slen < 2*sizeof(k)) {
759 if (slen <= sizeof(k)) {
760 memcpy((char *)&k + (sizeof(k) - slen), elementc, slen);
761 k<<=3;
762 } else {
763 memcpy((char *)&k + (sizeof(k)*2 - slen), elementc, slen-sizeof(k));
764 k<<=3;
765 k ^= *(u_long *)elementc;
766 }
767 } else {
768 k = *(u_long *)(elementc + sizeof(k));
769 k<<=3;
770 k ^= *(u_long *)elementc;
771 }
772 return k;
773 }
774
775 //--- concatenation support ----------------------------------
776
fxTempStr(const char * d1,u_int l1,const char * d2,u_int l2)777 fxTempStr::fxTempStr(const char *d1, u_int l1, const char *d2, u_int l2)
778 {
779 slength = l1 + l2 + 1;
780 if (slength <= sizeof(indata)) {
781 data = &indata[0];
782 } else {
783 data = (char*) malloc(slength);
784 }
785 memcpy(data,d1,l1);
786 memcpy(data+l1,d2,l2);
787 data[l1+l2] = 0;
788 }
789
fxTempStr(fxTempStr const & other)790 fxTempStr::fxTempStr(fxTempStr const &other)
791 {
792 slength = other.slength;
793 if (slength <= sizeof (indata)) {
794 data = &indata[0];
795 } else {
796 data = (char*) malloc(slength);
797 }
798 memcpy(data, other.data, slength);
799 data[slength] = 0;
800 }
801
~fxTempStr()802 fxTempStr::~fxTempStr()
803 {
804 if (data != indata) free(data);
805 }
806
operator |(const fxTempStr & ts,const fxStr & b)807 fxTempStr& operator|(const fxTempStr& ts, const fxStr &b)
808 {
809 return ((fxTempStr &)ts).concat(b.data, b.slength-1);
810 }
811
operator |(const fxTempStr & ts,const char * b)812 fxTempStr& operator|(const fxTempStr& ts, const char *b)
813 {
814 return ((fxTempStr &)ts).concat(b, strlen(b));
815 }
816
concat(const char * b,u_int bl)817 fxTempStr& fxTempStr::concat(const char* b, u_int bl)
818 {
819 if (slength <= sizeof(indata)) {
820 // Current temporary is in the internal buffer. See if the
821 // concatenation will fit too.
822 if (slength + bl > sizeof(indata)) {
823 // Have to malloc.
824 data = (char*) malloc(slength + bl);
825 memcpy(data, indata, slength - 1);
826 }
827 } else {
828 // Temporary is already too large.
829 data = (char*) realloc(data, slength + bl);
830 }
831
832 // concatenate data
833 memcpy(data+slength-1, b, bl);
834 slength += bl;
835 data[slength-1] = 0;
836 return *this;
837 }
838
operator |(const fxStr & a,const fxStr & b)839 fxTempStr operator|(const fxStr &a, const fxStr &b)
840 {
841 return fxTempStr(a.data, a.slength-1, b.data, b.slength-1);
842 }
843
operator |(const fxStr & a,const char * b)844 fxTempStr operator|(const fxStr &a, const char *b)
845 {
846 return fxTempStr(a.data, a.slength-1, b, strlen(b));
847 }
848
operator |(const char * a,const fxStr & b)849 fxTempStr operator|(const char *a, const fxStr &b)
850 {
851 return fxTempStr(a, strlen(a), b.data, b.slength-1);
852 }
853