1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/* 18 * Part of Very Secure FTPd 19 * Licence: GPL v2 20 * Author: Chris Evans 21 * str.c 22 * 23 * Generic string handling functions. The fact that a string is implemented 24 * internally using a buffer is not exposed in the API. If you can't see 25 * the buffers, you can't handle them in a screwed way. Or so goes the 26 * theory, anyway... 27 */ 28 29#include <string.h> 30 31/* Anti-lamer measures deployed, sir! */ 32#define PRIVATE_HANDS_OFF_p_buf p_buf 33#define PRIVATE_HANDS_OFF_len len 34#define PRIVATE_HANDS_OFF_alloc_bytes alloc_bytes 35#include "str.h" 36 37/* Ick. Its for die() */ 38#include "utility.h" 39#include "sysutil.h" 40 41/* File local functions */ 42static void str_split_text_common(struct mystr* p_src, struct mystr* p_rhs, 43 const char* p_text, int is_reverse); 44static int str_equal_internal(const char* p_buf1, unsigned int buf1_len, 45 const char* p_buf2, unsigned int buf2_len); 46 47/* Private functions */ 48static void 49s_setbuf(struct mystr* p_str, char* p_newbuf) 50{ 51 if (p_str->p_buf != 0) 52 { 53 bug("p_buf not NULL when setting it"); 54 } 55 p_str->p_buf = p_newbuf; 56} 57 58void 59private_str_alloc_memchunk(struct mystr* p_str, const char* p_src, 60 unsigned int len) 61{ 62 /* Make sure this will fit in the buffer */ 63 unsigned int buf_needed = len + 1; 64 if (buf_needed > p_str->alloc_bytes) 65 { 66 str_free(p_str); 67 s_setbuf(p_str, vsf_sysutil_malloc(buf_needed)); 68 p_str->alloc_bytes = buf_needed; 69 } 70 vsf_sysutil_memcpy(p_str->p_buf, p_src, len); 71 p_str->p_buf[len] = '\0'; 72 p_str->len = len; 73} 74 75void 76private_str_append_memchunk(struct mystr* p_str, const char* p_src, 77 unsigned int len) 78{ 79 unsigned int buf_needed = p_str->len + len + 1; 80 if (buf_needed > p_str->alloc_bytes) 81 { 82 p_str->p_buf = vsf_sysutil_realloc(p_str->p_buf, buf_needed); 83 p_str->alloc_bytes = buf_needed; 84 } 85 vsf_sysutil_memcpy(p_str->p_buf + p_str->len, p_src, len); 86 p_str->p_buf[p_str->len + len] = '\0'; 87 p_str->len += len; 88} 89 90/* Public functions */ 91void 92str_alloc_text(struct mystr* p_str, const char* p_src) 93{ 94 unsigned int len = vsf_sysutil_strlen(p_src); 95 private_str_alloc_memchunk(p_str, p_src, len); 96} 97 98void 99str_copy(struct mystr* p_dest, const struct mystr* p_src) 100{ 101 private_str_alloc_memchunk(p_dest, p_src->p_buf, p_src->len); 102} 103 104const char* 105str_strdup(const struct mystr* p_str) 106{ 107 return vsf_sysutil_strdup(str_getbuf(p_str)); 108} 109 110void 111str_alloc_alt_term(struct mystr* p_str, const char* p_src, char term) 112{ 113 const char* p_search = p_src; 114 unsigned int len = 0; 115 while (*p_search != term) 116 { 117 p_search++; 118 len++; 119 } 120 private_str_alloc_memchunk(p_str, p_src, len); 121} 122 123void 124str_alloc_ulong(struct mystr* p_str, unsigned long the_long) 125{ 126 str_alloc_text(p_str, vsf_sysutil_ulong_to_str(the_long)); 127} 128 129void 130str_alloc_filesize_t(struct mystr* p_str, filesize_t the_filesize) 131{ 132 str_alloc_text(p_str, vsf_sysutil_filesize_t_to_str(the_filesize)); 133} 134 135void 136str_free(struct mystr* p_str) 137{ 138 if (p_str->p_buf != 0) 139 { 140 vsf_sysutil_free(p_str->p_buf); 141 } 142 p_str->p_buf = 0; 143 p_str->len = 0; 144 p_str->alloc_bytes = 0; 145} 146 147void 148str_empty(struct mystr* p_str) 149{ 150 /* Ensure a buffer is allocated. */ 151 (void) str_getbuf(p_str); 152 str_trunc(p_str, 0); 153} 154 155void 156str_trunc(struct mystr* p_str, unsigned int trunc_len) 157{ 158 if (trunc_len >= p_str->alloc_bytes) 159 { 160 bug("trunc_len not smaller than alloc_bytes in str_trunc"); 161 } 162 p_str->len = trunc_len; 163 p_str->p_buf[p_str->len] = '\0'; 164} 165 166void 167str_reserve(struct mystr* p_str, unsigned int res_len) 168{ 169 /* Reserve space for the trailing zero as well. */ 170 res_len++; 171 if (res_len > p_str->alloc_bytes) 172 { 173 p_str->p_buf = vsf_sysutil_realloc(p_str->p_buf, res_len); 174 p_str->alloc_bytes = res_len; 175 } 176 p_str->p_buf[res_len - 1] = '\0'; 177} 178 179int 180str_isempty(const struct mystr* p_str) 181{ 182 return (p_str->len == 0); 183} 184 185unsigned int 186str_getlen(const struct mystr* p_str) 187{ 188 return p_str->len; 189} 190 191const char* 192str_getbuf(const struct mystr* p_str) 193{ 194 if (p_str->p_buf == 0) 195 { 196 if (p_str->len != 0 || p_str->alloc_bytes != 0) 197 { 198 bug("p_buf NULL and len or alloc_bytes != 0 in str_getbuf"); 199 } 200 private_str_alloc_memchunk((struct mystr*)p_str, 0, 0); 201 } 202 return p_str->p_buf; 203} 204 205int 206str_strcmp(const struct mystr* p_str1, const struct mystr* p_str2) 207{ 208 return str_equal_internal(p_str1->p_buf, p_str1->len, 209 p_str2->p_buf, p_str2->len); 210} 211 212static int 213str_equal_internal(const char* p_buf1, unsigned int buf1_len, 214 const char* p_buf2, unsigned int buf2_len) 215{ 216 int retval; 217 unsigned int minlen = buf1_len; 218 if (buf2_len < minlen) 219 { 220 minlen = buf2_len; 221 } 222 //printf(" [str_equal] [%s][%s](%d)(%d)(%d)\n", p_buf1, p_buf2, buf1_len, buf2_len, minlen); // tmp test 223 retval = vsf_sysutil_memcmp(p_buf1, p_buf2, minlen); 224 if (retval != 0 || buf1_len == buf2_len) 225 { 226 return retval; 227 } 228 /* Strings equal but lengths differ. The greater one, then, is the longer */ 229 return (int) (buf1_len - buf2_len); 230} 231 232int 233str_equal(const struct mystr* p_str1, const struct mystr* p_str2) 234{ 235 return (str_strcmp(p_str1, p_str2) == 0); 236} 237 238int 239str_equal_text(const struct mystr* p_str, const char* p_text) 240{ 241 unsigned int cmplen = vsf_sysutil_strlen(p_text); 242 return (str_equal_internal(p_str->p_buf, p_str->len, p_text, cmplen) == 0); 243} 244 245void 246str_append_str(struct mystr* p_str, const struct mystr* p_other) 247{ 248 private_str_append_memchunk(p_str, p_other->p_buf, p_other->len); 249} 250 251void 252str_append_text(struct mystr* p_str, const char* p_src) 253{ 254 unsigned int len = vsf_sysutil_strlen(p_src); 255 private_str_append_memchunk(p_str, p_src, len); 256} 257 258void 259str_append_char(struct mystr* p_str, char the_char) 260{ 261 private_str_append_memchunk(p_str, &the_char, sizeof(the_char)); 262} 263 264void 265str_append_ulong(struct mystr* p_str, unsigned long the_ulong) 266{ 267 str_append_text(p_str, vsf_sysutil_ulong_to_str(the_ulong)); 268} 269 270void 271str_append_filesize_t(struct mystr* p_str, filesize_t the_filesize) 272{ 273 str_append_text(p_str, vsf_sysutil_filesize_t_to_str(the_filesize)); 274} 275 276void 277str_append_double(struct mystr* p_str, double the_double) 278{ 279 str_append_text(p_str, vsf_sysutil_double_to_str(the_double)); 280} 281 282void 283str_upper(struct mystr* p_str) 284{ 285 unsigned int i; 286 for (i=0; i < p_str->len; i++) 287 { 288 p_str->p_buf[i] = vsf_sysutil_toupper(p_str->p_buf[i]); 289 } 290} 291 292void 293str_rpad(struct mystr* p_str, const unsigned int min_width) 294{ 295 unsigned int to_pad; 296 if (p_str->len >= min_width) 297 { 298 return; 299 } 300 to_pad = min_width - p_str->len; 301 while (to_pad--) 302 { 303 str_append_char(p_str, ' '); 304 } 305} 306 307void 308str_lpad(struct mystr* p_str, const unsigned int min_width) 309{ 310 static struct mystr s_tmp_str; 311 unsigned int to_pad; 312 if (p_str->len >= min_width) 313 { 314 return; 315 } 316 to_pad = min_width - p_str->len; 317 str_empty(&s_tmp_str); 318 while (to_pad--) 319 { 320 str_append_char(&s_tmp_str, ' '); 321 } 322 str_append_str(&s_tmp_str, p_str); 323 str_copy(p_str, &s_tmp_str); 324} 325 326void 327str_replace_char(struct mystr* p_str, char from, char to) 328{ 329 unsigned int i; 330 for (i=0; i < p_str->len; i++) 331 { 332 if (p_str->p_buf[i] == from) 333 { 334 p_str->p_buf[i] = to; 335 } 336 } 337} 338 339void 340str_replace_text(struct mystr* p_str, const char* p_from, const char* p_to) 341{ 342 static struct mystr s_lhs_chunk_str; 343 static struct mystr s_rhs_chunk_str; 344 unsigned int lhs_len; 345 str_copy(&s_lhs_chunk_str, p_str); 346 str_free(p_str); 347 do 348 { 349 lhs_len = str_getlen(&s_lhs_chunk_str); 350 str_split_text(&s_lhs_chunk_str, &s_rhs_chunk_str, p_from); 351 /* Copy lhs to destination */ 352 str_append_str(p_str, &s_lhs_chunk_str); 353 /* If this was a 'hit', append the 'to' text */ 354 if (str_getlen(&s_lhs_chunk_str) < lhs_len) 355 { 356 str_append_text(p_str, p_to); 357 } 358 /* Current rhs becomes new lhs */ 359 str_copy(&s_lhs_chunk_str, &s_rhs_chunk_str); 360 } while (!str_isempty(&s_lhs_chunk_str)); 361} 362 363void 364str_split_char(struct mystr* p_src, struct mystr* p_rhs, char c) 365{ 366 /* Just use str_split_text */ 367 char ministr[2]; 368 ministr[0] = c; 369 ministr[1] = '\0'; 370 str_split_text(p_src, p_rhs, ministr); 371} 372 373void 374str_split_char_reverse(struct mystr* p_src, struct mystr* p_rhs, char c) 375{ 376 /* Just use str_split_text_reverse */ 377 char ministr[2]; 378 ministr[0] = c; 379 ministr[1] = '\0'; 380 str_split_text_reverse(p_src, p_rhs, ministr); 381} 382 383void 384str_split_text(struct mystr* p_src, struct mystr* p_rhs, const char* p_text) 385{ 386 str_split_text_common(p_src, p_rhs, p_text, 0); 387} 388 389void 390str_split_text_reverse(struct mystr* p_src, struct mystr* p_rhs, 391 const char* p_text) 392{ 393 str_split_text_common(p_src, p_rhs, p_text, 1); 394} 395 396static void 397str_split_text_common(struct mystr* p_src, struct mystr* p_rhs, 398 const char* p_text, int is_reverse) 399{ 400 struct str_locate_result locate_result; 401 unsigned int indexx; 402 unsigned int search_len = vsf_sysutil_strlen(p_text); 403 if (is_reverse) 404 { 405 locate_result = str_locate_text_reverse(p_src, p_text); 406 } 407 else 408 { 409 locate_result = str_locate_text(p_src, p_text); 410 } 411 /* Not found? */ 412 if (!locate_result.found) 413 { 414 str_empty(p_rhs); 415 return; 416 } 417 indexx = locate_result.index; 418 if (indexx + search_len > p_src->len) 419 { 420 bug("indexx invalid in str_split_text"); 421 } 422 /* Build rhs */ 423 private_str_alloc_memchunk(p_rhs, p_src->p_buf + indexx + search_len, 424 p_src->len - indexx - search_len); 425 /* Build lhs */ 426 str_trunc(p_src, indexx); 427} 428 429struct str_locate_result 430str_locate_str(const struct mystr* p_str, const struct mystr* p_look_str) 431{ 432 return str_locate_text(p_str, str_getbuf(p_look_str)); 433} 434 435struct str_locate_result 436str_locate_str_reverse(const struct mystr* p_str, 437 const struct mystr* p_look_str) 438{ 439 return str_locate_text_reverse(p_str, str_getbuf(p_look_str)); 440} 441 442struct str_locate_result 443str_locate_char(const struct mystr* p_str, char look_char) 444{ 445 char look_str[2]; 446 look_str[0] = look_char; 447 look_str[1] = '\0'; 448 return str_locate_text(p_str, look_str); 449} 450 451struct str_locate_result 452str_locate_chars(const struct mystr* p_str, const char* p_chars) 453{ 454 struct str_locate_result retval; 455 unsigned int num_chars = vsf_sysutil_strlen(p_chars); 456 unsigned int i = 0; 457 458 memset(&retval, 0, sizeof(struct str_locate_result)); 459 retval.found = 0; 460 for (; i < p_str->len; ++i) 461 { 462 unsigned int j = 0; 463 char this_char = p_str->p_buf[i]; 464 for (; j < num_chars; ++j) 465 { 466 if (p_chars[j] == this_char) 467 { 468 retval.found = 1; 469 retval.index = i; 470 retval.char_found = p_chars[j]; 471 return retval; 472 } 473 } 474 } 475 return retval; 476} 477 478struct str_locate_result 479str_locate_text(const struct mystr* p_str, const char* p_text) 480{ 481 struct str_locate_result retval; 482 unsigned int i; 483 unsigned int text_len = vsf_sysutil_strlen(p_text); 484 retval.found = 0; 485 retval.index = 0; 486 if (text_len == 0 || text_len > p_str->len) 487 { 488 /* Not found */ 489 return retval; 490 } 491 for (i=0; i <= (p_str->len - text_len); i++) 492 { 493 if (vsf_sysutil_memcmp(p_str->p_buf + i, p_text, text_len) == 0) 494 { 495 retval.found = 1; 496 retval.index = i; 497 return retval; 498 } 499 } 500 /* Not found */ 501 return retval; 502} 503 504struct str_locate_result 505str_locate_text_reverse(const struct mystr* p_str, const char* p_text) 506{ 507 struct str_locate_result retval; 508 unsigned int i; 509 unsigned int text_len = vsf_sysutil_strlen(p_text); 510 retval.found = 0; 511 retval.index = 0; 512 if (text_len == 0 || text_len > p_str->len) 513 { 514 return retval; 515 } 516 i = p_str->len - text_len; 517 /* Want to go through loop once even if i==0 */ 518 while (1) 519 { 520 if (vsf_sysutil_memcmp(p_str->p_buf + i, p_text, text_len) == 0) 521 { 522 retval.found = 1; 523 retval.index = i; 524 return retval; 525 } 526 if (i == 0) 527 { 528 break; 529 } 530 i--; 531 } 532 /* Not found */ 533 return retval; 534} 535 536void 537str_left(const struct mystr* p_str, struct mystr* p_out, unsigned int chars) 538{ 539 if (chars > p_str->len) 540 { 541 bug("chars invalid in str_left"); 542 } 543 private_str_alloc_memchunk(p_out, p_str->p_buf, chars); 544} 545 546void 547str_right(const struct mystr* p_str, struct mystr* p_out, unsigned int chars) 548{ 549 unsigned int indexx = p_str->len - chars; 550 if (chars > p_str->len) 551 { 552 bug("chars invalid in str_right"); 553 } 554 private_str_alloc_memchunk(p_out, p_str->p_buf + indexx, chars); 555} 556 557void 558str_mid_to_end(const struct mystr* p_str, struct mystr* p_out, 559 unsigned int indexx) 560{ 561 if (indexx > p_str->len) 562 { 563 bug("invalid indexx in str_mid_to_end"); 564 } 565 private_str_alloc_memchunk(p_out, p_str->p_buf + indexx, 566 p_str->len - indexx); 567} 568 569char 570str_get_char_at(const struct mystr* p_str, const unsigned int indexx) 571{ 572 if (indexx >= p_str->len) 573 { 574 bug("bad indexx in str_get_char_at"); 575 } 576 return p_str->p_buf[indexx]; 577} 578 579int 580str_contains_space(const struct mystr* p_str) 581{ 582 unsigned int i; 583 for (i=0; i < p_str->len; i++) 584 { 585 if (vsf_sysutil_isspace(p_str->p_buf[i])) 586 { 587 return 1; 588 } 589 } 590 return 0; 591} 592 593int 594str_contains_unprintable(const struct mystr* p_str) 595{ 596 unsigned int i; 597 for (i=0; i < p_str->len; i++) 598 { 599 if (!vsf_sysutil_isprint(p_str->p_buf[i])) 600 { 601 return 1; 602 } 603 } 604 return 0; 605} 606 607int 608str_atoi(const struct mystr* p_str) 609{ 610 return vsf_sysutil_atoi(str_getbuf(p_str)); 611} 612 613filesize_t 614str_a_to_filesize_t(const struct mystr* p_str) 615{ 616 return vsf_sysutil_a_to_filesize_t(str_getbuf(p_str)); 617} 618 619unsigned int 620str_octal_to_uint(const struct mystr* p_str) 621{ 622 return vsf_sysutil_octal_to_uint(str_getbuf(p_str)); 623} 624 625int 626str_getline(const struct mystr* p_str, struct mystr* p_line_str, 627 unsigned int* p_pos) 628{ 629 unsigned int start_pos = *p_pos; 630 unsigned int curr_pos = start_pos; 631 unsigned int buf_len = str_getlen(p_str); 632 const char* p_buf = str_getbuf(p_str); 633 unsigned int out_len; 634 if (start_pos > buf_len) 635 { 636 bug("p_pos out of range in str_getline"); 637 } 638 str_empty(p_line_str); 639 if (start_pos == buf_len) 640 { 641 return 0; 642 } 643 while (curr_pos < buf_len && p_buf[curr_pos] != '\n') 644 { 645 curr_pos++; 646 } 647 out_len = curr_pos - start_pos; 648 /* If we ended on a \n - skip it */ 649 if (curr_pos < buf_len && p_buf[curr_pos] == '\n') 650 { 651 curr_pos++; 652 } 653 private_str_alloc_memchunk(p_line_str, p_buf + start_pos, out_len); 654 *p_pos = curr_pos; 655 return 1; 656} 657 658int 659str_contains_line(const struct mystr* p_str, const struct mystr* p_line_str) 660{ 661 static struct mystr s_curr_line_str; 662 unsigned int pos = 0; 663 while (str_getline(p_str, &s_curr_line_str, &pos)) 664 { 665 if (str_equal(&s_curr_line_str, p_line_str)) 666 { 667 return 1; 668 } 669 } 670 return 0; 671} 672 673void 674str_replace_unprintable(struct mystr* p_str, char new_char) 675{ 676 unsigned int i; 677 for (i=0; i < p_str->len; i++) 678 { 679 if (!vsf_sysutil_isprint(p_str->p_buf[i])) 680 { 681 p_str->p_buf[i] = new_char; 682 } 683 } 684} 685 686