symbol-db: removed deprecated code cxxparser/.
[anjuta.git] / plugins / project-wizard / parser.c
blob12d2ce65f57905b6ca0cef632af46865d65047a3
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 parser.c
4 Copyright (C) 2004 Sebastien Granjoux
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /*
22 * All functions for parsing wizard template (.wiz) files
24 *---------------------------------------------------------------------------*/
26 #include <config.h>
28 #include "parser.h"
30 #include <glib.h>
32 #include <string.h>
33 #include <stdarg.h>
35 #include <libanjuta/anjuta-debug.h>
37 /*---------------------------------------------------------------------------*/
39 #define PROJECT_WIZARD_EXTENSION ".wiz"
41 typedef enum {
42 NPW_NO_TAG = 0,
43 NPW_PROJECT_WIZARD_TAG,
44 NPW_NAME_TAG,
45 NPW_DESCRIPTION_TAG,
46 NPW_CATEGORY_TAG,
47 NPW_REQUIRED_PROGRAM_TAG,
48 NPW_REQUIRED_PACKAGE_TAG,
49 NPW_ICON_TAG,
50 NPW_PAGE_TAG,
51 NPW_PROPERTY_TAG,
52 NPW_ITEM_TAG,
53 NPW_DIRECTORY_TAG,
54 NPW_FILE_TAG,
55 NPW_CONTENT_TAG,
56 NPW_ACTION_TAG,
57 NPW_RUN_TAG,
58 NPW_OPEN_TAG,
59 NPW_UNKNOW_TAG
60 } NPWTag;
62 typedef enum {
63 NPW_NO_ATTRIBUTE = 0,
64 NPW_NAME_ATTRIBUTE,
65 NPW_LABEL_ATTRIBUTE,
66 NPW_DESCRIPTION_ATTRIBUTE,
67 NPW_VALUE_ATTRIBUTE,
68 NPW_SUMMARY_ATTRIBUTE,
69 NPW_TYPE_ATTRIBUTE,
70 NPW_RESTRICTION_ATTRIBUTE,
71 NPW_MANDATORY_ATTRIBUTE,
72 NPW_EXIST_ATTRIBUTE,
73 NPW_EDITABLE_ATTRIBUTE,
74 NPW_SOURCE_ATTRIBUTE,
75 NPW_DESTINATION_ATTRIBUTE,
76 NPW_EXECUTABLE_ATTRIBUTE,
77 NPW_PROJECT_ATTRIBUTE,
78 NPW_AUTOGEN_ATTRIBUTE,
79 NPW_COMMAND_ATTRIBUTE,
80 NPW_FILE_ATTRIBUTE,
81 NPW_UNKNOW_ATTRIBUTE
82 } NPWAttribute;
84 typedef enum {
85 NPW_HEADER_PARSER,
86 NPW_PAGE_PARSER,
87 NPW_FILE_PARSER,
88 NPW_ACTION_PARSER
89 } NPWParser;
91 typedef enum {
92 NPW_STOP_PARSING,
93 } NPWParserError;
96 /* Read all project templates in a directory
97 *---------------------------------------------------------------------------*/
99 gboolean
100 npw_header_list_readdir (GList** list, const gchar* path)
102 GDir* dir;
103 const gchar* name;
104 gboolean ok = FALSE;
106 g_return_val_if_fail (list != NULL, FALSE);
107 g_return_val_if_fail (path != NULL, FALSE);
109 /* Read all project template files */
110 dir = g_dir_open (path, 0, NULL);
111 if (!dir) return FALSE;
113 while ((name = g_dir_read_name (dir)) != NULL)
115 char* filename = g_build_filename (path, name, NULL);
117 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
119 /* Search recursively in sub directory */
120 if (npw_header_list_readdir (list, filename))
122 ok = TRUE;
125 else if (g_str_has_suffix (name, PROJECT_WIZARD_EXTENSION))
127 if (npw_header_list_read (list, filename))
129 /* Read at least one project file */
130 ok = TRUE;
133 g_free (filename);
136 g_dir_close (dir);
138 return ok;
141 /* Common parser functions
142 *---------------------------------------------------------------------------*/
144 static NPWTag
145 parse_tag (const char* name)
147 if (strcmp (name, "project-wizard") == 0)
149 return NPW_PROJECT_WIZARD_TAG;
151 else if ((strcmp ("_name", name) == 0) || (strcmp ("name", name) == 0))
153 return NPW_NAME_TAG;
155 else if ((strcmp ("_description", name) == 0) || (strcmp ("description", name) == 0))
157 return NPW_DESCRIPTION_TAG;
159 else if (strcmp ("icon", name) == 0)
161 return NPW_ICON_TAG;
163 else if (strcmp ("category", name) == 0)
165 return NPW_CATEGORY_TAG;
167 else if (strcmp ("required-program", name) == 0)
169 return NPW_REQUIRED_PROGRAM_TAG;
171 else if (strcmp ("required-package", name) == 0)
173 return NPW_REQUIRED_PACKAGE_TAG;
175 else if (strcmp ("page", name) == 0)
177 return NPW_PAGE_TAG;
179 else if (strcmp ("property", name) == 0)
181 return NPW_PROPERTY_TAG;
183 else if (strcmp ("item", name) == 0)
185 return NPW_ITEM_TAG;
187 else if (strcmp ("directory", name) == 0)
189 return NPW_DIRECTORY_TAG;
191 else if (strcmp ("content", name) == 0)
193 return NPW_CONTENT_TAG;
195 else if (strcmp ("file", name) == 0)
197 return NPW_FILE_TAG;
199 else if (strcmp ("action", name) == 0)
201 return NPW_ACTION_TAG;
203 else if (strcmp ("run", name) == 0)
205 return NPW_RUN_TAG;
207 else if (strcmp ("open", name) == 0)
209 return NPW_OPEN_TAG;
211 else
213 return NPW_UNKNOW_TAG;
217 static NPWAttribute
218 parse_attribute (const char* name)
220 if (strcmp ("name", name) == 0)
222 return NPW_NAME_ATTRIBUTE;
224 else if (strcmp ("_label", name) == 0)
226 return NPW_LABEL_ATTRIBUTE;
228 else if (strcmp ("_description", name) == 0)
230 return NPW_DESCRIPTION_ATTRIBUTE;
232 else if (strcmp ("default", name) == 0 || strcmp ("value", name) == 0)
234 return NPW_VALUE_ATTRIBUTE;
236 else if (strcmp ("type", name) == 0)
238 return NPW_TYPE_ATTRIBUTE;
240 else if (strcmp ("restriction", name) == 0)
242 return NPW_RESTRICTION_ATTRIBUTE;
244 else if (strcmp ("summary", name) == 0)
246 return NPW_SUMMARY_ATTRIBUTE;
248 else if (strcmp ("mandatory", name) == 0)
250 return NPW_MANDATORY_ATTRIBUTE;
252 else if (strcmp ("editable", name) == 0)
254 return NPW_EDITABLE_ATTRIBUTE;
256 else if (strcmp ("exist", name) == 0)
258 return NPW_EXIST_ATTRIBUTE;
260 else if (strcmp ("source", name) == 0)
262 return NPW_SOURCE_ATTRIBUTE;
264 else if (strcmp ("destination", name) == 0)
266 return NPW_DESTINATION_ATTRIBUTE;
268 else if (strcmp ("executable", name) == 0)
270 return NPW_EXECUTABLE_ATTRIBUTE;
272 else if (strcmp ("project", name) == 0)
274 return NPW_PROJECT_ATTRIBUTE;
276 else if (strcmp ("autogen", name) == 0)
278 return NPW_AUTOGEN_ATTRIBUTE;
280 else if (strcmp ("command", name) == 0)
282 return NPW_COMMAND_ATTRIBUTE;
284 else if (strcmp ("file", name) == 0)
286 return NPW_FILE_ATTRIBUTE;
288 else
290 return NPW_UNKNOW_ATTRIBUTE;
294 static gboolean
295 parse_boolean_string (const gchar* value)
297 return g_ascii_strcasecmp ("no", value) && g_ascii_strcasecmp ("0", value) && g_ascii_strcasecmp ("false", value);
300 static GQuark
301 parser_error_quark (void)
303 static GQuark error_quark = 0;
305 if (error_quark == 0)
306 error_quark = g_quark_from_static_string ("parser_error_quark");
307 return error_quark;
310 static void
311 parser_warning (GMarkupParseContext* ctx, const gchar* format,...)
313 va_list args;
314 gchar* msg;
315 gint line;
317 g_markup_parse_context_get_position (ctx, &line, NULL);
318 msg = g_strdup_printf ("line %d: %s", line, format);
319 va_start (args, format);
320 g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, msg, args);
321 va_end (args);
322 g_free (msg);
325 static void
326 parser_critical (GMarkupParseContext* ctx, const gchar* format,...)
328 va_list args;
329 gchar* msg;
330 gint line;
332 g_markup_parse_context_get_position (ctx, &line, NULL);
333 msg = g_strdup_printf ("line %d: %s", line, format);
334 va_start (args, format);
335 g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, msg, args);
336 va_end (args);
337 g_free (msg);
339 /* Parse project wizard block
340 *---------------------------------------------------------------------------*/
342 #define NPW_HEADER_PARSER_MAX_LEVEL 2 /* Maximum number of nested elements */
344 typedef struct _NPWHeaderParser
346 /* Type of parser (not used) */
347 NPWParser type;
348 GMarkupParseContext* ctx;
349 /* Known element stack */
350 NPWTag tag[NPW_HEADER_PARSER_MAX_LEVEL + 1];
351 NPWTag* last;
352 /* Unknown element stack */
353 guint unknown;
354 /* Current header */
355 NPWHeader* header;
356 /* Name of file read */
357 gchar* filename;
358 } NPWHeaderParser;
360 static void
361 parse_header_start (GMarkupParseContext* context,
362 const gchar* name,
363 const gchar** attributes,
364 const gchar** values,
365 gpointer data,
366 GError** error)
368 NPWHeaderParser* parser = (NPWHeaderParser*)data;
369 NPWTag tag;
370 gboolean known = FALSE;
372 /* Recognize element */
373 if (parser->unknown == 0)
375 /* Not inside an unknown element */
376 tag = parse_tag (name);
377 switch (*parser->last)
379 case NPW_NO_TAG:
380 /* Top level element */
381 switch (tag)
383 case NPW_PROJECT_WIZARD_TAG:
384 parser->header = npw_header_new ();
385 npw_header_set_filename (parser->header, parser->filename);
386 known = TRUE;
387 break;
388 case NPW_UNKNOW_TAG:
389 parser_warning (parser->ctx, "Unknown element \"%s\"", name);
390 break;
391 default:
392 break;
394 break;
395 case NPW_PROJECT_WIZARD_TAG:
396 /* Necessary to avoid neested PROJECT_WIZARD element */
397 switch (tag)
399 case NPW_NAME_TAG:
400 case NPW_DESCRIPTION_TAG:
401 case NPW_ICON_TAG:
402 case NPW_CATEGORY_TAG:
403 case NPW_REQUIRED_PROGRAM_TAG:
404 case NPW_REQUIRED_PACKAGE_TAG:
405 known = TRUE;
406 break;
407 default:
408 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
409 break;
411 break;
412 default:
413 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
414 break;
418 /* Push element */
419 if (known)
421 /* Know element stack overflow */
422 g_return_if_fail ((parser->last - parser->tag) <= NPW_HEADER_PARSER_MAX_LEVEL);
423 parser->last++;
424 *parser->last = tag;
426 else
428 parser->unknown++;
432 static void
433 parse_header_end (GMarkupParseContext* context,
434 const gchar* name,
435 gpointer data,
436 GError** error)
438 NPWHeaderParser* parser = (NPWHeaderParser*)data;
440 if (parser->unknown > 0)
442 /* Pop unknown element */
443 parser->unknown--;
445 else if (*parser->last != NPW_NO_TAG)
447 /* Pop known element */
448 parser->last--;
449 if (parser->last[1] == NPW_PROJECT_WIZARD_TAG)
451 /* Check if the element is valid */
452 if (parser->header && !npw_header_get_name (parser->header))
454 parser_critical (parser->ctx, "Missing name attribute");
455 npw_header_free (parser->header);
458 /* Stop parsing after first project wizard block
459 * Remaining file need to be passed through autogen
460 * to be a valid xml file */
462 /* error should be available to stop parsing */
463 g_return_if_fail (error != NULL);
465 /* Send an error */
466 *error = g_error_new_literal (parser_error_quark (), NPW_STOP_PARSING, "");
469 else
471 /* Know element stack underflow */
472 g_return_if_reached ();
476 static void
477 parse_header_text (GMarkupParseContext* context,
478 const gchar* text,
479 gsize len,
480 gpointer data,
481 GError** error)
483 NPWHeaderParser* parser = (NPWHeaderParser*)data;
485 if (parser->unknown == 0)
487 switch (*parser->last)
489 case NPW_NAME_TAG:
490 if (npw_header_get_name (parser->header) == NULL)
492 npw_header_set_name (parser->header, text);
494 else
496 parser_critical (parser->ctx, "Duplicated name tag");
498 break;
499 case NPW_DESCRIPTION_TAG:
500 if (npw_header_get_description (parser->header) == NULL)
502 npw_header_set_description (parser->header, text);
504 else
506 parser_critical (parser->ctx, "Duplicated description tag");
508 break;
509 case NPW_ICON_TAG:
510 if (npw_header_get_iconfile (parser->header) == NULL)
512 char* filename;
513 char* path;
515 path = g_path_get_dirname (parser->filename);
516 filename = g_build_filename (path, text, NULL);
517 npw_header_set_iconfile (parser->header, filename);
518 g_free (path);
519 g_free (filename);
521 else
523 parser_critical (parser->ctx, "Duplicated icon tag");
525 break;
526 case NPW_CATEGORY_TAG:
527 if (npw_header_get_category (parser->header) == NULL)
529 npw_header_set_category (parser->header, text);
531 else
533 parser_critical (parser->ctx, "Duplicated category tag");
535 break;
536 case NPW_REQUIRED_PROGRAM_TAG:
537 npw_header_add_required_program (parser->header, text);
538 break;
539 case NPW_REQUIRED_PACKAGE_TAG:
540 npw_header_add_required_package (parser->header, text);
541 break;
542 case NPW_PROJECT_WIZARD_TAG:
543 /* Nothing to do */
544 break;
545 default:
546 /* Unknown tag */
547 g_return_if_reached ();
548 break;
553 static GMarkupParser header_markup_parser = {
554 parse_header_start,
555 parse_header_end,
556 parse_header_text,
557 NULL,
558 NULL
561 static NPWHeaderParser*
562 npw_header_parser_new (GList** list, const gchar* filename)
564 NPWHeaderParser* parser;
566 g_return_val_if_fail (list != NULL, NULL);
567 g_return_val_if_fail (filename != NULL, NULL);
569 parser = g_new0 (NPWHeaderParser, 1);
571 parser->type = NPW_HEADER_PARSER;
572 parser->unknown = 0;
573 parser->tag[0] = NPW_NO_TAG;
574 parser->last = parser->tag;
575 parser->header = NULL;
576 parser->filename = g_strdup (filename);
578 parser->ctx = g_markup_parse_context_new (&header_markup_parser, 0, parser, NULL);
579 g_assert (parser->ctx != NULL);
581 return parser;
584 static void
585 npw_header_parser_free (NPWHeaderParser* parser)
587 g_return_if_fail (parser != NULL);
589 g_free (parser->filename);
590 g_markup_parse_context_free (parser->ctx);
591 g_free (parser);
594 static gboolean
595 npw_header_parser_parse (NPWHeaderParser* parser, const gchar* text, gssize len, GError** error)
597 return g_markup_parse_context_parse (parser->ctx, text, len, error);
600 /* Not used
602 static gboolean
603 npw_header_parser_end_parse (NPWHeaderParser* parser, GError** error)
605 return g_markup_parse_context_end_parse (parser->ctx, error);
608 gboolean
609 npw_header_list_read (GList** list, const gchar* filename)
611 gchar* content;
612 gsize len;
613 NPWHeaderParser* parser;
614 NPWHeader* header;
615 GError* err = NULL;
617 g_return_val_if_fail (list != NULL, FALSE);
618 g_return_val_if_fail (filename != NULL, FALSE);
620 if (!g_file_get_contents (filename, &content, &len, &err))
622 g_warning ("%s", err->message);
623 g_error_free (err);
625 return FALSE;
628 parser = npw_header_parser_new (list, filename);
630 npw_header_parser_parse (parser, content, len, &err);
631 header = parser->header;
632 /* Parse only a part of the file, so need to call parser_end_parse */
634 npw_header_parser_free (parser);
635 g_free (content);
637 if (err == NULL)
639 /* Parsing must end with an error
640 * generated at the end of the project wizard block */
641 g_warning ("Missing project wizard block in %s", filename);
642 npw_header_free (header);
644 return FALSE;
646 if (g_error_matches (err, parser_error_quark (), NPW_STOP_PARSING) == FALSE)
648 /* Parsing error */
649 g_warning ("%s", err->message);
650 g_error_free (err);
651 npw_header_free (header);
653 return FALSE;
655 g_error_free (err);
657 /* Add header to list if template does not already exist*/
658 if (npw_header_list_find_header (*list, header) == NULL)
660 *list = npw_header_list_insert_header (*list, header);
663 return TRUE;
667 /* Parse page block
668 *---------------------------------------------------------------------------*/
670 #define NPW_PAGE_PARSER_MAX_LEVEL 3 /* Maximum number of nested elements */
672 struct _NPWPageParser
674 /* Type of parser (not used) */
675 NPWParser type;
676 GMarkupParseContext* ctx;
677 /* Known element stack */
678 NPWTag tag[NPW_PAGE_PARSER_MAX_LEVEL + 1];
679 NPWTag* last;
680 /* Unknown element stack */
681 guint unknown;
682 /* page number to read */
683 gint count;
684 /* Current page object */
685 NPWPage* page;
686 /* Current property object */
687 NPWProperty* property;
690 static gboolean
691 parse_page (NPWPageParser* parser,
692 const gchar** attributes,
693 const gchar** values)
695 if (parser->count != 0)
697 /* Skip this page */
698 if (parser->count > 0) parser->count--;
700 return FALSE;
702 else
704 /* Read this page */
705 while (*attributes != NULL)
707 switch (parse_attribute (*attributes))
709 case NPW_NAME_ATTRIBUTE:
710 npw_page_set_name (parser->page, *values);
711 break;
712 case NPW_LABEL_ATTRIBUTE:
713 npw_page_set_label (parser->page, *values);
714 break;
715 case NPW_DESCRIPTION_ATTRIBUTE:
716 npw_page_set_description (parser->page, *values);
717 break;
718 default:
719 parser_warning (parser->ctx, "Unknown page attribute \"%s\"", *attributes);
720 break;
722 attributes++;
723 values++;
725 parser->count--;
727 return TRUE;
731 static gboolean
732 parse_property (NPWPageParser* parser,
733 const gchar** attributes,
734 const gchar** values)
736 parser->property = npw_property_new ();
737 npw_page_add_property (parser->page, parser->property);
739 while (*attributes != NULL)
741 switch (parse_attribute (*attributes))
743 case NPW_TYPE_ATTRIBUTE:
744 npw_property_set_string_type (parser->property, *values);
745 break;
746 case NPW_RESTRICTION_ATTRIBUTE:
747 npw_property_set_string_restriction (parser->property, *values);
748 break;
749 case NPW_NAME_ATTRIBUTE:
750 npw_property_set_name (parser->property, *values, parser->page);
751 break;
752 case NPW_LABEL_ATTRIBUTE:
753 npw_property_set_label (parser->property, *values);
754 break;
755 case NPW_DESCRIPTION_ATTRIBUTE:
756 npw_property_set_description (parser->property, *values);
757 break;
758 case NPW_VALUE_ATTRIBUTE:
759 npw_property_set_default (parser->property, *values);
760 break;
761 case NPW_SUMMARY_ATTRIBUTE:
762 npw_property_set_summary_option (parser->property, parse_boolean_string (*values));
763 break;
764 case NPW_MANDATORY_ATTRIBUTE:
765 npw_property_set_mandatory_option (parser->property, parse_boolean_string (*values));
766 break;
767 case NPW_EDITABLE_ATTRIBUTE:
768 npw_property_set_editable_option (parser->property, parse_boolean_string (*values));
769 break;
770 case NPW_EXIST_ATTRIBUTE:
771 npw_property_set_exist_option (parser->property, parse_boolean_string (*values));
772 break;
773 default:
774 parser_warning (parser->ctx, "Unknown property attribute \"%s\"", *attributes);
775 break;
777 attributes++;
778 values++;
781 return TRUE;
784 static gboolean
785 parse_item (NPWPageParser* parser,
786 const gchar** attributes,
787 const gchar** values)
789 const gchar* label = NULL;
790 const gchar* name = NULL;
792 while (*attributes != NULL)
794 switch (parse_attribute (*attributes))
796 case NPW_NAME_ATTRIBUTE:
797 name = *values;
798 break;
799 case NPW_LABEL_ATTRIBUTE:
800 label = *values;
801 break;
802 default:
803 parser_warning (parser->ctx, "Unknown item attribute \"%s\"", *attributes);
804 break;
806 attributes++;
807 values++;
810 if (name == NULL)
812 parser_warning (parser->ctx, "Missing name attribute");
814 else
816 npw_property_add_list_item (parser->property, name, label == NULL ? name : label);
819 return TRUE;
822 static void
823 parse_page_start (GMarkupParseContext* context,
824 const gchar* name,
825 const gchar** attributes,
826 const gchar** values,
827 gpointer data,
828 GError** error)
830 NPWPageParser* parser = (NPWPageParser*)data;
831 NPWTag tag;
832 gboolean known = FALSE;
834 /* Recognize element */
835 if (parser->unknown == 0)
837 /* Not inside an unknown element */
838 tag = parse_tag (name);
839 switch (*parser->last)
841 case NPW_NO_TAG:
842 /* Top level element */
843 switch (tag)
845 case NPW_PAGE_TAG:
846 known = parse_page (parser, attributes, values);
847 break;
848 case NPW_UNKNOW_TAG:
849 parser_warning (parser->ctx, "Unknown element \"%s\"", name);
850 break;
851 default:
852 break;
854 break;
855 case NPW_PAGE_TAG:
856 /* Necessary to avoid neested page element */
857 switch (tag)
859 case NPW_PROPERTY_TAG:
860 known = parse_property (parser, attributes, values);
861 break;
862 default:
863 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
864 break;
866 break;
867 case NPW_PROPERTY_TAG:
868 /* Necessary to avoid neested page & property element */
869 switch (tag)
871 case NPW_ITEM_TAG:
872 known = parse_item (parser, attributes, values);
873 break;
874 default:
875 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
876 break;
878 break;
879 default:
880 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
881 break;
885 /* Push element */
886 if (known)
888 /* Know element stack overflow */
889 g_return_if_fail ((parser->last - parser->tag) <= NPW_PAGE_PARSER_MAX_LEVEL);
890 parser->last++;
891 *parser->last = tag;
893 else
895 parser->unknown++;
899 static void
900 parse_page_end (GMarkupParseContext* context,
901 const gchar* name,
902 gpointer data,
903 GError** error)
905 NPWPageParser* parser = (NPWPageParser*)data;
907 if (parser->unknown > 0)
909 /* Pop unknown element */
910 parser->unknown--;
912 else if (*parser->last != NPW_NO_TAG)
914 /* Pop known element */
915 parser->last--;
917 else
919 /* Know element stack underflow */
920 g_return_if_reached ();
924 static GMarkupParser page_markup_parser = {
925 parse_page_start,
926 parse_page_end,
927 NULL,
928 NULL,
929 NULL
932 NPWPageParser*
933 npw_page_parser_new (NPWPage* page, const gchar* filename, gint count)
935 NPWPageParser* parser;
937 g_return_val_if_fail (page != NULL, NULL);
938 g_return_val_if_fail (count >= 0, NULL);
940 parser = g_new (NPWPageParser, 1);
942 parser->type = NPW_PAGE_PARSER;
944 parser->unknown = 0;
945 parser->tag[0] = NPW_NO_TAG;
946 parser->last =parser->tag;
948 parser->count = count;
949 parser->page = page;
950 parser->property = NULL;
952 parser->ctx = g_markup_parse_context_new (&page_markup_parser, 0, parser, NULL);
953 g_assert (parser->ctx != NULL);
955 return parser;
958 void
959 npw_page_parser_free (NPWPageParser* parser)
961 g_return_if_fail (parser != NULL);
963 g_markup_parse_context_free (parser->ctx);
964 g_free (parser);
967 gboolean
968 npw_page_parser_parse (NPWPageParser* parser, const gchar* text, gssize len, GError** error)
970 return g_markup_parse_context_parse (parser->ctx, text, len, error);
973 gboolean
974 npw_page_parser_end_parse (NPWPageParser* parser, GError** error)
976 return g_markup_parse_context_end_parse (parser->ctx, error);
979 gboolean
980 npw_page_read (NPWPage* page, const gchar* filename, gint count)
982 gchar* content;
983 gsize len;
984 NPWPageParser* parser;
985 GError* err = NULL;
987 g_return_val_if_fail (page != NULL, FALSE);
988 g_return_val_if_fail (filename != NULL, FALSE);
989 g_return_val_if_fail (count < 0, FALSE);
991 if (!g_file_get_contents (filename, &content, &len, &err))
993 g_warning ("%s", err->message);
994 g_error_free (err);
996 return FALSE;
999 parser = npw_page_parser_new (page, filename, count);
1001 npw_page_parser_parse (parser, content, len, &err);
1002 if (err == NULL) npw_page_parser_end_parse (parser, &err);
1004 npw_page_parser_free (parser);
1005 g_free (content);
1007 if (err != NULL)
1009 /* Parsing error */
1010 g_warning ("%s", err->message);
1011 g_error_free (err);
1013 return FALSE;
1016 return TRUE;
1020 /* Parse content block
1021 *---------------------------------------------------------------------------*/
1023 typedef struct _NPWFileTag
1025 NPWTag tag;
1026 gchar* destination;
1027 gchar* source;
1028 } NPWFileTag;
1030 struct _NPWFileListParser
1032 /* Type of parser (not used) */
1033 NPWParser type;
1034 GMarkupParseContext* ctx;
1035 /* Known element stack */
1036 GQueue* tag;
1037 /* Unknown element stack */
1038 guint unknown;
1039 /* Current file list */
1040 GList* list;
1043 static void
1044 npw_file_tag_free (NPWFileTag *tag)
1046 g_free (tag->destination);
1047 g_free (tag->source);
1048 g_slice_free (NPWFileTag, tag);
1051 /* concatenate two directories names, return value must be freed if
1052 * not equal to path1 or path2 */
1054 static gchar*
1055 concat_directory (const gchar* path1, const gchar* path2)
1057 const gchar* ptr;
1059 /* Check for not supported . and .. directory name in path2 */
1060 for (ptr = path2; ptr != '\0';)
1062 ptr = strchr (ptr, '.');
1063 if (ptr == NULL) break;
1065 /* Exception "." only is allowed */
1066 if ((ptr == path2) && (ptr[1] == '\0')) break;
1068 if ((ptr == path2) || (ptr[- 1] == G_DIR_SEPARATOR))
1070 if (ptr[1] == '.') ptr++;
1071 if ((ptr[1] == G_DIR_SEPARATOR) || (ptr[1] == '\0')) return NULL;
1073 ptr = ptr + 1;
1076 if ((*path1 == '\0') || (strcmp (path1, ".") == 0) || g_path_is_absolute (path2))
1078 return (char *)path2;
1080 else if ((*path2 == '\0') || (strcmp (path2, ".") == 0))
1082 return (char *)path1;
1084 else
1086 GString* path;
1088 path = g_string_new (path1);
1089 if (path->str[path->len -1] != G_DIR_SEPARATOR)
1091 g_string_append_c (path, G_DIR_SEPARATOR);
1093 g_string_append (path, path2);
1095 return g_string_free (path, FALSE);
1099 static void
1100 parse_directory (NPWFileListParser* parser, NPWFileTag* child, const gchar** attributes, const gchar** values)
1102 const gchar* source;
1103 const gchar* destination;
1104 char* path;
1106 /* Set default values */
1107 source = NULL;
1108 destination = NULL;
1110 /* Read all attributes */
1111 while (*attributes != NULL)
1113 switch (parse_attribute (*attributes))
1115 case NPW_SOURCE_ATTRIBUTE:
1116 source = *values;
1117 break;
1118 case NPW_DESTINATION_ATTRIBUTE:
1119 destination = *values;
1120 break;
1121 default:
1122 parser_warning (parser->ctx, "Unknow directory attribute \"%s\"", *attributes);
1123 break;
1125 attributes++;
1126 values++;
1129 /* Need source or destination */
1130 if ((source == NULL) && (destination != NULL))
1132 source = destination;
1134 else if ((source != NULL) && (destination == NULL))
1136 destination = source;
1138 else if ((source == NULL) && (destination == NULL))
1140 parser_warning (parser->ctx, "Missing source or destination attribute");
1141 child->tag = NPW_NO_TAG;
1143 return;
1146 path = concat_directory (child->source, source);
1147 if (path == NULL)
1149 parser_warning (parser->ctx, "Invalid directory source value \"%s\"", source);
1150 child->tag = NPW_NO_TAG;
1152 return;
1154 if (path == source)
1156 g_free (child->source);
1157 child->source = g_strdup (path);
1159 else if (path != child->source)
1161 g_free (child->source);
1162 child->source = path;
1166 path = concat_directory (child->destination, destination);
1167 if (path == NULL)
1169 parser_warning (parser->ctx, "Invalid directory destination value \"%s\"", source);
1170 child->tag = NPW_NO_TAG;
1172 return;
1174 if (path == destination)
1176 g_free (child->destination);
1177 child->destination = g_strdup (path);
1179 else if (path != child->destination)
1181 g_free (child->destination);
1182 child->destination = path;
1186 static void
1187 parse_file (NPWFileListParser* parser, NPWFileTag* child, const gchar** attributes, const gchar** values)
1189 const gchar* source;
1190 const gchar* destination;
1191 gchar* full_source;
1192 gchar* full_destination;
1193 gboolean execute;
1194 gboolean project;
1195 gboolean autogen;
1196 gboolean autogen_set;
1197 NPWFile* file;
1199 /* Set default values */
1200 source = NULL;
1201 destination = NULL;
1202 execute = FALSE;
1203 project = FALSE;
1204 autogen = FALSE;
1205 autogen_set = FALSE;
1207 while (*attributes != NULL)
1209 switch (parse_attribute (*attributes))
1211 case NPW_SOURCE_ATTRIBUTE:
1212 source = *values;
1213 break;
1214 case NPW_DESTINATION_ATTRIBUTE:
1215 destination = *values;
1216 break;
1217 case NPW_PROJECT_ATTRIBUTE:
1218 project = parse_boolean_string (*values);
1219 break;
1220 case NPW_EXECUTABLE_ATTRIBUTE:
1221 execute = parse_boolean_string (*values);
1222 break;
1223 case NPW_AUTOGEN_ATTRIBUTE:
1224 autogen = parse_boolean_string (*values);
1225 autogen_set = TRUE;
1226 break;
1227 default:
1228 parser_warning (parser->ctx, "Unknow file attribute \"%s\"", *attributes);
1229 break;
1231 attributes++;
1232 values++;
1235 if ((source == NULL) && (destination != NULL))
1237 source = destination;
1239 else if ((source != NULL) && (destination == NULL))
1241 destination = source;
1243 else if ((source == NULL) && (destination == NULL))
1245 parser_warning (parser->ctx, "Missing source or destination attribute");
1246 child->tag = NPW_NO_TAG;
1248 return;
1251 full_source = concat_directory (child->source, source);
1252 if ((full_source == NULL) || (full_source == child->source))
1254 parser_warning (parser->ctx, "Invalid file source value \"%s\"", source);
1255 child->tag = NPW_NO_TAG;
1257 return;
1259 full_destination = concat_directory (child->destination, destination);
1260 if ((full_destination == NULL) || (full_destination == child->destination))
1262 parser_warning (parser->ctx, "Invalid directory destination value \"%s\"", source);
1263 child->tag = NPW_NO_TAG;
1265 return;
1268 file = npw_file_new_file (full_destination, full_source);
1269 parser->list = g_list_prepend (parser->list, file);
1270 npw_file_set_execute (file, execute);
1271 npw_file_set_project (file, project);
1272 if (autogen_set)
1273 npw_file_set_autogen (file, autogen ? NPW_TRUE : NPW_FALSE);
1275 if (source != full_source)
1276 g_free (full_source);
1277 if (destination != full_destination)
1278 g_free (full_destination);
1281 static void
1282 parse_file_start (GMarkupParseContext* context,
1283 const gchar* name,
1284 const gchar** attributes,
1285 const gchar** values,
1286 gpointer data,
1287 GError** error)
1289 NPWFileListParser* parser = (NPWFileListParser*)data;
1290 NPWTag tag;
1291 NPWFileTag* parent;
1292 NPWFileTag child;
1294 child.tag = NPW_NO_TAG;
1295 child.source = NULL;
1296 child.destination = NULL;
1298 /* Recognize element */
1299 if (parser->unknown == 0)
1301 /* Not inside an unknown element */
1302 tag = parse_tag (name);
1304 parent = g_queue_peek_head (parser->tag);
1305 child.source = g_strdup (parent->source);
1306 child.destination = g_strdup (parent->destination);
1307 switch (parent->tag)
1309 case NPW_NO_TAG:
1310 /* Top level element */
1311 switch (tag)
1313 case NPW_CONTENT_TAG:
1314 child.tag = tag;
1315 break;
1316 case NPW_UNKNOW_TAG:
1317 parser_warning (parser->ctx, "Unknown element \"%s\"", name);
1318 break;
1319 default:
1320 break;
1322 break;
1323 case NPW_CONTENT_TAG:
1324 switch (tag)
1326 case NPW_DIRECTORY_TAG:
1327 child.tag = tag;
1328 parse_directory (parser, &child, attributes, values);
1329 break;
1330 default:
1331 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
1332 break;
1334 break;
1335 case NPW_DIRECTORY_TAG:
1336 switch (tag)
1338 case NPW_DIRECTORY_TAG:
1339 child.tag = tag;
1340 parse_directory (parser, &child, attributes, values);
1341 break;
1342 case NPW_FILE_TAG:
1343 child.tag = tag;
1344 parse_file (parser, &child, attributes, values);
1345 break;
1346 default:
1347 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
1348 break;
1350 break;
1351 default:
1352 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
1353 break;
1357 /* Push element */
1358 if (child.tag != NPW_NO_TAG)
1360 NPWFileTag* new_child;
1362 new_child = g_slice_new (NPWFileTag);
1363 memcpy (new_child, &child, sizeof (child));
1364 g_queue_push_head (parser->tag, new_child);
1366 else
1368 g_free (child.source);
1369 g_free (child.destination);
1370 parser->unknown++;
1374 static void
1375 parse_file_end (GMarkupParseContext* context,
1376 const gchar* name,
1377 gpointer data,
1378 GError** error)
1380 NPWFileListParser* parser = (NPWFileListParser*)data;
1382 DEBUG_PRINT("parser_file_end");
1383 if (parser->unknown > 0)
1385 /* Pop unknown element */
1386 parser->unknown--;
1388 else if (((NPWFileTag *)g_queue_peek_head (parser->tag))->tag != NPW_NO_TAG)
1390 /* Pop known element */
1391 npw_file_tag_free (g_queue_pop_head (parser->tag));
1393 else
1395 /* Know stack underflow */
1396 g_return_if_reached ();
1400 static GMarkupParser file_markup_parser = {
1401 parse_file_start,
1402 parse_file_end,
1403 NULL,
1404 NULL,
1405 NULL
1408 NPWFileListParser*
1409 npw_file_list_parser_new (const gchar* filename)
1411 NPWFileListParser* parser;
1412 NPWFileTag* root;
1414 g_return_val_if_fail (filename != NULL, NULL);
1416 parser = g_new (NPWFileListParser, 1);
1418 parser->type = NPW_FILE_PARSER;
1420 parser->unknown = 0;
1421 parser->tag = g_queue_new ();
1422 root = g_slice_new0 (NPWFileTag);
1423 root->tag = NPW_NO_TAG;
1424 root->destination = g_strdup (".");
1425 /* Use .wiz file path as base source directory */
1426 root->source = g_path_get_dirname (filename);
1427 g_queue_push_head (parser->tag, root);
1429 parser->list = NULL;
1431 parser->ctx = g_markup_parse_context_new (&file_markup_parser, 0, parser, NULL);
1432 g_assert (parser->ctx != NULL);
1434 return parser;
1437 void
1438 npw_file_list_parser_free (NPWFileListParser* parser)
1440 g_return_if_fail (parser != NULL);
1442 g_markup_parse_context_free (parser->ctx);
1443 DEBUG_PRINT("parser free");
1444 g_queue_foreach (parser->tag, (GFunc)npw_file_tag_free, NULL);
1445 DEBUG_PRINT("parser free ok");
1446 g_queue_free (parser->tag);
1447 g_free (parser);
1450 gboolean
1451 npw_file_list_parser_parse (NPWFileListParser* parser, const gchar* text, gssize len, GError** error)
1453 return g_markup_parse_context_parse (parser->ctx, text, len, error);
1456 GList *
1457 npw_file_list_parser_end_parse (NPWFileListParser* parser, GError** error)
1459 GList *list = NULL;
1461 if (g_markup_parse_context_end_parse (parser->ctx, error))
1463 /* Reverse file list */
1464 parser->list = g_list_reverse (parser->list);
1466 list = parser->list;
1469 return list;
1472 /* Parse action block
1473 *---------------------------------------------------------------------------*/
1475 #define NPW_ACTION_PARSER_MAX_LEVEL 2 /* Maximum number of nested elements */
1477 struct _NPWActionListParser
1479 /* Type of parser (not used) */
1480 NPWParser type;
1481 GMarkupParseContext* ctx;
1482 /* Known element stack */
1483 NPWTag tag[NPW_ACTION_PARSER_MAX_LEVEL + 1];
1484 NPWTag* last;
1485 /* Unknown element stack */
1486 guint unknown;
1487 /* Current action list object */
1488 GList* list;
1491 static gboolean
1492 parse_run (NPWActionListParser* parser, const gchar** attributes, const gchar** values)
1494 const gchar* command = NULL;
1496 while (*attributes != NULL)
1498 switch (parse_attribute (*attributes))
1500 case NPW_COMMAND_ATTRIBUTE:
1501 command = *values;
1502 break;
1503 default:
1504 parser_warning (parser->ctx, "Unknown run attribute \"%s\"", *attributes);
1505 break;
1507 attributes++;
1508 values++;
1511 if (command == NULL)
1513 parser_warning (parser->ctx, "Missing command attribute");
1515 else
1517 NPWAction* action;
1519 action = npw_action_new_command (command);
1520 parser->list = g_list_prepend (parser->list, action);
1523 return TRUE;
1526 static gboolean
1527 parse_open (NPWActionListParser* parser, const gchar** attributes, const gchar** values)
1529 const gchar* file = NULL;
1531 while (*attributes != NULL)
1533 switch (parse_attribute (*attributes))
1535 case NPW_FILE_ATTRIBUTE:
1536 file = *values;
1537 break;
1538 default:
1539 parser_warning (parser->ctx, "Unknown open attribute \"%s\"", *attributes);
1540 break;
1542 attributes++;
1543 values++;
1546 if (file == NULL)
1548 parser_warning (parser->ctx, "Missing file attribute");
1550 else
1552 NPWAction* action;
1554 action = npw_action_new_file (file);
1555 parser->list = g_list_prepend (parser->list, action);
1558 return TRUE;
1561 static void
1562 parse_action_start (GMarkupParseContext* context, const gchar* name, const gchar** attributes,
1563 const gchar** values, gpointer data, GError** error)
1565 NPWActionListParser* parser = (NPWActionListParser*)data;
1566 NPWTag tag;
1567 gboolean known = FALSE;
1569 /* Recognize element */
1570 if (parser->unknown == 0)
1572 /* Not inside an unknown element */
1573 tag = parse_tag (name);
1574 switch (*parser->last)
1576 case NPW_NO_TAG:
1577 /* Top level element */
1578 switch (tag)
1580 case NPW_ACTION_TAG:
1581 known = TRUE;
1582 break;
1583 case NPW_UNKNOW_TAG:
1584 parser_warning (parser->ctx, "Unknown element \"%s\"", name);
1585 break;
1586 default:
1587 break;
1589 break;
1590 case NPW_ACTION_TAG:
1591 /* Necessary to avoid neested page element */
1592 switch (tag)
1594 case NPW_RUN_TAG:
1595 known = parse_run (parser, attributes, values);
1596 break;
1597 case NPW_OPEN_TAG:
1598 known = parse_open (parser, attributes, values);
1599 break;
1600 default:
1601 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
1602 break;
1604 break;
1605 default:
1606 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
1607 break;
1611 /* Push element */
1612 if (known)
1614 /* Know element stack overflow */
1615 g_return_if_fail ((parser->last - parser->tag) <= NPW_ACTION_PARSER_MAX_LEVEL);
1616 parser->last++;
1617 *parser->last = tag;
1619 else
1621 parser->unknown++;
1625 static void
1626 parse_action_end (GMarkupParseContext* context, const gchar* name, gpointer data, GError** error)
1628 NPWActionListParser* parser = (NPWActionListParser*)data;
1630 if (parser->unknown > 0)
1632 /* Pop unknown element */
1633 parser->unknown--;
1635 else if (*parser->last != NPW_NO_TAG)
1637 /* Pop known element */
1638 parser->last--;
1640 else
1642 /* Know element stack underflow */
1643 g_return_if_reached ();
1647 static GMarkupParser action_markup_parser = {
1648 parse_action_start,
1649 parse_action_end,
1650 NULL,
1651 NULL,
1652 NULL
1655 NPWActionListParser*
1656 npw_action_list_parser_new (void)
1658 NPWActionListParser* parser;
1660 parser = g_new (NPWActionListParser, 1);
1662 parser->type = NPW_ACTION_PARSER;
1664 parser->unknown = 0;
1665 parser->tag[0] = NPW_NO_TAG;
1666 parser->last = parser->tag;
1668 parser->list = NULL;
1670 parser->ctx = g_markup_parse_context_new (&action_markup_parser, 0, parser, NULL);
1671 g_assert (parser->ctx != NULL);
1673 return parser;
1676 void
1677 npw_action_list_parser_free (NPWActionListParser* parser)
1679 g_return_if_fail (parser != NULL);
1681 g_markup_parse_context_free (parser->ctx);
1682 g_free (parser);
1685 gboolean
1686 npw_action_list_parser_parse (NPWActionListParser* parser, const gchar* text, gssize len, GError** error)
1688 GError* err = NULL;
1690 g_markup_parse_context_parse (parser->ctx, text, len, &err);
1691 if (err != NULL)
1693 g_warning ("%s", err->message);
1696 return TRUE;
1699 GList*
1700 npw_action_list_parser_end_parse (NPWActionListParser* parser, GError** error)
1702 GList *list = NULL;
1704 if (g_markup_parse_context_end_parse (parser->ctx, error))
1706 /* Reverse file list */
1707 parser->list = g_list_reverse (parser->list);
1709 list = parser->list;
1712 return list;