triostr.c 41.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*************************************************************************
 *
 * $Id$
 *
 * Copyright (C) 2001 Bjorn Reese and Daniel Stenberg.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
 *
 ************************************************************************/

/*************************************************************************
 * Include files
 */

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
27
#include "triodef.h"
28 29 30 31 32 33
#include "triostr.h"

/*************************************************************************
 * Definitions
 */

34 35 36 37 38 39 40 41
#if !defined(TRIO_STRING_PUBLIC)
# define TRIO_STRING_PUBLIC TRIO_PUBLIC
#endif
#if !defined(TRIO_STRING_PRIVATE)
# define TRIO_STRING_PRIVATE TRIO_PRIVATE
#endif

#if !defined(NULL)
42 43
# define NULL 0
#endif
44 45 46 47
#if !defined(NIL)
# define NIL ((char)0)
#endif
#if !defined(FALSE)
48 49 50
# define FALSE (1 == 0)
# define TRUE (! FALSE)
#endif
51 52 53
#if !defined(BOOLEAN_T)
# define BOOLEAN_T int
#endif
54

55 56 57
#ifdef __VMS
# define USE_STRTOD
#elif defined(TRIO_COMPILER_SUPPORTS_C99)
58 59 60 61 62 63 64 65 66
# define USE_STRTOD
# define USE_STRTOF
#elif defined(TRIO_COMPILER_MSVC)
# define USE_STRTOD
#endif

#if defined(TRIO_PLATFORM_UNIX)
# define USE_STRCASECMP
# define USE_STRNCASECMP
67 68 69 70 71
# if defined(TRIO_PLATFORM_SUNOS)
#  define USE_SYS_ERRLIST
# else
#  define USE_STRERROR
# endif
72 73 74 75 76 77
# if defined(TRIO_PLATFORM_QNX)
#  define strcasecmp(x,y) stricmp(x,y)
#  define strncasecmp(x,y,n) strnicmp(x,y,n)
# endif
#elif defined(TRIO_PLATFORM_WIN32)
# define USE_STRCASECMP
78 79 80 81 82
# if defined(_WIN32_WCE)
#  define strcasecmp(x,y) _stricmp(x,y)
# else
#  define strcasecmp(x,y) strcmpi(x,y)
# endif
83 84 85 86
#elif defined(TRIO_PLATFORM_OS400)
# define USE_STRCASECMP
# define USE_STRNCASECMP
# include <strings.h>
87 88
#endif

89 90 91 92 93
#if !(defined(TRIO_PLATFORM_SUNOS))
# define USE_TOLOWER
# define USE_TOUPPER
#endif

94 95 96 97 98 99 100 101 102 103 104
/*************************************************************************
 * Structures
 */

struct _trio_string_t
{
  char *content;
  size_t length;
  size_t allocated;
};

105 106 107 108 109 110 111 112
/*************************************************************************
 * Constants
 */

#if !defined(TRIO_MINIMAL)
static TRIO_CONST char rcsid[] = "@(#)$Id$";
#endif

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
/*************************************************************************
 * Static String Functions
 */

#if defined(TRIO_DOCUMENTATION)
# include "doc/doc_static.h"
#endif
/** @addtogroup StaticStrings
    @{
*/

/**
   Create new string.

   @param size Size of new string.
   @return Pointer to string, or NULL if allocation failed.
*/
130 131 132 133
TRIO_STRING_PUBLIC char *
trio_create
TRIO_ARGS1((size),
	   size_t size)
134 135 136 137 138 139 140 141 142 143
{
  return (char *)TRIO_MALLOC(size);
}


/**
   Destroy string.

   @param string String to be freed.
*/
144 145 146 147
TRIO_STRING_PUBLIC void
trio_destroy
TRIO_ARGS1((string),
	   char *string)
148 149 150 151 152 153 154 155 156 157 158 159 160 161
{
  if (string)
    {
      TRIO_FREE(string);
    }
}


/**
   Count the number of characters in a string.

   @param string String to measure.
   @return Number of characters in @string.
*/
162 163 164 165
TRIO_STRING_PUBLIC size_t
trio_length
TRIO_ARGS1((string),
	   TRIO_CONST char *string)
166 167 168 169 170
{
  return strlen(string);
}


171
#if !defined(TRIO_MINIMAL)
172 173
/**
   Append @p source at the end of @p target.
174

175 176 177
   @param target Target string.
   @param source Source string.
   @return Boolean value indicating success or failure.
178

179 180 181 182 183 184
   @pre @p target must point to a memory chunk with sufficient room to
   contain the @p target string and @p source string.
   @pre No boundary checking is performed, so insufficient memory will
   result in a buffer overrun.
   @post @p target will be zero terminated.
*/
185 186 187 188 189
TRIO_STRING_PUBLIC int
trio_append
TRIO_ARGS2((target, source),
	   char *target,
	   TRIO_CONST char *source)
190 191 192
{
  assert(target);
  assert(source);
193

194 195
  return (strcat(target, source) != NULL);
}
196
#endif /* !defined(TRIO_MINIMAL) */
197

198
#if !defined(TRIO_MINIMAL)
199 200
/**
   Append at most @p max characters from @p source to @p target.
201

202 203 204 205
   @param target Target string.
   @param max Maximum number of characters to append.
   @param source Source string.
   @return Boolean value indicating success or failure.
206

207 208 209 210 211 212 213
   @pre @p target must point to a memory chuck with sufficient room to
   contain the @p target string and the @p source string (at most @p max
   characters).
   @pre No boundary checking is performed, so insufficient memory will
   result in a buffer overrun.
   @post @p target will be zero terminated.
*/
214 215 216 217 218 219
TRIO_STRING_PUBLIC int
trio_append_max
TRIO_ARGS3((target, max, source),
	   char *target,
	   size_t max,
	   TRIO_CONST char *source)
