Fix Spanish translation header
[anjuta.git] / libanjuta / anjuta-autogen.c
blobed5ad92dab81a29122f31c36de47275f0b575e6a
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 anjuta-autogen.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 * SECTION:anjuta-autogen
23 * @title: AnjutaAutogen
24 * @short_description: Template engine using GNU autogen program.
25 * @see_also: #AnjutaLauncher
26 * @stability: Unstable
27 * @include: libanjuta/anjuta-autogen.h
29 * GNU autogen is a program generating a text file from a template and a
30 * definition file. The template contains fixed text and variables those will
31 * be replaced under the control of the definition file.
33 * By example from the following definition file
34 * <programlisting>
35 * AutoGen Definitions .;
36 * list = { list_element = alpha;
37 * list_info = "some alpha stuff"; };
38 * list = { list_info = "more beta stuff";
39 * list_element = beta; };
40 * list = { list_element = omega;
41 * list_info = "final omega stuff"; }
42 * </programlisting>
43 * And the following template
44 * <programlisting>
45 * [+ AutoGen5 template +]
46 * typedef enum {[+
47 * FOR list "," +]
48 * IDX_[+ (string-upcase! (get "list_element")) +][+
49 * ENDFOR list +] } list_enum;
50 * </programlisting>
51 * Autogen generates
52 * <programlisting>
53 * typedef enum {
54 * IDX_ALPHA,
55 * IDX_BETA,
56 * IDX_OMEGA } list_enum;
57 * </programlisting>
59 * The template file can be quite complex, you can read autogen documentation
60 * <ulink url="http://www.gnu.org/software/autogen">here</ulink>.
62 * The #AnjutaAutogen object takes care of writing the definition file from
63 * a hash table and call autogen. The output can be written in a file or passed
64 * to a callback function. Autogen is executed asynchronously, so there is
65 * another callback function called when the processing is completed.
68 #include <config.h>
70 #include <libanjuta/anjuta-launcher.h>
71 #include <libanjuta/anjuta-autogen.h>
73 #include <glib/gi18n.h>
74 #include <glib/gstdio.h>
75 #include <glib.h>
76 #include <errno.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <glib/gstdio.h>
82 /*---------------------------------------------------------------------------*/
84 #define TMP_DEF_FILENAME "NPWDEFXXXXXX"
85 #define TMP_TPL_FILENAME "NPWTPLXXXXXX"
87 #define FILE_BUFFER_SIZE 4096
89 #define TEMPLATES_DIR PACKAGE_DATA_DIR"/templates"
91 /*---------------------------------------------------------------------------*/
93 struct _AnjutaAutogen
95 GObject parent;
97 gchar* deffilename; /* name of generated definition file */
98 gchar* tplfilename; /* name of template (input) file */
99 const gchar* temptplfilename; /* name of generated template if the
100 * previous file doesn't contains
101 * autogen marker */
103 GList *library_paths; /* List of paths for searching include files */
104 /* Output file name and handle used
105 * when autogen output is written
106 * in a file */
107 gchar* outfilename;
108 FILE* output;
109 gboolean empty;
110 /* Call back function and data used
111 * when autogen output something */
112 AnjutaAutogenOutputFunc outfunc;
113 gpointer outdata;
114 GDestroyNotify destroy;
116 /* Call back function and data used
117 * when autogen terminate */
118 AnjutaAutogenFunc endfunc;
119 gpointer enddata;
121 AnjutaLauncher* launcher;
122 gboolean busy; /* For debugging */
125 struct _AnjutaAutogenClass
127 GObjectClass parent;
131 /*---------------------------------------------------------------------------*/
133 /* Helper functions
134 *---------------------------------------------------------------------------*/
137 * anjuta_check_autogen:
139 * Check if autogen version 5 is installed.
141 * Return value: %TRUE if autogen is installed.
144 gboolean
145 anjuta_check_autogen (void)
147 gchar* args[] = {"autogen", "-v", NULL};
148 gchar* output;
150 if (g_spawn_sync (NULL, args, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
151 NULL, NULL, &output, NULL, NULL, NULL))
153 GRegex *re;
154 GMatchInfo *minfo;
155 gint ver[3] = {0, 0, 0};
157 /* Check autogen 5 version string
158 * Examples:
159 * autogen - The Automated Program Generator - Ver. 5.5.7
160 * autogen (GNU AutoGen) - The Automated Program Generator - Ver. 5.11
161 * autogen (GNU AutoGen) 5.11.9
163 re = g_regex_new ("autogen.* (\\d+)\\.(\\d+)(?:\\.(\\d+))?", 0, 0, NULL);
164 g_regex_match (re, output, 0, &minfo);
165 if (g_match_info_matches (minfo)) {
166 gchar **match_strings;
168 match_strings = g_match_info_fetch_all (minfo);
169 ver[0] = g_ascii_strtoll (match_strings[1], NULL, 10);
170 ver[1] = g_ascii_strtoll (match_strings[2], NULL, 10);
171 if (match_strings[3] != NULL) ver[2] = g_ascii_strtoll (match_strings[3], NULL, 10);
173 g_strfreev (match_strings);
175 g_match_info_free (minfo);
176 g_regex_unref (re);
178 return ver[0] == 5;
181 return FALSE;
186 /* Write definitions
187 *---------------------------------------------------------------------------*/
189 static void
190 cb_autogen_write_key (const gchar* name, const gchar *value, gpointer user_data)
192 FILE* def = (FILE *)user_data;
194 if (value != NULL)
196 if(*value == '{') /* Seems to be a list, so do not quote */
198 fprintf(def, "%s = %s;\n", name, value);
200 else
202 gchar *esc_value = g_strescape (value, NULL);
203 fprintf (def, "%s = \"%s\";\n", name, esc_value);
204 g_free (esc_value);
210 * anjuta_autogen_write_definition_file:
211 * @this: A #AnjutaAutogen object
212 * @values: (element-type utf8 utf8): A hash table containing all definitions
213 * @error: Error propagation and reporting
215 * Write the autogen definition file. The definition file defined variables
216 * those will be used, typically replaced, in the template files.
218 * The hash table keys are the names of the variables. The name can include an
219 * index in square bracket, by example "members[0]". All values are strings but
220 * but they could include children using braces, by example
221 * "{count=2; list="aa bb"}".
223 * The file is created in a temporary directory and removed when the object
224 * is destroyed.
226 * Returns: %TRUE if the file has been written without error,
229 gboolean
230 anjuta_autogen_write_definition_file (AnjutaAutogen* this, GHashTable* values, GError **error)
232 FILE* def;
234 /* Autogen should not be running */
235 if (this->busy)
237 g_set_error_literal (error, G_FILE_ERROR,
238 G_FILE_ERROR_AGAIN,
239 _("Autogen is busy"));
241 return FALSE;
244 def = fopen (this->deffilename, "wt");
245 if (def == NULL)
247 g_set_error(
248 error,
249 G_FILE_ERROR,
250 g_file_error_from_errno(errno),
251 _("Could not write definition file \"%s\": %s"),
252 this->deffilename,
253 g_strerror(errno)
256 return FALSE;
259 /* Generate definition data for autogen */
260 fputs ("AutoGen Definitions .;\n",def);
261 g_hash_table_foreach (values, (GHFunc)cb_autogen_write_key, def);
263 fclose (def);
265 return TRUE;
268 /* Set library path
269 *---------------------------------------------------------------------------*/
272 * anjuta_autogen_set_library_path:
273 * @this: A #AnjutaAutogen object
274 * @directory: A path containing autogen library.
276 * Add a new directory in the list of autogen libraries path.
278 * Autogen can include files. These included file will be searched by default
279 * in the same directory than the template file. This functions allows you to
280 * add other directories.
283 void
284 anjuta_autogen_set_library_path (AnjutaAutogen* this, const gchar *directory)
286 g_return_if_fail (directory != NULL);
288 this->library_paths = g_list_prepend (this->library_paths, g_strdup (directory));
292 * anjuta_autogen_clear_library_path:
293 * @this: A #AnjutaAutogen object
295 * Remove all library pathes.
298 void
299 anjuta_autogen_clear_library_path (AnjutaAutogen* this)
301 g_list_foreach (this->library_paths, (GFunc)g_free, NULL);
302 g_list_free (this->library_paths);
303 this->library_paths = NULL;
307 * anjuta_autogen_get_library_paths:
308 * @this: A #AnjutaAutogen object
310 * Get the list of all directories searched for files included in the autogen
311 * templates.
313 * Returns: (element-type gchar*) (transfer none): A list of directories.
314 * The content and the list itself are owned by the #AnjutaAutogen object and
315 * should not be modified or freed.
318 GList *
319 anjuta_autogen_get_library_paths (AnjutaAutogen* this)
321 return this->library_paths;
324 /* Set input and output
325 *---------------------------------------------------------------------------*/
328 * anjuta_autogen_set_input_file:
329 * @this: A #AnjutaAutogen object
330 * @filename: name of the input template file
331 * @start_marker: (allow-none): start marker string
332 * @end_marker: (allow-none): end marker string
334 * Read an autogen template file, optionally adding autogen markers.
336 * To be recognized as an autogen template, the first line has to contain:
337 * - the start marker
338 * - "autogen5 template"
339 * - the end marker
341 * These markers are a custom sequence of up to 7 characters delimiting
342 * the start and the end of autogen variables and macros.
344 * This function can add this line using the value of @start_marker and
345 * @end_marker. If this line is already present in the file,
346 * @start_marker and @end_marker must be %NULL.
348 * Returns: %TRUE if the file has been read without error.
351 gboolean
352 anjuta_autogen_set_input_file (AnjutaAutogen* this, const gchar* filename, const gchar* start_marker, const gchar* end_marker)
354 FILE* tpl;
355 FILE* src;
356 gboolean ok;
357 gchar* buffer;
358 guint len;
360 /* Autogen should not be running */
361 g_return_val_if_fail (this->busy == FALSE, FALSE);
363 /* We need to specify start and end marker or nothing */
364 g_return_val_if_fail ((start_marker && end_marker) || (!start_marker && !end_marker), FALSE);
366 /* Remove previous temporary file if exist */
367 if (this->temptplfilename != NULL)
369 remove (this->temptplfilename);
370 this->temptplfilename = NULL;
372 g_free (this->tplfilename);
374 if ((start_marker == NULL) && (end_marker == NULL))
376 /* input file is really an autogen file, nothig do to */
377 this->tplfilename = g_strdup (filename);
379 return TRUE;
382 /* Autogen definition is missing, we need to create a temporary file
383 * with them */
385 /* Create temporary file */
386 this->tplfilename = g_build_filename (g_get_tmp_dir (), TMP_TPL_FILENAME, NULL);
387 mktemp (this->tplfilename);
388 this->temptplfilename = this->tplfilename;
389 tpl = fopen (this->tplfilename, "wt");
390 if (tpl == NULL) return FALSE;
392 /* Add autogen definition */
393 fputs (start_marker, tpl);
394 fputs (" autogen5 template ", tpl);
395 fputs (end_marker, tpl);
396 fputc ('\n', tpl);
398 /* Copy source file into this new file */
399 src = fopen (filename, "rb");
400 if (src == NULL) return FALSE;
402 buffer = g_new (gchar, FILE_BUFFER_SIZE);
404 ok = TRUE;
405 for (;!feof (src);)
407 len = fread (buffer, 1, FILE_BUFFER_SIZE, src);
408 if ((len != FILE_BUFFER_SIZE) && !feof (src))
410 ok = FALSE;
411 break;
414 if (len != fwrite (buffer, 1, len, tpl))
416 ok = FALSE;
417 break;
421 g_free (buffer);
422 fclose (src);
423 fclose (tpl);
425 return ok;
429 * anjuta_autogen_set_output_file:
430 * @this: A #AnjutaAutogen object
431 * @filename: name of the generated file
433 * Define the name of the generated file.
435 * Returns: %TRUE if the file has been set without error.
438 gboolean
439 anjuta_autogen_set_output_file (AnjutaAutogen* this, const gchar* filename)
441 /* Autogen should not be running */
442 g_return_val_if_fail (this->busy == FALSE, FALSE);
444 g_free (this->outfilename);
445 this->outfilename = g_strdup (filename);
446 this->outfunc = NULL;
448 return TRUE;
452 * anjuta_autogen_set_output_callback:
453 * @this: A #AnjutaAutogen object
454 * @func: Function call each time we get new data from autogen
455 * @user_data: (allow-none): User data to pass to @func, or %NULL
456 * @destroy: Function call when the process is complete to free user data
458 * Define that autogen output should be send to a function as soon as it arrives.
460 * Returns: %TRUE if there is no error.
463 gboolean
464 anjuta_autogen_set_output_callback (AnjutaAutogen* this, AnjutaAutogenOutputFunc func, gpointer user_data, GDestroyNotify destroy)
466 /* Autogen should not be running */
467 g_return_val_if_fail (this->busy == FALSE, FALSE);
469 this->outfunc = func;
470 this->outdata = user_data;
471 this->destroy = destroy;
472 this->outfilename = NULL;
474 return TRUE;
477 /* Execute autogen
478 *---------------------------------------------------------------------------*/
480 static void
481 on_autogen_output (AnjutaLauncher* launcher, AnjutaLauncherOutputType type, const gchar* output, gpointer user_data)
483 AnjutaAutogen* this = (AnjutaAutogen*)user_data;
485 if (this->outfilename != NULL)
487 /* Write output in a file */
488 if (this->output != NULL)
490 fputs (output, this->output);
491 this->empty = FALSE;
494 if (this->outfunc != NULL)
496 /* Call a callback function */
497 (this->outfunc)(output, this->outdata);
501 static void
502 on_autogen_terminated (AnjutaLauncher* launcher, gint pid, gint status, gulong time, AnjutaAutogen* this)
504 this->busy = FALSE;
505 if (this->output != NULL)
507 fclose (this->output);
508 this->output = NULL;
509 /* Delete empty file */
510 if (this->empty == TRUE)
512 g_remove (this->outfilename);
516 if (this->destroy)
518 (this->destroy)(this->outdata);
520 if (this->endfunc)
522 (this->endfunc)(this, this->enddata);
527 * anjuta_autogen_execute:
528 * @this: A #AnjutaAutogen object
529 * @func: (scope async) (allow-none): A function called when autogen is terminated
530 * @data: (allow-none): User data to pass to @func, or %NULL
531 * @error: (allow-none): Error propagation and reporting
533 * Asynchronously execute autogen to generate the output, calling @func when the
534 * process is completed.
536 * Returns: %TRUE if the file has been processed without error.
539 gboolean
540 anjuta_autogen_execute (AnjutaAutogen* this, AnjutaAutogenFunc func, gpointer data, GError** error)
542 gchar** args;
543 guint arg;
544 GList *path;
546 /* Autogen should not be running */
547 g_return_val_if_fail (this->busy == FALSE, FALSE);
548 g_return_val_if_fail (this, FALSE);
549 g_return_val_if_fail (this->launcher, FALSE);
551 /* Set output end callback */
552 if (func != NULL)
554 this->endfunc = func;
555 this->enddata = data;
557 else
559 this->endfunc = NULL;
561 args = g_new (gchar *, 5 + g_list_length (this->library_paths) * 2);
562 args[0] = "autogen";
563 arg = 1;
564 for (path = g_list_first (this->library_paths); path != NULL; path = g_list_next (path))
566 args[arg++] = "-L";
567 args[arg++] = (gchar *)(path->data);
569 args[arg++] = "-T";
570 args[arg++] = (gchar *)this->tplfilename;
571 args[arg++] = (gchar *)this->deffilename;
572 args[arg] = NULL;
574 /* Check if output file can be written */
575 if (this->outfilename != NULL)
577 /* Open file if it's not already done */
578 this->output = fopen (this->outfilename, "wt");
579 if (this->output == NULL)
581 g_set_error(
582 error,
583 G_FILE_ERROR,
584 g_file_error_from_errno(errno),
585 _("Could not open file \"%s\": %s"),
586 this->outfilename,
587 g_strerror(errno)
589 g_free (args);
591 return FALSE;
593 this->empty = TRUE;
596 /* The template and definition file are in UTF-8 so the output too */
597 anjuta_launcher_set_encoding (this->launcher, "UTF-8");
599 this->busy = TRUE;
600 if (!anjuta_launcher_execute_v (this->launcher, NULL, args, NULL, on_autogen_output, this))
602 g_free (args);
604 return FALSE;
606 g_free (args);
608 return TRUE;
611 /* Implement GObject
612 *---------------------------------------------------------------------------*/
614 G_DEFINE_TYPE (AnjutaAutogen, anjuta_autogen, G_TYPE_OBJECT);
616 static void
617 anjuta_autogen_init (AnjutaAutogen *this)
619 this->launcher = anjuta_launcher_new ();
620 g_signal_connect (G_OBJECT (this->launcher), "child-exited", G_CALLBACK (on_autogen_terminated), this);
622 /* Create a temporary file for definitions */
623 this->deffilename = g_build_filename (g_get_tmp_dir (), TMP_DEF_FILENAME, NULL);
624 mktemp (this->deffilename);
626 this->library_paths = g_list_prepend (NULL, g_strdup (TEMPLATES_DIR));
629 static void
630 anjuta_autogen_dispose (GObject *object)
632 AnjutaAutogen *this = ANJUTA_AUTOGEN (object);
634 if (this->output != NULL)
636 /* output is not used if a callback function is used */
637 fclose (this->output);
638 this->output = NULL;
641 if (this->outfilename != NULL)
643 g_free (this->outfilename);
644 this->outfilename = NULL;
647 if (this->tplfilename != NULL)
649 g_free (this->tplfilename);
650 this->tplfilename = NULL;
653 if (this->temptplfilename != NULL)
655 /* temptplfilename is not used if input file already
656 * contains autogen marker */
657 remove (this->temptplfilename);
658 this->temptplfilename = NULL;
661 g_list_foreach (this->library_paths, (GFunc)g_free, NULL);
662 g_list_free (this->library_paths);
663 this->library_paths = NULL;
665 if (this->deffilename != NULL)
667 remove (this->deffilename);
668 g_free (this->deffilename);
669 this->deffilename = NULL;
672 if (this->launcher != NULL)
674 g_signal_handlers_disconnect_by_func (G_OBJECT (this->launcher), G_CALLBACK (on_autogen_terminated), this);
675 g_object_unref (this->launcher);
676 this->launcher = NULL;
679 G_OBJECT_CLASS (anjuta_autogen_parent_class)->dispose (object);
682 static void
683 anjuta_autogen_class_init (AnjutaAutogenClass *klass)
685 GObjectClass* object_class = G_OBJECT_CLASS (klass);
687 object_class->dispose = anjuta_autogen_dispose;
691 /* Creation and Destruction
692 *---------------------------------------------------------------------------*/
695 * anjuta_autogen_new:
697 * Create a new autogen object.
699 * Returns: (transfer full): A new #AnjutaAutogen object. Free it using g_object_unref.
702 AnjutaAutogen* anjuta_autogen_new (void)
704 return g_object_new (ANJUTA_TYPE_AUTOGEN, NULL);