1 /*
2  * FRR string processing utilities.
3  * Copyright (C) 2018  Cumulus Networks, Inc.
4  *                     Quentin Young
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; see the file COPYING; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <string.h>
26 #include <ctype.h>
27 #include <sys/types.h>
28 #ifdef HAVE_LIBPCREPOSIX
29 #include <pcreposix.h>
30 #else
31 #include <regex.h>
32 #endif /* HAVE_LIBPCREPOSIX */
33 
34 #include "frrstr.h"
35 #include "memory.h"
36 #include "vector.h"
37 
frrstr_split(const char * string,const char * delimiter,char *** result,int * argc)38 void frrstr_split(const char *string, const char *delimiter, char ***result,
39 		  int *argc)
40 {
41 	if (!string)
42 		return;
43 
44 	unsigned int sz = 4, idx = 0;
45 	char *copy, *copystart;
46 	*result = XCALLOC(MTYPE_TMP, sizeof(char *) * sz);
47 	copystart = copy = XSTRDUP(MTYPE_TMP, string);
48 	*argc = 0;
49 
50 	const char *tok = NULL;
51 
52 	while (copy) {
53 		tok = strsep(&copy, delimiter);
54 		(*result)[idx] = XSTRDUP(MTYPE_TMP, tok);
55 		if (++idx == sz)
56 			*result = XREALLOC(MTYPE_TMP, *result,
57 					   (sz *= 2) * sizeof(char *));
58 		(*argc)++;
59 	}
60 
61 	XFREE(MTYPE_TMP, copystart);
62 }
63 
frrstr_split_vec(const char * string,const char * delimiter)64 vector frrstr_split_vec(const char *string, const char *delimiter)
65 {
66 	char **result;
67 	int argc;
68 
69 	if (!string)
70 		return NULL;
71 
72 	frrstr_split(string, delimiter, &result, &argc);
73 
74 	vector v = array_to_vector((void **)result, argc);
75 
76 	XFREE(MTYPE_TMP, result);
77 
78 	return v;
79 }
80 
frrstr_join(const char ** parts,int argc,const char * join)81 char *frrstr_join(const char **parts, int argc, const char *join)
82 {
83 	int i;
84 	char *str;
85 	char *p;
86 	size_t len = 0;
87 	size_t joinlen = join ? strlen(join) : 0;
88 
89 	if (!argc)
90 		return NULL;
91 
92 	for (i = 0; i < argc; i++)
93 		len += strlen(parts[i]);
94 	len += argc * joinlen + 1;
95 
96 	if (!len)
97 		return NULL;
98 
99 	p = str = XMALLOC(MTYPE_TMP, len);
100 
101 	for (i = 0; i < argc; i++) {
102 		size_t arglen = strlen(parts[i]);
103 
104 		memcpy(p, parts[i], arglen);
105 		p += arglen;
106 		if (i + 1 != argc && join) {
107 			memcpy(p, join, joinlen);
108 			p += joinlen;
109 		}
110 	}
111 
112 	*p = '\0';
113 
114 	return str;
115 }
116 
frrstr_join_vec(vector v,const char * join)117 char *frrstr_join_vec(vector v, const char *join)
118 {
119 	char **argv;
120 	int argc;
121 
122 	vector_to_array(v, (void ***)&argv, &argc);
123 
124 	char *ret = frrstr_join((const char **)argv, argc, join);
125 
126 	XFREE(MTYPE_TMP, argv);
127 
128 	return ret;
129 }
130 
frrstr_filter_vec(vector v,regex_t * filter)131 void frrstr_filter_vec(vector v, regex_t *filter)
132 {
133 	regmatch_t ignored[1];
134 
135 	for (unsigned int i = 0; i < vector_active(v); i++) {
136 		if (regexec(filter, vector_slot(v, i), 0, ignored, 0)) {
137 			XFREE(MTYPE_TMP, vector_slot(v, i));
138 			vector_unset(v, i);
139 		}
140 	}
141 }
142 
frrstr_strvec_free(vector v)143 void frrstr_strvec_free(vector v)
144 {
145 	unsigned int i;
146 	char *cp;
147 
148 	if (!v)
149 		return;
150 
151 	for (i = 0; i < vector_active(v); i++) {
152 		cp = vector_slot(v, i);
153 		XFREE(MTYPE_TMP, cp);
154 	}
155 
156 	vector_free(v);
157 }
158 
frrstr_replace(const char * str,const char * find,const char * replace)159 char *frrstr_replace(const char *str, const char *find, const char *replace)
160 {
161 	char *ch;
162 	char *nustr = XSTRDUP(MTYPE_TMP, str);
163 
164 	size_t findlen = strlen(find);
165 	size_t repllen = strlen(replace);
166 
167 	while ((ch = strstr(nustr, find))) {
168 		if (repllen > findlen) {
169 			size_t nusz = strlen(nustr) + repllen - findlen + 1;
170 			nustr = XREALLOC(MTYPE_TMP, nustr, nusz);
171 			ch = strstr(nustr, find);
172 		}
173 
174 		size_t nustrlen = strlen(nustr);
175 		size_t taillen = (nustr + nustrlen) - (ch + findlen);
176 
177 		memmove(ch + findlen + (repllen - findlen), ch + findlen,
178 			taillen + 1);
179 		memcpy(ch, replace, repllen);
180 	}
181 
182 	return nustr;
183 }
184 
frrstr_startswith(const char * str,const char * prefix)185 bool frrstr_startswith(const char *str, const char *prefix)
186 {
187 	if (!str || !prefix)
188 		return false;
189 
190 	size_t lenstr = strlen(str);
191 	size_t lenprefix = strlen(prefix);
192 
193 	if (lenprefix > lenstr)
194 		return false;
195 
196 	return strncmp(str, prefix, lenprefix) == 0;
197 }
198 
frrstr_endswith(const char * str,const char * suffix)199 bool frrstr_endswith(const char *str, const char *suffix)
200 {
201 	if (!str || !suffix)
202 		return false;
203 
204 	size_t lenstr = strlen(str);
205 	size_t lensuffix = strlen(suffix);
206 
207 	if (lensuffix > lenstr)
208 		return false;
209 
210 	return strncmp(&str[lenstr - lensuffix], suffix, lensuffix) == 0;
211 }
212 
all_digit(const char * str)213 int all_digit(const char *str)
214 {
215 	for (; *str != '\0'; str++)
216 		if (!isdigit((unsigned char)*str))
217 			return 0;
218 	return 1;
219 }
220