• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2008 Kristian Høgsberg
3  * Copyright © 2013-2015 Red Hat, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include "config.h"
26 
27 #include "util-strings.h"
28 
29 /**
30  * Return the next word in a string pointed to by state before the first
31  * separator character. Call repeatedly to tokenize a whole string.
32  *
33  * @param state Current state
34  * @param len String length of the word returned
35  * @param separators List of separator characters
36  *
37  * @return The first word in *state, NOT null-terminated
38  */
39 static const char *
next_word(const char ** state,size_t * len,const char * separators)40 next_word(const char **state, size_t *len, const char *separators)
41 {
42 	const char *next = *state;
43 	size_t l;
44 
45 	if (!*next)
46 		return NULL;
47 
48 	next += strspn(next, separators);
49 	if (!*next) {
50 		*state = next;
51 		return NULL;
52 	}
53 
54 	l = strcspn(next, separators);
55 	*state = next + l;
56 	*len = l;
57 
58 	return next;
59 }
60 
61 /**
62  * Return a null-terminated string array with the contents of argv
63  * duplicated.
64  *
65  * Use strv_free() to free the array.
66  *
67  * @return A null-terminated string array or NULL on errors
68  */
69 char**
strv_from_argv(int argc,char ** argv)70 strv_from_argv(int argc, char **argv)
71 {
72 	char **strv = NULL;
73 
74 	assert(argc >= 0);
75 
76 	if (argc == 0)
77 		return NULL;
78 
79 	strv = zalloc((argc + 1) * sizeof *strv);
80 	for (int i = 0; i < argc; i++) {
81 		char *copy = safe_strdup(argv[i]);
82 		if (!copy) {
83 			strv_free(strv);
84 			return NULL;
85 		}
86 		strv[i] = copy;
87 	}
88 	return strv;
89 }
90 
91 /**
92  * Return a null-terminated string array with the tokens in the input
93  * string, e.g. "one two\tthree" with a separator list of " \t" will return
94  * an array [ "one", "two", "three", NULL ].
95  *
96  * Use strv_free() to free the array.
97  *
98  * @param in Input string
99  * @param separators List of separator characters
100  *
101  * @return A null-terminated string array or NULL on errors
102  */
103 char **
strv_from_string(const char * in,const char * separators)104 strv_from_string(const char *in, const char *separators)
105 {
106 	const char *s, *word;
107 	char **strv = NULL;
108 	int nelems = 0, idx;
109 	size_t l;
110 
111 	assert(in != NULL);
112 
113 	s = in;
114 	while (next_word(&s, &l, separators) != NULL)
115 	       nelems++;
116 
117 	if (nelems == 0)
118 		return NULL;
119 
120 	nelems++; /* NULL-terminated */
121 	strv = zalloc(nelems * sizeof *strv);
122 
123 	idx = 0;
124 
125 	s = in;
126 	while ((word = next_word(&s, &l, separators)) != NULL) {
127 		char *copy = strndup(word, l);
128 		if (!copy) {
129 			strv_free(strv);
130 			return NULL;
131 		}
132 
133 		strv[idx++] = copy;
134 	}
135 
136 	return strv;
137 }
138 
139 /**
140  * Return a newly allocated string with all elements joined by the
141  * joiner, same as Python's string.join() basically.
142  * A strv of ["one", "two", "three", NULL] with a joiner of ", " results
143  * in "one, two, three".
144  *
145  * An empty strv ([NULL]) returns NULL, same for passing NULL as either
146  * argument.
147  *
148  * @param strv Input string array
149  * @param joiner Joiner between the elements in the final string
150  *
151  * @return A null-terminated string joining all elements
152  */
153 char *
strv_join(char ** strv,const char * joiner)154 strv_join(char **strv, const char *joiner)
155 {
156 	char **s;
157 	char *str;
158 	size_t slen = 0;
159 	size_t count = 0;
160 
161 	if (!strv || !joiner)
162 		return NULL;
163 
164 	if (strv[0] == NULL)
165 		return NULL;
166 
167 	for (s = strv, count = 0; *s; s++, count++) {
168 		slen += strlen(*s);
169 	}
170 
171 	assert(slen < 1000);
172 	assert(strlen(joiner) < 1000);
173 	assert(count > 0);
174 	assert(count < 100);
175 
176 	slen += (count - 1) * strlen(joiner);
177 
178 	str = zalloc(slen + 1); /* trailing \0 */
179 	for (s = strv; *s; s++) {
180 		strcat(str, *s);
181 		--count;
182 		if (count > 0)
183 			strcat(str, joiner);
184 	}
185 
186 	return str;
187 }
188 
189 /**
190  * Return a pointer to the basename within filename.
191  * If the filename the empty string or a directory (i.e. the last char of
192  * filename is '/') NULL is returned.
193  */
194 const char *
safe_basename(const char * filename)195 safe_basename(const char *filename)
196 {
197 	const char *basename;
198 
199 	if (*filename == '\0')
200 		return NULL;
201 
202 	basename = strrchr(filename, '/');
203 	if (basename == NULL)
204 		return filename;
205 
206 	if (*(basename + 1) == '\0')
207 		return NULL;
208 
209 	return basename + 1;
210 }
211 
212 
213 /**
214  * Similar to basename() but returns the trunk only without the (last)
215  * trailing suffix, so that:
216  *
217  * - foo.c returns foo
218  * - foo.a.b returns foo.a
219  * - foo returns foo
220  * - foo/ returns ""
221  *
222  * @return an allocated string representing the trunk name of the file
223  */
224 char *
trunkname(const char * filename)225 trunkname(const char *filename)
226 {
227 	const char *base = safe_basename(filename);
228 	char *suffix;
229 
230 	if (base == NULL)
231 		return safe_strdup("");
232 
233 	suffix = rindex(base, '.');
234 	if (suffix == NULL)
235 		return safe_strdup(base);
236 	else
237 		return strndup(base, suffix-base);
238 }
239