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

Last change on this file since 118 was 111, checked in by umoeller, 24 years ago

misc changes

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