220 221
{
  size_t length;
222

223 224 225 226
  assert(target);
  assert(source);

  length = trio_length(target);
227

228 229 230 231 232 233
  if (max > length)
    {
      strncat(target, source, max - length - 1);
    }
  return TRUE;
}
234
#endif /* !defined(TRIO_MINIMAL) */
235 236


237
#if !defined(TRIO_MINIMAL)
238 239 240 241 242 243 244
/**
   Determine if a string contains a substring.

   @param string String to be searched.
   @param substring String to be found.
   @return Boolean value indicating success or failure.
*/
245 246 247 248 249
TRIO_STRING_PUBLIC int
trio_contains
TRIO_ARGS2((string, substring),
	   TRIO_CONST char *string,
	   TRIO_CONST char *substring)
250 251 252
{
  assert(string);
  assert(substring);
253

254 255
  return (0 != strstr(string, substring));
}
256
#endif /* !defined(TRIO_MINIMAL) */
257 258


259
#if !defined(TRIO_MINIMAL)
260 261
/**
   Copy @p source to @p target.
262

263 264 265
   @param target Target string.
   @param source Source string.
   @return Boolean value indicating success or failure.
266

267 268 269 270 271 272
   @pre @p target must point to a memory chunk with sufficient room to
   contain the @p source string.
   @pre No boundary checking is performed, so insufficient memory will
   result in a buffer overrun.
   @post @p target will be zero terminated.
*/
273 274 275 276 277
TRIO_STRING_PUBLIC int
trio_copy
TRIO_ARGS2((target, source),
	   char *target,
	   TRIO_CONST char *source)
278 279 280
{
  assert(target);
  assert(source);
281

282 283 284
  (void)strcpy(target, source);
  return TRUE;
}
285
#endif /* !defined(TRIO_MINIMAL) */
286 287 288 289


/**
   Copy at most @p max characters from @p source to @p target.
290

291 292 293 294
   @param target Target string.
   @param max Maximum number of characters to append.
   @param source Source string.
   @return Boolean value indicating success or failure.
295

296 297 298 299 300 301
   @pre @p target must point to a memory chunk with sufficient room to
   contain the @p source string (at most @p max characters).
   @pre No boundary checking is performed, so insufficient memory will
   result in a buffer overrun.
   @post @p target will be zero terminated.
*/
302 303 304 305 306 307
TRIO_STRING_PUBLIC int
trio_copy_max
TRIO_ARGS3((target, max, source),
	   char *target,
	   size_t max,
	   TRIO_CONST char *source)
308 309 310 311 312 313 314 315 316 317 318
{
  assert(target);
  assert(source);
  assert(max > 0); /* Includes != 0 */

  (void)strncpy(target, source, max - 1);
  target[max - 1] = (char)0;
  return TRUE;
}


319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
/*
 * TrioDuplicateMax
 */
TRIO_STRING_PRIVATE char *
TrioDuplicateMax
TRIO_ARGS2((source, size),
	   TRIO_CONST char *source,
	   size_t size)
{
  char *target;

  assert(source);

  /* Make room for string plus a terminating zero */
  size++;
  target = trio_create(size);
  if (target)
    {
      trio_copy_max(target, size, source);
    }
  return target;
}


343 344
/**
   Duplicate @p source.
345

346 347
   @param source Source string.
   @return A copy of the @p source string.
348

349 350
   @post @p target will be zero terminated.
*/
351 352 353 354
TRIO_STRING_PUBLIC char *
trio_duplicate
TRIO_ARGS1((source),
	   TRIO_CONST char *source)
355 356 357 358 359
{
  return TrioDuplicateMax(source, trio_length(source));
}


360
#if !defined(TRIO_MINIMAL)
361 362
/**
   Duplicate at most @p max characters of @p source.
363

364 365 366
   @param source Source string.
   @param max Maximum number of characters to duplicate.
   @return A copy of the @p source string.
367

368 369
   @post @p target will be zero terminated.
*/
370 371 372 373
TRIO_STRING_PUBLIC char *
trio_duplicate_max TRIO_ARGS2((source, max),
			      TRIO_CONST char *source,
			      size_t max)
374 375 376 377 378 379 380 381 382 383 384 385 386
{
  size_t length;

  assert(source);
  assert(max > 0);

  length = trio_length(source);
  if (length > max)
    {
      length = max;
    }
  return TrioDuplicateMax(source, length);
}
387
#endif /* !defined(TRIO_MINIMAL) */
388 389 390 391


/**
   Compare if two strings are equal.
392

393 394 395
   @param first First string.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.
396

397 398
   Case-insensitive comparison.
*/
399 400 401 402 403
TRIO_STRING_PUBLIC int
trio_equal
TRIO_ARGS2((first, second),
	   TRIO_CONST char *first,
	   TRIO_CONST char *second)
404 405 406 407 408 409 410 411 412 413 414
{
  assert(first);
  assert(second);

  if ((first != NULL) && (second != NULL))
    {
#if defined(USE_STRCASECMP)
      return (0 == strcasecmp(first, second));
#else
      while ((*first != NIL) && (*second != NIL))
	{
415
	  if (trio_to_upper(*first) != trio_to_upper(*second))
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
	    {
	      break;
	    }
	  first++;
	  second++;
	}
      return ((*first == NIL) && (*second == NIL));
#endif
    }
  return FALSE;
}


/**
   Compare if two strings are equal.
431

432 433 434
   @param first First string.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.
435

436 437
   Case-sensitive comparison.
*/
438 439 440 441 442
TRIO_STRING_PUBLIC int
trio_equal_case
TRIO_ARGS2((first, second),
	   TRIO_CONST char *first,
	   TRIO_CONST char *second)
443 444 445 446 447 448 449 450 451 452 453 454
{
  assert(first);
  assert(second);

  if ((first != NULL) && (second != NULL))
    {
      return (0 == strcmp(first, second));
    }
  return FALSE;
}


