summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2010-10-29 18:37:43 -0400
committerColin Walters <walters@verbum.org>2010-12-02 09:14:06 -0500
commitaa8b7d2d0f586976ea7399d95e1ccce3000b4734 (patch)
treec775426885ef784d29161c306096a30be21a3591
parent1113955bb6a5276c21771685dd30c51f9ef1661f (diff)
downloadgobject-introspection-aa8b7d2d0f586976ea7399d95e1ccce3000b4734.tar.gz
Support hexadecimal escapes in constants
g_strcompress() only does some of what we need; fork it and add support for \x escapes too. https://bugzilla.gnome.org/show_bug.cgi?id=595773
-rw-r--r--giscanner/scannerparser.y83
-rw-r--r--tests/scanner/Regress-1.0-expected.gir3
-rw-r--r--tests/scanner/regress.h2
3 files changed, 86 insertions, 2 deletions
diff --git a/giscanner/scannerparser.y b/giscanner/scannerparser.y
index d32bbcc8..bac20980 100644
--- a/giscanner/scannerparser.y
+++ b/giscanner/scannerparser.y
@@ -49,6 +49,85 @@ extern void ctype_free (GISourceType * type);
static int last_enum_value = -1;
static gboolean is_bitfield;
static GHashTable *const_table = NULL;
+
+/**
+ * parse_c_string_literal:
+ * @str: A string containing a C string literal
+ *
+ * Based on g_strcompress(), but also handles
+ * hexadecimal escapes.
+ */
+static char *
+parse_c_string_literal (const char *str)
+{
+ const gchar *p = str, *num;
+ gchar *dest = g_malloc (strlen (str) + 1);
+ gchar *q = dest;
+
+ while (*p)
+ {
+ if (*p == '\\')
+ {
+ p++;
+ switch (*p)
+ {
+ case '\0':
+ g_warning ("parse_c_string_literal: trailing \\");
+ goto out;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ *q = 0;
+ num = p;
+ while ((p < num + 3) && (*p >= '0') && (*p <= '7'))
+ {
+ *q = (*q * 8) + (*p - '0');
+ p++;
+ }
+ q++;
+ p--;
+ break;
+ case 'x':
+ *q = 0;
+ p++;
+ num = p;
+ while ((p < num + 2) && (g_ascii_isxdigit(*p)))
+ {
+ *q = (*q * 16) + g_ascii_xdigit_value(*p);
+ p++;
+ }
+ q++;
+ p--;
+ break;
+ case 'b':
+ *q++ = '\b';
+ break;
+ case 'f':
+ *q++ = '\f';
+ break;
+ case 'n':
+ *q++ = '\n';
+ break;
+ case 'r':
+ *q++ = '\r';
+ break;
+ case 't':
+ *q++ = '\t';
+ break;
+ default: /* Also handles \" and \\ */
+ *q++ = *p;
+ break;
+ }
+ }
+ else
+ *q++ = *p;
+ p++;
+ }
+out:
+ *q = 0;
+
+ return dest;
+}
+
%}
%error-verbose
@@ -186,7 +265,7 @@ strings
{
$$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST, lineno);
yytext[strlen (yytext) - 1] = '\0';
- $$->const_string = g_strcompress (yytext + 1);
+ $$->const_string = parse_c_string_literal (yytext + 1);
if (!g_utf8_validate ($$->const_string, -1, NULL))
{
#if 0
@@ -202,7 +281,7 @@ strings
char *strings, *string2;
$$ = $1;
yytext[strlen (yytext) - 1] = '\0';
- string2 = g_strcompress (yytext + 1);
+ string2 = parse_c_string_literal (yytext + 1);
strings = g_strconcat ($$->const_string, string2, NULL);
g_free ($$->const_string);
g_free (string2);
diff --git a/tests/scanner/Regress-1.0-expected.gir b/tests/scanner/Regress-1.0-expected.gir
index 15fba0d8..c0590d7e 100644
--- a/tests/scanner/Regress-1.0-expected.gir
+++ b/tests/scanner/Regress-1.0-expected.gir
@@ -943,6 +943,9 @@ TpAccount::status-changed</doc>
<type name="GObject.ObjectClass" c:type="GObjectClass"/>
</field>
</record>
+ <constant name="UTF8_CONSTANT" value="const ♥ utf8">
+ <type name="utf8" c:type="gchar*"/>
+ </constant>
<record name="_TestStructC" c:type="_RegressTestStructC">
<field name="another_int" writable="1">
<type name="gint" c:type="gint"/>
diff --git a/tests/scanner/regress.h b/tests/scanner/regress.h
index 9daf1798..a7342a9b 100644
--- a/tests/scanner/regress.h
+++ b/tests/scanner/regress.h
@@ -579,4 +579,6 @@ typedef enum {
REGRESS_TEST_PUBLIC_ENUM_AFTER = 1 << 2,
} RegressTestPrivateEnum;
+#define REGRESS_UTF8_CONSTANT "const \xe2\x99\xa5 utf8"
+
#endif /* __GITESTTYPES_H__ */