1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #include <fc_config.h>
17 #include <stdlib.h> /* qsort() */
26 #include "string_vector.h"
28 /* The string vector structure. */
34 /**************************************************************************
36 **************************************************************************/
37 static void string_free(char *string
)
44 /**************************************************************************
46 **************************************************************************/
47 static char *string_duplicate(const char *string
)
50 return fc_strdup(string
);
55 /**************************************************************************
56 Create a new string vector.
57 **************************************************************************/
58 struct strvec
*strvec_new(void)
60 struct strvec
*psv
= fc_malloc(sizeof(struct strvec
));
68 /**************************************************************************
69 Destroy a string vector.
70 **************************************************************************/
71 void strvec_destroy(struct strvec
*psv
)
77 /**************************************************************************
78 Set the size of the vector.
79 **************************************************************************/
80 void strvec_reserve(struct strvec
*psv
, size_t reserve
)
82 if (reserve
== psv
->size
) {
84 } else if (reserve
== 0) {
87 } else if (!psv
->vec
) {
89 psv
->vec
= fc_calloc(reserve
, sizeof(char *));
90 } else if (reserve
> psv
->size
) {
91 /* Expand the vector. */
92 psv
->vec
= fc_realloc(psv
->vec
, reserve
* sizeof(char *));
93 memset(psv
->vec
+ psv
->size
, 0, (reserve
- psv
->size
) * sizeof(char *));
95 /* Shrink the vector: free the extra strings. */
98 for (i
= psv
->size
- 1; i
>= reserve
; i
--) {
99 string_free(psv
->vec
[i
]);
101 psv
->vec
= fc_realloc(psv
->vec
, reserve
* sizeof(char *));
106 /**************************************************************************
107 Stores the string vector from a normal vector. If size == -1, it will
108 assume it is a NULL terminated vector.
109 **************************************************************************/
110 void strvec_store(struct strvec
*psv
, const char *const *vec
, size_t size
)
112 if (size
== (size_t) -1) {
114 for (; *vec
; vec
++) {
115 strvec_append(psv
, *vec
);
120 strvec_reserve(psv
, size
);
121 for (i
= 0; i
< size
; i
++, vec
++) {
122 strvec_set(psv
, i
, *vec
);
127 /****************************************************************************
128 Build the string vector from a string until 'str_size' bytes are read.
129 Passing -1 for 'str_size' will assume 'str' as the expected format. Note
130 it's a bit dangerous.
132 This string format is a list of strings separated by 'separator'.
134 See also strvec_to_str().
135 ****************************************************************************/
136 void strvec_from_str(struct strvec
*psv
, char separator
, const char *str
)
142 while ((p
= strchr(str
, separator
))) {
143 new_str
= fc_malloc(p
- str
+ 1);
144 memcpy(new_str
, str
, p
- str
);
145 new_str
[p
- str
] = '\0';
147 psv
->vec
= fc_realloc(psv
->vec
, psv
->size
* sizeof(char *));
148 psv
->vec
[psv
->size
- 1] = new_str
;
152 strvec_append(psv
, str
);
156 /**************************************************************************
157 Remove all strings from the vector.
158 **************************************************************************/
159 void strvec_clear(struct strvec
*psv
)
168 for (i
= 0, p
= psv
->vec
; i
< psv
->size
; i
++, p
++) {
176 /**************************************************************************
177 Remove strings which are duplicated inside the vector.
178 **************************************************************************/
179 void strvec_remove_duplicate(struct strvec
*psv
,
180 int (*cmp_func
) (const char *, const char *))
183 const char *str1
, *str2
;
185 if (!psv
->vec
|| 1 == psv
->size
) {
189 for (i
= 1; i
< psv
->size
; i
++) {
190 if ((str1
= psv
->vec
[i
])) {
191 for (j
= 0; j
< i
; j
++) {
192 if ((str2
= psv
->vec
[j
])
193 && 0 == cmp_func(str2
, str1
)) {
194 strvec_remove(psv
, i
);
203 /**************************************************************************
204 Remove all empty strings from the vector and removes all leading and
206 **************************************************************************/
207 void strvec_remove_empty(struct strvec
*psv
)
216 for (i
= 0; i
< psv
->size
;) {
220 strvec_remove(psv
, i
);
224 remove_leading_trailing_spaces(str
);
225 if (str
[0] == '\0') {
226 strvec_remove(psv
, i
);
234 /**************************************************************************
235 Copy a string vector.
236 **************************************************************************/
237 void strvec_copy(struct strvec
*dest
, const struct strvec
*src
)
248 strvec_reserve(dest
, src
->size
);
249 for (i
= 0, p
= dest
->vec
, l
= src
->vec
; i
< dest
->size
; i
++, p
++, l
++) {
251 *p
= string_duplicate(*l
);
255 /**************************************************************************
256 Sort the string vector, using qsort().
257 **************************************************************************/
258 void strvec_sort(struct strvec
*psv
, int (*sort_func
) (const char *const *,
259 const char *const *))
261 qsort(psv
->vec
, psv
->size
, sizeof(const char *),
262 (int (*) (const void *, const void *)) sort_func
);
265 /**************************************************************************
266 Insert a string at the start of the vector.
267 **************************************************************************/
268 void strvec_prepend(struct strvec
*psv
, const char *string
)
270 strvec_reserve(psv
, psv
->size
+ 1);
271 memmove(psv
->vec
+ 1, psv
->vec
, (psv
->size
- 1) * sizeof(char *));
272 psv
->vec
[0] = string_duplicate(string
);
275 /**************************************************************************
276 Insert a string at the end of the vector.
277 **************************************************************************/
278 void strvec_append(struct strvec
*psv
, const char *string
)
280 strvec_reserve(psv
, psv
->size
+ 1);
281 psv
->vec
[psv
->size
- 1] = string_duplicate(string
);
284 /**************************************************************************
285 Insert a string at the index of the vector.
286 **************************************************************************/
287 void strvec_insert(struct strvec
*psv
, size_t svindex
, const char *string
)
290 strvec_prepend(psv
, string
);
291 } else if (svindex
>= psv
->size
) {
292 strvec_append(psv
, string
);
294 strvec_reserve(psv
, psv
->size
+ 1);
295 memmove(psv
->vec
+ svindex
+ 1, psv
->vec
+ svindex
,
296 (psv
->size
- svindex
- 1) * sizeof(char *));
297 psv
->vec
[svindex
] = string_duplicate(string
);
301 /**************************************************************************
302 Replace a string at the index of the vector.
303 Returns TRUE if the element has been really set.
304 **************************************************************************/
305 bool strvec_set(struct strvec
*psv
, size_t svindex
, const char *string
)
307 if (strvec_index_valid(psv
, svindex
)) {
308 string_free(psv
->vec
[svindex
]);
309 psv
->vec
[svindex
] = string_duplicate(string
);
315 /**************************************************************************
316 Remove the string at the index from the vector.
317 Returns TRUE if the element has been really removed.
318 **************************************************************************/
319 bool strvec_remove(struct strvec
*psv
, size_t svindex
)
321 if (!strvec_index_valid(psv
, svindex
)) {
325 if (psv
->size
== 1) {
326 /* It is the last. */
331 string_free(psv
->vec
[svindex
]);
332 memmove(psv
->vec
+ svindex
, psv
->vec
+ svindex
+ 1,
333 (psv
->size
- svindex
- 1) * sizeof(char *));
334 psv
->vec
[psv
->size
- 1] = NULL
; /* Do not attempt to free this data. */
335 strvec_reserve(psv
, psv
->size
- 1);
340 /**************************************************************************
341 Returns the size of the vector.
342 **************************************************************************/
343 size_t strvec_size(const struct strvec
*psv
)
348 /**************************************************************************
349 Returns the datas of the vector.
350 **************************************************************************/
351 const char *const *strvec_data(const struct strvec
*psv
)
353 return (const char **) psv
->vec
;
356 /**************************************************************************
357 Returns TRUE if the index is valid.
358 **************************************************************************/
359 bool strvec_index_valid(const struct strvec
*psv
, size_t svindex
)
361 return svindex
>= 0 && svindex
< psv
->size
;
364 /**************************************************************************
365 Returns the string at the index of the vector.
366 **************************************************************************/
367 const char *strvec_get(const struct strvec
*psv
, size_t svindex
)
369 return strvec_index_valid(psv
, svindex
) ? psv
->vec
[svindex
] : NULL
;
372 /****************************************************************************
373 Build the string from a string vector.
375 This string format is a list of strings separated by 'separator'.
377 See also strvec_from_str().
378 ****************************************************************************/
379 void strvec_to_str(const struct strvec
*psv
, char separator
,
380 char *buf
, size_t buf_len
)
384 strvec_iterate(psv
, str
) {
385 len
= fc_snprintf(buf
, buf_len
, "%s", str
) + 1;
394 *(buf
- 1) = separator
;
396 } strvec_iterate_end
;
401 /****************************************************************************
402 Build a localized string with the elements of the string vector. Elements
403 will be "or"-separated.
405 See also astr_build_or_list(), strvec_to_and_list().
406 ****************************************************************************/
407 const char *strvec_to_or_list(const struct strvec
*psv
,
408 struct astring
*astr
)
410 fc_assert_ret_val(NULL
!= psv
, NULL
);
411 return astr_build_or_list(astr
, (const char **) psv
->vec
, psv
->size
);
414 /****************************************************************************
415 Build a localized string with the elements of the string vector. Elements
416 will be "and"-separated.
418 See also astr_build_and_list(), strvec_to_or_list().
419 ****************************************************************************/
420 const char *strvec_to_and_list(const struct strvec
*psv
,
421 struct astring
*astr
)
423 fc_assert_ret_val(NULL
!= psv
, NULL
);
424 return astr_build_and_list(astr
, (const char **) psv
->vec
, psv
->size
);