455
#if !defined(TRIO_MINIMAL)
456 457
/**
   Compare if two strings up until the first @p max characters are equal.
458

459 460 461 462
   @param first First string.
   @param max Maximum number of characters to compare.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.
463

464 465
   Case-sensitive comparison.
*/
466 467 468 469 470 471
TRIO_STRING_PUBLIC int
trio_equal_case_max
TRIO_ARGS3((first, max, second),
	   TRIO_CONST char *first,
	   size_t max,
	   TRIO_CONST char *second)
472 473 474 475 476 477 478 479 480 481
{
  assert(first);
  assert(second);

  if ((first != NULL) && (second != NULL))
    {
      return (0 == strncmp(first, second, max));
    }
  return FALSE;
}
482
#endif /* !defined(TRIO_MINIMAL) */
483 484 485 486


/**
   Compare if two strings are equal.
487

488 489 490 491 492 493
   @param first First string.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.

   Collating characters are considered equal.
*/
494 495 496 497 498
TRIO_STRING_PUBLIC int
trio_equal_locale
TRIO_ARGS2((first, second),
	   TRIO_CONST char *first,
	   TRIO_CONST char *second)
499 500 501 502 503 504 505 506 507 508 509 510 511 512
{
  assert(first);
  assert(second);

#if defined(LC_COLLATE)
  return (strcoll(first, second) == 0);
#else
  return trio_equal(first, second);
#endif
}


/**
   Compare if two strings up until the first @p max characters are equal.
513

514 515 516 517
   @param first First string.
   @param max Maximum number of characters to compare.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.
518

519 520
   Case-insensitive comparison.
*/
521 522 523 524 525 526
TRIO_STRING_PUBLIC int
trio_equal_max
TRIO_ARGS3((first, max, second),
	   TRIO_CONST char *first,
	   size_t max,
	   TRIO_CONST char *second)
527 528 529 530 531 532 533 534 535 536 537 538 539
{
  assert(first);
  assert(second);

  if ((first != NULL) && (second != NULL))
    {
#if defined(USE_STRNCASECMP)
      return (0 == strncasecmp(first, second, max));
#else
      /* Not adequately tested yet */
      size_t cnt = 0;
      while ((*first != NIL) && (*second != NIL) && (cnt <= max))
	{
540
	  if (trio_to_upper(*first) != trio_to_upper(*second))
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
	    {
	      break;
	    }
	  first++;
	  second++;
	  cnt++;
	}
      return ((cnt == max) || ((*first == NIL) && (*second == NIL)));
#endif
    }
  return FALSE;
}


/**
   Provide a textual description of an error code (errno).

   @param error_number Error number.
   @return Textual description of @p error_number.
*/
561 562 563 564
TRIO_STRING_PUBLIC TRIO_CONST char *
trio_error
TRIO_ARGS1((error_number),
	   int error_number)
565 566
{
#if defined(USE_STRERROR)
567

568
  return strerror(error_number);
569 570 571 572 573 574 575 576 577

#elif defined(USE_SYS_ERRLIST)

  extern char *sys_errlist[];
  extern int sys_nerr;

  return ((error_number < 0) || (error_number >= sys_nerr))
    ? "unknown"
    : sys_errlist[error_number];
578

579
#else
580

581
  return "unknown";
582

583 584 585 586
#endif
}


587
#if !defined(TRIO_MINIMAL) && !defined(_WIN32_WCE)
588 589 590 591 592 593 594 595 596 597 598 599
/**
   Format the date/time according to @p format.

   @param target Target string.
   @param max Maximum number of characters to format.
   @param format Formatting string.
   @param datetime Date/time structure.
   @return Number of formatted characters.

   The formatting string accepts the same specifiers as the standard C
   function strftime.
*/
600 601 602 603 604 605 606
TRIO_STRING_PUBLIC size_t
trio_format_date_max
TRIO_ARGS4((target, max, format, datetime),
	   char *target,
	   size_t max,
	   TRIO_CONST char *format,
	   TRIO_CONST struct tm *datetime)
607 608 609 610 611
{
  assert(target);
  assert(format);
  assert(datetime);
  assert(max > 0);
612

613 614
  return strftime(target, max, format, datetime);
}
615
#endif /* !defined(TRIO_MINIMAL) */
616 617


618
#if !defined(TRIO_MINIMAL)
619 620 621 622 623 624 625 626 627 628
/**
   Calculate a hash value for a string.

   @param string String to be calculated on.
   @param type Hash function.
   @return Calculated hash value.

   @p type can be one of the following
   @li @c TRIO_HASH_PLAIN Plain hash function.
*/
629 630 631 632 633
TRIO_STRING_PUBLIC unsigned long
trio_hash
TRIO_ARGS2((string, type),
	   TRIO_CONST char *string,
	   int type)
634 635 636 637 638
{
  unsigned long value = 0L;
  char ch;

  assert(string);
639

640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
  switch (type)
    {
    case TRIO_HASH_PLAIN:
      while ( (ch = *string++) != NIL )
	{
	  value *= 31;
	  value += (unsigned long)ch;
	}
      break;
    default:
      assert(FALSE);
      break;
    }
  return value;
}
655
#endif /* !defined(TRIO_MINIMAL) */
656 657


658
#if !defined(TRIO_MINIMAL)
659 660 661 662 663 664 665
/**
   Find first occurrence of a character in a string.

   @param string String to be searched.
   @param character Character to be found.
   @param A pointer to the found character, or NULL if character was not found.
 */
666 667 668 669 670
TRIO_STRING_PUBLIC char *
trio_index
TRIO_ARGS2((string, character),
	   TRIO_CONST char *string,
	   int character)
671 672 673 674 675
{
  assert(string);

  return strchr(string, character);
}
676
#endif /* !defined(TRIO_MINIMAL) */
677 678


679
#if !defined(TRIO_MINIMAL)
680 681 682 683 684 685 686
/**
   Find last occurrence of a character in a string.

   @param string String to be searched.
   @param character Character to be found.
   @param A pointer to the found character, or NULL if character was not found.
 */
687 688 689 690 691
TRIO_STRING_PUBLIC char *
trio_index_last
TRIO_ARGS2((string, character),
	   TRIO_CONST char *string,
	   int character)
