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

Last change on this file since 130 was 129, checked in by umoeller, 24 years ago

Executable updates, mostly.

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