*/
#define G_N_ELEMENTS(s) (sizeof(s) / sizeof ((s) [0]))
+// e.g. strncmp (foo, G_STRING_CONSTANT_AND_LENGTH ("version"))
+#define G_STRING_CONSTANT_AND_LENGTH(x) (x), G_N_ELEMENTS (x) - 1
+
#define FALSE 0
#define TRUE 1
gchar g_ascii_tolower (gchar c);
gchar g_ascii_toupper (gchar c);
gchar *g_ascii_strdown (const gchar *str, gssize len);
+void g_ascii_strdown_no_alloc (char* dst, const char* src, gsize len);
gchar *g_ascii_strup (const gchar *str, gssize len);
gint g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n);
gint g_ascii_strcasecmp (const gchar *s1, const gchar *s2);
return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
}
+void
+g_ascii_strdown_no_alloc (char* dst, const char* src, gsize len)
+{
+ // dst can equal src. no_alloc means this function does no
+ // allocation; caller may very well.
+
+ for (gsize i = 0; i < len; ++i)
+ dst [i] = g_ascii_tolower (src [i]);
+}
+
gchar *
g_ascii_strdown (const gchar *str, gssize len)
{
char *ret;
- int i;
g_return_val_if_fail (str != NULL, NULL);
len = strlen (str);
ret = g_malloc (len + 1);
- for (i = 0; i < len; i++)
- ret [i] = (guchar) g_ascii_tolower (str [i]);
- ret [i] = 0;
+ g_ascii_strdown_no_alloc (ret, str, len);
+ ret [len] = 0;
return ret;
}
ret = g_malloc (len + 1);
for (i = 0; i < len; i++)
- ret [i] = (guchar) g_ascii_toupper (str [i]);
+ ret [i] = g_ascii_toupper (str [i]);
ret [i] = 0;
return ret;
}
+static
+int
+g_ascii_charcmp (char c1, char c2)
+{
+ // Do not subtract, to avoid overflow.
+ // Use unsigned to mimic strcmp, and so
+ // shorter strings compare as less.
+
+ const guchar u1 = (guchar)c1;
+ const guchar u2 = (guchar)c2;
+ return (u1 < u2) ? -1 : (u1 > u2) ? 1 : 0;
+}
+
+static
+int
+g_ascii_charcasecmp (char c1, char c2)
+{
+ return g_ascii_charcmp (g_ascii_tolower (c1), g_ascii_tolower (c2));
+}
+
gint
g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
{
+ // Unlike strncmp etc. this function does not stop at nul,
+ // unless there is a mismatch.
+
+ if (s1 == s2)
+ return 0;
+
gsize i;
-
+
g_return_val_if_fail (s1 != NULL, 0);
g_return_val_if_fail (s2 != NULL, 0);
for (i = 0; i < n; i++) {
- gchar c1 = g_ascii_tolower (*s1++);
- gchar c2 = g_ascii_tolower (*s2++);
-
- if (c1 != c2)
- return c1 - c2;
+ const int j = g_ascii_charcasecmp (*s1++, *s2++);
+ if (j)
+ return j;
}
return 0;
gint
g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
{
- const char *sp1 = s1;
- const char *sp2 = s2;
-
+ if (s1 == s2)
+ return 0;
+
g_return_val_if_fail (s1 != NULL, 0);
g_return_val_if_fail (s2 != NULL, 0);
-
- while (*sp1 != '\0') {
- char c1 = g_ascii_tolower (*sp1++);
- char c2 = g_ascii_tolower (*sp2++);
-
- if (c1 != c2)
- return c1 - c2;
+
+ char c1;
+
+ while ((c1 = *s1)) {
+ ++s1;
+ const int j = g_ascii_charcasecmp (c1, *s2++);
+ if (j)
+ return j;
}
-
- return (*sp1) - (*sp2);
+
+ return g_ascii_charcmp (0, *s2);
}
gboolean