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

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

Buncha fixes, plus Paul's screen wrap feature.

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