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.
7
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
16
17 #include <stdlib.h> /* qsort() */
18 #include <string.h>
19
20 /* utility */
21 #include "astring.h"
22 #include "mem.h"
23 #include "shared.h"
24 #include "support.h"
25
26 #include "string_vector.h"
27
28 /* The string vector structure. */
29 struct strvec {
30 char **vec;
31 size_t size;
32 };
33
34 /**************************************************************************
35 Free a string.
36 **************************************************************************/
string_free(char * string)37 static void string_free(char *string)
38 {
39 if (string) {
40 free(string);
41 }
42 }
43
44 /**************************************************************************
45 Duplicate a string.
46 **************************************************************************/
string_duplicate(const char * string)47 static char *string_duplicate(const char *string)
48 {
49 if (string) {
50 return fc_strdup(string);
51 }
52 return NULL;
53 }
54
55 /**************************************************************************
56 Create a new string vector.
57 **************************************************************************/
strvec_new(void)58 struct strvec *strvec_new(void)
59 {
60 struct strvec *psv = fc_malloc(sizeof(struct strvec));
61
62 psv->vec = NULL;
63 psv->size = 0;
64
65 return psv;
66 }
67
68 /**************************************************************************
69 Destroy a string vector.
70 **************************************************************************/
strvec_destroy(struct strvec * psv)71 void strvec_destroy(struct strvec *psv)
72 {
73 strvec_clear(psv);
74 free(psv);
75 }
76
77 /**************************************************************************
78 Set the size of the vector.
79 **************************************************************************/
strvec_reserve(struct strvec * psv,size_t reserve)80 void strvec_reserve(struct strvec *psv, size_t reserve)
81 {
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;
97
98 for (i = psv->size - 1; i >= reserve; i--) {
99 string_free(psv->vec[i]);
100 }
101 psv->vec = fc_realloc(psv->vec, reserve * sizeof(char *));
102 }
103 psv->size = reserve;
104 }
105
106 /**************************************************************************
107 Stores the string vector from a normal vector. If size == -1, it will
108 assume it is a NULL terminated vector.
109 **************************************************************************/
strvec_store(struct strvec * psv,const char * const * vec,size_t size)110 void strvec_store(struct strvec *psv, const char *const *vec, size_t size)
111 {
112 if (size == (size_t) -1) {
113 strvec_clear(psv);
114 for (; *vec; vec++) {
115 strvec_append(psv, *vec);
116 }
117 } else {
118 size_t i;
119
120 strvec_reserve(psv, size);
121 for (i = 0; i < size; i++, vec++) {
122 strvec_set(psv, i, *vec);
123 }
124 }
125 }
126
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.
131
132 This string format is a list of strings separated by 'separator'.
133
134 See also strvec_to_str().
135 ****************************************************************************/
strvec_from_str(struct strvec * psv,char separator,const char * str)136 void strvec_from_str(struct strvec *psv, char separator, const char *str)
137 {
138 const char *p;
139 char *new_str;
140
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;
150 }
151 if ('\0' != *str) {
152 strvec_append(psv, str);
153 }
154 }
155
156 /**************************************************************************
157 Remove all strings from the vector.
158 **************************************************************************/
strvec_clear(struct strvec * psv)159 void strvec_clear(struct strvec *psv)
160 {
161 size_t i;
162 char **p;
163
164 if (!psv->vec) {
165 return;
166 }
167
168 for (i = 0, p = psv->vec; i < psv->size; i++, p++) {
169 string_free(*p);
170 }
171 free(psv->vec);
172 psv->vec = NULL;
173 psv->size = 0;
174 }
175
176 /**************************************************************************
177 Remove strings which are duplicated inside the vector.
178 **************************************************************************/
strvec_remove_duplicate(struct strvec * psv,int (* cmp_func)(const char *,const char *))179 void strvec_remove_duplicate(struct strvec *psv,
180 int (*cmp_func) (const char *, const char *))
181 {
182 size_t i, j;
183 const char *str1, *str2;
184
185 if (!psv->vec || 1 == psv->size) {
186 return;
187 }
188
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;
197 }
198 }
199 }
200 }
201 }
202
203 /**************************************************************************
204 Remove all empty strings from the vector and removes all leading and
205 trailing spaces.
206 **************************************************************************/
strvec_remove_empty(struct strvec * psv)207 void strvec_remove_empty(struct strvec *psv)
208 {
209 size_t i;
210 char *str;
211
212 if (!psv->vec) {
213 return;
214 }
215
216 for (i = 0; i < psv->size;) {
217 str = psv->vec[i];
218
219 if (!str) {
220 strvec_remove(psv, i);
221 continue;
222 }
223
224 remove_leading_trailing_spaces(str);
225 if (str[0] == '\0') {
226 strvec_remove(psv, i);
227 continue;
228 }
229
230 i++;
231 }
232 }
233
234 /**************************************************************************
235 Copy a string vector.
236 **************************************************************************/
strvec_copy(struct strvec * dest,const struct strvec * src)237 void strvec_copy(struct strvec *dest, const struct strvec *src)
238 {
239 size_t i;
240 char **p;
241 char *const *l;
242
243 if (!src->vec) {
244 strvec_clear(dest);
245 return;
246 }
247
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);
252 }
253 }
254
255 /**************************************************************************
256 Sort the string vector, using qsort().
257 **************************************************************************/
strvec_sort(struct strvec * psv,int (* sort_func)(const char * const *,const char * const *))258 void strvec_sort(struct strvec *psv, int (*sort_func) (const char *const *,
259 const char *const *))
260 {
261 qsort(psv->vec, psv->size, sizeof(const char *),
262 (int (*) (const void *, const void *)) sort_func);
263 }
264
265 /**************************************************************************
266 Insert a string at the start of the vector.
267 **************************************************************************/
strvec_prepend(struct strvec * psv,const char * string)268 void strvec_prepend(struct strvec *psv, const char *string)
269 {
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);
273 }
274
275 /**************************************************************************
276 Insert a string at the end of the vector.
277 **************************************************************************/
strvec_append(struct strvec * psv,const char * string)278 void strvec_append(struct strvec *psv, const char *string)
279 {
280 strvec_reserve(psv, psv->size + 1);
281 psv->vec[psv->size - 1] = string_duplicate(string);
282 }
283
284 /**************************************************************************
285 Insert a string at the index of the vector.
286 **************************************************************************/
strvec_insert(struct strvec * psv,size_t svindex,const char * string)287 void strvec_insert(struct strvec *psv, size_t svindex, const char *string)
288 {
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);
298 }
299 }
300
301 /**************************************************************************
302 Replace a string at the index of the vector.
303 Returns TRUE if the element has been really set.
304 **************************************************************************/
strvec_set(struct strvec * psv,size_t svindex,const char * string)305 bool strvec_set(struct strvec *psv, size_t svindex, const char *string)
306 {
307 if (strvec_index_valid(psv, svindex)) {
308 string_free(psv->vec[svindex]);
309 psv->vec[svindex] = string_duplicate(string);
310 return TRUE;
311 }
312 return FALSE;
313 }
314
315 /**************************************************************************
316 Remove the string at the index from the vector.
317 Returns TRUE if the element has been really removed.
318 **************************************************************************/
strvec_remove(struct strvec * psv,size_t svindex)319 bool strvec_remove(struct strvec *psv, size_t svindex)
320 {
321 if (!strvec_index_valid(psv, svindex)) {
322 return FALSE;
323 }
324
325 if (psv->size == 1) {
326 /* It is the last. */
327 strvec_clear(psv);
328 return TRUE;
329 }
330
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);
336
337 return TRUE;
338 }
339
340 /**************************************************************************
341 Returns the size of the vector.
342 **************************************************************************/
strvec_size(const struct strvec * psv)343 size_t strvec_size(const struct strvec *psv)
344 {
345 return psv->size;
346 }
347
348 /**************************************************************************
349 Returns the datas of the vector.
350 **************************************************************************/
strvec_data(const struct strvec * psv)351 const char *const *strvec_data(const struct strvec *psv)
352 {
353 return (const char **) psv->vec;
354 }
355
356 /**************************************************************************
357 Returns TRUE if the index is valid.
358 **************************************************************************/
strvec_index_valid(const struct strvec * psv,size_t svindex)359 bool strvec_index_valid(const struct strvec *psv, size_t svindex)
360 {
361 return svindex >= 0 && svindex < psv->size;
362 }
363
364 /**************************************************************************
365 Returns the string at the index of the vector.
366 **************************************************************************/
strvec_get(const struct strvec * psv,size_t svindex)367 const char *strvec_get(const struct strvec *psv, size_t svindex)
368 {
369 return strvec_index_valid(psv, svindex) ? psv->vec[svindex] : NULL;
370 }
371
372 /****************************************************************************
373 Build the string from a string vector.
374
375 This string format is a list of strings separated by 'separator'.
376
377 See also strvec_from_str().
378 ****************************************************************************/
strvec_to_str(const struct strvec * psv,char separator,char * buf,size_t buf_len)379 void strvec_to_str(const struct strvec *psv, char separator,
380 char *buf, size_t buf_len)
381 {
382 int len;
383
384 strvec_iterate(psv, str) {
385 len = fc_snprintf(buf, buf_len, "%s", str) + 1;
386 if (1 >= len) {
387 /* Truncated. */
388 return;
389 }
390
391 buf += len;
392 buf_len -= len;
393 if (0 < buf_len) {
394 *(buf - 1) = separator;
395 }
396 } strvec_iterate_end;
397
398 buf[0] = '\0';
399 }
400
401 /****************************************************************************
402 Build a localized string with the elements of the string vector. Elements
403 will be "or"-separated.
404
405 See also astr_build_or_list(), strvec_to_and_list().
406 ****************************************************************************/
strvec_to_or_list(const struct strvec * psv,struct astring * astr)407 const char *strvec_to_or_list(const struct strvec *psv,
408 struct astring *astr)
409 {
410 fc_assert_ret_val(NULL != psv, NULL);
411 return astr_build_or_list(astr, (const char **) psv->vec, psv->size);
412 }
413
414 /****************************************************************************
415 Build a localized string with the elements of the string vector. Elements
416 will be "and"-separated.
417
418 See also astr_build_and_list(), strvec_to_or_list().
419 ****************************************************************************/
strvec_to_and_list(const struct strvec * psv,struct astring * astr)420 const char *strvec_to_and_list(const struct strvec *psv,
421 struct astring *astr)
422 {
423 fc_assert_ret_val(NULL != psv, NULL);
424 return astr_build_and_list(astr, (const char **) psv->vec, psv->size);
425 }
426