2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 * Copyright (C) 2006, Quy Tonthat <qtonthat@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /* babel.c: running external programs and redirecting to TRWLayers.
24 * GPSBabel may not be necessary for everything -- for instance,
25 * use a_babel_convert_from_shellcommand with input_file_type == NULL
26 * for an external program that outputs GPX.
37 #ifdef HAVE_SYS_WAIT_H
44 #include <glib/gstdio.h>
46 /* in the future we could have support for other shells (change command strings), or not use a shell at all */
47 #define BASH_LOCATION "/bin/bash"
49 gboolean a_babel_convert( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, gpointer user_data )
55 gchar *bargs = g_strconcat(babelargs, " -i gpx", NULL);
57 if ((fd_src = g_file_open_tmp("tmp-viking.XXXXXX", &name_src, NULL)) >= 0) {
58 f = fdopen(fd_src, "w");
59 a_gpx_write_file(vt, f);
62 ret = a_babel_convert_from ( vt, bargs, cb, name_src, user_data );
71 /* Runs args[0] with the arguments and uses the GPX module
72 * to import the GPX data into layer vt. Assumes that upon
73 * running the command, the data will appear in the (usually
74 * temporary) file name_dst.
76 * cb: callback that is run upon new data from STDOUT (?)
77 * (TODO: STDERR would be nice since we usually redirect STDOUT)
78 * user_data: passed along to cb
80 * returns TRUE on success
83 gboolean babel_general_convert_from( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_dst, gpointer user_data )
91 PROCESS_INFORMATION pi;
94 ZeroMemory( &si, sizeof(si) );
95 ZeroMemory( &pi, sizeof(pi) );
97 si.dwFlags = STARTF_USESHOWWINDOW;
98 si.wShowWindow = SW_HIDE;
100 cmd = g_strjoinv( " ", args);
101 args2 = g_strsplit(cmd, "\\", 0);
103 cmd = g_strjoinv( "\\\\", args2);
105 args2 = g_strsplit(cmd, "/", 0);
107 cmd = g_strjoinv( "\\\\", args2);
110 NULL, // No module name (use command line).
111 (LPTSTR)cmd, // Command line.
112 NULL, // Process handle not inheritable.
113 NULL, // Thread handle not inheritable.
114 FALSE, // Set handle inheritance to FALSE.
115 0, // No creation flags.
116 NULL, // Use parent's environment block.
117 NULL, // Use parent's starting directory.
118 &si, // Pointer to STARTUPINFO structure.
119 &pi ) // Pointer to PROCESS_INFORMATION structure.
121 g_warning( "CreateProcess failed");
125 WaitForSingleObject(pi.hProcess, INFINITE);
126 WaitForSingleObject(pi.hThread, INFINITE);
128 CloseHandle(pi.hThread);
129 CloseHandle(pi.hProcess);
132 cb(BABEL_DONE, NULL, user_data);
134 f = g_fopen(name_dst, "r");
135 a_gpx_read_file( vt, f );
148 gboolean babel_general_convert_from( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_dst, gpointer user_data )
150 gboolean ret = FALSE;
152 GError *error = NULL;
157 if (!g_spawn_async_with_pipes (NULL, args, NULL, 0, NULL, NULL, &pid, NULL, &babel_stdout, NULL, &error)) {
158 g_warning("Error : %s", error->message);
162 /* No data required */
168 diag = fdopen(babel_stdout, "r");
169 setvbuf(diag, NULL, _IONBF, 0);
171 while (fgets(line, sizeof(line), diag)) {
173 cb(BABEL_DIAG_OUTPUT, line, user_data);
176 cb(BABEL_DONE, NULL, user_data);
179 waitpid(pid, NULL, 0);
180 g_spawn_close_pid(pid);
182 f = g_fopen(name_dst, "r");
184 a_gpx_read_file ( vt, f );
195 gboolean a_babel_convert_from( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *from, gpointer user_data )
200 gboolean ret = FALSE;
203 if ((fd_dst = g_file_open_tmp("tmp-viking.XXXXXX", &name_dst, NULL)) >= 0) {
207 gpsbabel_loc = g_find_program_in_path("gpsbabel");
210 gchar *unbuffer_loc = g_find_program_in_path("unbuffer");
211 gchar **sub_args = g_strsplit(babelargs, " ", 0);
215 args[i++] = unbuffer_loc;
216 args[i++] = gpsbabel_loc;
217 for (j = 0; sub_args[j]; j++) {
218 /* some version of gpsbabel can not take extra blank arg */
219 if (sub_args[j][0] != '\0')
220 args[i++] = sub_args[j];
225 args[i++] = (char *)from;
227 args[i++] = name_dst;
230 ret = babel_general_convert_from ( vt, cb, args, name_dst, user_data );
232 g_free ( unbuffer_loc );
233 g_strfreev(sub_args);
235 g_warning("gpsbabel not found in PATH");
236 g_free(gpsbabel_loc);
244 /* Runs the input command in a shell (bash) and optionally uses GPSBabel to convert from input_file_type.
245 * If input_file_type is NULL, doesn't use GPSBabel. Input must be GPX (or Geocaching *.loc)
247 * Uses babel_general_convert_from to actually run the command. This function
248 * prepares the command and temporary file, and sets up the arguments for bash.
250 gboolean a_babel_convert_from_shellcommand ( VikTrwLayer *vt, const char *input_cmd, const char *input_file_type, BabelStatusFunc cb, gpointer user_data )
254 gboolean ret = FALSE;
257 if ((fd_dst = g_file_open_tmp("tmp-viking.XXXXXX", &name_dst, NULL)) >= 0) {
258 gchar *shell_command;
259 if ( input_file_type )
260 shell_command = g_strdup_printf("%s | gpsbabel -i %s -f - -o gpx -F %s", input_cmd, input_file_type, name_dst);
262 shell_command = g_strdup_printf("%s > %s", input_cmd, name_dst);
264 g_debug("%s: %s", __FUNCTION__, shell_command);
267 args = g_malloc(sizeof(gchar *)*4);
268 args[0] = BASH_LOCATION;
270 args[2] = shell_command;
273 ret = babel_general_convert_from ( vt, cb, args, name_dst, user_data );
275 g_free ( shell_command );
283 gboolean a_babel_convert_from_url ( VikTrwLayer *vt, const char *url, const char *input_type, BabelStatusFunc cb, gpointer user_data )
285 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_kml_file};
288 gboolean ret = FALSE;
292 g_debug("%s: input_type=%s url=%s", __FUNCTION__, input_type, url);
294 if ((fd_src = g_file_open_tmp("tmp-viking.XXXXXX", &name_src, NULL)) >= 0) {
298 babelargs = g_strdup_printf(" -i %s", input_type);
300 fetch_ret = a_http_download_get_url(url, "", name_src, &options, NULL);
302 ret = a_babel_convert_from( vt, babelargs, NULL, name_src, NULL);
313 gboolean babel_general_convert_to( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_src, gpointer user_data )
319 if (!a_file_export(vt, name_src, FILE_TYPE_GPX, NULL)) {
320 g_warning("%s(): error exporting to %s", __FUNCTION__, name_src);
325 PROCESS_INFORMATION pi;
327 ZeroMemory( &si, sizeof(si) );
328 ZeroMemory( &pi, sizeof(pi) );
330 si.dwFlags = STARTF_USESHOWWINDOW;
331 si.wShowWindow = SW_HIDE;
334 cmd = g_strjoinv( " ", args);
335 args2 = g_strsplit(cmd, "\\", 0);
336 cmd = g_strjoinv( "\\\\", args2);
338 args2 = g_strsplit(cmd, "/", 0);
340 cmd = g_strjoinv( "\\\\", args2);
343 NULL, // No module name (use command line).
344 (LPTSTR)cmd, // Command line.
345 NULL, // Process handle not inheritable.
346 NULL, // Thread handle not inheritable.
347 FALSE, // Set handle inheritance to FALSE.
348 0, // No creation flags.
349 NULL, // Use parent's environment block.
350 NULL, // Use parent's starting directory.
351 &si, // Pointer to STARTUPINFO structure.
352 &pi ) // Pointer to PROCESS_INFORMATION structure.
354 g_warning( "CreateProcess failed" );
359 WaitForSingleObject(pi.hProcess, INFINITE);
360 WaitForSingleObject(pi.hThread, INFINITE);
362 CloseHandle(pi.hThread);
363 CloseHandle(pi.hProcess);
366 cb(BABEL_DONE, NULL, user_data);
379 gboolean babel_general_convert_to( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_src, gpointer user_data )
381 gboolean ret = FALSE;
383 GError *error = NULL;
386 if (!a_file_export(vt, name_src, FILE_TYPE_GPX, NULL)) {
387 g_warning("%s(): error exporting to %s", __FUNCTION__, name_src);
391 if (!g_spawn_async_with_pipes (NULL, args, NULL, 0, NULL, NULL, &pid, NULL, &babel_stdout, NULL, &error)) {
392 g_warning("Error : %s", error->message);
398 diag = fdopen(babel_stdout, "r");
399 setvbuf(diag, NULL, _IONBF, 0);
401 while (fgets(line, sizeof(line), diag)) {
403 cb(BABEL_DIAG_OUTPUT, line, user_data);
406 cb(BABEL_DONE, NULL, user_data);
409 waitpid(pid, NULL, 0);
410 g_spawn_close_pid(pid);
419 gboolean a_babel_convert_to( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *to, gpointer user_data )
424 gboolean ret = FALSE;
427 if ((fd_src = g_file_open_tmp("tmp-viking.XXXXXX", &name_src, NULL)) >= 0) {
431 gpsbabel_loc = g_find_program_in_path("gpsbabel");
434 gchar *unbuffer_loc = g_find_program_in_path("unbuffer");
435 gchar **sub_args = g_strsplit(babelargs, " ", 0);
439 args[i++] = unbuffer_loc;
440 args[i++] = gpsbabel_loc;
443 for (j = 0; sub_args[j]; j++)
444 /* some version of gpsbabel can not take extra blank arg */
445 if (sub_args[j][0] != '\0')
446 args[i++] = sub_args[j];
448 args[i++] = name_src;
450 args[i++] = (char *)to;
453 ret = babel_general_convert_to ( vt, cb, args, name_src, user_data );
455 g_free ( unbuffer_loc );
456 g_strfreev(sub_args);
458 g_warning("gpsbabel not found in PATH");
459 g_free(gpsbabel_loc);