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

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

Tons of updates.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 31.0 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 *@@changed V0.9.7 (2000-12-31) [umoeller]: added ulExtraAllocate
204 */
205
206void xstrInitCopy(PXSTRING pxstr,
207 const char *pcszSource,
208 ULONG ulExtraAllocate) // in: if > 0, extra memory to allocate
209{
210 if (pxstr)
211 {
212 memset(pxstr, 0, sizeof(XSTRING));
213
214 if (pcszSource)
215 pxstr->ulLength = strlen(pcszSource);
216
217 if (pxstr->ulLength)
218 {
219 // we do have a source string:
220 pxstr->cbAllocated = pxstr->ulLength + 1 + ulExtraAllocate;
221 pxstr->psz = (PSZ)malloc(pxstr->cbAllocated);
222 strcpy(pxstr->psz, pcszSource);
223 }
224 }
225}
226
227/*
228 *@@ xstrClear:
229 * clears the specified stack XSTRING and
230 * frees allocated memory.
231 *
232 * This is the reverse to xstrInit.
233 *
234 *@@added V0.9.6 (2000-11-01) [umoeller]
235 */
236
237void xstrClear(PXSTRING pxstr) // in/out: string
238{
239 if (pxstr->psz)
240 free(pxstr->psz);
241 memset(pxstr, 0, sizeof(XSTRING));
242}
243
244/*
245 *@@ xstrCreate:
246 * allocates a new XSTRING from the heap
247 * and calls xstrInit on it.
248 *
249 * Always use xstrFree to free associated
250 * resources.
251 *
252 *@@added V0.9.6 (2000-11-01) [umoeller]
253 */
254
255PXSTRING xstrCreate(ULONG ulPreAllocate)
256{
257 PXSTRING pxstr = (PXSTRING)malloc(sizeof(XSTRING));
258 if (pxstr)
259 xstrInit(pxstr, ulPreAllocate);
260
261 return (pxstr);
262}
263
264/*
265 *@@ xstrFree:
266 * frees the specified heap XSTRING, which must
267 * have been created using xstrCreate.
268 *
269 *@@added V0.9.6 (2000-11-01) [umoeller]
270 */
271
272VOID xstrFree(PXSTRING pxstr) // in/out: string
273{
274 if (pxstr)
275 {
276 xstrClear(pxstr);
277 free(pxstr);
278 }
279}
280
281/*
282 *@@ xstrset:
283 * sets the specified XSTRING to a new string
284 * without copying it.
285 *
286 * pxstr is cleared before the new string is set.
287 *
288 * This ONLY works if pszNew has been allocated from
289 * the heap using malloc() or strdup() and is thus
290 * free()'able.
291 *
292 * This assumes that exactly strlen(pszNew) + 1
293 * bytes have been allocated for pszNew, which
294 * is true if pszNew comes from strdup().
295 *
296 *@@added V0.9.6 (2000-11-01) [umoeller]
297 */
298
299ULONG xstrset(PXSTRING pxstr, // in/out: string
300 PSZ pszNew) // in: heap PSZ to use
301{
302 xstrClear(pxstr);
303 pxstr->psz = pszNew;
304 if (pszNew)
305 {
306 pxstr->ulLength = strlen(pszNew);
307 pxstr->cbAllocated = pxstr->ulLength + 1;
308 }
309 // else null string: cbAllocated and ulLength are 0 already
310
311 return (pxstr->ulLength);
312}
313
314/*
315 *@@ xstrcpy:
316 * copies pcszSource to pxstr, for which memory is allocated
317 * as necessary.
318 *
319 * If pxstr contains something, its contents are destroyed.
320 *
321 * Returns the length of the new string (excluding the null
322 * terminator), or null upon errors.
323 *
324 * Example:
325 *
326 + XSTRING str;
327 + xstrInit(&str, 0);
328 + xstrcpy(&str, "blah");
329 *
330 * This sequence can be abbreviated using xstrInitCopy.
331 *
332 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcpy
333 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
334 */
335
336ULONG xstrcpy(PXSTRING pxstr, // in/out: string
337 const char *pcszSource) // in: source, can be NULL
338{
339 xstrClear(pxstr);
340
341 if (pxstr)
342 {
343 ULONG ulSourceLength = 0;
344 if (pcszSource)
345 ulSourceLength = strlen(pcszSource);
346
347 if (ulSourceLength)
348 {
349 // we do have a source string:
350 ULONG cbNeeded = ulSourceLength + 1;
351 if (cbNeeded > pxstr->cbAllocated)
352 {
353 // we need more memory than we have previously
354 // allocated:
355 pxstr->cbAllocated = cbNeeded;
356 pxstr->psz = (PSZ)malloc(cbNeeded);
357 }
358 // else: we have enough memory
359
360 strcpy(pxstr->psz, pcszSource);
361 }
362 else
363 {
364 // no source specified or source is empty:
365 if (pxstr->cbAllocated)
366 // we did have a string: set to empty,
367 // but leave allocated memory intact
368 *(pxstr->psz) = 0;
369 // else: pxstr->psz is still NULL
370 }
371
372 // in all cases, set new length
373 pxstr->ulLength = ulSourceLength;
374 }
375
376 return (pxstr->ulLength);
377}
378
379/*
380 *@@ xstrcat:
381 * appends pcszSource to pxstr, for which memory is
382 * reallocated if necessary.
383 *
384 * If pxstr is empty, this behaves just like xstrcpy.
385 *
386 * Returns the length of the new string (excluding the null
387 * terminator) if the string was changed, or 0 if nothing
388 * happened.
389 *
390 * Note: To append a single character, xstrcatc is faster
391 * than xstrcat.
392 *
393 * Example:
394 *
395 + XSTRING str;
396 + xstrInit(&str, 0);
397 + xstrcpy(&str, "blah");
398 + xstrcat(&str, "blup");
399 *
400 * After this, str.psz points to a new string containing
401 * "blahblup".
402 *
403 *@@changed V0.9.1 (99-12-20) [umoeller]: fixed memory leak
404 *@@changed V0.9.1 (2000-01-03) [umoeller]: crashed if pszString was null; fixed
405 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcat
406 *@@changed V0.9.3 (2000-05-11) [umoeller]: returned 0 if pszString was initially empty; fixed
407 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
408 *@@changed V0.9.7 (2000-12-10) [umoeller]: return value was wrong
409 */
410
411ULONG xstrcat(PXSTRING pxstr, // in/out: string
412 const char *pcszSource) // in: source, can be NULL
413{
414 ULONG ulrc = 0;
415
416 if (pxstr)
417 {
418 ULONG ulSourceLength = 0;
419 if (pcszSource)
420 ulSourceLength = strlen(pcszSource);
421
422 if (ulSourceLength)
423 {
424 // we do have a source string:
425
426 // 1) memory management
427 ULONG cbNeeded = pxstr->ulLength + ulSourceLength + 1;
428 if (cbNeeded > pxstr->cbAllocated)
429 {
430 // we need more memory than we have previously
431 // allocated:
432 if (pxstr->cbAllocated)
433 // appendee already had memory:
434 // reallocate
435 pxstr->psz = (PSZ)realloc(pxstr->psz,
436 cbNeeded);
437 else
438 // appendee has no memory:
439 pxstr->psz = (PSZ)malloc(cbNeeded);
440
441 pxstr->cbAllocated = cbNeeded;
442 // ulLength is unchanged yet
443 }
444 // else: we have enough memory, both if appendee
445 // is empty or not empty
446
447 // now we have:
448 // -- if appendee (pxstr) had enough memory, no problem
449 // -- if appendee (pxstr) needed more memory
450 // -- and was not empty: pxstr->psz now points to a
451 // reallocated copy of the old string
452 // -- and was empty: pxstr->psz now points to a
453 // new (unitialized) buffer
454
455 // 2) append source string:
456 memcpy(pxstr->psz + pxstr->ulLength,
457 pcszSource,
458 ulSourceLength + 1); // null terminator
459
460 // in all cases, set new length
461 pxstr->ulLength += ulSourceLength;
462 ulrc = pxstr->ulLength; // V0.9.7 (2000-12-10) [umoeller]
463
464 } // end if (ulSourceLength)
465 // else no source specified or source is empty:
466 // do nothing
467 }
468
469 return (ulrc);
470}
471
472/*
473 *@@ xstrcatc:
474 * this is similar to xstrcat, except that this is
475 * for a single character. This is a bit faster than
476 * xstrcat.
477 *
478 * If "c" is \0, nothing happens.
479 *
480 * If pxstr is empty, this behaves just like xstrcpy.
481 *
482 * Returns the length of the new string (excluding the null
483 * terminator) if the string was changed, or 0 if nothing
484 * happened.
485 *
486 * Example:
487 *
488 + XSTRING str;
489 + xstrInit(&str, 0);
490 + xstrcpy(&str, "blu");
491 + xstrcatc(&str, 'p');
492 *
493 * After this, str.psz points to a new string containing
494 * "blup".
495 *
496 *@@added V0.9.7 (2000-12-10) [umoeller]
497 */
498
499ULONG xstrcatc(PXSTRING pxstr, // in/out: string
500 CHAR c) // in: character to append, can be \0
501{
502 ULONG ulrc = 0;
503
504 if ((pxstr) && (c))
505 {
506 // ULONG ulSourceLength = 1;
507 // 1) memory management
508 ULONG cbNeeded = pxstr->ulLength // existing length, without null terminator
509 + 1 // new character
510 + 1; // null terminator
511 if (cbNeeded > pxstr->cbAllocated)
512 {
513 // we need more memory than we have previously
514 // allocated:
515 if (pxstr->cbAllocated)
516 // appendee already had memory:
517 // reallocate
518 pxstr->psz = (PSZ)realloc(pxstr->psz,
519 cbNeeded);
520 else
521 // appendee has no memory:
522 pxstr->psz = (PSZ)malloc(cbNeeded);
523
524 pxstr->cbAllocated = cbNeeded;
525 // ulLength is unchanged yet
526 }
527 // else: we have enough memory, both if appendee
528 // is empty or not empty
529
530 // now we have:
531 // -- if appendee (pxstr) had enough memory, no problem
532 // -- if appendee (pxstr) needed more memory
533 // -- and was not empty: pxstr->psz now points to a
534 // reallocated copy of the old string
535 // -- and was empty: pxstr->psz now points to a
536 // new (unitialized) buffer
537
538 // 2) append character:
539 pxstr->psz[pxstr->ulLength] = c;
540 pxstr->psz[pxstr->ulLength + 1] = '\0';
541
542 // in all cases, set new length
543 pxstr->ulLength++;
544 ulrc = pxstr->ulLength;
545
546 } // end if ((pxstr) && (c))
547
548 return (ulrc);
549}
550
551/*
552 *@@ xstrFindWord:
553 * searches for pstrFind in pxstr, starting at ulOfs.
554 * However, this only finds pstrFind if it's a "word",
555 * i.e. surrounded by one of the characters in the
556 * pcszBeginChars and pcszEndChars array.
557 *
558 * This is similar to strhFindWord, but this uses
559 * strhmemfind for fast searching, and it doesn't
560 * have to calculate the string lengths because these
561 * already in XSTRING.
562 *
563 * Returns 0 if no "word" was found, or the offset
564 * of the "word" in pxstr if found.
565 *
566 *@@added V0.9.6 (2000-11-12) [umoeller]
567 */
568
569PSZ xstrFindWord(const XSTRING *pxstr, // in: buffer to search ("haystack")
570 ULONG ulOfs, // in: where to begin search (0 = start)
571 const XSTRING *pstrFind, // in: word to find ("needle")
572 size_t *pShiftTable, // in: shift table (see strhmemfind)
573 PBOOL pfRepeatFind, // in: repeat find? (see strhmemfind)
574 const char *pcszBeginChars, // suggestion: "\x0d\x0a ()/\\-,."
575 const char *pcszEndChars) // suggestion: "\x0d\x0a ()/\\-,.:;"
576{
577 PSZ pReturn = 0;
578 ULONG ulFoundLen = pstrFind->ulLength;
579
580 if ((pxstr->ulLength) && (ulFoundLen))
581 {
582 const char *p = pxstr->psz + ulOfs;
583
584 do // while p
585 {
586 // p = strstr(p, pstrFind->psz);
587 p = (PSZ)strhmemfind(p, // in: haystack
588 pxstr->ulLength - (p - pxstr->psz),
589 // remaining length of haystack
590 pstrFind->psz,
591 ulFoundLen,
592 pShiftTable,
593 pfRepeatFind);
594 if (p)
595 {
596 // string found:
597 // check if that's a word
598
599 if (strhIsWord(pxstr->psz,
600 p,
601 ulFoundLen,
602 pcszBeginChars,
603 pcszEndChars))
604 {
605 // valid end char:
606 pReturn = (PSZ)p;
607 break;
608 }
609
610 p += ulFoundLen;
611 }
612 } while (p);
613
614 }
615 return (pReturn);
616}
617
618/*
619 *@@ xstrrpl:
620 * replaces the first occurence of pstrSearch with
621 * pstrReplace in pxstr.
622 *
623 * Starting with V0.9.6, this operates entirely on
624 * XSTRING's for speed because we then know the string
625 * lengths already and can use memcpy instead of strcpy.
626 * This new version should be magnitudes faster,
627 * especially with large string bufffers.
628 *
629 * None of the pointers can be NULL, but if pstrReplace
630 * is empty, this effectively erases pstrSearch in pxstr.
631 *
632 * Returns the length of the new string (exclusing the
633 * null terminator) or 0 if pszSearch was not found
634 * (and pxstr was therefore not changed).
635 *
636 * This starts the search at *pulOffset. If
637 * (*pulOffset == 0), this starts from the beginning
638 * of pxstr.
639 * If the string was found, *pulOffset will be set to the
640 * first character after the new replacement string. This
641 * allows you to call this func again with the same strings
642 * to have several occurences replaced (see the example below).
643 *
644 * There are two wrappers around this function which
645 * work on C strings instead (however, thus losing the
646 * speed advantage):
647 *
648 * -- strhrpl operates on C strings only;
649 *
650 * -- xstrcrpl uses C strings for the search and replace
651 * parameters.
652 *
653 * <B>Example usage:</B>
654 *
655 + XSTRING str;
656 + ULONG ulOffset = 0;
657 + xstrInit(&str, 0);
658 + xstrcpy(&str, "Test phrase 1. Test phrase 2.");
659 + while (xstrrpl(&str,
660 + &ulPos, // in/out: offset
661 + "Test", // search
662 + "Dummy") // replace
663 + ;
664 *
665 * would replace all occurences of "Test" in str with
666 * "Dummy".
667 *
668 *@@changed V0.9.0 [umoeller]: totally rewritten.
669 *@@changed V0.9.0 (99-11-08) [umoeller]: crashed if *ppszBuf was NULL. Fixed.
670 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxrpl
671 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
672 *@@changed V0.9.6 (2000-11-12) [umoeller]: now using strhmemfind
673 */
674
675ULONG xstrrpl(PXSTRING pxstr, // in/out: string
676 PULONG pulOfs, // in: where to begin search (0 = start);
677 // out: ofs of first char after replacement string
678 const XSTRING *pstrSearch, // in: search string; cannot be NULL
679 const XSTRING *pstrReplace, // in: replacement string; cannot be NULL
680 size_t *pShiftTable, // in: shift table (see strhmemfind)
681 PBOOL pfRepeatFind) // in: repeat find? (see strhmemfind)
682{
683 ULONG ulrc = 0; // default: not found
684
685 if ((pxstr) && (pstrSearch) && (pstrReplace))
686 {
687 ULONG cSearchLen = pstrSearch->ulLength;
688
689 // can we search this?
690 if ( (*pulOfs < pxstr->ulLength)
691 && (cSearchLen)
692 )
693 {
694 // yes:
695 /* PSZ pFound = strstr(pxstr->psz + *pulOfs,
696 pstrSearch->psz); */
697 PSZ pFound = (PSZ)strhmemfind(pxstr->psz + *pulOfs, // in: haystack
698 pxstr->ulLength - *pulOfs,
699 pstrSearch->psz,
700 cSearchLen,
701 pShiftTable,
702 pfRepeatFind);
703 if (pFound)
704 {
705 // found in buffer from ofs:
706 ULONG cReplaceLen = pstrReplace->ulLength;
707 // can be 0!
708
709 // length of new string
710 ULONG cbNeeded = pxstr->ulLength
711 + cReplaceLen
712 - cSearchLen
713 + 1, // null terminator
714 // offset where pszSearch was found
715 ulFoundOfs = pFound - pxstr->psz;
716
717 // now check if we have enough memory...
718 if (pxstr->cbAllocated < cbNeeded)
719 {
720 // no, we need more memory:
721 // allocate new buffer
722 PSZ pszNew = (PSZ)malloc(cbNeeded);
723
724 if (ulFoundOfs)
725 // "found" was not at the beginning:
726 // copy from beginning up to found-offset
727 memcpy(pszNew,
728 pxstr->psz,
729 ulFoundOfs); // up to "found"
730
731 if (cReplaceLen)
732 {
733 // we have a replacement:
734 // insert it next
735 memcpy(pszNew + ulFoundOfs,
736 pstrReplace->psz,
737 cReplaceLen + 1); // include null terminator
738 }
739
740 // copy rest:
741 // pxstr frontFOUNDtail
742 // 0 1
743 // 01234567890123
744 // ³ ³ ³ ³
745 // ³ ³ ÀÄ ulFoundOfs + cSearchLen = 10
746 // ³ ³ ³
747 // ³ ÀÄ ulFoundOfs = 5
748 // ³ ³
749 // pxstr->ulLength = 14
750 memcpy(pszNew + ulFoundOfs + cReplaceLen,
751 pFound + cSearchLen,
752 // remaining bytes:
753 pxstr->ulLength - ulFoundOfs - cSearchLen // 9
754 + 1); // null terminator
755
756 // replace old buffer with new one
757 free(pxstr->psz);
758 pxstr->psz = pszNew;
759 pxstr->ulLength = cbNeeded - 1;
760 pxstr->cbAllocated = cbNeeded;
761 } // end if (pxstr->cbAllocated < cbNeeded)
762 else
763 {
764 // we have enough memory left,
765 // we can just overwrite in the middle...
766
767 PSZ pszAfterFoundBackup = 0;
768 // calc length of string after "found"
769 ULONG cTailLength = pxstr->ulLength - ulFoundOfs - cSearchLen;
770
771 // if "replace" is longer than "found",
772 // make a backup of the stuff after "found",
773 // or this would get overwritten
774 if (cReplaceLen > cSearchLen)
775 {
776 pszAfterFoundBackup = (PSZ)malloc(cTailLength + 1);
777 memcpy(pszAfterFoundBackup,
778 pFound + cSearchLen,
779 cTailLength + 1);
780 }
781
782 // now overwrite "found" in the middle
783 if (cReplaceLen)
784 {
785 memcpy(pxstr->psz + ulFoundOfs,
786 pstrReplace->psz,
787 cReplaceLen); // no null terminator
788 }
789
790 // now append tail (stuff after "found") again...
791 if (pszAfterFoundBackup)
792 {
793 // we made a backup above:
794 memcpy(pxstr->psz + ulFoundOfs + cReplaceLen,
795 pszAfterFoundBackup,
796 cTailLength + 1);
797 free(pszAfterFoundBackup);
798 // done!
799 }
800 else
801 // no backup:
802 if (cReplaceLen < cSearchLen)
803 // "replace" is shorter than "found:
804 memcpy(pxstr->psz + ulFoundOfs + cReplaceLen,
805 pFound + cSearchLen,
806 cTailLength + 1);
807 // else (cReplaceLen == cSearchLen):
808 // we can leave the tail as it is
809
810 pxstr->ulLength = cbNeeded - 1;
811 }
812
813 // return new length
814 ulrc = cbNeeded - 1;
815 *pulOfs = ulFoundOfs + cReplaceLen;
816 } // end if (pFound)
817 } // end if ( (*pulOfs < pxstr->ulLength) ...
818 } // end if ((pxstr) && (pstrSearch) && (pstrReplace))
819
820 return (ulrc);
821}
822
823/*
824 *@@ xstrcrpl:
825 * wrapper around xstrrpl() which allows using C strings
826 * for the find and replace parameters.
827 *
828 * This creates two temporary XSTRING's for pcszSearch
829 * pcszReplace. As a result, this is slower than xstrrpl.
830 * If you search with the same strings several times,
831 * you'll be better off using xstrrpl() directly.
832 *
833 *@@added V0.9.6 (2000-11-01) [umoeller]
834 */
835
836ULONG xstrcrpl(PXSTRING pxstr, // in/out: string
837 PULONG pulOfs, // in: where to begin search (0 = start);
838 // out: ofs of first char after replacement string
839 const char *pcszSearch, // in: search string; cannot be NULL
840 const char *pcszReplace) // in: replacement string; cannot be NULL
841{
842 // ULONG ulrc = 0;
843 XSTRING xstrFind,
844 xstrReplace;
845 size_t ShiftTable[256];
846 BOOL fRepeat = FALSE;
847 // initialize find/replace strings... note that the
848 // C strings are not free()'able, so we MUST NOT use xstrClear
849 // before leaving
850 xstrInitSet(&xstrFind, (PSZ)pcszSearch);
851 xstrInitSet(&xstrReplace, (PSZ)pcszReplace);
852
853 return (xstrrpl(pxstr, pulOfs, &xstrFind, &xstrReplace, ShiftTable, &fRepeat));
854}
855
856// test case
857
858/* int main(void)
859{
860 XSTRING str,
861 strFind,
862 strReplace;
863 ULONG ulOfs = 0;
864
865 xstrInit(&str, 100);
866 xstrInit(&strFind, 0);
867 xstrInit(&strReplace, 0);
868
869 xstrcpy(&str, "Test string 1. Test string 2. Test string 3. !");
870 xstrcpy(&strFind, "Test");
871 xstrcpy(&strReplace, "Dummy");
872
873 printf("Old string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
874
875 while (xstrrpl(&str,
876 ulOfs,
877 &strFind,
878 &strReplace,
879 &ulOfs))
880 ;
881
882 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
883
884 xstrcpy(&strFind, strReplace.psz);
885 xstrClear(&strReplace);
886 ulOfs = 0;
887 while (xstrrpl(&str,
888 ulOfs,
889 &strFind,
890 &strReplace,
891 &ulOfs))
892 ;
893
894 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
895
896 xstrcpy(&strFind, " ");
897 xstrcpy(&strReplace, ".");
898 ulOfs = 0;
899 while (xstrrpl(&str,
900 ulOfs,
901 &strFind,
902 &strReplace,
903 &ulOfs))
904 ;
905
906 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
907
908 xstrcpy(&strFind, ".");
909 xstrcpy(&strReplace, "***************************");
910 ulOfs = 0;
911 while (xstrrpl(&str,
912 ulOfs,
913 &strFind,
914 &strReplace,
915 &ulOfs))
916 ;
917
918 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
919
920 xstrcpy(&strFind, "*");
921 xstrClear(&strReplace);
922 ulOfs = 0;
923 while (xstrrpl(&str,
924 ulOfs,
925 &strFind,
926 &strReplace,
927 &ulOfs))
928 ;
929
930 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
931} */
932
Note: See TracBrowser for help on using the repository browser.