diff options
Diffstat (limited to 'eel/eel-string.c')
-rw-r--r-- | eel/eel-string.c | 1275 |
1 files changed, 1275 insertions, 0 deletions
diff --git a/eel/eel-string.c b/eel/eel-string.c new file mode 100644 index 00000000..f554b91c --- /dev/null +++ b/eel/eel-string.c @@ -0,0 +1,1275 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + + eel-string.c: String routines to augment <string.h>. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Darin Adler <[email protected]> +*/ + +#include <config.h> +#include "eel-string.h" + +#include <errno.h> +#include <locale.h> +#include <stdlib.h> +#include <string.h> +#include <eel-glib-extensions.h> + +#if !defined (EEL_OMIT_SELF_CHECK) +#include "eel-lib-self-check-functions.h" +#endif + +size_t +eel_strlen (const char *string) +{ + return string == NULL ? 0 : strlen (string); +} + +char * +eel_strchr (const char *haystack, char needle) +{ + return haystack == NULL ? NULL : strchr (haystack, needle); +} + +int +eel_strcmp (const char *string_a, const char *string_b) +{ + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL < ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + return strcmp (string_a == NULL ? "" : string_a, + string_b == NULL ? "" : string_b); +} + +int +eel_strcasecmp (const char *string_a, const char *string_b) +{ + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL < ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + return g_ascii_strcasecmp (string_a == NULL ? "" : string_a, + string_b == NULL ? "" : string_b); +} + +int +eel_strcmp_case_breaks_ties (const char *string_a, const char *string_b) +{ + int casecmp_result; + + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL < ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + casecmp_result = eel_strcasecmp (string_a, string_b); + if (casecmp_result != 0) + { + return casecmp_result; + } + return eel_strcmp (string_a, string_b); +} + +gboolean +eel_str_is_empty (const char *string_or_null) +{ + return eel_strcmp (string_or_null, NULL) == 0; +} + +gboolean +eel_str_is_equal (const char *string_a, const char *string_b) +{ + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL != ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + return eel_strcmp (string_a, string_b) == 0; +} + +gboolean +eel_istr_is_equal (const char *string_a, const char *string_b) +{ + /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this + * treat 'NULL != ""', or have a flavor that does that. If we + * didn't have code that already relies on 'NULL == ""', I + * would change it right now. + */ + return eel_strcasecmp (string_a, string_b) == 0; +} + +gboolean +eel_str_has_prefix (const char *haystack, const char *needle) +{ + return g_str_has_prefix (haystack == NULL ? "" : haystack, + needle == NULL ? "" : needle); +} + +gboolean +eel_str_has_suffix (const char *haystack, const char *needle) +{ + if (needle == NULL) + { + return TRUE; + } + if (haystack == NULL) + { + return needle[0] == '\0'; + } + + return g_str_has_suffix (haystack, needle); +} + +gboolean +eel_istr_has_prefix (const char *haystack, const char *needle) +{ + const char *h, *n; + char hc, nc; + + /* Eat one character at a time. */ + h = haystack == NULL ? "" : haystack; + n = needle == NULL ? "" : needle; + do + { + if (*n == '\0') + { + return TRUE; + } + if (*h == '\0') + { + return FALSE; + } + hc = *h++; + nc = *n++; + hc = g_ascii_tolower (hc); + nc = g_ascii_tolower (nc); + } + while (hc == nc); + return FALSE; +} + +gboolean +eel_istr_has_suffix (const char *haystack, const char *needle) +{ + const char *h, *n; + char hc, nc; + + if (needle == NULL) + { + return TRUE; + } + if (haystack == NULL) + { + return needle[0] == '\0'; + } + + /* Eat one character at a time. */ + h = haystack + strlen (haystack); + n = needle + strlen (needle); + do + { + if (n == needle) + { + return TRUE; + } + if (h == haystack) + { + return FALSE; + } + hc = *--h; + nc = *--n; + hc = g_ascii_tolower (hc); + nc = g_ascii_tolower (nc); + } + while (hc == nc); + return FALSE; +} + +/** + * eel_str_get_prefix: + * Get a new string containing the first part of an existing string. + * + * @source: The string whose prefix should be extracted. + * @delimiter: The string that marks the end of the prefix. + * + * Return value: A newly-allocated string that that matches the first part + * of @source, up to but not including the first occurrence of + * @delimiter. If @source is NULL, returns NULL. If + * @delimiter is NULL, returns a copy of @source. + * If @delimiter does not occur in @source, returns + * a copy of @source. + **/ +char * +eel_str_get_prefix (const char *source, + const char *delimiter) +{ + char *prefix_start; + + if (source == NULL) + { + return NULL; + } + + if (delimiter == NULL) + { + return g_strdup (source); + } + + prefix_start = strstr (source, delimiter); + + if (prefix_start == NULL) + { + return g_strdup (""); + } + + return g_strndup (source, prefix_start - source); +} + +gboolean +eel_str_to_int (const char *string, int *integer) +{ + long result; + char *parse_end; + + /* Check for the case of an empty string. */ + if (string == NULL || *string == '\0') + { + return FALSE; + } + + /* Call the standard library routine to do the conversion. */ + errno = 0; + result = strtol (string, &parse_end, 0); + + /* Check that the result is in range. */ + if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) + { + return FALSE; + } + if (result < G_MININT || result > G_MAXINT) + { + return FALSE; + } + + /* Check that all the trailing characters are spaces. */ + while (*parse_end != '\0') + { + if (!g_ascii_isspace (*parse_end++)) + { + return FALSE; + } + } + + /* Return the result. */ + *integer = result; + return TRUE; +} + +char * +eel_str_double_underscores (const char *string) +{ + int underscores; + const char *p; + char *q; + char *escaped; + + if (string == NULL) + { + return NULL; + } + + underscores = 0; + for (p = string; *p != '\0'; p++) + { + underscores += (*p == '_'); + } + + if (underscores == 0) + { + return g_strdup (string); + } + + escaped = g_new (char, strlen (string) + underscores + 1); + for (p = string, q = escaped; *p != '\0'; p++, q++) + { + /* Add an extra underscore. */ + if (*p == '_') + { + *q++ = '_'; + } + *q = *p; + } + *q = '\0'; + + return escaped; +} + +char * +eel_str_capitalize (const char *string) +{ + char *capitalized; + + if (string == NULL) + { + return NULL; + } + + capitalized = g_strdup (string); + + capitalized[0] = g_ascii_toupper (capitalized[0]); + + return capitalized; +} + +/* Note: eel_string_ellipsize_* that use a length in pixels + * rather than characters can be found in eel_gdk_extensions.h + * + * FIXME bugzilla.eazel.com 5089: + * we should coordinate the names of eel_string_ellipsize_* + * and eel_str_*_truncate so that they match better and reflect + * their different behavior. + */ +char * +eel_str_middle_truncate (const char *string, + guint truncate_length) +{ + char *truncated; + guint length; + guint num_left_chars; + guint num_right_chars; + + const char delimter[] = "..."; + const guint delimter_length = strlen (delimter); + const guint min_truncate_length = delimter_length + 2; + + if (string == NULL) + { + return NULL; + } + + /* It doesnt make sense to truncate strings to less than + * the size of the delimiter plus 2 characters (one on each + * side) + */ + if (truncate_length < min_truncate_length) + { + return g_strdup (string); + } + + length = g_utf8_strlen (string, -1); + + /* Make sure the string is not already small enough. */ + if (length <= truncate_length) + { + return g_strdup (string); + } + + /* Find the 'middle' where the truncation will occur. */ + num_left_chars = (truncate_length - delimter_length) / 2; + num_right_chars = truncate_length - num_left_chars - delimter_length; + + truncated = g_new (char, strlen (string) + 1); + + g_utf8_strncpy (truncated, string, num_left_chars); + strcat (truncated, delimter); + strcat (truncated, g_utf8_offset_to_pointer (string, length - num_right_chars)); + + return truncated; +} + +char * +eel_str_strip_substring_and_after (const char *string, + const char *substring) +{ + const char *substring_position; + + g_return_val_if_fail (substring != NULL, g_strdup (string)); + g_return_val_if_fail (substring[0] != '\0', g_strdup (string)); + + if (string == NULL) + { + return NULL; + } + + substring_position = strstr (string, substring); + if (substring_position == NULL) + { + return g_strdup (string); + } + + return g_strndup (string, + substring_position - string); +} + +char * +eel_str_replace_substring (const char *string, + const char *substring, + const char *replacement) +{ + int substring_length, replacement_length, result_length, remaining_length; + const char *p, *substring_position; + char *result, *result_position; + + g_return_val_if_fail (substring != NULL, g_strdup (string)); + g_return_val_if_fail (substring[0] != '\0', g_strdup (string)); + + if (string == NULL) + { + return NULL; + } + + substring_length = strlen (substring); + replacement_length = eel_strlen (replacement); + + result_length = strlen (string); + for (p = string; ; p = substring_position + substring_length) + { + substring_position = strstr (p, substring); + if (substring_position == NULL) + { + break; + } + result_length += replacement_length - substring_length; + } + + result = g_malloc (result_length + 1); + + result_position = result; + for (p = string; ; p = substring_position + substring_length) + { + substring_position = strstr (p, substring); + if (substring_position == NULL) + { + remaining_length = strlen (p); + memcpy (result_position, p, remaining_length); + result_position += remaining_length; + break; + } + memcpy (result_position, p, substring_position - p); + result_position += substring_position - p; + memcpy (result_position, replacement, replacement_length); + result_position += replacement_length; + } + g_assert (result_position - result == result_length); + result_position[0] = '\0'; + + return result; +} + +/**************** Custom printf ***********/ + +typedef struct +{ + const char *start; + const char *end; + GString *format; + int arg_pos; + int width_pos; + int width_format_index; + int precision_pos; + int precision_format_index; +} ConversionInfo; + +enum +{ + ARG_TYPE_INVALID, + ARG_TYPE_INT, + ARG_TYPE_LONG, + ARG_TYPE_LONG_LONG, + ARG_TYPE_SIZE, + ARG_TYPE_LONG_DOUBLE, + ARG_TYPE_DOUBLE, + ARG_TYPE_POINTER +}; + +typedef int ArgType; /* An int, because custom are < 0 */ + + +static const char * +get_position (const char *format, int *i) +{ + const char *p; + + p = format; + + if (g_ascii_isdigit (*p)) + { + p++; + + while (g_ascii_isdigit (*p)) + { + p++; + } + + if (*p == '$') + { + if (i != NULL) + { + *i = atoi (format) - 1; + } + return p + 1; + } + } + + return format; +} + +static gboolean +is_flag (char c) +{ + return strchr ("#0- +'I", c) != NULL; +} + +static gboolean +is_length_modifier (char c) +{ + return strchr ("hlLjzt", c) != NULL; +} + + +static ArgType +get_arg_type_from_format (EelPrintfHandler *custom_handlers, + const char *format, + int len) +{ + int i; + char c; + + c = format[len-1]; + + if (custom_handlers != NULL) + { + for (i = 0; custom_handlers[i].character != 0; i++) + { + if (custom_handlers[i].character == c) + { + return -(i + 1); + } + } + } + + switch (c) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (g_str_has_prefix (format, "ll")) + { + return ARG_TYPE_LONG_LONG; + } + if (g_str_has_prefix (format, "l")) + { + return ARG_TYPE_LONG; + } + if (g_str_has_prefix (format, "l")) + { + return ARG_TYPE_LONG; + } + if (g_str_has_prefix (format, "z")) + { + return ARG_TYPE_SIZE; + } + return ARG_TYPE_INT; + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case 'a': + case 'A': + if (g_str_has_prefix (format, "L")) + { + return ARG_TYPE_LONG_DOUBLE; + } + return ARG_TYPE_DOUBLE; + case 'c': + return ARG_TYPE_INT; + case 's': + case 'p': + case 'n': + return ARG_TYPE_POINTER; + } + return ARG_TYPE_INVALID; +} + +static void +skip_argv (va_list *va, + ArgType type, + EelPrintfHandler *custom_handlers) +{ + if (type < 0) + { + custom_handlers[-type - 1].skip (va); + return; + } + + switch (type) + { + default: + case ARG_TYPE_INVALID: + return; + + case ARG_TYPE_INT: + (void) va_arg (*va, int); + break; + case ARG_TYPE_LONG: + (void) va_arg (*va, long int); + break; + case ARG_TYPE_LONG_LONG: + (void) va_arg (*va, long long int); + break; + case ARG_TYPE_SIZE: + (void) va_arg (*va, gsize); + break; + case ARG_TYPE_LONG_DOUBLE: + (void) va_arg (*va, long double); + break; + case ARG_TYPE_DOUBLE: + (void) va_arg (*va, double); + break; + case ARG_TYPE_POINTER: + (void) va_arg (*va, void *); + break; + } +} + +static void +skip_to_arg (va_list *va, + ArgType *types, + EelPrintfHandler *custom_handlers, + int n) +{ + int i; + for (i = 0; i < n; i++) + { + skip_argv (va, types[i], custom_handlers); + } +} + +char * +eel_strdup_vprintf_with_custom (EelPrintfHandler *custom, + const char *format, + va_list va_orig) +{ + va_list va; + const char *p; + int num_args, i, j; + ArgType *args; + ArgType type; + ConversionInfo *conversions; + GString *f, *str; + const char *flags, *width, *prec, *mod, *pos; + char *s; + + num_args = 0; + for (p = format; *p != 0; p++) + { + if (*p == '%') + { + p++; + if (*p != '%') + { + num_args++; + } + } + } + + args = g_new0 (ArgType, num_args * 3 + 1); + conversions = g_new0 (ConversionInfo, num_args); + + /* i indexes conversions, j indexes args */ + i = 0; + j = 0; + p = format; + while (*p != 0) + { + if (*p != '%') + { + p++; + continue; + } + p++; + if (*p == '%') + { + p++; + continue; + } + + /* We got a real conversion: */ + f = g_string_new ("%"); + conversions[i].start = p - 1; + + /* First comes the positional arg */ + + pos = p; + p = get_position (p, NULL); + + /* Then flags */ + flags = p; + while (is_flag (*p)) + { + p++; + } + g_string_append_len (f, flags, p - flags); + + /* Field width */ + + if (*p == '*') + { + p++; + p = get_position (p, &j); + args[j] = ARG_TYPE_INT; + conversions[i].width_pos = j++; + conversions[i].width_format_index = f->len; + } + else + { + conversions[i].width_pos = -1; + conversions[i].width_format_index = -1; + width = p; + while (g_ascii_isdigit (*p)) + { + p++; + } + g_string_append_len (f, width, p - width); + } + + /* Precision */ + conversions[i].precision_pos = -1; + conversions[i].precision_format_index = -1; + if (*p == '.') + { + g_string_append_c (f, '.'); + p++; + + if (*p == '*') + { + p++; + p = get_position (p, &j); + args[j] = ARG_TYPE_INT; + conversions[i].precision_pos = j++; + conversions[i].precision_format_index = f->len; + } + else + { + prec = p; + while (g_ascii_isdigit (*p) || *p == '-') + { + p++; + } + g_string_append_len (f, prec, p - prec); + } + } + + /* length modifier */ + + mod = p; + + while (is_length_modifier (*p)) + { + p++; + } + + /* conversion specifier */ + if (*p != 0) + p++; + + g_string_append_len (f, mod, p - mod); + + get_position (pos, &j); + args[j] = get_arg_type_from_format (custom, mod, p - mod); + conversions[i].arg_pos = j++; + conversions[i].format = f; + conversions[i].end = p; + + i++; + } + + g_assert (i == num_args); + + str = g_string_new (""); + + p = format; + for (i = 0; i < num_args; i++) + { + g_string_append_len (str, p, conversions[i].start - p); + p = conversions[i].end; + + if (conversions[i].precision_pos != -1) + { + char *val; + + G_VA_COPY(va, va_orig); + skip_to_arg (&va, args, custom, conversions[i].precision_pos); + val = g_strdup_vprintf ("%d", va); + va_end (va); + + g_string_insert (conversions[i].format, + conversions[i].precision_format_index, + val); + + g_free (val); + } + + if (conversions[i].width_pos != -1) + { + char *val; + + G_VA_COPY(va, va_orig); + skip_to_arg (&va, args, custom, conversions[i].width_pos); + val = g_strdup_vprintf ("%d", va); + va_end (va); + + g_string_insert (conversions[i].format, + conversions[i].width_format_index, + val); + + g_free (val); + } + + G_VA_COPY(va, va_orig); + skip_to_arg (&va, args, custom, conversions[i].arg_pos); + type = args[conversions[i].arg_pos]; + if (type < 0) + { + s = custom[-type - 1].to_string (conversions[i].format->str, va); + g_string_append (str, s); + g_free (s); + } + else + { + g_string_append_vprintf (str, conversions[i].format->str, va); + } + va_end (va); + + g_string_free (conversions[i].format, TRUE); + } + g_string_append (str, p); + + g_free (args); + g_free (conversions); + + return g_string_free (str, FALSE); +} + +char * +eel_strdup_printf_with_custom (EelPrintfHandler *handlers, + const char *format, + ...) +{ + va_list va; + char *res; + + va_start (va, format); + res = eel_strdup_vprintf_with_custom (handlers, format, va); + va_end (va); + + return res; +} + +/*********** refcounted strings ****************/ + +G_LOCK_DEFINE_STATIC (unique_ref_strs); +static GHashTable *unique_ref_strs = NULL; + +static eel_ref_str +eel_ref_str_new_internal (const char *string, int start_count) +{ + char *res; + volatile gint *count; + gsize len; + + len = strlen (string); + res = g_malloc (sizeof (gint) + len + 1); + count = (volatile gint *)res; + *count = start_count; + res += sizeof(gint); + memcpy (res, string, len + 1); + return res; +} + +eel_ref_str +eel_ref_str_new (const char *string) +{ + if (string == NULL) + { + return NULL; + } + + return eel_ref_str_new_internal (string, 1); +} + +eel_ref_str +eel_ref_str_get_unique (const char *string) +{ + eel_ref_str res; + + if (string == NULL) + { + return NULL; + } + + G_LOCK (unique_ref_strs); + if (unique_ref_strs == NULL) + { + unique_ref_strs = + eel_g_hash_table_new_free_at_exit (g_str_hash, g_str_equal, + "unique eel_ref_str"); + } + + res = g_hash_table_lookup (unique_ref_strs, string); + if (res != NULL) + { + eel_ref_str_ref (res); + } + else + { + res = eel_ref_str_new_internal (string, 0x80000001); + g_hash_table_insert (unique_ref_strs, res, res); + } + + G_UNLOCK (unique_ref_strs); + + return res; +} + +eel_ref_str +eel_ref_str_ref (eel_ref_str str) +{ + volatile gint *count; + + count = (volatile gint *)((char *)str - sizeof (gint)); + g_atomic_int_add (count, 1); + + return str; +} + +void +eel_ref_str_unref (eel_ref_str str) +{ + volatile gint *count; + gint old_ref; + + if (str == NULL) + return; + + count = (volatile gint *)((char *)str - sizeof (gint)); + +retry_atomic_decrement: + old_ref = g_atomic_int_get (count); + if (old_ref == 1) + { + g_free ((char *)count); + } + else if (old_ref == 0x80000001) + { + G_LOCK (unique_ref_strs); + /* Need to recheck after taking lock to avoid races with _get_unique() */ + if (g_atomic_int_exchange_and_add (count, -1) == 0x80000001) + { + g_hash_table_remove (unique_ref_strs, (char *)str); + g_free ((char *)count); + } + G_UNLOCK (unique_ref_strs); + } + else if (!g_atomic_int_compare_and_exchange (count, + old_ref, old_ref - 1)) + { + goto retry_atomic_decrement; + } +} + + +#if !defined (EEL_OMIT_SELF_CHECK) + +static int +call_str_to_int (const char *string) +{ + int integer; + + integer = 9999; + eel_str_to_int (string, &integer); + return integer; +} + +static void +verify_printf (const char *format, ...) +{ + va_list va; + char *orig, *new; + + va_start (va, format); + orig = g_strdup_vprintf (format, va); + va_end (va); + + va_start (va, format); + new = eel_strdup_vprintf_with_custom (NULL, format, va); + va_end (va); + + EEL_CHECK_STRING_RESULT (new, orig); + + g_free (orig); +} + +static char * +custom1_to_string (char *format, va_list va) +{ + int i; + + i = va_arg (va, int); + + return g_strdup_printf ("c1-%d-", i); +} + +static void +custom1_skip (va_list *va) +{ + (void) va_arg (*va, int); +} + +static char * +custom2_to_string (char *format, va_list va) +{ + char *s; + + s = va_arg (va, char *); + + return g_strdup_printf ("c2-%s-", s); +} + +static void +custom2_skip (va_list *va) +{ + (void) va_arg (*va, char *); +} + +static EelPrintfHandler handlers[] = +{ + { 'N', custom1_to_string, custom1_skip }, + { 'Y', custom2_to_string, custom2_skip }, + { 0 } +}; + +static void +verify_custom (const char *orig, const char *format, ...) +{ + char *new; + va_list va; + + va_start (va, format); + new = eel_strdup_vprintf_with_custom (handlers, format, va); + va_end (va); + + EEL_CHECK_STRING_RESULT (new, orig); +} + +void +eel_self_check_string (void) +{ + int integer; + + EEL_CHECK_INTEGER_RESULT (eel_strlen (NULL), 0); + EEL_CHECK_INTEGER_RESULT (eel_strlen (""), 0); + EEL_CHECK_INTEGER_RESULT (eel_strlen ("abc"), 3); + + EEL_CHECK_INTEGER_RESULT (eel_strcmp (NULL, NULL), 0); + EEL_CHECK_INTEGER_RESULT (eel_strcmp (NULL, ""), 0); + EEL_CHECK_INTEGER_RESULT (eel_strcmp ("", NULL), 0); + EEL_CHECK_INTEGER_RESULT (eel_strcmp ("a", "a"), 0); + EEL_CHECK_INTEGER_RESULT (eel_strcmp ("aaab", "aaab"), 0); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp (NULL, "a") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", NULL) > 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("", "a") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", "") > 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", "b") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", "ab") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("ab", "a") > 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("aaa", "aaab") < 0, TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("aaab", "aaa") > 0, TRUE); + + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix (NULL, NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix (NULL, ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", "a"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("aaab", "aaab"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix (NULL, "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("", "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", "b"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", "ab"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("ab", "a"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("aaa", "aaab"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("aaab", "aaa"), TRUE); + + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix (NULL, NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix (NULL, ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("", "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", "a"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("aaab", "aaab"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix (NULL, "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("", "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", "b"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("a", "ab"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("ab", "a"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("ab", "b"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("aaa", "baaa"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_has_suffix ("baaa", "aaa"), TRUE); + + EEL_CHECK_STRING_RESULT (eel_str_get_prefix (NULL, NULL), NULL); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix (NULL, "foo"), NULL); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo", NULL), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("", ""), ""); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("", "foo"), ""); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo", ""), ""); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo", "foo"), ""); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo:", ":"), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo:bar", ":"), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("footle:bar", "tle:"), "foo"); + + EEL_CHECK_STRING_RESULT (eel_str_double_underscores (NULL), NULL); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores (""), ""); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("_"), "__"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo"), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_bar"), "foo__bar"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_bar_2"), "foo__bar__2"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("_foo"), "__foo"); + EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_"), "foo__"); + + EEL_CHECK_STRING_RESULT (eel_str_capitalize (NULL), NULL); + EEL_CHECK_STRING_RESULT (eel_str_capitalize (""), ""); + EEL_CHECK_STRING_RESULT (eel_str_capitalize ("foo"), "Foo"); + EEL_CHECK_STRING_RESULT (eel_str_capitalize ("Foo"), "Foo"); + + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 0), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 1), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 3), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 4), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 5), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 6), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 7), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 0), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 1), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 2), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 3), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 4), "a_much_longer_foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 5), "a...o"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 6), "a...oo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 7), "a_...oo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 8), "a_...foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 9), "a_m...foo"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 8), "so...ven"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 8), "so...odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 9), "som...ven"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 9), "som...odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 10), "som...even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 10), "som..._odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 11), "some...even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 11), "some..._odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 12), "some..._even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 12), "some...g_odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 13), "somet..._even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 13), "something_odd"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 14), "something_even"); + EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 13), "something_odd"); + +#define TEST_INTEGER_CONVERSION_FUNCTIONS(string, boolean_result, integer_result) \ + EEL_CHECK_BOOLEAN_RESULT (eel_str_to_int (string, &integer), boolean_result); \ + EEL_CHECK_INTEGER_RESULT (call_str_to_int (string), integer_result); + + TEST_INTEGER_CONVERSION_FUNCTIONS (NULL, FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("a", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS (".", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("0", TRUE, 0) + TEST_INTEGER_CONVERSION_FUNCTIONS ("1", TRUE, 1) + TEST_INTEGER_CONVERSION_FUNCTIONS ("+1", TRUE, 1) + TEST_INTEGER_CONVERSION_FUNCTIONS ("-1", TRUE, -1) + TEST_INTEGER_CONVERSION_FUNCTIONS ("2147483647", TRUE, 2147483647) + TEST_INTEGER_CONVERSION_FUNCTIONS ("2147483648", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("+2147483647", TRUE, 2147483647) + TEST_INTEGER_CONVERSION_FUNCTIONS ("+2147483648", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("-2147483648", TRUE, INT_MIN) + TEST_INTEGER_CONVERSION_FUNCTIONS ("-2147483649", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("1a", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("0.0", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("1e1", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("21474836470", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("+21474836470", FALSE, 9999) + TEST_INTEGER_CONVERSION_FUNCTIONS ("-21474836480", FALSE, 9999) + + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal (NULL, NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal (NULL, ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("foo", "foo"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_str_is_equal ("foo", "bar"), FALSE); + + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal (NULL, NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal (NULL, ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("", NULL), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("", ""), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("foo", "foo"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("foo", "bar"), FALSE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("Foo", "foo"), TRUE); + EEL_CHECK_BOOLEAN_RESULT (eel_istr_is_equal ("foo", "Foo"), TRUE); + + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after (NULL, "bar"), NULL); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("", "bar"), ""); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo", "bar"), "foo"); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo bar", "bar"), "foo "); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo bar xxx", "bar"), "foo "); + EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("bar", "bar"), ""); + + EEL_CHECK_STRING_RESULT (eel_str_replace_substring (NULL, "foo", NULL), NULL); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring (NULL, "foo", "bar"), NULL); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("bar", "foo", NULL), "bar"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("", "foo", ""), ""); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("", "foo", "bar"), ""); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("bar", "foo", ""), "bar"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("xxx", "x", "foo"), "foofoofoo"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("fff", "f", "foo"), "foofoofoo"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("foofoofoo", "foo", "f"), "fff"); + EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("foofoofoo", "f", ""), "oooooo"); + + verify_printf ("%.*s", 2, "foo"); + verify_printf ("%*.*s", 2, 4, "foo"); + verify_printf ("before %5$*1$.*2$s between %6$*3$.*4$d after", + 4, 5, 6, 7, "foo", G_PI); + verify_custom ("c1-42- c2-foo-","%N %Y", 42 ,"foo"); + verify_custom ("c1-42- bar c2-foo-","%N %s %Y", 42, "bar" ,"foo"); + verify_custom ("c1-42- bar c2-foo-","%3$N %2$s %1$Y","foo", "bar", 42); + +} + +#endif /* !EEL_OMIT_SELF_CHECK */ |