]> git.street.me.uk Git - andy/viking.git/blame - src/babel.c
Improve README to mention OSM.
[andy/viking.git] / src / babel.c
CommitLineData
1d1bc3c1
EB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
a482007a 5 * Copyright (C) 2006, Quy Tonthat <qtonthat@gmail.com>
1d1bc3c1
EB
6 *
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.
11 *
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.
16 *
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
20 *
21 */
22
28c82d8b
EB
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.
27 */
28
45acf79e
MA
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
1d1bc3c1
EB
33#include "viking.h"
34#include "gpx.h"
35#include "babel.h"
8c060406 36#include <stdio.h>
e81e41fb 37#ifdef HAVE_SYS_WAIT_H
29a5a545 38#include <sys/wait.h>
e81e41fb 39#endif
45acf79e
MA
40#ifdef HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43#include <glib.h>
44#include <glib/gstdio.h>
1d1bc3c1 45
8cf048bd
EB
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"
48
7b3479e3 49gboolean a_babel_convert( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, gpointer user_data )
1d1bc3c1
EB
50{
51 int fd_src;
52 FILE *f;
53 gchar *name_src;
54 gboolean ret = FALSE;
3adc68b0 55 gchar *bargs = g_strconcat(babelargs, " -i gpx", NULL);
1d1bc3c1 56
2ecf5998 57 if ((fd_src = g_file_open_tmp("tmp-viking.XXXXXX", &name_src, NULL)) >= 0) {
1d1bc3c1
EB
58 f = fdopen(fd_src, "w");
59 a_gpx_write_file(vt, f);
60 fclose(f);
8c060406 61 f = NULL;
7b3479e3 62 ret = a_babel_convert_from ( vt, bargs, cb, name_src, user_data );
1d1bc3c1
EB
63 }
64
65 g_free(bargs);
8c060406 66 g_remove(name_src);
1d1bc3c1
EB
67 g_free(name_src);
68 return ret;
69}
70
28c82d8b
EB
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.
75 *
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
79 *
80 * returns TRUE on success
81 */
70548902
MA
82#ifdef WINDOWS
83gboolean babel_general_convert_from( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_dst, gpointer user_data )
84{
85 gboolean ret;
86 FILE *f;
87 gchar *cmd;
88 gchar **args2;
89
90 STARTUPINFO si;
91 PROCESS_INFORMATION pi;
92
93
94 ZeroMemory( &si, sizeof(si) );
95 ZeroMemory( &pi, sizeof(pi) );
96 si.cb = sizeof(si);
97 si.dwFlags = STARTF_USESHOWWINDOW;
98 si.wShowWindow = SW_HIDE;
99
100 cmd = g_strjoinv( " ", args);
101 args2 = g_strsplit(cmd, "\\", 0);
102 g_free(cmd);
103 cmd = g_strjoinv( "\\\\", args2);
104 g_free(args2);
105 args2 = g_strsplit(cmd, "/", 0);
106 g_free(cmd);
107 cmd = g_strjoinv( "\\\\", args2);
108
109 if( !CreateProcess(
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.
120 ){
121 g_warning( "CreateProcess failed");
122 ret = FALSE;
123 }
124 else {
125 WaitForSingleObject(pi.hProcess, INFINITE);
126 WaitForSingleObject(pi.hThread, INFINITE);
127
128 CloseHandle(pi.hThread);
129 CloseHandle(pi.hProcess);
130
131 if ( cb )
132 cb(BABEL_DONE, NULL, user_data);
133
134 f = g_fopen(name_dst, "r");
135 a_gpx_read_file( vt, f );
136 fclose(f);
137 ret = TRUE;
138 }
139
140 g_strfreev( args2 );
141 g_free( cmd );
142
143 return ret;
144}
145/* Windows */
146#else
147/* Posix */
7b3479e3 148gboolean babel_general_convert_from( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_dst, gpointer user_data )
8cf048bd 149{
2ecf5998 150 gboolean ret = FALSE;
8cf048bd 151 GPid pid;
6c641b1a
MA
152 GError *error = NULL;
153 gint babel_stdout;
8cf048bd
EB
154 FILE *f;
155
156
6c641b1a
MA
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);
159 g_error_free(error);
8cf048bd
EB
160 ret = FALSE;
161 } else {
2b756ea0
RN
162 /* No data required */
163 if ( vt == NULL )
164 return TRUE;
165
8cf048bd
EB
166 gchar line[512];
167 FILE *diag;
168 diag = fdopen(babel_stdout, "r");
169 setvbuf(diag, NULL, _IONBF, 0);
170
171 while (fgets(line, sizeof(line), diag)) {
7b3479e3
EB
172 if ( cb )
173 cb(BABEL_DIAG_OUTPUT, line, user_data);
8cf048bd 174 }
7b3479e3
EB
175 if ( cb )
176 cb(BABEL_DONE, NULL, user_data);
8cf048bd 177 fclose(diag);
8c060406 178 diag = NULL;
8cf048bd
EB
179 waitpid(pid, NULL, 0);
180 g_spawn_close_pid(pid);
181
8c060406
MA
182 f = g_fopen(name_dst, "r");
183 if (f) {
184 a_gpx_read_file ( vt, f );
185 fclose(f);
186 f = NULL;
187 ret = TRUE;
2ecf5998 188 }
8cf048bd
EB
189 }
190
191 return ret;
192}
70548902 193#endif /* Posix */
8cf048bd 194
7b3479e3 195gboolean a_babel_convert_from( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *from, gpointer user_data )
1d1bc3c1 196{
f3cd9987 197 int i,j;
1d1bc3c1 198 int fd_dst;
1d1bc3c1 199 gchar *name_dst;
1d1bc3c1 200 gboolean ret = FALSE;
f3cd9987 201 gchar *args[64];
1d1bc3c1 202
2ecf5998 203 if ((fd_dst = g_file_open_tmp("tmp-viking.XXXXXX", &name_dst, NULL)) >= 0) {
92255687 204 gchar *gpsbabel_loc;
1d1bc3c1
EB
205 close(fd_dst);
206
92255687
EB
207 gpsbabel_loc = g_find_program_in_path("gpsbabel");
208
209 if (gpsbabel_loc ) {
210 gchar *unbuffer_loc = g_find_program_in_path("unbuffer");
f3cd9987
QT
211 gchar **sub_args = g_strsplit(babelargs, " ", 0);
212
213 i = 0;
214 if (unbuffer_loc)
215 args[i++] = unbuffer_loc;
216 args[i++] = gpsbabel_loc;
e208e3c0
QT
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];
221 }
f3cd9987
QT
222 args[i++] = "-o";
223 args[i++] = "gpx";
e208e3c0 224 args[i++] = "-f";
8398d878 225 args[i++] = (char *)from;
e208e3c0 226 args[i++] = "-F";
f3cd9987
QT
227 args[i++] = name_dst;
228 args[i] = NULL;
229
230 ret = babel_general_convert_from ( vt, cb, args, name_dst, user_data );
231
232 g_free ( unbuffer_loc );
233 g_strfreev(sub_args);
374b7f45
GB
234 } else
235 g_warning("gpsbabel not found in PATH");
f3cd9987 236 g_free(gpsbabel_loc);
1d1bc3c1
EB
237 }
238
8c060406 239 g_remove(name_dst);
1d1bc3c1
EB
240 g_free(name_dst);
241 return ret;
242}
8cf048bd 243
28c82d8b
EB
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)
246 *
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.
249 */
250gboolean a_babel_convert_from_shellcommand ( VikTrwLayer *vt, const char *input_cmd, const char *input_file_type, BabelStatusFunc cb, gpointer user_data )
8cf048bd
EB
251{
252 int fd_dst;
253 gchar *name_dst;
254 gboolean ret = FALSE;
255 gchar **args;
256
2ecf5998 257 if ((fd_dst = g_file_open_tmp("tmp-viking.XXXXXX", &name_dst, NULL)) >= 0) {
28c82d8b
EB
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);
261 else
262 shell_command = g_strdup_printf("%s > %s", input_cmd, name_dst);
263
29a5a545 264 g_debug("%s: %s", __FUNCTION__, shell_command);
8cf048bd
EB
265 close(fd_dst);
266
267 args = g_malloc(sizeof(gchar *)*4);
268 args[0] = BASH_LOCATION;
269 args[1] = "-c";
270 args[2] = shell_command;
271 args[3] = NULL;
272
7b3479e3 273 ret = babel_general_convert_from ( vt, cb, args, name_dst, user_data );
8cf048bd
EB
274 g_free ( args );
275 g_free ( shell_command );
276 }
277
8c060406 278 g_remove(name_dst);
8cf048bd
EB
279 g_free(name_dst);
280 return ret;
281}
282
533bbf34
MA
283gboolean a_babel_convert_from_url ( VikTrwLayer *vt, const char *url, const char *input_type, BabelStatusFunc cb, gpointer user_data )
284{
74fbca98 285 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_kml_file};
533bbf34 286 gint fd_src;
8bd9fe17
GB
287 int fetch_ret;
288 gboolean ret = FALSE;
533bbf34
MA
289 gchar *name_src;
290 gchar *babelargs;
291
292 g_debug("%s: input_type=%s url=%s", __FUNCTION__, input_type, url);
293
8bd9fe17 294 if ((fd_src = g_file_open_tmp("tmp-viking.XXXXXX", &name_src, NULL)) >= 0) {
533bbf34
MA
295 close(fd_src);
296 g_remove(name_src);
297
298 babelargs = g_strdup_printf(" -i %s", input_type);
299
825413ba 300 fetch_ret = a_http_download_get_url(url, "", name_src, &options, NULL);
8bd9fe17
GB
301 if (fetch_ret == 0)
302 ret = a_babel_convert_from( vt, babelargs, NULL, name_src, NULL);
533bbf34
MA
303
304 g_remove(name_src);
305 g_free(babelargs);
306 g_free(name_src);
307 }
308
309 return ret;
310}
311
70548902
MA
312#ifdef WINDOWS
313gboolean babel_general_convert_to( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_src, gpointer user_data )
314{
315 gboolean ret;
316 gchar *cmd;
317 gchar **args2;
318
f7f8a0a6 319 if (!a_file_export(vt, name_src, FILE_TYPE_GPX, NULL)) {
70548902
MA
320 g_warning("%s(): error exporting to %s", __FUNCTION__, name_src);
321 return(FALSE);
322 }
323
324 STARTUPINFO si;
325 PROCESS_INFORMATION pi;
326
327 ZeroMemory( &si, sizeof(si) );
328 ZeroMemory( &pi, sizeof(pi) );
329 si.cb = sizeof(si);
330 si.dwFlags = STARTF_USESHOWWINDOW;
331 si.wShowWindow = SW_HIDE;
332
333
334 cmd = g_strjoinv( " ", args);
335 args2 = g_strsplit(cmd, "\\", 0);
336 cmd = g_strjoinv( "\\\\", args2);
337 g_free(args2);
338 args2 = g_strsplit(cmd, "/", 0);
339 g_free(cmd);
340 cmd = g_strjoinv( "\\\\", args2);
341
342 if( !CreateProcess(
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.
353 ){
354 g_warning( "CreateProcess failed" );
355 ret = FALSE;
356 }
357 else {
358
359 WaitForSingleObject(pi.hProcess, INFINITE);
360 WaitForSingleObject(pi.hThread, INFINITE);
361
362 CloseHandle(pi.hThread);
363 CloseHandle(pi.hProcess);
364
365 if ( cb )
366 cb(BABEL_DONE, NULL, user_data);
367
368 ret = TRUE;
369 }
370
371 g_strfreev(args2);
372 g_free( cmd );
373
374 return ret;
375}
376/* Windows */
377#else
378/* Posix */
b364d6bc
QT
379gboolean babel_general_convert_to( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_src, gpointer user_data )
380{
2ecf5998 381 gboolean ret = FALSE;
b364d6bc 382 GPid pid;
6c641b1a
MA
383 GError *error = NULL;
384 gint babel_stdout;
b364d6bc 385
f7f8a0a6 386 if (!a_file_export(vt, name_src, FILE_TYPE_GPX, NULL)) {
29a5a545 387 g_warning("%s(): error exporting to %s", __FUNCTION__, name_src);
b364d6bc
QT
388 return(FALSE);
389 }
390
6c641b1a
MA
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);
393 g_error_free(error);
b364d6bc
QT
394 ret = FALSE;
395 } else {
396 gchar line[512];
397 FILE *diag;
398 diag = fdopen(babel_stdout, "r");
399 setvbuf(diag, NULL, _IONBF, 0);
400
401 while (fgets(line, sizeof(line), diag)) {
402 if ( cb )
403 cb(BABEL_DIAG_OUTPUT, line, user_data);
404 }
405 if ( cb )
406 cb(BABEL_DONE, NULL, user_data);
407 fclose(diag);
8c060406 408 diag = NULL;
b364d6bc
QT
409 waitpid(pid, NULL, 0);
410 g_spawn_close_pid(pid);
411
412 ret = TRUE;
413 }
414
415 return ret;
416}
70548902 417#endif /* Posix */
b364d6bc
QT
418
419gboolean a_babel_convert_to( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *to, gpointer user_data )
420{
f3cd9987 421 int i,j;
b364d6bc
QT
422 int fd_src;
423 gchar *name_src;
b364d6bc 424 gboolean ret = FALSE;
f3cd9987 425 gchar *args[64];
b364d6bc 426
2ecf5998 427 if ((fd_src = g_file_open_tmp("tmp-viking.XXXXXX", &name_src, NULL)) >= 0) {
b364d6bc
QT
428 gchar *gpsbabel_loc;
429 close(fd_src);
430
431 gpsbabel_loc = g_find_program_in_path("gpsbabel");
432
433 if (gpsbabel_loc ) {
434 gchar *unbuffer_loc = g_find_program_in_path("unbuffer");
f3cd9987
QT
435 gchar **sub_args = g_strsplit(babelargs, " ", 0);
436
437 i = 0;
438 if (unbuffer_loc)
439 args[i++] = unbuffer_loc;
440 args[i++] = gpsbabel_loc;
441 args[i++] = "-i";
442 args[i++] = "gpx";
443 for (j = 0; sub_args[j]; j++)
e208e3c0
QT
444 /* some version of gpsbabel can not take extra blank arg */
445 if (sub_args[j][0] != '\0')
446 args[i++] = sub_args[j];
447 args[i++] = "-f";
f3cd9987 448 args[i++] = name_src;
e208e3c0 449 args[i++] = "-F";
8398d878 450 args[i++] = (char *)to;
f3cd9987
QT
451 args[i] = NULL;
452
453 ret = babel_general_convert_to ( vt, cb, args, name_src, user_data );
454
455 g_free ( unbuffer_loc );
456 g_strfreev(sub_args);
374b7f45
GB
457 } else
458 g_warning("gpsbabel not found in PATH");
f3cd9987 459 g_free(gpsbabel_loc);
b364d6bc
QT
460 }
461
8c060406 462 g_remove(name_src);
b364d6bc
QT
463 g_free(name_src);
464 return ret;
465}