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
;
48 bug("integer overflow");
51 if (buf_needed
> p_str
->alloc_bytes
)
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';
63 private_str_append_memchunk(struct mystr
* p_str
, const char* p_src
,
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");
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';
87 /* Public functions */
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
);
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
);
102 str_strdup(const struct mystr
* p_str
)
104 return vsf_sysutil_strdup(str_getbuf(p_str
));
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
)
118 bug("integer overflow");
121 private_str_alloc_memchunk(p_str
, p_src
, len
);
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
));
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
));
137 str_free(struct mystr
* p_str
)
139 if (p_str
->p_buf
!= 0)
141 vsf_sysutil_free(p_str
->p_buf
);
145 p_str
->alloc_bytes
= 0;
149 str_empty(struct mystr
* p_str
)
151 /* Ensure a buffer is allocated. */
152 (void) str_getbuf(p_str
);
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';
168 str_reserve(struct mystr
* p_str
, unsigned int res_len
)
170 /* Reserve space for the trailing zero as well. */
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);
191 str_getlen(const struct mystr
* p_str
)
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);
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
);
218 str_equal_internal(const char* p_buf1
, unsigned int buf1_len
,
219 const char* p_buf2
, unsigned int buf2_len
)
222 unsigned int minlen
= buf1_len
;
223 if (buf2_len
< minlen
)
227 retval
= vsf_sysutil_memcmp(p_buf1
, p_buf2
, minlen
);
228 if (retval
!= 0 || buf1_len
== buf2_len
)
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);
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
);
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
);
263 str_append_char(struct mystr
* p_str
, char the_char
)
265 private_str_append_memchunk(p_str
, &the_char
, sizeof(the_char
));
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
));
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
));
281 str_append_double(struct mystr
* p_str
, double the_double
)
283 str_append_text(p_str
, vsf_sysutil_double_to_str(the_double
));
287 str_upper(struct mystr
* p_str
)
290 for (i
=0; i
< p_str
->len
; i
++)
292 p_str
->p_buf
[i
] = (char) vsf_sysutil_toupper(p_str
->p_buf
[i
]);
297 str_rpad(struct mystr
* p_str
, const unsigned int min_width
)
300 if (p_str
->len
>= min_width
)
304 to_pad
= min_width
- p_str
->len
;
307 str_append_char(p_str
, ' ');
312 str_lpad(struct mystr
* p_str
, const unsigned int min_width
)
314 static struct mystr s_tmp_str
;
316 if (p_str
->len
>= min_width
)
320 to_pad
= min_width
- p_str
->len
;
321 str_empty(&s_tmp_str
);
324 str_append_char(&s_tmp_str
, ' ');
326 str_append_str(&s_tmp_str
, p_str
);
327 str_copy(p_str
, &s_tmp_str
);
331 str_replace_char(struct mystr
* p_str
, char from
, char to
)
334 for (i
=0; i
< p_str
->len
; i
++)
336 if (p_str
->p_buf
[i
] == from
)
338 p_str
->p_buf
[i
] = to
;
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
);
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
));
368 str_split_char(struct mystr
* p_src
, struct mystr
* p_rhs
, char c
)
370 /* Just use str_split_text */
374 str_split_text(p_src
, p_rhs
, ministr
);
378 str_split_char_reverse(struct mystr
* p_src
, struct mystr
* p_rhs
, char c
)
380 /* Just use str_split_text_reverse */
384 str_split_text_reverse(p_src
, p_rhs
, ministr
);
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);
394 str_split_text_reverse(struct mystr
* p_src
, struct mystr
* p_rhs
,
397 str_split_text_common(p_src
, p_rhs
, p_text
, 1);
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
;
406 unsigned int search_len
= vsf_sysutil_strlen(p_text
);
409 locate_result
= str_locate_text_reverse(p_src
, p_text
);
413 locate_result
= str_locate_text(p_src
, p_text
);
416 if (!locate_result
.found
)
421 indexx
= locate_result
.index
;
422 if (indexx
+ search_len
> p_src
->len
)
424 bug("indexx invalid in str_split_text");
427 private_str_alloc_memchunk(p_rhs
, p_src
->p_buf
+ indexx
+ search_len
,
428 p_src
->len
- indexx
- search_len
);
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
)
450 look_str
[0] = look_char
;
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
);
462 retval
.char_found
= 0;
464 for (; i
< p_str
->len
; ++i
)
467 char this_char
= p_str
->p_buf
[i
];
468 for (; j
< num_chars
; ++j
)
470 if (p_chars
[j
] == this_char
)
474 retval
.char_found
= p_chars
[j
];
482 struct str_locate_result
483 str_locate_text(const struct mystr
* p_str
, const char* p_text
)
485 struct str_locate_result retval
;
487 unsigned int text_len
= vsf_sysutil_strlen(p_text
);
489 retval
.char_found
= 0;
491 if (text_len
== 0 || text_len
> p_str
->len
)
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)
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
;
514 unsigned int text_len
= vsf_sysutil_strlen(p_text
);
516 retval
.char_found
= 0;
518 if (text_len
== 0 || text_len
> p_str
->len
)
522 i
= p_str
->len
- text_len
;
523 /* Want to go through loop once even if i==0 */
526 if (vsf_sysutil_memcmp(p_str
->p_buf
+ i
, p_text
, text_len
) == 0)
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
);
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
);
564 str_mid_to_end(const struct mystr
* p_str
, struct mystr
* p_out
,
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
);
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
)
589 for (i
=0; i
< p_str
->len
; i
++)
591 if (vsf_sysutil_isspace(p_str
->p_buf
[i
]))
600 str_all_space(const struct mystr
* p_str
)
603 for (i
=0; i
< p_str
->len
; i
++)
605 if (!vsf_sysutil_isspace(p_str
->p_buf
[i
]))
614 str_contains_unprintable(const struct mystr
* p_str
)
617 for (i
=0; i
< p_str
->len
; i
++)
619 if (!vsf_sysutil_isprint(p_str
->p_buf
[i
]))
628 str_atoi(const struct mystr
* p_str
)
630 return vsf_sysutil_atoi(str_getbuf(p_str
));
634 str_a_to_filesize_t(const struct mystr
* p_str
)
636 return vsf_sysutil_a_to_filesize_t(str_getbuf(p_str
));
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
,
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
)
663 while (curr_pos
< buf_len
&& p_buf
[curr_pos
] != '\n')
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')
678 bug("integer overflow");
681 private_str_alloc_memchunk(p_line_str
, p_buf
+ start_pos
, out_len
);
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
))
702 str_replace_unprintable(struct mystr
* p_str
, char new_char
)
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
;