1 #include <nm_core.h>
2 #include <nm_utils.h>
3 #include <nm_string.h>
4 
5 static void nm_str_alloc_mem(nm_str_t *str, const char *src, size_t len);
6 static void nm_str_append_mem(nm_str_t *str, const char *src, size_t len);
7 static void nm_str_append_mem_opt(nm_str_t *str, const char *src, size_t len);
8 static const char *nm_str_get(const nm_str_t *str);
9 static uint64_t nm_str_stoul__(const char *str, int base);
10 
nm_str_alloc_text(nm_str_t * str,const char * src)11 void nm_str_alloc_text(nm_str_t *str, const char *src)
12 {
13     size_t len = strlen(src);
14     nm_str_alloc_mem(str, src, len);
15 }
16 
nm_str_add_char(nm_str_t * str,char ch)17 void nm_str_add_char(nm_str_t *str, char ch)
18 {
19     nm_str_append_mem(str, &ch, sizeof(ch));
20 }
21 
nm_str_add_char_opt(nm_str_t * str,char ch)22 void nm_str_add_char_opt(nm_str_t *str, char ch)
23 {
24     nm_str_append_mem_opt(str, &ch, sizeof(ch));
25 }
26 
nm_str_add_text(nm_str_t * str,const char * src)27 void nm_str_add_text(nm_str_t *str, const char *src)
28 {
29     size_t len = strlen(src);
30     nm_str_append_mem(str, src, len);
31 }
32 
nm_str_add_text_part(nm_str_t * str,const char * src,size_t len)33 void nm_str_add_text_part(nm_str_t *str, const char *src, size_t len)
34 {
35     if (!src)
36         return;
37     nm_str_append_mem(str, src, len);
38 }
39 
nm_str_add_str(nm_str_t * str,const nm_str_t * src)40 void nm_str_add_str(nm_str_t *str, const nm_str_t *src)
41 {
42     if (!src)
43         return;
44     nm_str_append_mem(str, src->data, src->len);
45 }
46 
nm_str_add_str_part(nm_str_t * str,const nm_str_t * src,size_t len)47 void nm_str_add_str_part(nm_str_t *str, const nm_str_t *src, size_t len)
48 {
49     if (!src)
50         return;
51     nm_str_append_mem(str, src->data, len);
52 }
53 
nm_str_copy(nm_str_t * str,const nm_str_t * src)54 void nm_str_copy(nm_str_t *str, const nm_str_t *src)
55 {
56     if (!src)
57         return;
58     nm_str_alloc_mem(str, src->data, src->len);
59 }
60 
nm_str_trunc(nm_str_t * str,size_t len)61 void nm_str_trunc(nm_str_t *str, size_t len)
62 {
63     if (!str)
64         return;
65 
66     if (len >= str->alloc_bytes)
67         nm_bug(_("%s: bad length"), __func__);
68 
69     str->len = len;
70     str->data[str->len] = '\0';
71 }
72 
nm_str_free(nm_str_t * str)73 void nm_str_free(nm_str_t *str)
74 {
75     if (!str)
76         return;
77 
78     if (str->data != NULL)
79         free(str->data);
80 
81     str->data = NULL;
82     str->alloc_bytes = 0;
83     str->len = 0;
84 }
85 
nm_str_cmp_st(const nm_str_t * str,const char * text)86 int nm_str_cmp_st(const nm_str_t *str, const char *text)
87 {
88     if (!str || !str->data || !text)
89         return NM_ERR;
90 
91     if (strcmp(str->data, text) != 0)
92         return NM_ERR;
93 
94     return NM_OK;
95 }
96 
nm_str_cmp_tt(const char * text1,const char * text2)97 int nm_str_cmp_tt(const char *text1, const char *text2)
98 {
99     if (!text1 || !text2)
100         return NM_ERR;
101 
102     if (strcmp(text1, text2) != 0)
103         return NM_ERR;
104 
105     return NM_OK;
106 }
107 
nm_str_case_cmp_tt(const char * text1,const char * text2)108 int nm_str_case_cmp_tt(const char *text1, const char *text2)
109 {
110     if (!text1 || !text2)
111         return NM_ERR;
112 
113     if (strcasecmp(text1, text2) != 0)
114         return NM_ERR;
115 
116     return NM_OK;
117 }
118 
nm_str_cmp_ss(const nm_str_t * str1,const nm_str_t * str2)119 int nm_str_cmp_ss(const nm_str_t *str1, const nm_str_t *str2)
120 {
121     if (!str1 || !str2 || !str1->data || !str2->data)
122         return NM_ERR;
123 
124     if (strcmp(str1->data, str2->data) != 0)
125         return NM_ERR;
126 
127     return NM_OK;
128 }
129 
nm_str_stoui(const nm_str_t * str,int base)130 uint32_t nm_str_stoui(const nm_str_t *str, int base)
131 {
132     uint64_t res;
133     char *endp;
134     const char *data = nm_str_get(str);
135 
136     res = strtoul(data, &endp, base);
137 
138     if ((res == ULONG_MAX && errno == ERANGE) || (res > UINT32_MAX))
139         nm_bug(_("%s: integer overflow"), __func__);
140 
141     if ((endp == data) || (*endp != '\0'))
142         nm_bug(_("%s: bad integer value=\'%s\'"), __func__, data);
143 
144     return res;
145 }
146 
nm_str_stoul__(const char * str,int base)147 static uint64_t nm_str_stoul__(const char *str, int base)
148 {
149     uint64_t res;
150     char *endp;
151 
152     res = strtoull(str, &endp, base);
153 
154     if (res == ULLONG_MAX && errno == ERANGE)
155         nm_bug(_("%s: integer overflow"), __func__);
156 
157     if ((endp == str) || (*endp != '\0'))
158         nm_bug(_("%s: bad integer value=\'%s\'"), __func__, str);
159 
160     return res;
161 }
162 
nm_str_stoul(const nm_str_t * str,int base)163 uint64_t nm_str_stoul(const nm_str_t *str, int base)
164 {
165     return nm_str_stoul__(nm_str_get(str), base);
166 }
167 
nm_str_ttoul(const char * str,int base)168 uint64_t nm_str_ttoul(const char *str, int base)
169 {
170     return nm_str_stoul__(str, base);
171 }
172 
nm_str_stol(const nm_str_t * str,int base)173 int64_t nm_str_stol(const nm_str_t *str, int base)
174 {
175     int64_t res;
176     char *endp;
177     const char *data = nm_str_get(str);
178 
179     res = strtoll(data, &endp, base);
180 
181     if ((res == LLONG_MAX || res == LLONG_MIN) && errno == ERANGE)
182         nm_bug(_("%s: integer overflow"), __func__);
183 
184     if ((endp == data) || (*endp != '\0'))
185         nm_bug(_("%s: bad integer value=\'%s\'"), __func__, data);
186 
187     return res;
188 }
189 
nm_str_dirname(const nm_str_t * str,nm_str_t * res)190 void nm_str_dirname(const nm_str_t *str, nm_str_t *res)
191 {
192     if (!str)
193         return;
194 
195     const char *data = nm_str_get(str);
196     size_t pos;
197 
198     pos = str->len;
199 
200     if (str->len == 0)
201         nm_bug(_("%s: zero length string"), __func__);
202 
203     for (size_t n = (pos - 1); n > 0; n--) {
204         if (data[n] == '/') {
205             pos = n;
206             break;
207         }
208     }
209 
210     if ((pos == str->len) && (*data == '/'))
211         pos = 1;
212 
213     nm_str_alloc_mem(res, data, pos);
214 }
215 
216 #if 0
217 void nm_str_basename(const nm_str_t *str, nm_str_t *res)
218 {
219     if (!str)
220         return;
221 
222     nm_str_t path = NM_INIT_STR;
223     char *path_end;
224 
225     nm_str_copy(&path, str);
226 
227     if (str->len == 0)
228         nm_bug(_("%s: zero length string"), __func__);
229 
230     path_end = strrchr(path.data, '/');
231     if (path_end == NULL) {
232         nm_str_copy(res, str);
233         return;
234     }
235 
236     if (path_end[1] == '\0') {
237         while ((path_end > path.data) && (path_end[-1] == '/'))
238             --path_end;
239 
240         if (path_end > path.data) {
241             *path_end-- = '\0';
242             while ((path_end > path.data) && (path_end[-1]) != '/')
243                 --path_end;
244         } else {
245             while (path_end[1] != '\0')
246                 ++path_end;
247         }
248     } else {
249         ++path_end;
250     }
251 
252     nm_str_alloc_mem(res, path_end, strlen(path_end));
253     nm_str_free(&path);
254 }
255 #endif
256 
nm_str_append_format(nm_str_t * str,const char * fmt,...)257 void nm_str_append_format(nm_str_t *str, const char *fmt, ...)
258 {
259     int len = 0;
260     char *buf = NULL;
261     va_list args;
262 
263     /* get required length */
264     va_start(args, fmt);
265     len = vsnprintf(buf, 0, fmt, args);
266     va_end(args);
267 
268     if (len < 0)
269         nm_bug(_("%s: invalid length: %d"), __func__, len);
270 
271     len++; /* for \0 */
272 
273     buf = nm_calloc(1, len);
274 
275     va_start(args, fmt);
276     len = vsnprintf(buf, len, fmt, args);
277     if (len < 0)
278         nm_bug(_("%s: invalid length: %d"), __func__, len);
279     va_end(args);
280 
281     nm_str_append_mem(str, buf, len);
282     free(buf);
283 }
284 
nm_str_format(nm_str_t * str,const char * fmt,...)285 void nm_str_format(nm_str_t *str, const char *fmt, ...)
286 {
287     int len = 0;
288     char *buf = NULL;
289     va_list args;
290 
291     /* get required length */
292     va_start(args, fmt);
293     len = vsnprintf(buf, 0, fmt, args);
294     va_end(args);
295 
296     if (len < 0)
297         nm_bug(_("%s: invalid length: %d"), __func__, len);
298 
299     len++; /* for \0 */
300 
301     buf = nm_calloc(1, len);
302 
303     va_start(args, fmt);
304     len = vsnprintf(buf, len, fmt, args);
305     if (len < 0)
306         nm_bug(_("%s: invalid length: %d"), __func__, len);
307     va_end(args);
308 
309     nm_str_alloc_mem(str, buf, len);
310     free(buf);
311 }
312 
nm_str_remove_char(nm_str_t * str,char ch)313 void nm_str_remove_char(nm_str_t *str, char ch)
314 {
315     if (!str)
316         return;
317 
318     char *prd, *pwr;
319 
320     prd = pwr = str->data;
321 
322     while (*prd) {
323         *pwr = *prd++;
324         pwr += (*pwr == ch) ? 0 : 1;
325     }
326 
327     *pwr = '\0';
328 }
329 
nm_strlcpy(char * dst,const char * src,size_t buflen)330 size_t nm_strlcpy(char *dst, const char *src, size_t buflen)
331 {
332     size_t srclen = strlen(src);
333     size_t ret = srclen;
334 
335     if (buflen > 0) {
336         if (srclen >= buflen)
337             srclen = buflen - 1;
338 
339         memcpy(dst, src, srclen);
340         dst[srclen] = '\0';
341     }
342 
343     return ret;
344 }
345 
nm_str_append_to_vect(const nm_str_t * src,nm_vect_t * v,const char * delim)346 void nm_str_append_to_vect(const nm_str_t *src, nm_vect_t *v, const char *delim)
347 {
348     char *token, *saveptr;
349     nm_str_t buf = NM_INIT_STR;
350 
351     nm_str_copy(&buf, src);
352     saveptr = buf.data;
353 
354     while ((token = strtok_r(saveptr, delim, &saveptr))) {
355         nm_vect_insert_cstr(v, token);
356     }
357 
358     nm_str_free(&buf);
359 }
360 
nm_str_vect_ins_cb(void * unit_p,const void * ctx)361 void nm_str_vect_ins_cb(void *unit_p, const void *ctx)
362 {
363     nm_str_copy((nm_str_t *) unit_p, (const nm_str_t *) ctx);
364 }
365 
nm_str_vect_free_cb(void * unit_p)366 void nm_str_vect_free_cb(void *unit_p)
367 {
368     nm_str_free((nm_str_t *) unit_p);
369 }
370 
nm_str_replace_text(nm_str_t * str,const char * old,const char * new)371 void nm_str_replace_text(nm_str_t *str, const char *old, const char *new)
372 {
373     nm_str_t buf = NM_INIT_STR;
374     size_t count = 0;
375     char *prev = NULL;
376     char *cur = NULL;
377     size_t old_len = strlen(old);
378     size_t new_len = strlen(new);
379     char *ins = str->data;
380 
381     for (count = 0; (cur = strstr(ins, old)); ++count)
382         ins = cur + old_len;
383 
384     if (count == 0)
385         return;
386 
387     nm_str_alloc_mem(&buf, NULL, str->len + (new_len * count) - (old_len * count));
388     buf.len = 0;
389 
390     ins = buf.data;
391     prev = str->data;
392     while ((cur = strstr(prev, old)))
393     {
394         memcpy(ins, prev, cur - prev);
395         ins += cur - prev;
396         buf.len += cur - prev;
397 
398         memcpy(ins, new, new_len);
399         ins += new_len;
400         buf.len += new_len;
401 
402         prev += cur - prev + old_len;
403     }
404 
405     memcpy(ins, prev, str->len - (prev - str->data));
406     buf.len += str->len - (prev - str->data);
407 
408     if (buf.len != buf.alloc_bytes - 1)
409         nm_bug(_("%s: string replace failed"), __func__);
410 
411     buf.data[buf.len] = '\0';
412 
413     nm_str_free(str);
414     str->alloc_bytes = buf.alloc_bytes;
415     str->data = buf.data;
416     str->len = buf.len;
417 }
418 
nm_str_alloc_mem(nm_str_t * str,const char * src,size_t len)419 static void nm_str_alloc_mem(nm_str_t *str, const char *src, size_t len)
420 {
421     if (!str)
422         return;
423 
424     size_t len_needed;
425 
426     if (len + 1 < len)
427         nm_bug(_("Integer overflow\n"));
428 
429     len_needed = len + 1;
430 
431     if (len_needed > str->alloc_bytes) {
432         nm_str_free(str);
433         str->data = nm_alloc(len_needed);
434         str->alloc_bytes = len_needed;
435     }
436 
437     if (src) {
438         memcpy(str->data, src, len);
439         str->data[len] = '\0';
440     }
441 
442     str->len = len;
443 }
444 
nm_str_append_mem(nm_str_t * str,const char * src,size_t len)445 static void nm_str_append_mem(nm_str_t *str, const char *src, size_t len)
446 {
447     if (!str)
448         return;
449 
450     size_t len_needed;
451 
452     if (len + str->len < len)
453         nm_bug(_("Integer overflow\n"));
454 
455     len_needed = len + str->len;
456     if (len_needed + 1 < len_needed)
457         nm_bug(_("Integer overflow\n"));
458 
459     len_needed++;
460 
461     if (len_needed > str->alloc_bytes) {
462         str->data = nm_realloc(str->data, len_needed);
463         str->alloc_bytes = len_needed;
464     }
465 
466     memcpy(str->data + str->len, src, len);
467     str->data[str->len + len] = '\0';
468     str->len += len;
469 }
470 
nm_str_append_mem_opt(nm_str_t * str,const char * src,size_t len)471 static void nm_str_append_mem_opt(nm_str_t *str, const char *src, size_t len)
472 {
473     if (!str)
474         return;
475 
476     size_t len_needed;
477 
478     if (len + str->len < len)
479         nm_bug(_("Integer overflow"));
480 
481     len_needed = len + str->len;
482     if ((len_needed + 1) * 10 < len_needed)
483         nm_bug(_("Integer overflow"));
484 
485     len_needed++;
486 
487     if (len_needed > str->alloc_bytes) {
488         str->data = nm_realloc(str->data, len_needed * 10);
489         str->alloc_bytes = len_needed * 10;
490     }
491 
492     memcpy(str->data + str->len, src, len);
493     str->data[str->len + len] = '\0';
494     str->len += len;
495 }
496 
nm_str_get(const nm_str_t * str)497 static const char *nm_str_get(const nm_str_t *str)
498 {
499     if (!str)
500         return NULL;
501 
502     if (str->data == NULL) {
503         if ((str->alloc_bytes != 0) || (str->len != 0))
504             nm_bug(_("Malformed nm_str_t data"));
505 
506         nm_str_alloc_mem((nm_str_t *)str, NULL, 0);
507     }
508 
509     return str->data;
510 }
511 
512 /* vim:set ts=4 sw=4: */
513