692 693 694 695 696
{
  assert(string);

  return strchr(string, character);
}
697
#endif /* !defined(TRIO_MINIMAL) */
698 699


700
#if !defined(TRIO_MINIMAL)
701 702 703 704 705 706
/**
   Convert the alphabetic letters in the string to lower-case.

   @param target String to be converted.
   @return Number of processed characters (converted or not).
*/
707 708 709 710
TRIO_STRING_PUBLIC int
trio_lower
TRIO_ARGS1((target),
	   char *target)
711 712 713
{
  assert(target);

714
  return trio_span_function(target, target, trio_to_lower);
715
}
716
#endif /* !defined(TRIO_MINIMAL) */
717 718


719
#if !defined(TRIO_MINIMAL)
720 721 722 723 724 725 726 727
/**
   Compare two strings using wildcards.

   @param string String to be searched.
   @param pattern Pattern, including wildcards, to search for.
   @return Boolean value indicating success or failure.

   Case-insensitive comparison.
728

729 730 731 732
   The following wildcards can be used
   @li @c * Match any number of characters.
   @li @c ? Match a single character.
*/
733 734 735 736 737
TRIO_STRING_PUBLIC int
trio_match
TRIO_ARGS2((string, pattern),
	   TRIO_CONST char *string,
	   TRIO_CONST char *pattern)
738 739 740
{
  assert(string);
  assert(pattern);
741

742 743 744 745 746 747
  for (; ('*' != *pattern); ++pattern, ++string)
    {
      if (NIL == *string)
	{
	  return (NIL == *pattern);
	}
748
      if ((trio_to_upper((int)*string) != trio_to_upper((int)*pattern))
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
	  && ('?' != *pattern))
	{
	  return FALSE;
	}
    }
  /* two-line patch to prevent *too* much recursiveness: */
  while ('*' == pattern[1])
    pattern++;

  do
    {
      if ( trio_match(string, &pattern[1]) )
	{
	  return TRUE;
	}
    }
  while (*string++);
766

767 768
  return FALSE;
}
769
#endif /* !defined(TRIO_MINIMAL) */
770 771


772
#if !defined(TRIO_MINIMAL)
773 774 775 776 777 778 779 780
/**
   Compare two strings using wildcards.

   @param string String to be searched.
   @param pattern Pattern, including wildcards, to search for.
   @return Boolean value indicating success or failure.

   Case-sensitive comparison.
781

782 783 784 785
   The following wildcards can be used
   @li @c * Match any number of characters.
   @li @c ? Match a single character.
*/
786 787 788 789 790
TRIO_STRING_PUBLIC int
trio_match_case
TRIO_ARGS2((string, pattern),
	   TRIO_CONST char *string,
	   TRIO_CONST char *pattern)
791 792 793
{
  assert(string);
  assert(pattern);
794

795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
  for (; ('*' != *pattern); ++pattern, ++string)
    {
      if (NIL == *string)
	{
	  return (NIL == *pattern);
	}
      if ((*string != *pattern)
	  && ('?' != *pattern))
	{
	  return FALSE;
	}
    }
  /* two-line patch to prevent *too* much recursiveness: */
  while ('*' == pattern[1])
    pattern++;

  do
    {
      if ( trio_match_case(string, &pattern[1]) )
	{
	  return TRUE;
	}
    }
  while (*string++);
819

820 821
  return FALSE;
}
822
#endif /* !defined(TRIO_MINIMAL) */
823 824


825
#if !defined(TRIO_MINIMAL)
826 827 828 829 830 831 832 833
/**
   Execute a function on each character in string.

   @param target Target string.
   @param source Source string.
   @param Function Function to be executed.
   @return Number of processed characters.
*/
834 835 836 837 838 839
TRIO_STRING_PUBLIC size_t
trio_span_function
TRIO_ARGS3((target, source, Function),
	   char *target,
	   TRIO_CONST char *source,
	   int (*Function) TRIO_PROTO((int)))
840 841 842 843 844 845
{
  size_t count = 0;

  assert(target);
  assert(source);
  assert(Function);
846

847 848 849 850 851 852 853
  while (*source != NIL)
    {
      *target++ = Function(*source++);
      count++;
    }
  return count;
}
854
#endif /* !defined(TRIO_MINIMAL) */
855 856


857
#if !defined(TRIO_MINIMAL)
858 859 860 861 862 863 864 865
/**
   Search for a substring in a string.

   @param string String to be searched.
   @param substring String to be found.
   @return Pointer to first occurrence of @p substring in @p string, or NULL
   if no match was found.
*/
866 867 868 869 870
TRIO_STRING_PUBLIC char *
trio_substring
TRIO_ARGS2((string, substring),
	   TRIO_CONST char *string,
	   TRIO_CONST char *substring)
871 872 873 874 875 876
{
  assert(string);
  assert(substring);

  return strstr(string, substring);
}
877
#endif /* !defined(TRIO_MINIMAL) */
878 879


880
#if !defined(TRIO_MINIMAL)
881 882 883 884 885 886 887 888 889
/**
   Search for a substring in the first @p max characters of a string.

   @param string String to be searched.
   @param max Maximum characters to be searched.
   @param substring String to be found.
   @return Pointer to first occurrence of @p substring in @p string, or NULL
   if no match was found.
*/
890 891 892 893 894 895
TRIO_STRING_PUBLIC char *
trio_substring_max
TRIO_ARGS3((string, max, substring),
	   TRIO_CONST char *string,
	   size_t max,
	   TRIO_CONST char *substring)
896 897 898 899 900 901 902
{
  size_t count;
  size_t size;
  char *result = NULL;

  assert(string);
  assert(substring);
903

904 905 906 907 908 909 910 911 912 913 914 915 916 917
  size = trio_length(substring);
  if (size <= max)
    {
      for (count = 0; count <= max - size; count++)
	{
	  if (trio_equal_max(substring, size, &string[count]))
	    {
	      result = (char *)&string[count];
	      break;
	    }
	}
    }
  return result;
}
918
#endif /* !defined(TRIO_MINIMAL) */
919 920


