Ignore:
Timestamp:
Nov 4, 2000, 8:55:45 PM (25 years ago)
Author:
umoeller
Message:

Updated string helpers.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/helpers/xstring.c

    r8 r12  
    66 *      Usage: All OS/2 programs.
    77 *
     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 an XSTRING structure, which contains a char*
     15 *      pointer instead.
     16 *
     17 *      Using these functions has the following advantages:
     18 *
     19 *      -- Automatic memory management. For example, xstrcat will
     20 *         automatically allocate new memory if the new string
     21 *         does not fit into the present buffer.
     22 *
     23 *      -- The length of the string is always known. Instead
     24 *         of running strlen (which consumes time), XSTRING.ulLength
     25 *         always contains the current length of the string.
     26 *
     27 *      -- The functions also differentiate between allocated
     28 *         memory and the length of the string. That is, for
     29 *         iterative appends, you can pre-allocate memory to
     30 *         avoid excessive reallocations.
     31 *
     32 *      Usage:
     33 *
     34 *      1) Allocate an XSTRING structure on the stack. Always
     35 *         call xstrInit on the structure, like this:
     36 *
     37 +              XSTRING str;
     38 +              xstrInit(&str, 0);      // no pre-allocation
     39 *
     40 *         Alternatively, use xstrCreate to have an XSTRING
     41 *         allocated from the heap.
     42 *
     43 *         Always call xstrClear(&str) to free allocated
     44 *         memory. Otherwise you'll get memory leaks.
     45 *         (For heap XSTRING's from xstrCreate, use xstrFree.)
     46 *
     47 *      2) To copy something into the string, use xstrcpy.
     48 *         To append something to the string, use xstrcat.
     49 *         See those functions for samples.
     50 *
     51 *      3) If you need the char* pointer (e.g. for a call
     52 *         to another function), use XSTRING.psz. However,
     53 *         you should NEVER modify the psz pointer yourself
     54 *         because then these functions will get into trouble.
     55 *
     56 *         Also, you should never assume that the "psz"
     57 *         pointer has not changed after you have called
     58 *         one of the xstr* functions because these can
     59 *         always reallocate the buffer if needed.
     60 *
     61 *      4) If (and only if) you have a char* buffer which
     62 *         is free()'able (e.g. from strdup()), you can
     63 *         use xstrset to avoid duplicate copying.
     64 *
    865 *      Function prefixes:
    966 *      --  xstr*       extended string functions.
    1067 *
    1168 *      The functions in this file used to be in stringh.c
    12  *      before V0.9.3 (2000-04-01).
    13  *
    14  *      Note: Version numbering in this file relates to XWorkplace version
    15  *            numbering.
     69 *      before V0.9.3 (2000-04-01). These have been largely
     70 *      rewritten with V0.9.6 (2000-11-01).
     71 *
     72 *      Note: Version numbering in this file relates to XWorkplace
     73 *            version numbering.
    1674 *
    1775 *@@added V0.9.3 (2000-04-01) [umoeller]
     
    53111
    54112/*
     113 *@@ xstrInit:
     114 *      initializes an empty XSTRING.
     115 *
     116 *      If (ulPreAllocate != 0), memory is pre-allocated
     117 *      for the string, but the string will be empty.
     118 *      This is useful if you plan to add more stuff to
     119 *      the string later so we don't have to reallocate
     120 *      all the time in xstrcat.
     121 *
     122 *      Do not use this on an XSTRING which is already
     123 *      initialized. Use xstrset instead.
     124 *
     125 *@@added V0.9.6 (2000-11-01) [umoeller]
     126 */
     127
     128void xstrInit(PXSTRING pxstr,               // in/out: string
     129              ULONG ulPreAllocate)          // in: if > 0, memory to allocate
     130{
     131    memset(pxstr, 0, sizeof(XSTRING));
     132    if (ulPreAllocate)
     133    {
     134        pxstr->psz = (PSZ)malloc(ulPreAllocate);
     135        pxstr->cbAllocated = ulPreAllocate;
     136                // ulLength is still zero
     137        *(pxstr->psz) = 0;
     138    }
     139}
     140
     141/*
     142 *@@ xstrInitSet:
     143 *      this can be used instead of xstrInit if you
     144 *      have a free()'able string you want to initialize
     145 *      the XSTRING with.
     146 *
     147 *      Do not use this on an XSTRING which is already
     148 *      initialized. Use xstrset instead.
     149 *
     150 *@@added V0.9.6 (2000-11-01) [umoeller]
     151 */
     152
     153void xstrInitSet(PXSTRING pxstr,
     154                 PSZ pszNew)
     155{
     156    pxstr->psz = pszNew;
     157    if (!pszNew)
     158    {
     159        pxstr->cbAllocated = 0;
     160        pxstr->ulLength = 0;
     161    }
     162    else
     163    {
     164        pxstr->ulLength = strlen(pszNew);
     165        pxstr->cbAllocated = pxstr->ulLength + 1;
     166    }
     167}
     168
     169/*
     170 *@@ xstrInitCopy:
     171 *      this can be used instead of xstrInit if you
     172 *      want to initialize an XSTRING with a copy
     173 *      of an existing string.
     174 *
     175 *      Do not use this on an XSTRING which is already
     176 *      initialized. Use xstrcpy instead.
     177 *
     178 *@@added V0.9.6 (2000-11-01) [umoeller]
     179 */
     180
     181void xstrInitCopy(PXSTRING pxstr,
     182                  const char *pcszSource)
     183{
     184    if (pxstr)
     185    {
     186        memset(pxstr, 0, sizeof(XSTRING));
     187
     188        if (pcszSource)
     189            pxstr->ulLength = strlen(pcszSource);
     190
     191        if (pxstr->ulLength)
     192        {
     193            // we do have a source string:
     194            pxstr->cbAllocated = pxstr->ulLength + 1;
     195            pxstr->psz = (PSZ)malloc(pxstr->cbAllocated);
     196            strcpy(pxstr->psz, pcszSource);
     197        }
     198    }
     199}
     200
     201/*
     202 *@@ xstrClear:
     203 *      clears the specified stack XSTRING and
     204 *      frees allocated memory.
     205 *
     206 *      This is the reverse to xstrInit.
     207 *
     208 *@@added V0.9.6 (2000-11-01) [umoeller]
     209 */
     210
     211void xstrClear(PXSTRING pxstr)              // in/out: string
     212{
     213    if (pxstr->psz)
     214        free(pxstr->psz);
     215    memset(pxstr, 0, sizeof(XSTRING));
     216}
     217
     218/*
     219 *@@ xstrCreate:
     220 *      allocates a new XSTRING from the heap
     221 *      and calls xstrInit on it.
     222 *
     223 *      Always use xstrFree to free associated
     224 *      resources.
     225 *
     226 *@@added V0.9.6 (2000-11-01) [umoeller]
     227 */
     228
     229PXSTRING xstrCreate(ULONG ulPreAllocate)
     230{
     231    PXSTRING pxstr = (PXSTRING)malloc(sizeof(XSTRING));
     232    if (pxstr)
     233        xstrInit(pxstr, ulPreAllocate);
     234
     235    return (pxstr);
     236}
     237
     238/*
     239 *@@ xstrFree:
     240 *      frees the specified heap XSTRING, which must
     241 *      have been created using xstrCreate.
     242 *
     243 *@@added V0.9.6 (2000-11-01) [umoeller]
     244 */
     245
     246VOID xstrFree(PXSTRING pxstr)               // in/out: string
     247{
     248    if (pxstr)
     249    {
     250        xstrClear(pxstr);
     251        free(pxstr);
     252    }
     253}
     254
     255/*
     256 *@@ xstrset:
     257 *      sets the specified XSTRING to a new string
     258 *      without copying it.
     259 *
     260 *      pxstr is cleared before the new string is set.
     261 *
     262 *      This ONLY works if pszNew has been allocated from
     263 *      the heap using malloc() or strdup() and is thus
     264 *      free()'able.
     265 *
     266 *      This assumes that exactly strlen(pszNew) + 1
     267 *      bytes have been allocated for pszNew, which
     268 *      is true if pszNew comes from strdup().
     269 *
     270 *@@added V0.9.6 (2000-11-01) [umoeller]
     271 */
     272
     273ULONG xstrset(PXSTRING pxstr,               // in/out: string
     274              PSZ pszNew)                   // in: heap PSZ to use
     275{
     276    xstrClear(pxstr);
     277    pxstr->psz = pszNew;
     278    if (pszNew)
     279    {
     280        pxstr->ulLength = strlen(pszNew);
     281        pxstr->cbAllocated = pxstr->ulLength + 1;
     282    }
     283    // else null string: cbAllocated and ulLength are 0 already
     284
     285    return (pxstr->ulLength);
     286}
     287
     288/*
    55289 *@@ xstrcpy:
    56  *      copies pszString to *ppszBuf, for which memory is allocated
     290 *      copies pcszSource to pxstr, for which memory is allocated
    57291 *      as necessary.
    58292 *
    59  *      If *ppszBuf != NULL, the existing memory is freed.
    60  *
    61  *      Returns the length of the new string (including the null
     293 *      If pxstr contains something, its contents are destroyed.
     294 *
     295 *      Returns the length of the new string (excluding the null
    62296 *      terminator), or null upon errors.
    63297 *
    64298 *      Example:
    65  +          PSZ psz = NULL;
    66  +          xstrcpy(&psz, "blah");
    67  *      would have "psz" point to newly allocated buffer containing
    68  *      "blah".
     299 *
     300 +          XSTRING str;
     301 +          xstrInit(&str, 0);
     302 +          xstrcpy(&str, "blah");
    69303 *
    70304 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcpy
    71  */
    72 
    73 ULONG xstrcpy(XSTR ppszBuf,
    74               const char *pszString)
    75 {
    76     ULONG   ulrc = 0;
    77     if (ppszBuf)
    78     {
    79         if (*ppszBuf)
    80             free(*ppszBuf);
    81         ulrc = strlen(pszString) + 1;
    82         *ppszBuf = (PSZ)malloc(ulrc);
    83         strcpy(*ppszBuf, pszString);
    84     }
    85     return (ulrc);
    86 }
    87 
    88 #ifdef __XWPMEMDEBUG__ // setup.h, helpers\memdebug.c
    89 
    90 /*
    91  *@@ xstrcatDebug:
    92  *      debug version of xstrcat.
    93  *
    94  *      stringh.h automatically maps xstrcat to this
    95  *      function if __XWPMEMDEBUG__ is defined.
    96  *
    97  *@@addded V0.9.1 (99-12-20) [umoeller]
    98  *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcatDebug
    99  */
    100 
    101 ULONG xstrcatDebug(XSTR ppszBuf,
    102                    const char *pszString,
    103                    const char *file,
    104                    unsigned long line,
    105                    const char *function)
    106 {
    107     ULONG   ulrc = 0;
    108     if ((ppszBuf) && (pszString))
    109     {
    110         if (*ppszBuf == NULL)
    111             xstrcpy(ppszBuf, pszString);
     305 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
     306 */
     307
     308ULONG xstrcpy(PXSTRING pxstr,               // in/out: string
     309              const char *pcszSource)       // in: source, can be NULL
     310{
     311    xstrClear(pxstr);
     312
     313    if (pxstr)
     314    {
     315        ULONG   ulSourceLength = 0;
     316        if (pcszSource)
     317            ulSourceLength = strlen(pcszSource);
     318
     319        if (ulSourceLength)
     320        {
     321            // we do have a source string:
     322            ULONG cbNeeded = ulSourceLength + 1;
     323            if (cbNeeded > pxstr->cbAllocated)
     324            {
     325                // we need more memory than we have previously
     326                // allocated:
     327                pxstr->cbAllocated = cbNeeded;
     328                pxstr->psz = (PSZ)malloc(cbNeeded);
     329            }
     330            // else: we have enough memory
     331
     332            strcpy(pxstr->psz, pcszSource);
     333        }
    112334        else
    113335        {
    114             ULONG   cbOld = strlen(*ppszBuf),
    115                     cbString = strlen(pszString);
    116             PSZ     pszOldCopy = strdup(*ppszBuf);
    117 
    118             ulrc = cbOld + cbString + 1;
    119             if (*ppszBuf)
    120                 free(*ppszBuf);
    121             *ppszBuf = (PSZ)memdMalloc(ulrc, file, line, function);
    122             // copy old string
    123             memcpy(*ppszBuf,
    124                    pszOldCopy,
    125                    cbOld);
    126             // append new string
    127             memcpy(*ppszBuf + cbOld,
    128                    pszString,
    129                    cbString + 1);       // include null terminator
    130             free(pszOldCopy);       // fixed V0.9.1 (99-12-20) [umoeller]
     336            // no source specified or source is empty:
     337            if (pxstr->cbAllocated)
     338                // we did have a string: set to empty,
     339                // but leave allocated memory intact
     340                *(pxstr->psz) = 0;
     341            // else: pxstr->psz is still NULL
    131342        }
    132     }
    133     return (ulrc);
    134 }
    135 
    136 #else // __XWPMEMDEBUG__
     343
     344        // in all cases, set new length
     345        pxstr->ulLength = ulSourceLength;
     346    }
     347
     348    return (pxstr->ulLength);
     349}
    137350
    138351/*
    139352 *@@ xstrcat:
    140  *      appends pszString to *ppszBuf, which is re-allocated as
    141  *      necessary.
    142  *
    143  *      If *ppszBuf is NULL, this behaves just as xstrcpy.
    144  *
    145  *      Returns the length of the new string (including the null
     353 *      appends pcszSource to pxstr, for which memory is allocated
     354 *      as necessary.
     355 *
     356 *      If pxstr is empty, this behaves just like xstrcpy.
     357 *
     358 *      Returns the length of the new string (excluding the null
    146359 *      terminator), or null upon errors.
    147360 *
    148361 *      Example:
    149  +          PSZ psz = strdup("blah");
    150  +          xstrcat(&psz, "blup");
     362 *
     363 +          XSTRING str;
     364 +          xstrInit(&str, 0);
     365 +          xstrcpy(&str, "blah");
     366 +          xstrcat(&str, "blup");
     367 *
    151368 *      would do the following:
    152  *      a)  free the old value of psz ("blah");
    153  *      b)  reallocate psz;
     369 *      a)  free the old value of str ("blah");
     370 *      b)  reallocate str;
    154371 *      c)  so that psz afterwards points to a new string containing
    155372 *          "blahblup".
     
    159376 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxcat
    160377 *@@changed V0.9.3 (2000-05-11) [umoeller]: returned 0 if pszString was initially empty; fixed
    161  */
    162 
    163 ULONG xstrcat(XSTR ppszBuf,
    164               const char *pszString)
     378 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
     379 */
     380
     381ULONG xstrcat(PXSTRING pxstr,               // in/out: string
     382              const char *pcszSource)       // in: source, can be NULL
    165383{
    166384    ULONG   ulrc = 0;
    167     if ((ppszBuf) && (pszString))
    168     {
    169         if (*ppszBuf == NULL)
    170             ulrc = xstrcpy(ppszBuf, pszString);
    171         else
     385
     386    if (pxstr)
     387    {
     388        ULONG   ulSourceLength = 0;
     389        if (pcszSource)
     390            ulSourceLength = strlen(pcszSource);
     391
     392        if (ulSourceLength)
    172393        {
    173             ULONG   cbOld = strlen(*ppszBuf),
    174                     cbString = strlen(pszString);
    175             PSZ     pszOldCopy = strdup(*ppszBuf);
    176 
    177             ulrc = cbOld + cbString + 1;
    178             if (*ppszBuf)
    179                 free(*ppszBuf);
    180             *ppszBuf = (PSZ)malloc(ulrc);
    181             // copy old string
    182             memcpy(*ppszBuf,
    183                    pszOldCopy,
    184                    cbOld);
    185             // append new string
    186             memcpy(*ppszBuf + cbOld,
    187                    pszString,
    188                    cbString + 1);       // include null terminator
    189             free(pszOldCopy);       // fixed V0.9.1 (99-12-20) [umoeller]
     394            // we do have a source string:
     395
     396            // 1) memory management
     397            ULONG   cbNeeded = pxstr->ulLength + ulSourceLength + 1;
     398            if (cbNeeded > pxstr->cbAllocated)
     399            {
     400                // we need more memory than we have previously
     401                // allocated:
     402                if (pxstr->cbAllocated)
     403                    // appendee already had memory:
     404                    // reallocate
     405                    pxstr->psz = (PSZ)realloc(pxstr->psz,
     406                                              cbNeeded);
     407                else
     408                    // appendee has no memory:
     409                    pxstr->psz = (PSZ)malloc(cbNeeded);
     410
     411                pxstr->cbAllocated = cbNeeded;
     412                        // ulLength is unchanged yet
     413            }
     414            // else: we have enough memory, both if appendee
     415            //       is empty or not empty
     416
     417            // now we have:
     418            // -- if appendee (pxstr) had enough memory, no problem
     419            // -- if appendee (pxstr) needed more memory
     420            //      -- and was not empty: pxstr->psz now points to a
     421            //         reallocated copy of the old string
     422            //      -- and was empty: pxstr->psz now points to a
     423            //         new (unitialized) buffer
     424
     425            // 2) append source string:
     426            strcpy(pxstr->psz + pxstr->ulLength,
     427                   pcszSource);
     428
     429            // in all cases, set new length
     430            pxstr->ulLength += ulSourceLength;
     431            ulrc = ulSourceLength;
    190432        }
    191     }
     433        // else no source specified or source is empty:
     434        // do nothing
     435    }
     436
    192437    return (ulrc);
    193438}
    194439
    195 #endif // else __XWPMEMDEBUG__
    196 
    197 #ifdef __XWPMEMDEBUG__ // setup.h, helpers\memdebug.c
    198 
    199 /*
    200  *@@ xstrrplDebug:
    201  *
    202  *@@added V0.9.3 (2000-04-11) [umoeller]
    203  */
    204 
    205 ULONG xstrrplDebug(PSZ *ppszBuf,     // in/out: text buffer
    206                    ULONG ulOfs,      // in: where to begin search (can be 0)
    207                    const char *pszSearch,    // in: search string
    208                    const char *pszReplace,   // in: replacement string
    209                    PULONG pulAfterOfs,  // out: offset where found (can be NULL)
    210                    const char *file,
    211                    unsigned long line,
    212                    const char *function)
    213 {
    214     ULONG    ulrc = 0;
    215 
    216     if ((ppszBuf) && (pszSearch) && (pszReplace))
    217     {
    218         ULONG   cbBuf = 0,
    219                 cbSearch = strlen(pszSearch);
    220         if (*ppszBuf)                       // fixed V0.9.0 (99-11-08) [umoeller]
    221             cbBuf =  strlen(*ppszBuf);
    222 
    223         if ((ulOfs < cbBuf) && (cbSearch))
    224         {
    225             PSZ     pFound = strstr((*ppszBuf) + ulOfs,
    226                                     pszSearch);
    227 
    228             if (pFound)
    229             {
    230                 ULONG   cbReplace = strlen(pszReplace),
    231                         // length of new string
    232                         cbNew = cbBuf
    233                                 + cbReplace
    234                                 - cbSearch
    235                                 + 1,                  // null terminator
    236                         // offset where pszSearch was found
    237                         ulFoundOfs = pFound - *ppszBuf;
    238 
    239                 // allocate new buffer
    240                 PSZ     pszNew = (PSZ)memdMalloc(cbNew,
    241                                                  file, line, function);
    242 
    243                 if (ulFoundOfs)
    244                 {
    245                     // copy until offset
    246                     strncpy(pszNew,
    247                             *ppszBuf,
    248                             ulFoundOfs);
    249                 }
    250 
    251                 if (cbReplace)
    252                 {
    253                     // copy replacement
    254                     strncpy(pszNew + ulFoundOfs,
    255                             pszReplace,
    256                             cbReplace);
    257                 }
    258                 // copy rest
    259                 strcpy(pszNew + ulFoundOfs + cbReplace,
    260                        pFound + cbSearch);
    261 
    262                 // replace PSZ pointer
    263                 memdFree(*ppszBuf, file, line, function);
    264                 *ppszBuf = pszNew;
    265 
    266                 // return new length
    267                 ulrc = cbNew;
    268                 if (pulAfterOfs)
    269                     *pulAfterOfs = ulFoundOfs + cbReplace;
    270             }
    271         }
    272     }
    273     return (ulrc);
    274 }
    275 
    276 #else
    277 
    278440/*
    279441 *@@ xstrrpl:
    280  *      replaces pszSearch with pszReplace in *ppszBuf.
    281  *
    282  *      If pszSearch was found, *ppszBuf is
    283  *      re-allocated so the buffer cannot overflow. As
    284  *      a result, *ppszBuf must be free()'able.
    285  *
    286  *      Returns the length of the new string or 0 if
    287  *      pszSearch was not found (and ppszBuf was therefore
    288  *      not changed).
     442 *      replaces pstrSearch with pstrReplace in pxstr.
     443 *
     444 *      Starting with V0.9.6, this operates entirely on
     445 *      XSTRING's for speed because we then know the string
     446 *      lengths already and can use memcpy instead of strcpy.
     447 *      This new version should be magnitudes faster.
     448 *
     449 *      None of the pointers can be NULL, but if pstrReplace
     450 *      is empty, this effectively erases pstrSearch in pxstr.
     451 *
     452 *      Returns the length of the new string (exclusing the
     453 *      null terminator) or 0 if pszSearch was not found
     454 *      (and pxstr was therefore not changed).
    289455 *
    290456 *      If the string was found and (pulAfterOfs != NULL),
     
    298464 *      function until it returns 0.
    299465 *
     466 *      There are two wrappers around this function which
     467 *      work on C strings instead (however, thus losing the
     468 *      speed advantage):
     469 *
     470 *      -- strhrpl operates on C strings only;
     471 *
     472 *      -- xstrcrpl uses C strings for the search and replace
     473 *         parameters.
     474 *
    300475 *      <B>Example usage:</B>
    301  +          PSZ psz = strdup("Test string");
    302  +          xstrrpl(&psz, "Test", "Dummy");
    303  *
    304  *      would reallocate psz to point to a new string
    305  *      containing "Dummy string".
     476 *
     477 +          XSTRING str;
     478 +          ULONG ulPos = 0;
     479 +          xstrInit(&str, 0);
     480 +          xstrcpy(&str, "Test phrase 1. Test phrase 2.");
     481 +          while (xstrrpl(&str,
     482 +                         ulPos,
     483 +                         "Test",      // search
     484 +                         "Dummy",     // replace
     485 +                         &ulPos))
     486 +              ;
     487 *
     488 *      would replace all occurences of "Test" in str with
     489 *      "Dummy".
    306490 *
    307491 *@@changed V0.9.0 [umoeller]: totally rewritten.
    308492 *@@changed V0.9.0 (99-11-08) [umoeller]: crashed if *ppszBuf was NULL. Fixed.
    309493 *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxrpl
    310  */
    311 
    312 ULONG xstrrpl(PSZ *ppszBuf,     // in/out: text buffer; cannot be NULL
    313               ULONG ulOfs,      // in: where to begin search (can be 0)
    314               const char *pszSearch,    // in: search string; cannot be NULL
    315               const char *pszReplace,   // in: replacement string; cannot be NULL
    316               PULONG pulAfterOfs)  // out: offset where found (can be NULL)
     494 *@@changed V0.9.6 (2000-11-01) [umoeller]: rewritten
     495 */
     496
     497ULONG xstrrpl(PXSTRING pxstr,               // in/out: string
     498              ULONG ulOfs,                  // in: where to begin search (0 = start)
     499              const XSTRING *pstrSearch,    // in: search string; cannot be NULL
     500              const XSTRING *pstrReplace,   // in: replacement string; cannot be NULL
     501              PULONG pulAfterOfs)           // out: offset where found (ptr can be NULL)
    317502{
    318503    ULONG    ulrc = 0;
    319504
    320     if ((ppszBuf) && (pszSearch) && (pszReplace))
    321     {
    322         ULONG   cbBuf = 0,
    323                 cbSearch = strlen(pszSearch);
    324         if (*ppszBuf)                       // fixed V0.9.0 (99-11-08) [umoeller]
    325             cbBuf =  strlen(*ppszBuf);
    326 
    327         if ((ulOfs < cbBuf) && (cbSearch))
     505    if ((pxstr) && (pstrSearch) && (pstrReplace))
     506    {
     507        ULONG   cSearchLen = pstrSearch->ulLength;
     508
     509        // can we search this?
     510        if (    (ulOfs < pxstr->ulLength)
     511             && (cSearchLen)
     512           )
    328513        {
    329             PSZ     pFound = strstr((*ppszBuf) + ulOfs,
    330                                     pszSearch);
     514            // yes:
     515            PSZ     pFound = strstr(pxstr->psz + ulOfs,
     516                                    pstrSearch->psz);
    331517
    332518            if (pFound)
    333519            {
    334                 ULONG   cbReplace = strlen(pszReplace),
    335                         // length of new string
    336                         cbNew = cbBuf
    337                                 + cbReplace
    338                                 - cbSearch
    339                                 + 1,                  // null terminator
    340                         // offset where pszSearch was found
    341                         ulFoundOfs = pFound - *ppszBuf;
    342 
    343                 // allocate new buffer
    344                 PSZ     pszNew = (PSZ)malloc(cbNew);
    345 
    346                 if (ulFoundOfs)
     520                // found in buffer from ofs:
     521                ULONG   cReplaceLen = pstrReplace->ulLength;
     522                            // can be 0!
     523
     524                // length of new string
     525                ULONG   cbNeeded = pxstr->ulLength
     526                                 + cReplaceLen
     527                                 - cSearchLen
     528                                 + 1,                  // null terminator
     529                // offset where pszSearch was found
     530                        ulFoundOfs = pFound - pxstr->psz;
     531
     532                // now check if we have enough memory...
     533                if (pxstr->cbAllocated < cbNeeded)
    347534                {
    348                     // copy until offset
    349                     strncpy(pszNew,
    350                             *ppszBuf,
    351                             ulFoundOfs);
     535                    // no, we need more memory:
     536                    // allocate new buffer
     537                    PSZ pszNew = (PSZ)malloc(cbNeeded);
     538
     539                    if (ulFoundOfs)
     540                        // "found" was not at the beginning:
     541                        // copy from beginning up to found-offset
     542                        memcpy(pszNew,
     543                               pxstr->psz,
     544                               ulFoundOfs);     // up to "found"
     545
     546                    if (cReplaceLen)
     547                    {
     548                        // we have a replacement:
     549                        // insert it next
     550                        memcpy(pszNew + ulFoundOfs,
     551                               pstrReplace->psz,
     552                               cReplaceLen + 1);        // include null terminator
     553                    }
     554
     555                    // copy rest:
     556                    // pxstr      frontFOUNDtail
     557                    //            0         1
     558                    //            01234567890123
     559                    //            ³    ³    ³  ³
     560                    //            ³    ³    ÀÄ ulFoundOfs + cSearchLen = 10
     561                    //            ³    ³       ³
     562                    //            ³    ÀÄ ulFoundOfs = 5
     563                    //            ³            ³
     564                    //            pxstr->ulLength = 14
     565                    memcpy(pszNew + ulFoundOfs + cReplaceLen,
     566                           pFound + cSearchLen,
     567                           // remaining bytes:
     568                           pxstr->ulLength - ulFoundOfs - cSearchLen // 9
     569                                + 1); // null terminator
     570
     571                    free(pxstr->psz);
     572                    pxstr->psz = pszNew;
     573                    pxstr->ulLength = cbNeeded - 1;
     574                    pxstr->cbAllocated = cbNeeded;
     575                } // end if (pxstr->cbAllocated < cbNeeded)
     576                else
     577                {
     578                    // we have enough memory left,
     579                    // we can just overwrite in the middle...
     580
     581                    PSZ     pszAfterFoundBackup = 0;
     582                    // calc length of string after "found"
     583                    ULONG   cTailLength = pxstr->ulLength - ulFoundOfs - cSearchLen;
     584
     585                    // if "replace" is longer than "found",
     586                    // make a backup of the stuff after "found",
     587                    // or this would get overwritten
     588                    if (cReplaceLen > cSearchLen)
     589                    {
     590                        pszAfterFoundBackup = (PSZ)malloc(cTailLength + 1);
     591                        memcpy(pszAfterFoundBackup,
     592                               pFound + cSearchLen,
     593                               cTailLength + 1);
     594                    }
     595
     596                    // now overwrite "found" in the middle
     597                    if (cReplaceLen)
     598                    {
     599                        memcpy(pxstr->psz + ulFoundOfs,
     600                               pstrReplace->psz,
     601                               cReplaceLen);        // no null terminator
     602                    }
     603
     604                    // now append tail (stuff after "found") again...
     605                    if (pszAfterFoundBackup)
     606                    {
     607                        // we made a backup above:
     608                        memcpy(pxstr->psz + ulFoundOfs + cReplaceLen,
     609                               pszAfterFoundBackup,
     610                               cTailLength + 1);
     611                        free(pszAfterFoundBackup);
     612                                // done!
     613                    }
     614                    else
     615                        // no backup:
     616                        if (cReplaceLen < cSearchLen)
     617                            // "replace" is shorter than "found:
     618                            memcpy(pxstr->psz + ulFoundOfs + cReplaceLen,
     619                                   pFound + cSearchLen,
     620                                   cTailLength + 1);
     621                        // else (cReplaceLen == cSearchLen):
     622                        // we can leave the tail as it is
     623
     624                    pxstr->ulLength = cbNeeded - 1;
    352625                }
    353626
    354                 if (cbReplace)
    355                 {
    356                     // copy replacement
    357                     strncpy(pszNew + ulFoundOfs,
    358                             pszReplace,
    359                             cbReplace);
    360                 }
    361                 // copy rest
    362                 strcpy(pszNew + ulFoundOfs + cbReplace,
    363                        pFound + cbSearch);
    364 
    365                 // replace PSZ pointer
    366                 free(*ppszBuf);
    367                 *ppszBuf = pszNew;
    368 
    369627                // return new length
    370                 ulrc = cbNew;
     628                ulrc = cbNeeded - 1;
    371629                if (pulAfterOfs)
    372                     *pulAfterOfs = ulFoundOfs + cbReplace;
     630                    *pulAfterOfs = ulFoundOfs + cReplaceLen;
    373631            }
    374632        }
    375633    }
     634
    376635    return (ulrc);
    377636}
    378637
    379 #endif // else __XWPMEMDEBUG__
    380 
    381 /*
    382  *@@ xstrins:
    383  *      this inserts one string into another.
    384  *
    385  *      pszInsert is inserted into pszBuffer at offset
    386  *      ulInsertOfs (which counts from 0).
    387  *
    388  *      A newly allocated string is returned. pszBuffer is
    389  *      not changed. The new string should be free()'d after
    390  *      use.
    391  *
    392  *      Upon errors, NULL is returned.
    393  *
    394  *@@changed V0.9.0 [umoeller]: completely rewritten.
    395  *@@changed V0.9.2 (2000-04-01) [umoeller]: renamed from strhxins
    396  */
    397 
    398 PSZ xstrins(PSZ pszBuffer,
    399             ULONG ulInsertOfs,
    400             const char *pszInsert)
    401 {
    402     PSZ     pszNew = NULL;
    403 
    404     if ((pszBuffer) && (pszInsert))
    405     {
    406         do {
    407             ULONG   cbBuffer = strlen(pszBuffer);
    408             ULONG   cbInsert = strlen(pszInsert);
    409 
    410             // check string length
    411             if (ulInsertOfs > cbBuffer + 1)
    412                 break;  // do
    413 
    414             // OK, let's go.
    415             pszNew = (PSZ)malloc(cbBuffer + cbInsert + 1);  // additional null terminator
    416 
    417             // copy stuff before pInsertPos
    418             memcpy(pszNew,
    419                    pszBuffer,
    420                    ulInsertOfs);
    421             // copy string to be inserted
    422             memcpy(pszNew + ulInsertOfs,
    423                    pszInsert,
    424                    cbInsert);
    425             // copy stuff after pInsertPos
    426             strcpy(pszNew + ulInsertOfs + cbInsert,
    427                    pszBuffer + ulInsertOfs);
    428         } while (FALSE);
    429     }
    430 
    431     return (pszNew);
    432 }
    433 
    434 
     638/*
     639 *@@ xstrcrpl:
     640 *      wrapper around xstrrpl which allows using C strings
     641 *      for the find and replace parameters.
     642 *
     643 *@@added V0.9.6 (2000-11-01) [umoeller]
     644 */
     645
     646ULONG xstrcrpl(PXSTRING pxstr,              // in/out: string
     647               ULONG ulOfs,                 // in: where to begin search (0 = start)
     648               const char *pcszSearch,      // in: search string; cannot be NULL
     649               const char *pcszReplace,     // in: replacement string; cannot be NULL
     650               PULONG pulAfterOfs)          // out: offset where found (ptr can be NULL)
     651{
     652    ULONG   ulrc = 0;
     653    XSTRING xstrFind,
     654            xstrReplace;
     655    xstrInit(&xstrFind, 0);
     656    xstrset(&xstrFind, (PSZ)pcszSearch);
     657    xstrInit(&xstrReplace, 0);
     658    xstrset(&xstrReplace, (PSZ)pcszReplace);
     659
     660    return (xstrrpl(pxstr, ulOfs, &xstrFind, &xstrReplace, pulAfterOfs));
     661}
     662
     663// test case
     664
     665/* int main(void)
     666{
     667    XSTRING str,
     668            strFind,
     669            strReplace;
     670    ULONG   ulOfs = 0;
     671
     672    xstrInit(&str, 100);
     673    xstrInit(&strFind, 0);
     674    xstrInit(&strReplace, 0);
     675
     676    xstrcpy(&str, "Test string 1. Test string 2. Test string 3. !");
     677    xstrcpy(&strFind, "Test");
     678    xstrcpy(&strReplace, "Dummy");
     679
     680    printf("Old string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
     681
     682    while (xstrrpl(&str,
     683                   ulOfs,
     684                   &strFind,
     685                   &strReplace,
     686                   &ulOfs))
     687        ;
     688
     689    printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
     690
     691    xstrcpy(&strFind, strReplace.psz);
     692    xstrClear(&strReplace);
     693    ulOfs = 0;
     694    while (xstrrpl(&str,
     695                   ulOfs,
     696                   &strFind,
     697                   &strReplace,
     698                   &ulOfs))
     699        ;
     700
     701    printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
     702
     703    xstrcpy(&strFind, " ");
     704    xstrcpy(&strReplace, ".");
     705    ulOfs = 0;
     706    while (xstrrpl(&str,
     707                   ulOfs,
     708                   &strFind,
     709                   &strReplace,
     710                   &ulOfs))
     711        ;
     712
     713    printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
     714
     715    xstrcpy(&strFind, ".");
     716    xstrcpy(&strReplace, "***************************");
     717    ulOfs = 0;
     718    while (xstrrpl(&str,
     719                   ulOfs,
     720                   &strFind,
     721                   &strReplace,
     722                   &ulOfs))
     723        ;
     724
     725    printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
     726
     727    xstrcpy(&strFind, "*");
     728    xstrClear(&strReplace);
     729    ulOfs = 0;
     730    while (xstrrpl(&str,
     731                   ulOfs,
     732                   &strFind,
     733                   &strReplace,
     734                   &ulOfs))
     735        ;
     736
     737    printf("New string is: \"%s\" (%d/%d)\n", str.psz, str.ulLength, str.cbAllocated);
     738} */
     739
Note: See TracChangeset for help on using the changeset viewer.