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

Last change on this file since 83 was 74, checked in by umoeller, 24 years ago

Misc updates

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 49.8 KB
Line 
1
2/*
3 *@@sourcefile xstring.c:
4 * string functions with memory management.
5 *
6 * Usage: All OS/2 programs.
7 *
8 * The functions in this file are intended as a replacement
9 * to the C library string functions (such as strcpy, strcat)
10 * in cases where the length of the string is unknown and
11 * dynamic memory management is desirable.
12 *
13 * Instead of char* pointers, the functions in this file
14 * operate on XSTRING structures, which in turn contain
15 * a char* pointer pointing to heap memory, which is managed
16 * automatically.
17 *
18 * Using these functions has the following advantages:
19 *
20 * -- Automatic memory management. For example, xstrcat will
21 * automatically allocate new memory if the new string
22 * does not fit into the present buffer.
23 *
24 * -- The length of the string is always known. Instead
25 * of running strlen (which consumes time), XSTRING.ulLength
26 * always contains the current length of the string.
27 *
28 * -- The functions also differentiate between allocated
29 * memory and the length of the string. That is, for
30 * iterative appends, you can pre-allocate memory to
31 * avoid excessive reallocations.
32 *
33 * Usage:
34 *
35 * 1) Allocate an XSTRING structure on the stack. Always
36 * call xstrInit on the structure, like this:
37 *
38 + XSTRING str;
39 + xstrInit(&str, 0); // no pre-allocation
40 *
41 * Alternatively, use xstrCreate to have an XSTRING
42 * allocated from the heap.
43 *
44 * Always call xstrClear(&str) to free allocated
45 * memory. Otherwise you'll get memory leaks.
46 * (For heap XSTRING's from xstrCreate, use xstrFree.)
47 *
48 * 2) To copy something into the string, use xstrcpy.
49 * To append something to the string, use xstrcat.
50 * See those functions for samples.
51 *
52 * 3) If you need the char* pointer (e.g. for a call
53 * to another function), use XSTRING.psz. However,
54 * you should ONLY modify the psz pointer yourself
55 * if the other XSTRING members are updated accordingly.
56 * You may, for example, change single characters
57 * in the psz buffer. By contrast, if you change the
58 * length of the string, you must update XSTRING.ulLength.
59 * Otherwise these functions will get into trouble.
60 *
61 * Also, you should never assume that the "psz"
62 * pointer has not changed after you have called
63 * one of the xstr* functions because these can
64 * always reallocate the buffer if more memory
65 * was needed.
66 *
67 * 4) If (and only if) you have a char* buffer which
68 * is free()'able (e.g. from strdup()), you can
69 * use xstrset to avoid duplicate copying.
70 *
71 * Function prefixes:
72 * -- xstr* extended string functions.
73 *
74 * The functions in this file used to be in stringh.c
75 * before V0.9.3 (2000-04-01). These have been largely
76 * rewritten with V0.9.6 (2000-11-01) and are now much
77 * more efficient.
78 *
79 * Note: Version numbering in this file relates to XWorkplace
80 * version numbering.
81 *
82 *@@added V0.9.3 (2000-04-01) [umoeller]
83 *@@header "helpers\xstring.h"
84 */
85
86/*
87 * Copyright (C) 1999-2000 Ulrich M”ller.
88 * This file is part of the "XWorkplace helpers" source package.
89 * This is free software; you can redistribute it and/or modify
90 * it under the terms of the GNU General Public License as published
91 * by the Free Software Foundation, in version 2 as it comes in the
92 * "COPYING" file of the XWorkplace main distribution.
93 * This program is distributed in the hope that it will be useful,
94 * but WITHOUT ANY WARRANTY; without even the implied warranty of
95 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
96 * GNU General Public License for more details.
97 */
98
99#define OS2EMX_PLAIN_CHAR
100 // this is needed for "os2emx.h"; if this is defined,
101 // emx will define PSZ as _signed_ char, otherwise
102 // as unsigned char
103
104#include <os2.h>
105
106#include <stdlib.h>
107#include <stdio.h>
108#include <string.h>
109#include <ctype.h>
110
111#include "setup.h" // code generation and debugging options
112
113#include "helpers\stringh.h"
114#include "helpers\xstring.h" // extended string helpers
115
116/*
117 *@@category: Helpers\C helpers\String management\XStrings (with memory management)
118 * See xstring.c.
119 */
120
121/*
122 *@@ xstrInit:
123 * initializes a new XSTRING. Always call this before
124 * using an XSTRING from the stack.
125 *
126 * If (ulPreAllocate != 0), memory is pre-allocated
127 * for the string, but the string will be empty
128 * (its first byte is set to '\0'). In addition,
129 * pxstr->ulDelta will be set to 10% of ulPreAllocate.
130 *
131 * This is useful if you plan to add more stuff to
132 * the string later so we don't have to reallocate
133 * all the time in xstrcat.
134 *
135 * Do not use this on an XSTRING which is already
136 * initialized (this would cause memory leaks).
137 * Use xstrcpy or xstrset instead.
138 *
139 *@@added V0.9.6 (2000-11-01) [umoeller]
140 *@@changed V0.9.9 (2001-03-09) [umoeller]: added ulDelta
141 */
142
143void xstrInit(PXSTRING pxstr, // in/out: string
144 ULONG ulPreAllocate) // in: if > 0, memory to allocate
145{
146 memset(pxstr, 0, sizeof(XSTRING));
147 if (ulPreAllocate)
148 {
149 pxstr->psz = (PSZ)malloc(ulPreAllocate);
150 pxstr->cbAllocated = ulPreAllocate;
151 // ulLength is still zero
152 *(pxstr->psz) = 0;
153
154 pxstr->ulDelta = ulPreAllocate * 10 / 100;
155 }
156 // else: pxstr->ulDelta is still 0
157}
158
159/*
160 *@@ xstrInitSet:
161 * this can be used instead of xstrInit if you
162 * have a free()'able string you want to initialize
163 * the XSTRING with.
164 *
165 * This does not create a copy of pszNew. Instead,
166 * pszNew is used as the member string in pxstr
167 * directly.
168 *
169 * Do not use this on an XSTRING which is already
170 * initialized (this would cause memory leaks).
171 * Use xstrcpy or xstrset instead.
172 *
173 * Example:
174 *
175 + XSTRING str;
176 + xstrInitSet(&str, strdup("blah"));
177 *
178 *@@added V0.9.6 (2000-11-01) [umoeller]
179 *@@changed V0.9.9 (2001-03-09) [umoeller]: added ulDelta
180 */
181
182void xstrInitSet(PXSTRING pxstr,
183 PSZ pszNew)
184{
185 if (!pszNew)
186 {
187 memset(pxstr, 0, sizeof(XSTRING));
188 }
189 else
190 {
191 pxstr->psz = pszNew;
192 pxstr->ulLength = strlen(pszNew);
193 pxstr->cbAllocated = pxstr->ulLength + 1;
194 pxstr->ulDelta = pxstr->ulLength * 10 / 100;
195 }
196}
197
198/*
199 *@@ xstrInitCopy:
200 * this can be used instead of xstrInit if you
201 * want to initialize an XSTRING with a copy
202 * of an existing string. This is a shortcut
203 * for xstrInit() and then xstrcpy().
204 *
205 * As opposed to xstrInitSet, this does create
206 * a copy of pcszSource.
207 *
208 * Do not use this on an XSTRING which is already
209 * initialized (this would cause memory leaks).
210 * Use xstrcpy or xstrset instead.
211 *
212 * Example:
213 *
214 + XSTRING str;
215 + xstrInitCopy(&str, "blah");
216 *
217 *@@added V0.9.6 (2000-11-01) [umoeller]
218 *@@changed V0.9.7 (2000-12-31) [umoeller]: added ulExtraAllocate
219 *@@changed V0.9.9 (2001-03-09) [umoeller]: added ulDelta
220 */
221
222void xstrInitCopy(PXSTRING pxstr,
223 const char *pcszSource,
224 ULONG ulExtraAllocate) // in: if > 0, extra memory to allocate
225{
226 if (pxstr)
227 {
228 memset(pxstr, 0, sizeof(XSTRING));
229
230 if (pcszSource)
231 {
232 pxstr->ulLength = strlen(pcszSource);
233
234 if (pxstr->ulLength)
235 {
236 // we do have a source string:
237 pxstr->cbAllocated = pxstr->ulLength + 1 + ulExtraAllocate;
238 pxstr->psz = (PSZ)malloc(pxstr->cbAllocated);
239 strcpy(pxstr->psz, pcszSource);
240
241 pxstr->ulDelta = pxstr->cbAllocated * 10 / 100;
242 }
243 }
244 }
245}
246
247/*
248 *@@ xstrClear:
249 * clears the specified stack XSTRING and
250 * frees allocated memory.
251 *
252 * This is the reverse to xstrInit.
253 *
254 *@@added V0.9.6 (2000-11-01) [umoeller]
255 */
256
257void xstrClear(PXSTRING pxstr) // in/out: string
258{
259 if (pxstr->psz)
260 free(pxstr->psz);
261 memset(pxstr, 0, sizeof(XSTRING));
262}
263
264/*
265 *@@ xstrReserve:
266 * this function makes sure that the specified
267 * XSTRING has at least ulBytes bytes allocated.
268 *
269 * This function is useful if you plan to do
270 * a lot of string replacements or appends and
271 * want to avoid that the buffer is reallocated
272 * with each operation. Before those operations,
273 * call this function to make room for the operations.
274 *
275 * If ulBytes is smaller than the current allocation,
276 * this function does nothing.
277 *
278 * pxstr->ulDelta has no effect here.
279 *
280 * The XSTRING must be initialized before the
281 * call.
282 *
283 * Returns the new total no. of allocated bytes.
284 *
285 *@@added V0.9.7 (2001-01-07) [umoeller]
286 *@@changed V0.9.9 (2001-03-09) [umoeller]: now using ulDelta
287 *@@changed V0.9.12 (2001-05-21) [umoeller]: now reporting error on realloc fail
288 */
289
290ULONG xstrReserve(PXSTRING pxstr,
291 ULONG ulBytes)
292{
293 ULONG cbNeeded = ulBytes;
294
295 if (cbNeeded > pxstr->cbAllocated)
296 {
297 // we need more memory than we have previously
298 // allocated:
299 ULONG cbAllocate;
300 if (pxstr->ulDelta)
301 {
302 // delta specified: allocate in chunks of that
303 // V0.9.9 (2001-03-07) [umoeller]
304 ULONG cbExtra = cbNeeded - pxstr->cbAllocated;
305 cbExtra = ( (cbExtra + pxstr->ulDelta)
306 / pxstr->ulDelta
307 )
308 * pxstr->ulDelta;
309 // if we need 3 extra bytes and ulDelta is 10,
310 // this gives us 10 extra bytes
311 // if we need 3 extra bytes and ulDelta is 1000,
312 // this gives us 1000 extra bytes
313 cbAllocate = pxstr->cbAllocated + cbExtra;
314 }
315 else
316 // no delta specified:
317 cbAllocate = cbNeeded;
318 // V0.9.9 (2001-03-05) [umoeller]: use realloc;
319 // this gives the C runtime a chance to expand the
320 // existing block
321 if (pxstr->psz = (PSZ)realloc(pxstr->psz, cbAllocate))
322 // if pxstr->psz is NULL, realloc behaves like malloc
323 pxstr->cbAllocated = cbAllocate;
324 // ulLength is unchanged
325 else
326 // error: V0.9.12 (2001-05-21) [umoeller]
327 pxstr->cbAllocated = 0;
328 }
329 // else: we have enough memory
330
331 return (pxstr->cbAllocated);
332}
333
334/*
335 *@@ xstrCreate:
336 * allocates a new XSTRING from the heap
337 * and calls xstrInit on it.
338 *
339 * Always use xstrFree to free associated
340 * resources.
341 *
342 *@@added V0.9.6 (2000-11-01) [umoeller]
343 */
344
345PXSTRING xstrCreate(ULONG ulPreAllocate)
346{
347 PXSTRING pxstr = (PXSTRING)malloc(sizeof(XSTRING));
348 if (pxstr)
349 xstrInit(pxstr, ulPreAllocate);
350
351 return (pxstr);
352}
353
354/*
355 *@@ xstrFree:
356 * frees the specified heap XSTRING, which must
357 * have been created using xstrCreate.
358 *
359 * This uses a pointer to a PXSTRING so that
360 * the pointer is automatically reset to NULL
361 * by this function AND to avoid confusion
362 * with xstrClear.
363 *
364 *@@added V0.9.6 (2000-11-01) [umoeller]
365 *@@changed V0.9.12 (2001-05-24) [umoeller]: changed prototype to use pointer to pointer
366 */
367
368VOID xstrFree(PXSTRING *ppxstr) // in/out: string
369{
370 PXSTRING p;
371 if ( ppxstr
372 && (p = *ppxstr)
373 )
374 {
375 xstrClear(p);
376 free(p);
377 *ppxstr = NULL;
378 }
379}
380
381/*
382 *@@ xstrset:
383 * sets the specified XSTRING to a new string
384 * without copying it.
385 *
386 * pxstr is cleared before the new string is set.
387 *
388 * This ONLY works if pszNew has been allocated from
389 * the heap using malloc() or strdup() and is thus
390 * free()'able.
391 *
392 * This assumes that exactly strlen(pszNew) + 1
393 * bytes have been allocated for pszNew, which
394 * is true if pszNew comes from strdup().
395 *
396 *@@added V0.9.6 (2000-11-01) [umoeller]
397 *@@changed V0.9.9 (2001-02-14) [umoeller]: fixed NULL target crash
398 */
399
400ULONG xstrset(PXSTRING pxstr, // in/out: string
401 PSZ pszNew) // in: heap PSZ to use
402{
403 if (!pxstr)
404 return (0); // V0.9.9 (2001-02-14) [umoeller]
405
406 xstrClear(pxstr);
407 pxstr->psz = pszNew;
408 if (pszNew)
409 {
410 pxstr->ulLength = strlen(pszNew);
411 pxstr->cbAllocated = pxstr->ulLength + 1;
412
413 pxstr->ulDelta = pxstr->cbAllocated * 10 / 100;
414 }
415 // else null string: cbAllocated and ulLength are 0 already
416
417 return (pxstr->ulLength);
418}
419
420/*
421 *@@ xstrcpy:
422 * copies pcszSource to pxstr, for which memory is allocated
423 * as necessary.
424 *
425 * If pxstr contains something, its contents are destroyed.
426 *
427 * With ulSourceLength, specify the length of pcszSource
428 * or 0.
429 *
430 * -- If you specify 0, this function will run
431 * strlen(pcszSource) and copy the entire source
432 * string.
433 *
434 * -- If you already know the length of pcszSource, you
435 * can speed this function up by specifying the
436 * length.
437 *
438 * -- You are required to specify ulSourceLength if you
439 * only want to copy a substring, or if pcszSource is
440 * not zero-terminated.
441 *
442 * Returns the length of the new string (excluding the null
443 * terminator), or null upon errors.
444 *
445 * Example:
446 *
447 + XSTRING str;
448 + xstrInit(&str, 0);
449 + xstrcpy(&str, "blah", 0);
450 *
451 * This sequence can be abbreviated using xstrInitCopy.
452 *
453 * Memory cost: If there's enough room in pxstr for
454 * pcszSource, none. Otherwise pxstr is reallocated
455 * to hold enough room for pcszSource.
456 *
457 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcpy
458 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
459 *@@changed V0.9.7 (2001-01-15) [umoeller]: added ulSourceLength
460 *@@changed V0.9.9 (2001-01-28) [lafaix]: fixed memory leak and NULL source behavior
461 *@@changed V0.9.9 (2001-02-14) [umoeller]: fixed NULL target crash
462 *@@changed V0.9.9 (2001-02-16) [umoeller]: now supporting non-zero-terminated pcszSource
463 *@@changed V0.9.9 (2001-03-09) [umoeller]: now using xstrReserve
464 *@@changed V0.9.12 (2001-05-21) [umoeller]: added xstrReserve error checking
465 */
466
467ULONG xstrcpy(PXSTRING pxstr, // in/out: string
468 const char *pcszSource, // in: source, can be NULL
469 ULONG ulSourceLength) // in: length of pcszSource or 0
470{
471 if (!pxstr)
472 return (0); // V0.9.9 (2001-02-14) [umoeller]
473
474 if (pcszSource)
475 {
476 // source specified:
477 if (ulSourceLength == 0)
478 // but not length:
479 ulSourceLength = strlen(pcszSource);
480 }
481 else
482 ulSourceLength = 0;
483
484 if (ulSourceLength)
485 {
486 // we do have a source string:
487 if (xstrReserve(pxstr,
488 // required memory:
489 ulSourceLength + 1))
490 {
491 memcpy(pxstr->psz,
492 pcszSource,
493 ulSourceLength);
494 *(pxstr->psz + ulSourceLength) = '\0';
495 // V0.9.9 (2001-02-16) [umoeller]
496 // we must do this or otherwise we require pcszSource
497 // to be zero-terminated... not a good idea
498 }
499 else
500 pxstr->ulLength = 0; // error V0.9.12 (2001-05-21) [umoeller]
501 }
502 else
503 {
504 // no source specified or source is empty:
505 if (pxstr->cbAllocated)
506 // we did have a string: set to empty,
507 // but leave allocated memory intact
508 *(pxstr->psz) = 0;
509 // else
510 // we had no string previously: in that case
511 // psz and ulLength and cbAllocated are all still NULL
512 }
513
514 // in all cases, set new length
515 pxstr->ulLength = ulSourceLength;
516
517 return (pxstr->ulLength);
518}
519
520/*
521 *@@ xstrcpys:
522 * shortcut to xstrcpy if the source is an XSTRING also.
523 *
524 *@@added V0.9.9 (2001-02-14) [umoeller]
525 */
526
527ULONG xstrcpys(PXSTRING pxstr,
528 const XSTRING *pcstrSource)
529{
530 if (!pcstrSource)
531 return (0);
532
533 return (xstrcpy(pxstr, pcstrSource->psz, pcstrSource->ulLength));
534}
535
536/*
537 *@@ xstrcat:
538 * appends pcszSource to pxstr, for which memory is
539 * reallocated if necessary.
540 *
541 * If pxstr is empty, this behaves just like xstrcpy.
542 *
543 * With ulSourceLength, specify the length of pcszSource
544 * or 0 (see xstrcpy for details).
545 *
546 * Returns the length of the new string (excluding the null
547 * terminator) if the string was changed, or 0 if nothing
548 * happened.
549 *
550 * Note: To append a single character, xstrcatc is faster
551 * than xstrcat.
552 *
553 * Example:
554 *
555 + XSTRING str;
556 + xstrInit(&str, 0);
557 + xstrcpy(&str, "blah", 0);
558 + xstrcat(&str, "blup", 0);
559 *
560 * After this, str.psz points to a new string containing
561 * "blahblup".
562 *
563 * Memory cost: If there's enough room in pxstr for
564 * pcszSource, none. Otherwise pxstr is reallocated
565 * to hold enough room for pcszSource.
566 *
567 *@@changed V0.9.1 (99-12-20) [umoeller]: fixed memory leak
568 *@@changed V0.9.1 (2000-01-03) [umoeller]: crashed if pszString was null; fixed
569 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcat
570 *@@changed V0.9.3 (2000-05-11) [umoeller]: returned 0 if pszString was initially empty; fixed
571 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
572 *@@changed V0.9.7 (2000-12-10) [umoeller]: return value was wrong
573 *@@changed V0.9.7 (2001-01-15) [umoeller]: added ulSourceLength
574 *@@changed V0.9.9 (2001-02-16) [umoeller]: now supporting non-zero-terminated pcszSource
575 *@@changed V0.9.9 (2001-03-09) [umoeller]: now using xstrReserve
576 */
577
578ULONG xstrcat(PXSTRING pxstr, // in/out: string
579 const char *pcszSource, // in: source, can be NULL
580 ULONG ulSourceLength) // in: length of pcszSource or 0
581{
582 ULONG ulrc = 0;
583
584 if (pxstr)
585 {
586 if (pcszSource)
587 {
588 if (ulSourceLength == 0)
589 ulSourceLength = strlen(pcszSource);
590
591 if (ulSourceLength)
592 {
593 // we do have a source string:
594
595 // 1) memory management
596 xstrReserve(pxstr,
597 // required memory:
598 pxstr->ulLength + ulSourceLength + 1);
599
600 // 2) append source string:
601 memcpy(pxstr->psz + pxstr->ulLength,
602 pcszSource,
603 ulSourceLength);
604
605 *(pxstr->psz + pxstr->ulLength + ulSourceLength) = '\0';
606 // V0.9.9 (2001-02-16) [umoeller]
607 // we must do this or otherwise we require pcszSource
608 // to be zero-terminated... not a good idea
609
610 // in all cases, set new length
611 pxstr->ulLength += ulSourceLength;
612 ulrc = pxstr->ulLength; // V0.9.7 (2000-12-10) [umoeller]
613
614 } // end if (ulSourceLength)
615 }
616
617 // else no source specified or source is empty:
618 // do nothing
619 }
620
621 return (ulrc);
622}
623
624/*
625 *@@ xstrcatc:
626 * this is similar to xstrcat, except that this is
627 * for a single character. This is a bit faster than
628 * xstrcat.
629 *
630 * If "c" is \0, nothing happens.
631 *
632 * If pxstr is empty, this behaves just like xstrcpy.
633 *
634 * Returns the length of the new string (excluding the null
635 * terminator) if the string was changed, or 0 if nothing
636 * happened.
637 *
638 * Example:
639 *
640 + XSTRING str;
641 + xstrInit(&str, 0);
642 + xstrcpy(&str, "blu", 0);
643 + xstrcatc(&str, 'p');
644 *
645 * After this, str.psz points to a new string containing
646 * "blup".
647 *
648 * Memory cost: If there's enough room in pxstr for
649 * c, none. Otherwise pxstr is reallocated
650 * to hold enough room for c.
651 *
652 *@@added V0.9.7 (2000-12-10) [umoeller]
653 *@@changed V0.9.9 (2001-03-09) [umoeller]: now using xstrReserve
654 */
655
656ULONG xstrcatc(PXSTRING pxstr, // in/out: string
657 CHAR c) // in: character to append, can be \0
658{
659 ULONG ulrc = 0;
660
661 if ((pxstr) && (c))
662 {
663 // ULONG ulSourceLength = 1;
664 // 1) memory management
665 xstrReserve(pxstr,
666 // required memory:
667 pxstr->ulLength // existing length, without null terminator
668 + 1 // new character
669 + 1); // null terminator
670 // 2) append character:
671 pxstr->psz[pxstr->ulLength] = c;
672 pxstr->psz[pxstr->ulLength + 1] = '\0';
673
674 // in all cases, set new length
675 (pxstr->ulLength)++;
676 ulrc = pxstr->ulLength;
677
678 } // end if ((pxstr) && (c))
679
680 return (ulrc);
681}
682
683/*
684 *@@ xstrcats:
685 * shortcut to xstrcat if the source is an XSTRING also.
686 *
687 *@@added V0.9.9 (2001-02-14) [umoeller]
688 */
689
690ULONG xstrcats(PXSTRING pxstr,
691 const XSTRING *pcstrSource)
692{
693 if (!pcstrSource)
694 return (0);
695
696 return (xstrcat(pxstr,
697 pcstrSource->psz,
698 pcstrSource->ulLength));
699}
700
701/*
702 *@@ xstrrpl:
703 * replaces "cReplLen" characters in pxstr, starting
704 * at the position "ulFirstReplPos", with the first
705 * "cReplaceWithLen" characters from pcszReplaceWith.
706 *
707 * Returns the new length of the string, excluding
708 * the null terminator, or 0 if the replacement failed
709 * (e.g. because the offsets were too large).
710 *
711 * This has been extracted from xstrFindReplace because
712 * if you already know the position of a substring,
713 * you can now call this directly. This properly
714 * reallocates the string if more memory is needed.
715 *
716 * Example:
717 *
718 + XSTRING xstr, xstrReplacement;
719 + xstrInitCopy(&xstr, "This is a test string.");
720 + // positions: 0123456789012345678901
721 + // 1 2
722 +
723 + xstrInitCopy(&xstrReplacement, "stupid");
724 +
725 + xstrrpl(&xstr,
726 + 10, // position of "test"
727 + 4, // length of "test"
728 + &xstrReplacement);
729 *
730 * This would yield "This is a stupid string."
731 *
732 * Memory cost: If there's enough room in pxstr for
733 * the replacement, none. Otherwise pxstr is reallocated
734 * to hold enough room for the replacement.
735 *
736 *@@added V0.9.7 (2001-01-15) [umoeller]
737 *@@changed V0.9.9 (2001-01-29) [lafaix]: fixed unnecessary allocation when pxstr was big enough
738 *@@changed V0.9.9 (2001-02-14) [umoeller]: fixed NULL target crash
739 *@@changed V0.9.9 (2001-03-09) [umoeller]: now using xstrReserve
740 *@@changed V0.9.11 (2001-04-22) [umoeller]: replaced replacement XSTRING with PCSZ
741 */
742
743ULONG xstrrpl(PXSTRING pxstr, // in/out: string
744 ULONG ulFirstReplOfs, // in: ofs of first char to replace
745 ULONG cReplLen, // in: no. of chars to replace
746 const char *pcszReplaceWith, // in: string to replace chars with
747 ULONG cReplaceWithLen) // in: length of replacement string
748 // (this MUST be specified; if 0, chars are removed only)
749{
750 ULONG ulrc = 0;
751
752 // security checks...
753 if ( (pxstr) // V0.9.9 (2001-02-14) [umoeller]
754 && (ulFirstReplOfs + cReplLen <= pxstr->ulLength)
755 && (pcszReplaceWith)
756 )
757 {
758 // size of new buffer:
759 ULONG cbNeeded = pxstr->ulLength // existing
760 + cReplaceWithLen // plus replacement string length
761 - cReplLen // minus replaced characters
762 + 1; // plus null terminator
763 // offset where pszSearch was found
764 PSZ pFound = pxstr->psz + ulFirstReplOfs;
765
766 // now check if we have enough memory...
767 if (cbNeeded > pxstr->cbAllocated)
768 {
769 // we need more memory than we have previously
770 // allocated:
771 // reallocate using ulDelta V0.9.9 (2001-03-07) [umoeller]
772 ULONG cbAllocate;
773 PSZ pszNew;
774 if (pxstr->ulDelta)
775 {
776 // delta specified: allocate in chunks of that
777 // V0.9.9 (2001-03-07) [umoeller]
778 ULONG cbExtra = cbNeeded - pxstr->cbAllocated;
779 cbExtra = ( (cbExtra + pxstr->ulDelta)
780 / pxstr->ulDelta
781 )
782 * pxstr->ulDelta;
783 // if we need 3 extra bytes and ulDelta is 10,
784 // this gives us 10 extra bytes
785 // if we need 3 extra bytes and ulDelta is 1000,
786 // this gives us 1000 extra bytes
787 cbAllocate = pxstr->cbAllocated + cbExtra;
788 }
789 else
790 // no delta specified:
791 cbAllocate = cbNeeded;
792 // allocate new buffer
793 pszNew = (PSZ)malloc(cbAllocate);
794 // end V0.9.9 (2001-03-07) [umoeller]
795
796 if (ulFirstReplOfs)
797 // "found" was not at the beginning:
798 // copy from beginning up to found-offset
799 memcpy(pszNew,
800 pxstr->psz,
801 ulFirstReplOfs); // up to "found"
802
803 if (cReplaceWithLen)
804 {
805 // we have a replacement:
806 // insert it next
807
808 /* memcpy(pszNew + ulFirstReplOfs,
809 pstrReplaceWith->psz,
810 cReplaceWithLen + 1); // include null terminator
811 */
812 // no, we no longer can be sure that pcszReplaceWith is
813 // null terminated, so terminate explicitly
814 // V0.9.11 (2001-04-22) [umoeller]
815
816 memcpy(pszNew + ulFirstReplOfs,
817 pcszReplaceWith,
818 cReplaceWithLen);
819 *(pszNew + ulFirstReplOfs + cReplaceWithLen) = '\0';
820 }
821
822 // copy rest:
823 // pxstr frontFOUNDtail
824 // 0 1
825 // 01234567890123
826 // ³ ³ ³ ³
827 // ³ ³ ÀÄ ulFirstReplOfs + cReplLen = 10
828 // ³ ³ ³
829 // ³ ÀÄ ulFirstReplOfs = 5
830 // ³ ³
831 // pxstr->ulLength = 14
832 memcpy(pszNew + ulFirstReplOfs + cReplaceWithLen,
833 pFound + cReplLen,
834 // remaining bytes:
835 pxstr->ulLength - ulFirstReplOfs - cReplLen // 9
836 + 1); // null terminator
837
838 // replace old buffer with new one
839 free(pxstr->psz);
840 pxstr->psz = pszNew;
841 pxstr->ulLength = cbNeeded - 1;
842 pxstr->cbAllocated = cbAllocate; // V0.9.9 (2001-03-07) [umoeller]
843 } // end if (pxstr->cbAllocated < cbNeeded)
844 else
845 {
846 // we have enough memory left,
847 // we can just overwrite in the middle...
848 // fixed V0.9.9 (2001-01-29) [lafaix]
849
850 // calc length of string after "found"
851 ULONG cTailLength = pxstr->ulLength - ulFirstReplOfs - cReplLen;
852
853 // first, we move the end to its new location
854 // (memmove handles overlap if needed)
855 memmove(pFound + cReplaceWithLen,
856 pFound + cReplLen,
857 cTailLength + 1); // including null terminator
858
859 // now overwrite "found" in the middle
860 if (cReplaceWithLen)
861 {
862 memcpy(pFound,
863 pcszReplaceWith,
864 cReplaceWithLen); // no null terminator
865 }
866
867 // that's it; adjust the string length now
868 pxstr->ulLength = cbNeeded - 1;
869 }
870
871 ulrc = cbNeeded - 1;
872 } // end checks
873
874 return (ulrc);
875}
876
877/*
878 *@@ xstrFindWord:
879 * searches for pstrFind in pxstr, starting at ulOfs.
880 * However, this only finds pstrFind if it's a "word",
881 * i.e. surrounded by one of the characters in the
882 * pcszBeginChars and pcszEndChars array.
883 *
884 * This is similar to strhFindWord, but this uses
885 * strhmemfind for fast searching, and it doesn't
886 * have to calculate the string lengths because these
887 * already in XSTRING.
888 *
889 * Returns 0 if no "word" was found, or the offset
890 * of the "word" in pxstr if found.
891 *
892 *@@added V0.9.6 (2000-11-12) [umoeller]
893 *@@changed V0.9.9 (2001-02-14) [umoeller]: fixed NULL string crashs
894 */
895
896PSZ xstrFindWord(const XSTRING *pxstr, // in: buffer to search ("haystack")
897 ULONG ulOfs, // in: where to begin search (0 = start)
898 const XSTRING *pstrFind, // in: word to find ("needle")
899 size_t *pShiftTable, // in: shift table (see strhmemfind)
900 PBOOL pfRepeatFind, // in: repeat find? (see strhmemfind)
901 const char *pcszBeginChars, // suggestion: "\x0d\x0a ()/\\-,."
902 const char *pcszEndChars) // suggestion: "\x0d\x0a ()/\\-,.:;"
903{
904 PSZ pReturn = 0;
905
906 if (pxstr && pstrFind) // V0.9.9 (2001-02-14) [umoeller]
907 {
908 ULONG ulFoundLen = pstrFind->ulLength;
909
910 if ((pxstr->ulLength) && (ulFoundLen))
911 {
912 const char *p = pxstr->psz + ulOfs;
913
914 do // while p
915 {
916 p = (PSZ)strhmemfind(p, // in: haystack
917 pxstr->ulLength - (p - pxstr->psz),
918 // remaining length of haystack
919 pstrFind->psz,
920 ulFoundLen,
921 pShiftTable,
922 pfRepeatFind);
923 if (p)
924 {
925 // string found:
926 // check if that's a word
927
928 if (strhIsWord(pxstr->psz,
929 p,
930 ulFoundLen,
931 pcszBeginChars,
932 pcszEndChars))
933 {
934 // valid end char:
935 pReturn = (PSZ)p;
936 break;
937 }
938
939 p += ulFoundLen;
940 }
941 } while (p);
942
943 }
944 }
945
946 return (pReturn);
947}
948
949/*
950 *@@ xstrFindReplace:
951 * replaces the first occurence of pstrSearch with
952 * pstrReplace in pxstr.
953 *
954 * Starting with V0.9.6, this operates entirely on
955 * XSTRING's for speed because we then know the string
956 * lengths already and can use memcpy instead of strcpy.
957 * This new version should be magnitudes faster,
958 * especially with large string bufffers.
959 *
960 * None of the pointers can be NULL, but if pstrReplace
961 * is empty, this effectively erases pstrSearch in pxstr.
962 *
963 * Returns the length of the new string (exclusing the
964 * null terminator) or 0 if pszSearch was not found
965 * (and pxstr was therefore not changed).
966 *
967 * This starts the search at *pulOfs. If
968 * (*pulOfs == 0), this starts from the beginning
969 * of pxstr.
970 *
971 * If the string was found, *pulOfs will be set to the
972 * first character after the new replacement string. This
973 * allows you to call this func again with the same strings
974 * to have several occurences replaced (see the example below).
975 *
976 * There are two wrappers around this function which
977 * work on C strings instead (however, thus losing the
978 * speed advantage):
979 *
980 * -- strhFindReplace operates on C strings only;
981 *
982 * -- xstrFindReplaceC uses C strings for the search and replace
983 * parameters.
984 *
985 * <B>Example usage:</B>
986 *
987 + XSTRING strBuf,
988 + strFind,
989 + strRepl;
990 + size_t ShiftTable[256];
991 + BOOL fRepeat = FALSE;
992 + ULONG ulOffset = 0;
993 +
994 + xstrInitCopy(&strBuf, "Test phrase 1. Test phrase 2.", 0);
995 + xstrInitSet(&strFind, "Test");
996 + xstrInitSet(&strRepl, "Dummy");
997 + while (xstrFindReplace(&str,
998 + &ulPos, // in/out: offset
999 + &strFind, // search
1000 + &strRepl, // replace
1001 + ShiftTable,
1002 + &fRepeat))
1003 + ;
1004 *
1005 * would replace all occurences of "Test" in str with
1006 * "Dummy".
1007 *
1008 * Memory cost: Calls xstrrpl if pstrSearch was found.
1009 *
1010 *@@changed V0.9.0 [umoeller]: totally rewritten.
1011 *@@changed V0.9.0 (99-11-08) [umoeller]: crashed if *ppszBuf was NULL. Fixed.
1012 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxrpl
1013 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
1014 *@@changed V0.9.6 (2000-11-12) [umoeller]: now using strhmemfind
1015 *@@changed V0.9.7 (2001-01-15) [umoeller]: renamed from xstrrpl; extracted new xstrrpl
1016 */
1017
1018ULONG xstrFindReplace(PXSTRING pxstr, // in/out: string
1019 PULONG pulOfs, // in: where to begin search (0 = start);
1020 // out: ofs of first char after replacement string
1021 const XSTRING *pstrSearch, // in: search string; cannot be NULL
1022 const XSTRING *pstrReplace, // in: replacement string; cannot be NULL
1023 size_t *pShiftTable, // in: shift table (see strhmemfind)
1024 PBOOL pfRepeatFind) // in: repeat find? (see strhmemfind)
1025{
1026 ULONG ulrc = 0; // default: not found
1027
1028 if ((pxstr) && (pstrSearch) && (pstrReplace))
1029 {
1030 ULONG cSearchLen = pstrSearch->ulLength;
1031
1032 // can we search this?
1033 if ( (*pulOfs < pxstr->ulLength)
1034 && (cSearchLen)
1035 )
1036 {
1037 // yes:
1038 ULONG ulOfs = *pulOfs;
1039 const char *pFound
1040 = (const char *)strhmemfind(pxstr->psz + ulOfs, // in: haystack
1041 pxstr->ulLength - ulOfs,
1042 pstrSearch->psz,
1043 cSearchLen,
1044 pShiftTable,
1045 pfRepeatFind);
1046 if (pFound)
1047 {
1048 ULONG ulFirstReplOfs = pFound - pxstr->psz;
1049 // found in buffer from ofs:
1050 // replace pFound with pstrReplace
1051 ulrc = xstrrpl(pxstr,
1052 ulFirstReplOfs, // where to start
1053 cSearchLen, // chars to replace
1054 pstrReplace->psz,
1055 pstrReplace->ulLength); // adjusted V0.9.11 (2001-04-22) [umoeller]
1056
1057 // return new length
1058 *pulOfs = ulFirstReplOfs + pstrReplace->ulLength;
1059 } // end if (pFound)
1060 } // end if ( (*pulOfs < pxstr->ulLength) ...
1061 } // end if ((pxstr) && (pstrSearch) && (pstrReplace))
1062
1063 return (ulrc);
1064}
1065
1066/*
1067 *@@ xstrFindReplaceC:
1068 * wrapper around xstrFindReplace() which allows using
1069 * C strings for the find and replace parameters.
1070 *
1071 * This creates two temporary XSTRING's for pcszSearch
1072 * and pcszReplace and thus cannot use the shift table
1073 * for repetitive searches. As a result, this is slower
1074 * than xstrFindReplace.
1075 *
1076 * If you search with the same strings several times,
1077 * you'll be better off using xstrFindReplace() directly.
1078 *
1079 *@@added V0.9.6 (2000-11-01) [umoeller]
1080 *@@changed V0.9.7 (2001-01-15) [umoeller]: renamed from xstrcrpl
1081 */
1082
1083ULONG xstrFindReplaceC(PXSTRING pxstr, // in/out: string
1084 PULONG pulOfs, // in: where to begin search (0 = start);
1085 // out: ofs of first char after replacement string
1086 const char *pcszSearch, // in: search string; cannot be NULL
1087 const char *pcszReplace) // in: replacement string; cannot be NULL
1088{
1089 XSTRING xstrFind,
1090 xstrReplace;
1091 size_t ShiftTable[256];
1092 BOOL fRepeat = FALSE;
1093 // initialize find/replace strings... note that the
1094 // C strings are not free()'able, so we MUST NOT use xstrClear
1095 // before leaving
1096 xstrInitSet(&xstrFind, (PSZ)pcszSearch);
1097 xstrInitSet(&xstrReplace, (PSZ)pcszReplace);
1098
1099 return (xstrFindReplace(pxstr, pulOfs, &xstrFind, &xstrReplace, ShiftTable, &fRepeat));
1100}
1101
1102// static encoding table for xstrEncode
1103static PSZ apszEncoding[] =
1104{
1105 "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
1106 "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F",
1107 "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
1108 "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F",
1109 "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27",
1110 "%28", "%29", "%2A", "%2B", "%2C", "%2D", "%2E", "%2F",
1111 "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37",
1112 "%38", "%39", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F",
1113 "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47",
1114 "%48", "%49", "%4A", "%4B", "%4C", "%4D", "%4E", "%4F",
1115 "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57",
1116 "%58", "%59", "%5A", "%5B", "%5C", "%5D", "%5E", "%5F",
1117 "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67",
1118 "%68", "%69", "%6A", "%6B", "%6C", "%6D", "%6E", "%6F",
1119 "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77",
1120 "%78", "%79", "%7A", "%7B", "%7C", "%7D", "%7E", "%7F",
1121 "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
1122 "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F",
1123 "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
1124 "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
1125 "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7",
1126 "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF",
1127 "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7",
1128 "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF",
1129 "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
1130 "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF",
1131 "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7",
1132 "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF",
1133 "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7",
1134 "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
1135 "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7",
1136 "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
1137};
1138
1139/*
1140 *@@ xstrEncode:
1141 * encodes characters in a string.
1142 *
1143 * This searches pxstr for all occurences of the
1144 * characters in pcszEncode (which must be a
1145 * null-terminated list of characters to be
1146 * encoded). Each occurence that is found is
1147 * replaced with "%hh", with "hh" being the
1148 * two-digit hex number of the encoded character.
1149 *
1150 * For example, to encode strings for the XCenter,
1151 * set pcszEncode to "%,();=".
1152 *
1153 * Returns the no. of characters replaced.
1154 *
1155 * NOTE: You must make sure that pcszEncode ALWAYS
1156 * contains the "%" character as well, which must
1157 * always be encoded (i.e. escaped) because it is
1158 * used for encoding the characters. Otherwise
1159 * you won't be able to decode the string again.
1160 *
1161 * Example: To encode all occurences of
1162 * "a", "b", and "c" in a string, do this:
1163 *
1164 + XSTRING str;
1165 + xstrInitCopy(&str, "Sample characters.";
1166 + xstrEncode(&str, "abc%";
1167 *
1168 * would convert str to contain:
1169 *
1170 + S%61mple %63hara%63ters.
1171 *
1172 * Memory cost: None, except for that of xstrcpy.
1173 *
1174 *@@added V0.9.9 (2001-02-28) [umoeller]
1175 *@@changed V0.9.9 (2001-03-06) [lafaix]: rewritten.
1176 */
1177
1178ULONG xstrEncode(PXSTRING pxstr, // in/out: string to convert
1179 const char *pcszEncode) // in: characters to encode (e.g. "%,();=")
1180{
1181 ULONG ulrc = 0,
1182 ul,
1183 ulEncodeLength;
1184
1185 if ( (pxstr)
1186 && (pxstr->ulLength)
1187 && (pcszEncode)
1188 && (ulEncodeLength = strlen(pcszEncode)))
1189 {
1190 PSZ pszDest = (PSZ)malloc(pxstr->ulLength * 3
1191 + 1),
1192 pszDestCurr = pszDest;
1193
1194 if (pszDest)
1195 {
1196 for (ul = 0;
1197 ul < pxstr->ulLength;
1198 ul++)
1199 {
1200 ULONG ulEncode;
1201
1202 for (ulEncode = 0;
1203 ulEncode < ulEncodeLength;
1204 ulEncode++)
1205 {
1206 if (pxstr->psz[ul] == pcszEncode[ulEncode])
1207 {
1208 // use the static encoding table for speed
1209 memcpy(pszDestCurr,
1210 apszEncoding[(unsigned char)pcszEncode[ulEncode]],
1211 3);
1212 pszDestCurr += 3;
1213 ulrc++;
1214 goto iterate;
1215 }
1216 }
1217
1218 *pszDestCurr++ = pxstr->psz[ul];
1219
1220 iterate:
1221 ;
1222 }
1223 }
1224
1225 // something was encoded; update pxstr
1226 if (ulrc)
1227 {
1228 *pszDestCurr = 0;
1229
1230 xstrcpy(pxstr, pszDest, pszDestCurr-pszDest);
1231 }
1232
1233 free(pszDest);
1234 }
1235
1236 return (ulrc);
1237}
1238
1239/*
1240 *@@ xstrDecode:
1241 * decodes a string previously encoded by xstrEncode.
1242 *
1243 * This simply assumes that all '%' characters in
1244 * pxstr introduce encodings and the next two characters
1245 * after '%' always are a hex character code. This
1246 * only recognizes hex in upper case. All this will
1247 * work properly with encodings from xstrEncode.
1248 *
1249 * Returns the no. of encodings replaced.
1250 *
1251 * Memory cost: None.
1252 *
1253 *@@added V0.9.9 (2001-02-28) [umoeller]
1254 *@@changed V0.9.9 (2001-03-06) [lafaix]: removed memory allocation
1255 */
1256
1257ULONG xstrDecode(PXSTRING pxstr) // in/out: string to be decoded
1258{
1259 ULONG ulrc = 0;
1260
1261 if ( (pxstr)
1262 && (pxstr->ulLength)
1263 )
1264 {
1265 const char *pSource = pxstr->psz;
1266 PSZ pszDest = (PSZ)pSource,
1267 pDest = (PSZ)pSource;
1268 CHAR c;
1269
1270 while ((c = *pSource++))
1271 {
1272 // pSource points to next char now
1273
1274 if (c == '%')
1275 {
1276 static char ach[] = "0123456789ABCDEF";
1277
1278 // convert two chars after '%'
1279 CHAR c2, // first char after '%' --> hi-nibble
1280 c3; // second char after '%' --> lo-nibble
1281 const char *p2, // for first char: points into ach or is NULL
1282 *p3; // for second char: points into ach or is NULL
1283 if ( (c2 = *pSource)
1284 && (p2 = strchr(ach, c2))
1285 && (c3 = *(pSource + 1))
1286 && (p3 = strchr(ach, c3))
1287 )
1288 {
1289 // both chars after '%' were valid:
1290 *pDest++ = // lo-nibble:
1291 (p3 - ach) // 0 for '0', 10 for 'A', ...
1292 // hi-nibble:
1293 + ((p2 - ach) << 4);
1294 // go on after that
1295 pSource += 2;
1296 // raise return count
1297 ulrc++;
1298 // next in loop
1299 continue;
1300 }
1301 }
1302
1303 // not encoding, or null after '%', or invalid encoding:
1304 // just copy this
1305 *pDest++ = c;
1306 } // while ((ch = *pSource++))
1307
1308 if (ulrc)
1309 {
1310 *pDest = 0;
1311 pxstr->ulLength = (pDest - pszDest);
1312 }
1313 }
1314
1315 return (ulrc);
1316}
1317
1318/*
1319 *@@ xstrConvertLineFormat:
1320 * converts between line formats.
1321 *
1322 * If (fToCFormat == CRLF2LF), all \r\n pairs are replaced
1323 * with \n chars (UNIX or C format).
1324 *
1325 * Reversely, if (fToCFormat == LF2CRLF), all \n chars
1326 * are converted to \r\n pairs (DOS and OS/2 formats).
1327 * No check is made whether this has already been done.
1328 *
1329 *@@added V0.9.7 (2001-01-15) [umoeller]
1330 */
1331
1332VOID xstrConvertLineFormat(PXSTRING pxstr,
1333 BOOL fToCFormat) // in: if CRLF2LF, to C format; if LF2CRLF, to OS/2 format.
1334{
1335 XSTRING strFind,
1336 strRepl;
1337 size_t ShiftTable[256];
1338 BOOL fRepeat = FALSE;
1339 ULONG ulOfs = 0;
1340
1341 if (fToCFormat)
1342 {
1343 // OS/2 to C:
1344 xstrInitSet(&strFind, "\r\n");
1345 xstrInitSet(&strRepl, "\n");
1346 }
1347 else
1348 {
1349 // C to OS/2:
1350 xstrInitSet(&strFind, "\n");
1351 xstrInitSet(&strRepl, "\r\n");
1352 }
1353
1354 while (xstrFindReplace(pxstr,
1355 &ulOfs,
1356 &strFind,
1357 &strRepl,
1358 ShiftTable,
1359 &fRepeat))
1360 ;
1361}
1362
1363// test case
1364
1365/* int main(void)
1366{
1367 XSTRING str,
1368 strFind,
1369 strReplace;
1370 size_t shift[256];
1371 BOOL fRepeat = FALSE;
1372 ULONG ulOfs = 0;
1373
1374 xstrInit(&str, 0);
1375 xstrInit(&strFind, 0);
1376 xstrInit(&strReplace, 0);
1377
1378 str.ulDelta = 50;
1379
1380 xstrcpy(&str, "Test string 1. Test string 2. Test string 3. !", 0);
1381 xstrcpy(&strFind, "Test", 0);
1382 xstrcpy(&strReplace, "Dummy", 0);
1383
1384 printf("Old string is: \"%s\" (%d/%d/%d)\n", str.psz, str.ulLength, str.cbAllocated, str.ulDelta);
1385
1386 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1387
1388 fRepeat = FALSE;
1389 ulOfs = 0;
1390 while (xstrFindReplace(&str,
1391 &ulOfs,
1392 &strFind,
1393 &strReplace,
1394 shift, &fRepeat));
1395 ;
1396
1397 printf("New string is: \"%s\" (%d/%d/%d)\n", str.psz, str.ulLength, str.cbAllocated, str.ulDelta);
1398
1399 printf("Appending \"blah\".\n");
1400 xstrcat(&str, "blah", 0);
1401 printf("New string is: \"%s\" (%d/%d/%d)\n", str.psz, str.ulLength, str.cbAllocated, str.ulDelta);
1402
1403 xstrcpy(&strFind, strReplace.psz, 0);
1404 xstrClear(&strReplace);
1405
1406 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1407
1408 fRepeat = FALSE;
1409 ulOfs = 0;
1410 while (xstrFindReplace(&str,
1411 &ulOfs,
1412 &strFind,
1413 &strReplace,
1414 shift, &fRepeat));
1415 ;
1416
1417 printf("New string is: \"%s\" (%d/%d/%d)\n", str.psz, str.ulLength, str.cbAllocated, str.ulDelta);
1418
1419 xstrcpy(&strFind, " ", 0);
1420 xstrcpy(&strReplace, ".", 0);
1421
1422 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1423
1424 fRepeat = FALSE;
1425 ulOfs = 0;
1426 while (xstrFindReplace(&str,
1427 &ulOfs,
1428 &strFind,
1429 &strReplace,
1430 shift, &fRepeat));
1431 ;
1432
1433 printf("New string is: \"%s\" (%d/%d/%d)\n", str.psz, str.ulLength, str.cbAllocated, str.ulDelta);
1434
1435 xstrcpy(&strFind, ".", 0);
1436 xstrcpy(&strReplace, "*.........................*", 0);
1437
1438 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1439
1440 fRepeat = FALSE;
1441 ulOfs = 0;
1442 while (xstrFindReplace(&str,
1443 &ulOfs,
1444 &strFind,
1445 &strReplace,
1446 shift, &fRepeat));
1447 ;
1448
1449 printf("New string is: \"%s\" (%d/%d/%d)\n", str.psz, str.ulLength, str.cbAllocated, str.ulDelta);
1450
1451 xstrcpy(&strFind, "..........", 0);
1452 xstrcpy(&strReplace, "@", 0);
1453
1454 printf("Replacing \"%s\" with \"%s\".\n", strFind.psz, strReplace.psz);
1455
1456 fRepeat = FALSE;
1457 ulOfs = 0;
1458 while (xstrFindReplace(&str,
1459 &ulOfs,
1460 &strFind,
1461 &strReplace,
1462 shift, &fRepeat));
1463 ;
1464
1465 printf("New string is: \"%s\" (%d/%d/%d)\n", str.psz, str.ulLength, str.cbAllocated, str.ulDelta);
1466
1467 printf("Encoding @* chars.\n");
1468 xstrEncode(&str, "@*");
1469 printf("New string is: \"%s\" (%d/%d/%d)\n", str.psz, str.ulLength, str.cbAllocated, str.ulDelta);
1470
1471 printf("Decoding @* chars.\n");
1472 xstrDecode(&str);
1473 printf("New string is: \"%s\" (%d/%d/%d)\n", str.psz, str.ulLength, str.cbAllocated, str.ulDelta);
1474
1475 return (0);
1476} */
1477
1478
Note: See TracBrowser for help on using the repository browser.