2 * Part of Very Secure FTPd
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
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
19 /* Ick. Its for die() */
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 */
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
;
41 private_str_alloc_memchunk(struct mystr
* p_str
, const char* p_src
,
44 /* Make sure this will fit in the buffer */
45 unsigned int buf_needed
= len
+ 1;
46 if (buf_needed
> p_str
->alloc_bytes
)
49 s_setbuf(p_str
, vsf_sysutil_malloc(buf_needed
));
50 p_str
->alloc_bytes
= buf_needed
;
52 vsf_sysutil_memcpy(p_str
->p_buf
, p_src
, len
);
53 p_str
->p_buf
[len
] = '\0';
58 private_str_append_memchunk(struct mystr
* p_str
, const char* p_src
,
61 unsigned int buf_needed
= p_str
->len
+ len
+ 1;
62 if (buf_needed
> p_str
->alloc_bytes
)
64 p_str
->p_buf
= vsf_sysutil_realloc(p_str
->p_buf
, buf_needed
);
65 p_str
->alloc_bytes
= buf_needed
;
67 vsf_sysutil_memcpy(p_str
->p_buf
+ p_str
->len
, p_src
, len
);
68 p_str
->p_buf
[p_str
->len
+ len
] = '\0';
72 /* Public functions */
74 str_alloc_text(struct mystr
* p_str
, const char* p_src
)
76 unsigned int len
= vsf_sysutil_strlen(p_src
);
77 private_str_alloc_memchunk(p_str
, p_src
, len
);
81 str_copy(struct mystr
* p_dest
, const struct mystr
* p_src
)
83 private_str_alloc_memchunk(p_dest
, p_src
->p_buf
, p_src
->len
);
87 str_strdup(const struct mystr
* p_str
)
89 return vsf_sysutil_strdup(str_getbuf(p_str
));
93 str_alloc_alt_term(struct mystr
* p_str
, const char* p_src
, char term
)
95 const char* p_search
= p_src
;
97 while (*p_search
!= term
)
102 private_str_alloc_memchunk(p_str
, p_src
, len
);
106 str_alloc_ulong(struct mystr
* p_str
, unsigned long the_long
)
108 str_alloc_text(p_str
, vsf_sysutil_ulong_to_str(the_long
));
112 str_alloc_filesize_t(struct mystr
* p_str
, filesize_t the_filesize
)
114 str_alloc_text(p_str
, vsf_sysutil_filesize_t_to_str(the_filesize
));
118 str_free(struct mystr
* p_str
)
120 if (p_str
->p_buf
!= 0)
122 vsf_sysutil_free(p_str
->p_buf
);
126 p_str
->alloc_bytes
= 0;
130 str_empty(struct mystr
* p_str
)
132 /* Ensure a buffer is allocated. */
133 (void) str_getbuf(p_str
);
138 str_trunc(struct mystr
* p_str
, unsigned int trunc_len
)
140 if (trunc_len
>= p_str
->alloc_bytes
)
142 bug("trunc_len not smaller than alloc_bytes in str_trunc");
144 p_str
->len
= trunc_len
;
145 p_str
->p_buf
[p_str
->len
] = '\0';
149 str_reserve(struct mystr
* p_str
, unsigned int res_len
)
151 /* Reserve space for the trailing zero as well. */
153 if (res_len
> p_str
->alloc_bytes
)
155 p_str
->p_buf
= vsf_sysutil_realloc(p_str
->p_buf
, res_len
);
156 p_str
->alloc_bytes
= res_len
;
158 p_str
->p_buf
[res_len
- 1] = '\0';
162 str_isempty(const struct mystr
* p_str
)
164 return (p_str
->len
== 0);
168 str_getlen(const struct mystr
* p_str
)
174 str_getbuf(const struct mystr
* p_str
)
176 if (p_str
->p_buf
== 0)
178 if (p_str
->len
!= 0 || p_str
->alloc_bytes
!= 0)
180 bug("p_buf NULL and len or alloc_bytes != 0 in str_getbuf");
182 private_str_alloc_memchunk((struct mystr
*)p_str
, 0, 0);
188 str_strcmp(const struct mystr
* p_str1
, const struct mystr
* p_str2
)
190 return str_equal_internal(p_str1
->p_buf
, p_str1
->len
,
191 p_str2
->p_buf
, p_str2
->len
);
195 str_equal_internal(const char* p_buf1
, unsigned int buf1_len
,
196 const char* p_buf2
, unsigned int buf2_len
)
199 unsigned int minlen
= buf1_len
;
200 if (buf2_len
< minlen
)
204 retval
= vsf_sysutil_memcmp(p_buf1
, p_buf2
, minlen
);
205 if (retval
!= 0 || buf1_len
== buf2_len
)
209 /* Strings equal but lengths differ. The greater one, then, is the longer */
210 return (int) (buf1_len
- buf2_len
);
214 str_equal(const struct mystr
* p_str1
, const struct mystr
* p_str2
)
216 return (str_strcmp(p_str1
, p_str2
) == 0);
220 str_equal_text(const struct mystr
* p_str
, const char* p_text
)
222 unsigned int cmplen
= vsf_sysutil_strlen(p_text
);
223 return (str_equal_internal(p_str
->p_buf
, p_str
->len
, p_text
, cmplen
) == 0);
227 str_append_str(struct mystr
* p_str
, const struct mystr
* p_other
)
229 private_str_append_memchunk(p_str
, p_other
->p_buf
, p_other
->len
);
233 str_append_text(struct mystr
* p_str
, const char* p_src
)
235 unsigned int len
= vsf_sysutil_strlen(p_src
);
236 private_str_append_memchunk(p_str
, p_src
, len
);
240 str_append_char(struct mystr
* p_str
, char the_char
)
242 private_str_append_memchunk(p_str
, &the_char
, sizeof(the_char
));
246 str_append_ulong(struct mystr
* p_str
, unsigned long the_ulong
)
248 str_append_text(p_str
, vsf_sysutil_ulong_to_str(the_ulong
));
252 str_append_filesize_t(struct mystr
* p_str
, filesize_t the_filesize
)
254 str_append_text(p_str
, vsf_sysutil_filesize_t_to_str(the_filesize
));
258 str_append_double(struct mystr
* p_str
, double the_double
)
260 str_append_text(p_str
, vsf_sysutil_double_to_str(the_double
));
264 str_upper(struct mystr
* p_str
)
267 for (i
=0; i
< p_str
->len
; i
++)
269 p_str
->p_buf
[i
] = vsf_sysutil_toupper(p_str
->p_buf
[i
]);
274 str_rpad(struct mystr
* p_str
, const unsigned int min_width
)
277 if (p_str
->len
>= min_width
)
281 to_pad
= min_width
- p_str
->len
;
284 str_append_char(p_str
, ' ');
289 str_lpad(struct mystr
* p_str
, const unsigned int min_width
)
291 static struct mystr s_tmp_str
;
293 if (p_str
->len
>= min_width
)
297 to_pad
= min_width
- p_str
->len
;
298 str_empty(&s_tmp_str
);
301 str_append_char(&s_tmp_str
, ' ');
303 str_append_str(&s_tmp_str
, p_str
);
304 str_copy(p_str
, &s_tmp_str
);
308 str_replace_char(struct mystr
* p_str
, char from
, char to
)
311 for (i
=0; i
< p_str
->len
; i
++)
313 if (p_str
->p_buf
[i
] == from
)
315 p_str
->p_buf
[i
] = to
;
321 str_replace_text(struct mystr
* p_str
, const char* p_from
, const char* p_to
)
323 static struct mystr s_lhs_chunk_str
;
324 static struct mystr s_rhs_chunk_str
;
325 unsigned int lhs_len
;
326 str_copy(&s_lhs_chunk_str
, p_str
);
330 lhs_len
= str_getlen(&s_lhs_chunk_str
);
331 str_split_text(&s_lhs_chunk_str
, &s_rhs_chunk_str
, p_from
);
332 /* Copy lhs to destination */
333 str_append_str(p_str
, &s_lhs_chunk_str
);
334 /* If this was a 'hit', append the 'to' text */
335 if (str_getlen(&s_lhs_chunk_str
) < lhs_len
)
337 str_append_text(p_str
, p_to
);
339 /* Current rhs becomes new lhs */
340 str_copy(&s_lhs_chunk_str
, &s_rhs_chunk_str
);
341 } while (!str_isempty(&s_lhs_chunk_str
));
345 str_split_char(struct mystr
* p_src
, struct mystr
* p_rhs
, char c
)
347 /* Just use str_split_text */
351 str_split_text(p_src
, p_rhs
, ministr
);
355 str_split_char_reverse(struct mystr
* p_src
, struct mystr
* p_rhs
, char c
)
357 /* Just use str_split_text_reverse */
361 str_split_text_reverse(p_src
, p_rhs
, ministr
);
365 str_split_text(struct mystr
* p_src
, struct mystr
* p_rhs
, const char* p_text
)
367 str_split_text_common(p_src
, p_rhs
, p_text
, 0);
371 str_split_text_reverse(struct mystr
* p_src
, struct mystr
* p_rhs
,
374 str_split_text_common(p_src
, p_rhs
, p_text
, 1);
378 str_split_text_common(struct mystr
* p_src
, struct mystr
* p_rhs
,
379 const char* p_text
, int is_reverse
)
381 struct str_locate_result locate_result
;
383 unsigned int search_len
= vsf_sysutil_strlen(p_text
);
386 locate_result
= str_locate_text_reverse(p_src
, p_text
);
390 locate_result
= str_locate_text(p_src
, p_text
);
393 if (!locate_result
.found
)
398 indexx
= locate_result
.index
;
399 if (indexx
+ search_len
> p_src
->len
)
401 bug("indexx invalid in str_split_text");
404 private_str_alloc_memchunk(p_rhs
, p_src
->p_buf
+ indexx
+ search_len
,
405 p_src
->len
- indexx
- search_len
);
407 str_trunc(p_src
, indexx
);
410 struct str_locate_result
411 str_locate_str(const struct mystr
* p_str
, const struct mystr
* p_look_str
)
413 return str_locate_text(p_str
, str_getbuf(p_look_str
));
416 struct str_locate_result
417 str_locate_str_reverse(const struct mystr
* p_str
,
418 const struct mystr
* p_look_str
)
420 return str_locate_text_reverse(p_str
, str_getbuf(p_look_str
));
423 struct str_locate_result
424 str_locate_char(const struct mystr
* p_str
, char look_char
)
427 look_str
[0] = look_char
;
429 return str_locate_text(p_str
, look_str
);
432 struct str_locate_result
433 str_locate_chars(const struct mystr
* p_str
, const char* p_chars
)
435 struct str_locate_result retval
;
436 unsigned int num_chars
= vsf_sysutil_strlen(p_chars
);
439 retval
.char_found
= 0;
441 for (; i
< p_str
->len
; ++i
)
444 char this_char
= p_str
->p_buf
[i
];
445 for (; j
< num_chars
; ++j
)
447 if (p_chars
[j
] == this_char
)
451 retval
.char_found
= p_chars
[j
];
459 struct str_locate_result
460 str_locate_text(const struct mystr
* p_str
, const char* p_text
)
462 struct str_locate_result retval
;
464 unsigned int text_len
= vsf_sysutil_strlen(p_text
);
466 retval
.char_found
= 0;
468 if (text_len
== 0 || text_len
> p_str
->len
)
473 for (i
=0; i
<= (p_str
->len
- text_len
); i
++)
475 if (vsf_sysutil_memcmp(p_str
->p_buf
+ i
, p_text
, text_len
) == 0)
486 struct str_locate_result
487 str_locate_text_reverse(const struct mystr
* p_str
, const char* p_text
)
489 struct str_locate_result retval
;
491 unsigned int text_len
= vsf_sysutil_strlen(p_text
);
493 retval
.char_found
= 0;
495 if (text_len
== 0 || text_len
> p_str
->len
)
499 i
= p_str
->len
- text_len
;
500 /* Want to go through loop once even if i==0 */
503 if (vsf_sysutil_memcmp(p_str
->p_buf
+ i
, p_text
, text_len
) == 0)
520 str_left(const struct mystr
* p_str
, struct mystr
* p_out
, unsigned int chars
)
522 if (chars
> p_str
->len
)
524 bug("chars invalid in str_left");
526 private_str_alloc_memchunk(p_out
, p_str
->p_buf
, chars
);
530 str_right(const struct mystr
* p_str
, struct mystr
* p_out
, unsigned int chars
)
532 unsigned int indexx
= p_str
->len
- chars
;
533 if (chars
> p_str
->len
)
535 bug("chars invalid in str_right");
537 private_str_alloc_memchunk(p_out
, p_str
->p_buf
+ indexx
, chars
);
541 str_mid_to_end(const struct mystr
* p_str
, struct mystr
* p_out
,
544 if (indexx
> p_str
->len
)
546 bug("invalid indexx in str_mid_to_end");
548 private_str_alloc_memchunk(p_out
, p_str
->p_buf
+ indexx
,
549 p_str
->len
- indexx
);
553 str_get_char_at(const struct mystr
* p_str
, const unsigned int indexx
)
555 if (indexx
>= p_str
->len
)
557 bug("bad indexx in str_get_char_at");
559 return p_str
->p_buf
[indexx
];
563 str_contains_space(const struct mystr
* p_str
)
566 for (i
=0; i
< p_str
->len
; i
++)
568 if (vsf_sysutil_isspace(p_str
->p_buf
[i
]))
577 str_all_space(const struct mystr
* p_str
)
580 for (i
=0; i
< p_str
->len
; i
++)
582 if (!vsf_sysutil_isspace(p_str
->p_buf
[i
]))
591 str_contains_unprintable(const struct mystr
* p_str
)
594 for (i
=0; i
< p_str
->len
; i
++)
596 if (!vsf_sysutil_isprint(p_str
->p_buf
[i
]))
605 str_atoi(const struct mystr
* p_str
)
607 return vsf_sysutil_atoi(str_getbuf(p_str
));
611 str_a_to_filesize_t(const struct mystr
* p_str
)
613 return vsf_sysutil_a_to_filesize_t(str_getbuf(p_str
));
617 str_octal_to_uint(const struct mystr
* p_str
)
619 return vsf_sysutil_octal_to_uint(str_getbuf(p_str
));
623 str_getline(const struct mystr
* p_str
, struct mystr
* p_line_str
,
626 unsigned int start_pos
= *p_pos
;
627 unsigned int curr_pos
= start_pos
;
628 unsigned int buf_len
= str_getlen(p_str
);
629 const char* p_buf
= str_getbuf(p_str
);
630 unsigned int out_len
;
631 if (start_pos
> buf_len
)
633 bug("p_pos out of range in str_getline");
635 str_empty(p_line_str
);
636 if (start_pos
== buf_len
)
640 while (curr_pos
< buf_len
&& p_buf
[curr_pos
] != '\n')
644 out_len
= curr_pos
- start_pos
;
645 /* If we ended on a \n - skip it */
646 if (curr_pos
< buf_len
&& p_buf
[curr_pos
] == '\n')
650 private_str_alloc_memchunk(p_line_str
, p_buf
+ start_pos
, out_len
);
656 str_contains_line(const struct mystr
* p_str
, const struct mystr
* p_line_str
)
658 static struct mystr s_curr_line_str
;
659 unsigned int pos
= 0;
660 while (str_getline(p_str
, &s_curr_line_str
, &pos
))
662 if (str_equal(&s_curr_line_str
, p_line_str
))
671 str_replace_unprintable(struct mystr
* p_str
, char new_char
)
674 for (i
=0; i
< p_str
->len
; i
++)
676 if (!vsf_sysutil_isprint(p_str
->p_buf
[i
]))
678 p_str
->p_buf
[i
] = new_char
;