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

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