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