xref: /openbsd-src/gnu/lib/libiberty/src/dyn-string.c (revision 150b7e42cfa21e6546d96ae514ca23e80d970ac7)
12e0724c7Sespie /* An abstract string datatype.
2*150b7e42Smiod    Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
32e0724c7Sespie    Contributed by Mark Mitchell (mark@markmitchell.com).
42e0724c7Sespie 
52e0724c7Sespie This file is part of GNU CC.
62e0724c7Sespie 
72e0724c7Sespie GNU CC is free software; you can redistribute it and/or modify
82e0724c7Sespie it under the terms of the GNU General Public License as published by
92e0724c7Sespie the Free Software Foundation; either version 2, or (at your option)
102e0724c7Sespie any later version.
112e0724c7Sespie 
1237c53322Sespie In addition to the permissions in the GNU General Public License, the
1337c53322Sespie Free Software Foundation gives you unlimited permission to link the
1437c53322Sespie compiled version of this file into combinations with other programs,
1537c53322Sespie and to distribute those combinations without any restriction coming
1637c53322Sespie from the use of this file.  (The General Public License restrictions
1737c53322Sespie do apply in other respects; for example, they cover modification of
1837c53322Sespie the file, and distribution when not linked into a combined
1937c53322Sespie executable.)
2037c53322Sespie 
212e0724c7Sespie GNU CC is distributed in the hope that it will be useful,
222e0724c7Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
232e0724c7Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
242e0724c7Sespie GNU General Public License for more details.
252e0724c7Sespie 
262e0724c7Sespie You should have received a copy of the GNU General Public License
272e0724c7Sespie along with GNU CC; see the file COPYING.  If not, write to
28*150b7e42Smiod the Free Software Foundation, 51 Franklin Street - Fifth Floor,
29*150b7e42Smiod Boston, MA 02110-1301, USA.  */
302e0724c7Sespie 
312e0724c7Sespie #ifdef HAVE_CONFIG_H
322e0724c7Sespie #include "config.h"
332e0724c7Sespie #endif
342e0724c7Sespie 
352e0724c7Sespie #include <stdio.h>
362e0724c7Sespie 
372e0724c7Sespie #ifdef HAVE_STRING_H
382e0724c7Sespie #include <string.h>
392e0724c7Sespie #endif
402e0724c7Sespie 
412e0724c7Sespie #ifdef HAVE_STDLIB_H
422e0724c7Sespie #include <stdlib.h>
432e0724c7Sespie #endif
442e0724c7Sespie 
452e0724c7Sespie #include "libiberty.h"
462e0724c7Sespie #include "dyn-string.h"
472e0724c7Sespie 
482e0724c7Sespie /* If this file is being compiled for inclusion in the C++ runtime
492e0724c7Sespie    library, as part of the demangler implementation, we don't want to
502e0724c7Sespie    abort if an allocation fails.  Instead, percolate an error code up
512e0724c7Sespie    through the call chain.  */
522e0724c7Sespie 
5337c53322Sespie #if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
542e0724c7Sespie #define RETURN_ON_ALLOCATION_FAILURE
552e0724c7Sespie #endif
562e0724c7Sespie 
572e0724c7Sespie /* Performs in-place initialization of a dyn_string struct.  This
582e0724c7Sespie    function can be used with a dyn_string struct on the stack or
592e0724c7Sespie    embedded in another object.  The contents of of the string itself
602e0724c7Sespie    are still dynamically allocated.  The string initially is capable
612e0724c7Sespie    of holding at least SPACE characeters, including the terminating
622e0724c7Sespie    NUL.  If SPACE is 0, it will silently be increated to 1.
632e0724c7Sespie 
642e0724c7Sespie    If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
652e0724c7Sespie    fails, returns 0.  Otherwise returns 1.  */
662e0724c7Sespie 
672e0724c7Sespie int
dyn_string_init(struct dyn_string * ds_struct_ptr,int space)68*150b7e42Smiod dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
692e0724c7Sespie {
702e0724c7Sespie   /* We need at least one byte in which to store the terminating NUL.  */
712e0724c7Sespie   if (space == 0)
722e0724c7Sespie     space = 1;
732e0724c7Sespie 
742e0724c7Sespie #ifdef RETURN_ON_ALLOCATION_FAILURE
752e0724c7Sespie   ds_struct_ptr->s = (char *) malloc (space);
762e0724c7Sespie   if (ds_struct_ptr->s == NULL)
772e0724c7Sespie     return 0;
782e0724c7Sespie #else
79*150b7e42Smiod   ds_struct_ptr->s = XNEWVEC (char, space);
802e0724c7Sespie #endif
812e0724c7Sespie   ds_struct_ptr->allocated = space;
822e0724c7Sespie   ds_struct_ptr->length = 0;
832e0724c7Sespie   ds_struct_ptr->s[0] = '\0';
842e0724c7Sespie 
852e0724c7Sespie   return 1;
862e0724c7Sespie }
872e0724c7Sespie 
882e0724c7Sespie /* Create a new dynamic string capable of holding at least SPACE
892e0724c7Sespie    characters, including the terminating NUL.  If SPACE is 0, it will
902e0724c7Sespie    be silently increased to 1.  If RETURN_ON_ALLOCATION_FAILURE is
912e0724c7Sespie    defined and memory allocation fails, returns NULL.  Otherwise
922e0724c7Sespie    returns the newly allocated string.  */
932e0724c7Sespie 
942e0724c7Sespie dyn_string_t
dyn_string_new(int space)95*150b7e42Smiod dyn_string_new (int space)
962e0724c7Sespie {
972e0724c7Sespie   dyn_string_t result;
982e0724c7Sespie #ifdef RETURN_ON_ALLOCATION_FAILURE
992e0724c7Sespie   result = (dyn_string_t) malloc (sizeof (struct dyn_string));
1002e0724c7Sespie   if (result == NULL)
1012e0724c7Sespie     return NULL;
1022e0724c7Sespie   if (!dyn_string_init (result, space))
1032e0724c7Sespie     {
1042e0724c7Sespie       free (result);
1052e0724c7Sespie       return NULL;
1062e0724c7Sespie     }
1072e0724c7Sespie #else
108*150b7e42Smiod   result = XNEW (struct dyn_string);
1092e0724c7Sespie   dyn_string_init (result, space);
1102e0724c7Sespie #endif
1112e0724c7Sespie   return result;
1122e0724c7Sespie }
1132e0724c7Sespie 
1142e0724c7Sespie /* Free the memory used by DS.  */
1152e0724c7Sespie 
1162e0724c7Sespie void
dyn_string_delete(dyn_string_t ds)117*150b7e42Smiod dyn_string_delete (dyn_string_t ds)
1182e0724c7Sespie {
1192e0724c7Sespie   free (ds->s);
1202e0724c7Sespie   free (ds);
1212e0724c7Sespie }
1222e0724c7Sespie 
1232e0724c7Sespie /* Returns the contents of DS in a buffer allocated with malloc.  It
1242e0724c7Sespie    is the caller's responsibility to deallocate the buffer using free.
1252e0724c7Sespie    DS is then set to the empty string.  Deletes DS itself.  */
1262e0724c7Sespie 
1272e0724c7Sespie char*
dyn_string_release(dyn_string_t ds)128*150b7e42Smiod dyn_string_release (dyn_string_t ds)
1292e0724c7Sespie {
1302e0724c7Sespie   /* Store the old buffer.  */
1312e0724c7Sespie   char* result = ds->s;
1322e0724c7Sespie   /* The buffer is no longer owned by DS.  */
1332e0724c7Sespie   ds->s = NULL;
1342e0724c7Sespie   /* Delete DS.  */
1352e0724c7Sespie   free (ds);
1362e0724c7Sespie   /* Return the old buffer.  */
1372e0724c7Sespie   return result;
1382e0724c7Sespie }
1392e0724c7Sespie 
1402e0724c7Sespie /* Increase the capacity of DS so it can hold at least SPACE
1412e0724c7Sespie    characters, plus the terminating NUL.  This function will not (at
1422e0724c7Sespie    present) reduce the capacity of DS.  Returns DS on success.
1432e0724c7Sespie 
1442e0724c7Sespie    If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
1452e0724c7Sespie    operation fails, deletes DS and returns NULL.  */
1462e0724c7Sespie 
1472e0724c7Sespie dyn_string_t
dyn_string_resize(dyn_string_t ds,int space)148*150b7e42Smiod dyn_string_resize (dyn_string_t ds, int space)
1492e0724c7Sespie {
1502e0724c7Sespie   int new_allocated = ds->allocated;
1512e0724c7Sespie 
1522e0724c7Sespie   /* Increase SPACE to hold the NUL termination.  */
1532e0724c7Sespie   ++space;
1542e0724c7Sespie 
1552e0724c7Sespie   /* Increase allocation by factors of two.  */
1562e0724c7Sespie   while (space > new_allocated)
1572e0724c7Sespie     new_allocated *= 2;
1582e0724c7Sespie 
1592e0724c7Sespie   if (new_allocated != ds->allocated)
1602e0724c7Sespie     {
1612e0724c7Sespie       ds->allocated = new_allocated;
1622e0724c7Sespie       /* We actually need more space.  */
1632e0724c7Sespie #ifdef RETURN_ON_ALLOCATION_FAILURE
1642e0724c7Sespie       ds->s = (char *) realloc (ds->s, ds->allocated);
1652e0724c7Sespie       if (ds->s == NULL)
1662e0724c7Sespie 	{
1672e0724c7Sespie 	  free (ds);
1682e0724c7Sespie 	  return NULL;
1692e0724c7Sespie 	}
1702e0724c7Sespie #else
171*150b7e42Smiod       ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
1722e0724c7Sespie #endif
1732e0724c7Sespie     }
1742e0724c7Sespie 
1752e0724c7Sespie   return ds;
1762e0724c7Sespie }
1772e0724c7Sespie 
1782e0724c7Sespie /* Sets the contents of DS to the empty string.  */
1792e0724c7Sespie 
1802e0724c7Sespie void
dyn_string_clear(dyn_string_t ds)181*150b7e42Smiod dyn_string_clear (dyn_string_t ds)
1822e0724c7Sespie {
1832e0724c7Sespie   /* A dyn_string always has room for at least the NUL terminator.  */
1842e0724c7Sespie   ds->s[0] = '\0';
1852e0724c7Sespie   ds->length = 0;
1862e0724c7Sespie }
1872e0724c7Sespie 
1882e0724c7Sespie /* Makes the contents of DEST the same as the contents of SRC.  DEST
1892e0724c7Sespie    and SRC must be distinct.  Returns 1 on success.  On failure, if
1902e0724c7Sespie    RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
1912e0724c7Sespie 
1922e0724c7Sespie int
dyn_string_copy(dyn_string_t dest,dyn_string_t src)193*150b7e42Smiod dyn_string_copy (dyn_string_t dest, dyn_string_t src)
1942e0724c7Sespie {
1952e0724c7Sespie   if (dest == src)
1962e0724c7Sespie     abort ();
1972e0724c7Sespie 
1982e0724c7Sespie   /* Make room in DEST.  */
1992e0724c7Sespie   if (dyn_string_resize (dest, src->length) == NULL)
2002e0724c7Sespie     return 0;
2012e0724c7Sespie   /* Copy DEST into SRC.  */
2022aa20281Sespie   strlcpy (dest->s, src->s, dest->allocated);
2032e0724c7Sespie   /* Update the size of DEST.  */
2042e0724c7Sespie   dest->length = src->length;
2052e0724c7Sespie   return 1;
2062e0724c7Sespie }
2072e0724c7Sespie 
2082e0724c7Sespie /* Copies SRC, a NUL-terminated string, into DEST.  Returns 1 on
2092e0724c7Sespie    success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2102e0724c7Sespie    and returns 0.  */
2112e0724c7Sespie 
2122e0724c7Sespie int
dyn_string_copy_cstr(dyn_string_t dest,const char * src)213*150b7e42Smiod dyn_string_copy_cstr (dyn_string_t dest, const char *src)
2142e0724c7Sespie {
2152e0724c7Sespie   int length = strlen (src);
2162e0724c7Sespie   /* Make room in DEST.  */
2172e0724c7Sespie   if (dyn_string_resize (dest, length) == NULL)
2182e0724c7Sespie     return 0;
2192e0724c7Sespie   /* Copy DEST into SRC.  */
2202aa20281Sespie   strlcpy (dest->s, src, dest->allocated);
2212e0724c7Sespie   /* Update the size of DEST.  */
2222e0724c7Sespie   dest->length = length;
2232e0724c7Sespie   return 1;
2242e0724c7Sespie }
2252e0724c7Sespie 
2262e0724c7Sespie /* Inserts SRC at the beginning of DEST.  DEST is expanded as
2272e0724c7Sespie    necessary.  SRC and DEST must be distinct.  Returns 1 on success.
2282e0724c7Sespie    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
2292e0724c7Sespie    returns 0.  */
2302e0724c7Sespie 
2312e0724c7Sespie int
dyn_string_prepend(dyn_string_t dest,dyn_string_t src)232*150b7e42Smiod dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
2332e0724c7Sespie {
2342e0724c7Sespie   return dyn_string_insert (dest, 0, src);
2352e0724c7Sespie }
2362e0724c7Sespie 
2372e0724c7Sespie /* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
2382e0724c7Sespie    DEST is expanded as necessary.  Returns 1 on success.  On failure,
2392e0724c7Sespie    if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
2402e0724c7Sespie 
2412e0724c7Sespie int
dyn_string_prepend_cstr(dyn_string_t dest,const char * src)242*150b7e42Smiod dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
2432e0724c7Sespie {
2442e0724c7Sespie   return dyn_string_insert_cstr (dest, 0, src);
2452e0724c7Sespie }
2462e0724c7Sespie 
2472e0724c7Sespie /* Inserts SRC into DEST starting at position POS.  DEST is expanded
2482e0724c7Sespie    as necessary.  SRC and DEST must be distinct.  Returns 1 on
2492e0724c7Sespie    success.  On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2502e0724c7Sespie    and returns 0.  */
2512e0724c7Sespie 
2522e0724c7Sespie int
dyn_string_insert(dyn_string_t dest,int pos,dyn_string_t src)253*150b7e42Smiod dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
2542e0724c7Sespie {
2552e0724c7Sespie   int i;
2562e0724c7Sespie 
2572e0724c7Sespie   if (src == dest)
2582e0724c7Sespie     abort ();
2592e0724c7Sespie 
2602e0724c7Sespie   if (dyn_string_resize (dest, dest->length + src->length) == NULL)
2612e0724c7Sespie     return 0;
2622e0724c7Sespie   /* Make room for the insertion.  Be sure to copy the NUL.  */
2632e0724c7Sespie   for (i = dest->length; i >= pos; --i)
2642e0724c7Sespie     dest->s[i + src->length] = dest->s[i];
2652e0724c7Sespie   /* Splice in the new stuff.  */
2662e0724c7Sespie   strncpy (dest->s + pos, src->s, src->length);
2672e0724c7Sespie   /* Compute the new length.  */
2682e0724c7Sespie   dest->length += src->length;
2692e0724c7Sespie   return 1;
2702e0724c7Sespie }
2712e0724c7Sespie 
2722e0724c7Sespie /* Inserts SRC, a NUL-terminated string, into DEST starting at
2732e0724c7Sespie    position POS.  DEST is expanded as necessary.  Returns 1 on
2742e0724c7Sespie    success.  On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
2752e0724c7Sespie    and returns 0.  */
2762e0724c7Sespie 
2772e0724c7Sespie int
dyn_string_insert_cstr(dyn_string_t dest,int pos,const char * src)278*150b7e42Smiod dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
2792e0724c7Sespie {
2802e0724c7Sespie   int i;
2812e0724c7Sespie   int length = strlen (src);
2822e0724c7Sespie 
2832e0724c7Sespie   if (dyn_string_resize (dest, dest->length + length) == NULL)
2842e0724c7Sespie     return 0;
2852e0724c7Sespie   /* Make room for the insertion.  Be sure to copy the NUL.  */
2862e0724c7Sespie   for (i = dest->length; i >= pos; --i)
2872e0724c7Sespie     dest->s[i + length] = dest->s[i];
2882e0724c7Sespie   /* Splice in the new stuff.  */
2892e0724c7Sespie   strncpy (dest->s + pos, src, length);
2902e0724c7Sespie   /* Compute the new length.  */
2912e0724c7Sespie   dest->length += length;
2922e0724c7Sespie   return 1;
2932e0724c7Sespie }
2942e0724c7Sespie 
295f5dd06f4Sespie /* Inserts character C into DEST starting at position POS.  DEST is
296f5dd06f4Sespie    expanded as necessary.  Returns 1 on success.  On failure,
297f5dd06f4Sespie    RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
298f5dd06f4Sespie 
299f5dd06f4Sespie int
dyn_string_insert_char(dyn_string_t dest,int pos,int c)300*150b7e42Smiod dyn_string_insert_char (dyn_string_t dest, int pos, int c)
301f5dd06f4Sespie {
302f5dd06f4Sespie   int i;
303f5dd06f4Sespie 
304f5dd06f4Sespie   if (dyn_string_resize (dest, dest->length + 1) == NULL)
305f5dd06f4Sespie     return 0;
306f5dd06f4Sespie   /* Make room for the insertion.  Be sure to copy the NUL.  */
307f5dd06f4Sespie   for (i = dest->length; i >= pos; --i)
308f5dd06f4Sespie     dest->s[i + 1] = dest->s[i];
309f5dd06f4Sespie   /* Add the new character.  */
310f5dd06f4Sespie   dest->s[pos] = c;
311f5dd06f4Sespie   /* Compute the new length.  */
312f5dd06f4Sespie   ++dest->length;
313f5dd06f4Sespie   return 1;
314f5dd06f4Sespie }
315f5dd06f4Sespie 
3162e0724c7Sespie /* Append S to DS, resizing DS if necessary.  Returns 1 on success.
3172e0724c7Sespie    On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
3182e0724c7Sespie    returns 0.  */
3192e0724c7Sespie 
3202e0724c7Sespie int
dyn_string_append(dyn_string_t dest,dyn_string_t s)321*150b7e42Smiod dyn_string_append (dyn_string_t dest, dyn_string_t s)
3222e0724c7Sespie {
3232e0724c7Sespie   if (dyn_string_resize (dest, dest->length + s->length) == 0)
3242e0724c7Sespie     return 0;
3252aa20281Sespie   strlcpy (dest->s + dest->length, s->s, dest->allocated - dest->length);
3262e0724c7Sespie   dest->length += s->length;
3272e0724c7Sespie   return 1;
3282e0724c7Sespie }
3292e0724c7Sespie 
3302e0724c7Sespie /* Append the NUL-terminated string S to DS, resizing DS if necessary.
3312e0724c7Sespie    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
3322e0724c7Sespie    deletes DEST and returns 0.  */
3332e0724c7Sespie 
3342e0724c7Sespie int
dyn_string_append_cstr(dyn_string_t dest,const char * s)335*150b7e42Smiod dyn_string_append_cstr (dyn_string_t dest, const char *s)
3362e0724c7Sespie {
3372e0724c7Sespie   int len = strlen (s);
3382e0724c7Sespie 
3392e0724c7Sespie   /* The new length is the old length plus the size of our string, plus
3402e0724c7Sespie      one for the null at the end.  */
3412e0724c7Sespie   if (dyn_string_resize (dest, dest->length + len) == NULL)
3422e0724c7Sespie     return 0;
3432aa20281Sespie   strlcpy (dest->s + dest->length, s, dest->allocated - dest->length);
3442e0724c7Sespie   dest->length += len;
3452e0724c7Sespie   return 1;
3462e0724c7Sespie }
3472e0724c7Sespie 
3482e0724c7Sespie /* Appends C to the end of DEST.  Returns 1 on success.  On failiure,
3492e0724c7Sespie    if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0.  */
3502e0724c7Sespie 
3512e0724c7Sespie int
dyn_string_append_char(dyn_string_t dest,int c)352*150b7e42Smiod dyn_string_append_char (dyn_string_t dest, int c)
3532e0724c7Sespie {
3542e0724c7Sespie   /* Make room for the extra character.  */
3552e0724c7Sespie   if (dyn_string_resize (dest, dest->length + 1) == NULL)
3562e0724c7Sespie     return 0;
3572e0724c7Sespie   /* Append the character; it will overwrite the old NUL.  */
3582e0724c7Sespie   dest->s[dest->length] = c;
3592e0724c7Sespie   /* Add a new NUL at the end.  */
3602e0724c7Sespie   dest->s[dest->length + 1] = '\0';
3612e0724c7Sespie   /* Update the length.  */
3622e0724c7Sespie   ++(dest->length);
3632e0724c7Sespie   return 1;
3642e0724c7Sespie }
3652e0724c7Sespie 
3662e0724c7Sespie /* Sets the contents of DEST to the substring of SRC starting at START
3672e0724c7Sespie    and ending before END.  START must be less than or equal to END,
3682e0724c7Sespie    and both must be between zero and the length of SRC, inclusive.
3692e0724c7Sespie    Returns 1 on success.  On failure, if RETURN_ON_ALLOCATION_FAILURE,
3702e0724c7Sespie    deletes DEST and returns 0.  */
3712e0724c7Sespie 
3722e0724c7Sespie int
dyn_string_substring(dyn_string_t dest,dyn_string_t src,int start,int end)373*150b7e42Smiod dyn_string_substring (dyn_string_t dest, dyn_string_t src,
374*150b7e42Smiod                       int start, int end)
3752e0724c7Sespie {
3762e0724c7Sespie   int i;
3772e0724c7Sespie   int length = end - start;
3782e0724c7Sespie 
3792e0724c7Sespie   if (start > end || start > src->length || end > src->length)
3802e0724c7Sespie     abort ();
3812e0724c7Sespie 
3822e0724c7Sespie   /* Make room for the substring.  */
3832e0724c7Sespie   if (dyn_string_resize (dest, length) == NULL)
3842e0724c7Sespie     return 0;
3852e0724c7Sespie   /* Copy the characters in the substring,  */
3862e0724c7Sespie   for (i = length; --i >= 0; )
3872e0724c7Sespie     dest->s[i] = src->s[start + i];
3882e0724c7Sespie   /* NUL-terimate the result.  */
3892e0724c7Sespie   dest->s[length] = '\0';
3902e0724c7Sespie   /* Record the length of the substring.  */
3912e0724c7Sespie   dest->length = length;
3922e0724c7Sespie 
3932e0724c7Sespie   return 1;
3942e0724c7Sespie }
3952e0724c7Sespie 
3962e0724c7Sespie /* Returns non-zero if DS1 and DS2 have the same contents.  */
3972e0724c7Sespie 
3982e0724c7Sespie int
dyn_string_eq(dyn_string_t ds1,dyn_string_t ds2)399*150b7e42Smiod dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
4002e0724c7Sespie {
4012e0724c7Sespie   /* If DS1 and DS2 have different lengths, they must not be the same.  */
4022e0724c7Sespie   if (ds1->length != ds2->length)
4032e0724c7Sespie     return 0;
4042e0724c7Sespie   else
4052e0724c7Sespie     return !strcmp (ds1->s, ds2->s);
4062e0724c7Sespie }
407