1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 Copyright (C) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Load and save tools.xml files. It is quite close but not compatible with
23 * the previous tools.xml file from Anjuta 1.2.
25 *---------------------------------------------------------------------------*/
34 #include <libanjuta/anjuta-debug.h>
41 /*---------------------------------------------------------------------------*/
68 /* Common parser functions
69 *---------------------------------------------------------------------------*/
72 parse_tag (const gchar
* name
)
74 if (strcmp (name
, "anjuta-tools") == 0)
76 return ATP_ANJUTA_TOOLS_TAG
;
78 else if (strcmp ("tool", name
) == 0)
82 else if (strcmp ("command", name
) == 0)
84 return ATP_COMMAND_TAG
;
86 else if (strcmp ("parameter", name
) == 0)
90 else if (strcmp ("working_dir", name
) == 0)
92 return ATP_WORKING_DIR_TAG
;
94 else if (strcmp ("enabled", name
) == 0)
96 return ATP_ENABLE_TAG
;
98 else if (strcmp ("autosave", name
) == 0)
100 return ATP_AUTOSAVE_TAG
;
102 else if (strcmp ("run_in_terminal", name
) == 0)
104 return ATP_TERMINAL_TAG
;
106 else if (strcmp ("output", name
) == 0)
108 return ATP_OUTPUT_TAG
;
110 else if (strcmp ("error", name
) == 0)
112 return ATP_ERROR_TAG
;
114 else if (strcmp ("input_type", name
) == 0)
116 return ATP_INPUT_TAG
;
118 else if (strcmp ("input", name
) == 0)
120 return ATP_INPUT_VALUE_TAG
;
122 else if (strcmp ("shortcut", name
) == 0)
124 return ATP_SHORTCUT_TAG
;
126 else if (strcmp ("icon", name
) == 0)
132 return ATP_UNKNOW_TAG
;
137 parse_attribute (const gchar
* name
)
139 if ((strcmp ("name", name
) == 0) || (strcmp ("_name", name
) == 0))
141 return ATP_NAME_ATTRIBUTE
;
145 return ATP_UNKNOW_ATTRIBUTE
;
150 parse_boolean_string (const gchar
* value
)
152 return g_ascii_strcasecmp ("no", value
) && g_ascii_strcasecmp ("0", value
) && g_ascii_strcasecmp ("false", value
);
156 parse_integer_string (const gchar
* value
)
162 parser_warning (GMarkupParseContext
* ctx
, const gchar
* format
,...)
168 g_markup_parse_context_get_position (ctx
, &line
, NULL
);
169 msg
= g_strdup_printf ("line %d: %s", line
, format
);
170 va_start (args
, format
);
171 g_logv (G_LOG_DOMAIN
, G_LOG_LEVEL_WARNING
, msg
, args
);
177 *---------------------------------------------------------------------------*/
179 #define ATP_TOOL_PARSER_MAX_LEVEL 3 /* Maximum number of nested elements */
181 typedef struct _ATPToolParser
183 GMarkupParseContext
* ctx
;
184 /* Known element stack */
185 ATPTag tag
[ATP_TOOL_PARSER_MAX_LEVEL
+ 1];
187 /* Unknown element stack */
189 /* List where should be added the header */
191 /* Type of storage */
192 ATPToolStore storage
;
198 parse_tool_start (GMarkupParseContext
* context
,
200 const gchar
** attributes
,
201 const gchar
** values
,
205 ATPToolParser
* parser
= (ATPToolParser
*)data
;
207 gboolean known
= FALSE
;
208 const gchar
* tool_name
;
210 /* Recognize element */
211 if (parser
->unknown
== 0)
213 /* Not inside an unknown element */
214 tag
= parse_tag (name
);
215 switch (*parser
->last
)
218 /* Top level element */
221 case ATP_ANJUTA_TOOLS_TAG
:
225 parser_warning (parser
->ctx
, "Unknown element \"%s\"", name
);
231 case ATP_ANJUTA_TOOLS_TAG
:
232 /* Necessary to avoid neested anjuta-tools element */
237 while (*attributes
!= NULL
)
239 if (parse_attribute (*attributes
) == ATP_NAME_ATTRIBUTE
)
246 if (tool_name
== NULL
)
248 parser_warning (parser
->ctx
, _("Missing tool name"));
253 parser
->tool
= atp_tool_list_append_new (parser
->list
, tool_name
, parser
->storage
);
258 parser_warning (parser
->ctx
, _("Unexpected element \"%s\""), name
);
265 case ATP_COMMAND_TAG
:
267 case ATP_WORKING_DIR_TAG
:
269 case ATP_AUTOSAVE_TAG
:
270 case ATP_TERMINAL_TAG
:
274 case ATP_INPUT_VALUE_TAG
:
275 case ATP_SHORTCUT_TAG
:
280 /* No warning on unknown tags */
283 parser_warning (parser
->ctx
, "Unexpected element \"%s\"", name
);
288 parser_warning (parser
->ctx
, "Unexpected element \"%s\"", name
);
296 /* Know element stack overflow */
297 g_return_if_fail ((parser
->last
- parser
->tag
) <= ATP_TOOL_PARSER_MAX_LEVEL
);
308 parse_tool_end (GMarkupParseContext
* context
,
313 ATPToolParser
* parser
= (ATPToolParser
*)data
;
315 if (parser
->unknown
> 0)
317 /* Pop unknown element */
320 else if (*parser
->last
== ATP_TOOL_TAG
)
322 /* Pop known element */
325 /* Check if tool is valid */
326 if (atp_user_tool_is_valid (parser
->tool
) == FALSE
)
329 atp_user_tool_free (parser
->tool
);
333 else if (*parser
->last
!= ATP_NO_TAG
)
335 /* Pop known element */
340 /* Know element stack underflow */
341 g_return_if_reached ();
346 parse_tool_text (GMarkupParseContext
* context
,
352 ATPToolParser
* parser
= (ATPToolParser
*)data
;
354 GdkModifierType accel_mods
;
356 if (parser
->unknown
== 0)
358 switch (*parser
->last
)
360 case ATP_COMMAND_TAG
:
361 g_return_if_fail (parser
->tool
);
363 atp_user_tool_set_command (parser
->tool
, text
);
366 g_return_if_fail (parser
->tool
);
368 atp_user_tool_set_param (parser
->tool
, text
);
370 case ATP_WORKING_DIR_TAG
:
371 g_return_if_fail (parser
->tool
);
373 atp_user_tool_set_working_dir (parser
->tool
, text
);
376 g_return_if_fail (parser
->tool
);
377 atp_user_tool_set_flag (parser
->tool
, ATP_TOOL_ENABLE
| (parse_boolean_string (text
) ? ATP_SET
: ATP_CLEAR
));
379 case ATP_AUTOSAVE_TAG
:
380 g_return_if_fail (parser
->tool
);
381 atp_user_tool_set_flag (parser
->tool
, ATP_TOOL_AUTOSAVE
| (parse_boolean_string (text
) ? ATP_SET
: ATP_CLEAR
));
383 case ATP_TERMINAL_TAG
:
384 g_return_if_fail (parser
->tool
);
385 atp_user_tool_set_flag (parser
->tool
, ATP_TOOL_TERMINAL
| (parse_boolean_string (text
) ? ATP_SET
: ATP_CLEAR
));
388 g_return_if_fail (parser
->tool
);
389 atp_user_tool_set_output (parser
->tool
, parse_integer_string (text
));
392 g_return_if_fail (parser
->tool
);
393 atp_user_tool_set_error (parser
->tool
, parse_integer_string (text
));
396 g_return_if_fail (parser
->tool
);
397 atp_user_tool_set_input (parser
->tool
, parse_integer_string (text
), NULL
);
399 case ATP_INPUT_VALUE_TAG
:
400 g_return_if_fail (parser
->tool
);
401 atp_user_tool_set_input (parser
->tool
, atp_user_tool_get_input (parser
->tool
), text
);
403 case ATP_SHORTCUT_TAG
:
404 g_return_if_fail (parser
->tool
);
405 gtk_accelerator_parse (text
, &accel_key
, &accel_mods
);
406 atp_user_tool_set_accelerator (parser
->tool
, accel_key
, accel_mods
);
409 g_return_if_fail (parser
->tool
);
411 atp_user_tool_set_icon (parser
->tool
, text
);
413 case ATP_ANJUTA_TOOLS_TAG
:
420 g_return_if_reached ();
426 static GMarkupParser tool_markup_parser
= {
434 static ATPToolParser
*
435 atp_tool_parser_new (ATPToolList
* list
, ATPToolStore storage
)
439 this = g_new0 (ATPToolParser
, 1);
442 this->tag
[0] = ATP_NO_TAG
;
443 this->last
= this->tag
;
446 this->storage
= storage
;
449 this->ctx
= g_markup_parse_context_new (&tool_markup_parser
, 0, this, NULL
);
450 g_assert (this->ctx
!= NULL
);
456 atp_tool_parser_free (ATPToolParser
* this)
458 g_return_if_fail (this != NULL
);
460 g_markup_parse_context_free (this->ctx
);
465 atp_tool_parser_parse (ATPToolParser
* this, const gchar
* text
, gssize len
, GError
** error
)
467 return g_markup_parse_context_parse (this->ctx
, text
, len
, error
);
471 atp_tool_parser_end_parse (ATPToolParser
* this, GError
** error
)
473 return g_markup_parse_context_end_parse (this->ctx
, error
);
476 /* Loads toolset from a xml configuration file.
477 * Tools properties are saved xml format */
479 atp_tool_list_load_from_file (ATPToolList
* this, const gchar
* filename
, ATPToolStore storage
)
483 ATPToolParser
* parser
;
486 g_return_val_if_fail (this != NULL
, FALSE
);
487 g_return_val_if_fail (filename
!= NULL
, FALSE
);
489 if (!g_file_get_contents (filename
, &content
, &len
, &err
))
491 /* This is not an error condition since the user might not have
492 ** defined any tools, or there might not be any global tools */
498 parser
= atp_tool_parser_new (this, storage
);
501 atp_tool_parser_parse (parser
, content
, len
, &err
);
502 if (err
== NULL
) atp_tool_parser_end_parse (parser
, &err
);
504 atp_tool_parser_free (parser
);
510 g_warning (err
->message
);
520 atp_anjuta_tools_load(ATPPlugin
* plugin
)
525 /* First, load global tools */
526 file_name
= g_build_filename (ANJUTA_TOOLS_DIRECTORY
, TOOLS_FILE
, NULL
);
527 DEBUG_PRINT ("Loading system tools: %s", file_name
);
528 ok
= atp_tool_list_load_from_file (atp_plugin_get_tool_list(plugin
), file_name
, ATP_TSTORE_GLOBAL
);
531 /* Now, user tools */
532 file_name
= g_build_filename (g_get_home_dir(), LOCAL_ANJUTA_TOOLS_DIRECTORY
, TOOLS_FILE
, NULL
);
533 ok
= atp_tool_list_load_from_file (atp_plugin_get_tool_list(plugin
), file_name
, ATP_TSTORE_LOCAL
);
537 anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (plugin
)->shell
),_("Error when loading external tools"));
545 *---------------------------------------------------------------------------*/
547 typedef const gchar
* const_gchar_ptr
;
550 write_xml_string (const gchar
*value
, const gchar
*tag
, const_gchar_ptr
*head
, FILE *f
)
554 if (value
== NULL
) return FALSE
;
556 /* Check if we need the header */
561 /* Use for writing tools without value */
562 line
= g_markup_printf_escaped ("\t<tool name=\"%s\"/>\n", *head
);
566 line
= g_markup_printf_escaped ("\t<tool name=\"%s\">\n", *head
);
576 line
= g_markup_printf_escaped ("\t\t<%s>%s</%s>\n", tag
, value
, tag
);
585 write_xml_boolean (gboolean value
, const gchar
*tag
, const_gchar_ptr
*head
, FILE *f
)
587 return write_xml_string (value
? "1" : "0", tag
, head
, f
);
591 write_xml_integer (gint value
, const gchar
*tag
, const_gchar_ptr
*head
, FILE *f
)
595 sprintf (buffer
,"%d", value
);
597 return write_xml_string (buffer
, tag
, head
, f
);
601 write_xml_accelerator (guint key
, GdkModifierType mods
, const gchar
*tag
, const_gchar_ptr
*head
, FILE *f
)
606 value
= gtk_accelerator_name (key
, mods
);
607 ok
= write_xml_string (value
, tag
, head
, f
);
613 #define SAVE_STRING(func, key) \
616 save = atp_user_tool_get_##func (tool); \
617 if (!over || (save != atp_user_tool_get_##func (over))) \
618 write_xml_string (save, key, &head, f); \
621 #define SAVE_FLAG(flag, key) \
624 save = atp_user_tool_get_flag (tool, flag); \
625 if (!over || (save != atp_user_tool_get_flag (over, flag))) \
626 write_xml_boolean (save, key, &head, f); \
629 #define SAVE_INTEGER(func, key) \
632 save = atp_user_tool_get_##func (tool); \
633 if (!over || (save != atp_user_tool_get_##func (over))) \
634 write_xml_integer (save, key, &head, f); \
637 #define SAVE_ACCELERATOR(func, key) \
640 GdkModifierType save_mask; \
642 GdkModifierType over_mask; \
643 atp_user_tool_get_##func (tool, &save_key, &save_mask); \
644 if (over) atp_user_tool_get_##func (over, &over_key, &over_mask); \
645 if (!over || (save_key != over_key) || (save_mask != over_mask)) \
646 write_xml_accelerator (save_key, save_mask, key, &head, f); \
649 /* Writes tool information to the given file in xml format */
651 atp_user_tool_save (ATPUserTool
*tool
, FILE *f
)
656 /* head contains the tool name until the tool header is written */
657 head
= atp_user_tool_get_name (tool
);
659 over
= atp_user_tool_override (tool
);
661 SAVE_STRING (command
, "command");
662 SAVE_STRING (param
, "parameter");
663 SAVE_STRING (working_dir
, "working_dir");
664 SAVE_FLAG (ATP_TOOL_ENABLE
, "enabled");
665 SAVE_FLAG (ATP_TOOL_AUTOSAVE
, "autosave");
666 SAVE_FLAG (ATP_TOOL_TERMINAL
, "run_in_terminal");
667 SAVE_INTEGER (output
, "output");
668 SAVE_INTEGER (error
, "error");
669 SAVE_INTEGER (input
, "input_type");
670 SAVE_STRING (input_string
, "input");
671 SAVE_ACCELERATOR (accelerator
, "shortcut");
672 SAVE_STRING (icon
, "icon");
676 fprintf (f
, "\t</tool>\n");
682 /* Force at least one line for the tool */
683 write_xml_string (NULL
, NULL
, &head
, f
);
689 /* While saving, save only the user tools since it is unlikely that the
690 ** user will have permission to write to the system-wide tools file
692 gboolean
atp_anjuta_tools_save(ATPPlugin
* plugin
)
699 /* Save local tools */
700 file_name
= g_build_filename (g_get_home_dir(), LOCAL_ANJUTA_TOOLS_DIRECTORY
, TOOLS_FILE
, NULL
);
701 if (NULL
== (f
= fopen(file_name
, "w")))
703 anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (plugin
)->shell
),_("Unable to open %s for writing"), file_name
);
706 fprintf (f
, "<?xml version=\"1.0\"?>\n");
707 fprintf (f
, "<anjuta-tools>\n");
709 for (tool
= atp_tool_list_first_in_storage (atp_plugin_get_tool_list(plugin
), ATP_TSTORE_LOCAL
); tool
!= NULL
; tool
= atp_user_tool_next_in_same_storage(tool
))
711 /* Tool is in local storage, save it */
712 atp_user_tool_save(tool
, f
);
714 fprintf (f
, "</anjuta-tools>\n");