libanjuta: Move autogen functions from project-wizard to libanjuta
[anjuta.git] / libanjuta / anjuta-autogen.c
blob71e434e4b962df5cdd6efa56ebd1742f72a8943b
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
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 *---------------------------------------------------------------------------*/
32 #include <config.h>
34 #include <libanjuta/anjuta-launcher.h>
35 #include <libanjuta/anjuta-autogen.h>
37 #include <glib/gi18n.h>
38 #include <glib/gstdio.h>
39 #include <glib.h>
40 #include <errno.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.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 /*---------------------------------------------------------------------------*/
55 struct _AnjutaAutogen
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
61 * autogen marker */
63 GList *library_paths; /* List of paths for searching include files */
64 /* Output file name and handle used
65 * when autogen output is written
66 * in a file */
67 const gchar* outfilename;
68 FILE* output;
69 gboolean empty;
70 /* Call back function and data used
71 * when autogen output something */
72 AnjutaAutogenOutputFunc outfunc;
73 gpointer outdata;
74 /* Call back function and data used
75 * when autogen terminate */
76 AnjutaAutogenFunc endfunc;
77 gpointer enddata;
79 AnjutaLauncher* launcher;
80 gboolean busy; /* For debugging */
83 /*---------------------------------------------------------------------------*/
85 /* Helper functions
86 *---------------------------------------------------------------------------*/
88 /* Check if autogen version 5 is present */
90 gboolean
91 anjuta_check_autogen (void)
93 gchar* args[] = {"autogen", "-v", NULL};
94 gchar* output;
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))
99 GRegex *re;
100 GMatchInfo *minfo;
101 gint ver[3] = {0, 0, 0};
103 /* Check autogen 5 version string
104 * Examples:
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);
122 g_regex_unref (re);
124 return ver[0] == 5;
127 return FALSE;
130 GQuark
131 anjuta_autogen_error_quark (void)
133 static GQuark quark;
135 if (!quark) quark = g_quark_from_static_string ("anjuta_autogen_error");
137 return quark;
142 /* Write definitions
143 *---------------------------------------------------------------------------*/
145 static void
146 cb_autogen_write_key (const gchar* name, const gchar *value, gpointer user_data)
148 FILE* def = (FILE *)user_data;
150 if (value != NULL)
152 if(*value == '{') /* Seems to be a list, so do not quote */
154 fprintf(def, "%s = %s;\n", name, value);
156 else
158 gchar *esc_value = g_strescape (value, NULL);
159 fprintf (def, "%s = \"%s\";\n", name, esc_value);
160 g_free (esc_value);
165 gboolean
166 anjuta_autogen_write_definition_file (AnjutaAutogen* this, GHashTable* values, GError **error)
168 FILE* def;
170 /* Autogen should not be running */
171 if (this->busy)
173 g_set_error_literal (error, ANJUTA_AUTOGEN_ERROR,
174 ANJUTA_AUTOGEN_ERROR_BUSY,
175 _("Autogen is busy"));
177 return FALSE;
180 def = fopen (this->deffilename, "wt");
181 if (def == NULL)
183 g_set_error (error, ANJUTA_AUTOGEN_ERROR,
184 ANJUTA_AUTOGEN_ERROR_WRITE_FAIL,
185 _("Failed to write autogen definition file %s"),
186 this->deffilename);
188 return FALSE;
191 /* Generate definition data for autogen */
192 fputs ("AutoGen Definitions .;\n",def);
193 g_hash_table_foreach (values, (GHFunc)cb_autogen_write_key, def);
195 fclose (def);
197 return TRUE;
200 /* Set library path
201 *---------------------------------------------------------------------------*/
203 void
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));
211 void
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;
219 GList *
220 anjuta_autogen_get_library_paths (AnjutaAutogen* this)
222 return this->library_paths;
225 /* Set input and output
226 *---------------------------------------------------------------------------*/
228 gboolean
229 anjuta_autogen_set_input_file (AnjutaAutogen* this, const gchar* filename, const gchar* start_marker, const gchar* end_marker)
231 FILE* tpl;
232 FILE* src;
233 gboolean ok;
234 gchar* buffer;
235 guint len;
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;
256 return TRUE;
259 /* Autogen definition is missing, we need to create a temporary file
260 * with them */
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);
273 fputc ('\n', 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);
281 ok = TRUE;
282 for (;!feof (src);)
284 len = fread (buffer, 1, FILE_BUFFER_SIZE, src);
285 if ((len != FILE_BUFFER_SIZE) && !feof (src))
287 ok = FALSE;
288 break;
291 if (len != fwrite (buffer, 1, len, tpl))
293 ok = FALSE;
294 break;
298 g_free (buffer);
299 fclose (src);
300 fclose (tpl);
302 return ok;
305 gboolean
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;
314 return TRUE;
317 gboolean
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;
327 return TRUE;
330 /* Execute autogen
331 *---------------------------------------------------------------------------*/
333 static void
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);
344 this->empty = FALSE;
347 if (this->outfunc != NULL)
349 /* Call a callback function */
350 (this->outfunc)(output, this->outdata);
354 static void
355 on_autogen_terminated (AnjutaLauncher* launcher, gint pid, gint status, gulong time, AnjutaAutogen* this)
357 this->busy = FALSE;
358 if (this->output != NULL)
360 fclose (this->output);
361 this->output = NULL;
362 /* Delete empty file */
363 if (this->empty == TRUE)
365 g_remove (this->outfilename);
369 if (this->endfunc)
371 (this->endfunc)(this, this->enddata);
375 gboolean
376 anjuta_autogen_execute (AnjutaAutogen* this, AnjutaAutogenFunc func, gpointer data, GError** error)
378 gchar** args;
379 guint arg;
380 GList *path;
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 */
388 if (func != NULL)
390 this->endfunc = func;
391 this->enddata = data;
393 else
395 this->endfunc = NULL;
397 args = g_new (gchar *, 5 + g_list_length (this->library_paths) * 2);
398 args[0] = "autogen";
399 arg = 1;
400 for (path = g_list_first (this->library_paths); path != NULL; path = g_list_next (path))
402 args[arg++] = "-L";
403 args[arg++] = (gchar *)(path->data);
405 args[arg++] = "-T";
406 args[arg++] = (gchar *)this->tplfilename;
407 args[arg++] = (gchar *)this->deffilename;
408 args[arg] = NULL;
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)
417 g_set_error(
418 error,
419 G_FILE_ERROR,
420 g_file_error_from_errno(errno),
421 "Could not open file \"%s\": %s",
422 this->outfilename,
423 g_strerror(errno)
425 g_free (args);
427 return FALSE;
429 this->empty = TRUE;
432 /* The template and definition file are in UTF-8 so the output too */
433 anjuta_launcher_set_encoding (this->launcher, "UTF-8");
435 this->busy = TRUE;
436 if (!anjuta_launcher_execute_v (this->launcher, NULL, args, NULL, on_autogen_output, this))
438 g_free (args);
440 return FALSE;
442 g_free (args);
444 return TRUE;
447 /* Creation and Destruction
448 *---------------------------------------------------------------------------*/
450 AnjutaAutogen* anjuta_autogen_new (void)
452 AnjutaAutogen* this;
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);
463 return this;
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);
495 g_free (this);