gboolean _gtk_css_parser_try_int (GtkCssParser *parser, int *value) { gint64 result; char *end; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE); g_return_val_if_fail (value != NULL, FALSE); /* strtoll parses a plus, but we are not allowed to */ if (*parser->data == '+') return FALSE; errno = 0; result = g_ascii_strtoll (parser->data, &end, 10); if (errno) return FALSE; if (result > G_MAXINT || result < G_MININT) return FALSE; if (parser->data == end) return FALSE; parser->data = end; *value = result; _gtk_css_parser_skip_whitespace (parser); return TRUE; }
gboolean _gtk_css_parser_is_string (GtkCssParser *parser) { g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE); return *parser->data == '"' || *parser->data == '\''; }
char * _gtk_css_parser_read_string (GtkCssParser *parser) { GString *str; char quote; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL); quote = *parser->data; if (quote != '"' && quote != '\'') { _gtk_css_parser_error (parser, "Expected a string."); return NULL; } parser->data++; str = g_string_new (NULL); while (TRUE) { gsize len = strcspn (parser->data, "\\'\"\n\r\f"); g_string_append_len (str, parser->data, len); parser->data += len; switch (*parser->data) { case '\\': _gtk_css_parser_unescape (parser, str); break; case '"': case '\'': if (*parser->data == quote) { parser->data++; _gtk_css_parser_skip_whitespace (parser); return g_string_free (str, FALSE); } g_string_append_c (str, *parser->data); parser->data++; break; case '\0': /* FIXME: position */ _gtk_css_parser_error (parser, "Missing end quote in string."); g_string_free (str, TRUE); return NULL; default: _gtk_css_parser_error (parser, "Invalid character in string. Must be escaped."); g_string_free (str, TRUE); return NULL; } } g_assert_not_reached (); return NULL; }
guint _gtk_css_parser_get_position (GtkCssParser *parser) { g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), 1); return parser->data - parser->line_start; }
char * _gtk_css_parser_try_ident (GtkCssParser *parser, gboolean skip_whitespace) { const char *start; GString *ident; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL); start = parser->data; ident = g_string_new (NULL); if (*parser->data == '-') { g_string_append_c (ident, '-'); parser->data++; } if (!_gtk_css_parser_read_char (parser, ident, NMSTART)) { parser->data = start; g_string_free (ident, TRUE); return NULL; } while (_gtk_css_parser_read_char (parser, ident, NMCHAR)) ; if (skip_whitespace) _gtk_css_parser_skip_whitespace (parser); return g_string_free (ident, FALSE); }
guint _gtk_css_parser_get_line (GtkCssParser *parser) { g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), 1); return parser->line; }
char * _gtk_css_parser_read_value (GtkCssParser *parser) { const char *start; char *result; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL); start = parser->data; /* This needs to be done better */ _gtk_css_parser_resync_internal (parser, TRUE, FALSE, '}'); result = g_strndup (start, parser->data - start); if (result) { g_strchomp (result); if (result[0] == 0) { g_free (result); result = NULL; } } if (result == NULL) _gtk_css_parser_error (parser, "Expected a property value"); return result; }
void _gtk_css_parser_free (GtkCssParser *parser) { g_return_if_fail (GTK_IS_CSS_PARSER (parser)); g_slice_free (GtkCssParser, parser); }
gboolean _gtk_css_parser_is_eof (GtkCssParser *parser) { g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), TRUE); return *parser->data == 0; }
gboolean _gtk_css_parser_try_uint (GtkCssParser *parser, guint *value) { guint64 result; char *end; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE); g_return_val_if_fail (value != NULL, FALSE); errno = 0; result = g_ascii_strtoull (parser->data, &end, 10); if (errno) return FALSE; if (result > G_MAXUINT) return FALSE; if (parser->data == end) return FALSE; parser->data = end; *value = result; _gtk_css_parser_skip_whitespace (parser); return TRUE; }
gboolean _gtk_css_parser_begins_with (GtkCssParser *parser, char c) { g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), TRUE); return *parser->data == c; }
gboolean _gtk_css_parser_has_prefix (GtkCssParser *parser, const char *prefix) { g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE); return g_ascii_strncasecmp (parser->data, prefix, strlen (prefix)) == 0; }
void _gtk_css_parser_resync (GtkCssParser *parser, gboolean sync_at_semicolon, char terminator) { g_return_if_fail (GTK_IS_CSS_PARSER (parser)); gtk_css_parser_resync_internal (parser, sync_at_semicolon, TRUE, terminator); }
void _gtk_css_parser_free (GtkCssParser *parser) { g_return_if_fail (GTK_IS_CSS_PARSER (parser)); if (parser->file) g_object_unref (parser->file); g_slice_free (GtkCssParser, parser); }
char * _gtk_css_parser_read_uri (GtkCssParser *parser) { char *result; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL); if (!_gtk_css_parser_try (parser, "url(", TRUE)) { _gtk_css_parser_error (parser, "expected 'url('"); return NULL; } _gtk_css_parser_skip_whitespace (parser); if (_gtk_css_parser_is_string (parser)) { result = _gtk_css_parser_read_string (parser); } else { GString *str = g_string_new (NULL); while (_gtk_css_parser_read_char (parser, str, URLCHAR)) ; result = g_string_free (str, FALSE); if (result == NULL) _gtk_css_parser_error (parser, "not a url"); } if (result == NULL) return NULL; _gtk_css_parser_skip_whitespace (parser); if (*parser->data != ')') { _gtk_css_parser_error (parser, "missing ')' for url"); g_free (result); return NULL; } parser->data++; _gtk_css_parser_skip_whitespace (parser); return result; }
gboolean _gtk_css_parser_try_enum (GtkCssParser *parser, GType enum_type, int *value) { GEnumClass *enum_class; gboolean result; const char *start; char *str; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE); g_return_val_if_fail (value != NULL, FALSE); result = FALSE; enum_class = g_type_class_ref (enum_type); start = parser->data; str = _gtk_css_parser_try_ident (parser, TRUE); if (str == NULL) return FALSE; if (enum_class->n_values) { GEnumValue *enum_value; for (enum_value = enum_class->values; enum_value->value_name; enum_value++) { if (enum_value->value_nick && g_ascii_strcasecmp (str, enum_value->value_nick) == 0) { *value = enum_value->value; result = TRUE; break; } } } g_free (str); g_type_class_unref (enum_class); if (!result) parser->data = start; return result; }
gboolean _gtk_css_parser_try (GtkCssParser *parser, const char *string, gboolean skip_whitespace) { g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE); g_return_val_if_fail (string != NULL, FALSE); if (g_ascii_strncasecmp (parser->data, string, strlen (string)) != 0) return FALSE; parser->data += strlen (string); if (skip_whitespace) _gtk_css_parser_skip_whitespace (parser); return TRUE; }
char * _gtk_css_parser_try_name (GtkCssParser *parser, gboolean skip_whitespace) { GString *name; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL); name = g_string_new (NULL); while (_gtk_css_parser_read_char (parser, name, NMCHAR)) ; if (skip_whitespace) _gtk_css_parser_skip_whitespace (parser); return g_string_free (name, FALSE); }
gboolean _gtk_css_parser_try_double (GtkCssParser *parser, gdouble *value) { gdouble result; char *end; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE); g_return_val_if_fail (value != NULL, FALSE); errno = 0; result = g_ascii_strtod (parser->data, &end); if (errno) return FALSE; if (parser->data == end) return FALSE; parser->data = end; *value = result; _gtk_css_parser_skip_whitespace (parser); return TRUE; }
GtkCssValue * _gtk_css_number_value_parse (GtkCssParser *parser, GtkCssNumberParseFlags flags) { static const struct { const char *name; GtkCssUnit unit; GtkCssNumberParseFlags required_flags; } units[] = { { "px", GTK_CSS_PX, GTK_CSS_PARSE_LENGTH }, { "pt", GTK_CSS_PT, GTK_CSS_PARSE_LENGTH }, { "em", GTK_CSS_EM, GTK_CSS_PARSE_LENGTH }, { "ex", GTK_CSS_EX, GTK_CSS_PARSE_LENGTH }, { "pc", GTK_CSS_PC, GTK_CSS_PARSE_LENGTH }, { "in", GTK_CSS_IN, GTK_CSS_PARSE_LENGTH }, { "cm", GTK_CSS_CM, GTK_CSS_PARSE_LENGTH }, { "mm", GTK_CSS_MM, GTK_CSS_PARSE_LENGTH }, { "rad", GTK_CSS_RAD, GTK_CSS_PARSE_ANGLE }, { "deg", GTK_CSS_DEG, GTK_CSS_PARSE_ANGLE }, { "grad", GTK_CSS_GRAD, GTK_CSS_PARSE_ANGLE }, { "turn", GTK_CSS_TURN, GTK_CSS_PARSE_ANGLE }, { "s", GTK_CSS_S, GTK_CSS_PARSE_TIME }, { "ms", GTK_CSS_MS, GTK_CSS_PARSE_TIME } }; char *end, *unit_name; double value; GtkCssUnit unit; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL); errno = 0; value = g_ascii_strtod (parser->data, &end); if (errno) { _gtk_css_parser_error (parser, "not a number: %s", g_strerror (errno)); return NULL; } if (parser->data == end) { _gtk_css_parser_error (parser, "not a number"); return NULL; } parser->data = end; if (flags & GTK_CSS_POSITIVE_ONLY && value < 0) { _gtk_css_parser_error (parser, "negative values are not allowed."); return NULL; } unit_name = _gtk_css_parser_try_ident (parser, FALSE); if (unit_name) { guint i; for (i = 0; i < G_N_ELEMENTS (units); i++) { if (flags & units[i].required_flags && g_ascii_strcasecmp (unit_name, units[i].name) == 0) break; } if (i >= G_N_ELEMENTS (units)) { _gtk_css_parser_error (parser, "`%s' is not a valid unit.", unit_name); g_free (unit_name); return NULL; } unit = units[i].unit; g_free (unit_name); } else { if ((flags & GTK_CSS_PARSE_PERCENT) && _gtk_css_parser_try (parser, "%", FALSE)) { unit = GTK_CSS_PERCENT; } else if (value == 0.0) { if (flags & GTK_CSS_PARSE_NUMBER) unit = GTK_CSS_NUMBER; else if (flags & GTK_CSS_PARSE_LENGTH) unit = GTK_CSS_PX; else if (flags & GTK_CSS_PARSE_ANGLE) unit = GTK_CSS_DEG; else if (flags & GTK_CSS_PARSE_TIME) unit = GTK_CSS_S; else unit = GTK_CSS_PERCENT; } else if (flags & GTK_CSS_NUMBER_AS_PIXELS) { _gtk_css_parser_error_full (parser, GTK_CSS_PROVIDER_ERROR_DEPRECATED, "Not using units is deprecated. Assuming 'px'."); unit = GTK_CSS_PX; } else if (flags & GTK_CSS_PARSE_NUMBER) { unit = GTK_CSS_NUMBER; } else { _gtk_css_parser_error (parser, "Unit is missing."); return NULL; } } _gtk_css_parser_skip_whitespace (parser); return _gtk_css_number_value_new (value, unit); }
GtkSymbolicColor * _gtk_css_parser_read_symbolic_color (GtkCssParser *parser) { GtkSymbolicColor *symbolic; guint color; const char *names[] = {"rgba", "rgb", "lighter", "darker", "shade", "alpha", "mix", GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME}; char *name; g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL); if (_gtk_css_parser_try (parser, "@", FALSE)) { name = _gtk_css_parser_try_name (parser, TRUE); if (name) { symbolic = gtk_symbolic_color_new_name (name); } else { _gtk_css_parser_error (parser, "'%s' is not a valid symbolic color name", name); symbolic = NULL; } g_free (name); return symbolic; } for (color = 0; color < G_N_ELEMENTS (names); color++) { if (_gtk_css_parser_try (parser, names[color], TRUE)) break; } if (color < G_N_ELEMENTS (names)) return gtk_css_parser_read_symbolic_color_function (parser, color); symbolic = gtk_css_parser_try_hash_color (parser); if (symbolic) return symbolic; name = _gtk_css_parser_try_name (parser, TRUE); if (name) { GdkRGBA rgba; if (gdk_rgba_parse (&rgba, name)) { symbolic = gtk_symbolic_color_new_literal (&rgba); } else { _gtk_css_parser_error (parser, "'%s' is not a valid color name", name); symbolic = NULL; } g_free (name); return symbolic; } _gtk_css_parser_error (parser, "Not a color definition"); return NULL; }