1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "bl_str.h"
4 
5 #include <stdio.h>  /* sprintf */
6 #include <stdarg.h> /* va_list */
7 #include <ctype.h>  /* isdigit */
8 
9 #include "bl_debug.h"
10 #include "bl_mem.h"
11 
12 #undef bl_str_sep
13 #undef bl_basename
14 
15 /* --- global functions --- */
16 
17 #ifndef HAVE_STRSEP
18 
__bl_str_sep(char ** strp,const char * delim)19 char* __bl_str_sep(char **strp, const char *delim) {
20   char *s;
21   const char *spanp;
22   int c;
23   int sc;
24   char *tok;
25 
26   if ((s = *strp) == NULL) {
27     return NULL;
28   }
29 
30   for (tok = s;;) {
31     c = *s++;
32     spanp = delim;
33     do {
34       if ((sc = *spanp++) == c) {
35         if (c == 0) {
36           s = NULL;
37         } else {
38           s[-1] = 0;
39         }
40 
41         *strp = s;
42 
43         return tok;
44       }
45     } while (sc != 0);
46   }
47 }
48 
49 #endif
50 
51 /*
52  * !! Notice !!
53  * It is a caller that is responsible to check buffer overrun.
54  */
bl_snprintf(char * str,size_t size,const char * format,...)55 int bl_snprintf(char *str, size_t size, const char *format, ...) {
56   va_list arg_list;
57 
58   va_start(arg_list, format);
59 
60 #ifdef HAVE_SNPRINTF
61   return vsnprintf(str, size, format, arg_list);
62 #else
63   /*
64    * XXX
65    * this may cause buffer overrun.
66    */
67 
68   return vsprintf(str, format, arg_list);
69 #endif
70 }
71 
__bl_str_dup(const char * str,const char * file,int line,const char * func)72 char *__bl_str_dup(const char *str, const char *file /* should be allocated memory. */,
73                    int line, const char *func /* should be allocated memory. */) {
74   char *new_str;
75 
76   if ((new_str = bl_mem_malloc(strlen(str) + 1, file, line, func)) == NULL) {
77     return NULL;
78   }
79 
80   strcpy(new_str, str);
81 
82   return new_str;
83 }
84 
85 #ifndef REMOVE_FUNCS_MLTERM_UNUSE
86 /*
87  * XXX
88  * this doesn't concern about ISO2022 sequences or so.
89  * dst/src must be u_char since 0x80 - 0x9f is specially dealed.
90  */
bl_str_tabify(u_char * dst,size_t dst_len,const u_char * src,size_t src_len,size_t tab_len)91 size_t bl_str_tabify(u_char *dst, size_t dst_len, const u_char *src, size_t src_len,
92                      size_t tab_len) {
93   size_t pos_in_tab;
94   size_t space_num;
95   int dst_pos;
96   int src_pos;
97   int count;
98 
99   if (tab_len == 0) {
100 #ifdef BL_DEBUG
101     bl_warn_printf(BL_DEBUG_TAG " 0 is illegal tab length.\n");
102 #endif
103 
104     return 0;
105   }
106 
107   dst_pos = 0;
108   pos_in_tab = 0;
109   space_num = 0;
110   for (src_pos = 0; src_pos < src_len; src_pos++) {
111     if (src[src_pos] == ' ') {
112       if (pos_in_tab == tab_len - 1) {
113         dst[dst_pos++] = '\t';
114 
115         if (dst_pos >= dst_len) {
116           return dst_pos;
117         }
118 
119         space_num = 0;
120 
121         /* next */
122         pos_in_tab = 0;
123       } else {
124         space_num++;
125 
126         /* next */
127         pos_in_tab++;
128       }
129     } else {
130       if (space_num > 0) {
131         for (count = 0; count < space_num; count++) {
132           dst[dst_pos++] = ' ';
133 
134           if (dst_pos >= dst_len) {
135             return dst_pos;
136           }
137         }
138 
139         space_num = 0;
140       }
141 
142       dst[dst_pos++] = src[src_pos];
143 
144       if (dst_pos >= dst_len) {
145         return dst_pos;
146       }
147 
148       if (src[src_pos] == '\n' || src[src_pos] == '\t') {
149         /* next */
150         pos_in_tab = 0;
151       } else if ((0x20 <= src[src_pos] && src[src_pos] < 0x7f) || 0xa0 <= src[src_pos]) {
152         /* next */
153         if (pos_in_tab == tab_len - 1) {
154           pos_in_tab = 0;
155         } else {
156           pos_in_tab++;
157         }
158       } else if (src[src_pos] == 0x1b) {
159         /* XXX  ISO2022 seq should be considered. */
160       }
161     }
162   }
163 
164   if (space_num > 0) {
165     for (count = 0; count < space_num; count++) {
166       dst[dst_pos++] = ' ';
167 
168       if (dst_pos >= dst_len) {
169         return dst_pos;
170       }
171     }
172   }
173 
174   return dst_pos;
175 }
176 #endif
177 
bl_str_chop_spaces(char * str)178 char *bl_str_chop_spaces(char *str) {
179   size_t pos;
180 
181   pos = strlen(str);
182 
183   while (pos > 0) {
184     pos--;
185 
186     if (str[pos] != ' ' && str[pos] != '\t') {
187       str[pos + 1] = '\0';
188 
189       break;
190     }
191   }
192 
193   return str;
194 }
195 
bl_str_n_to_uint(u_int * i,const char * s,size_t n)196 int bl_str_n_to_uint(u_int *i, const char *s, size_t n) {
197   u_int _i;
198   int digit;
199 
200   if (n == 0) {
201     return 0;
202   }
203 
204   _i = 0;
205   for (digit = 0; digit < n && s[digit]; digit++) {
206     if (!isdigit(s[digit])) {
207       return 0;
208     }
209 
210     _i *= 10;
211     _i += (s[digit] - 0x30);
212   }
213 
214   *i = _i;
215 
216   return 1;
217 }
218 
bl_str_n_to_int(int * i,const char * s,size_t n)219 int bl_str_n_to_int(int *i, const char *s, size_t n) {
220   u_int _i;
221   int is_minus;
222 
223   if (n == 0) {
224     return 0;
225   }
226 
227   if (*s == '-') {
228     if (--n == 0) {
229       return 0;
230     }
231 
232     s++;
233 
234     is_minus = 1;
235   } else {
236     is_minus = 0;
237   }
238 
239   if (!bl_str_n_to_uint(&_i, s, n)) {
240     return 0;
241   }
242 
243   if ((int)_i < 0) {
244     return 0;
245   }
246 
247   if (is_minus) {
248     *i = -((int)_i);
249   } else {
250     *i = (int)_i;
251   }
252 
253   return 1;
254 }
255 
bl_str_to_uint(u_int * i,const char * s)256 int bl_str_to_uint(u_int *i, const char *s) {
257   u_int _i;
258 
259   if (*s == '\0') {
260     return 0;
261   }
262 
263   _i = 0;
264   while (*s) {
265     if (!isdigit(*s)) {
266       return 0;
267     }
268 
269     _i *= 10;
270     _i += (*s - 0x30);
271 
272     s++;
273   }
274 
275   *i = _i;
276 
277   return 1;
278 }
279 
bl_str_to_int(int * i,const char * s)280 int bl_str_to_int(int *i, const char *s) {
281   u_int _i;
282   int is_minus;
283 
284   if (*s == '\0') {
285     return 0;
286   }
287 
288   if (*s == '-') {
289     if (*(++s) == '\0') {
290       return 0;
291     }
292 
293     is_minus = 1;
294   } else {
295     is_minus = 0;
296   }
297 
298   if (!bl_str_to_uint(&_i, s)) {
299     return 0;
300   }
301 
302   if ((int)_i < 0) {
303     return 0;
304   }
305 
306   if (is_minus) {
307     *i = -((int)_i);
308   } else {
309     *i = (int)_i;
310   }
311 
312   return 1;
313 }
314 
bl_count_char_in_str(const char * str,char ch)315 u_int bl_count_char_in_str(const char *str, char ch) {
316   u_int count;
317 
318   count = 0;
319   while (*str) {
320     if (*str == ch) {
321       count++;
322     }
323 
324     str++;
325   }
326 
327   return count;
328 }
329 
330 /* str1 and str2 can be NULL */
bl_compare_str(const char * str1,const char * str2)331 int bl_compare_str(const char *str1, const char *str2) {
332   if (str1 == str2) {
333     return 0;
334   }
335 
336   if (str1 == NULL) {
337     return -1;
338   } else if (str2 == NULL) {
339     return 1;
340   }
341 
342   return strcmp(str1, str2);
343 }
344 
bl_str_replace(const char * str,const char * orig,const char * new)345 char *bl_str_replace(const char *str, const char *orig, /* Don't specify "". */
346                      const char *new) {
347   size_t orig_len;
348   size_t new_len;
349   int diff;
350   const char *p;
351   char *new_str;
352   char *dst;
353 
354   orig_len = strlen(orig);
355   new_len = strlen(new);
356   if ((diff = new_len - orig_len) != 0) {
357     int num;
358 
359     for (num = 0, p = str; (p = strstr(p, orig)); num++, p += orig_len);
360 
361     if (num == 0) {
362       return NULL;
363     }
364 
365     diff *= num;
366   }
367 
368   if (!(p = strstr(str, orig)) || !(dst = new_str = malloc(strlen(str) + diff + 1))) {
369     return NULL;
370   }
371 
372   do {
373     memcpy(dst, str, p - str);
374     dst += (p - str);
375     memcpy(dst, new, new_len);
376     dst += new_len;
377     str = p + orig_len;
378   } while ((p = strstr(str, orig)));
379   strcpy(dst, str);
380 
381   return new_str;
382 }
383 
384 #if 0
385 char *bl_str_escape_backslash(char *str) {
386   char *escaped_str;
387   char *p;
388 
389   if (!(p = escaped_str = malloc(strlen(str) + bl_count_char_in_str(str, '\\') + 1))) {
390     return str;
391   }
392 
393   while (1) {
394     *(p++) = *str;
395 
396     if (*str == '\0') {
397       g_free(str);
398 
399       return escaped_str;
400     } else if (*str == '\\') {
401       *(p++) = '\\';
402     }
403 
404     str++;
405   }
406 }
407 #endif
408 
bl_str_unescape(const char * str)409 char *bl_str_unescape(const char *str) {
410   char *new_str;
411   char *p;
412 
413   if ((new_str = malloc(strlen(str) + 1)) == NULL) {
414     return NULL;
415   }
416 
417   for (p = new_str; *str; str++, p++) {
418     if (*str == '\\') {
419       u_int digit;
420 
421       if (*(++str) == '\0') {
422         break;
423       } else if (sscanf(str, "x%2x", &digit) == 1) {
424         *p = (char)digit;
425         str += 2;
426       } else if (*str == 'n') {
427         *p = '\n';
428       } else if (*str == 'r') {
429         *p = '\r';
430       } else if (*str == 't') {
431         *p = '\t';
432       } else if (*str == 'e' || *str == 'E') {
433         *p = '\033';
434       } else {
435         *p = *str;
436       }
437     } else if (*str == '^') {
438       if (*(++str) == '\0') {
439         break;
440       } else if ('@' <= *str && *str <= '_') {
441         *p = *str - 'A' + 1;
442       } else if (*str == '?') {
443         *p = '\x7f';
444       } else {
445         *p = *str;
446       }
447     } else {
448       *p = *str;
449     }
450   }
451 
452   *p = '\0';
453 
454   return new_str;
455 }
456 
457 #ifdef BL_DEBUG
458 
459 #include <assert.h>
460 
TEST_bl_str(void)461 void TEST_bl_str(void) {
462   char *str;
463 
464   str = bl_str_replace("abcdefabcdef", "abc", "xxxx");
465   assert(strcmp(str, "xxxxdefxxxxdef") == 0);
466   free(str);
467 
468   str = bl_str_unescape("abc\\n\\r\\t\\e\\E^A\\x1b");
469   assert(strcmp(str, "abc\n\r\t\x1b\x1b\x01\x1b") == 0);
470   free(str);
471 
472   bl_msg_printf("PASS bl_str test.\n");
473 }
474 
475 #endif
476