xref: /freebsd/contrib/elftoolchain/libelftc/libelftc_vstr.c (revision c2bffd0a9793be8a23ab719557756b2a2ce2c3b5)
1  /*-
2   * Copyright (c) 2008 Hyogeol Lee <hyogeollee@gmail.com>
3   * All rights reserved.
4   *
5   * Redistribution and use in source and binary forms, with or without
6   * modification, are permitted provided that the following conditions
7   * are met:
8   * 1. Redistributions of source code must retain the above copyright
9   *    notice, this list of conditions and the following disclaimer
10   *    in this position and unchanged.
11   * 2. Redistributions in binary form must reproduce the above copyright
12   *    notice, this list of conditions and the following disclaimer in the
13   *    documentation and/or other materials provided with the distribution.
14   *
15   * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  #include <sys/types.h>
28  #include <assert.h>
29  #include <libelftc.h>
30  #include <stdio.h>
31  #include <stdlib.h>
32  #include <string.h>
33  
34  #include "_libelftc.h"
35  
36  ELFTC_VCSID("$Id: libelftc_vstr.c 3531 2017-06-05 05:08:43Z kaiwang27 $");
37  
38  /**
39   * @file vector_str.c
40   * @brief Dynamic vector data for string implementation.
41   *
42   * Resemble to std::vector<std::string> in C++.
43   */
44  
45  static size_t	get_strlen_sum(const struct vector_str *v);
46  static bool	vector_str_grow(struct vector_str *v);
47  
48  static size_t
get_strlen_sum(const struct vector_str * v)49  get_strlen_sum(const struct vector_str *v)
50  {
51  	size_t i, len = 0;
52  
53  	if (v == NULL)
54  		return (0);
55  
56  	assert(v->size > 0);
57  
58  	for (i = 0; i < v->size; ++i)
59  		len += strlen(v->container[i]);
60  
61  	return (len);
62  }
63  
64  /**
65   * @brief Deallocate resource in vector_str.
66   */
67  void
vector_str_dest(struct vector_str * v)68  vector_str_dest(struct vector_str *v)
69  {
70  	size_t i;
71  
72  	if (v == NULL)
73  		return;
74  
75  	for (i = 0; i < v->size; ++i)
76  		free(v->container[i]);
77  
78  	free(v->container);
79  }
80  
81  /**
82   * @brief Find string in vector_str.
83   * @param v Destination vector.
84   * @param o String to find.
85   * @param l Length of the string.
86   * @return -1 at failed, 0 at not found, 1 at found.
87   */
88  int
vector_str_find(const struct vector_str * v,const char * o,size_t l)89  vector_str_find(const struct vector_str *v, const char *o, size_t l)
90  {
91  	size_t i;
92  
93  	if (v == NULL || o == NULL)
94  		return (-1);
95  
96  	for (i = 0; i < v->size; ++i)
97  		if (strncmp(v->container[i], o, l) == 0)
98  			return (1);
99  
100  	return (0);
101  }
102  
103  /**
104   * @brief Get new allocated flat string from vector.
105   *
106   * If l is not NULL, return length of the string.
107   * @param v Destination vector.
108   * @param l Length of the string.
109   * @return NULL at failed or NUL terminated new allocated string.
110   */
111  char *
vector_str_get_flat(const struct vector_str * v,size_t * l)112  vector_str_get_flat(const struct vector_str *v, size_t *l)
113  {
114  	ssize_t elem_pos, elem_size, rtn_size;
115  	size_t i;
116  	char *rtn;
117  
118  	if (v == NULL || v->size == 0)
119  		return (NULL);
120  
121  	if ((rtn_size = get_strlen_sum(v)) == 0)
122  		return (NULL);
123  
124  	if ((rtn = malloc(sizeof(char) * (rtn_size + 1))) == NULL)
125  		return (NULL);
126  
127  	elem_pos = 0;
128  	for (i = 0; i < v->size; ++i) {
129  		elem_size = strlen(v->container[i]);
130  
131  		memcpy(rtn + elem_pos, v->container[i], elem_size);
132  
133  		elem_pos += elem_size;
134  	}
135  
136  	rtn[rtn_size] = '\0';
137  
138  	if (l != NULL)
139  		*l = rtn_size;
140  
141  	return (rtn);
142  }
143  
144  static bool
vector_str_grow(struct vector_str * v)145  vector_str_grow(struct vector_str *v)
146  {
147  	size_t i, tmp_cap;
148  	char **tmp_ctn;
149  
150  	if (v == NULL)
151  		return (false);
152  
153  	assert(v->capacity > 0);
154  
155  	tmp_cap = BUFFER_GROW(v->capacity);
156  
157  	assert(tmp_cap > v->capacity);
158  
159  	if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL)
160  		return (false);
161  
162  	for (i = 0; i < v->size; ++i)
163  		tmp_ctn[i] = v->container[i];
164  
165  	free(v->container);
166  
167  	v->container = tmp_ctn;
168  	v->capacity = tmp_cap;
169  
170  	return (true);
171  }
172  
173  /**
174   * @brief Initialize vector_str.
175   * @return false at failed, true at success.
176   */
177  bool
vector_str_init(struct vector_str * v)178  vector_str_init(struct vector_str *v)
179  {
180  
181  	if (v == NULL)
182  		return (false);
183  
184  	v->size = 0;
185  	v->capacity = VECTOR_DEF_CAPACITY;
186  
187  	assert(v->capacity > 0);
188  
189  	if ((v->container = malloc(sizeof(char *) * v->capacity)) == NULL)
190  		return (false);
191  
192  	assert(v->container != NULL);
193  
194  	return (true);
195  }
196  
197  /**
198   * @brief Remove last element in vector_str.
199   * @return false at failed, true at success.
200   */
201  bool
vector_str_pop(struct vector_str * v)202  vector_str_pop(struct vector_str *v)
203  {
204  
205  	if (v == NULL)
206  		return (false);
207  
208  	if (v->size == 0)
209  		return (true);
210  
211  	--v->size;
212  
213  	free(v->container[v->size]);
214  	v->container[v->size] = NULL;
215  
216  	return (true);
217  }
218  
219  /**
220   * @brief Push back string to vector.
221   * @return false at failed, true at success.
222   */
223  bool
vector_str_push(struct vector_str * v,const char * str,size_t len)224  vector_str_push(struct vector_str *v, const char *str, size_t len)
225  {
226  
227  	if (v == NULL || str == NULL)
228  		return (false);
229  
230  	if (v->size == v->capacity && vector_str_grow(v) == false)
231  		return (false);
232  
233  	if ((v->container[v->size] = malloc(sizeof(char) * (len + 1))) == NULL)
234  		return (false);
235  
236  	snprintf(v->container[v->size], len + 1, "%s", str);
237  
238  	++v->size;
239  
240  	return (true);
241  }
242  
243  /**
244   * @brief Push front org vector to det vector.
245   * @return false at failed, true at success.
246   */
247  bool
vector_str_push_vector_head(struct vector_str * dst,struct vector_str * org)248  vector_str_push_vector_head(struct vector_str *dst, struct vector_str *org)
249  {
250  	size_t i, j, tmp_cap;
251  	char **tmp_ctn;
252  
253  	if (dst == NULL || org == NULL)
254  		return (false);
255  
256  	tmp_cap = BUFFER_GROW(dst->size + org->size);
257  
258  	if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL)
259  		return (false);
260  
261  	for (i = 0; i < org->size; ++i)
262  		if ((tmp_ctn[i] = strdup(org->container[i])) == NULL) {
263  			for (j = 0; j < i; ++j)
264  				free(tmp_ctn[j]);
265  
266  			free(tmp_ctn);
267  
268  			return (false);
269  		}
270  
271  	for (i = 0; i < dst->size; ++i)
272  		tmp_ctn[i + org->size] = dst->container[i];
273  
274  	free(dst->container);
275  
276  	dst->container = tmp_ctn;
277  	dst->capacity = tmp_cap;
278  	dst->size += org->size;
279  
280  	return (true);
281  }
282  
283  /**
284   * @brief Push org vector to the tail of det vector.
285   * @return false at failed, true at success.
286   */
287  bool
vector_str_push_vector(struct vector_str * dst,struct vector_str * org)288  vector_str_push_vector(struct vector_str *dst, struct vector_str *org)
289  {
290  	size_t i, j, tmp_cap;
291  	char **tmp_ctn;
292  
293  	if (dst == NULL || org == NULL)
294  		return (false);
295  
296  	tmp_cap = BUFFER_GROW(dst->size + org->size);
297  
298  	if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL)
299  		return (false);
300  
301  	for (i = 0; i < dst->size; ++i)
302  		tmp_ctn[i] = dst->container[i];
303  
304  	for (i = 0; i < org->size; ++i)
305  		if ((tmp_ctn[i + dst->size] = strdup(org->container[i])) ==
306  		    NULL) {
307  			for (j = 0; j < i + dst->size; ++j)
308  				free(tmp_ctn[j]);
309  
310  			free(tmp_ctn);
311  
312  			return (false);
313  		}
314  
315  	free(dst->container);
316  
317  	dst->container = tmp_ctn;
318  	dst->capacity = tmp_cap;
319  	dst->size += org->size;
320  
321  	return (true);
322  }
323  
324  /**
325   * @brief Get new allocated flat string from vector between begin and end.
326   *
327   * If r_len is not NULL, string length will be returned.
328   * @return NULL at failed or NUL terminated new allocated string.
329   */
330  char *
vector_str_substr(const struct vector_str * v,size_t begin,size_t end,size_t * r_len)331  vector_str_substr(const struct vector_str *v, size_t begin, size_t end,
332      size_t *r_len)
333  {
334  	size_t cur, i, len;
335  	char *rtn;
336  
337  	if (v == NULL || begin > end)
338  		return (NULL);
339  
340  	len = 0;
341  	for (i = begin; i < end + 1; ++i)
342  		len += strlen(v->container[i]);
343  
344  	if ((rtn = malloc(sizeof(char) * (len + 1))) == NULL)
345  		return (NULL);
346  
347  	if (r_len != NULL)
348  		*r_len = len;
349  
350  	cur = 0;
351  	for (i = begin; i < end + 1; ++i) {
352  		len = strlen(v->container[i]);
353  		memcpy(rtn + cur, v->container[i], len);
354  		cur += len;
355  	}
356  	rtn[cur] = '\0';
357  
358  	return (rtn);
359  }
360