vsftpd 3.0.2
[tomato/tomato-dir865l.git] / release / src / router / vsftpd / str.c
blob6596204a561e2764bd29b1a2fa4d134253e61dd1
1 /*
2 * Part of Very Secure FTPd
3 * Licence: GPL v2
4 * Author: Chris Evans
5 * str.c
7 * Generic string handling functions. The fact that a string is implemented
8 * internally using a buffer is not exposed in the API. If you can't see
9 * the buffers, you can't handle them in a screwed way. Or so goes the
10 * theory, anyway...
13 /* Anti-lamer measures deployed, sir! */
14 #define PRIVATE_HANDS_OFF_p_buf p_buf
15 #define PRIVATE_HANDS_OFF_len len
16 #define PRIVATE_HANDS_OFF_alloc_bytes alloc_bytes
17 #include "str.h"
19 /* Ick. Its for die() */
20 #include "utility.h"
21 #include "sysutil.h"
23 /* File local functions */
24 static void str_split_text_common(struct mystr* p_src, struct mystr* p_rhs,
25 const char* p_text, int is_reverse);
26 static int str_equal_internal(const char* p_buf1, unsigned int buf1_len,
27 const char* p_buf2, unsigned int buf2_len);
29 /* Private functions */
30 static void
31 s_setbuf(struct mystr* p_str, char* p_newbuf)
33 if (p_str->p_buf != 0)
35 bug("p_buf not NULL when setting it");
37 p_str->p_buf = p_newbuf;
40 void
41 private_str_alloc_memchunk(struct mystr* p_str, const char* p_src,
42 unsigned int len)
44 /* Make sure this will fit in the buffer */
45 unsigned int buf_needed;
46 if (len + 1 < len)
48 bug("integer overflow");
50 buf_needed = len + 1;
51 if (buf_needed > p_str->alloc_bytes)
53 str_free(p_str);
54 s_setbuf(p_str, vsf_sysutil_malloc(buf_needed));
55 p_str->alloc_bytes = buf_needed;
57 vsf_sysutil_memcpy(p_str->p_buf, p_src, len);
58 p_str->p_buf[len] = '\0';
59 p_str->len = len;
62 void
63 private_str_append_memchunk(struct mystr* p_str, const char* p_src,
64 unsigned int len)
66 unsigned int buf_needed;
67 if (len + p_str->len < len)
69 bug("integer overflow");
71 buf_needed = len + p_str->len;
72 if (buf_needed + 1 < buf_needed)
74 bug("integer overflow");
76 buf_needed++;
77 if (buf_needed > p_str->alloc_bytes)
79 p_str->p_buf = vsf_sysutil_realloc(p_str->p_buf, buf_needed);
80 p_str->alloc_bytes = buf_needed;
82 vsf_sysutil_memcpy(p_str->p_buf + p_str->len, p_src, len);
83 p_str->p_buf[p_str->len + len] = '\0';
84 p_str->len += len;
87 /* Public functions */
88 void
89 str_alloc_text(struct mystr* p_str, const char* p_src)
91 unsigned int len = vsf_sysutil_strlen(p_src);
92 private_str_alloc_memchunk(p_str, p_src, len);
95 void
96 str_copy(struct mystr* p_dest, const struct mystr* p_src)
98 private_str_alloc_memchunk(p_dest, p_src->p_buf, p_src->len);
101 const char*
102 str_strdup(const struct mystr* p_str)
104 return vsf_sysutil_strdup(str_getbuf(p_str));
107 void
108 str_alloc_alt_term(struct mystr* p_str, const char* p_src, char term)
110 const char* p_search = p_src;
111 unsigned int len = 0;
112 while (*p_search != term)
114 p_search++;
115 len++;
116 if (len == 0)
118 bug("integer overflow");
121 private_str_alloc_memchunk(p_str, p_src, len);
124 void
125 str_alloc_ulong(struct mystr* p_str, unsigned long the_long)
127 str_alloc_text(p_str, vsf_sysutil_ulong_to_str(the_long));
130 void
131 str_alloc_filesize_t(struct mystr* p_str, filesize_t the_filesize)
133 str_alloc_text(p_str, vsf_sysutil_filesize_t_to_str(the_filesize));
136 void
137 str_free(struct mystr* p_str)
139 if (p_str->p_buf != 0)
141 vsf_sysutil_free(p_str->p_buf);
143 p_str->p_buf = 0;
144 p_str->len = 0;
145 p_str->alloc_bytes = 0;
148 void
149 str_empty(struct mystr* p_str)
151 /* Ensure a buffer is allocated. */
152 (void) str_getbuf(p_str);
153 str_trunc(p_str, 0);
156 void
157 str_trunc(struct mystr* p_str, unsigned int trunc_len)
159 if (trunc_len >= p_str->alloc_bytes)
161 bug("trunc_len not smaller than alloc_bytes in str_trunc");
163 p_str->len = trunc_len;
164 p_str->p_buf[p_str->len] = '\0';
167 void
168 str_reserve(struct mystr* p_str, unsigned int res_len)
170 /* Reserve space for the trailing zero as well. */
171 res_len++;
172 if (res_len == 0)
174 bug("integer overflow");
176 if (res_len > p_str->alloc_bytes)
178 p_str->p_buf = vsf_sysutil_realloc(p_str->p_buf, res_len);
179 p_str->alloc_bytes = res_len;
181 p_str->p_buf[res_len - 1] = '\0';
185 str_isempty(const struct mystr* p_str)
187 return (p_str->len == 0);
190 unsigned int
191 str_getlen(const struct mystr* p_str)
193 return p_str->len;
196 const char*
197 str_getbuf(const struct mystr* p_str)
199 if (p_str->p_buf == 0)
201 if (p_str->len != 0 || p_str->alloc_bytes != 0)
203 bug("p_buf NULL and len or alloc_bytes != 0 in str_getbuf");
205 private_str_alloc_memchunk((struct mystr*)p_str, 0, 0);
207 return p_str->p_buf;
211 str_strcmp(const struct mystr* p_str1, const struct mystr* p_str2)
213 return str_equal_internal(p_str1->p_buf, p_str1->len,
214 p_str2->p_buf, p_str2->len);
217 static int
218 str_equal_internal(const char* p_buf1, unsigned int buf1_len,
219 const char* p_buf2, unsigned int buf2_len)
221 int retval;
222 unsigned int minlen = buf1_len;
223 if (buf2_len < minlen)
225 minlen = buf2_len;
227 retval = vsf_sysutil_memcmp(p_buf1, p_buf2, minlen);
228 if (retval != 0 || buf1_len == buf2_len)
230 return retval;
232 /* Strings equal but lengths differ. The greater one, then, is the longer */
233 return (int) (buf1_len - buf2_len);
237 str_equal(const struct mystr* p_str1, const struct mystr* p_str2)
239 return (str_strcmp(p_str1, p_str2) == 0);
243 str_equal_text(const struct mystr* p_str, const char* p_text)
245 unsigned int cmplen = vsf_sysutil_strlen(p_text);
246 return (str_equal_internal(p_str->p_buf, p_str->len, p_text, cmplen) == 0);
249 void
250 str_append_str(struct mystr* p_str, const struct mystr* p_other)
252 private_str_append_memchunk(p_str, p_other->p_buf, p_other->len);
255 void
256 str_append_text(struct mystr* p_str, const char* p_src)
258 unsigned int len = vsf_sysutil_strlen(p_src);
259 private_str_append_memchunk(p_str, p_src, len);
262 void
263 str_append_char(struct mystr* p_str, char the_char)
265 private_str_append_memchunk(p_str, &the_char, sizeof(the_char));
268 void
269 str_append_ulong(struct mystr* p_str, unsigned long the_ulong)
271 str_append_text(p_str, vsf_sysutil_ulong_to_str(the_ulong));
274 void
275 str_append_filesize_t(struct mystr* p_str, filesize_t the_filesize)
277 str_append_text(p_str, vsf_sysutil_filesize_t_to_str(the_filesize));
280 void
281 str_append_double(struct mystr* p_str, double the_double)
283 str_append_text(p_str, vsf_sysutil_double_to_str(the_double));
286 void
287 str_upper(struct mystr* p_str)
289 unsigned int i;
290 for (i=0; i < p_str->len; i++)
292 p_str->p_buf[i] = (char) vsf_sysutil_toupper(p_str->p_buf[i]);
296 void
297 str_rpad(struct mystr* p_str, const unsigned int min_width)
299 unsigned int to_pad;
300 if (p_str->len >= min_width)
302 return;
304 to_pad = min_width - p_str->len;
305 while (to_pad--)
307 str_append_char(p_str, ' ');
311 void
312 str_lpad(struct mystr* p_str, const unsigned int min_width)
314 static struct mystr s_tmp_str;
315 unsigned int to_pad;
316 if (p_str->len >= min_width)
318 return;
320 to_pad = min_width - p_str->len;
321 str_empty(&s_tmp_str);
322 while (to_pad--)
324 str_append_char(&s_tmp_str, ' ');
326 str_append_str(&s_tmp_str, p_str);
327 str_copy(p_str, &s_tmp_str);
330 void
331 str_replace_char(struct mystr* p_str, char from, char to)
333 unsigned int i;
334 for (i=0; i < p_str->len; i++)
336 if (p_str->p_buf[i] == from)
338 p_str->p_buf[i] = to;
343 void
344 str_replace_text(struct mystr* p_str, const char* p_from, const char* p_to)
346 static struct mystr s_lhs_chunk_str;
347 static struct mystr s_rhs_chunk_str;
348 unsigned int lhs_len;
349 str_copy(&s_lhs_chunk_str, p_str);
350 str_free(p_str);
353 lhs_len = str_getlen(&s_lhs_chunk_str);
354 str_split_text(&s_lhs_chunk_str, &s_rhs_chunk_str, p_from);
355 /* Copy lhs to destination */
356 str_append_str(p_str, &s_lhs_chunk_str);
357 /* If this was a 'hit', append the 'to' text */
358 if (str_getlen(&s_lhs_chunk_str) < lhs_len)
360 str_append_text(p_str, p_to);
362 /* Current rhs becomes new lhs */
363 str_copy(&s_lhs_chunk_str, &s_rhs_chunk_str);
364 } while (!str_isempty(&s_lhs_chunk_str));
367 void
368 str_split_char(struct mystr* p_src, struct mystr* p_rhs, char c)
370 /* Just use str_split_text */
371 char ministr[2];
372 ministr[0] = c;
373 ministr[1] = '\0';
374 str_split_text(p_src, p_rhs, ministr);
377 void
378 str_split_char_reverse(struct mystr* p_src, struct mystr* p_rhs, char c)
380 /* Just use str_split_text_reverse */
381 char ministr[2];
382 ministr[0] = c;
383 ministr[1] = '\0';
384 str_split_text_reverse(p_src, p_rhs, ministr);
387 void
388 str_split_text(struct mystr* p_src, struct mystr* p_rhs, const char* p_text)
390 str_split_text_common(p_src, p_rhs, p_text, 0);
393 void
394 str_split_text_reverse(struct mystr* p_src, struct mystr* p_rhs,
395 const char* p_text)
397 str_split_text_common(p_src, p_rhs, p_text, 1);
400 static void
401 str_split_text_common(struct mystr* p_src, struct mystr* p_rhs,
402 const char* p_text, int is_reverse)
404 struct str_locate_result locate_result;
405 unsigned int indexx;
406 unsigned int search_len = vsf_sysutil_strlen(p_text);
407 if (is_reverse)
409 locate_result = str_locate_text_reverse(p_src, p_text);
411 else
413 locate_result = str_locate_text(p_src, p_text);
415 /* Not found? */
416 if (!locate_result.found)
418 str_empty(p_rhs);
419 return;
421 indexx = locate_result.index;
422 if (indexx + search_len > p_src->len)
424 bug("indexx invalid in str_split_text");
426 /* Build rhs */
427 private_str_alloc_memchunk(p_rhs, p_src->p_buf + indexx + search_len,
428 p_src->len - indexx - search_len);
429 /* Build lhs */
430 str_trunc(p_src, indexx);
433 struct str_locate_result
434 str_locate_str(const struct mystr* p_str, const struct mystr* p_look_str)
436 return str_locate_text(p_str, str_getbuf(p_look_str));
439 struct str_locate_result
440 str_locate_str_reverse(const struct mystr* p_str,
441 const struct mystr* p_look_str)
443 return str_locate_text_reverse(p_str, str_getbuf(p_look_str));
446 struct str_locate_result
447 str_locate_char(const struct mystr* p_str, char look_char)
449 char look_str[2];
450 look_str[0] = look_char;
451 look_str[1] = '\0';
452 return str_locate_text(p_str, look_str);
455 struct str_locate_result
456 str_locate_chars(const struct mystr* p_str, const char* p_chars)
458 struct str_locate_result retval;
459 unsigned int num_chars = vsf_sysutil_strlen(p_chars);
460 unsigned int i = 0;
461 retval.found = 0;
462 retval.char_found = 0;
463 retval.index = 0;
464 for (; i < p_str->len; ++i)
466 unsigned int j = 0;
467 char this_char = p_str->p_buf[i];
468 for (; j < num_chars; ++j)
470 if (p_chars[j] == this_char)
472 retval.found = 1;
473 retval.index = i;
474 retval.char_found = p_chars[j];
475 return retval;
479 return retval;
482 struct str_locate_result
483 str_locate_text(const struct mystr* p_str, const char* p_text)
485 struct str_locate_result retval;
486 unsigned int i;
487 unsigned int text_len = vsf_sysutil_strlen(p_text);
488 retval.found = 0;
489 retval.char_found = 0;
490 retval.index = 0;
491 if (text_len == 0 || text_len > p_str->len)
493 /* Not found */
494 return retval;
496 for (i=0; i <= (p_str->len - text_len); i++)
498 if (vsf_sysutil_memcmp(p_str->p_buf + i, p_text, text_len) == 0)
500 retval.found = 1;
501 retval.index = i;
502 return retval;
505 /* Not found */
506 return retval;
509 struct str_locate_result
510 str_locate_text_reverse(const struct mystr* p_str, const char* p_text)
512 struct str_locate_result retval;
513 unsigned int i;
514 unsigned int text_len = vsf_sysutil_strlen(p_text);
515 retval.found = 0;
516 retval.char_found = 0;
517 retval.index = 0;
518 if (text_len == 0 || text_len > p_str->len)
520 return retval;
522 i = p_str->len - text_len;
523 /* Want to go through loop once even if i==0 */
524 while (1)
526 if (vsf_sysutil_memcmp(p_str->p_buf + i, p_text, text_len) == 0)
528 retval.found = 1;
529 retval.index = i;
530 return retval;
532 if (i == 0)
534 break;
536 i--;
538 /* Not found */
539 return retval;
542 void
543 str_left(const struct mystr* p_str, struct mystr* p_out, unsigned int chars)
545 if (chars > p_str->len)
547 bug("chars invalid in str_left");
549 private_str_alloc_memchunk(p_out, p_str->p_buf, chars);
552 void
553 str_right(const struct mystr* p_str, struct mystr* p_out, unsigned int chars)
555 unsigned int indexx = p_str->len - chars;
556 if (chars > p_str->len)
558 bug("chars invalid in str_right");
560 private_str_alloc_memchunk(p_out, p_str->p_buf + indexx, chars);
563 void
564 str_mid_to_end(const struct mystr* p_str, struct mystr* p_out,
565 unsigned int indexx)
567 if (indexx > p_str->len)
569 bug("invalid indexx in str_mid_to_end");
571 private_str_alloc_memchunk(p_out, p_str->p_buf + indexx,
572 p_str->len - indexx);
575 char
576 str_get_char_at(const struct mystr* p_str, const unsigned int indexx)
578 if (indexx >= p_str->len)
580 bug("bad indexx in str_get_char_at");
582 return p_str->p_buf[indexx];
586 str_contains_space(const struct mystr* p_str)
588 unsigned int i;
589 for (i=0; i < p_str->len; i++)
591 if (vsf_sysutil_isspace(p_str->p_buf[i]))
593 return 1;
596 return 0;
600 str_all_space(const struct mystr* p_str)
602 unsigned int i;
603 for (i=0; i < p_str->len; i++)
605 if (!vsf_sysutil_isspace(p_str->p_buf[i]))
607 return 0;
610 return 1;
614 str_contains_unprintable(const struct mystr* p_str)
616 unsigned int i;
617 for (i=0; i < p_str->len; i++)
619 if (!vsf_sysutil_isprint(p_str->p_buf[i]))
621 return 1;
624 return 0;
628 str_atoi(const struct mystr* p_str)
630 return vsf_sysutil_atoi(str_getbuf(p_str));
633 filesize_t
634 str_a_to_filesize_t(const struct mystr* p_str)
636 return vsf_sysutil_a_to_filesize_t(str_getbuf(p_str));
639 unsigned int
640 str_octal_to_uint(const struct mystr* p_str)
642 return vsf_sysutil_octal_to_uint(str_getbuf(p_str));
646 str_getline(const struct mystr* p_str, struct mystr* p_line_str,
647 unsigned int* p_pos)
649 unsigned int start_pos = *p_pos;
650 unsigned int curr_pos = start_pos;
651 unsigned int buf_len = str_getlen(p_str);
652 const char* p_buf = str_getbuf(p_str);
653 unsigned int out_len;
654 if (start_pos > buf_len)
656 bug("p_pos out of range in str_getline");
658 str_empty(p_line_str);
659 if (start_pos == buf_len)
661 return 0;
663 while (curr_pos < buf_len && p_buf[curr_pos] != '\n')
665 curr_pos++;
666 if (curr_pos == 0)
668 bug("integer overflow");
671 out_len = curr_pos - start_pos;
672 /* If we ended on a \n - skip it */
673 if (curr_pos < buf_len && p_buf[curr_pos] == '\n')
675 curr_pos++;
676 if (curr_pos == 0)
678 bug("integer overflow");
681 private_str_alloc_memchunk(p_line_str, p_buf + start_pos, out_len);
682 *p_pos = curr_pos;
683 return 1;
687 str_contains_line(const struct mystr* p_str, const struct mystr* p_line_str)
689 static struct mystr s_curr_line_str;
690 unsigned int pos = 0;
691 while (str_getline(p_str, &s_curr_line_str, &pos))
693 if (str_equal(&s_curr_line_str, p_line_str))
695 return 1;
698 return 0;
701 void
702 str_replace_unprintable(struct mystr* p_str, char new_char)
704 unsigned int i;
705 for (i=0; i < p_str->len; i++)
707 if (!vsf_sysutil_isprint(p_str->p_buf[i]))
709 p_str->p_buf[i] = new_char;