Blame gtksourceview/gtksourcelanguage-parser-1.c

Packit a7d494
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
Packit a7d494
 * gtksourcelanguage-parser-ver1.c
Packit a7d494
 * Language specification parser for 1.0 version .lang files
Packit a7d494
 * This file is part of GtkSourceView
Packit a7d494
 *
Packit a7d494
 * Copyright (C) 2003 - Paolo Maggi <paolo.maggi@polito.it>
Packit a7d494
 *
Packit a7d494
 * GtkSourceView is free software; you can redistribute it and/or
Packit a7d494
 * modify it under the terms of the GNU Lesser General Public
Packit a7d494
 * License as published by the Free Software Foundation; either
Packit a7d494
 * version 2.1 of the License, or (at your option) any later version.
Packit a7d494
 *
Packit a7d494
 * GtkSourceView is distributed in the hope that it will be useful,
Packit a7d494
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a7d494
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit a7d494
 * Lesser General Public License for more details.
Packit a7d494
 *
Packit a7d494
 * You should have received a copy of the GNU Lesser General Public
Packit a7d494
 * License along with this library; if not, write to the Free Software
Packit a7d494
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit a7d494
 */
Packit a7d494
Packit a7d494
#ifdef HAVE_CONFIG_H
Packit a7d494
#include <config.h>
Packit a7d494
#endif
Packit a7d494
Packit a7d494
#include <string.h>
Packit a7d494
Packit a7d494
#include <libxml/parser.h>
Packit a7d494
#include "gtksourceview-i18n.h"
Packit a7d494
#include "gtksourcebuffer.h"
Packit a7d494
#include "gtksourcelanguage.h"
Packit a7d494
#include "gtksourcelanguage-private.h"
Packit a7d494
Packit a7d494
static gchar *
Packit a7d494
fix_pattern (const gchar *pattern,
Packit a7d494
	     gboolean    *end_at_line_end)
Packit a7d494
{
Packit a7d494
	char *slash;
Packit a7d494
Packit a7d494
	if (pattern == NULL)
Packit a7d494
		return NULL;
Packit a7d494
Packit a7d494
	slash = strchr (pattern, '/');
Packit a7d494
Packit a7d494
	if (slash != NULL)
Packit a7d494
	{
Packit a7d494
		GString *str;
Packit a7d494
Packit a7d494
		str = g_string_new_len (pattern, slash - pattern);
Packit a7d494
		g_string_append (str, "\\/");
Packit a7d494
		pattern = slash + 1;
Packit a7d494
Packit a7d494
		while ((slash = strchr (pattern, '/')) != NULL)
Packit a7d494
		{
Packit a7d494
			g_string_append_len (str, pattern, slash - pattern);
Packit a7d494
			g_string_append (str, "\\/");
Packit a7d494
			pattern = slash + 1;
Packit a7d494
		}
Packit a7d494
Packit a7d494
		if (g_str_has_suffix (pattern, "\\n"))
Packit a7d494
			g_string_append_len (str, pattern, strlen(pattern) - 2);
Packit a7d494
		else
Packit a7d494
			g_string_append (str, pattern);
Packit a7d494
Packit a7d494
		return g_string_free (str, FALSE);
Packit a7d494
	}
Packit a7d494
	else if (g_str_has_suffix (pattern, "\\n"))
Packit a7d494
	{
Packit a7d494
		if (end_at_line_end)
Packit a7d494
			*end_at_line_end = TRUE;
Packit a7d494
		return g_strndup (pattern, strlen (pattern) - 2);
Packit a7d494
	}
Packit a7d494
	else
Packit a7d494
	{
Packit a7d494
		return g_strdup (pattern);
Packit a7d494
	}
Packit a7d494
}
Packit a7d494
Packit a7d494
static gboolean
Packit a7d494
ctx_data_add_simple_pattern (GtkSourceContextData *ctx_data,
Packit a7d494
			     GtkSourceLanguage    *language,
Packit a7d494
			     const gchar          *id,
Packit a7d494
			     const gchar          *style,
Packit a7d494
			     const gchar          *pattern)
