/[pearpc]/src/tools/str.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/tools/str.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (11 years, 10 months ago) by dpavlin
File size: 14836 byte(s)
import upstream CVS
1 /*
2 * HT Editor
3 * str.cc
4 *
5 * Copyright (C) 2002 Stefan Weyergraf
6 * Copyright (C) 2002, 2003 Sebastian Biallas (sb@biallas.net)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <cctype>
23 #include <cstdlib>
24 #include <cstring>
25
26 #include "except.h"
27 #include "debug.h"
28 #include "snprintf.h"
29 #include "str.h"
30 #include "stream.h"
31 #include "strtools.h"
32
33 #ifdef HAVE_HT_OBJECTS
34 #include "atom.h"
35 #endif
36
37 //extern "C" {
38 //#include "regex.h"
39 //}
40
41 /*
42 * CLASS String
43 */
44
45 /**
46 * creates empty string
47 */
48 String::String()
49 {
50 mContent = NULL;
51 realloc(0);
52 }
53
54 /**
55 * create string from char *
56 */
57 String::String(const char *s)
58 {
59 mContent = NULL;
60 assign(s);
61 }
62
63 /**
64 * copy constructor
65 */
66 String::String(const String *s)
67 {
68 mContent = NULL;
69 assign(s);
70 }
71
72 /**
73 * copy constructor
74 */
75 String::String(const String &s)
76 {
77 ASSERT(&s != this);
78 mContent = NULL;
79 assign(s);
80 }
81
82 /**
83 * creates string from array |s| size |aLength|
84 */
85 String::String(const byte *s, int aLength)
86 {
87 mContent = NULL;
88 assign(s, aLength);
89 }
90
91 /**
92 * creates string with |count| times |c|
93 */
94 String::String(char c, int count)
95 {
96 mContent = NULL;
97 assign(c, count);
98 }
99
100 String::~String()
101 {
102 if (mContent) free(mContent);
103 }
104
105 /**
106 * (re-)assigns string to |s|
107 */
108 void String::assign(const String *s)
109 {
110 realloc(s->mLength);
111 memcpy(mContent, s->mContent, mLength);
112 }
113
114 /**
115 * (re-)assigns string to |s|
116 */
117 void String::assign(const String &s)
118 {
119 realloc(s.mLength);
120 memcpy(mContent, s.mContent, mLength);
121 }
122
123 /**
124 * (re-)assigns string to char * |s|
125 */
126 void String::assign(const char *s)
127 {
128 int slen = s ? strlen(s) : 0;
129 realloc(slen);
130 memcpy(mContent, s, mLength);
131 }
132
133 /**
134 * (re-)assigns string to array |s| length |aLength|
135 */
136 void String::assign(const byte *s, int aLength)
137 {
138 realloc(aLength);
139 memcpy(mContent, s, mLength);
140 }
141
142 /**
143 * (re-)assigns string to |count| times |c|
144 */
145 void String::assign(char c, int count)
146 {
147 realloc(count);
148 memset(mContent, c, count);
149 }
150
151 /**
152 * (re-)assigns string via ht_snprintf
153 */
154 void String::assignFormat(const char *s, ...)
155 {
156 char buf[1024];
157 va_list vargs;
158 va_start(vargs, s);
159 ht_vsnprintf(buf, sizeof buf, s, vargs);
160 va_end(vargs);
161 assign(buf);
162 }
163
164 /**
165 * appends |s| to the end
166 */
167 void String::append(const String &s)
168 {
169 if (s.mLength) {
170 int oldLength = mLength;
171 realloc(mLength + s.mLength);
172 memcpy(&mContent[oldLength], s.mContent, s.mLength);
173 }
174 }
175
176 void String::append(const char *s)
177 {
178 if (s && *s) {
179 int oldLength = mLength;
180 int slen = strlen(s);
181 realloc(mLength + slen);
182 memcpy(&mContent[oldLength], s, slen);
183 }
184 }
185
186 void String::appendChar(char c)
187 {
188 realloc(mLength+1);
189 mContent[mLength-1] = c;
190 }
191
192 /**
193 * prepends |s| to the front
194 */
195 void String::prepend(const String &s)
196 {
197 if (s.mLength) {
198 int oldLength = mLength;
199 realloc(mLength + s.mLength);
200 memmove(&mContent[s.mLength], &mContent[0], oldLength);
201 memcpy(&mContent[0], s.mContent, s.mLength);
202 }
203 }
204
205 /**
206 * Empties string.
207 */
208 void String::clear()
209 {
210 realloc(0);
211 }
212
213 String *String::clone() const
214 {
215 return new String(mContent, mLength);
216 }
217
218 /**
219 * compares to characters.
220 * used in compareTo() and findXXX() (and therefore replace())
221 * @returns 0 for equality, negative number if |c1<c2| and positive number if |c1>c2|
222 */
223 int String::compareChar(char c1, char c2) const
224 {
225 if (c1<c2) return -1;
226 if (c1>c2) return 1;
227 return 0;
228 }
229
230 int String::compare(const char *s) const
231 {
232 if (!mLength) {
233 return (s) ? -1: 0;
234 }
235 if (!s) {
236 return 1;
237 }
238 int l = mLength;
239 for (int i=0; i < l; i++) {
240 if (!*s) return 1;
241 int r = compareChar(mContent[i], s[i]);
242 if (r) return r;
243 }
244 if (s[l]) return -1;
245 return 0;
246 }
247
248 int String::compare(const String &s) const
249 {
250 if (!mContent) {
251 return (s.mContent) ? -1: 0;
252 }
253 if (!s.mContent) {
254 return 1;
255 }
256 int l = MIN(mLength, s.mLength);
257 for (int i=0; i<l; i++) {
258 int r = compareChar(mContent[i], s.mContent[i]);
259 if (r) return r;
260 }
261 if (mLength < s.mLength) return -1;
262 if (mLength == s.mLength) return 0;
263 return 1;
264 }
265
266 /*
267 * like compare(s) but considers a maximum of |aMax| characters
268 */
269 int String::compare(const String &s, int aMax) const
270 {
271 if (aMax <= 0) return 0;
272 if (!mContent) {
273 return (s.mContent) ? -1: 0;
274 }
275 if (!s.mContent) {
276 return 1;
277 }
278 int l = MIN(mLength, s.mLength);
279 l = MIN(l, aMax);
280 int i;
281 for (i=0; i<l; i++) {
282 int r = compareChar(mContent[i], s.mContent[i]);
283 if (r) return r;
284 }
285 if (i == aMax) return 0;
286 if (mLength < s.mLength) return -1;
287 if (mLength == s.mLength) return 0;
288 return 1;
289 }
290
291 int String::compareTo(const Object *o) const
292 {
293 ASSERT(getObjectID() == o->getObjectID());
294 return compare(*((String *)o));
295 }
296
297 /**
298 * Crops the string to contain a maximum of |aNewLength| characters.
299 */
300 void String::crop(int aNewLength)
301 {
302 if ((aNewLength >= 0) && (aNewLength < mLength)) realloc(aNewLength);
303 }
304
305 /**
306 * Deletes |aLength| characters at |pos|
307 */
308 void String::del(int pos, int aLength)
309 {
310 if (pos < 0) {
311 aLength += pos;
312 pos = 0;
313 }
314 if (aLength <= 0 || pos >= mLength) return;
315 if (pos+aLength >= mLength) aLength = mLength-pos;
316 if (!aLength) return;
317 if (pos + aLength < mLength) {
318 memmove(&mContent[pos], &mContent[pos+aLength], mLength-aLength-pos);
319 }
320 realloc(mLength-aLength);
321 }
322
323 /**
324 * Escapes certains characters in a c-style manner (all characters < 0x20).
325 * @param aSpecialChars characters that need a \
326 * @param bit7 hex encode (\x..) characters >127
327 */
328 void String::escape(const char *aSpecialChars, bool bit7)
329 {
330 if (!mLength) return;
331 String copy(this);
332 realloc(mLength*4);
333 realloc(escape_special((char*)mContent, mLength, copy.mContent,
334 copy.mLength, aSpecialChars, bit7));
335 }
336
337 /**
338 * Search forwards for |c| in string
339 * @param c character to search for
340 * @param start first character position to look for
341 * @returns position of character or number < 0 if not found
342 */
343 int String::findFirstChar(char c, int start) const
344 {
345 if (!mLength) return -1;
346 if (start >= mLength) return -1;
347 if (start < 0) start = 0;
348 for (int i=start; i<mLength; i++) {
349 if (compareChar(mContent[i], c) == 0) return i;
350 }
351 return -1;
352 }
353
354 /**
355 * Search forwards for |s| in string
356 * @param s string to search for
357 * @param start first character position to look for
358 * @returns position of character or number < 0 if not found
359 */
360 int String::findFirstString(const String &s, int start) const
361 {
362 if (!s.mLength) return 0;
363 if (start < 0) start = 0;
364 if (!mLength || (start+s.mLength > mLength)) return -1;
365 for (int i=start; (i+s.mLength <= mLength); i++) {
366 for (int j=i; (j>=0) && (j+s.mLength <= mLength) && (j-i < s.mLength); j++) {
367 if (compareChar(mContent[j], s.mContent[j-i])) goto notfound;
368 }
369 return i;
370 notfound:;
371 }
372 return -1;
373 }
374
375 /**
376 * Search backwards for |c| in string
377 * @param c character to search for
378 * @param start first character position to look for
379 * @returns position of character or number < 0 if not found
380 */
381 int String::findLastChar(char c, int start) const
382 {
383 if (!mLength) return -1;
384 if (start >= mLength) return -1;
385 if (start < 0) start = mLength-1;
386 for (int i=start; i>=0; i--) {
387 if (compareChar(mContent[i], c) == 0) return i;
388 }
389 return -1;
390 }
391
392 /**
393 * Search backwards for |s| in string
394 * @param s string to search for
395 * @param start first character position to look for
396 * @returns position of character or number < 0 if not found
397 */
398 int String::findLastString(const String &s, int start) const
399 {
400 if (!mLength) return -1;
401 return -1;
402 }
403
404 /**
405 * inserts |s| at postion |pos| in string.
406 */
407 void String::insert(const String &s, int pos)
408 {
409 if (pos > mLength || pos < 0) throw MsgException("index out of bounds");
410 if (!s.mLength) return;
411 realloc(mLength+s.mLength);
412 if (mLength-s.mLength-pos > 0)
413 memmove(&mContent[pos+s.mLength], &mContent[pos], mLength-s.mLength-pos);
414 memmove(&mContent[pos], s.mContent, s.mLength);
415 }
416
417 bool String::instanceOf(ObjectID id) const
418 {
419 if (id == getObjectID()) return true;
420 return Object::instanceOf(id);
421 }
422
423 bool String::leftSplit(char chr, String &initial, String &rem) const
424 {
425 int pivot = findFirstChar(chr);
426 if (pivot < 0) {
427 initial = *this;
428 rem.clear();
429 return false;
430 }
431 subString(0, pivot, initial);
432 subString(pivot+1, length(), rem);
433 return true;
434 }
435
436 ObjectID String::getObjectID() const
437 {
438 return OBJID_STRING;
439 }
440
441 void String::realloc(int aNewSize)
442 {
443 mLength = aNewSize;
444 mContent = (byte*)::realloc(mContent, mLength+1);
445 mContent[mLength] = 0;
446 /* if (mContent) {
447 if (aNewSize) {
448 mContent = (byte*)::realloc(mContent, aNewSize);
449 } else {
450 free(mContent);
451 mContent = NULL;
452 }
453 } else {
454 if (aNewSize) {
455 mContent = (byte*)malloc(aNewSize);
456 }
457 }
458 mLength = aNewSize;*/
459 }
460
461 /*bool String::regexMatch(const String &aRegEx, Container *resultStrings, int maxRegExMatches) const
462 {
463 const char *re = aRegEx.toString();
464 bool result = false;
465 regex_t rx;
466
467 int r = regcomp(&rx, re, REG_EXTENDED | ((compareChar('A','a')==0) ? REG_ICASE : 0));
468 if (r) throw MsgException("EINVAL");
469
470 regmatch_t pmatch[maxRegExMatches];
471 if (regexec(&rx, (char*)mContent, maxRegExMatches, pmatch, 0) != 0) return false;
472
473 if (resultStrings) {
474 for (int i=1; i < maxRegExMatches; i++) {
475 if (pmatch[i].rm_so == -1) break;
476 String *s = new String();
477 subString(pmatch[i].rm_so, pmatch[i].rm_eo-pmatch[i].rm_so, *s);
478 resultStrings->insert(s);
479 }
480 }
481
482 delete re;
483 return result;
484 }*/
485
486 /**
487 * replaces all occurences of |what| in string with |with|
488 * @param what searchstring
489 * @param with replacement
490 * @param start
491 * @param maxReplacements
492 * @returns number of replacements
493 */
494 int String::replace(const String &what, const String &with, int start, int maxReplacements)
495 {
496 if (!maxReplacements) return 0;
497 int whatlen = what.length();
498 int withlen = with.length();
499 int numRepl = 0;
500 int p = findFirstString(what, start);
501 while (p >= 0) {
502 if (whatlen == withlen) {
503 // replace in situ
504 memmove(&mContent[p], with.mContent, withlen);
505 } else {
506 del(p, whatlen);
507 insert(with, p);
508 }
509 numRepl++;
510 if (maxReplacements > 0) {
511 maxReplacements--;
512 if (!maxReplacements) break;
513 }
514 p = findFirstString(what, p+withlen);
515 }
516 return numRepl;
517 }
518
519 bool String::rightSplit(char chr, String &initial, String &rem) const
520 {
521 int pivot = findLastChar(chr);
522 if (pivot < 0) {
523 initial = *this;
524 rem.clear();
525 return false;
526 }
527 subString(0, pivot, initial);
528 subString(pivot+1, length(), rem);
529 return true;
530 }
531
532 /**
533 * assigns result to the substring with
534 * |aLength| characters starting at |aStart|.
535 * @param result will hold the result
536 * @param aStart position of first character in new string
537 * @param aLength number of characters to copy
538 * @returns number of characters copied
539 */
540 int String::subString(int aStart, int aLength, String &result) const
541 {
542 if (aLength <= 0 || aStart >= mLength) {
543 result.clear();
544 return 0;
545 }
546 if (aStart+aLength >= mLength) aLength = mLength-aStart;
547 result.assign(&mContent[aStart], aLength);
548 return aLength;
549 }
550
551 /**
552 *
553 */
554 void String::transformCase(StringCase c)
555 {
556 if (c==stringCaseCaps) {
557 } else {
558 for (int i=0; i<mLength; i++) {
559 if (c==stringCaseLower) {
560 mContent[i]=tolower(mContent[i]);
561 } else {
562 mContent[i]=toupper(mContent[i]);
563 }
564 }
565 }
566 }
567
568 /**
569 * replace all characters of |inAlpha| in string with the corrensponding
570 * characters of |outAlpha|. The lengths of |inAlpha| and |outAlpha| must
571 * be identical. |inAlpha| should not contain the same characters multiple
572 * times.
573 */
574 void String::translate(const String &inAlpha, const String &outAlpha)
575 {
576 ASSERT(inAlpha.mLength == outAlpha.mLength);
577 if (inAlpha.isEmpty() || isEmpty()) return;
578 byte tr[256];
579 for (int i=0; i<256; i++) tr[i] = i;
580 for (int i=0; i<inAlpha.mLength; i++) {
581 tr[inAlpha.mContent[i]] = outAlpha.mContent[i];
582 }
583 for (int i=0; i<mLength; i++) {
584 mContent[i] = tr[mContent[i]];
585 }
586 }
587
588 /**
589 *
590 */
591 int String::toArray(byte *buf, int buflen) const
592 {
593 if (buflen <= 0) return 0;
594 int r = MIN(mLength, buflen-1);
595 memcpy(buf, mContent, r);
596 return r;
597 }
598
599 /**
600 *
601 */
602 bool String::toInt(int &i, int defaultbase) const
603 {
604 const char *b = (const char*)mContent;
605 uint64 u64;
606 if (!parseIntStr(b, u64, defaultbase)) return false;
607 if (b-(const char*)mContent != mLength) return false;
608 i = (sint64)u64;
609 return true;
610 }
611
612 /**
613 *
614 */
615 bool String::toInt32(uint32 &u32, int defaultbase) const
616 {
617 const char *b = (const char*)mContent;
618 uint64 u64;
619 if (!parseIntStr(b, u64, defaultbase)) return false;
620 if (b-(const char*)mContent != mLength) return false;
621 u32 = u64;
622 return true;
623 }
624
625 /**
626 *
627 */
628 bool String::toInt64(uint64 &u64, int defaultbase) const
629 {
630 const char *b = (const char*)mContent;
631 if (!parseIntStr(b, u64, defaultbase)) return false;
632 return (b-(const char*)mContent == mLength);
633 }
634
635 int String::toString(char *buf, int buflen) const
636 {
637 if (buflen <= 0) return 0;
638 int r = MIN(mLength, buflen-1);
639 for (int i=0; i<r; i++) {
640 if (mContent[i]) {
641 buf[i] = mContent[i];
642 } else {
643 buf[i] = ' ';
644 }
645 }
646 buf[r] = 0;
647 return r;
648 }
649
650 /**
651 * all '\0' will be converted to ' ' (space)
652 * @returns new[] allocated char *
653 */
654 char *String::toString() const
655 {
656 char *s = new char[mLength+1];
657 for (int i=0; i<mLength; i++) {
658 if (mContent[i]) {
659 s[i] = mContent[i];
660 } else {
661 s[i] = ' ';
662 }
663 }
664 s[mLength] = 0;
665 return s;
666 }
667
668 /**
669 * reverses action of <code>escape</code>.
670 * Note that output isnt defined if string wasnt escaped before.
671 */
672 void String::unescape()
673 {
674 String copy(this);
675 realloc(unescape_special(mContent, mLength, (char*)copy.mContent));
676 }
677
678 String &String::operator +=(char c)
679 {
680 realloc(mLength+1);
681 mContent[mLength-1] = c;
682 return *this;
683 }
684
685 /*
686 * global
687 */
688
689 String operator +(const String &s1, const String &s2)
690 {
691 String temp = String(s1);
692 temp.append(s2);
693 return temp;
694 }
695
696 String operator +(const char *s1, const String &s2)
697 {
698 String temp = String(s1);
699 temp.append(s2);
700 return temp;
701 }
702
703 /*
704 * CLASS IString
705 */
706
707 IString::IString()
708 {
709 }
710
711 IString *IString::clone() const
712 {
713 IString *r = new IString();
714 *r = *this;
715 return r;
716 }
717
718 int IString::compareChar(char c1, char c2) const
719 {
720 c1 = tolower(c1);
721 c2 = tolower(c2);
722 return String::compareChar(c1, c2);
723 }
724
725 bool IString::instanceOf(ObjectID id) const
726 {
727 if (id == getObjectID()) return true;
728 return String::instanceOf(id);
729 }
730
731 ObjectID IString::getObjectID() const
732 {
733 return OBJID_ISTRING;
734 }
735

  ViewVC Help
Powered by ViewVC 1.1.26