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

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

Misc changes.

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