1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
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
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
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"; }
43 * And the following template
45 * [+ AutoGen5 template +]
48 * IDX_[+ (string-upcase! (get "list_element")) +][+
49 * ENDFOR list +] } list_enum;
56 * IDX_OMEGA } list_enum;
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.
70 #include <libanjuta/anjuta-launcher.h>
71 #include <libanjuta/anjuta-autogen.h>
73 #include <glib/gi18n.h>
74 #include <glib/gstdio.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 /*---------------------------------------------------------------------------*/
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
103 GList
*library_paths
; /* List of paths for searching include files */
104 /* Output file name and handle used
105 * when autogen output is written
110 /* Call back function and data used
111 * when autogen output something */
112 AnjutaAutogenOutputFunc outfunc
;
114 GDestroyNotify destroy
;
116 /* Call back function and data used
117 * when autogen terminate */
118 AnjutaAutogenFunc endfunc
;
121 AnjutaLauncher
* launcher
;
122 gboolean busy
; /* For debugging */
125 struct _AnjutaAutogenClass
131 /*---------------------------------------------------------------------------*/
134 *---------------------------------------------------------------------------*/
137 * anjuta_check_autogen:
139 * Check if autogen version 5 is installed.
141 * Return value: %TRUE if autogen is installed.
145 anjuta_check_autogen (void)
147 gchar
* args
[] = {"autogen", "-v", NULL
};
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
))
155 gint ver
[3] = {0, 0, 0};
157 /* Check autogen 5 version string
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
);
187 *---------------------------------------------------------------------------*/
190 cb_autogen_write_key (const gchar
* name
, const gchar
*value
, gpointer user_data
)
192 FILE* def
= (FILE *)user_data
;
196 if(*value
== '{') /* Seems to be a list, so do not quote */
198 fprintf(def
, "%s = %s;\n", name
, value
);
202 gchar
*esc_value
= g_strescape (value
, NULL
);
203 fprintf (def
, "%s = \"%s\";\n", name
, 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
226 * Returns: %TRUE if the file has been written without error,
230 anjuta_autogen_write_definition_file (AnjutaAutogen
* this, GHashTable
* values
, GError
**error
)
234 /* Autogen should not be running */
237 g_set_error_literal (error
, G_FILE_ERROR
,
239 _("Autogen is busy"));
244 def
= fopen (this->deffilename
, "wt");
250 g_file_error_from_errno(errno
),
251 _("Could not write definition file \"%s\": %s"),
259 /* Generate definition data for autogen */
260 fputs ("AutoGen Definitions .;\n",def
);
261 g_hash_table_foreach (values
, (GHFunc
)cb_autogen_write_key
, def
);
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.
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.
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
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.
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:
338 * - "autogen5 template"
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.
352 anjuta_autogen_set_input_file (AnjutaAutogen
* this, const gchar
* filename
, const gchar
* start_marker
, const gchar
* end_marker
)
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
);
382 /* Autogen definition is missing, we need to create a temporary file
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
);
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
);
407 len
= fread (buffer
, 1, FILE_BUFFER_SIZE
, src
);
408 if ((len
!= FILE_BUFFER_SIZE
) && !feof (src
))
414 if (len
!= fwrite (buffer
, 1, len
, tpl
))
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.
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
;
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.
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
;
478 *---------------------------------------------------------------------------*/
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
);
494 if (this->outfunc
!= NULL
)
496 /* Call a callback function */
497 (this->outfunc
)(output
, this->outdata
);
502 on_autogen_terminated (AnjutaLauncher
* launcher
, gint pid
, gint status
, gulong time
, AnjutaAutogen
* this)
505 if (this->output
!= NULL
)
507 fclose (this->output
);
509 /* Delete empty file */
510 if (this->empty
== TRUE
)
512 g_remove (this->outfilename
);
518 (this->destroy
)(this->outdata
);
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.
540 anjuta_autogen_execute (AnjutaAutogen
* this, AnjutaAutogenFunc func
, gpointer data
, GError
** error
)
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 */
554 this->endfunc
= func
;
555 this->enddata
= data
;
559 this->endfunc
= NULL
;
561 args
= g_new (gchar
*, 5 + g_list_length (this->library_paths
) * 2);
564 for (path
= g_list_first (this->library_paths
); path
!= NULL
; path
= g_list_next (path
))
567 args
[arg
++] = (gchar
*)(path
->data
);
570 args
[arg
++] = (gchar
*)this->tplfilename
;
571 args
[arg
++] = (gchar
*)this->deffilename
;
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
)
584 g_file_error_from_errno(errno
),
585 _("Could not open file \"%s\": %s"),
596 /* The template and definition file are in UTF-8 so the output too */
597 anjuta_launcher_set_encoding (this->launcher
, "UTF-8");
600 if (!anjuta_launcher_execute_v (this->launcher
, NULL
, args
, NULL
, on_autogen_output
, this))
612 *---------------------------------------------------------------------------*/
614 G_DEFINE_TYPE (AnjutaAutogen
, anjuta_autogen
, G_TYPE_OBJECT
);
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
));
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
);
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
);
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
);