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

Last change on this file since 70 was 65, checked in by umoeller, 24 years ago

Misc fixes.

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