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