gtk2/gtk/gtkistringprivate.h
Christian Hergert a4512a4c95 istring: fix istring_prepend() on malloc transition
When transitioning from internal to malloc, the strings were placed in
the wrong order to g_strconcat(). This fixes an issue with undo where
if you hit the boundary in just the right way, your undo stack will do
unexpected things.

Fixes #5506
2023-03-01 00:53:03 +02:00

172 lines
3.5 KiB
C

#ifndef __GTK_ISTRING_PRIVATE_H__
#define __GTK_ISTRING_PRIVATE_H__
#include <glib.h>
#include <string.h>
typedef struct
{
guint n_bytes;
guint n_chars;
union {
char buf[24];
char *str;
} u;
} IString;
static inline gboolean
istring_is_inline (const IString *str)
{
return str->n_bytes <= (sizeof str->u.buf - 1);
}
static inline char *
istring_str (IString *str)
{
if (istring_is_inline (str))
return str->u.buf;
else
return str->u.str;
}
static inline void
istring_clear (IString *str)
{
if (istring_is_inline (str))
str->u.buf[0] = 0;
else
g_clear_pointer (&str->u.str, g_free);
str->n_bytes = 0;
str->n_chars = 0;
}
static inline void
istring_set (IString *str,
const char *text,
guint n_bytes,
guint n_chars)
{
if G_LIKELY (n_bytes <= (sizeof str->u.buf - 1))
{
memcpy (str->u.buf, text, n_bytes);
str->u.buf[n_bytes] = 0;
}
else
{
str->u.str = g_strndup (text, n_bytes);
}
str->n_bytes = n_bytes;
str->n_chars = n_chars;
}
static inline gboolean
istring_empty (IString *str)
{
return str->n_bytes == 0;
}
static inline gboolean
istring_ends_with_space (IString *str)
{
return g_ascii_isspace (istring_str (str)[str->n_bytes - 1]);
}
static inline gboolean
istring_starts_with_space (IString *str)
{
return g_unichar_isspace (g_utf8_get_char (istring_str (str)));
}
static inline gboolean
istring_contains_unichar (IString *str,
gunichar ch)
{
return g_utf8_strchr (istring_str (str), str->n_bytes, ch) != NULL;
}
static inline gboolean
istring_only_contains_space (IString *str)
{
const char *iter;
for (iter = istring_str (str); *iter; iter = g_utf8_next_char (iter))
{
if (!g_unichar_isspace (g_utf8_get_char (iter)))
return FALSE;
}
return TRUE;
}
static inline gboolean
istring_contains_space (IString *str)
{
const char *iter;
for (iter = istring_str (str); *iter; iter = g_utf8_next_char (iter))
{
if (g_unichar_isspace (g_utf8_get_char (iter)))
return TRUE;
}
return FALSE;
}
static inline void
istring_prepend (IString *str,
IString *other)
{
if G_LIKELY (str->n_bytes + other->n_bytes < sizeof str->u.buf - 1)
{
memmove (str->u.buf + other->n_bytes, str->u.buf, str->n_bytes);
memcpy (str->u.buf, other->u.buf, other->n_bytes);
str->n_bytes += other->n_bytes;
str->n_chars += other->n_chars;
str->u.buf[str->n_bytes] = 0;
}
else
{
char *old = NULL;
if (!istring_is_inline (str))
old = str->u.str;
str->u.str = g_strconcat (istring_str (other), istring_str (str), NULL);
str->n_bytes += other->n_bytes;
str->n_chars += other->n_chars;
g_free (old);
}
}
static inline void
istring_append (IString *str,
IString *other)
{
const char *text = istring_str (other);
guint n_bytes = other->n_bytes;
guint n_chars = other->n_chars;
if G_LIKELY (istring_is_inline (str))
{
if G_LIKELY (str->n_bytes + n_bytes <= (sizeof str->u.buf - 1))
memcpy (str->u.buf + str->n_bytes, text, n_bytes);
else
str->u.str = g_strconcat (str->u.buf, text, NULL);
}
else
{
str->u.str = g_realloc (str->u.str, str->n_bytes + n_bytes + 1);
memcpy (str->u.str + str->n_bytes, text, n_bytes);
}
str->n_bytes += n_bytes;
str->n_chars += n_chars;
istring_str (str)[str->n_bytes] = 0;
}
#endif /* __GTK_ISTRING_PRIVATE_H__ */