* plugins/project-wizard/templates/terminal.wiz,
[anjuta-git-plugin.git] / plugins / project-wizard / autogen.c
blob4f1d166e22803d1a41b27ee39ab86e3e817ebc45
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 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 "autogen.h"
36 #include <libanjuta/anjuta-launcher.h>
38 #include <glib/gstdio.h>
39 #include <glib/gfileutils.h>
40 #include <glib/gstrfuncs.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <glib/gstdio.h>
47 /*---------------------------------------------------------------------------*/
49 #define TMP_DEF_FILENAME "NPWDEFXXXXXX"
50 #define TMP_TPL_FILENAME "NPWTPLXXXXXX"
52 #define FILE_BUFFER_SIZE 4096
54 /*---------------------------------------------------------------------------*/
56 struct _NPWAutogen
58 gchar* deffilename; /* name of generated definition file */
59 const gchar* tplfilename; /* name of template (input) file */
60 gchar* temptplfilename; /* name of generated template if the
61 * previous file doesn't contains
62 * autogen marker */
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 NPWAutogenOutputFunc outfunc;
73 gpointer outdata;
74 /* Call back function and data used
75 * when autogen terminate */
76 NPWAutogenFunc 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 npw_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 gint ver[3];
100 gchar* ptr;
102 /* Check autogen */
103 if (strstr(output, "The Automated Program Generator") == NULL) return FALSE;
105 /* Get version number */
106 ptr = strstr(output, "Ver. ");
107 if (ptr == NULL) return FALSE;
108 ptr += 5;
109 sscanf(ptr,"%d.%d.%d", &ver[0], &ver[1], &ver[2]);
111 return (ver[0] == 5);
114 return FALSE;
117 /* Write definitions
118 *---------------------------------------------------------------------------*/
120 static void
121 cb_autogen_write_definition (const gchar* name, const gchar* value, NPWValueTag tag, gpointer user_data)
123 FILE* def = (FILE *)user_data;
125 if ((tag & NPW_VALID_VALUE) && (value != NULL))
127 if(value[0] == '{') /* Seems to be a list, so do not quote */
129 fprintf(def, "%s = %s;\n", name, value);
131 else
133 gchar *esc_value = g_strescape (value, NULL);
134 fprintf (def, "%s = \"%s\";\n", name, esc_value);
135 g_free (esc_value);
140 gboolean
141 npw_autogen_write_definition_file (NPWAutogen* this, NPWValueHeap* values)
143 FILE* def;
145 /* Autogen should not be running */
146 g_return_val_if_fail (this->busy == FALSE, FALSE);
148 def = fopen (this->deffilename, "wt");
149 if (def == NULL) return FALSE;
151 /* Generate definition data for autogen */
152 fputs ("AutoGen Definitions .;\n",def);
153 npw_value_heap_foreach_value (values, cb_autogen_write_definition, def);
155 fclose (def);
157 return TRUE;
160 /* Set input and output
161 *---------------------------------------------------------------------------*/
163 gboolean
164 npw_autogen_set_input_file (NPWAutogen* this, const gchar* filename, const gchar* start_marker, const gchar* end_marker)
166 FILE* tpl;
167 FILE* src;
168 gboolean ok;
169 gchar* buffer;
170 guint len;
172 /* Autogen should not be running */
173 g_return_val_if_fail (this->busy == FALSE, FALSE);
175 /* We need to specify start and end marker or nothing */
176 g_return_val_if_fail ((start_marker && end_marker) || (!start_marker && !end_marker), FALSE);
178 /* Remove previous temporary file if exist */
179 if (this->temptplfilename != NULL)
181 remove (this->temptplfilename);
182 g_free (this->temptplfilename);
183 this->temptplfilename = NULL;
186 if ((start_marker == NULL) && (end_marker == NULL))
188 /* input file is really an autogen file, nothig do to */
189 this->tplfilename = filename;
191 return TRUE;
194 /* Autogen definition is missing, we need to create a temporary file
195 * with them */
197 /* Create temporary file */
198 this->temptplfilename = g_build_filename (g_get_tmp_dir (), TMP_TPL_FILENAME, NULL);
199 mktemp (this->temptplfilename);
200 this->tplfilename = this->temptplfilename;
201 tpl = fopen (this->tplfilename, "wt");
202 if (tpl == NULL) return FALSE;
204 /* Add autogen definition */
205 fputs (start_marker, tpl);
206 fputs (" autogen5 template ", tpl);
207 fputs (end_marker, tpl);
208 fputc ('\n', tpl);
210 /* Copy source file into this new file */
211 src = fopen (filename, "rb");
212 if (src == NULL) return FALSE;
214 buffer = g_new (gchar, FILE_BUFFER_SIZE);
216 ok = TRUE;
217 for (;!feof (src);)
219 len = fread (buffer, 1, FILE_BUFFER_SIZE, src);
220 if ((len != FILE_BUFFER_SIZE) && !feof (src))
222 ok = FALSE;
223 break;
226 if (len != fwrite (buffer, 1, len, tpl))
228 ok = FALSE;
229 break;
233 g_free (buffer);
234 fclose (src);
235 fclose (tpl);
237 return ok;
240 gboolean
241 npw_autogen_set_output_file (NPWAutogen* this, const gchar* filename)
243 /* Autogen should not be running */
244 g_return_val_if_fail (this->busy == FALSE, FALSE);
246 this->outfilename = filename;
247 this->outfunc = NULL;
249 return TRUE;
252 gboolean
253 npw_autogen_set_output_callback (NPWAutogen* this, NPWAutogenOutputFunc func, gpointer user_data)
255 /* Autogen should not be running */
256 g_return_val_if_fail (this->busy == FALSE, FALSE);
258 this->outfunc = func;
259 this->outdata = user_data;
260 this->outfilename = NULL;
262 return TRUE;
265 /* Execute autogen
266 *---------------------------------------------------------------------------*/
268 static void
269 on_autogen_output (AnjutaLauncher* launcher, AnjutaLauncherOutputType type, const gchar* output, gpointer user_data)
271 NPWAutogen* this = (NPWAutogen*)user_data;
273 if (this->outfilename != NULL)
275 /* Write output in a file */
276 if (this->output != NULL)
278 fputs (output, this->output);
279 this->empty = FALSE;
282 if (this->outfunc != NULL)
284 /* Call a callback function */
285 (this->outfunc)(output, this->outdata);
289 static void
290 on_autogen_terminated (AnjutaLauncher* launcher, gint pid, gint status, gulong time, NPWAutogen* this)
292 this->busy = FALSE;
293 if (this->output != NULL)
295 fclose (this->output);
296 this->output = NULL;
297 /* Delete empty file */
298 if (this->empty == TRUE)
300 g_remove (this->outfilename);
304 if (this->endfunc)
306 (this->endfunc)(this, this->enddata);
310 gboolean
311 npw_autogen_execute (NPWAutogen* this, NPWAutogenFunc func, gpointer data, GError** error)
313 gchar* args[] = {"autogen", "-T", NULL, NULL, NULL};
315 /* Autogen should not be running */
316 g_return_val_if_fail (this->busy == FALSE, FALSE);
317 g_return_val_if_fail (this, FALSE);
318 g_return_val_if_fail (this->launcher, FALSE);
320 /* Set output end callback */
321 if (func != NULL)
323 this->endfunc = func;
324 this->enddata = data;
326 else
328 this->endfunc = NULL;
330 args[2] = (gchar *)this->tplfilename;
331 args[3] = (gchar *)this->deffilename;
333 /* Check if output file can be written */
334 if (this->outfilename != NULL)
336 /* Open file if it's not already done */
337 this->output = fopen (this->outfilename, "wt");
338 if (this->output == NULL)
340 g_set_error(
341 error,
342 G_FILE_ERROR,
343 g_file_error_from_errno(errno),
344 "Could not open file \"%s\": %s",
345 this->outfilename,
346 g_strerror(errno)
349 return FALSE;
351 this->empty = TRUE;
354 this->busy = TRUE;
355 if (!anjuta_launcher_execute_v (this->launcher, args, NULL, on_autogen_output, this))
357 return FALSE;
359 /* Keep output as it is */
360 anjuta_launcher_set_encoding (this->launcher, NULL);
362 return TRUE;
365 /* Creation and Destruction
366 *---------------------------------------------------------------------------*/
368 NPWAutogen* npw_autogen_new (void)
370 NPWAutogen* this;
372 this = g_new0(NPWAutogen, 1);
374 this->launcher = anjuta_launcher_new ();
375 g_signal_connect (G_OBJECT (this->launcher), "child-exited", G_CALLBACK (on_autogen_terminated), this);
377 /* Create a temporary file for definitions */
378 this->deffilename = g_build_filename (g_get_tmp_dir (), TMP_DEF_FILENAME, NULL);
379 mktemp (this->deffilename);
381 return this;
384 void npw_autogen_free (NPWAutogen* this)
386 g_return_if_fail(this != NULL);
388 if (this->output != NULL)
390 /* output is not used if a callback function is used */
391 fclose (this->output);
394 if (this->temptplfilename != NULL)
396 /* temptplfilename is not used if input file already
397 * contains autogen marker */
398 remove (this->temptplfilename);
399 g_free (this->temptplfilename);
403 /* deffilename should always be here (created in new) */
404 g_return_if_fail (this->deffilename);
405 remove (this->deffilename);
406 g_free (this->deffilename);
408 g_signal_handlers_disconnect_by_func (G_OBJECT (this->launcher), G_CALLBACK (on_autogen_terminated), this);
409 g_object_unref (this->launcher);
411 g_free (this);