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 * Execute autogen program
24 * This takes cares of everything needed to run autogen:
25 * - generate the definition files from a list of values
26 * - add autogen marker in template file if necessary
27 * - check autogen version
28 * - run autogen with AnjutaLauncher object
29 * Autogen output could be written in a file or pass to callback function.
30 *---------------------------------------------------------------------------*/
34 #include <libanjuta/anjuta-launcher.h>
35 #include <libanjuta/anjuta-autogen.h>
37 #include <glib/gi18n.h>
38 #include <glib/gstdio.h>
44 #include <glib/gstdio.h>
46 /*---------------------------------------------------------------------------*/
48 #define TMP_DEF_FILENAME "NPWDEFXXXXXX"
49 #define TMP_TPL_FILENAME "NPWTPLXXXXXX"
51 #define FILE_BUFFER_SIZE 4096
53 /*---------------------------------------------------------------------------*/
57 gchar
* deffilename
; /* name of generated definition file */
58 const gchar
* tplfilename
; /* name of template (input) file */
59 gchar
* temptplfilename
; /* name of generated template if the
60 * previous file doesn't contains
63 GList
*library_paths
; /* List of paths for searching include files */
64 /* Output file name and handle used
65 * when autogen output is written
67 const gchar
* outfilename
;
70 /* Call back function and data used
71 * when autogen output something */
72 AnjutaAutogenOutputFunc outfunc
;
74 /* Call back function and data used
75 * when autogen terminate */
76 AnjutaAutogenFunc endfunc
;
79 AnjutaLauncher
* launcher
;
80 gboolean busy
; /* For debugging */
83 /*---------------------------------------------------------------------------*/
86 *---------------------------------------------------------------------------*/
88 /* Check if autogen version 5 is present */
91 anjuta_check_autogen (void)
93 gchar
* args
[] = {"autogen", "-v", NULL
};
96 if (g_spawn_sync (NULL
, args
, NULL
, G_SPAWN_SEARCH_PATH
| G_SPAWN_STDERR_TO_DEV_NULL
,
97 NULL
, NULL
, &output
, NULL
, NULL
, NULL
))
101 gint ver
[3] = {0, 0, 0};
103 /* Check autogen 5 version string
105 * autogen - The Automated Program Generator - Ver. 5.5.7
106 * autogen (GNU AutoGen) - The Automated Program Generator - Ver. 5.11
107 * autogen (GNU AutoGen) 5.11.9
109 re
= g_regex_new ("autogen.* (\\d+)\\.(\\d+)(?:\\.(\\d+))?", 0, 0, NULL
);
110 g_regex_match (re
, output
, 0, &minfo
);
111 if (g_match_info_matches (minfo
)) {
112 gchar
**match_strings
;
114 match_strings
= g_match_info_fetch_all (minfo
);
115 ver
[0] = g_ascii_strtoll (match_strings
[1], NULL
, 10);
116 ver
[1] = g_ascii_strtoll (match_strings
[2], NULL
, 10);
117 if (match_strings
[3] != NULL
) ver
[2] = g_ascii_strtoll (match_strings
[3], NULL
, 10);
119 g_strfreev (match_strings
);
121 g_match_info_free (minfo
);
131 anjuta_autogen_error_quark (void)
135 if (!quark
) quark
= g_quark_from_static_string ("anjuta_autogen_error");
143 *---------------------------------------------------------------------------*/
146 cb_autogen_write_key (const gchar
* name
, const gchar
*value
, gpointer user_data
)
148 FILE* def
= (FILE *)user_data
;
152 if(*value
== '{') /* Seems to be a list, so do not quote */
154 fprintf(def
, "%s = %s;\n", name
, value
);
158 gchar
*esc_value
= g_strescape (value
, NULL
);
159 fprintf (def
, "%s = \"%s\";\n", name
, esc_value
);
166 anjuta_autogen_write_definition_file (AnjutaAutogen
* this, GHashTable
* values
, GError
**error
)
170 /* Autogen should not be running */
173 g_set_error_literal (error
, ANJUTA_AUTOGEN_ERROR
,
174 ANJUTA_AUTOGEN_ERROR_BUSY
,
175 _("Autogen is busy"));
180 def
= fopen (this->deffilename
, "wt");
183 g_set_error (error
, ANJUTA_AUTOGEN_ERROR
,
184 ANJUTA_AUTOGEN_ERROR_WRITE_FAIL
,
185 _("Failed to write autogen definition file %s"),
191 /* Generate definition data for autogen */
192 fputs ("AutoGen Definitions .;\n",def
);
193 g_hash_table_foreach (values
, (GHFunc
)cb_autogen_write_key
, def
);
201 *---------------------------------------------------------------------------*/
204 anjuta_autogen_set_library_path (AnjutaAutogen
* this, const gchar
*directory
)
206 g_return_if_fail (directory
!= NULL
);
208 this->library_paths
= g_list_prepend (this->library_paths
, g_strdup (directory
));
212 anjuta_autogen_clear_library_path (AnjutaAutogen
* this)
214 g_list_foreach (this->library_paths
, (GFunc
)g_free
, NULL
);
215 g_list_free (this->library_paths
);
216 this->library_paths
= NULL
;
220 anjuta_autogen_get_library_paths (AnjutaAutogen
* this)
222 return this->library_paths
;
225 /* Set input and output
226 *---------------------------------------------------------------------------*/
229 anjuta_autogen_set_input_file (AnjutaAutogen
* this, const gchar
* filename
, const gchar
* start_marker
, const gchar
* end_marker
)
237 /* Autogen should not be running */
238 g_return_val_if_fail (this->busy
== FALSE
, FALSE
);
240 /* We need to specify start and end marker or nothing */
241 g_return_val_if_fail ((start_marker
&& end_marker
) || (!start_marker
&& !end_marker
), FALSE
);
243 /* Remove previous temporary file if exist */
244 if (this->temptplfilename
!= NULL
)
246 remove (this->temptplfilename
);
247 g_free (this->temptplfilename
);
248 this->temptplfilename
= NULL
;
251 if ((start_marker
== NULL
) && (end_marker
== NULL
))
253 /* input file is really an autogen file, nothig do to */
254 this->tplfilename
= filename
;
259 /* Autogen definition is missing, we need to create a temporary file
262 /* Create temporary file */
263 this->temptplfilename
= g_build_filename (g_get_tmp_dir (), TMP_TPL_FILENAME
, NULL
);
264 mktemp (this->temptplfilename
);
265 this->tplfilename
= this->temptplfilename
;
266 tpl
= fopen (this->tplfilename
, "wt");
267 if (tpl
== NULL
) return FALSE
;
269 /* Add autogen definition */
270 fputs (start_marker
, tpl
);
271 fputs (" autogen5 template ", tpl
);
272 fputs (end_marker
, tpl
);
275 /* Copy source file into this new file */
276 src
= fopen (filename
, "rb");
277 if (src
== NULL
) return FALSE
;
279 buffer
= g_new (gchar
, FILE_BUFFER_SIZE
);
284 len
= fread (buffer
, 1, FILE_BUFFER_SIZE
, src
);
285 if ((len
!= FILE_BUFFER_SIZE
) && !feof (src
))
291 if (len
!= fwrite (buffer
, 1, len
, tpl
))
306 anjuta_autogen_set_output_file (AnjutaAutogen
* this, const gchar
* filename
)
308 /* Autogen should not be running */
309 g_return_val_if_fail (this->busy
== FALSE
, FALSE
);
311 this->outfilename
= filename
;
312 this->outfunc
= NULL
;
318 anjuta_autogen_set_output_callback (AnjutaAutogen
* this, AnjutaAutogenOutputFunc func
, gpointer user_data
)
320 /* Autogen should not be running */
321 g_return_val_if_fail (this->busy
== FALSE
, FALSE
);
323 this->outfunc
= func
;
324 this->outdata
= user_data
;
325 this->outfilename
= NULL
;
331 *---------------------------------------------------------------------------*/
334 on_autogen_output (AnjutaLauncher
* launcher
, AnjutaLauncherOutputType type
, const gchar
* output
, gpointer user_data
)
336 AnjutaAutogen
* this = (AnjutaAutogen
*)user_data
;
338 if (this->outfilename
!= NULL
)
340 /* Write output in a file */
341 if (this->output
!= NULL
)
343 fputs (output
, this->output
);
347 if (this->outfunc
!= NULL
)
349 /* Call a callback function */
350 (this->outfunc
)(output
, this->outdata
);
355 on_autogen_terminated (AnjutaLauncher
* launcher
, gint pid
, gint status
, gulong time
, AnjutaAutogen
* this)
358 if (this->output
!= NULL
)
360 fclose (this->output
);
362 /* Delete empty file */
363 if (this->empty
== TRUE
)
365 g_remove (this->outfilename
);
371 (this->endfunc
)(this, this->enddata
);
376 anjuta_autogen_execute (AnjutaAutogen
* this, AnjutaAutogenFunc func
, gpointer data
, GError
** error
)
382 /* Autogen should not be running */
383 g_return_val_if_fail (this->busy
== FALSE
, FALSE
);
384 g_return_val_if_fail (this, FALSE
);
385 g_return_val_if_fail (this->launcher
, FALSE
);
387 /* Set output end callback */
390 this->endfunc
= func
;
391 this->enddata
= data
;
395 this->endfunc
= NULL
;
397 args
= g_new (gchar
*, 5 + g_list_length (this->library_paths
) * 2);
400 for (path
= g_list_first (this->library_paths
); path
!= NULL
; path
= g_list_next (path
))
403 args
[arg
++] = (gchar
*)(path
->data
);
406 args
[arg
++] = (gchar
*)this->tplfilename
;
407 args
[arg
++] = (gchar
*)this->deffilename
;
410 /* Check if output file can be written */
411 if (this->outfilename
!= NULL
)
413 /* Open file if it's not already done */
414 this->output
= fopen (this->outfilename
, "wt");
415 if (this->output
== NULL
)
420 g_file_error_from_errno(errno
),
421 "Could not open file \"%s\": %s",
432 /* The template and definition file are in UTF-8 so the output too */
433 anjuta_launcher_set_encoding (this->launcher
, "UTF-8");
436 if (!anjuta_launcher_execute_v (this->launcher
, NULL
, args
, NULL
, on_autogen_output
, this))
447 /* Creation and Destruction
448 *---------------------------------------------------------------------------*/
450 AnjutaAutogen
* anjuta_autogen_new (void)
454 this = g_new0(AnjutaAutogen
, 1);
456 this->launcher
= anjuta_launcher_new ();
457 g_signal_connect (G_OBJECT (this->launcher
), "child-exited", G_CALLBACK (on_autogen_terminated
), this);
459 /* Create a temporary file for definitions */
460 this->deffilename
= g_build_filename (g_get_tmp_dir (), TMP_DEF_FILENAME
, NULL
);
461 mktemp (this->deffilename
);
466 void anjuta_autogen_free (AnjutaAutogen
* this)
468 g_return_if_fail(this != NULL
);
470 if (this->output
!= NULL
)
472 /* output is not used if a callback function is used */
473 fclose (this->output
);
476 if (this->temptplfilename
!= NULL
)
478 /* temptplfilename is not used if input file already
479 * contains autogen marker */
480 remove (this->temptplfilename
);
481 g_free (this->temptplfilename
);
484 g_list_foreach (this->library_paths
, (GFunc
)g_free
, NULL
);
485 g_list_free (this->library_paths
);
487 /* deffilename should always be here (created in new) */
488 g_return_if_fail (this->deffilename
);
489 remove (this->deffilename
);
490 g_free (this->deffilename
);
492 g_signal_handlers_disconnect_by_func (G_OBJECT (this->launcher
), G_CALLBACK (on_autogen_terminated
), this);
493 g_object_unref (this->launcher
);