921
#if !defined(TRIO_MINIMAL)
922 923 924 925 926 927 928 929 930
/**
   Tokenize string.

   @param string String to be tokenized.
   @param tokens String containing list of delimiting characters.
   @return Start of new token.

   @warning @p string will be destroyed.
*/
931 932 933 934 935
TRIO_STRING_PUBLIC char *
trio_tokenize
TRIO_ARGS2((string, delimiters),
	   char *string,
	   TRIO_CONST char *delimiters)
936 937
{
  assert(delimiters);
938

939 940
  return strtok(string, delimiters);
}
941
#endif /* !defined(TRIO_MINIMAL) */
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965


/**
   Convert string to floating-point number.

   @param source String to be converted.
   @param endp Pointer to end of the converted string.
   @return A floating-point number.

   The following Extended Backus-Naur form is used
   @verbatim
   double        ::= [ <sign> ]
                     ( <number> |
                       <number> <decimal_point> <number> |
                       <decimal_point> <number> )
                     [ <exponential> [ <sign> ] <number> ]
   number        ::= 1*( <digit> )
   digit         ::= ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
   exponential   ::= ( 'e' | 'E' )
   sign          ::= ( '-' | '+' )
   decimal_point ::= '.'
   @endverbatim
*/
/* FIXME: Add EBNF for hex-floats */
966 967 968 969 970 971 972 973
TRIO_STRING_PUBLIC trio_long_double_t
trio_to_long_double
TRIO_ARGS2((source, endp),
	   TRIO_CONST char *source,
	   char **endp)
{
#if defined(USE_STRTOLD)
  return strtold(source, endp);
974 975 976
#else
  int isNegative = FALSE;
  int isExponentNegative = FALSE;
977 978
  trio_long_double_t integer = 0.0;
  trio_long_double_t fraction = 0.0;
979
  unsigned long exponent = 0;
980 981 982
  trio_long_double_t base;
  trio_long_double_t fracdiv = 1.0;
  trio_long_double_t value = 0.0;
983 984 985 986

  /* First try hex-floats */
  if ((source[0] == '0') && ((source[1] == 'x') || (source[1] == 'X')))
    {
987
      base = 16.0;
988 989 990
      source += 2;
      while (isxdigit((int)*source))
	{
991
	  integer *= base;
992 993
	  integer += (isdigit((int)*source)
		      ? (*source - '0')
994
		      : 10 + (trio_to_upper((int)*source) - 'A'));
995 996 997 998 999 1000 1001
	  source++;
	}
      if (*source == '.')
	{
	  source++;
	  while (isxdigit((int)*source))
	    {
1002 1003 1004
	      fracdiv /= base;
	      fraction += fracdiv * (isdigit((int)*source)
				     ? (*source - '0')
1005
				     : 10 + (trio_to_upper((int)*source) - 'A'));
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
	      source++;
	    }
	  if ((*source == 'p') || (*source == 'P'))
	    {
	      source++;
	      if ((*source == '+') || (*source == '-'))
		{
		  isExponentNegative = (*source == '-');
		  source++;
		}
	      while (isdigit((int)*source))
		{
1018
		  exponent *= 10;
1019 1020 1021 1022 1023
		  exponent += (*source - '0');
		  source++;
		}
	    }
	}
1024 1025
      /* For later use with exponent */
      base = 2.0;
1026 1027 1028
    }
  else /* Then try normal decimal floats */
    {
1029
      base = 10.0;
1030 1031 1032 1033 1034 1035 1036 1037
      isNegative = (*source == '-');
      /* Skip sign */
      if ((*source == '+') || (*source == '-'))
	source++;

      /* Integer part */
      while (isdigit((int)*source))
	{
1038
	  integer *= base;
1039 1040 1041 1042 1043 1044 1045 1046 1047
	  integer += (*source - '0');
	  source++;
	}

      if (*source == '.')
	{
	  source++; /* skip decimal point */
	  while (isdigit((int)*source))
	    {
1048 1049
	      fracdiv /= base;
	      fraction += (*source - '0') * fracdiv;
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
	      source++;
	    }
	}
      if ((*source == 'e')
	  || (*source == 'E')
#if TRIO_MICROSOFT
	  || (*source == 'd')
	  || (*source == 'D')
#endif
	  )
	{
	  source++; /* Skip exponential indicator */
	  isExponentNegative = (*source == '-');
	  if ((*source == '+') || (*source == '-'))
	    source++;
	  while (isdigit((int)*source))
	    {
1067
	      exponent *= (int)base;
1068 1069 1070 1071 1072
	      exponent += (*source - '0');
	      source++;
	    }
	}
    }
1073

1074
  value = integer + fraction;
1075 1076 1077
  if (exponent != 0)
    {
      if (isExponentNegative)
1078
	value /= pow(base, (double)exponent);
1079
      else
1080
	value *= pow(base, (double)exponent);
1081 1082 1083 1084 1085
    }
  if (isNegative)
    value = -value;

  if (endp)
1086
    *endp = (char *)source;
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
  return value;
#endif
}


/**
   Convert string to floating-point number.

   @param source String to be converted.
   @param endp Pointer to end of the converted string.
   @return A floating-point number.

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
   See @ref trio_to_long_double.
*/
TRIO_STRING_PUBLIC double
trio_to_double
TRIO_ARGS2((source, endp),
	   TRIO_CONST char *source,
	   char **endp)
{
#if defined(USE_STRTOD)
  return strtod(source, endp);
#else
  return (double)trio_to_long_double(source, endp);
#endif
}

#if !defined(TRIO_MINIMAL)
/**
   Convert string to floating-point number.

   @param source String to be converted.
   @param endp Pointer to end of the converted string.
   @return A floating-point number.

   See @ref trio_to_long_double.
1123
*/
1124 1125 1126 1127 1128
TRIO_STRING_PUBLIC float
trio_to_float
TRIO_ARGS2((source, endp),
	   TRIO_CONST char *source,
	   char **endp)
