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