Packit a7d494
{
Packit a7d494
	gboolean result;
Packit a7d494
	gchar *real_id, *root_id, *fixed;
Packit a7d494
	GError *error = NULL;
Packit a7d494
Packit a7d494
	g_return_val_if_fail (id != NULL, FALSE);
Packit a7d494
Packit a7d494
	root_id = g_strdup_printf ("%s:%s", language->priv->id, language->priv->id);
Packit a7d494
	real_id = g_strdup_printf ("%s:%s", language->priv->id, id);
Packit a7d494
Packit a7d494
	fixed = fix_pattern (pattern, NULL);
Packit a7d494
Packit a7d494
	result = _gtk_source_context_data_define_context (ctx_data, real_id,
Packit a7d494
							  root_id,
Packit a7d494
							  fixed, NULL, NULL,
Packit a7d494
							  style, NULL,
Packit a7d494
							  GTK_SOURCE_CONTEXT_EXTEND_PARENT |
Packit a7d494
								GTK_SOURCE_CONTEXT_END_AT_LINE_END,
Packit a7d494
							  &error);
Packit a7d494
Packit a7d494
	if (error != NULL)
Packit a7d494
	{
Packit a7d494
		g_warning ("%s", error->message);
Packit a7d494
		g_error_free (error);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	g_free (fixed);
Packit a7d494
	g_free (real_id);
Packit a7d494
	g_free (root_id);
Packit a7d494
	return result;
Packit a7d494
}
Packit a7d494
Packit a7d494
static gboolean
Packit a7d494
ctx_data_add_syntax_pattern (GtkSourceContextData *ctx_data,
Packit a7d494
			     GtkSourceLanguage    *language,
Packit a7d494
			     const gchar          *id,
Packit a7d494
			     const gchar          *style,
Packit a7d494
			     const gchar          *pattern_start,
Packit a7d494
			     const gchar          *pattern_end,
Packit a7d494
			     gboolean              end_at_line_end)
Packit a7d494
{
Packit a7d494
	gboolean result;
Packit a7d494
	gchar *real_id, *root_id;
Packit a7d494
	gchar *fixed_start, *fixed_end;
Packit a7d494
	GError *error = NULL;
Packit a7d494
	GtkSourceContextFlags flags = GTK_SOURCE_CONTEXT_EXTEND_PARENT;
Packit a7d494
Packit a7d494
	g_return_val_if_fail (id != NULL, FALSE);
Packit a7d494
Packit a7d494
	root_id = g_strdup_printf ("%s:%s", language->priv->id, language->priv->id);
Packit a7d494
	real_id = g_strdup_printf ("%s:%s", language->priv->id, id);
Packit a7d494
Packit a7d494
	fixed_start = fix_pattern (pattern_start, &end_at_line_end);
Packit a7d494
	fixed_end = fix_pattern (pattern_end, &end_at_line_end);
Packit a7d494
Packit a7d494
	if (end_at_line_end)
Packit a7d494
		flags |= GTK_SOURCE_CONTEXT_END_AT_LINE_END;
Packit a7d494
Packit a7d494
	result = _gtk_source_context_data_define_context (ctx_data, real_id, root_id,
Packit a7d494
							  NULL,
Packit a7d494
							  pattern_start,
Packit a7d494
							  pattern_end,
Packit a7d494
							  style,
Packit a7d494
							  NULL,
Packit a7d494
							  flags,
Packit a7d494
							  &error);
Packit a7d494
Packit a7d494
	if (error != NULL)
Packit a7d494
	{
Packit a7d494
		g_warning ("%s", error->message);
Packit a7d494
		g_error_free (error);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	g_free (real_id);
Packit a7d494
	g_free (root_id);
Packit a7d494
	g_free (fixed_start);
Packit a7d494
	g_free (fixed_end);
Packit a7d494
Packit a7d494
	return result;
Packit a7d494
}
Packit a7d494
Packit a7d494
static gchar *
Packit a7d494
build_keyword_list (const GSList *keywords,
Packit a7d494
		    gboolean      case_sensitive,
Packit a7d494
		    gboolean      match_empty_string_at_beginning,
Packit a7d494
		    gboolean      match_empty_string_at_end,
Packit a7d494
		    const gchar  *beginning_regex,
Packit a7d494
		    const gchar  *end_regex)
Packit a7d494
{
Packit a7d494
	GString *str;
Packit a7d494
Packit a7d494
	g_return_val_if_fail (keywords != NULL, NULL);
Packit a7d494
Packit a7d494
	str =  g_string_new ("");
Packit a7d494
Packit a7d494
	if (keywords != NULL)
Packit a7d494
	{
Packit a7d494
		if (match_empty_string_at_beginning)
Packit a7d494
			g_string_append (str, "\\b");
Packit a7d494
Packit a7d494
		if (beginning_regex != NULL)
Packit a7d494
			g_string_append (str, beginning_regex);
Packit a7d494
Packit a7d494
		if (case_sensitive)
Packit a7d494
			g_string_append (str, "(?:");
Packit a7d494
		else
Packit a7d494
			g_string_append (str, "(?i:");
Packit a7d494
Packit a7d494
		/* TODO Make sure pcre can handle big lists, and split lists if necessary.
Packit a7d494
		 * See #110991 */
Packit a7d494
		while (keywords != NULL)
Packit a7d494
		{
Packit a7d494
			g_string_append (str, (gchar*) keywords->data);
Packit a7d494
Packit a7d494
			keywords = g_slist_next (keywords);
Packit a7d494
Packit a7d494
			if (keywords != NULL)
Packit a7d494
				g_string_append (str, "|");
Packit a7d494
		}
Packit a7d494
		g_string_append (str, ")");
Packit a7d494
Packit a7d494
		if (end_regex != NULL)
Packit a7d494
			g_string_append (str, end_regex);
Packit a7d494
Packit a7d494
		if (match_empty_string_at_end)
Packit a7d494
			g_string_append (str, "\\b");
Packit a7d494
	}
Packit a7d494
Packit a7d494
	return g_string_free (str, FALSE);
Packit a7d494
}
Packit a7d494
Packit a7d494
static void
Packit a7d494
parseLineComment (xmlNodePtr            cur,
Packit a7d494
		  gchar                *id,
Packit a7d494
		  xmlChar              *style,
Packit a7d494
		  GtkSourceContextData *ctx_data,
Packit a7d494
		  GtkSourceLanguage    *language)
Packit a7d494
{
Packit a7d494
	xmlNodePtr child;
Packit a7d494
Packit a7d494
	child = cur->xmlChildrenNode;
Packit a7d494
Packit a7d494
	if ((child != NULL) && !xmlStrcmp (child->name, (const xmlChar *)"start-regex"))
Packit a7d494
	{
Packit a7d494
		xmlChar *start_regex;
Packit a7d494
Packit a7d494
		start_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
Packit a7d494
Packit a7d494
		ctx_data_add_syntax_pattern (ctx_data, language, id,
Packit a7d494
					     (gchar*) style,
Packit a7d494
					     (gchar*) start_regex,
Packit a7d494
					     NULL, TRUE);
Packit a7d494
Packit a7d494
		xmlFree (start_regex);
Packit a7d494
	}
Packit a7d494
	else
Packit a7d494
	{
Packit a7d494
		g_warning ("Missing start-regex in tag 'line-comment' (%s, line %ld)",
Packit a7d494
			   child->doc->name, xmlGetLineNo (child));
Packit a7d494
	}
Packit a7d494
}
Packit a7d494
Packit a7d494
static void
Packit a7d494
parseBlockComment (xmlNodePtr            cur,
Packit a7d494
		   gchar                *id,
Packit a7d494
		   xmlChar              *style,
Packit a7d494
		   GtkSourceContextData *ctx_data,
Packit a7d494
		   GtkSourceLanguage    *language)
Packit a7d494
{
Packit a7d494
	xmlChar *start_regex = NULL;
Packit a7d494
	xmlChar *end_regex = NULL;
Packit a7d494
Packit a7d494
	xmlNodePtr child;
Packit a7d494
Packit a7d494
	child = cur->xmlChildrenNode;
Packit a7d494
Packit a7d494
	while (child != NULL)
Packit a7d494
	{
Packit a7d494
		if (!xmlStrcmp (child->name, (const xmlChar *)"start-regex"))
Packit a7d494
		{
Packit a7d494
			start_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
Packit a7d494
		}
Packit a7d494
		else
Packit a7d494
		if (!xmlStrcmp (child->name, (const xmlChar *)"end-regex"))
Packit a7d494
		{
Packit a7d494
			end_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
Packit a7d494
		}
Packit a7d494
Packit a7d494
		child = child->next;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (start_regex == NULL)
Packit a7d494
	{
Packit a7d494
		g_warning ("Missing start-regex in tag 'block-comment' (%s, line %ld)",
Packit a7d494
			   child->doc->name, xmlGetLineNo (cur));
Packit a7d494
Packit a7d494
		return;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (end_regex == NULL)
Packit a7d494
	{
Packit a7d494
		xmlFree (start_regex);
Packit a7d494
Packit a7d494
		g_warning ("Missing end-regex in tag 'block-comment' (%s, line %ld)",
Packit a7d494
			   child->doc->name, xmlGetLineNo (cur));
Packit a7d494
Packit a7d494
		return;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	ctx_data_add_syntax_pattern (ctx_data, language, id,
Packit a7d494
				     (gchar*) style,
Packit a7d494
				     (gchar*) start_regex,
Packit a7d494
				     (gchar*) end_regex,
Packit a7d494
				     FALSE);
Packit a7d494
Packit a7d494
	xmlFree (start_regex);
Packit a7d494
	xmlFree (end_regex);
Packit a7d494
}
Packit a7d494
Packit a7d494
static void
Packit a7d494
parseString (xmlNodePtr            cur,
Packit a7d494
	     gchar                *id,
Packit a7d494
	     xmlChar              *style,
Packit a7d494
	     GtkSourceContextData *ctx_data,
Packit a7d494
	     GtkSourceLanguage    *language)
Packit a7d494
{
Packit a7d494
	xmlChar *start_regex = NULL;
Packit a7d494
	xmlChar *end_regex = NULL;
Packit a7d494
Packit a7d494
	xmlChar *prop = NULL;
Packit a7d494
	gboolean end_at_line_end = TRUE;
Packit a7d494
Packit a7d494
	xmlNodePtr child;
Packit a7d494
Packit a7d494
	prop = xmlGetProp (cur, BAD_CAST "end-at-line-end");
Packit a7d494
	if (prop != NULL)
Packit a7d494
	{
Packit a7d494
		if (!xmlStrcasecmp (prop, (const xmlChar *)"TRUE") ||
Packit a7d494
		    !xmlStrcmp (prop, (const xmlChar *)"1"))
Packit a7d494
Packit a7d494
				end_at_line_end = TRUE;
Packit a7d494
			else
Packit a7d494
				end_at_line_end = FALSE;
Packit a7d494
Packit a7d494
		xmlFree (prop);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	child = cur->xmlChildrenNode;
Packit a7d494
Packit a7d494
	while (child != NULL)
Packit a7d494
	{
Packit a7d494
		if (!xmlStrcmp (child->name, (const xmlChar *)"start-regex"))
Packit a7d494
		{
Packit a7d494
			start_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
Packit a7d494
		}
Packit a7d494
		else
Packit a7d494
		if (!xmlStrcmp (child->name, (const xmlChar *)"end-regex"))
Packit a7d494
		{
Packit a7d494
			end_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
Packit a7d494
		}
Packit a7d494
Packit a7d494
		child = child->next;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (start_regex == NULL)
Packit a7d494
	{
Packit a7d494
		g_warning ("Missing start-regex in tag 'string' (%s, line %ld)",
Packit a7d494
			   child->doc->name, xmlGetLineNo (cur));
Packit a7d494
Packit a7d494
		return;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (end_regex == NULL)
Packit a7d494
	{
Packit a7d494
		xmlFree (start_regex);
Packit a7d494
Packit a7d494
		g_warning ("Missing end-regex in tag 'string' (%s, line %ld)",
Packit a7d494
			   child->doc->name, xmlGetLineNo (cur));
Packit a7d494
Packit a7d494
		return;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	ctx_data_add_syntax_pattern (ctx_data, language, id,
Packit a7d494
				     (gchar*) style,
Packit a7d494
				     (gchar*) start_regex,
Packit a7d494
				     (gchar*) end_regex,
Packit a7d494
				     end_at_line_end);
Packit a7d494
Packit a7d494
	xmlFree (start_regex);
Packit a7d494
	xmlFree (end_regex);
Packit a7d494
}
Packit a7d494
Packit a7d494
static void
Packit a7d494
parseKeywordList (xmlNodePtr            cur,
Packit a7d494
		  gchar                *id,
Packit a7d494
		  xmlChar              *style,
Packit a7d494
		  GtkSourceContextData *ctx_data,
Packit a7d494
		  GtkSourceLanguage    *language)
Packit a7d494
{
Packit a7d494
	gboolean case_sensitive = TRUE;
Packit a7d494
	gboolean match_empty_string_at_beginning = TRUE;
Packit a7d494
	gboolean match_empty_string_at_end = TRUE;
Packit a7d494
	gchar  *beginning_regex = NULL;
Packit a7d494
	gchar  *end_regex = NULL;
Packit a7d494
Packit a7d494
	GSList *list = NULL;
Packit a7d494
	gchar *regex;
Packit a7d494
Packit a7d494
	xmlChar *prop;
Packit a7d494
Packit a7d494
	xmlNodePtr child;
Packit a7d494
Packit a7d494
	prop = xmlGetProp (cur, BAD_CAST "case-sensitive");
Packit a7d494
	if (prop != NULL)
Packit a7d494
	{
Packit a7d494
		if (!xmlStrcasecmp (prop, (const xmlChar *)"TRUE") ||
Packit a7d494
		    !xmlStrcmp (prop, (const xmlChar *)"1"))
Packit a7d494
Packit a7d494
				case_sensitive = TRUE;
Packit a7d494
			else
Packit a7d494
				case_sensitive = FALSE;
Packit a7d494
Packit a7d494
		xmlFree (prop);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	prop = xmlGetProp (cur, BAD_CAST "match-empty-string-at-beginning");
Packit a7d494
	if (prop != NULL)
Packit a7d494
	{
Packit a7d494
		if (!xmlStrcasecmp (prop, (const xmlChar *)"TRUE") ||
Packit a7d494
		    !xmlStrcmp (prop, (const xmlChar *)"1"))
Packit a7d494
Packit a7d494
				match_empty_string_at_beginning = TRUE;
Packit a7d494
			else
Packit a7d494
				match_empty_string_at_beginning = FALSE;
Packit a7d494
Packit a7d494
		xmlFree (prop);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	prop = xmlGetProp (cur, BAD_CAST "match-empty-string-at-end");
Packit a7d494
	if (prop != NULL)
Packit a7d494
	{
Packit a7d494
		if (!xmlStrcasecmp (prop, (const xmlChar *)"TRUE") ||
Packit a7d494
		    !xmlStrcmp (prop, (const xmlChar *)"1"))
Packit a7d494
Packit a7d494
				match_empty_string_at_end = TRUE;
Packit a7d494
			else
Packit a7d494
				match_empty_string_at_end = FALSE;
Packit a7d494
Packit a7d494
		xmlFree (prop);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	prop = xmlGetProp (cur, BAD_CAST "beginning-regex");
Packit a7d494
	if (prop != NULL)
Packit a7d494
	{
Packit a7d494
		beginning_regex = g_strdup ((gchar *)prop);
Packit a7d494
Packit a7d494
		xmlFree (prop);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	prop = xmlGetProp (cur, BAD_CAST "end-regex");
Packit a7d494
	if (prop != NULL)
Packit a7d494
	{
Packit a7d494
		end_regex = g_strdup ((gchar *)prop);
Packit a7d494
Packit a7d494
		xmlFree (prop);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	child = cur->xmlChildrenNode;
Packit a7d494
Packit a7d494
	while (child != NULL)
Packit a7d494
	{
Packit a7d494
		if (!xmlStrcmp (child->name, BAD_CAST "keyword"))
Packit a7d494
		{
Packit a7d494
			xmlChar *keyword;
Packit a7d494
			keyword = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
Packit a7d494
			list = g_slist_prepend (list, keyword);
Packit a7d494
		}
Packit a7d494
Packit a7d494
		child = child->next;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	list = g_slist_reverse (list);
Packit a7d494
Packit a7d494
	if (list == NULL)
Packit a7d494
	{
Packit a7d494
		g_warning ("No keywords in tag 'keyword-list' (%s, line %ld)",
Packit a7d494
			   child->doc->name, xmlGetLineNo (cur));
Packit a7d494
Packit a7d494
		g_free (beginning_regex),
Packit a7d494
		g_free (end_regex);
Packit a7d494
Packit a7d494
		return;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	regex = build_keyword_list (list,
Packit a7d494
				    case_sensitive,
Packit a7d494
				    match_empty_string_at_beginning,
Packit a7d494
				    match_empty_string_at_end,
Packit a7d494
				    beginning_regex,
Packit a7d494
				    end_regex);
Packit a7d494
Packit a7d494
	g_free (beginning_regex),
Packit a7d494
	g_free (end_regex);
Packit a7d494
Packit a7d494
	g_slist_free_full (list, (GDestroyNotify)xmlFree);
Packit a7d494
Packit a7d494
	ctx_data_add_simple_pattern (ctx_data, language, id, (gchar*) style, regex);
Packit a7d494
Packit a7d494
	g_free (regex);
Packit a7d494
}
Packit a7d494
Packit a7d494
static void
Packit a7d494
parsePatternItem (xmlNodePtr            cur,
Packit a7d494
		  gchar                *id,
Packit a7d494
		  xmlChar              *style,
Packit a7d494
		  GtkSourceContextData *ctx_data,
Packit a7d494
		  GtkSourceLanguage    *language)
Packit a7d494
{
Packit a7d494
	xmlNodePtr child;
Packit a7d494
Packit a7d494
	child = cur->xmlChildrenNode;
Packit a7d494
Packit a7d494
	if ((child != NULL) && !xmlStrcmp (child->name, (const xmlChar *)"regex"))
Packit a7d494
	{
Packit a7d494
		xmlChar *regex;
Packit a7d494
Packit a7d494
		regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
Packit a7d494
Packit a7d494
		ctx_data_add_simple_pattern (ctx_data, language, id,
Packit a7d494
					     (gchar*) style,
Packit a7d494
					     (gchar*) regex);
Packit a7d494
Packit a7d494
		xmlFree (regex);
Packit a7d494
	}
Packit a7d494
	else
Packit a7d494
	{
Packit a7d494
		g_warning ("Missing regex in tag 'pattern-item' (%s, line %ld)",
Packit a7d494
			   child->doc->name, xmlGetLineNo (child));
Packit a7d494
	}
Packit a7d494
}
Packit a7d494
Packit a7d494
static void
Packit a7d494
parseSyntaxItem (xmlNodePtr            cur,
Packit a7d494
		 const gchar          *id,
Packit a7d494
		 xmlChar              *style,
Packit a7d494
		 GtkSourceContextData *ctx_data,
Packit a7d494
		 GtkSourceLanguage    *language)
Packit a7d494
{
Packit a7d494
	xmlChar *start_regex = NULL;
Packit a7d494
	xmlChar *end_regex = NULL;
Packit a7d494
Packit a7d494
	xmlNodePtr child;
Packit a7d494
Packit a7d494
	child = cur->xmlChildrenNode;
Packit a7d494
Packit a7d494
	while (child != NULL)
Packit a7d494
	{
Packit a7d494
		if (!xmlStrcmp (child->name, (const xmlChar *)"start-regex"))
Packit a7d494
		{
Packit a7d494
			start_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
Packit a7d494
		}
Packit a7d494
		else
Packit a7d494
		if (!xmlStrcmp (child->name, (const xmlChar *)"end-regex"))
Packit a7d494
		{
Packit a7d494
			end_regex = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
Packit a7d494
		}
Packit a7d494
Packit a7d494
		child = child->next;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (start_regex == NULL)
Packit a7d494
	{
Packit a7d494
		g_warning ("Missing start-regex in tag 'syntax-item' (%s, line %ld)",
Packit a7d494
			   child->doc->name, xmlGetLineNo (cur));
Packit a7d494
Packit a7d494
		return;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (end_regex == NULL)
Packit a7d494
	{
Packit a7d494
		xmlFree (start_regex);
Packit a7d494
Packit a7d494
		g_warning ("Missing end-regex in tag 'syntax-item' (%s, line %ld)",
Packit a7d494
			   child->doc->name, xmlGetLineNo (cur));
Packit a7d494
Packit a7d494
		return;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	ctx_data_add_syntax_pattern (ctx_data, language, id,
Packit a7d494
				     (gchar*) style,
Packit a7d494
				     (gchar*) start_regex,
Packit a7d494
				     (gchar*) end_regex,
Packit a7d494
				     FALSE);
Packit a7d494
Packit a7d494
	xmlFree (start_regex);
Packit a7d494
	xmlFree (end_regex);
Packit a7d494
}
Packit a7d494
Packit a7d494
static void
Packit a7d494
parseTag (GtkSourceLanguage    *language,
Packit a7d494
	  xmlNodePtr            cur,
Packit a7d494
	  GtkSourceContextData *ctx_data)
Packit a7d494
{
Packit a7d494
	xmlChar *name;
Packit a7d494
	xmlChar *style;
Packit a7d494
	xmlChar *id;
Packit a7d494
Packit a7d494
	name = xmlGetProp (cur, BAD_CAST "_name");
Packit a7d494
	if (name == NULL)
Packit a7d494
	{
Packit a7d494
		name = xmlGetProp (cur, BAD_CAST "name");
Packit a7d494
		id = xmlStrdup (name);
Packit a7d494
	}
Packit a7d494
	else
Packit a7d494
	{
Packit a7d494
		gchar *tmp1 = _gtk_source_language_translate_string (language, (gchar*) name);
Packit a7d494
		xmlChar *tmp2 = xmlStrdup (BAD_CAST tmp1);
Packit a7d494
		id = name;
Packit a7d494
		name = tmp2;
Packit a7d494
		g_free (tmp1);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (name == NULL)
Packit a7d494
	{
Packit a7d494
		return;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	style = xmlGetProp (cur, BAD_CAST "style");
Packit a7d494
Packit a7d494
	if (!xmlStrcmp (cur->name, (const xmlChar*) "line-comment"))
Packit a7d494
	{
Packit a7d494
		parseLineComment (cur, (gchar*) id, style, ctx_data, language);
Packit a7d494
	}
Packit a7d494
	else if (!xmlStrcmp (cur->name, (const xmlChar*) "block-comment"))
Packit a7d494
	{
Packit a7d494
		parseBlockComment (cur, (gchar*) id, style, ctx_data, language);
Packit a7d494
	}
Packit a7d494
	else if (!xmlStrcmp (cur->name, (const xmlChar*) "string"))
Packit a7d494
	{
Packit a7d494
		parseString (cur, (gchar*) id, style, ctx_data, language);
Packit a7d494
	}
Packit a7d494
	else if (!xmlStrcmp (cur->name, (const xmlChar*) "keyword-list"))
Packit a7d494
	{
Packit a7d494
		parseKeywordList (cur, (gchar*) id, style, ctx_data, language);
Packit a7d494
	}
Packit a7d494
	else if (!xmlStrcmp (cur->name, (const xmlChar*) "pattern-item"))
Packit a7d494
	{
Packit a7d494
		parsePatternItem (cur, (gchar*) id, style, ctx_data, language);
Packit a7d494
	}
Packit a7d494
	else if (!xmlStrcmp (cur->name, (const xmlChar*) "syntax-item"))
Packit a7d494
	{
Packit a7d494
		parseSyntaxItem (cur, (gchar*) id, style, ctx_data, language);
Packit a7d494
	}
Packit a7d494
	else
Packit a7d494
	{
Packit a7d494
		g_print ("Unknown tag: %s\n", cur->name);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	xmlFree (name);
Packit a7d494
	xmlFree (style);
Packit a7d494
	xmlFree (id);
Packit a7d494
}
Packit a7d494
Packit a7d494
static gboolean
Packit a7d494
define_root_context (GtkSourceContextData *ctx_data,
Packit a7d494
		     GtkSourceLanguage    *language)
Packit a7d494
{
Packit a7d494
	gboolean result;
Packit a7d494
	gchar *id;
Packit a7d494
	GError *error = NULL;
Packit a7d494
Packit a7d494
	g_return_val_if_fail (language->priv->id != NULL, FALSE);
Packit a7d494
Packit a7d494
	id = g_strdup_printf ("%s:%s", language->priv->id, language->priv->id);
Packit a7d494
	result = _gtk_source_context_data_define_context (ctx_data, id,
Packit a7d494
							  NULL, NULL, NULL, NULL,
Packit a7d494
							  NULL, NULL,
Packit a7d494
							  GTK_SOURCE_CONTEXT_EXTEND_PARENT,
Packit a7d494
							  &error);
Packit a7d494
Packit a7d494
	if (error != NULL)
Packit a7d494
	{
Packit a7d494
		g_warning ("%s", error->message);
Packit a7d494
		g_error_free (error);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	g_free (id);
Packit a7d494
	return result;
Packit a7d494
}
Packit a7d494
Packit a7d494
gboolean
Packit a7d494
_gtk_source_language_file_parse_version1 (GtkSourceLanguage    *language,
Packit a7d494
					  GtkSourceContextData *ctx_data)
Packit a7d494
{
Packit a7d494
	xmlDocPtr doc;
Packit a7d494
	xmlNodePtr cur;
Packit a7d494
	GMappedFile *mf;
Packit a7d494
	gunichar esc_char = 0;
Packit a7d494
	xmlChar *lang_version = NULL;
Packit a7d494
Packit a7d494
	xmlKeepBlanksDefault (0);
Packit a7d494
Packit a7d494
	mf = g_mapped_file_new (language->priv->lang_file_name, FALSE, NULL);
Packit a7d494
Packit a7d494
	if (mf == NULL)
Packit a7d494
	{
Packit a7d494
		doc = NULL;
Packit a7d494
	}
Packit a7d494
	else
Packit a7d494
	{
Packit a7d494
		doc = xmlParseMemory (g_mapped_file_get_contents (mf),
Packit a7d494
				      g_mapped_file_get_length (mf));
Packit a7d494
Packit a7d494
		g_mapped_file_unref (mf);
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (doc == NULL)
Packit a7d494
	{
Packit a7d494
		g_warning ("Impossible to parse file '%s'",
Packit a7d494
			   language->priv->lang_file_name);
Packit a7d494
		return FALSE;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	cur = xmlDocGetRootElement (doc);
Packit a7d494
Packit a7d494
	if (cur == NULL)
Packit a7d494
	{
Packit a7d494
		g_warning ("The lang file '%s' is empty",
Packit a7d494
			   language->priv->lang_file_name);
Packit a7d494
		goto error;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (xmlStrcmp (cur->name, (const xmlChar *) "language") != 0)
Packit a7d494
	{
Packit a7d494
		g_warning ("File '%s' is of the wrong type",
Packit a7d494
			   language->priv->lang_file_name);
Packit a7d494
		goto error;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	lang_version = xmlGetProp (cur, BAD_CAST "version");
Packit a7d494
Packit a7d494
	if (lang_version == NULL || strcmp ("1.0", (char*) lang_version) != 0)
Packit a7d494
	{
Packit a7d494
		if (lang_version != NULL)
Packit a7d494
			g_warning ("Wrong language version '%s' in file '%s', expected '%s'",
Packit a7d494
				   (char*) lang_version, language->priv->lang_file_name, "1.0");
Packit a7d494
		else
Packit a7d494
			g_warning ("Language version missing in file '%s'",
Packit a7d494
				   language->priv->lang_file_name);
Packit a7d494
		goto error;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (!define_root_context (ctx_data, language))
Packit a7d494
	{
Packit a7d494
		g_warning ("Could not create root context for file '%s'",
Packit a7d494
			   language->priv->lang_file_name);
Packit a7d494
		goto error;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	/* FIXME: check that the language name, version, etc. are the
Packit a7d494
	 * right ones - Paolo */
Packit a7d494
Packit a7d494
	cur = xmlDocGetRootElement (doc);
Packit a7d494
	cur = cur->xmlChildrenNode;
Packit a7d494
	g_return_val_if_fail (cur != NULL, FALSE);
Packit a7d494
Packit a7d494
	while (cur != NULL)
Packit a7d494
	{
Packit a7d494
		if (!xmlStrcmp (cur->name, (const xmlChar *)"escape-char"))
Packit a7d494
		{
Packit a7d494
			xmlChar *escape;
Packit a7d494
Packit a7d494
			escape = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
Packit a7d494
			esc_char = g_utf8_get_char_validated ((gchar*) escape, -1);
Packit a7d494
Packit a7d494
			if (esc_char == (gunichar) -1 || esc_char == (gunichar) -2)
Packit a7d494
			{
Packit a7d494
				g_warning ("Invalid (non UTF8) escape character in file '%s'",
Packit a7d494
					   language->priv->lang_file_name);
Packit a7d494
				esc_char = 0;
Packit a7d494
			}
Packit a7d494
Packit a7d494
			xmlFree (escape);
Packit a7d494
		}
Packit a7d494
		else
Packit a7d494
		{
Packit a7d494
			parseTag (language, cur, ctx_data);
Packit a7d494
		}
Packit a7d494
Packit a7d494
		cur = cur->next;
Packit a7d494
	}
Packit a7d494
Packit a7d494
	if (esc_char != 0)
Packit a7d494
		_gtk_source_context_data_set_escape_char (ctx_data, esc_char);
Packit a7d494
Packit a7d494
	_gtk_source_context_data_finish_parse (ctx_data, NULL, NULL);
Packit a7d494
	_gtk_source_language_define_language_styles (language);
Packit a7d494
Packit a7d494
	xmlFreeDoc (doc);
Packit a7d494
	xmlFree (lang_version);
Packit a7d494
	return TRUE;
Packit a7d494
Packit a7d494
error:
Packit a7d494
	if (doc)
Packit a7d494
		xmlFreeDoc (doc);
Packit a7d494
	xmlFree (lang_version);
Packit a7d494
	return FALSE;
Packit a7d494
}
Packit a7d494