source: trunk/src/helpers/xstring.c

Last change on this file was 249, checked in by umoeller, 23 years ago

Build updates, moved files from warpin.

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