Updated Spanish translation
[anjuta-git-plugin.git] / plugins / tools / fileop.c
blobd67e29e5f67df888c6f6569f7a528dcac8589568
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 fileop.c
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 *---------------------------------------------------------------------------*/
27 #include <config.h>
29 #include "fileop.h"
31 #include "tool.h"
33 #include <glib.h>
34 #include <libanjuta/anjuta-debug.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
41 /*---------------------------------------------------------------------------*/
43 typedef enum {
44 ATP_NO_TAG = 0,
45 ATP_ANJUTA_TOOLS_TAG,
46 ATP_TOOL_TAG,
47 ATP_COMMAND_TAG,
48 ATP_PARAM_TAG,
49 ATP_WORKING_DIR_TAG,
50 ATP_ENABLE_TAG,
51 ATP_AUTOSAVE_TAG,
52 ATP_TERMINAL_TAG,
53 ATP_OUTPUT_TAG,
54 ATP_ERROR_TAG,
55 ATP_INPUT_TAG,
56 ATP_INPUT_VALUE_TAG,
57 ATP_SHORTCUT_TAG,
58 ATP_ICON_TAG,
59 ATP_UNKNOW_TAG
60 } ATPTag;
62 typedef enum {
63 ATP_NO_ATTRIBUTE = 0,
64 ATP_NAME_ATTRIBUTE,
65 ATP_UNKNOW_ATTRIBUTE
66 } ATPAttribute;
68 /* Common parser functions
69 *---------------------------------------------------------------------------*/
71 static ATPTag
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)
80 return ATP_TOOL_TAG;
82 else if (strcmp ("command", name) == 0)
84 return ATP_COMMAND_TAG;
86 else if (strcmp ("parameter", name) == 0)
88 return ATP_PARAM_TAG;
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)
128 return ATP_ICON_TAG;
130 else
132 return ATP_UNKNOW_TAG;
136 static ATPAttribute
137 parse_attribute (const gchar* name)
139 if ((strcmp ("name", name) == 0) || (strcmp ("_name", name) == 0))
141 return ATP_NAME_ATTRIBUTE;
143 else
145 return ATP_UNKNOW_ATTRIBUTE;
149 static gboolean
150 parse_boolean_string (const gchar* value)
152 return g_ascii_strcasecmp ("no", value) && g_ascii_strcasecmp ("0", value) && g_ascii_strcasecmp ("false", value);
155 static gint
156 parse_integer_string (const gchar* value)
158 return atoi(value);
161 static void
162 parser_warning (GMarkupParseContext* ctx, const gchar* format,...)
164 va_list args;
165 gchar* msg;
166 gint line;
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);
172 va_end (args);
173 g_free (msg);
176 /* Load anjuta-tools
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];
186 ATPTag* last;
187 /* Unknown element stack */
188 guint unknown;
189 /* List where should be added the header */
190 ATPToolList* list;
191 /* Type of storage */
192 ATPToolStore storage;
193 /* Current header */
194 ATPUserTool* tool;
195 } ATPToolParser;
197 static void
198 parse_tool_start (GMarkupParseContext* context,
199 const gchar* name,
200 const gchar** attributes,
201 const gchar** values,
202 gpointer data,
203 GError** error)
205 ATPToolParser* parser = (ATPToolParser*)data;
206 ATPTag tag;
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)
217 case ATP_NO_TAG:
218 /* Top level element */
219 switch (tag)
221 case ATP_ANJUTA_TOOLS_TAG:
222 known = TRUE;
223 break;
224 case ATP_UNKNOW_TAG:
225 parser_warning (parser->ctx, "Unknown element \"%s\"", name);
226 break;
227 default:
228 break;
230 break;
231 case ATP_ANJUTA_TOOLS_TAG:
232 /* Necessary to avoid neested anjuta-tools element */
233 switch (tag)
235 case ATP_TOOL_TAG:
236 tool_name = NULL;
237 while (*attributes != NULL)
239 if (parse_attribute (*attributes) == ATP_NAME_ATTRIBUTE)
241 tool_name = *values;
243 attributes++;
244 values++;
246 if (tool_name == NULL)
248 parser_warning (parser->ctx, _("Missing tool name"));
249 break;
251 else
253 parser->tool = atp_tool_list_append_new (parser->list, tool_name, parser->storage);
254 known = TRUE;
256 break;
257 default:
258 parser_warning (parser->ctx, _("Unexpected element \"%s\""), name);
259 break;
261 break;
262 case ATP_TOOL_TAG:
263 switch (tag)
265 case ATP_COMMAND_TAG:
266 case ATP_PARAM_TAG:
267 case ATP_WORKING_DIR_TAG:
268 case ATP_ENABLE_TAG:
269 case ATP_AUTOSAVE_TAG:
270 case ATP_TERMINAL_TAG:
271 case ATP_OUTPUT_TAG:
272 case ATP_ERROR_TAG:
273 case ATP_INPUT_TAG:
274 case ATP_INPUT_VALUE_TAG:
275 case ATP_SHORTCUT_TAG:
276 case ATP_ICON_TAG:
277 known = TRUE;
278 break;
279 case ATP_UNKNOW_TAG:
280 /* No warning on unknown tags */
281 break;
282 default:
283 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
284 break;
286 break;
287 default:
288 parser_warning (parser->ctx, "Unexpected element \"%s\"", name);
289 break;
293 /* Push element */
294 if (known)
296 /* Know element stack overflow */
297 g_return_if_fail ((parser->last - parser->tag) <= ATP_TOOL_PARSER_MAX_LEVEL);
298 parser->last++;
299 *parser->last = tag;
301 else
303 parser->unknown++;
307 static void
308 parse_tool_end (GMarkupParseContext* context,
309 const gchar* name,
310 gpointer data,
311 GError** error)
313 ATPToolParser* parser = (ATPToolParser*)data;
315 if (parser->unknown > 0)
317 /* Pop unknown element */
318 parser->unknown--;
320 else if (*parser->last == ATP_TOOL_TAG)
322 /* Pop known element */
323 parser->last--;
325 /* Check if tool is valid */
326 if (atp_user_tool_is_valid (parser->tool) == FALSE)
328 /* Remove it */
329 atp_user_tool_free (parser->tool);
331 parser->tool = NULL;
333 else if (*parser->last != ATP_NO_TAG)
335 /* Pop known element */
336 parser->last--;
338 else
340 /* Know element stack underflow */
341 g_return_if_reached ();
345 static void
346 parse_tool_text (GMarkupParseContext* context,
347 const gchar* text,
348 gsize len,
349 gpointer data,
350 GError** error)
352 ATPToolParser* parser = (ATPToolParser*)data;
353 guint accel_key;
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);
364 break;
365 case ATP_PARAM_TAG:
366 g_return_if_fail (parser->tool);
368 atp_user_tool_set_param (parser->tool, text);
369 break;
370 case ATP_WORKING_DIR_TAG:
371 g_return_if_fail (parser->tool);
373 atp_user_tool_set_working_dir (parser->tool, text);
374 break;
375 case ATP_ENABLE_TAG:
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));
378 break;
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));
382 break;
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));
386 break;
387 case ATP_OUTPUT_TAG:
388 g_return_if_fail (parser->tool);
389 atp_user_tool_set_output (parser->tool, parse_integer_string (text));
390 break;
391 case ATP_ERROR_TAG:
392 g_return_if_fail (parser->tool);
393 atp_user_tool_set_error (parser->tool, parse_integer_string (text));
394 break;
395 case ATP_INPUT_TAG:
396 g_return_if_fail (parser->tool);
397 atp_user_tool_set_input (parser->tool, parse_integer_string (text), NULL);
398 break;
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);
402 break;
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);
407 break;
408 case ATP_ICON_TAG:
409 g_return_if_fail (parser->tool);
411 atp_user_tool_set_icon (parser->tool, text);
412 break;
413 case ATP_ANJUTA_TOOLS_TAG:
414 case ATP_TOOL_TAG:
415 case ATP_UNKNOW_TAG:
416 /* Nothing to do */
417 break;
418 default:
419 /* Unknown tag */
420 g_return_if_reached ();
421 break;
426 static GMarkupParser tool_markup_parser = {
427 parse_tool_start,
428 parse_tool_end,
429 parse_tool_text,
430 NULL,
431 NULL
434 static ATPToolParser*
435 atp_tool_parser_new (ATPToolList* list, ATPToolStore storage)
437 ATPToolParser* this;
439 this = g_new0 (ATPToolParser, 1);
441 this->unknown = 0;
442 this->tag[0] = ATP_NO_TAG;
443 this->last = this->tag;
445 this->list = list;
446 this->storage = storage;
447 this->tool = NULL;
449 this->ctx = g_markup_parse_context_new (&tool_markup_parser, 0, this, NULL);
450 g_assert (this->ctx != NULL);
452 return this;
455 static void
456 atp_tool_parser_free (ATPToolParser* this)
458 g_return_if_fail (this != NULL);
460 g_markup_parse_context_free (this->ctx);
461 g_free (this);
464 static gboolean
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);
470 static gboolean
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 */
478 static gboolean
479 atp_tool_list_load_from_file (ATPToolList* this, const gchar* filename, ATPToolStore storage)
481 gchar* content;
482 gsize len;
483 ATPToolParser* parser;
484 GError* err = NULL;
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 */
493 g_error_free (err);
495 return TRUE;
498 parser = atp_tool_parser_new (this, storage);
500 parser->tool = NULL;
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);
505 g_free (content);
507 if (err != NULL)
509 /* Parsing error */
510 g_warning (err->message);
511 g_error_free (err);
513 return FALSE;
516 return TRUE;
519 gboolean
520 atp_anjuta_tools_load(ATPPlugin* plugin)
522 gboolean ok;
523 gchar* file_name;
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);
529 g_free (file_name);
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);
534 g_free (file_name);
535 if (!ok)
537 anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (plugin)->shell),_("Error when loading external tools"));
538 return FALSE;
541 return TRUE;
544 /* Save tools file
545 *---------------------------------------------------------------------------*/
547 typedef const gchar* const_gchar_ptr;
549 static gboolean
550 write_xml_string (const gchar *value, const gchar *tag, const_gchar_ptr *head, FILE *f)
552 gchar* line;
554 if (value == NULL) return FALSE;
556 /* Check if we need the header */
557 if (*head != NULL)
559 if (value == NULL)
561 /* Use for writing tools without value */
562 line = g_markup_printf_escaped ("\t<tool name=\"%s\"/>\n", *head);
564 else
566 line = g_markup_printf_escaped ("\t<tool name=\"%s\">\n", *head);
568 fputs (line, f);
569 g_free (line);
570 *head = NULL;
573 if (value != NULL)
575 /* Write xml line */
576 line = g_markup_printf_escaped ("\t\t<%s>%s</%s>\n", tag, value, tag);
577 fputs (line, f);
578 g_free (line);
581 return TRUE;
584 static gboolean
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);
590 static gboolean
591 write_xml_integer (gint value, const gchar *tag, const_gchar_ptr *head, FILE *f)
593 gchar buffer[33];
595 sprintf (buffer,"%d", value);
597 return write_xml_string (buffer, tag, head, f);
600 static gboolean
601 write_xml_accelerator (guint key, GdkModifierType mods, const gchar *tag, const_gchar_ptr *head, FILE *f)
603 gchar* value;
604 gboolean ok;
606 value = gtk_accelerator_name (key, mods);
607 ok = write_xml_string (value, tag, head, f);
608 g_free (value);
610 return ok;
613 #define SAVE_STRING(func, key) \
615 const gchar* save; \
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) \
623 gboolean save; \
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) \
631 gint save; \
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) \
639 guint save_key; \
640 GdkModifierType save_mask; \
641 guint over_key; \
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 */
650 static gboolean
651 atp_user_tool_save (ATPUserTool *tool, FILE *f)
653 const gchar* head;
654 ATPUserTool *over;
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");
674 if (head == NULL)
676 fprintf (f, "\t</tool>\n");
678 return TRUE;
680 else
682 /* Force at least one line for the tool */
683 write_xml_string (NULL, NULL, &head, f);
685 return FALSE;
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)
694 FILE *f;
695 ATPUserTool *tool;
696 gchar* file_name;
697 gboolean ok;
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);
704 return FALSE;
706 fprintf (f, "<?xml version=\"1.0\"?>\n");
707 fprintf (f, "<anjuta-tools>\n");
708 ok = TRUE;
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");
715 fclose(f);
717 return TRUE;