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

Last change on this file since 144 was 144, checked in by umoeller, 23 years ago

Misc minor fixes.

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