Improve error handling
[viking/guyou.git] / src / babel.c
blobf44a977474cf1ed73b4d054d8e7fb840c631f088
1 /*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /* babel.c: running external programs and redirecting to TRWLayers.
23 * GPSBabel may not be necessary for everything -- for instance,
24 * use a_babel_convert_from_shellcommand with input_file_type == NULL
25 * for an external program that outputs GPX.
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
32 #include "viking.h"
33 #include "gpx.h"
34 #include "babel.h"
35 #include <stdio.h>
36 #ifdef HAVE_SYS_WAIT_H
37 #include <sys/wait.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #include <glib.h>
43 #include <glib/gstdio.h>
45 /* in the future we could have support for other shells (change command strings), or not use a shell at all */
46 #define BASH_LOCATION "/bin/bash"
48 gboolean a_babel_convert( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, gpointer user_data )
50 int fd_src;
51 FILE *f;
52 gchar *name_src;
53 gboolean ret = FALSE;
54 gchar *bargs = g_strconcat(babelargs, " -i gpx", NULL);
56 if ((fd_src = g_file_open_tmp("tmp-viking.XXXXXX", &name_src, NULL)) >= 0) {
57 f = fdopen(fd_src, "w");
58 a_gpx_write_file(vt, f);
59 fclose(f);
60 f = NULL;
61 ret = a_babel_convert_from ( vt, bargs, cb, name_src, user_data );
64 g_free(bargs);
65 g_remove(name_src);
66 g_free(name_src);
67 return ret;
70 /* Runs args[0] with the arguments and uses the GPX module
71 * to import the GPX data into layer vt. Assumes that upon
72 * running the command, the data will appear in the (usually
73 * temporary) file name_dst.
75 * cb: callback that is run upon new data from STDOUT (?)
76 * (TODO: STDERR would be nice since we usually redirect STDOUT)
77 * user_data: passed along to cb
79 * returns TRUE on success
81 gboolean babel_general_convert_from( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_dst, gpointer user_data )
83 gboolean ret = FALSE;
84 GPid pid;
85 GError *error = NULL;
86 gint babel_stdout;
87 FILE *f;
90 if (!g_spawn_async_with_pipes (NULL, args, NULL, 0, NULL, NULL, &pid, NULL, &babel_stdout, NULL, &error)) {
91 g_warning("Error : %s", error->message);
92 g_error_free(error);
93 ret = FALSE;
94 } else {
95 gchar line[512];
96 FILE *diag;
97 diag = fdopen(babel_stdout, "r");
98 setvbuf(diag, NULL, _IONBF, 0);
100 while (fgets(line, sizeof(line), diag)) {
101 if ( cb )
102 cb(BABEL_DIAG_OUTPUT, line, user_data);
104 if ( cb )
105 cb(BABEL_DONE, NULL, user_data);
106 fclose(diag);
107 diag = NULL;
108 waitpid(pid, NULL, 0);
109 g_spawn_close_pid(pid);
111 f = g_fopen(name_dst, "r");
112 if (f) {
113 a_gpx_read_file ( vt, f );
114 fclose(f);
115 f = NULL;
116 ret = TRUE;
120 return ret;
123 gboolean a_babel_convert_from( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *from, gpointer user_data )
125 int fd_dst;
126 gchar *name_dst;
127 gchar *cmd;
128 gboolean ret = FALSE;
129 gchar **args;
130 gint nb_args;
132 if ((fd_dst = g_file_open_tmp("tmp-viking.XXXXXX", &name_dst, NULL)) >= 0) {
133 gchar *gpsbabel_loc;
134 close(fd_dst);
136 gpsbabel_loc = g_find_program_in_path("gpsbabel");
138 if (gpsbabel_loc ) {
139 gchar *unbuffer_loc = g_find_program_in_path("unbuffer");
140 cmd = g_strdup_printf ( "%s%s%s %s -o gpx %s %s",
141 unbuffer_loc ? unbuffer_loc : "",
142 unbuffer_loc ? " " : "",
143 gpsbabel_loc,
144 babelargs,
145 from,
146 name_dst );
148 if ( unbuffer_loc )
149 g_free ( unbuffer_loc );
151 if ( g_shell_parse_argv(cmd, &nb_args, &args, NULL) ) {
152 ret = babel_general_convert_from ( vt, cb, args, name_dst, user_data );
153 g_strfreev(args);
155 g_free ( cmd );
159 g_remove(name_dst);
160 g_free(name_dst);
161 return ret;
164 /* Runs the input command in a shell (bash) and optionally uses GPSBabel to convert from input_file_type.
165 * If input_file_type is NULL, doesn't use GPSBabel. Input must be GPX (or Geocaching *.loc)
167 * Uses babel_general_convert_from to actually run the command. This function
168 * prepares the command and temporary file, and sets up the arguments for bash.
170 gboolean a_babel_convert_from_shellcommand ( VikTrwLayer *vt, const char *input_cmd, const char *input_file_type, BabelStatusFunc cb, gpointer user_data )
172 int fd_dst;
173 gchar *name_dst;
174 gboolean ret = FALSE;
175 gchar **args;
177 if ((fd_dst = g_file_open_tmp("tmp-viking.XXXXXX", &name_dst, NULL)) >= 0) {
178 gchar *shell_command;
179 if ( input_file_type )
180 shell_command = g_strdup_printf("%s | gpsbabel -i %s -f - -o gpx -F %s", input_cmd, input_file_type, name_dst);
181 else
182 shell_command = g_strdup_printf("%s > %s", input_cmd, name_dst);
184 g_debug("%s: %s", __FUNCTION__, shell_command);
185 close(fd_dst);
187 args = g_malloc(sizeof(gchar *)*4);
188 args[0] = BASH_LOCATION;
189 args[1] = "-c";
190 args[2] = shell_command;
191 args[3] = NULL;
193 ret = babel_general_convert_from ( vt, cb, args, name_dst, user_data );
194 g_free ( args );
195 g_free ( shell_command );
198 g_remove(name_dst);
199 g_free(name_dst);
200 return ret;
203 gboolean a_babel_convert_from_url ( VikTrwLayer *vt, const char *url, const char *input_type, BabelStatusFunc cb, gpointer user_data )
205 gint fd_src;
206 int fetch_ret;
207 gboolean ret = FALSE;
208 gchar *name_src;
209 gchar *babelargs;
211 g_debug("%s: input_type=%s url=%s", __FUNCTION__, input_type, url);
213 if ((fd_src = g_file_open_tmp("tmp-viking.XXXXXX", &name_src, NULL)) >= 0) {
214 close(fd_src);
215 g_remove(name_src);
217 babelargs = g_strdup_printf(" -i %s", input_type);
219 fetch_ret = a_http_download_get_url(url, "", name_src, NULL);
220 if (fetch_ret == 0)
221 ret = a_babel_convert_from( vt, babelargs, NULL, name_src, NULL);
223 g_remove(name_src);
224 g_free(babelargs);
225 g_free(name_src);
228 return ret;
231 gboolean babel_general_convert_to( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_src, gpointer user_data )
233 gboolean ret = FALSE;
234 GPid pid;
235 GError *error = NULL;
236 gint babel_stdout;
238 if (!a_file_export(vt, name_src, FILE_TYPE_GPX)) {
239 g_warning("%s(): error exporting to %s", __FUNCTION__, name_src);
240 return(FALSE);
243 if (!g_spawn_async_with_pipes (NULL, args, NULL, 0, NULL, NULL, &pid, NULL, &babel_stdout, NULL, &error)) {
244 g_warning("Error : %s", error->message);
245 g_error_free(error);
246 ret = FALSE;
247 } else {
248 gchar line[512];
249 FILE *diag;
250 diag = fdopen(babel_stdout, "r");
251 setvbuf(diag, NULL, _IONBF, 0);
253 while (fgets(line, sizeof(line), diag)) {
254 if ( cb )
255 cb(BABEL_DIAG_OUTPUT, line, user_data);
257 if ( cb )
258 cb(BABEL_DONE, NULL, user_data);
259 fclose(diag);
260 diag = NULL;
261 waitpid(pid, NULL, 0);
262 g_spawn_close_pid(pid);
264 ret = TRUE;
267 return ret;
270 gboolean a_babel_convert_to( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *to, gpointer user_data )
272 int fd_src;
273 gchar *name_src;
274 gchar *cmd;
275 gboolean ret = FALSE;
276 gchar **args;
277 gint nb_args;
279 if ((fd_src = g_file_open_tmp("tmp-viking.XXXXXX", &name_src, NULL)) >= 0) {
280 gchar *gpsbabel_loc;
281 close(fd_src);
283 gpsbabel_loc = g_find_program_in_path("gpsbabel");
285 if (gpsbabel_loc ) {
286 gchar *unbuffer_loc = g_find_program_in_path("unbuffer");
287 cmd = g_strdup_printf ( "%s%s%s %s -i gpx %s %s",
288 unbuffer_loc ? unbuffer_loc : "",
289 unbuffer_loc ? " " : "",
290 gpsbabel_loc,
291 babelargs,
292 name_src,
293 to);
295 if ( unbuffer_loc )
296 g_free ( unbuffer_loc );
297 g_debug ( "%s: %s", __FUNCTION__, cmd );
298 if ( g_shell_parse_argv(cmd, &nb_args, &args, NULL) ) {
299 ret = babel_general_convert_to ( vt, cb, args, name_src, user_data );
300 g_strfreev(args);
302 g_free ( cmd );
306 g_remove(name_src);
307 g_free(name_src);
308 return ret;