1129 1130
{
#if defined(USE_STRTOF)
1131
  return strtof(source, endp);
1132
#else
1133
  return (float)trio_to_long_double(source, endp);
1134 1135
#endif
}
1136
#endif /* !defined(TRIO_MINIMAL) */
1137 1138 1139 1140 1141 1142 1143 1144 1145


/**
   Convert string to signed integer.

   @param string String to be converted.
   @param endp Pointer to end of converted string.
   @param base Radix number of number.
*/
1146 1147 1148 1149 1150 1151
TRIO_STRING_PUBLIC long
trio_to_long
TRIO_ARGS3((string, endp, base),
	   TRIO_CONST char *string,
	   char **endp,
	   int base)
1152 1153 1154
{
  assert(string);
  assert((base >= 2) && (base <= 36));
1155

1156 1157 1158 1159
  return strtol(string, endp, base);
}


1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
#if !defined(TRIO_MINIMAL)
/**
   Convert one alphabetic letter to lower-case.

   @param source The letter to be converted.
   @return The converted letter.
*/
TRIO_STRING_PUBLIC int
trio_to_lower
TRIO_ARGS1((source),
	   int source)
{
#if defined(USE_TOLOWER)
1173

1174
  return tolower(source);
1175

1176 1177 1178 1179 1180 1181
#else

  /* Does not handle locales or non-contiguous alphabetic characters */
  return ((source >= (int)'A') && (source <= (int)'Z'))
    ? source - 'A' + 'a'
    : source;
1182

1183 1184 1185 1186
#endif
}
#endif /* !defined(TRIO_MINIMAL) */

1187
#if !defined(TRIO_MINIMAL)
1188 1189 1190 1191 1192 1193 1194
/**
   Convert string to unsigned integer.

   @param string String to be converted.
   @param endp Pointer to end of converted string.
   @param base Radix number of number.
*/
1195 1196 1197 1198 1199 1200
TRIO_STRING_PUBLIC unsigned long
trio_to_unsigned_long
TRIO_ARGS3((string, endp, base),
	   TRIO_CONST char *string,
	   char **endp,
	   int base)
1201 1202 1203
{
  assert(string);
  assert((base >= 2) && (base <= 36));
1204

1205 1206
  return strtoul(string, endp, base);
}
1207
#endif /* !defined(TRIO_MINIMAL) */
1208 1209


1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
/**
   Convert one alphabetic letter to upper-case.

   @param source The letter to be converted.
   @return The converted letter.
*/
TRIO_STRING_PUBLIC int
trio_to_upper
TRIO_ARGS1((source),
	   int source)
{
#if defined(USE_TOUPPER)
1222

1223
  return toupper(source);
1224

1225 1226 1227 1228 1229 1230
#else

  /* Does not handle locales or non-contiguous alphabetic characters */
  return ((source >= (int)'a') && (source <= (int)'z'))
    ? source - 'a' + 'A'
    : source;
1231

1232 1233 1234
#endif
}

1235
#if !defined(TRIO_MINIMAL)
1236 1237 1238 1239 1240 1241
/**
   Convert the alphabetic letters in the string to upper-case.

   @param target The string to be converted.
   @return The number of processed characters (converted or not).
*/
1242 1243 1244 1245
TRIO_STRING_PUBLIC int
trio_upper
TRIO_ARGS1((target),
	   char *target)
1246 1247 1248
{
  assert(target);

1249
  return trio_span_function(target, target, trio_to_upper);
1250
}
1251
#endif /* !defined(TRIO_MINIMAL) */
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270


/** @} End of StaticStrings */


/*************************************************************************
 * Dynamic String Functions
 */

#if defined(TRIO_DOCUMENTATION)
# include "doc/doc_dynamic.h"
#endif
/** @addtogroup DynamicStrings
    @{
*/

/*
 * TrioStringAlloc
 */
1271 1272
TRIO_STRING_PRIVATE trio_string_t *
TrioStringAlloc(TRIO_NOARGS)
1273 1274
{
  trio_string_t *self;
1275

1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
  self = (trio_string_t *)TRIO_MALLOC(sizeof(trio_string_t));
  if (self)
    {
      self->content = NULL;
      self->length = 0;
      self->allocated = 0;
    }
  return self;
}


/*
 * TrioStringGrow
 *
 * The size of the string will be increased by 'delta' characters. If
 * 'delta' is zero, the size will be doubled.
 */
1293 1294 1295 1296 1297
TRIO_STRING_PRIVATE BOOLEAN_T
TrioStringGrow
TRIO_ARGS2((self, delta),
	   trio_string_t *self,
	   size_t delta)
1298 1299 1300 1301 1302 1303 1304 1305
{
  BOOLEAN_T status = FALSE;
  char *new_content;
  size_t new_size;

  new_size = (delta == 0)
    ? ( (self->allocated == 0) ? 1 : self->allocated * 2 )
    : self->allocated + delta;
1306

1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
  new_content = (char *)TRIO_REALLOC(self->content, new_size);
  if (new_content)
    {
      self->content = new_content;
      self->allocated = new_size;
      status = TRUE;
    }
  return status;
}


1318
#if !defined(TRIO_MINIMAL)
1319 1320 1321 1322 1323 1324 1325
/*
 * TrioStringGrowTo
 *
 * The size of the string will be increased to 'length' plus one characters.
 * If 'length' is less than the original size, the original size will be
 * used (that is, the size of the string is never decreased).
 */
1326 1327 1328 1329 1330
TRIO_STRING_PRIVATE BOOLEAN_T
TrioStringGrowTo
TRIO_ARGS2((self, length),
	   trio_string_t *self,
	   size_t length)
1331 1332 1333 1334 1335 1336
{
  length++; /* Room for terminating zero */
  return (self->allocated < length)
    ? TrioStringGrow(self, length - self->allocated)
    : TRUE;
}
1337
#endif /* !defined(TRIO_MINIMAL) */
1338 1339


