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

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

misc. changes

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