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

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