1340
#if !defined(TRIO_MINIMAL)
1341 1342
/**
   Create a new dynamic string.
1343

1344 1345 1346
   @param initial_size Initial size of the buffer.
   @return Newly allocated dynamic string, or NULL if memory allocation failed.
*/
1347 1348 1349 1350
TRIO_STRING_PUBLIC trio_string_t *
trio_string_create
TRIO_ARGS1((initial_size),
	   int initial_size)
1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
{
  trio_string_t *self;

  self = TrioStringAlloc();
  if (self)
    {
      if (TrioStringGrow(self,
			 (size_t)((initial_size > 0) ? initial_size : 1)))
	{
	  self->content[0] = (char)0;
	  self->allocated = initial_size;
	}
      else
	{
	  trio_string_destroy(self);
	  self = NULL;
	}
    }
  return self;
}
1371
#endif /* !defined(TRIO_MINIMAL) */
1372 1373 1374 1375


/**
   Deallocate the dynamic string and its contents.
1376

1377 1378
   @param self Dynamic string
*/
1379 1380 1381 1382
TRIO_STRING_PUBLIC void
trio_string_destroy
TRIO_ARGS1((self),
	   trio_string_t *self)
1383 1384
{
  assert(self);
1385

1386 1387 1388 1389 1390 1391 1392 1393
  if (self)
    {
      trio_destroy(self->content);
      TRIO_FREE(self);
    }
}


1394
#if !defined(TRIO_MINIMAL)
1395 1396
/**
   Get a pointer to the content.
1397

1398 1399 1400
   @param self Dynamic string.
   @param offset Offset into content.
   @return Pointer to the content.
1401

1402 1403 1404 1405 1406 1407 1408
   @p Offset can be zero, positive, or negative. If @p offset is zero,
   then the start of the content will be returned. If @p offset is positive,
   then a pointer to @p offset number of characters from the beginning of the
   content is returned. If @p offset is negative, then a pointer to @p offset
   number of characters from the ending of the string, starting at the
   terminating zero, is returned.
*/
1409 1410 1411 1412 1413
TRIO_STRING_PUBLIC char *
trio_string_get
TRIO_ARGS2((self, offset),
	   trio_string_t *self,
	   int offset)
1414 1415
{
  char *result = NULL;
1416

1417 1418 1419 1420 1421 1422 1423 1424 1425 1426
  assert(self);

  if (self->content != NULL)
    {
      if (self->length == 0)
	{
	  (void)trio_string_length(self);
	}
      if (offset >= 0)
	{
1427
	  if (offset > (int)self->length)
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
	    {
	      offset = self->length;
	    }
	}
      else
	{
	  offset += self->length + 1;
	  if (offset < 0)
	    {
	      offset = 0;
	    }
	}
      result = &(self->content[offset]);
    }
  return result;
}
1444
#endif /* !defined(TRIO_MINIMAL) */
1445 1446 1447 1448


/**
   Extract the content.
1449

1450 1451
   @param self Dynamic String
   @return Content of dynamic string.
1452

1453 1454 1455
   The content is removed from the dynamic string. This enables destruction
   of the dynamic string without deallocation of the content.
*/
1456 1457 1458 1459
TRIO_STRING_PUBLIC char *
trio_string_extract
TRIO_ARGS1((self),
	   trio_string_t *self)
1460 1461
{
  char *result;
1462

1463 1464 1465 1466 1467 1468 1469 1470 1471 1472
  assert(self);

  result = self->content;
  /* FIXME: Allocate new empty buffer? */
  self->content = NULL;
  self->length = self->allocated = 0;
  return result;
}


1473
#if !defined(TRIO_MINIMAL)
1474 1475
/**
   Set the content of the dynamic string.
1476

1477 1478
   @param self Dynamic String
   @param buffer The new content.
1479

1480 1481
   Sets the content of the dynamic string to a copy @p buffer.
   An existing content will be deallocated first, if necessary.
1482

1483 1484 1485 1486
   @remark
   This function will make a copy of @p buffer.
   You are responsible for deallocating @p buffer yourself.
*/
1487 1488 1489 1490 1491
TRIO_STRING_PUBLIC void
trio_xstring_set
TRIO_ARGS2((self, buffer),
	   trio_string_t *self,
	   char *buffer)
1492 1493 1494 1495 1496 1497
{
  assert(self);

  trio_destroy(self->content);
  self->content = trio_duplicate(buffer);
}
1498
#endif /* !defined(TRIO_MINIMAL) */
1499 1500 1501 1502 1503


/*
 * trio_string_size
 */
1504 1505 1506 1507
TRIO_STRING_PUBLIC int
trio_string_size
TRIO_ARGS1((self),
	   trio_string_t *self)
1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
{
  assert(self);

  return self->allocated;
}


/*
 * trio_string_terminate
 */
1518 1519 1520 1521
TRIO_STRING_PUBLIC void
trio_string_terminate
TRIO_ARGS1((self),
	   trio_string_t *self)
1522
{
1523
  trio_xstring_append_char(self, 0);
1524 1525 1526
}


1527
#if !defined(TRIO_MINIMAL)
1528 1529
/**
   Append the second string to the first.
1530

1531 1532 1533 1534
   @param self Dynamic string to be modified.
   @param other Dynamic string to copy from.
   @return Boolean value indicating success or failure.
*/
1535 1536 1537 1538 1539
TRIO_STRING_PUBLIC int
trio_string_append
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
1540 1541
{
  size_t length;
1542

1543 1544 1545 1546 1547 1548 1549 1550 1551
  assert(self);
  assert(other);

  length = self->length + other->length;
  if (!TrioStringGrowTo(self, length))
    goto error;
  trio_copy(&self->content[self->length], other->content);
  self->length = length;
  return TRUE;
1552

1553 1554 1555
 error:
  return FALSE;
}
1556
#endif /* !defined(TRIO_MINIMAL) */
1557 1558


