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

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

Lots of updates from the last week for conditional compiles and other stuff.

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