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

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

Misc. changes.

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