1559
#if !defined(TRIO_MINIMAL)
1560 1561 1562
/*
 * trio_xstring_append
 */
1563 1564 1565 1566 1567
TRIO_STRING_PUBLIC int
trio_xstring_append
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
1568 1569
{
  size_t length;
1570

1571 1572 1573 1574 1575 1576 1577 1578 1579
  assert(self);
  assert(other);

  length = self->length + trio_length(other);
  if (!TrioStringGrowTo(self, length))
    goto error;
  trio_copy(&self->content[self->length], other);
  self->length = length;
  return TRUE;
1580

1581 1582 1583
 error:
  return FALSE;
}
1584
#endif /* !defined(TRIO_MINIMAL) */
1585 1586 1587 1588 1589


/*
 * trio_xstring_append_char
 */
1590 1591 1592 1593 1594
TRIO_STRING_PUBLIC int
trio_xstring_append_char
TRIO_ARGS2((self, character),
	   trio_string_t *self,
	   char character)
1595 1596 1597
{
  assert(self);

1598
  if ((int)self->length >= trio_string_size(self))
1599 1600 1601 1602 1603 1604 1605
    {
      if (!TrioStringGrow(self, 0))
	goto error;
    }
  self->content[self->length] = character;
  self->length++;
  return TRUE;
1606

1607 1608 1609 1610 1611
 error:
  return FALSE;
}


1612
#if !defined(TRIO_MINIMAL)
1613 1614
/**
   Search for the first occurrence of second parameter in the first.
1615

1616 1617 1618 1619
   @param self Dynamic string to be modified.
   @param other Dynamic string to copy from.
   @return Boolean value indicating success or failure.
*/
1620 1621 1622 1623 1624
TRIO_STRING_PUBLIC int
trio_string_contains
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
1625 1626 1627 1628 1629 1630
{
  assert(self);
  assert(other);

  return trio_contains(self->content, other->content);
}
1631
#endif /* !defined(TRIO_MINIMAL) */
1632 1633


1634
#if !defined(TRIO_MINIMAL)
1635 1636 1637
/*
 * trio_xstring_contains
 */
1638 1639 1640 1641 1642
TRIO_STRING_PUBLIC int
trio_xstring_contains
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
1643 1644 1645 1646 1647 1648
{
  assert(self);
  assert(other);

  return trio_contains(self->content, other);
}
1649
#endif /* !defined(TRIO_MINIMAL) */
1650 1651


1652
#if !defined(TRIO_MINIMAL)
1653 1654 1655
/*
 * trio_string_copy
 */
1656 1657 1658 1659 1660
TRIO_STRING_PUBLIC int
trio_string_copy
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
1661 1662 1663 1664 1665 1666 1667
{
  assert(self);
  assert(other);

  self->length = 0;
  return trio_string_append(self, other);
}
1668
#endif /* !defined(TRIO_MINIMAL) */
1669 1670


1671
#if !defined(TRIO_MINIMAL)
1672 1673 1674
/*
 * trio_xstring_copy
 */
1675 1676 1677 1678 1679
TRIO_STRING_PUBLIC int
trio_xstring_copy
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
1680 1681 1682 1683 1684 1685 1686
{
  assert(self);
  assert(other);

  self->length = 0;
  return trio_xstring_append(self, other);
}
1687
#endif /* !defined(TRIO_MINIMAL) */
1688 1689


1690
#if !defined(TRIO_MINIMAL)
1691 1692 1693
/*
 * trio_string_duplicate
 */
1694 1695 1696 1697
TRIO_STRING_PUBLIC trio_string_t *
trio_string_duplicate
TRIO_ARGS1((other),
	   trio_string_t *other)
1698 1699
{
  trio_string_t *self;
1700

1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718
  assert(other);

  self = TrioStringAlloc();
  if (self)
    {
      self->content = TrioDuplicateMax(other->content, other->length);
      if (self->content)
	{
	  self->length = other->length;
	  self->allocated = self->length + 1;
	}
      else
	{
	  self->length = self->allocated = 0;
	}
    }
  return self;
}
1719
#endif /* !defined(TRIO_MINIMAL) */
1720 1721 1722 1723 1724


/*
 * trio_xstring_duplicate
 */
1725 1726 1727 1728
TRIO_STRING_PUBLIC trio_string_t *
trio_xstring_duplicate
TRIO_ARGS1((other),
	   TRIO_CONST char *other)
1729 1730
{
  trio_string_t *self;
1731

1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
  assert(other);

  self = TrioStringAlloc();
  if (self)
    {
      self->content = TrioDuplicateMax(other, trio_length(other));
      if (self->content)
	{
	  self->length = trio_length(self->content);
	  self->allocated = self->length + 1;
	}
      else
	{
	  self->length = self->allocated = 0;
	}
    }
  return self;
}


1752
#if !defined(TRIO_MINIMAL)
1753 1754 1755
/*
 * trio_string_equal
 */
1756 1757 1758 1759 1760
TRIO_STRING_PUBLIC int
trio_string_equal
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
1761 1762 1763 1764 1765 1766
{
  assert(self);
  assert(other);

  return trio_equal(self->content, other->content);
}
1767
#endif /* !defined(TRIO_MINIMAL) */
1768 1769


1770
#if !defined(TRIO_MINIMAL)
1771 1772 1773
/*
 * trio_xstring_equal
 */
1774 1775 1776 1777 1778
TRIO_STRING_PUBLIC int
trio_xstring_equal
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
1779 1780 1781 1782 1783 1784
{
  assert(self);
  assert(other);

  return trio_equal(self->content, other);
}
1785
#endif /* !defined(TRIO_MINIMAL) */
1786 1787


1788
#if !defined(TRIO_MINIMAL)
1789 1790 1791
/*
 * trio_string_equal_max
 */
1792 1793 1794 1795 1796 1797
TRIO_STRING_PUBLIC int
trio_string_equal_max
TRIO_ARGS3((self, max, other),
	   trio_string_t *self,
	   size_t max,
	   trio_string_t *other)
1798 1799 1800