1%% options 2 3copyright owner = Dirk Krause 4copyright year = 2015-xxxx 5SPDX-License-Identifier: BSD-3-Clause 6 7 8 9%% header 10 11/** @file 12 Additional string functions for 13 8 bit characters. 14 15 Although some of the functions in this module duplicate 16 functionality from string.h functions, you should use 17 the functions from this module. 18 With DK4DK4_WIN_AVOID_CRT or DK4_WIN_DENY_CRT defined to non-zero 19 these functions call Windows API functions like 20 lstrcmpA() ... instead of CRT functions. 21*/ 22 23#ifndef DK4CONF_H_INCLUDED 24#if DK4_BUILDING_DKTOOLS4 25#include "dk4conf.h" 26#else 27#include <dktools-4/dk4conf.h> 28#endif 29#endif 30 31#ifndef DK4TYPES_H_INCLUDED 32#if DK4_BUILDING_DKTOOLS4 33#include <libdk4base/dk4types.h> 34#else 35#include <dktools-4/dk4types.h> 36#endif 37#endif 38 39#ifndef DK4ERROR_H_INCLUDED 40#if DK4_BUILDING_DKTOOLS4 41#include <libdk4base/dk4error.h> 42#else 43#include <dktools-4/dk4error.h> 44#endif 45#endif 46 47#ifndef STDLIB_H_INCLUDED 48#include <stdlib.h> 49#define STDLIB_H_INCLUDED 1 50#endif 51 52 53#ifdef __cplusplus 54extern "C" { 55#endif 56 57/** Copy string, check destination buffer size. 58 59 CRT on Windows: Optional. 60 @param dst Destination buffer address. 61 @param sz Destination buffer size. 62 @param src Source string. 63 @param erp Error report, may be NULL. 64 @return 1 on success, 0 on error. 65 66 Error codes: 67 - DK4_E_INVALID_ARGUMENTS<br> 68 if dst or src is NULL or sz is 0, 69 - DK4_E_BUFFER_TOO_SMALL<br> 70 if the dst buffer is too small. 71*/ 72int 73 74dk4str8_cpy_s(char *dst, size_t sz, const char *src, dk4_er_t *erp); 75 76/** Concatenate strings, check destination buffer size. 77 78 CRT on Windows: Optional. 79 @param dst Destination buffer address. 80 @param sz Destination buffer size. 81 @param src Source string. 82 @param erp Error report, may be NULL. 83 @return 1 on success, 0 on error. 84 85 Error codes: 86 - DK4_E_INVALID_ARGUMENTS<br> 87 if dst or src is NULL or sz is 0, 88 - DK4_E_MATH_OVERFLOW<br> 89 if a mathematical overflow occured in size calculation, 90 - DK4_E_BUFFER_TOO_SMALL<br> 91 if the concatenated string doest not fit into the buffer. 92*/ 93int 94 95dk4str8_cat_s(char *dst, size_t sz, const char *src, dk4_er_t *erp); 96 97/** Copy characters within a string from right to left. 98 This copy operation is intended for moving characters within 99 one string from right to left, making the string shorter 100 as is. This function does not check buffer size or report 101 any error. 102 For normal string copy operations, use the dk4str8_cpy_s() 103 function instead. 104 105 CRT on Windows: Not used. 106 @param dst Destination buffer address. 107 @param src Source string. 108*/ 109void 110 111dk4str8_cpy_to_left(char *dst, const char *src); 112 113/** Find string length. 114 115 CRT on Windows: Optional. 116 @param src Source string. 117 @return String length. 118*/ 119size_t 120 121dk4str8_len(const char *src); 122 123/** Compare two strings. 124 125 CRT on Windows: Optional. 126 @param s1 Left string, may be NULL. 127 @param s2 Right string, may be NULL. 128 @return 1 if s1>s2, 0 if s1==s2, -1 if s1<s2. 129*/ 130int 131 132dk4str8_cmp(const char *s1, const char *s2); 133 134/** Compare two strings. 135 136 CRT on Windows: Optional, disabling CRT probably degrades performance. 137 @param s1 Left string, may be NULL. 138 @param s2 Right string, may be NULL. 139 @param n Maximum number of characters to compare. 140 @return 1 if s1>s2, 0 if s1==s2, -1 if s1<s2. 141*/ 142int 143 144dk4str8_ncmp(const char *s1, const char *s2, size_t n); 145 146/** Compare two strings, case-insensitive comparison. 147 148 CRT on Windows: Optional. 149 @param s1 Left string, may be NULL. 150 @param s2 Right string, may be NULL. 151 @return 1 if s1>s2, 0 if s1==s2, -1 if s1<s2. 152*/ 153int 154 155dk4str8_casecmp(const char *s1, const char *s2); 156 157/** Compare two file path names. 158 159 CRT on Windows: Optional. 160 @param s1 Left string, may be NULL. 161 @param s2 Right string, may be NULL. 162 @return 1 if s1>s2, 0 if s1==s2, -1 if s1<s2. 163*/ 164int 165 166dk4str8_pathcmp(const char *s1, const char *s2); 167 168/** Find first occurance of character c in string s. 169 170 CRT on Windows: Optional, disabling CRT degrades performance. 171 @param s String to search for c. 172 @param c Character to find. 173 @return Pointer to first occurance if found, NULL otherwise. 174*/ 175char * 176 177dk4str8_chr(const char *s, char c); 178 179/** Find last occurance of character c in string s. 180 181 CRT on Windows: Optional, disabling CRT degrades performance. 182 @param s String to search for c. 183 @param c Character to find. 184 @return Pointer to last occurance if found, NULL otherwise. 185*/ 186char * 187 188dk4str8_rchr(const char *s, char c); 189 190/** Retrieve first token from *stringp. 191 192 CRT on Windows: Optional, disabling CRT degrades performance. 193 @param stringp Adress of string pointer. 194 @param delim String containing the delimiter set, 195 my be NULL to use the default delimiter 196 set (space, tabulator, carriage return and newline). 197 @return Pointer to first token on success, NULL if no (further) 198 token found. 199*/ 200char * 201 202dk4str8_sep(char **stringp, const char *delim); 203 204/** Find first token in string. 205 206 CRT on Windows: Optional, disabling CRT degrades performance. 207 @param src String to search for tokens. 208 @param delim String containing the delimiter characters, 209 may be NULL to use the default delimiter set. 210 @return Pointer to first token if found, NULL otherwise. 211*/ 212char * 213 214dk4str8_start(const char *src, const char *delim); 215 216/** Cut string after first token, find start of second token in string. 217 218 CRT on Windows: Optional, disabling CRT degrades performance. 219 @param src String to search for tokens, 220 normally the result of dk4str8_start() or a 221 previous dk4str8_next() call. 222 @param delim String containing the delimiter characters, 223 may be NULL to use the default delimiter set. 224 @return Pointer to second token if found, NULL otherwise. 225*/ 226char * 227 228dk4str8_next(char *src, const char *delim); 229 230/** Split a string into tokens. 231 232 CRT on Windows: Optional, disabling CRT degrades performance. 233 @param dpp Pointer to string pointer array. 234 @param szdpp Size of destination string pointer array. 235 @param src Source string to process. 236 @param delim String containing delimiter characters, 237 may be NULL to use the default delimiter set. 238 @param erp Error report, may be NULL. 239 @return Number of tokens found on success, 0 if no token 240 found or on error. 241 242 Error codes: 243 - DK4_E_INVALID_ARGUMENTS<br> 244 for invalid function arguments, 245 - DK4_E_BUFFER_TOO_SMALL<br> 246 with dt.mem.nelem set to the number of tokens in string if the dpp 247 array is too short. 248*/ 249size_t 250 251dk4str8_tokenize( 252 char **dpp, size_t szdpp, char *src, const char *delim, dk4_er_t *erp 253); 254 255/** Normalize a string (remove leading and trailing delimiters, 256 replace delimiter sequences by just one delimiter). 257 258 CRT on Windows: Optional, disabling CRT degrades performance. 259 @param src Buffer containing the string to normalize. 260 @param delim String containing delimiter characters, 261 may be NULL to use the default delimiter set. 262*/ 263void 264 265dk4str8_normalize(char *src, const char *delim); 266 267/** Find index of a string in an array of strings. 268 269 CRT on Windows: Optional. 270 @param arr Array of strings. 271 @param str String to find in array. 272 @param cs Flag: Case-sensitive search (0=no, other=yes). 273 @return Non-negative index value on success, -1 on error. 274*/ 275int 276 277dk4str8_array_index(const char * const *arr, const char *str, int cs); 278 279/** Find index of a string in an array of strings. 280 281 CRT on Windows: Optional, disabling CRT degrades performances 282 and reduces to upper-case conversion to characters 'a' to 'z'. 283 @param arr Array of string allowing abbreviations. 284 @param spec Special character indicating start of optional text. 285 @param str String to find in array. 286 @param cs Flag: Case-sensitive search (0=no, other=yes). 287 @return Non-negative index value on success, -1 on error. 288*/ 289int 290 291dk4str8_abbr_index(const char * const *arr, char spec, const char *str, int cs); 292 293/** Check whether a text matches a pattern, the text may be abbreviated. 294 295 CRT on Windows: Optional, disabling CRT degrades performances 296 and reduces to upper-case conversion to characters 'a' to 'z' 297 in case-insensitive comparisons. 298 @param str Text to check. 299 @param pattern Pattern for comparison. 300 @param spec Special character marking the abbreviation in the 301 pattern. 302 @param cs Flag: Case sensitive (1) or not (0). 303 @return 1 for a match, 0 otherwise. 304*/ 305int 306 307dk4str8_is_abbr(const char *str, const char *pattern, char spec, int cs); 308 309/** Check whether a string represents a boolean value. 310 311 CRT on Windows: Optional, disabling CRT degrades performances. 312 @param str String to check. 313 @return 1 if str represents a boolean value, 0 otherwise. 314*/ 315int 316 317dk4str8_is_bool(const char *str); 318 319/** Check whether a string represents the boolean value TRUE. 320 321 CRT on Windows: Optional, disabling CRT degrades performances. 322 @param str String to check. 323 @return 1 if str represents the boolean value TRUE, 0 otherwise. 324*/ 325int 326 327dk4str8_is_on(const char *str); 328 329#if (DK4_ON_WINDOWS) || (DK4_HAVE_MALLOC && DK4_HAVE_FREE) 330 331/** Duplicate string in dynamically allocated memory. 332 333 CRT on Windows: Optional, disabling CRT reduces functionality 334 to strings with length fitting to int and overall size in 335 bytes - including finalizer - fitting into a DWORD. 336 @param src String to duplicate. 337 @param erp Error report, may be NULL. 338 @return Pointer to string in new memory on succes, NULL on error. 339 Use dk4mem_free() to release the memory after usage. 340 341 Error codes: 342 - DK4_E_INVALID_ARGUMENTS<br> 343 if src is a NULL pointer, 344 - DK4_E_MATH_OVERFLOW<br> 345 on mathematical overflow in size calculation, 346 - DK4_E_MEMORY<br> 347 if no memory is available. 348*/ 349char * 350 351dk4str8_dup(const char *src, dk4_er_t *erp); 352 353#endif 354 355 356/** Remove trailing white spaces. 357 358 CRT on Windows: Optional, disabling CRT degrades performance. 359 @param str String to remove white spaces from. 360 @param whsp White spaces set. 361*/ 362void 363 364dk4str8_rtwh(char *str, const char *whsp); 365 366/** Convert character to uppercase. 367 368 CRT on Windows: Optional, disabling CRT degrades performances 369 and reduces functionality to characters 'a' to 'z'. 370 @param c Character to convert. 371 @return Conversion result. 372*/ 373char 374 375dk4str8_toupper(char c); 376 377/** Convert character to lowercase. 378 379 CRT on Windows: Optional, disabling CRT degrades performances 380 and reduces functionality to characters 'A' to 'Z'. 381 @param c Character to convert. 382 @return Conversion result. 383*/ 384char 385 386dk4str8_tolower(char c); 387 388/** Remove trailing newline from line. 389 390 CRT on Windows: Not used. 391 @param lptr Line pointer. 392*/ 393void 394 395dk4str8_delnl(char *lptr); 396 397/** Skip the first text words in a line, return pointer to start 398 of next word. 399 400 CRT on Windows: Optional, disabling CRT degrades performance. 401 @param line Line to process. 402 @param skip Number of words to skip. 403 @return Pointer to next word on success, NULL on error. 404*/ 405const char * 406 407dk4str8_skip(const char *line, size_t skip); 408 409/** Sanitize string (overwrite using 0 bytes). 410 411 CRT on Windows: Optional. 412 @param str Address of string to sanitize. 413 @return 1 on success, 0 on error. 414*/ 415int 416 417dk4str8_sanitize(char *str); 418 419/** Sanitize string buffer (overwrite using 0 bytes). 420 421 CRT on Windows: Optional. 422 @param str Address of string buffer. 423 @param sz Size of string buffer (number of elements). 424 @return 1 on success, 0 on error. 425*/ 426int 427 428dk4str8_buffer_sanitize(char *str, size_t sz); 429 430/** Sanitize dynamically allocated memory and release it. 431 432 CRT on Windows: Optional. 433 @param str Address of string to sanitize and release. 434 @return 1 on success, 0 on error. 435*/ 436int 437 438dk4str8_free_sanitized(char *str); 439 440#ifdef __cplusplus 441} 442#endif 443 444 445/** Sanitize string and release it, set pointer to NULL. 446 @param p Pointer to string to release. 447*/ 448#define dk4str8_release_sanitized(p) \ 449do { if (NULL != p) { (void)dk4str8_free_sanitized(p); } p = NULL; } while (0) 450 451 452%% module 453 454#include "dk4conf.h" 455 456#ifndef DK4USE_H_INCLUDED 457#include <libdk4base/dk4use.h> 458#endif 459 460#if DK4_ON_WINDOWS && (DK4_WIN_AVOID_CRT || DK4_WIN_DENY_CRT) 461#ifndef WINDOWS_H_INCLUDED 462#include <windows.h> 463#define WINDOWS_H_INCLUDED 1 464#endif 465#endif 466 467#include <libdk4base/dk4str8.h> 468 469#if DK4_HAVE_STRING_H 470#ifndef STRING_H_INCLUDED 471#include <string.h> 472#define STRING_H_INCLUDED 1 473#endif 474#endif 475 476#if DK4_HAVE_CTYPE_H 477#ifndef CTYPE_H_INCLUDED 478#include <ctype.h> 479#define CTYPE_H_INCLUDED 1 480#endif 481#endif 482 483#if DK4_HAVE_ASSERT_H 484#ifndef ASSERT_H_INCLUDED 485#include <assert.h> 486#define ASSERT_H_INCLUDED 1 487#endif 488#endif 489 490 491#ifndef DK4NUMCO_H_INCLUDED 492#include <libdk4base/dk4numco.h> 493#endif 494 495#ifndef DK4MEM_H_INCLUDED 496#include <libdk4base/dk4mem.h> 497#endif 498 499#ifndef DK4MEMRS_H_INCLUDED 500#include <libdk4base/dk4memrs.h> 501#endif 502 503 504$!trace-include 505 506 507 508/** Constant strings used in the module. 509*/ 510static const char * const dk4str8_modkw[] = { 511$!string-table 512# 513# 0 Default delimiters. 514# 515 \t\r\n 516$!end 517}; 518 519 520 521/** First index of a keyword indicating true in the 522 dk4str8_boolkw array below. 523*/ 524#define DK4STR8_FIRST_TRUE 5 525 526/** Keywords for boolean values. 527*/ 528static const char * const dk4str8_boolkw[] = { 529$!string-table 530# 531# 0...4 false 532# 533- 5340 535n$o 536of$f 537f$alse 538# 539# 5... true 540# 541+ 5421 543y$es 544on 545t$rue 546ok 547$!end 548}; 549 550 551 552#if 0 553/** Number of significant digits. 554*/ 555static const int dk4str8_dbl_digits = DK4_DBL_DIGITS; 556#endif 557 558 559void 560 561dk4str8_cpy_to_left(char *dst, const char *src) 562{ 563 register char *dptr; 564 register const char *sptr; 565#if DK4_USE_ASSERT 566 assert(NULL != dst); 567 assert(NULL != src); 568#endif 569 if (NULL != dst) { 570 *dst = '\0'; 571 if (NULL != src) { 572 dptr = dst; sptr = src; 573 while('\0' != *sptr) { *(dptr++) = *(sptr++); } 574 *dptr = '\0'; 575 } 576 } 577} 578 579 580 581size_t 582 583dk4str8_len(const char *src) 584{ 585 if (NULL == src) { 586 return 0; 587 } 588#if DK4_ON_WINDOWS 589 /* +++ Windows */ 590#if DK4_WIN_AVOID_CRT || DK4_WIN_DENY_CRT 591 return ((size_t)lstrlenA(src)); 592#else 593 return (strlen(src)); 594#endif 595 /* --- Windows */ 596#else 597 /* +++ non-Windows */ 598 return (strlen(src)); 599 /* --- non-Windows */ 600#endif 601} 602 603 604 605char 606 607dk4str8_toupper(char c) 608{ 609#if DK4_ON_WINDOWS 610#if DK4_WIN_DENY_CRT 611 char back; 612 back = c; 613 if (('a' <= c) && ('z' >= c)) { 614 back = 'A' + (c - 'a'); 615 } 616 return back; 617#else 618 return (char)toupper((unsigned char)c); 619#endif 620#else 621 return (char)toupper((unsigned char)c); 622#endif 623} 624 625 626 627char 628 629dk4str8_tolower(char c) 630{ 631#if DK4_ON_WINDOWS 632#if DK4_WIN_DENY_CRT 633 char back; 634 back = c; 635 if (('A' <= c) && ('Z' >= c)) { 636 back = 'a' + (c - 'A'); 637 } 638 return back; 639#else 640 return (char)tolower((unsigned char)c); 641#endif 642#else 643 return (char)tolower((unsigned char)c); 644#endif 645} 646 647 648 649char * 650 651dk4str8_chr(const char *s, char c) 652{ 653 if (NULL == s) { return NULL; } 654#if DK4_ON_WINDOWS 655 /* +++ Windows */ 656#if DK4_WIN_DENY_CRT 657 { 658 char *back = NULL; 659 while (('\0' != *s) && (NULL == back)) { 660 if (c == *s) { 661 back = (char *)s; 662 } else { 663 s++; 664 } 665 } 666 return back; 667 } 668#else 669#ifdef __cplusplus 670 return ((char *)strchr(s, (int)((unsigned char)c))); 671#else 672 return (strchr(s, (int)((unsigned char)c))); 673#endif 674#endif 675 /* --- Windows */ 676#else 677 /* +++ non-Windows */ 678#ifdef __cplusplus 679 return ((char *)strchr(s, (int)((unsigned char)c))); 680#else 681 return (strchr(s, (int)((unsigned char)c))); 682#endif 683 /* --- non-Windows */ 684#endif 685} 686 687 688 689char * 690 691dk4str8_rchr(const char *s, char c) 692{ 693 if (NULL == s) { return NULL; } 694#if DK4_ON_WINDOWS 695#if DK4_WIN_DENY_CRT 696 { 697 char *back = NULL; 698 while ('\0' != *s) { 699 if (c == *s) { 700 back = (char *)s; 701 } 702 s++; 703 } 704 return back; 705 } 706#else 707#ifdef __cplusplus 708 return ((char *)strrchr(s, (int)((unsigned char)c))); 709#else 710 return (strrchr(s, (int)((unsigned char)c))); 711#endif 712#endif 713#else 714#ifdef __cplusplus 715 return ((char *)strrchr(s, (int)((unsigned char)c))); 716#else 717 return (strrchr(s, (int)((unsigned char)c))); 718#endif 719#endif 720} 721 722 723 724int 725 726dk4str8_cpy_s(char *dst, size_t sz, const char *src, dk4_er_t *erp) 727{ 728 int back = 0; 729#if DK4_USE_ASSERT 730 assert(NULL != dst); 731 assert(0 < sz); 732#endif 733 if ((NULL != dst) && (0 < sz)) { 734 *dst = '\0'; 735 if (NULL != src) { 736 if (dk4str8_len(src) < sz) { 737#if DK4_ON_WINDOWS 738 /* +++ Windows */ 739#if DK4_WIN_AVOID_CRT || DK4_WIN_DENY_CRT 740 (void)lstrcpyA(dst, (char *)src); 741#else 742#if DK4_USE_PRAGMA_WARNING_DISABLE 743#pragma warning( push ) 744#pragma warning( disable: 4996 ) 745#endif 746 (void)strcpy(dst, src); 747#if DK4_USE_PRAGMA_WARNING_DISABLE 748#pragma warning( pop ) 749#endif 750#endif 751 /* --- Windows */ 752#else 753 /* +++ non-Windows */ 754 (void)strcpy(dst, src); 755 /* --- non-Windows */ 756#endif 757 back = 1; 758 } else { 759 *dst = '\0'; 760 dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL); 761 } 762 } else { 763 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 764 } 765 } else { 766 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 767 } 768 return back; 769} 770 771 772 773int 774 775dk4str8_cat_s(char *dst, size_t sz, const char *src, dk4_er_t *erp) 776{ 777 size_t la; 778 size_t lb; 779 int back = 0; 780#if DK4_USE_ASSERT 781 assert(NULL != dst); 782 assert(0 < sz); 783#endif 784 if ((NULL != dst) && (0 < sz) && (NULL != src)) { 785 la = dk4str8_len(dst); 786 lb = dk4str8_len(src); 787 if ((SIZE_MAX - la) >= lb) { 788 if ((la + lb) < sz) { 789#if DK4_ON_WINDOWS 790 /* +++ Windows */ 791#if DK4_WIN_AVOID_CRT || DK4_WIN_DENY_CRT 792 (void)lstrcatA(dst, (char *)src); 793#else 794#if DK4_USE_PRAGMA_WARNING_DISABLE 795#pragma warning( push ) 796#pragma warning( disable: 4996 ) 797#endif 798 (void)strcat(dst, src); 799#if DK4_USE_PRAGMA_WARNING_DISABLE 800#pragma warning( pop ) 801#endif 802#endif 803 /* --- Windows */ 804#else 805 /* +++ non-Windows */ 806 (void)strcat(dst, src); 807 /* --- non-Windows */ 808#endif 809 back = 1; 810 } else { 811 dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL); 812 } 813 } else { 814 dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW); 815 } 816 } else { 817 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 818 } 819 return back; 820} 821 822 823 824int 825 826dk4str8_cmp(const char *s1, const char *s2) 827{ 828 int back = 0; 829 if (NULL != s1) { 830 if (NULL != s2) { 831#if DK4_ON_WINDOWS 832 /* +++ Windows */ 833#if DK4_WIN_AVOID_CRT || DK4_WIN_DENY_CRT 834 back = lstrcmpA(s1, s2); 835#else 836 back = strcmp(s1, s2); 837#endif 838 /* --- Windows */ 839#else 840 /* +++ non-Windows */ 841 back = strcmp(s1, s2); 842 /* --- non-Windows */ 843#endif 844 if (0 > back) back = -1; 845 if (0 < back) back = 1; 846 } else { 847 back = 1; 848 } 849 } else { 850 if (NULL != s2) { 851 back = -1; 852 } 853 } 854 return back; 855} 856 857 858 859int 860 861dk4str8_ncmp(const char *s1, const char *s2, size_t n) 862{ 863 int back = 0; 864 if (NULL != s1) { 865 if (NULL != s2) { 866#if (DK4_ON_WINDOWS && (DK4_WIN_AVOID_CRT || DK4_WIN_DENY_CRT) ) \ 867|| (!(DK4_HAVE_WCSNCMP)) || (!(DK4_HAVE__WCSNCMP)) 868 while((0 < n--) && (0 == back)) { 869 if ('\0' == *s1) { 870 if ('\0' == *s2) { 871 n = 0; 872 } else { 873 back = -1; 874 } 875 } else { 876 if ('\0' == *s2) { 877 back = 1; 878 } else { 879 if (*s1 > *s2) { 880 back = 1; 881 } else { 882 if (*s1 < *s2) { 883 back = -1; 884 } else { 885 s1++; s2++; 886 } 887 } 888 } 889 } 890 } 891#else 892 back = strncmp(s1, s2, n); 893 if (-1 > back) back = -1; 894 if ( 1 < back) back = 1; 895#endif 896 } else { 897 back = 1; 898 } 899 } else { 900 if (NULL != s2) { 901 back = -1; 902 } 903 } 904 return back; 905} 906 907 908 909int 910 911dk4str8_casecmp(const char *s1, const char *s2) 912{ 913 int back = 0; 914 if (NULL != s1) { 915 if (NULL != s2) { 916#if DK4_ON_WINDOWS 917 /* +++ Windows */ 918#if DK4_WIN_AVOID_CRT || DK4_WIN_DENY_CRT 919 back = lstrcmpiA(s1, s2); 920#else 921 back = _stricmp(s1, s2); 922#endif 923 /* --- non-Windows */ 924#else 925 /* +++ non-Windows */ 926#if DK4_HAVE_STRCASECMP 927 back = strcasecmp(s1, s2); 928#else 929#if DK4_HAVE__STRICMP 930 back = _stricmp(s1, s2); 931#else 932#if DK4_HAVE_STRICMP 933 back = stricmp(s1, s2); 934#else 935#error No function for case-insensitive comparison available! 936#endif 937#endif 938#endif 939 /* --- non-Windows */ 940#endif 941 if (0 > back) back = -1; 942 if (0 < back) back = 1; 943 } else { 944 back = 1; 945 } 946 } else { 947 if (NULL != s2) { 948 back = -1; 949 } 950 } 951 return back; 952} 953 954 955 956#if (DK4_ON_WINDOWS) || (DK4_HAVE_MALLOC && DK4_HAVE_FREE) 957 958char * 959 960dk4str8_dup(const char *src, dk4_er_t *erp) 961{ 962 char *back = NULL; 963 size_t lgt; 964 if (NULL != src) { 965 lgt = dk4str8_len(src); 966 if (SIZE_MAX > lgt) { 967 back = (char *)dk4mem_malloc_bytes((1+lgt), erp); 968 if (NULL != back) { 969 (void)dk4str8_cpy_s(back, (1+lgt), src, erp); 970 } 971 } else { 972 dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW); 973 } 974 } else { 975 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 976 } 977 return back; 978} 979 980#endif 981 982 983 984char * 985 986dk4str8_start(const char *src, const char *delim) 987{ 988 char *back = NULL; 989 if (NULL != src) { 990 if (NULL == delim) { delim = dk4str8_modkw[0]; } 991 while (('\0' != *src) && (NULL == back)) { 992 if (NULL != dk4str8_chr(delim, *src)) { 993 src++; 994 } else { 995 back = (char *)src; 996 } 997 } 998 } 999 return back; 1000} 1001 1002 1003 1004/** Internal function for next token search. 1005 1006 CRT on Windows: Optional, disabling CRT degrades performance. 1007 @param src String containing tokens, must be set to 1008 the start of a token. 1009 @param delim Delimiter set. 1010 @return Pointer to next token on success, NULL on error. 1011*/ 1012static 1013char * 1014dk4str8_i_next(char *src, const char *delim) 1015{ 1016 char *back = NULL; 1017 if (NULL != src) { 1018 if (NULL == delim) { delim = dk4str8_modkw[0]; } 1019 while (('\0' != *src) && (NULL == back)) { 1020 if (NULL != dk4str8_chr(delim, *src)) { 1021 back = src; 1022 } else { 1023 src++; 1024 } 1025 } 1026 if (NULL != back) { 1027 *(back++) = '\0'; 1028 back = dk4str8_start(back, delim); 1029 } 1030 } 1031 return back; 1032} 1033 1034 1035 1036char * 1037 1038dk4str8_next(char *src, const char *delim) 1039{ 1040 char *back = NULL; 1041 if (NULL != src) { 1042 back = dk4str8_start(src, delim); 1043 if (NULL != back) { 1044 back = dk4str8_i_next(back, delim); 1045 } 1046 } 1047 return back; 1048} 1049 1050 1051 1052char * 1053 1054dk4str8_sep(char **stringp, const char *delim) 1055{ 1056 char *back = NULL; 1057 $? "+ dk4str8_sep \"%!8s\" \"%!8s\"", TR_8STR(*stringp), TR_8STR(delim) 1058#if DK4_USE_ASSERT 1059 assert(NULL != stringp); 1060#endif 1061 if (NULL != stringp) { 1062 if (NULL != *stringp) { 1063 if (NULL == delim) { delim = dk4str8_modkw[0]; } 1064 back = dk4str8_start(*stringp, delim); 1065 if (NULL != back) { 1066 *stringp = dk4str8_next(back, delim); 1067 } else { 1068 *stringp = NULL; 1069 } 1070 } 1071 } $? "- dk4str8_sep \"%!8s\"", TR_8STR(back) 1072 return back; 1073} 1074 1075 1076 1077size_t 1078 1079dk4str8_tokenize( 1080 char **dpp, size_t szdpp, char *src, const char *delim, dk4_er_t *erp 1081) 1082{ 1083 char *context; 1084 char *token; 1085 size_t back = 0; 1086#if DK4_USE_ASSERT 1087 assert(NULL != dpp); 1088 assert(0 < szdpp); 1089#endif 1090 if ((NULL != dpp) && (0 < szdpp) && (NULL != src)) { 1091 if (NULL == delim) { delim = dk4str8_modkw[0]; } 1092 context = src; 1093 while (NULL != (token = dk4str8_sep(&context, delim))) { 1094 if (back < szdpp) { 1095 dpp[back] = token; 1096 } 1097 back++; 1098 } 1099 if (back >= szdpp) { 1100 dk4error_set_elsize_nelem( 1101 erp, DK4_E_BUFFER_TOO_SMALL, sizeof(DK4_PCHAR), back 1102 ); 1103 back = 0; 1104 } 1105 } else { 1106 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 1107 } 1108 return back; 1109} 1110 1111 1112 1113void 1114 1115dk4str8_normalize(char *src, const char *delim) 1116{ 1117 char *p1; /* Pointer to traverse text. */ 1118 char *p2; /* Start of next token. */ 1119 int cc; /* Flag: Can continue. */ 1120 if (NULL != src) { 1121 /* 1122 Set up delimiter set, correct if necessary. 1123 */ 1124 if (NULL == delim) { delim = dk4str8_modkw[0]; } 1125 /* 1126 Remove leading delimiters. 1127 */ 1128 p1 = src; 1129 cc = 0; 1130 if ('\0' != *p1) { 1131 if (NULL != dk4str8_chr(delim, *p1)) { 1132 p2 = dk4str8_start(p1, delim); 1133 if (NULL != p2) { 1134 dk4str8_cpy_to_left(p1, p2); 1135 cc = 1; 1136 } else { 1137 *p1 = '\0'; 1138 } 1139 } else { 1140 cc = 1; 1141 } 1142 } 1143 /* 1144 Now traverse the string. 1145 */ 1146 while (0 != cc) { 1147 if ('\0' == *p1) { 1148 cc = 0; 1149 } else { 1150 if (NULL != dk4str8_chr(delim, *p1)) { 1151 *p1 = *delim; 1152 if ('\0' == p1[1]) { 1153 *p1 = '\0'; 1154 cc = 0; 1155 } else { 1156 if (NULL != dk4str8_chr(delim, p1[1])) { 1157 p2 = dk4str8_start(p1, delim); 1158 if (NULL != p2) { 1159 dk4str8_cpy_to_left(++p1, p2); 1160 } else { 1161 *p1 = '\0'; 1162 cc = 0; 1163 } 1164 } else { 1165 p1++; 1166 } 1167 } 1168 } else { 1169 p1++; 1170 } 1171 } 1172 } 1173 } 1174} 1175 1176 1177 1178int 1179 1180dk4str8_array_index(const char * const *arr, const char *str, int cs) 1181{ 1182 int back = -1; 1183 int cand = 0; 1184#if DK4_USE_ASSERT 1185 assert(NULL != arr); 1186#endif 1187 if ((NULL != arr) && (NULL != str)) { 1188 while((NULL != *arr) && (-1 == back)) { 1189 if (0 != cs) { 1190 if (0 == dk4str8_cmp(*arr, str)) { back = cand; } 1191 } else { 1192 if (0 == dk4str8_casecmp(*arr, str)) { back = cand; } 1193 } 1194 arr++; cand++; 1195 } 1196 } 1197 return back; 1198} 1199 1200 1201 1202int 1203 1204dk4str8_is_abbr(const char *str, const char *pattern, char spec, int cs) 1205{ 1206 const char *lptr = NULL; /* Pointer to traverse string */ 1207 const char *pptr = NULL; /* Pointer to traverse pattern */ 1208 int back = 0; /* Function result */ 1209 int fspec = 0; /* Flag: spec was found */ 1210 int cc = 1; /* Flag: Can continue */ 1211 char cl; 1212 char cp; 1213 $? "+ dk4str8_is_abbr \"%!8s\" \"%!8s\" \"%!8c\"", pattern, str, spec 1214#if DK4_USE_ASSERT 1215 assert(NULL != pattern); 1216#endif 1217 if ((NULL != str) && (NULL != pattern)) { 1218 lptr = str; pptr = pattern; 1219 while (0 != cc) { 1220 if ((0 == fspec) && (*pptr == spec)) { 1221 fspec = 1; 1222 pptr++; 1223 } else { 1224 if ('\0' != *lptr) { 1225 cl = *lptr; cp = *pptr; 1226 if (0 == cs) { 1227 cl = dk4str8_toupper(cl); 1228 cp = dk4str8_toupper(cp); 1229 } 1230 if (cl == cp) { 1231 lptr++; 1232 pptr++; 1233 } else { 1234 cc = 0; 1235 } 1236 } else { 1237 cc = 0; 1238 if (('\0' == *pptr) || (0 != fspec)) { back = 1; } 1239 } 1240 } 1241 } 1242 } $? "- dk4str8_is_abbr %d", back 1243 return back; 1244} 1245 1246 1247 1248int 1249 1250dk4str8_abbr_index(const char * const *arr, char spec, const char *str, int cs) 1251{ 1252 int back = -1; 1253 int cand = 0; 1254 $? "+ dk4str8_abbr_index" 1255#if DK4_USE_ASSERT 1256 assert(NULL != arr); 1257#endif 1258 if ((NULL != arr) && (NULL != str)) { 1259 while ((NULL != *arr) && (-1 == back)) { 1260 if (0 != dk4str8_is_abbr(str, *arr, spec, cs)) { 1261 back = cand; 1262 } 1263 arr++; cand++; 1264 } 1265 } 1266 $? "- dk4str8_abbr_index %d", back 1267 return back; 1268} 1269 1270 1271 1272int 1273 1274dk4str8_is_bool(const char *str) 1275{ 1276 int back = 0; 1277 if (NULL != str) { 1278 if (-1 < dk4str8_abbr_index(dk4str8_boolkw, '$', str, 0)) { 1279 back = 1; 1280 } 1281 } 1282 return back; 1283} 1284 1285 1286 1287int 1288 1289dk4str8_is_on(const char *str) 1290{ 1291 int back = 0; 1292 $? "+ dk4str8_is_on" 1293 if (NULL != str) { 1294 back = dk4str8_abbr_index(dk4str8_boolkw, '$', str, 0); 1295 if (-1 < back) { 1296 if (DK4STR8_FIRST_TRUE <= back) { 1297 back = 1; 1298 } else { 1299 back = 0; 1300 } 1301 } else { 1302 back = 0; 1303 } 1304 } 1305 $? "- dk4str8_is_on %d", back 1306 return back; 1307} 1308 1309 1310 1311int 1312 1313dk4str8_pathcmp(const char *s1, const char *s2) 1314{ 1315#if DK4_HAVE_CASE_INSENSITIVE_PATHNAMES 1316 return (dk4str8_casecmp(s1, s2)); 1317#else 1318 return (dk4str8_cmp(s1, s2)); 1319#endif 1320} 1321 1322 1323 1324void 1325 1326dk4str8_rtwh(char *str, const char *whsp) 1327{ 1328 char *ptr = NULL; 1329 if (NULL == whsp) { whsp = dk4str8_modkw[0]; } 1330 if (NULL != str) { 1331 while ('\0' != *str) { 1332 if (NULL != dk4str8_chr(whsp, *str)) { 1333 if (NULL == ptr) { ptr = str; } 1334 } else { 1335 ptr = NULL; 1336 } 1337 str++; 1338 } 1339 if (NULL != ptr) { *ptr = '\0'; } 1340 } 1341} 1342 1343 1344 1345void 1346 1347dk4str8_delnl(char *lptr) 1348{ 1349 if (NULL != lptr) { 1350 while ('\0' != *lptr) { 1351 if ('\n' == *lptr) { 1352 *lptr = '\0'; 1353 } else { 1354 if ('\r' == *lptr) { 1355 if ('\n' == lptr[1]) { 1356 *lptr = '\0'; 1357 } else { 1358 if ('\0' == lptr[1]) { 1359 *lptr = '\0'; 1360 } else { 1361 lptr++; 1362 } 1363 } 1364 } else { 1365 lptr++; 1366 } 1367 } 1368 } 1369 } 1370} 1371 1372 1373 1374const char * 1375 1376dk4str8_skip(const char *line, size_t skip) 1377{ 1378 const char *back = NULL; 1379 size_t words = 0; /* Number of words already found */ 1380 int lwt = 0; /* Flag: Last char was text */ 1381 1382 if (NULL != line) { 1383 if (0 < skip) { 1384 while((NULL == back) && ('\0' != *line)) { 1385 switch (*line) { 1386 case ' ': case '\t': case '\n': case '\r': { 1387 lwt = 0; 1388 } break; 1389 default: { 1390 if (0 == lwt) { 1391 if (++words > skip) { 1392 back = line; 1393 } 1394 } 1395 lwt = 1; 1396 } break; 1397 } 1398 line++; 1399 } 1400 } else { 1401 back = dk4str8_start(line, NULL); 1402 } 1403 } 1404 return back; 1405} 1406 1407 1408 1409int 1410 1411dk4str8_buffer_sanitize(char *str, size_t sz) 1412{ 1413 int back = 0; 1414#if DK4_USE_ASSERT 1415 assert(NULL != str); 1416 assert(0 < sz); 1417#endif 1418 if (NULL != str) { 1419 if (0 < sz) { 1420 back = dk4mem_reset_secure(str, sz, NULL); 1421 } else { 1422 back = 1; 1423 } 1424 } 1425 return back; 1426} 1427 1428 1429 1430int 1431 1432dk4str8_sanitize(char *str) 1433{ 1434 int back = 0; 1435 if (NULL != str) { 1436 back = dk4str8_buffer_sanitize(str, dk4str8_len(str)); 1437 } 1438 return back; 1439} 1440 1441 1442 1443int 1444 1445dk4str8_free_sanitized(char *str) 1446{ 1447 int back = 0; 1448 if (NULL != str) { 1449 back = dk4str8_sanitize(str); 1450 dk4mem_free(str); 1451 } 1452 return back; 1453} 1454 1455