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

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

Fixes for V0.9.7.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 38.1 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 * With ulSourceLength, specify the length of pcszSource.
373 * If you specify 0, this function will run strlen(pcszSource)
374 * itself. If you already know the length of pcszSource (or
375 * only want to copy a substring), you can speed this function
376 * up a bit this way.
377 *
378 * Returns the length of the new string (excluding the null
379 * terminator), or null upon errors.
380 *
381 * Example:
382 *
383 + XSTRING str;
384 + xstrInit(&str, 0);
385 + xstrcpy(&str, "blah", 0);
386 *
387 * This sequence can be abbreviated using xstrInitCopy.
388 *
389 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcpy
390 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
391 *@@changed V0.9.7 (2001-01-15) [umoeller]: added ulSourceLength
392 */
393
394ULONG xstrcpy(PXSTRING pxstr, // in/out: string
395 const char *pcszSource, // in: source, can be NULL
396 ULONG ulSourceLength) // in: length of pcszSource or 0
397{
398 // xstrClear(pxstr); NOOOO! this frees the string, we want to keep the memory
399
400 if (pxstr)
401 {
402 if (pcszSource)
403 {
404 if (ulSourceLength == 0)
405 ulSourceLength = strlen(pcszSource);
406
407 if (ulSourceLength)
408 {
409 // we do have a source string:
410 ULONG cbNeeded = ulSourceLength + 1;
411 if (cbNeeded > pxstr->cbAllocated)
412 {
413 // we need more memory than we have previously
414 // allocated:
415 pxstr->cbAllocated = cbNeeded;
416 pxstr->psz = (PSZ)malloc(cbNeeded);
417 }
418 // else: we have enough memory
419
420 // strcpy(pxstr->psz, pcszSource);
421 memcpy(pxstr->psz,
422 pcszSource,
423 ulSourceLength);
424 *(pxstr->psz + ulSourceLength) = 0;
425 }
426 else
427 {
428 // no source specified or source is empty:
429 if (pxstr->cbAllocated)
430 // we did have a string: set to empty,
431 // but leave allocated memory intact
432 *(pxstr->psz) = 0;
433 // else: pxstr->psz is still NULL
434 }
435
436 // in all cases, set new length
437 pxstr->ulLength = ulSourceLength;
438 }
439 }
440
441 return (pxstr->ulLength);
442}
443
444/*
445 *@@ xstrcat:
446 * appends pcszSource to pxstr, for which memory is
447 * reallocated if necessary.
448 *
449 * If pxstr is empty, this behaves just like xstrcpy.
450 *
451 * With ulSourceLength, specify the length of pcszSource.
452 * If you specify 0, this function will run strlen(pcszSource)
453 * itself. If you already know the length of pcszSource (or
454 * only want to copy a substring), you can speed this function
455 * up a bit this way.
456 *
457 * Returns the length of the new string (excluding the null
458 * terminator) if the string was changed, or 0 if nothing
459 * happened.
460 *
461 * Note: To append a single character, xstrcatc is faster
462 * than xstrcat.
463 *
464 * Example:
465 *
466 + XSTRING str;
467 + xstrInit(&str, 0);
468 + xstrcpy(&str, "blah", 0);
469 + xstrcat(&str, "blup", 0);
470 *
471 * After this, str.psz points to a new string containing
472 * "blahblup".
473 *
474 *@@changed V0.9.1 (99-12-20) [umoeller]: fixed memory leak
475 *@@changed V0.9.1 (2000-01-03) [umoeller]: crashed if pszString was null; fixed
476 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcat
477 *@@changed V0.9.3 (2000-05-11) [umoeller]: returned 0 if pszString was initially empty; fixed
478 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
479 *@@changed V0.9.7 (2000-12-10) [umoeller]: return value was wrong
480 *@@changed V0.9.7 (2001-01-15) [umoeller]: added ulSourceLength
481 */
482
483ULONG xstrcat(PXSTRING pxstr, // in/out: string
484 const char *pcszSource, // in: source, can be NULL
485 ULONG ulSourceLength) // in: length of pcszSource or 0
486{
487 ULONG ulrc = 0;
488
489 if (pxstr)
490 {
491 if (pcszSource)
492 {
493 if (ulSourceLength == 0)
494 ulSourceLength = strlen(pcszSource);
495
496 if (ulSourceLength)
497 {
498 // we do have a source string:
499
500 // 1) memory management
501 ULONG cbNeeded = pxstr->ulLength + ulSourceLength + 1;
502 if (cbNeeded > pxstr->cbAllocated)
503 {
504 // we need more memory than we have previously
505 // allocated:
506 if (pxstr->cbAllocated)
507 // appendee already had memory:
508 // reallocate
509 pxstr->psz = (PSZ)realloc(pxstr->psz,
510 cbNeeded);
511 else
512 // appendee has no memory:
513 pxstr->psz = (PSZ)malloc(cbNeeded);
514
515 pxstr->cbAllocated = cbNeeded;
516 // ulLength is unchanged yet
517 }
518 // else: we have enough memory, both if appendee
519 // is empty or not empty
520
521 // now we have:
522 // -- if appendee (pxstr) had enough memory, no problem
523 // -- if appendee (pxstr) needed more memory
524 // -- and was not empty: pxstr->psz now points to a
525 // reallocated copy of the old string
526 // -- and was empty: pxstr->psz now points to a
527 // new (unitialized) buffer
528
529 // 2) append source string:
530 memcpy(pxstr->psz + pxstr->ulLength,
531 pcszSource,
532 ulSourceLength + 1); // null terminator
533
534 // in all cases, set new length
535 pxstr->ulLength += ulSourceLength;
536 ulrc = pxstr->ulLength; // V0.9.7 (2000-12-10) [umoeller]
537
538 } // end if (ulSourceLength)
539 }
540
541 // else no source specified or source is empty:
542 // do nothing
543 }
544
545 return (ulrc);
546}
547
548/*
549 *@@ xstrcatc:
550 * this is similar to xstrcat, except that this is
551 * for a single character. This is a bit faster than
552 * xstrcat.
553 *
554 * If "c" is \0, nothing happens.
555 *
556 * If pxstr is empty, this behaves just like xstrcpy.
557 *
558 * Returns the length of the new string (excluding the null
559 * terminator) if the string was changed, or 0 if nothing
560 * happened.
561 *
562 * Example:
563 *
564 + XSTRING str;
565 + xstrInit(&str, 0);
566 + xstrcpy(&str, "blu");
567 + xstrcatc(&str, 'p');
568 *
569 * After this, str.psz points to a new string containing
570 * "blup".
571 *
572 *@@added V0.9.7 (2000-12-10) [umoeller]
573 */
574
575ULONG xstrcatc(PXSTRING pxstr, // in/out: string
576 CHAR c) // in: character to append, can be \0
577{
578 ULONG ulrc = 0;
579
580 if ((pxstr) && (c))
581 {
582 // ULONG ulSourceLength = 1;
583 // 1) memory management
584 ULONG cbNeeded = pxstr->ulLength // existing length, without null terminator
585 + 1 // new character
586 + 1; // null terminator
587 if (cbNeeded > pxstr->cbAllocated)
588 {
589 // we need more memory than we have previously
590 // allocated:
591 if (pxstr->cbAllocated)
592 // appendee already had memory:
593 // reallocate
594 pxstr->psz = (PSZ)realloc(pxstr->psz,
595 cbNeeded);
596 else
597 // appendee has no memory:
598 pxstr->psz = (PSZ)malloc(cbNeeded);
599
600 pxstr->cbAllocated = cbNeeded;
601 // ulLength is unchanged yet
602 }
603 // else: we have enough memory, both if appendee
604 // is empty or not empty
605
606 // now we have:
607 // -- if appendee (pxstr) had enough memory, no problem
608 // -- if appendee (pxstr) needed more memory
609 // -- and was not empty: pxstr->psz now points to a
610 // reallocated copy of the old string
611 // -- and was empty: pxstr->psz now points to a
612 // new (unitialized) buffer
613
614 // 2) append character:
615 pxstr->psz[pxstr->ulLength] = c;
616 pxstr->psz[pxstr->ulLength + 1] = '\0';
617
618 // in all cases, set new length
619 pxstr->ulLength++;
620 ulrc = pxstr->ulLength;
621
622 } // end if ((pxstr) && (c))
623
624 return (ulrc);
625}
626
627/*
628 *@@ xstrrpl:
629 * replaces cSearchLen characters in pxstr, starting
630 * at the position ulStart, with the string
631 * in pxstrReplaceWith.
632 *
633 * Returns the new length of the string, excluding
634 * the null terminator, or 0 if the replacement failed
635 * (e.g. because the offsets were too large).
636 *
637 * This has been extracted from xstrFindReplace because
638 * if you already know the position of a substring,
639 * you can now call this directly. This properly
640 * reallocates the string if more memory is needed.
641 *
642 * Example:
643 *
644 + XSTRING xstr, xstrReplacement;
645 + xstrInitCopy(&xstr, "This is a test string.");
646 + // positions: 0123456789012345678901
647 + // 1 2
648 +
649 + xstrInitCopy(&xstrReplacement, "stupid");
650 +
651 + xstrrpl(&xstr,
652 + 10, // position of "test"
653 + 4, // length of "test"
654 + &xstrReplacement);
655 *
656 * This would yield "This is a stupid string."
657 *
658 *@@added V0.9.7 (2001-01-15) [umoeller]
659 */
660
661ULONG xstrrpl(PXSTRING pxstr, // in/out: string
662 ULONG ulFirstReplOfs, // in: ofs of first char to replace
663 ULONG cReplLen, // in: no. of chars to replace
664 const XSTRING *pstrReplaceWith) // in: string to replace chars with
665{
666 ULONG ulrc = 0;
667
668 // security checks...
669 if ( (ulFirstReplOfs + cReplLen <= pxstr->ulLength)
670 && (pstrReplaceWith)
671 // && (pstrReplaceWith->ulLength) no, this can be empty
672 )
673 {
674 ULONG cReplaceLen = pstrReplaceWith->ulLength;
675 // can be 0!
676
677 // length of new string
678 ULONG cbNeeded = pxstr->ulLength
679 + cReplaceLen
680 - cReplLen
681 + 1; // null terminator
682 // offset where pszSearch was found
683 // ulFirstReplOfs = pFound - pxstr->psz; now ulFirstReplOfs
684 PSZ pFound = pxstr->psz + ulFirstReplOfs;
685
686 // now check if we have enough memory...
687 if (pxstr->cbAllocated < cbNeeded)
688 {
689 // no, we need more memory:
690 // allocate new buffer
691 PSZ pszNew = (PSZ)malloc(cbNeeded);
692
693 if (ulFirstReplOfs)
694 // "found" was not at the beginning:
695 // copy from beginning up to found-offset
696 memcpy(pszNew,
697 pxstr->psz,
698 ulFirstReplOfs); // up to "found"
699
700 if (cReplaceLen)
701 {
702 // we have a replacement:
703 // insert it next
704 memcpy(pszNew + ulFirstReplOfs,
705 pstrReplaceWith->psz,
706 cReplaceLen + 1); // include null terminator
707 }
708
709 // copy rest:
710 // pxstr frontFOUNDtail
711 // 0 1
712 // 01234567890123
713 // ³ ³ ³ ³
714 // ³ ³ ÀÄ ulFirstReplOfs + cReplLen = 10
715 // ³ ³ ³
716 // ³ ÀÄ ulFirstReplOfs = 5
717 // ³ ³
718 // pxstr->ulLength = 14
719 memcpy(pszNew + ulFirstReplOfs + cReplaceLen,
720 pFound + cReplLen,
721 // remaining bytes:
722 pxstr->ulLength - ulFirstReplOfs - cReplLen // 9
723 + 1); // null terminator
724
725 // replace old buffer with new one
726 free(pxstr->psz);
727 pxstr->psz = pszNew;
728 pxstr->ulLength = cbNeeded - 1;
729 pxstr->cbAllocated = cbNeeded;
730 } // end if (pxstr->cbAllocated < cbNeeded)
731 else
732 {
733 // we have enough memory left,
734 // we can just overwrite in the middle...
735
736 PSZ pszAfterFoundBackup = 0;
737 // calc length of string after "found"
738 ULONG cTailLength = pxstr->ulLength - ulFirstReplOfs - cReplLen;
739
740 // if "replace" is longer than "found",
741 // make a backup of the stuff after "found",
742 // or this would get overwritten
743 if (cReplaceLen > cReplLen)
744 {
745 pszAfterFoundBackup = (PSZ)malloc(cTailLength + 1);
746 memcpy(pszAfterFoundBackup,
747 pFound + cReplLen,
748 cTailLength + 1);
749 }
750
751 // now overwrite "found" in the middle
752 if (cReplaceLen)
753 {
754 memcpy(pxstr->psz + ulFirstReplOfs,
755 pstrReplaceWith->psz,
756 cReplaceLen); // no null terminator
757 }
758
759 // now append tail (stuff after "found") again...
760 if (pszAfterFoundBackup)
761 {
762 // we made a backup above:
763 memcpy(pxstr->psz + ulFirstReplOfs + cReplaceLen,
764 pszAfterFoundBackup,
765 cTailLength + 1);
766 free(pszAfterFoundBackup);
767 // done!
768 }
769 else
770 // no backup:
771 if (cReplaceLen < cReplLen)
772 // "replace" is shorter than "found:
773 memcpy(pxstr->psz + ulFirstReplOfs + cReplaceLen,
774 pFound + cReplLen,
775 cTailLength + 1);
776 // else (cReplaceLen == cReplLen):
777 // we can leave the tail as it is
778
779 pxstr->ulLength = cbNeeded - 1;
780 }
781
782 ulrc = cbNeeded - 1;
783 } // end checks
784
785 return (ulrc);
786}
787
788/*
789 *@@ xstrFindWord:
790 * searches for pstrFind in pxstr, starting at ulOfs.
791 * However, this only finds pstrFind if it's a "word",
792 * i.e. surrounded by one of the characters in the
793 * pcszBeginChars and pcszEndChars array.
794 *
795 * This is similar to strhFindWord, but this uses
796 * strhmemfind for fast searching, and it doesn't
797 * have to calculate the string lengths because these
798 * already in XSTRING.
799 *
800 * Returns 0 if no "word" was found, or the offset
801 * of the "word" in pxstr if found.
802 *
803 *@@added V0.9.6 (2000-11-12) [umoeller]
804 */
805
806PSZ xstrFindWord(const XSTRING *pxstr, // in: buffer to search ("haystack")
807 ULONG ulOfs, // in: where to begin search (0 = start)
808 const XSTRING *pstrFind, // in: word to find ("needle")
809 size_t *pShiftTable, // in: shift table (see strhmemfind)
810 PBOOL pfRepeatFind, // in: repeat find? (see strhmemfind)
811 const char *pcszBeginChars, // suggestion: "\x0d\x0a ()/\\-,."
812 const char *pcszEndChars) // suggestion: "\x0d\x0a ()/\\-,.:;"
813{
814 PSZ pReturn = 0;
815 ULONG ulFoundLen = pstrFind->ulLength;
816
817 if ((pxstr->ulLength) && (ulFoundLen))
818 {
819 const char *p = pxstr->psz + ulOfs;
820
821 do // while p
822 {
823 // p = strstr(p, pstrFind->psz);
824 p = (PSZ)strhmemfind(p, // in: haystack
825 pxstr->ulLength - (p - pxstr->psz),
826 // remaining length of haystack
827 pstrFind->psz,
828 ulFoundLen,
829 pShiftTable,
830 pfRepeatFind);
831 if (p)
832 {
833 // string found:
834 // check if that's a word
835
836 if (strhIsWord(pxstr->psz,
837 p,
838 ulFoundLen,
839 pcszBeginChars,
840 pcszEndChars))
841 {
842 // valid end char:
843 pReturn = (PSZ)p;
844 break;
845 }
846
847 p += ulFoundLen;
848 }
849 } while (p);
850
851 }
852 return (pReturn);
853}
854
855/*
856 *@@ xstrFindReplace:
857 * replaces the first occurence of pstrSearch with
858 * pstrReplace in pxstr.
859 *
860 * Starting with V0.9.6, this operates entirely on
861 * XSTRING's for speed because we then know the string
862 * lengths already and can use memcpy instead of strcpy.
863 * This new version should be magnitudes faster,
864 * especially with large string bufffers.
865 *
866 * None of the pointers can be NULL, but if pstrReplace
867 * is empty, this effectively erases pstrSearch in pxstr.
868 *
869 * Returns the length of the new string (exclusing the
870 * null terminator) or 0 if pszSearch was not found
871 * (and pxstr was therefore not changed).
872 *
873 * This starts the search at *pulOffset. If
874 * (*pulOffset == 0), this starts from the beginning
875 * of pxstr.
876 *
877 * If the string was found, *pulOffset will be set to the
878 * first character after the new replacement string. This
879 * allows you to call this func again with the same strings
880 * to have several occurences replaced (see the example below).
881 *
882 * There are two wrappers around this function which
883 * work on C strings instead (however, thus losing the
884 * speed advantage):
885 *
886 * -- strhFindReplace operates on C strings only;
887 *
888 * -- xstrFindReplaceC uses C strings for the search and replace
889 * parameters.
890 *
891 * <B>Example usage:</B>
892 *
893 + XSTRING strBuf,
894 + strFind,
895 + strRepl;
896 + size_t ShiftTable[256];
897 + BOOL fRepeat = FALSE;
898 + ULONG ulOffset = 0;
899 +
900 + xstrInitCopy(&strBuf, "Test phrase 1. Test phrase 2.", 0);
901 + xstrInitSet(&strFind, "Test");
902 + xstrInitSet(&strRepl, "Dummy");
903 + while (xstrFindReplace(&str,
904 + &ulPos, // in/out: offset
905 + &strFind, // search
906 + &strRepl, // replace
907 + ShiftTable,
908 + &fRepeat))
909 + ;
910 *
911 * would replace all occurences of "Test" in str with
912 * "Dummy".
913 *
914 *@@changed V0.9.0 [umoeller]: totally rewritten.
915 *@@changed V0.9.0 (99-11-08) [umoeller]: crashed if *ppszBuf was NULL. Fixed.
916 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxrpl
917 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
918 *@@changed V0.9.6 (2000-11-12) [umoeller]: now using strhmemfind
919 *@@changed V0.9.7 (2001-01-15) [umoeller]: renamed from xstrrpl; extracted new xstrrpl
920 */
921
922ULONG xstrFindReplace(PXSTRING pxstr, // in/out: string
923 PULONG pulOfs, // in: where to begin search (0 = start);
924 // out: ofs of first char after replacement string
925 const XSTRING *pstrSearch, // in: search string; cannot be NULL
926 const XSTRING *pstrReplace, // in: replacement string; cannot be NULL
927 size_t *pShiftTable, // in: shift table (see strhmemfind)
928 PBOOL pfRepeatFind) // in: repeat find? (see strhmemfind)
929{
930 ULONG ulrc = 0; // default: not found
931
932 if ((pxstr) && (pstrSearch) && (pstrReplace))
933 {
934 ULONG cSearchLen = pstrSearch->ulLength;
935
936 // can we search this?
937 if ( (*pulOfs < pxstr->ulLength)
938 && (cSearchLen)
939 )
940 {
941 // yes:
942 ULONG ulOfs = *pulOfs;
943 const char *pFound
944 = (const char *)strhmemfind(pxstr->psz + ulOfs, // in: haystack
945 pxstr->ulLength - ulOfs,
946 pstrSearch->psz,
947 cSearchLen,
948 pShiftTable,
949 pfRepeatFind);
950 if (pFound)
951 {
952 ULONG ulFirstReplOfs = pFound - pxstr->psz;
953 // found in buffer from ofs:
954 // replace pFound with pstrReplace
955 ulrc = xstrrpl(pxstr,
956 ulFirstReplOfs, // where to start
957 cSearchLen, // chars to replace
958 pstrReplace);
959
960 // return new length
961 *pulOfs = ulFirstReplOfs + pstrReplace->ulLength;
962 } // end if (pFound)
963 } // end if ( (*pulOfs < pxstr->ulLength) ...
964 } // end if ((pxstr) && (pstrSearch) && (pstrReplace))
965
966 return (ulrc);
967}
968
969/*
970 *@@ xstrFindReplaceC:
971 * wrapper around xstrFindReplace() which allows using
972 * C strings for the find and replace parameters.
973 *
974 * This creates two temporary XSTRING's for pcszSearch
975 * and pcszReplace and thus cannot use the shift table
976 * for repetitive searches. As a result, this is slower
977 * than xstrFindReplace.
978 *
979 * If you search with the same strings several times,
980 * you'll be better off using xstrFindReplace() directly.
981 *
982 *@@added V0.9.6 (2000-11-01) [umoeller]
983 *@@changed V0.9.7 (2001-01-15) [umoeller]: renamed from xstrcrpl
984 */
985
986ULONG xstrFindReplaceC(PXSTRING pxstr, // in/out: string
987 PULONG pulOfs, // in: where to begin search (0 = start);
988 // out: ofs of first char after replacement string
989 const char *pcszSearch, // in: search string; cannot be NULL
990 const char *pcszReplace) // in: replacement string; cannot be NULL
991{
992 XSTRING xstrFind,
993 xstrReplace;
994 size_t ShiftTable[256];
995 BOOL fRepeat = FALSE;
996 // initialize find/replace strings... note that the
997 // C strings are not free()'able, so we MUST NOT use xstrClear
998 // before leaving
999 xstrInitSet(&xstrFind, (PSZ)pcszSearch);
1000 xstrInitSet(&xstrReplace, (PSZ)pcszReplace);
1001
1002 return (xstrFindReplace(pxstr, pulOfs, &xstrFind, &xstrReplace, ShiftTable, &fRepeat));
1003}
1004
1005/*
1006 *@@ xstrConvertLineFormat:
1007 * converts between line formats.
1008 *
1009 * If (fToCFormat == TRUE), all \r\n pairs are replaced
1010 * with \n chars (UNIX or C format).
1011 *
1012 * Reversely, if (fToCFormat == FALSE), all \n chars
1013 * are converted to \r\n pairs (DOS and OS/2 formats).
1014 * No check is made whether this has already been done.
1015 *
1016 *@@added V0.9.7 (2001-01-15) [umoeller]
1017 */
1018
1019VOID xstrConvertLineFormat(PXSTRING pxstr,
1020 BOOL fToCFormat) // in: if TRUE, to C format; if FALSE, to OS/2 format.
1021{
1022 XSTRING strFind,
1023 strRepl;
1024 size_t ShiftTable[256];
1025 BOOL fRepeat = FALSE;
1026 ULONG ulOfs = 0;
1027
1028 if (fToCFormat)
1029 {
1030 // OS/2 to C:
1031 xstrInitSet(&strFind, "\r\n");
1032 xstrInitSet(&strRepl, "\n");
1033 }
1034 else
1035 {
1036 // C to OS/2:
1037 xstrInitSet(&strFind, "\n");
1038 xstrInitSet(&strRepl, "\r\n");
1039 }
1040
1041 while (xstrFindReplace(pxstr,
1042 &ulOfs,
1043 &strFind,
1044 &strRepl,
1045 ShiftTable,
1046 &fRepeat))
1047 ;
1048}
1049
1050// test case
1051
1052/* int main(void)
1053{
1054 XSTRING str,
1055 strFind,
1056 strReplace;
1057 size_t shift[256];
1058 BOOL fRepeat = FALSE;
1059 ULONG ulOfs = 0;
1060
1061 xstrInit(&str, 100);
1062 xstrInit(&strFind, 0);
1063 xstrInit(&strReplace, 0);
1064
1065 xstrcpy(&str, "Test string 1. Test string 2. Test string 3. !", 0);
1066 xstrcpy(&strFind, "Test", 0);
1067 xstrcpy(&strReplace, "Dummy", 0);
1068
1069 printf("Old string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
1070
1071 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1072
1073 fRepeat = FALSE;
1074 ulOfs = 0;
1075 while (xstrFindReplace(&str,
1076 &ulOfs,
1077 &strFind,
1078 &strReplace,
1079 shift, &fRepeat));
1080 ;
1081
1082 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
1083
1084 xstrcpy(&strFind, strReplace.psz, 0);
1085 xstrClear(&strReplace);
1086
1087 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1088
1089 fRepeat = FALSE;
1090 ulOfs = 0;
1091 while (xstrFindReplace(&str,
1092 &ulOfs,
1093 &strFind,
1094 &strReplace,
1095 shift, &fRepeat));
1096 ;
1097
1098 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
1099
1100 xstrcpy(&strFind, " ", 0);
1101 xstrcpy(&strReplace, ".", 0);
1102
1103 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1104
1105 fRepeat = FALSE;
1106 ulOfs = 0;
1107 while (xstrFindReplace(&str,
1108 &ulOfs,
1109 &strFind,
1110 &strReplace,
1111 shift, &fRepeat));
1112 ;
1113
1114 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
1115
1116 xstrcpy(&strFind, ".", 0);
1117 xstrcpy(&strReplace, "*.........................*", 0);
1118
1119 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1120
1121 fRepeat = FALSE;
1122 ulOfs = 0;
1123 while (xstrFindReplace(&str,
1124 &ulOfs,
1125 &strFind,
1126 &strReplace,
1127 shift, &fRepeat));
1128 ;
1129
1130 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
1131
1132 printf("Reserving extra mem.\n");
1133
1134 xstrReserve(&str, 6000);
1135 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
1136
1137 xstrcpy(&strFind, "..........", 0);
1138 xstrcpy(&strReplace, "@", 0);
1139
1140 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1141
1142 fRepeat = FALSE;
1143 ulOfs = 0;
1144 while (xstrFindReplace(&str,
1145 &ulOfs,
1146 &strFind,
1147 &strReplace,
1148 shift, &fRepeat));
1149 ;
1150
1151 printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
1152
1153 return (0);
1154}
1155*/
1156
1157
Note: See TracBrowser for help on using the repository browser.