Replaced deprecated gtk_menu_popup() calls with modern constructs in gtk3.22-client
[freeciv.git] / utility / string_vector.c
blob9f811c9ddaa4ec2e8592154b343970a292804c7c
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)
6 any later version.
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 ***********************************************************************/
13 #ifdef HAVE_CONFIG_H
14 #include <fc_config.h>
15 #endif
17 #include <stdlib.h> /* qsort() */
18 #include <string.h>
20 /* utility */
21 #include "astring.h"
22 #include "mem.h"
23 #include "shared.h"
24 #include "support.h"
26 #include "string_vector.h"
28 /* The string vector structure. */
29 struct strvec {
30 char **vec;
31 size_t size;
34 /**************************************************************************
35 Free a string.
36 **************************************************************************/
37 static void string_free(char *string)
39 if (string) {
40 free(string);
44 /**************************************************************************
45 Duplicate a string.
46 **************************************************************************/
47 static char *string_duplicate(const char *string)
49 if (string) {
50 return fc_strdup(string);
52 return NULL;
55 /**************************************************************************
56 Create a new string vector.
57 **************************************************************************/
58 struct strvec *strvec_new(void)
60 struct strvec *psv = fc_malloc(sizeof(struct strvec));
62 psv->vec = NULL;
63 psv->size = 0;
65 return psv;
68 /**************************************************************************
69 Destroy a string vector.
70 **************************************************************************/
71 void strvec_destroy(struct strvec *psv)
73 strvec_clear(psv);
74 free(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) {
83 return;
84 } else if (reserve == 0) {
85 strvec_clear(psv);
86 return;
87 } else if (!psv->vec) {
88 /* Initial reserve */
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 *));
94 } else {
95 /* Shrink the vector: free the extra strings. */
96 size_t i;
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 *));
103 psv->size = reserve;
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) {
113 strvec_clear(psv);
114 for (; *vec; vec++) {
115 strvec_append(psv, *vec);
117 } else {
118 size_t i;
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)
138 const char *p;
139 char *new_str;
141 strvec_clear(psv);
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';
146 psv->size++;
147 psv->vec = fc_realloc(psv->vec, psv->size * sizeof(char *));
148 psv->vec[psv->size - 1] = new_str;
149 str = p + 1;
151 if ('\0' != *str) {
152 strvec_append(psv, str);
156 /**************************************************************************
157 Remove all strings from the vector.
158 **************************************************************************/
159 void strvec_clear(struct strvec *psv)
161 size_t i;
162 char **p;
164 if (!psv->vec) {
165 return;
168 for (i = 0, p = psv->vec; i < psv->size; i++, p++) {
169 string_free(*p);
171 free(psv->vec);
172 psv->vec = NULL;
173 psv->size = 0;
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 *))
182 size_t i, j;
183 const char *str1, *str2;
185 if (!psv->vec || 1 == psv->size) {
186 return;
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);
195 i--;
196 break;
203 /**************************************************************************
204 Remove all empty strings from the vector and removes all leading and
205 trailing spaces.
206 **************************************************************************/
207 void strvec_remove_empty(struct strvec *psv)
209 size_t i;
210 char *str;
212 if (!psv->vec) {
213 return;
216 for (i = 0; i < psv->size;) {
217 str = psv->vec[i];
219 if (!str) {
220 strvec_remove(psv, i);
221 continue;
224 remove_leading_trailing_spaces(str);
225 if (str[0] == '\0') {
226 strvec_remove(psv, i);
227 continue;
230 i++;
234 /**************************************************************************
235 Copy a string vector.
236 **************************************************************************/
237 void strvec_copy(struct strvec *dest, const struct strvec *src)
239 size_t i;
240 char **p;
241 char *const *l;
243 if (!src->vec) {
244 strvec_clear(dest);
245 return;
248 strvec_reserve(dest, src->size);
249 for (i = 0, p = dest->vec, l = src->vec; i < dest->size; i++, p++, l++) {
250 string_free(*p);
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)
289 if (svindex <= 0) {
290 strvec_prepend(psv, string);
291 } else if (svindex >= psv->size) {
292 strvec_append(psv, string);
293 } else {
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);
310 return TRUE;
312 return FALSE;
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)) {
322 return FALSE;
325 if (psv->size == 1) {
326 /* It is the last. */
327 strvec_clear(psv);
328 return TRUE;
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);
337 return TRUE;
340 /**************************************************************************
341 Returns the size of the vector.
342 **************************************************************************/
343 size_t strvec_size(const struct strvec *psv)
345 return psv->size;
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)
382 int len;
384 strvec_iterate(psv, str) {
385 len = fc_snprintf(buf, buf_len, "%s", str) + 1;
386 if (1 >= len) {
387 /* Truncated. */
388 return;
391 buf += len;
392 buf_len -= len;
393 if (0 < buf_len) {
394 *(buf - 1) = separator;
396 } strvec_iterate_end;
398 buf[0] = '\0';
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);