@@ -43,8 +43,6 @@ static bool string_list_deinitialize_internal(struct string_list *list)
4343 free (list -> elems [i ].data );
4444 if (list -> elems [i ].userdata )
4545 free (list -> elems [i ].userdata );
46- list -> elems [i ].data = NULL ;
47- list -> elems [i ].userdata = NULL ;
4846 }
4947
5048 free (list -> elems );
@@ -64,7 +62,8 @@ bool string_list_capacity(struct string_list *list, size_t cap)
6462 return false;
6563
6664 if (cap > list -> cap )
67- memset (& new_data [list -> cap ], 0 , sizeof (* new_data ) * (cap - list -> cap ));
65+ memset (& new_data [list -> cap ], 0 ,
66+ sizeof (* new_data ) * (cap - list -> cap ));
6867
6968 list -> elems = new_data ;
7069 list -> cap = cap ;
@@ -87,78 +86,104 @@ bool string_list_deinitialize(struct string_list *list)
8786 return false;
8887 if (!string_list_deinitialize_internal (list ))
8988 return false;
90- list -> elems = NULL ;
91- list -> size = 0 ;
92- list -> cap = 0 ;
89+ list -> elems = NULL ;
90+ list -> size = 0 ;
91+ list -> cap = 0 ;
9392 return true;
9493}
9594
9695struct string_list * string_list_new (void )
9796{
98- struct string_list_elem *
99- elems = NULL ;
97+ struct string_list_elem * elems = NULL ;
10098 struct string_list * list = (struct string_list * )
10199 malloc (sizeof (* list ));
102100 if (!list )
103101 return NULL ;
104102
105- list -> cap = 0 ;
106- list -> size = 0 ;
107- list -> elems = NULL ;
103+ list -> cap = 0 ;
104+ list -> size = 0 ;
105+ list -> elems = NULL ;
108106
109- if (!(elems = (struct string_list_elem * )
110- calloc (32 , sizeof (* elems ))))
107+ elems = (struct string_list_elem * )
108+ calloc (32 , sizeof (* elems ));
109+ if (!elems )
111110 {
112- string_list_free (list );
111+ free (list );
113112 return NULL ;
114113 }
115114
116- list -> elems = elems ;
117- list -> cap = 32 ;
115+ list -> elems = elems ;
116+ list -> cap = 32 ;
118117
119118 return list ;
120119}
121120
122121bool string_list_initialize (struct string_list * list )
123122{
124- struct string_list_elem *
125- elems = NULL ;
123+ struct string_list_elem * elems = NULL ;
126124 if (!list )
127125 return false;
128- if (!(elems = (struct string_list_elem * )
129- calloc (32 , sizeof (* elems ))))
126+
127+ elems = (struct string_list_elem * )
128+ calloc (32 , sizeof (* elems ));
129+ if (!elems )
130130 {
131131 string_list_deinitialize (list );
132132 return false;
133133 }
134- list -> elems = elems ;
135- list -> size = 0 ;
136- list -> cap = 32 ;
134+
135+ list -> elems = elems ;
136+ list -> size = 0 ;
137+ list -> cap = 32 ;
137138 return true;
138139}
139140
140141bool string_list_append (struct string_list * list , const char * elem ,
141142 union string_list_elem_attr attr )
142143{
143144 char * data_dup = NULL ;
145+ size_t elem_len ;
144146
145- /* Note: If 'list' is incorrectly initialised
146- * (i.e. if struct is zero initialised and
147- * string_list_initialize() is not called on
148- * it) capacity will be zero. This will cause
149- * a segfault. Handle this case by forcing the new
150- * capacity to a fixed size of 32 */
147+ /* Grow first - if this fails we haven't wasted a strdup. */
151148 if ( list -> size >= list -> cap
152149 && !string_list_capacity (list ,
153150 (list -> cap > 0 ) ? (list -> cap * 2 ) : 32 ))
154151 return false;
155152
156- if (!(data_dup = strdup (elem )))
153+ /* Manual strdup: single traversal of elem to get length,
154+ * then malloc + memcpy (avoids the hidden strlen inside
155+ * libc strdup on some platforms that do strlen+malloc+memcpy
156+ * as two passes). */
157+ elem_len = strlen (elem );
158+ data_dup = (char * )malloc (elem_len + 1 );
159+ if (!data_dup )
157160 return false;
161+ memcpy (data_dup , elem , elem_len + 1 );
158162
159163 list -> elems [list -> size ].data = data_dup ;
160164 list -> elems [list -> size ].attr = attr ;
165+ list -> size ++ ;
166+ return true;
167+ }
168+
169+ bool string_list_append_n (struct string_list * list , const char * elem ,
170+ size_t len , union string_list_elem_attr attr )
171+ {
172+ char * data_dup = NULL ;
173+
174+ if ( list -> size >= list -> cap
175+ && !string_list_capacity (list ,
176+ (list -> cap > 0 ) ? (list -> cap * 2 ) : 32 ))
177+ return false;
161178
179+ data_dup = (char * )malloc (len + 1 );
180+ if (!data_dup )
181+ return false;
182+ memcpy (data_dup , elem , len );
183+ data_dup [len ] = '\0' ;
184+
185+ list -> elems [list -> size ].data = data_dup ;
186+ list -> elems [list -> size ].attr = attr ;
162187 list -> size ++ ;
163188 return true;
164189}
@@ -200,6 +225,31 @@ void string_list_join_concat_special(char *s, size_t len,
200225 }
201226}
202227
228+ /**
229+ * Count delimited tokens in @str without modifying it.
230+ * Treats any character in @delim as a separator (same as strtok).
231+ * Returns the number of non-empty tokens.
232+ */
233+ static size_t string_count_tokens (const char * str , const char * delim )
234+ {
235+ size_t count = 0 ;
236+ bool in_tok = false;
237+ const char * p = str ;
238+
239+ for (; * p != '\0' ; p ++ )
240+ {
241+ if (strchr (delim , (unsigned char )* p ))
242+ in_tok = false;
243+ else if (!in_tok )
244+ {
245+ in_tok = true;
246+ count ++ ;
247+ }
248+ }
249+
250+ return count ;
251+ }
252+
203253struct string_list * string_split (const char * str , const char * delim )
204254{
205255 char * save = NULL ;
@@ -213,14 +263,28 @@ struct string_list *string_split(const char *str, const char *delim)
213263 if (!(copy = strdup (str )))
214264 goto error ;
215265
266+ /* Pre-size the element array to avoid repeated reallocs.
267+ * We scan the original string (not the copy, since strtok
268+ * mutates it) to count tokens. */
269+ {
270+ size_t token_count = string_count_tokens (str , delim );
271+ if (token_count > list -> cap )
272+ {
273+ if (!string_list_capacity (list , token_count ))
274+ goto error ;
275+ }
276+ }
277+
216278 tmp = strtok_r (copy , delim , & save );
217279 while (tmp )
218280 {
219281 union string_list_elem_attr attr ;
282+ size_t tok_len ;
220283
221- attr .i = 0 ;
284+ attr .i = 0 ;
285+ tok_len = strlen (tmp );
222286
223- if (!string_list_append (list , tmp , attr ))
287+ if (!string_list_append_n (list , tmp , tok_len , attr ))
224288 goto error ;
225289
226290 tmp = strtok_r (NULL , delim , & save );
@@ -248,14 +312,29 @@ bool string_split_noalloc(struct string_list *list,
248312 if (!(copy = strdup (str )))
249313 return false;
250314
251- tmp = strtok_r (copy , delim , & save );
315+ /* Pre-size to avoid repeated reallocs. */
316+ {
317+ size_t token_count = string_count_tokens (str , delim );
318+ if (token_count > list -> cap )
319+ {
320+ if (!string_list_capacity (list , token_count ))
321+ {
322+ free (copy );
323+ return false;
324+ }
325+ }
326+ }
327+
328+ tmp = strtok_r (copy , delim , & save );
252329 while (tmp )
253330 {
254331 union string_list_elem_attr attr ;
332+ size_t tok_len ;
255333
256- attr .i = 0 ;
334+ attr .i = 0 ;
335+ tok_len = strlen (tmp );
257336
258- if (!string_list_append (list , tmp , attr ))
337+ if (!string_list_append_n (list , tmp , tok_len , attr ))
259338 {
260339 free (copy );
261340 return false;
@@ -289,7 +368,7 @@ bool string_list_find_elem_prefix(const struct string_list *list,
289368 {
290369 size_t i ;
291370 char prefixed [255 ];
292- size_t _len = strlcpy (prefixed , prefix , sizeof (prefixed ));
371+ size_t _len = strlcpy (prefixed , prefix , sizeof (prefixed ));
293372 strlcpy (prefixed + _len , elem , sizeof (prefixed ) - _len );
294373 for (i = 0 ; i < list -> size ; i ++ )
295374 {
@@ -311,36 +390,34 @@ struct string_list *string_list_clone(const struct string_list *src)
311390 if (!dest )
312391 return NULL ;
313392
314- dest -> elems = NULL ;
315- dest -> size = src -> size ;
316- if (src -> cap < dest -> size )
317- dest -> cap = dest -> size ;
318- else
319- dest -> cap = src -> cap ;
393+ dest -> elems = NULL ;
394+ dest -> size = src -> size ;
395+ dest -> cap = (src -> cap < dest -> size ) ? dest -> size : src -> cap ;
320396
321- if (!(elems = (struct string_list_elem * )
322- calloc (dest -> cap , sizeof (struct string_list_elem ))))
397+ elems = (struct string_list_elem * )
398+ calloc (dest -> cap , sizeof (struct string_list_elem ));
399+ if (!elems )
323400 {
324401 free (dest );
325402 return NULL ;
326403 }
327404
328- dest -> elems = elems ;
405+ dest -> elems = elems ;
329406
330407 for (i = 0 ; i < src -> size ; i ++ )
331408 {
332- const char * _src = src -> elems [i ].data ;
333- size_t len = _src ? strlen (_src ) : 0 ;
409+ const char * _src = src -> elems [i ].data ;
410+ size_t slen = _src ? strlen (_src ) : 0 ;
334411
335412 dest -> elems [i ].data = NULL ;
336413 dest -> elems [i ].attr = src -> elems [i ].attr ;
337414
338- if (len != 0 )
415+ if (slen != 0 )
339416 {
340- char * ret = (char * )malloc (len + 1 );
417+ char * ret = (char * )malloc (slen + 1 );
341418 if (ret )
342419 {
343- strcpy (ret , _src );
420+ memcpy (ret , _src , slen + 1 ); /* memcpy > strcpy: no NUL scan */
344421 dest -> elems [i ].data = ret ;
345422 }
346423 }
0 commit comments