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

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

Final changes for 0.9.7, i hope...

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