source: trunk/src/helpers/xstring.c@ 15

Last change on this file since 15 was 15, checked in by umoeller, 25 years ago

Coupla bugfixes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 30.8 KB
Line 
1
2/*
3 *@@sourcefile xstring.c:
4 * string functions with memory management.
5 *
6 * Usage: All OS/2 programs.
7 *
8 * The functions in this file are intended as a replacement
9 * to the C library string functions (such as strcpy, strcat)
10 * in cases where the length of the string is unknown and
11 * dynamic memory management is desirable.
12 *
13 * Instead of char* pointers, the functions in this file
14 * operate on an XSTRING structure, which contains a char*
15 * pointer instead.
16 *
17 * Using these functions has the following advantages:
18 *
19 * -- Automatic memory management. For example, xstrcat will
20 * automatically allocate new memory if the new string
21 * does not fit into the present buffer.
22 *
23 * -- The length of the string is always known. Instead
24 * of running strlen (which consumes time), XSTRING.ulLength
25 * always contains the current length of the string.
26 *
27 * -- The functions also differentiate between allocated
28 * memory and the length of the string. That is, for
29 * iterative appends, you can pre-allocate memory to
30 * avoid excessive reallocations.
31 *
32 * Usage:
33 *
34 * 1) Allocate an XSTRING structure on the stack. Always
35 * call xstrInit on the structure, like this:
36 *
37 + XSTRING str;
38 + xstrInit(&str, 0); // no pre-allocation
39 *
40 * Alternatively, use xstrCreate to have an XSTRING
41 * allocated from the heap.
42 *
43 * Always call xstrClear(&str) to free allocated
44 * memory. Otherwise you'll get memory leaks.
45 * (For heap XSTRING's from xstrCreate, use xstrFree.)
46 *
47 * 2) To copy something into the string, use xstrcpy.
48 * To append something to the string, use xstrcat.
49 * See those functions for samples.
50 *
51 * 3) If you need the char* pointer (e.g. for a call
52 * to another function), use XSTRING.psz. However,
53 * you should ONLY modify the psz pointer yourself
54 * if the other XSTRING members are updated accordingly.
55 * You may, for example, change single characters
56 * in the psz buffer. By contrast, if you change the
57 * length of the string, you must update XSTRING.ulLength.
58 * Otherwise these functions will get into trouble.
59 *
60 * Also, you should never assume that the "psz"
61 * pointer has not changed after you have called
62 * one of the xstr* functions because these can
63 * always reallocate the buffer if more memory
64 * was needed.
65 *
66 * 4) If (and only if) you have a char* buffer which
67 * is free()'able (e.g. from strdup()), you can
68 * use xstrset to avoid duplicate copying.
69 *
70 * Function prefixes:
71 * -- xstr* extended string functions.
72 *
73 * The functions in this file used to be in stringh.c
74 * before V0.9.3 (2000-04-01). These have been largely
75 * rewritten with V0.9.6 (2000-11-01) and are now much
76 * more efficient.
77 *
78 * Note: Version numbering in this file relates to XWorkplace
79 * version numbering.
80 *
81 *@@added V0.9.3 (2000-04-01) [umoeller]
82 *@@header "helpers\xstring.h"
83 */
84
85/*
86 * Copyright (C) 1999-2000 Ulrich M”ller.
87 * This file is part of the "XWorkplace helpers" source package.
88 * This is free software; you can redistribute it and/or modify
89 * it under the terms of the GNU General Public License as published
90 * by the Free Software Foundation, in version 2 as it comes in the
91 * "COPYING" file of the XWorkplace main distribution.
92 * This program is distributed in the hope that it will be useful,
93 * but WITHOUT ANY WARRANTY; without even the implied warranty of
94 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
95 * GNU General Public License for more details.
96 */
97
98#define OS2EMX_PLAIN_CHAR
99 // this is needed for "os2emx.h"; if this is defined,
100 // emx will define PSZ as _signed_ char, otherwise
101 // as unsigned char
102
103#include <os2.h>
104
105#include <stdlib.h>
106#include <stdio.h>
107#include <string.h>
108
109#include "setup.h" // code generation and debugging options
110
111#include "helpers\stringh.h"
112#include "helpers\xstring.h" // extended string helpers
113
114/*
115 *@@category: Helpers\C helpers\String management
116 */
117
118/*
119 *@@ xstrInit:
120 * initializes an empty XSTRING.
121 *
122 * If (ulPreAllocate != 0), memory is pre-allocated
123 * for the string, but the string will be empty.
124 * This is useful if you plan to add more stuff to
125 * the string later so we don't have to reallocate
126 * all the time in xstrcat.
127 *
128 * Do not use this on an XSTRING which is already
129 * initialized. Use xstrset instead.
130 *
131 *@@added V0.9.6 (2000-11-01) [umoeller]
132 */
133
134void xstrInit(PXSTRING pxstr, // in/out: string
135 ULONG ulPreAllocate) // in: if > 0, memory to allocate
136{
137 memset(pxstr, 0, sizeof(XSTRING));
138 if (ulPreAllocate)
139 {
140 pxstr->psz = (PSZ)malloc(ulPreAllocate);
141 pxstr->cbAllocated = ulPreAllocate;
142 // ulLength is still zero
143 *(pxstr->psz) = 0;
144 }
145}
146
147/*
148 *@@ xstrInitSet:
149 * this can be used instead of xstrInit if you
150 * have a free()'able string you want to initialize
151 * the XSTRING with.
152 *
153 * This does not create a copy of pszNew. Instead,
154 * pszNew is used as the member string in pxstr
155 * directly.
156 *
157 * Do not use this on an XSTRING which is already
158 * initialized. Use xstrset instead.
159 *
160 * Example:
161 *
162 + XSTRING str;
163 + xstrInitSet(&str, strdup("blah"));
164 *
165 *@@added V0.9.6 (2000-11-01) [umoeller]
166 */
167
168void xstrInitSet(PXSTRING pxstr,
169 PSZ pszNew)
170{
171 pxstr->psz = pszNew;
172 if (!pszNew)
173 {
174 pxstr->cbAllocated = 0;
175 pxstr->ulLength = 0;
176 }
177 else
178 {
179 pxstr->ulLength = strlen(pszNew);
180 pxstr->cbAllocated = pxstr->ulLength + 1;
181 }
182}
183
184/*
185 *@@ xstrInitCopy:
186 * this can be used instead of xstrInit if you
187 * want to initialize an XSTRING with a copy
188 * of an existing string. This is a shortcut
189 * for xstrInit() and then xstrcpy().
190 *
191 * As opposed to xstrInitSet, this does create
192 * a copy of pcszSource.
193 *
194 * Do not use this on an XSTRING which is already
195 * initialized. Use xstrcpy instead.
196 *
197 * Example:
198 *
199 + XSTRING str;
200 + xstrInitCopy(&str, "blah");
201 *
202 *@@added V0.9.6 (2000-11-01) [umoeller]
203 */
204
205void xstrInitCopy(PXSTRING pxstr,
206 const char *pcszSource)
207{
208 if (pxstr)
209 {
210 memset(pxstr, 0, sizeof(XSTRING));
211
212 if (pcszSource)
213 pxstr->ulLength = strlen(pcszSource);
214
215 if (pxstr->ulLength)
216 {
217 // we do have a source string:
218 pxstr->cbAllocated = pxstr->ulLength + 1;
219 pxstr->psz = (PSZ)malloc(pxstr->cbAllocated);
220 strcpy(pxstr->psz, pcszSource);
221 }
222 }
223}
224
225/*
226 *@@ xstrClear:
227 * clears the specified stack XSTRING and
228 * frees allocated memory.
229 *
230 * This is the reverse to xstrInit.
231 *
232 *@@added V0.9.6 (2000-11-01) [umoeller]
233 */
234
235void xstrClear(PXSTRING pxstr) // in/out: string
236{
237 if (pxstr->psz)
238 free(pxstr->psz);
239 memset(pxstr, 0, sizeof(XSTRING));
240}
241
242/*
243 *@@ xstrCreate:
244 * allocates a new XSTRING from the heap
245 * and calls xstrInit on it.
246 *
247 * Always use xstrFree to free associated
248 * resources.
249 *
250 *@@added V0.9.6 (2000-11-01) [umoeller]
251 */
252
253PXSTRING xstrCreate(ULONG ulPreAllocate)
254{
255 PXSTRING pxstr = (PXSTRING)malloc(sizeof(XSTRING));
256 if (pxstr)
257 xstrInit(pxstr, ulPreAllocate);
258
259 return (pxstr);
260}
261
262/*
263 *@@ xstrFree:
264 * frees the specified heap XSTRING, which must
265 * have been created using xstrCreate.
266 *
267 *@@added V0.9.6 (2000-11-01) [umoeller]
268 */
269
270VOID xstrFree(PXSTRING pxstr) // in/out: string
271{
272 if (pxstr)
273 {
274 xstrClear(pxstr);
275 free(pxstr);
276 }
277}
278
279/*
280 *@@ xstrset:
281 * sets the specified XSTRING to a new string
282 * without copying it.
283 *
284 * pxstr is cleared before the new string is set.
285 *
286 * This ONLY works if pszNew has been allocated from
287 * the heap using malloc() or strdup() and is thus
288 * free()'able.
289 *
290 * This assumes that exactly strlen(pszNew) + 1
291 * bytes have been allocated for pszNew, which
292 * is true if pszNew comes from strdup().
293 *
294 *@@added V0.9.6 (2000-11-01) [umoeller]
295 */
296
297ULONG xstrset(PXSTRING pxstr, // in/out: string
298 PSZ pszNew) // in: heap PSZ to use
299{
300 xstrClear(pxstr);
301 pxstr->psz = pszNew;
302 if (pszNew)
303 {
304 pxstr->ulLength = strlen(pszNew);
305 pxstr->cbAllocated = pxstr->ulLength + 1;
306 }
307 // else null string: cbAllocated and ulLength are 0 already
308
309 return (pxstr->ulLength);
310}
311
312/*
313 *@@ xstrcpy:
314 * copies pcszSource to pxstr, for which memory is allocated
315 * as necessary.
316 *
317 * If pxstr contains something, its contents are destroyed.
318 *
319 * Returns the length of the new string (excluding the null
320 * terminator), or null upon errors.
321 *
322 * Example:
323 *
324 + XSTRING str;
325 + xstrInit(&str, 0);
326 + xstrcpy(&str, "blah");
327 *
328 * This sequence can be abbreviated using xstrInitCopy.
329 *
330 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcpy
331 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
332 */
333
334ULONG xstrcpy(PXSTRING pxstr, // in/out: string
335 const char *pcszSource) // in: source, can be NULL
336{
337 xstrClear(pxstr);
338
339 if (pxstr)
340 {
341 ULONG ulSourceLength = 0;
342 if (pcszSource)
343 ulSourceLength = strlen(pcszSource);
344
345 if (ulSourceLength)
346 {
347 // we do have a source string:
348 ULONG cbNeeded = ulSourceLength + 1;
349 if (cbNeeded > pxstr->cbAllocated)
350 {
351 // we need more memory than we have previously
352 // allocated:
353 pxstr->cbAllocated = cbNeeded;
354 pxstr->psz = (PSZ)malloc(cbNeeded);
355 }
356 // else: we have enough memory
357
358 strcpy(pxstr->psz, pcszSource);
359 }
360 else
361 {
362 // no source specified or source is empty:
363 if (pxstr->cbAllocated)
364 // we did have a string: set to empty,
365 // but leave allocated memory intact
366 *(pxstr->psz) = 0;
367 // else: pxstr->psz is still NULL
368 }
369
370 // in all cases, set new length
371 pxstr->ulLength = ulSourceLength;
372 }
373
374 return (pxstr->ulLength);
375}
376
377/*
378 *@@ xstrcat:
379 * appends pcszSource to pxstr, for which memory is
380 * reallocated if necessary.
381 *
382 * If pxstr is empty, this behaves just like xstrcpy.
383 *
384 * Returns the length of the new string (excluding the null
385 * terminator) if the string was changed, or 0 if nothing
386 * happened.
387 *
388 * Note: To append a single character, xstrcatc is faster
389 * than xstrcat.
390 *
391 * Example:
392 *
393 + XSTRING str;
394 + xstrInit(&str, 0);
395 + xstrcpy(&str, "blah");
396 + xstrcat(&str, "blup");
397 *
398 * After this, str.psz points to a new string containing
399 * "blahblup".
400 *
401 *@@changed V0.9.1 (99-12-20) [umoeller]: fixed memory leak
402 *@@changed V0.9.1 (2000-01-03) [umoeller]: crashed if pszString was null; fixed
403 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcat
404 *@@changed V0.9.3 (2000-05-11) [umoeller]: returned 0 if pszString was initially empty; fixed
405 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
406 *@@changed V0.9.7 (2000-12-10) [umoeller]: return value was wrong
407 */
408
409ULONG xstrcat(PXSTRING pxstr, // in/out: string
410 const char *pcszSource) // in: source, can be NULL
411{
412 ULONG ulrc = 0;
413
414 if (pxstr)
415 {
416 ULONG ulSourceLength = 0;
417 if (pcszSource)
418 ulSourceLength = strlen(pcszSource);
419
420 if (ulSourceLength)
421 {
422 // we do have a source string:
423
424 // 1) memory management
425 ULONG cbNeeded = pxstr->ulLength + ulSourceLength + 1;
426 if (cbNeeded > pxstr->cbAllocated)
427 {
428 // we need more memory than we have previously
429 // allocated:
430 if (pxstr->cbAllocated)
431 // appendee already had memory:
432 // reallocate
433 pxstr->psz = (PSZ)realloc(pxstr->psz,
434 cbNeeded);
435 else
436 // appendee has no memory:
437 pxstr->psz = (PSZ)malloc(cbNeeded);
438
439 pxstr->cbAllocated = cbNeeded;
440 // ulLength is unchanged yet
441 }
442 // else: we have enough memory, both if appendee
443 // is empty or not empty
444
445 // now we have:
446 // -- if appendee (pxstr) had enough memory, no problem
447 // -- if appendee (pxstr) needed more memory
448 // -- and was not empty: pxstr->psz now points to a
449 // reallocated copy of the old string
450 // -- and was empty: pxstr->psz now points to a
451 // new (unitialized) buffer
452
453 // 2) append source string:
454 memcpy(pxstr->psz + pxstr->ulLength,
455 pcszSource,
456 ulSourceLength + 1); // null terminator
457
458 // in all cases, set new length
459 pxstr->ulLength += ulSourceLength;
460 ulrc = pxstr->ulLength; // V0.9.7 (2000-12-10) [umoeller]
461
462 } // end if (ulSourceLength)
463 // else no source specified or source is empty:
464 // do nothing
465 }
466
467 return (ulrc);
468}
469
470/*
471 *@@ xstrcatc:
472 * this is similar to xstrcat, except that this is
473 * for a single character. This is a bit faster than
474 * xstrcat.
475 *
476 * If "c" is \0, nothing happens.
477 *
478 * If pxstr is empty, this behaves just like xstrcpy.
479 *
480 * Returns the length of the new string (excluding the null
481 * terminator) if the string was changed, or 0 if nothing
482 * happened.
483 *
484 * Example:
485 *
486 + XSTRING str;
487 + xstrInit(&str, 0);
488 + xstrcpy(&str, "blu");
489 + xstrcatc(&str, 'p');
490 *
491 * After this, str.psz points to a new string containing
492 * "blup".
493 *
494 *@@added V0.9.7 (2000-12-10) [umoeller]
495 */
496
497ULONG xstrcatc(PXSTRING pxstr, // in/out: string
498 CHAR c) // in: character to append, can be \0
499{
500 ULONG ulrc = 0;
501
502 if ((pxstr) && (c))
503 {
504 // ULONG ulSourceLength = 1;
505 // 1) memory management
506 ULONG cbNeeded = pxstr->ulLength // existing length, without null terminator
507 + 1 // new character
508 + 1; // null terminator
509 if (cbNeeded > pxstr->cbAllocated)
510 {
511 // we need more memory than we have previously
512 // allocated:
513 if (pxstr->cbAllocated)
514 // appendee already had memory:
515 // reallocate
516 pxstr->psz = (PSZ)realloc(pxstr->psz,
517 cbNeeded);
518 else
519 // appendee has no memory:
520 pxstr->psz = (PSZ)malloc(cbNeeded);
521
522 pxstr->cbAllocated = cbNeeded;
523 // ulLength is unchanged yet
524 }
525 // else: we have enough memory, both if appendee
526 // is empty or not empty
527
528 // now we have:
529 // -- if appendee (pxstr) had enough memory, no problem
530 // -- if appendee (pxstr) needed more memory
531 // -- and was not empty: pxstr->psz now points to a
532 // reallocated copy of the old string
533 // -- and was empty: pxstr->psz now points to a
534 // new (unitialized) buffer
535
536 // 2) append character:
537 pxstr->psz[pxstr->ulLength] = c;
538 pxstr->psz[pxstr->ulLength + 1] = '\0';
539
540 // in all cases, set new length
541 pxstr->ulLength++;
542 ulrc = pxstr->ulLength;
543
544 } // end if ((pxstr) && (c))
545
546 return (ulrc);
547}
548
549/*
550 *@@ xstrFindWord:
551 * searches for pstrFind in pxstr, starting at ulOfs.
552 * However, this only finds pstrFind if it's a "word",
553 * i.e. surrounded by one of the characters in the
554 * pcszBeginChars and pcszEndChars array.
555 *
556 * This is similar to strhFindWord, but this uses
557 * strhmemfind for fast searching, and it doesn't
558 * have to calculate the string lengths because these
559 * already in XSTRING.
560 *
561 * Returns 0 if no "word" was found, or the offset
562 * of the "word" in pxstr if found.
563 *
564 *@@added V0.9.6 (2000-11-12) [umoeller]
565 */
566
567PSZ xstrFindWord(const XSTRING *pxstr, // in: buffer to search ("haystack")
568 ULONG ulOfs, // in: where to begin search (0 = start)
569 const XSTRING *pstrFind, // in: word to find ("needle")
570 size_t *pShiftTable, // in: shift table (see strhmemfind)
571 PBOOL pfRepeatFind, // in: repeat find? (see strhmemfind)
572 const char *pcszBeginChars, // suggestion: "\x0d\x0a ()/\\-,."
573 const char *pcszEndChars) // suggestion: "\x0d\x0a ()/\\-,.:;"
574{
575 PSZ pReturn = 0;
576 ULONG ulFoundLen = pstrFind->ulLength;
577
578 if ((pxstr->ulLength) && (ulFoundLen))
579 {
580 const char *p = pxstr->psz + ulOfs;
581
582 do // while p
583 {
584 // p = strstr(p, pstrFind->psz);
585 p = (PSZ)strhmemfind(p, // in: haystack
586 pxstr->ulLength - (p - pxstr->psz),
587 // remaining length of haystack
588 pstrFind->psz,
589 ulFoundLen,
590 pShiftTable,
591 pfRepeatFind);
592 if (p)
593 {
594 // string found:
595 // check if that's a word
596
597 if (strhIsWord(pxstr->psz,
598 p,
599 ulFoundLen,
600 pcszBeginChars,
601 pcszEndChars))
602 {
603 // valid end char:
604 pReturn = (PSZ)p;
605 break;
606 }
607
608 p += ulFoundLen;
609 }
610 } while (p);
611
612 }
613 return (pReturn);
614}
615
616/*
617 *@@ xstrrpl:
618 * replaces the first occurence of pstrSearch with
619 * pstrReplace in pxstr.
620 *
621 * Starting with V0.9.6, this operates entirely on
622 * XSTRING's for speed because we then know the string
623 * lengths already and can use memcpy instead of strcpy.
624 * This new version should be magnitudes faster,
625 * especially with large string bufffers.
626 *
627 * None of the pointers can be NULL, but if pstrReplace
628 * is empty, this effectively erases pstrSearch in pxstr.
629 *
630 * Returns the length of the new string (exclusing the
631 * null terminator) or 0 if pszSearch was not found
632 * (and pxstr was therefore not changed).
633 *
634 * This starts the search at *pulOffset. If
635 * (*pulOffset == 0), this starts from the beginning
636 * of pxstr.
637 * If the string was found, *pulOffset will be set to the
638 * first character after the new replacement string. This
639 * allows you to call this func again with the same strings
640 * to have several occurences replaced (see the example below).
641 *
642 * There are two wrappers around this function which
643 * work on C strings instead (however, thus losing the
644 * speed advantage):
645 *
646 * -- strhrpl operates on C strings only;
647 *
648 * -- xstrcrpl uses C strings for the search and replace
649 * parameters.
650 *
651 * <B>Example usage:</B>
652 *
653 + XSTRING str;
654 + ULONG ulOffset = 0;
655 + xstrInit(&str, 0);
656 + xstrcpy(&str, "Test phrase 1. Test phrase 2.");
657 + while (xstrrpl(&str,
658 + &ulPos, // in/out: offset
659 + "Test", // search
660 + "Dummy") // replace
661 + ;
662 *
663 * would replace all occurences of "Test" in str with
664 * "Dummy".
665 *
666 *@@changed V0.9.0 [umoeller]: totally rewritten.
667 *@@changed V0.9.0 (99-11-08) [umoeller]: crashed if *ppszBuf was NULL. Fixed.
668 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxrpl
669 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
670 *@@changed V0.9.6 (2000-11-12) [umoeller]: now using strhmemfind
671 */
672
673ULONG xstrrpl(PXSTRING pxstr, // in/out: string
674 PULONG pulOfs, // in: where to begin search (0 = start);
675 // out: ofs of first char after replacement string
676 const XSTRING *pstrSearch, // in: search string; cannot be NULL
677 const XSTRING *pstrReplace, // in: replacement string; cannot be NULL
678 size_t *pShiftTable, // in: shift table (see strhmemfind)
679 PBOOL pfRepeatFind) // in: repeat find? (see strhmemfind)
680{
681 ULONG ulrc = 0; // default: not found
682
683 if ((pxstr) && (pstrSearch) && (pstrReplace))
684 {
685 ULONG cSearchLen = pstrSearch->ulLength;
686
687 // can we search this?
688 if ( (*pulOfs < pxstr->ulLength)
689 && (cSearchLen)
690 )
691 {
692 // yes:
693 /* PSZ pFound = strstr(pxstr->psz + *pulOfs,
694 pstrSearch->psz); */
695 PSZ pFound = (PSZ)strhmemfind(pxstr->psz + *pulOfs, // in: haystack
696 pxstr->ulLength - *pulOfs,
697 pstrSearch->psz,
698 cSearchLen,
699 pShiftTable,
700 pfRepeatFind);
701 if (pFound)
702 {
703 // found in buffer from ofs:
704 ULONG cReplaceLen = pstrReplace->ulLength;
705 // can be 0!
706
707 // length of new string
708 ULONG cbNeeded = pxstr->ulLength
709 + cReplaceLen
710 - cSearchLen
711 + 1, // null terminator
712 // offset where pszSearch was found
713 ulFoundOfs = pFound - pxstr->psz;
714
715 // now check if we have enough memory...
716 if (pxstr->cbAllocated < cbNeeded)
717 {
718 // no, we need more memory:
719 // allocate new buffer
720 PSZ pszNew = (PSZ)malloc(cbNeeded);
721
722 if (ulFoundOfs)
723 // "found" was not at the beginning:
724 // copy from beginning up to found-offset
725 memcpy(pszNew,
726 pxstr->psz,
727 ulFoundOfs); // up to "found"
728
729 if (cReplaceLen)
730 {
731 // we have a replacement:
732 // insert it next
733 memcpy(pszNew + ulFoundOfs,
734 pstrReplace->psz,
735 cReplaceLen + 1); // include null terminator
736 }
737
738 // copy rest:
739 // pxstr frontFOUNDtail
740 // 0 1
741 // 01234567890123
742 // ³ ³ ³ ³
743 // ³ ³ ÀÄ ulFoundOfs + cSearchLen = 10
744 // ³ ³ ³
745 // ³ ÀÄ ulFoundOfs = 5
746 // ³ ³
747 // pxstr->ulLength = 14
748 memcpy(pszNew + ulFoundOfs + cReplaceLen,
749 pFound + cSearchLen,
750 // remaining bytes:
751 pxstr->ulLength - ulFoundOfs - cSearchLen // 9
752 + 1); // null terminator
753
754 // replace old buffer with new one
755 free(pxstr->psz);
756 pxstr->psz = pszNew;
757 pxstr->ulLength = cbNeeded - 1;
758 pxstr->cbAllocated = cbNeeded;
759 } // end if (pxstr->cbAllocated < cbNeeded)
760 else
761 {
762 // we have enough memory left,
763 // we can just overwrite in the middle...
764
765 PSZ pszAfterFoundBackup = 0;
766 // calc length of string after "found"
767 ULONG cTailLength = pxstr->ulLength - ulFoundOfs - cSearchLen;
768
769 // if "replace" is longer than "found",
770 // make a backup of the stuff after "found",
771 // or this would get overwritten
772 if (cReplaceLen > cSearchLen)
773 {
774 pszAfterFoundBackup = (PSZ)malloc(cTailLength + 1);
775 memcpy(pszAfterFoundBackup,
776 pFound + cSearchLen,
777 cTailLength + 1);
778 }
779
780 // now overwrite "found" in the middle
781 if (cReplaceLen)
782 {
783 memcpy(pxstr->psz + ulFoundOfs,
784 pstrReplace->psz,
785 cReplaceLen); // no null terminator
786 }
787
788 // now append tail (stuff after "found") again...
789 if (pszAfterFoundBackup)
790 {
791 // we made a backup above:
792 memcpy(pxstr->psz + ulFoundOfs + cReplaceLen,
793 pszAfterFoundBackup,
794 cTailLength + 1);
795 free(pszAfterFoundBackup);
796 // done!
797 }
798 else
799 // no backup:
800 if (cReplaceLen < cSearchLen)
801 // "replace" is shorter than "found:
802 memcpy(pxstr->psz + ulFoundOfs + cReplaceLen,
803 pFound + cSearchLen,
804 cTailLength + 1);
805 // else (cReplaceLen == cSearchLen):
806 // we can leave the tail as it is
807
808 pxstr->ulLength = cbNeeded - 1;
809 }
810
811 // return new length
812 ulrc = cbNeeded - 1;
813 *pulOfs = ulFoundOfs + cReplaceLen;
814 } // end if (pFound)
815 } // end if ( (*pulOfs < pxstr->ulLength) ...
816 } // end if ((pxstr) && (pstrSearch) && (pstrReplace))
817
818 return (ulrc);
819}
820
821/*
822 *@@ xstrcrpl:
823 * wrapper around xstrrpl() which allows using C strings
824 * for the find and replace parameters.
825 *
826 * This creates two temporary XSTRING's for pcszSearch
827 * pcszReplace. As a result, this is slower than xstrrpl.
828 * If you search with the same strings several times,
829 * you'll be better off using xstrrpl() directly.
830 *
831 *@@added V0.9.6 (2000-11-01) [umoeller]
832 */
833
834ULONG xstrcrpl(PXSTRING pxstr, // in/out: string
835 PULONG pulOfs, // in: where to begin search (0 = start);
836 // out: ofs of first char after replacement string
837 const char *pcszSearch, // in: search string; cannot be NULL
838 const char *pcszReplace) // in: replacement string; cannot be NULL
839{
840 // ULONG ulrc = 0;
841 XSTRING xstrFind,
842 xstrReplace;
843 size_t ShiftTable[256];
844 BOOL fRepeat = FALSE;
845 // initialize find/replace strings... note that the
846 // C strings are not free()'able, so we MUST NOT use xstrClear
847 // before leaving
848 xstrInitSet(&xstrFind, (PSZ)pcszSearch);
849 xstrInitSet(&xstrReplace, (PSZ)pcszReplace);
850
851 return (xstrrpl(pxstr, pulOfs, &xstrFind, &xstrReplace, ShiftTable, &fRepeat));
852}
853
854// test case
855
856/* int main(void)
857{
858 XSTRING str,
859 strFind,
860 strReplace;
861 ULONG ulOfs = 0;
862
863 xstrInit(&str, 100);
864 xstrInit(&strFind, 0);
865 xstrInit(&strReplace, 0);
866
867 xstrcpy(&str, "Test string 1. Test string 2. Test string 3. !");
868 xstrcpy(&strFind, "Test");
869 xstrcpy(&strReplace, "Dummy");
870
871 printf("Old string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
872
873 while (xstrrpl(&str,
874 ulOfs,
875 &strFind,
876 &strReplace,
877 &ulOfs))
878 ;
879
880 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
881
882 xstrcpy(&strFind, strReplace.psz);
883 xstrClear(&strReplace);
884 ulOfs = 0;
885 while (xstrrpl(&str,
886 ulOfs,
887 &strFind,
888 &strReplace,
889 &ulOfs))
890 ;
891
892 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
893
894 xstrcpy(&strFind, " ");
895 xstrcpy(&strReplace, ".");
896 ulOfs = 0;
897 while (xstrrpl(&str,
898 ulOfs,
899 &strFind,
900 &strReplace,
901 &ulOfs))
902 ;
903
904 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
905
906 xstrcpy(&strFind, ".");
907 xstrcpy(&strReplace, "***************************");
908 ulOfs = 0;
909 while (xstrrpl(&str,
910 ulOfs,
911 &strFind,
912 &strReplace,
913 &ulOfs))
914 ;
915
916 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
917
918 xstrcpy(&strFind, "*");
919 xstrClear(&strReplace);
920 ulOfs = 0;
921 while (xstrrpl(&str,
922 ulOfs,
923 &strFind,
924 &strReplace,
925 &ulOfs))
926 ;
927
928 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
929} */
930
Note: See TracBrowser for help on using the repository browser.