Makefile: remotes: Add bitbucket. Welcome.
[gpstools.git] / gpst
blob628d87a90e250ef2f21c971f4442625353d97933
1 #!/usr/bin/perl
3 #=======================================================================
4 # gpst
5 # File ID: 082106ec-f924-11dd-b757-0001805bf4b1
6 # Converts between various GPS formats
8 # Character set: UTF-8
9 # ©opyleft 2002– Øyvind A. Holm <sunny@sunbase.org>
10 # License: GNU General Public License version 3 or later, see end of
11 # file for legal stuff.
12 #=======================================================================
14 use strict;
15 use warnings;
16 use Getopt::Long;
17 use Time::Local qw { timegm_nocheck };
19 BEGIN {
20 push(@INC, "$ENV{'HOME'}/bin/src/gpstools");
23 use GPST;
24 use GPSTdate;
25 use GPSTdebug;
26 use GPSTgeo;
27 use GPSTxml;
29 $| = 1;
31 our $Debug = 0;
33 our %Opt = (
34 # Initial values for command line arguments {{{
36 'chronology' => 0,
37 'create-breaks' => 0,
38 'debug' => 0,
39 'double-y-scale' => 0,
40 'epoch' => 0,
41 'fix' => 0,
42 'from-date' => "",
43 'help' => 0,
44 'inside' => 0,
45 'output-format' => "gpsml",
46 'outside' => 0,
47 'pos1' => "",
48 'pos2' => "",
49 'require' => "",
50 'round' => "",
51 'save-to-file' => "\n", # \n = undefined, it’s banned in filenames anyway.
52 'short-date' => 0,
53 'skip-dups' => 0,
54 'strip-whitespace' => 0,
55 'time-shift' => 0,
56 'undefined' => "",
57 'verbose' => 0,
58 'version' => 0,
60 # }}}
63 our $progname = $0;
64 $progname =~ s/^.*\/(.*?)$/$1/;
65 our $VERSION = "0.00";
67 Getopt::Long::Configure("bundling");
68 GetOptions(
69 # Command line options {{{
71 "chronology" => \$Opt{'chronology'},
72 "create-breaks|t" => \$Opt{'create-breaks'},
73 "debug" => \$Opt{'debug'},
74 "double-y-scale|y" => \$Opt{'double-y-scale'},
75 "epoch|e" => \$Opt{'epoch'},
76 "fix" => \$Opt{'fix'},
77 "from-date=s" => \$Opt{'from-date'},
78 "help|h" => \$Opt{'help'},
79 "inside" => \$Opt{'inside'},
80 "output-format|o=s" => \$Opt{'output-format'},
81 "outside" => \$Opt{'outside'},
82 "pos1=s" => \$Opt{'pos1'},
83 "pos2=s" => \$Opt{'pos2'},
84 "require|r=s" => \$Opt{'require'},
85 "round|R=s" => \$Opt{'round'},
86 "save-to-file|S=s" => \$Opt{'save-to-file'},
87 "short-date|s" => \$Opt{'short-date'},
88 "skip-dups|d" => \$Opt{'skip-dups'},
89 "strip-whitespace|w" => \$Opt{'strip-whitespace'},
90 "time-shift|T=i" => \$Opt{'time-shift'},
91 "undefined|n=s" => \$Opt{'undefined'},
92 "verbose|v+" => \$Opt{'verbose'},
93 "version" => \$Opt{'version'},
95 # }}}
96 ) || die("$progname: Option error. Use -h for help.\n");
98 my %Dat;
100 my $PAUSE_LIMIT = 2 * 60; # Antall sekunder mellom to punkter det må til før en move legges inn.
101 my $Udef = "?";
102 my $DIGIT = '[0-9\.\-\+]'; # Used in regexps
103 $GPST::Spc = $Opt{'strip-whitespace'} ? "" : " ";
104 my $Spc = $GPST::Spc; # FIXME
105 my $found_move = 0; # Settes til 1 hvis en /^# move$/ blir funnet.
106 my $first_time = 0;
107 my $last_time = 0;
108 my ($last_lon, $last_lat, $last_line) =
109 ( 1000, 1000, ""); # Vi kan jo teoretisk sett være i Greenwich eller på ekvator
110 my ($lat1, $lon1, $lat2, $lon2) =
111 (-1000, -1000, 1000, 1000);
113 our %Cmd = (
114 'gpsbabel' => '/usr/local/bin/gpsbabel',
117 my %Poscount = ();
119 if ($Opt{'output-format'} =~ /^(gpx|pgtab)$/) {
120 $Opt{'require'} .= "p";
122 my %Req = (
123 'ele' => ($Opt{'require'} =~ /e/) ? 1 : 0,
124 'position' => ($Opt{'require'} =~ /p/) ? 1 : 0,
125 'time' => ($Opt{'require'} =~ /t/) ? 1 : 0,
127 $Opt{'require'} =~ /[^ept]/
128 && die("$0: Unknown flag in --require (-r) value\n");
130 $Opt{'debug'} && ($Debug = 1);
131 $Opt{'help'} && usage(0);
132 if ($Opt{'version'}) {
133 print_version();
134 exit(0);
137 if ($Opt{'pos1'} =~ /^($DIGIT+),($DIGIT+)$/) {
138 $lat1 = $1;
139 $lon1 = $2;
141 if ($Opt{'pos2'} =~ /^($DIGIT+),($DIGIT+)$/) {
142 $lat2 = $1;
143 $lon2 = $2;
145 if ($lat1 > $lat2) {
146 my $Tmp = $lat1;
147 $lat1 = $lat2;
148 $lat2 = $Tmp;
150 if ($lon1 > $lon2) {
151 my $Tmp = $lon1;
152 $lon1 = $lon2;
153 $lon2 = $Tmp;
156 if ($Opt{'epoch'} && $Opt{'short-date'}) {
157 die("$progname: Cannot mix the --epoch (-e) and --short-date (-s) options\n");
160 if ($Opt{'inside'} && $Opt{'outside'}) {
161 die("$progname: Cannot mix the --inside and --outside options\n");
164 # To avoid printing out extra "/> at the start of svg output:
165 my $svg_start_thing = "";
167 my %Round = ();
169 if (defined($Opt{'round'})) {
170 my $R = $Opt{'round'};
171 $R =~ s/([a-z]+)=(\d+)/($Round{$1}=$2, "")/eg;
174 length($Opt{'undefined'}) && ($Udef = $Opt{'undefined'});
176 $Opt{'save-to-file'} eq "\n" && print_header(*STDOUT);
178 my @first_lines;
179 my $xml_data;
180 my $data_line = "";
182 my $from_stdin = scalar(@ARGV) ? 0 : 1;
184 $from_stdin && push(@ARGV, "-");
186 for my $curr_file (@ARGV) {
187 # Scan through stdin or specified files and send every GPS entry to
188 # print_entry()
189 # {{{
190 print(STDERR "$progname: Opening \"$curr_file\" for read\n") if $Opt{'verbose'};
191 if (open(my $curr_fp, "<$curr_file")) {
192 # {{{
193 while (<$curr_fp>) {
194 $data_line = $_;
195 %Dat = (
196 'year' => '', 'month' => '', 'day' => '',
197 'hour' => '', 'min' => '', 'sec' => '',
198 'epoch' => '',
199 'date-format' => '',
200 'lat' => '', 'lon' => '',
201 'ele' => '',
202 'desc' => '',
203 'error' => "",
204 'what' => 'tp',
205 'curr_file' => $curr_file,
208 $Opt{'epoch'} && ($Dat{'date-format'} = "epoch");
209 $Opt{'short-date'} && ($Dat{'date-format'} = "short");
211 if ($Opt{'save-to-file'} ne "\n") {
212 push(@first_lines, $_);
214 s/^# error // && ($Dat{'error'} = "error");
215 s/^# ?// && ($Dat{'error'} = "desc");
216 $xml_data = "";
217 if (m#^<(e?tp)\b(.*?)>(.*?)</(e?tp)>\s*$#) {
218 # gpsml — The main storage format {{{
219 my ($Elem, $Props, $Data) =
220 ( $1, $2, $3);
221 my $err_str = ($Props =~ /\berr="(.*?)"/) ? $1 : "error";
222 $Elem eq "etp" && ($Dat{'error'} = $err_str);
223 my $Time = "";
224 $Data =~ m#<time>(.*?)</time># && ($Time = $1);
225 $Time =~ s{
226 (\d\d\d\d)-?(\d\d)-?(\d\d)[T ](\d\d):?(\d\d):?([\d\.]+?)Z
228 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
229 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}) =
230 ( $1, $2, $3,
231 $4, $5, $6);
233 }ex;
234 $Data =~ m#<lat>($DIGIT*?)</lat># && ($Dat{'lat'} = $1);
235 $Data =~ m#<lon>($DIGIT*?)</lon># && ($Dat{'lon'} = $1);
236 $Data =~ m#<ele>($DIGIT*?)</ele># && ($Dat{'ele'} = $1);
237 $Data =~ m#<desc>(.*?)</desc># && ($Dat{'desc'} = $1);
238 print_entry(%Dat);
239 # }}}
240 } elsif (m#^<break\b.*?/>#) {
241 $found_move = 1;
242 } elsif (m#^<(title|pause)\b.*?>(.*?)</(title|pause)>#) {
243 $Dat{'what'} = $1;
244 $Dat{$1} = $2;
245 print_entry(%Dat);
246 } elsif (m#^<desc\b.*?>(.*$)#s) {
247 $Dat{'what'} = "desc";
248 my $Txt = $1;
249 until ($Txt =~ m#</desc>#s) {
250 $Txt .= <$curr_fp>;
252 $Txt =~ s#^(.*)(</desc>.*$)#$1#s;
253 $Dat{'desc'} = $Txt;
254 print_entry(%Dat);
255 } elsif (/<gpx\b/) {
256 $xml_data = $_;
257 $xml_data .= join("", <$curr_fp>);
258 if (!length($Opt{'output-format'})) {
259 $Opt{'output-format'} = "gpx";
260 print_header(*STDOUT);
262 read_xmlfile($xml_data);
263 last;
264 } elsif (/^move$/) {
265 $found_move = 1;
266 } elsif (m#^(\d+)\t($DIGIT+)\t($DIGIT+)\t($DIGIT)#) {
267 # CSV format, epoch style {{{
268 my ($ep_time, $lon_val, $lat_val, $Alt) =
269 ( $1, $2, $3, $4);
270 $Dat{'epoch'} = $ep_time;
271 ($Dat{'sec'}, $Dat{'min'}, $Dat{'hour'},
272 $Dat{'day'}, $Dat{'month'}, $Dat{'year'},
273 $Dat{'wday'}, $Dat{'yday'}) = gmtime($ep_time);
274 $Dat{'month'}++; # Urgh Ⅰ
275 $Dat{'year'} += 1900; # Urgh Ⅱ
276 print_entry(%Dat);
277 # }}}
278 } elsif (
280 (\d\d\d\d)-?(\d\d)-?(\d\d)[T\ ](\d\d):?(\d\d):?(\d\d)Z?\t
281 ($DIGIT+)\t($DIGIT+)\t($DIGIT)
284 # CSV format, human-readable date format {{{
285 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
286 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'},
287 $Dat{'lon'}, $Dat{'lat'}, $Dat{'ele'}) =
288 ($1, $2, $3,
289 $4, $5, $6,
290 $7, $8, $9);
291 print_entry(%Dat);
292 # }}}
293 } elsif (/^Trackpoint\t/) {
294 # Trackpoint\tN60.41630 E5.31675\t09.02.2006 20:24:37 (UTC)\t13.6 m\t\t93.9 m\t00:00:06\t56 kph\t123° true {{{
296 # Trackpoint\t
297 # N60.41630 E5.31675\t
298 # 09.02.2006 20:24:37 (UTC)\t
299 # 13.6 m\t
300 # \t
301 # 93.9 m\t
302 # 00:00:06\t
303 # 56 kph\t
304 # 123° true
305 my $Orig = $_;
306 $Orig =~ s/[\r\n]+$//;
307 my ($Marker_f, $Position_f, $Time_f, $Alt_f, $Depth_f,
308 $Leglength_f, $Legtime_f, $Legspeed_f, $Legcourse_f) =
309 split(/\t/, $Orig .
310 # Nødløsning for å unngå at variabler
311 # blir udefinert.
312 "\t\t\t\t\t\t\t\t\t\t"
314 # D(join("",
315 # "Position_f=\"$Position_f\" \x7B\x7B\x7B\n",
316 # "Time_f=\"$Time_f\"\n",
317 # "Alt_f=\"$Alt_f\"\n",
318 # "Depth_f=\"$Depth_f\"\n",
319 # "Leglength_f=\"$Leglength_f\"\n",
320 # "Legtime_f=\"$Legtime_f\"\n",
321 # "Legspeed_f=\"$Legspeed_f\"\n",
322 # "Legcourse_f=\"$Legcourse_f\" \x7D\x7D\x7D\n",
323 # ));
324 my ($NS, $WE,
325 $Alt_unit,
326 $Leglength,
327 $Legtime_hour, $Legtime_min, $Legtime_sec,
328 $Legspeed, $Legspeed_unit,
329 $Legcourse
330 ) = ("", "", "", "", "", "", "", "", "", "", "", "", "",
331 "", "", "", "", "", "", "", "", "", "");
332 ($Position_f =~ /^(N|S)([\d\.]+) (W|E)([\d\.]+)/) &&
333 ($NS = $1, $Dat{'lat'} = $2, $WE = $3, $Dat{'lon'} = $4);
334 ($Time_f =~ /^(\d+)\.(\d+)\.(\d+) (\d+):(\d+):(\d+) \((.+?)\)/) &&
335 ($Dat{'day'} = $1, $Dat{'month'} = $2, $Dat{'year'} = $3,
336 $Dat{'hour'} = $4, $Dat{'min'} = $5, $Dat{'sec'} = $6);
337 ($Alt_f =~ /^($DIGIT+) (.*?)/) &&
338 ($Dat{'ele'} = $1, $Alt_unit = $2);
339 # D("ele = \"$Dat{'ele'}\"");
340 ($NS eq "S") && ($Dat{'lat'} = 0-$Dat{'lat'});
341 ($WE eq "W") && ($Dat{'lon'} = 0-$Dat{'lon'});
342 # MapSource in win xp writes YYYY, but YY in win98se.
344 defined($Dat{'year'})
345 && $Dat{'year'} =~ /\d/
346 && $Dat{'year'} < 1900
347 ) && ($Dat{'year'} += 2000);
348 print_entry(%Dat);
349 # }}}
350 } elsif (/^Track\t(.*?)\t/) {
351 $Dat{'title'} = txt_to_xml($1);
352 $Dat{'what'} = "title";
353 $found_move = 1;
354 print_entry(%Dat);
355 } elsif (
358 (\d\d)/(\d\d)/(\d\d\d\d)\ (\d\d):(\d\d):(\d\d)\t
359 (.+)\xB0(.+)'(.+)"\t
360 (.+)\xB0(.+)'(.+)"
363 # T 09/01/2002 11:51:26 60°23'36.3" 5°19'35.9" {{{
364 my ($lat_d, $lat_m, $lat_s, $lon_d, $lon_m, $lon_s);
365 ($Dat{'month'}, $Dat{'day'}, $Dat{'year'},
366 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'},
367 $lat_d, $lat_m, $lat_s,
368 $lon_d, $lon_m, $lon_s) =
369 ($1, $2, $3,
370 $4, $5, $6,
371 $7, $8, $9,
372 $10, $11, $12);
373 my $Flat = defined($Round{'lat'}) ? ".$Round{'lat'}" : "";
374 my $Flon = defined($Round{'lon'}) ? ".$Round{'lon'}" : "";
375 $Dat{'lat'} = sprintf("%${Flat}f",
376 1.0*($lat_d+($lat_m/60)+($lat_s/3600)));
377 $Dat{'lon'} = sprintf("%${Flon}f",
378 1.0*$lon_d+($lon_m/60)+($lon_s/3600));
379 print_entry(%Dat);
380 # }}}
381 } elsif (
383 1\ (\S+)\ (\S+)\ (\S+)\ (\S+)\x20
384 (\d\d)/(\d\d)/(\d\d\d\d)\ (\d\d):(\d\d):(\d\d)
387 # 1 60.3938222 5.3238754 17.3 0 09/01/2002 14:18:23 {{{
388 ($Dat{'lat'}, $Dat{'lon'}, $Dat{'speed'},
389 $Dat{'unkn'},
390 $Dat{'month'}, $Dat{'day'}, $Dat{'year'},
391 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}) =
392 ($1, $2, $3,
394 $5, $6, $7,
395 $8, $9, $10);
396 print_entry(%Dat);
397 # }}}
398 } elsif (/^
399 # @020721221336N6048353E00701826S015-00001E4859N1673U0000 {{{
400 # Regexp {{{
401 (@) # @
402 (\d\d) # Year
403 (\d\d) # Month
404 (\d\d) # Day
405 (\d\d) # Hours
406 (\d\d) # Minutes
407 (\d\d) # Seconds
408 ([NS]) # N|S
409 (\d\d) # Latitude degree
410 (\d\d) # Latitude minute
411 (\d\d\d) # Latitude minute decimals
412 ([EW]) # E|W
413 (\d\d\d) # Longitude degree
414 (\d\d) # Longitude minute
415 (\d\d\d) # Longitude minute degree
416 (....) # Accurancy
417 (......) # Elevation
418 (...............)
419 # }}}
420 /x) {
421 my ($NS, $EW, $lat_deg, $lat_degmin, $lat_mindec, $lon_deg,
422 $lon_degmin, $lon_mindec);
423 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'}, $Dat{'hour'},
424 $Dat{'min'}, $Dat{'sec'}, $NS, $lat_deg,
425 $lat_degmin, $lat_mindec, $EW,
426 $lon_deg, $lon_degmin, $lon_mindec,
427 $Dat{'accur'}, $Dat{'ele'}, $Dat{'unknown'}) =
428 ($2+2000, $3, $4, $5,
429 $6, $7, $8, $9,
430 $10, $11, $12,
431 $13, $14, $15,
432 $16, $17, $18);
433 my $ep_time = timegm_nocheck(
434 $Dat{'sec'}, $Dat{'min'}, $Dat{'hour'},
435 $Dat{'day'}, $Dat{'month'}-1, $Dat{'year'}
437 $last_time = $ep_time;
438 my $Flat = defined($Round{'lat'}) ? ".$Round{'lat'}" : "";
439 my $Flon = defined($Round{'lon'}) ? ".$Round{'lon'}" : "";
440 my $tmp_lon = sprintf(
441 "%${Flon}f",
442 $lon_deg +
443 $lon_degmin/60 +
444 $lon_mindec/60000);
445 my $tmp_lat = sprintf("%${Flat}f",
446 $lat_deg +
447 $lat_degmin/60 +
448 $lat_mindec/60000);
449 ($NS eq "S") && ($tmp_lat = 0-$tmp_lat);
450 ($EW eq "W") && ($tmp_lon = 0-$tmp_lon);
451 $Dat{'lat'} = $tmp_lat;
452 $Dat{'lon'} = $tmp_lon;
453 print_entry(%Dat);
454 # }}}
455 } elsif (/^(@)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(_{42})/) {
456 # @020721221336__________________________________________ {{{
457 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
458 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}, $Dat{'rest'}) =
459 ($2+2000, $3, $4,
460 $5, $6, $7, $8);
461 $Dat{'error'} = "nosignal";
462 print_entry(%Dat);
463 # }}}
464 } elsif (/^xmaplog /) {
465 # NOP
466 } elsif (/^$/) {
467 ($Opt{'output-format'} eq "csv")
468 && ($Opt{'save-to-file'} eq "\n")
469 && print("\n");
470 } elsif (/^Pause: /) {
471 # NOP, is here to cope with old files I’ve lying around.
472 } elsif ($Dat{'error'} eq "desc") {
473 my $Comment = $_;
474 if (defined($Comment)) {
475 $Comment =~ s/^\s*(.*?)\s*$/$1/;
476 if ($Opt{'output-format'} eq "gpsml") {
477 $Dat{'desc'} = txt_to_xml($Comment);
478 $Dat{'what'} = "desc";
479 print_entry(%Dat);
482 } else {
483 $Opt{'verbose'} && warn("Line $.: Unknown: \"$_\"\n");
486 # }}}
487 } else {
488 warn("$progname: $curr_file: Cannot open file for read: $!\n");
490 # }}}
493 print_footer(*STDOUT);
495 exit(0);
497 sub read_xmlfile {
498 # {{{
499 my $Txt = join("", @_);
500 $Txt =~ s/<!--(.*?)-->//gs;
501 $Txt =~ s#(<gpx\b.*?>.*?</gpx>)#print_gpx($1)#gse;
502 # }}}
503 } # read_xmlfile()
505 sub print_gpx {
506 # {{{
507 my $Orig = shift;
508 my $Str = $Orig;
509 # D("print_xml_gps(\"$Orig\")\n");
510 $Str =~ s/<!--(.*?)-->//gs;
511 my $fromdate_str = "";
512 if ($Opt{'from-date'}) {
513 $fromdate_str = "date >= '$Opt{'from-date'}' AND ";
515 if ($Opt{'output-format'} =~ /^(pgwtab|pgwupd)$/) {
516 # {{{
517 $Str =~
519 <wpt\b(.*?)>(.*?)</wpt>
522 my $attr_wpt = $1;
523 my $el_wpt = $2;
524 my ($Lat, $Lon, $Name, $Ele, $Type, $Time, $Cmt, $Desc, $Src, $Sym) =
525 ('\N', '\N', '\N', '\N', '\N', '\N', '\N', '\N', '\N', '\N');
527 $attr_wpt =~ /.*lat="($DIGIT+?)"/s &&
528 ($Lat = postgresql_copy_safe($1));
529 $attr_wpt =~ /.*lon="($DIGIT+?)"/s &&
530 ($Lon = postgresql_copy_safe($1));
531 $el_wpt =~ /.*<name\b(.*?)>(.*?)<\/name>/s &&
532 ($Name = postgresql_copy_safe(xml_to_txt($2)));
533 $el_wpt =~ /.*<ele\b(.*?)>(.*?)<\/ele>/s &&
534 ($Ele = postgresql_copy_safe(xml_to_txt($2)));
535 $el_wpt =~ /.*<type\b(.*?)>(.*?)<\/type>/s &&
536 ($Type = postgresql_copy_safe(xml_to_txt($2)));
537 $el_wpt =~ /.*<time\b(.*?)>(.*?)<\/time>/s &&
538 ($Time = postgresql_copy_safe(xml_to_txt($2)));
539 $el_wpt =~ /.*<cmt\b(.*?)>(.*?)<\/cmt>/s &&
540 ($Cmt = postgresql_copy_safe(xml_to_txt($2)));
541 $el_wpt =~ /.*<desc\b(.*?)>(.*?)<\/desc>/s &&
542 ($Desc = postgresql_copy_safe(xml_to_txt($2)));
543 $el_wpt =~ /.*<src\b(.*?)>(.*?)<\/src>/s &&
544 ($Src = postgresql_copy_safe(xml_to_txt($2)));
545 $el_wpt =~ /.*<sym\b(.*?)>(.*?)<\/sym>/s &&
546 ($Sym = postgresql_copy_safe(xml_to_txt($2)));
548 if (length($Opt{'round'})) {
549 if (defined($Round{'lat'}) && length($Lat)) {
550 ($Lat = 1.0 * sprintf("%.$Round{'lat'}f", $Lat));
552 if (defined($Round{'lon'}) && length($Lon)) {
553 ($Lon = 1.0 * sprintf("%.$Round{'lon'}f", $Lon));
555 if (defined($Round{'ele'}) && $Ele ne '\N') {
556 ($Ele = 1.0 * sprintf("%.$Round{'ele'}f", $Ele));
560 if ($Opt{'output-format'} eq "pgwtab") {
561 print(
562 join("\t",
563 "($Lat,$Lon)",
564 $Name,
565 $Ele,
566 $Type,
567 $Time,
568 $Cmt,
569 $Desc,
570 $Src,
571 $Sym
572 ) . "\n"
574 } elsif ($Opt{'output-format'} eq "pgwupd") {
575 $Name =~ s/'/''/gs;
576 print(join("\n",
577 "BEGIN;",
578 "$Spc${Spc}UPDATE logg SET name = clname(coor) " .
579 "WHERE $fromdate_str(point($Lat,$Lon) <-> coor) < 0.05;",
580 "$Spc${Spc}UPDATE logg SET dist = cldist(coor) " .
581 "WHERE $fromdate_str(point($Lat,$Lon) <-> coor) < 0.05;",
582 "COMMIT;"
583 ) . "\n");
586 }gsex;
587 # }}}
588 } else {
589 # {{{
590 $Str =~
592 <trk\b(.*?)>(.*?)</trk>
595 my $el_trk = $2;
596 $el_trk =~
598 <name\b(.*?)>(.*?)</name>
600 my %tmp_dat = ();
601 $tmp_dat{'title'} = $2;
602 $tmp_dat{'what'} = "title";
603 $tmp_dat{'error'} = "";
604 print_entry(%tmp_dat);
606 }sex;
607 $el_trk =~
609 <trkseg\b(.*?)>(.*?)</trkseg>
612 my $el_trkseg = $2;
613 $el_trkseg =~
615 <trkpt\b(.*?)>(.*?)</trkpt>
618 my ($attr_trkpt, $el_trkpt) =
619 ( $1, $2);
620 %Dat = (
621 'year' => '', 'month' => '', 'day' => '',
622 'hour' => '', 'min' => '', 'sec' => '',
623 'epoch' => '',
624 'date-format' => '',
625 'lat' => '', 'lon' => '',
626 'ele' => '',
627 'desc' => '',
628 'error' => "",
629 'what' => 'tp',
631 ($attr_trkpt =~ /\blon="(.*?)"/) && ($Dat{'lon'} = $1);
632 ($attr_trkpt =~ /\blat="(.*?)"/) && ($Dat{'lat'} = $1);
633 ($el_trkpt =~ m#<ele\b.*?>(.*?)</ele>#) && ($Dat{'ele'} = $1);
634 if (
635 $el_trkpt =~
637 <time>(\d\d\d\d)-?(\d\d)-?(\d\d)T
638 (\d\d):?(\d\d):?([\d\.]+)Z</time>
641 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
642 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}) =
643 ($1, $2, $3, $4, $5, $6);
645 print_entry(%Dat);
647 }gsex;
648 $found_move = 1;
649 }gsex;
650 $found_move = 1;
651 }gsex;
652 # }}}
654 # }}}
655 } # print_gpx()
657 sub print_header {
658 # {{{
659 my $out_fp = shift;
660 if ($Opt{'output-format'} eq "gpsml") {
661 print($out_fp join("",
662 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
663 "<gpsml>\n",
664 "<track>\n",
666 } elsif ($Opt{'output-format'} eq "gpstrans") {
667 print($out_fp "Format: DMS UTC Offset: 0.00 hrs " .
668 "Datum[100]: WGS 84\n");
669 } elsif ($Opt{'output-format'} eq "gpx") {
670 print($out_fp join("",
671 qq{<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n},
672 qq{<gpx\n},
673 qq{$Spc${Spc}version="1.1"\n},
674 qq{$Spc${Spc}creator="gpst - http://sunny256.github.com/gpstools/"\n},
675 qq{$Spc${Spc}xmlns="http://www.topografix.com/GPX/1/1"\n},
676 qq{$Spc${Spc}xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n},
677 qq{$Spc${Spc}xsi:schemaLocation="http://www.topografix.com/GPX/1/1 },
678 qq{http://www.topografix.com/GPX/1/1/gpx.xsd"\n},
679 qq{>\n},
680 qq{$Spc$Spc<trk>\n},
681 qq{$Spc$Spc$Spc$Spc<trkseg>\n},
683 } elsif ($Opt{'output-format'} eq "ps") {
684 print($out_fp ps_header(532, 6034, 533, 6040));
685 print($out_fp "*u\n");
686 } elsif ($Opt{'output-format'} eq "svg") {
687 print($out_fp join("",
688 "<?xml version=\"1.0\" standalone=\"no\"?>\n",
689 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
690 "$Spc$Spc\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
691 "<svg height=\"1000\" width=\"1000\" viewBox=\"23 70 2 2\"\n",
692 "$Spc${Spc}xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n",
693 "$Spc$Spc<title></title>\n",
694 "$Spc$Spc<desc></desc>\n",
697 # }}}
698 } # print_header()
700 sub print_footer {
701 # Print footer {{{
702 my $out_fp = shift;
703 if ($Opt{'output-format'} eq "gpsml") {
704 print($out_fp join("",
705 "</track>\n",
706 "</gpsml>\n",
708 } elsif ($Opt{'output-format'} eq "gpx") {
709 print($out_fp join("",
710 "$Spc$Spc$Spc$Spc</trkseg>\n",
711 "$Spc$Spc</trk>\n",
712 "</gpx>\n",
714 } elsif ($Opt{'output-format'} eq "poscount") {
715 while (my ($l_name, $l_val) = each %Poscount) {
716 $l_name =~ /^(.+?),(.+?)$/
717 && print($out_fp "$1\t$2\t$l_val\n");
719 } elsif ($Opt{'output-format'} eq "ps") {
720 print($out_fp join("",
721 "*U\n",
722 "%%Trailer\n",
723 "%%EOF\n",
725 } elsif ($Opt{'output-format'} eq "svg") {
726 print($out_fp "\"/>\n</svg>\n");
728 # }}}
729 } # print_footer()
731 sub print_entry {
732 # Print a GPS entry with time, latitude, longitude and elevation in
733 # various formats
734 # {{{
735 my %Dat = @_;
736 defined($Dat{'desc'}) || ($Dat{'desc'} = "");
737 defined($Dat{'ele'}) || ($Dat{'ele'} = "");
738 defined($Dat{'lat'}) || ($Dat{'lat'} = "");
739 defined($Dat{'lon'}) || ($Dat{'lon'} = "");
740 defined($Dat{'year'}) || ($Dat{'year'} = "");
741 my $print_time = length($Dat{'year'}) ? 1 : 0;
742 my $print_pos;
743 if (!$Req{'position'} && $Opt{'output-format'} eq "gpsml") {
744 $print_pos = (length($Dat{'lat'}) || length($Dat{'lon'})) ? 1 : 0;
745 } else {
746 $print_pos = (length($Dat{'lat'}) && length($Dat{'lon'})) ? 1 : 0;
748 if (!$print_pos) {
749 $Dat{'lat'} = $Dat{'lon'} = "";
751 my $print_ele = length($Dat{'ele'}) ? 1 : 0;
752 my $print_desc = length($Dat{'desc'}) ? 1 : 0;
753 my $Line = "";
754 # D("print_entry(\"" . join("\", \"", @_) . "\");");
755 my $ep_time;
757 if (length($Opt{'round'})) {
758 for my $Tmp (qw{ lat lon ele }) {
759 if (defined($Round{$Tmp}) && length($Dat{$Tmp})) {
760 # D("Tmp = '$Tmp'");
761 ($Dat{$Tmp} = num_expand(1.0 * sprintf("%.$Round{$Tmp}f", $Dat{$Tmp})));
766 if ($Opt{'output-format'} eq "poscount") {
767 # FIXME: Sort output in some way
768 if (!length($Dat{'error'})) {
769 $Dat{'lat'} = num_expand($Dat{'lat'});
770 $Dat{'lon'} = num_expand($Dat{'lon'});
771 my $Name = "$Dat{'lon'},$Dat{'lat'}";
772 defined($Poscount{$Name}) || ($Poscount{$Name} = 0);
773 $Poscount{$Name}++;
775 return;
778 if ($print_time) {
779 $ep_time = timegm_nocheck(
780 $Dat{'sec'}, $Dat{'min'}, $Dat{'hour'},
781 $Dat{'day'}, $Dat{'month'} - 1, $Dat{'year'}
783 if ($Opt{'time-shift'}) {
784 # D("ep_time før: '$ep_time'");
785 $ep_time += $Opt{'time-shift'};
786 # D("ep_time etter: '$ep_time'");
787 ($Dat{'sec'}, $Dat{'min'},$Dat{'hour'}, $Dat{'day'},
788 $Dat{'month'}, $Dat{'year'}) = gmtime($ep_time);
789 $Dat{'year'} += 1900;
790 $Dat{'month'}++;
792 $Dat{'epoch'} = $ep_time;
793 $Dat{'year'} = sprintf("%04u", $Dat{'year'});
794 $Dat{'month'} = sprintf("%02u", $Dat{'month'});
795 $Dat{'day'} = sprintf("%02u", $Dat{'day'});
796 $Dat{'hour'} = sprintf("%02u", $Dat{'hour'});
797 $Dat{'min'} = sprintf("%02u", $Dat{'min'});
798 $Dat{'sec'} = sprintf("%02u", $Dat{'sec'});
799 if ($Opt{'chronology'}) {
800 if ($last_time > $ep_time && !length($Dat{'error'})) {
801 warn(sprintf(
802 "%s: $Dat{'curr_file'}: \"%sZ\": Next date is %s in the past (%sZ)\n",
803 $progname, sec_to_string($last_time, "T"),
804 sec_to_readable($last_time-$ep_time),
805 sec_to_string($ep_time, "T")
807 # FIXME: Make --fix work with gpx.
808 if ($Opt{'fix'} && ($Opt{'output-format'} !~ /^gpx$/)) {
809 $Dat{'error'} = "chrono";
811 } elsif ($last_time == $ep_time && !length($Dat{'error'})) {
812 warn(sprintf(
813 "%s: $Dat{'curr_file'}: \"%sZ\": Duplicated time\n",
814 $progname, sec_to_string($last_time, "T")
816 # FIXME: Make --fix work with gpx.
817 if ($Opt{'fix'} && ($Opt{'output-format'} !~ /^gpx$/)) {
818 $Dat{'error'} = "duptime";
822 } else {
823 $ep_time = 0;
824 $Dat{'year'} = 0;
825 $Dat{'month'} = 0;
826 $Dat{'day'} = 0;
827 $Dat{'hour'} = 0;
828 $Dat{'min'} = 0;
829 $Dat{'sec'} = 0;
832 if ($Opt{'save-to-file'} ne "\n") {
833 # {{{
834 $print_time || return;
835 my $base_name = "$Dat{'year'}$Dat{'month'}$Dat{'day'}T" .
836 "$Dat{'hour'}$Dat{'min'}$Dat{'sec'}Z" .
837 "$Opt{'save-to-file'}";
838 my $file_name = $base_name;
839 if (-e $file_name) {
840 for (my $a = 1; (-e $file_name) && ($a < 1000); $a++) {
841 $file_name = "$base_name.dup_$a";
843 if (-e $file_name) {
844 die("$progname: $base_name: File already exists, and ran " .
845 "out of attempts to create unique file name\n");
847 if ($Opt{'verbose'}) {
848 warn("$progname: $base_name: File already exists, using " .
849 "unique name \"$file_name\" instead\n");
852 if (open(my $to_fp, ">", $file_name)) {
853 print_header(*$to_fp);
854 print($to_fp (
855 $from_stdin
856 ? @first_lines
857 : ()),
858 (length($xml_data)
859 ? $xml_data
860 : <>)
861 ) || die("$progname: $file_name: Cannot write to file: $!\n");
862 print_footer(*$to_fp);
863 close($to_fp);
864 if ($Opt{'output-format'} eq "gpsml") {
865 printf("<include>%s</include>\n",
866 txt_to_xml($file_name));
867 } elsif ($Opt{'output-format'} eq "gpx") {
868 printf("<!-- Saved unconverted data to \"%s\" -->\n",
869 txt_to_xml($file_name));
870 } else {
871 print("$progname: Saved unconverted data to \"$file_name\"\n");
873 exit 0;
874 } else {
875 die("$progname: $file_name: Cannot create file: $!\n");
877 # }}}
880 my $pause_len = 0;
881 my $do_print = 1;
883 if ($Dat{'what'} eq "tp") {
884 # {{{
885 if ($Opt{'require'}) {
886 $Req{'time'} && !$print_time && return;
887 $Req{'position'} && !$print_pos && return;
888 $Req{'ele'} && !$print_ele && return;
891 if ($Opt{'inside'} || $Opt{'outside'}) {
892 if (
893 ($Dat{'lat'} < $lat1) ||
894 ($Dat{'lat'} > $lat2) ||
895 ($Dat{'lon'} < $lon1) ||
896 ($Dat{'lon'} > $lon2)
898 $Opt{'inside'} && return;
899 } else {
900 $Opt{'outside'} && return;
904 if ($Opt{'output-format'} eq "ps") {
905 $Dat{'lon'} *= 100;
906 $Dat{'lat'} *= 100;
909 if (
910 $Opt{'skip-dups'}
911 && ($Dat{'lon'} eq $last_lon)
912 && ($Dat{'lat'} eq $last_lat)
914 if ($Opt{'output-format'} eq 'gpsml') {
915 $Dat{'error'} = "dup";
916 } else {
917 $do_print = 0;
919 } else {
920 $do_print = 1;
923 if (
924 $Opt{'create-breaks'}
925 && $ep_time-$last_time > $PAUSE_LIMIT
926 && $last_time
928 $pause_len = $ep_time-$last_time;
929 # D("pause_len set to '$pause_len'");
932 $Line .= pause_entry($pause_len, $ep_time, $last_time);
933 # }}}
936 if ($do_print) {
937 # Valid data was found, send to stdout {{{
938 unless ($first_time) {
939 $first_time = $ep_time;
941 $Line .= gen_entry($print_pos, $pause_len, $print_time, $ep_time, $print_ele, %Dat);
942 # }}}
945 if (!$last_time && $Opt{'output-format'} eq "ps") {
946 $Line .= "$Dat{'lon'} $Dat{'lat'} m\n";
949 if ($do_print) {
950 if ($found_move) {
951 if ($Opt{'output-format'} eq "gpsml") {
952 $Line = "<break/>\n$Line";
954 (!$pause_len && ($Opt{'output-format'} eq "xgraph"))
955 && ($Line .= "move $Line");
956 ($Opt{'output-format'} eq "clean") && ($Line .= "\n");
957 if ($Opt{'output-format'} eq "gpx") {
958 $Line .= "$Spc$Spc$Spc$Spc</trkseg>\n" .
959 "$Spc$Spc$Spc$Spc<trkseg>\n";
961 $found_move = 0;
963 print($Line);
965 $print_time && ($last_time = $ep_time);
966 if ($print_pos) {
967 $last_lon = $Dat{'lon'};
968 $last_lat = $Dat{'lat'};
970 $last_line = $data_line;
971 $svg_start_thing = "\"/>\n";
972 # }}}
973 } # print_entry()
975 sub gen_entry {
976 # Generate trackpoint entry, calls trackpoint() {{{
977 my ($print_pos, $pause_len, $print_time, $ep_time, $print_ele, %Dat) = @_;
978 my $Line = "";
979 if ($Opt{'double-y-scale'} && length($Dat{'lat'})) {
980 $Dat{'lat'} *= 2;
982 if ($Opt{'output-format'} eq "gpsml") {
983 if ($Dat{'what'} eq "tp") {
984 $Dat{'format'} = "gpsml";
985 $Line .= trackpoint(%Dat);
986 } elsif ($Dat{'what'} =~ /^(pause|desc|title)$/) {
987 $Line .= sprintf("<%s>%s</%s>\n",
989 $Dat{$1},
990 $1);
992 } elsif ($Opt{'output-format'} eq "pgtab") {
993 if ($Dat{'what'} eq "tp" && !length($Dat{'error'})) {
994 $Dat{'format'} = "pgtab";
995 $Line .= trackpoint(%Dat);
997 } elsif ($Opt{'output-format'} eq "xgraph") {
998 if ($print_pos && !length($Dat{'error'})) {
999 $Dat{'format'} = "xgraph";
1000 $Line .= trackpoint(%Dat);
1002 } elsif($Opt{'output-format'} eq "gpstrans") {
1003 if ($print_pos && !length($Dat{'error'})) {
1004 $Dat{'format'} = "gpstrans";
1005 $Line .= trackpoint(%Dat);
1007 } elsif($Opt{'output-format'} eq "gpx") {
1008 if ($Dat{'what'} eq "tp") {
1009 $Dat{'format'} = "gpx";
1010 $Line .= trackpoint(%Dat);
1012 } elsif ($Opt{'output-format'} eq "clean") {
1013 if ($Dat{'what'} eq "tp" && !length($Dat{'error'})) {
1014 $Dat{'format'} = "clean";
1015 $Line .= trackpoint(%Dat);
1017 } elsif ($Opt{'output-format'} eq "ps") {
1018 $Line .= (
1019 $pause_len
1020 ? "f\n$Dat{'lon'} $Dat{'lat'} m\n"
1021 : "$Dat{'lon'} $Dat{'lat'} l\n"
1023 } elsif ($Opt{'output-format'} eq "svg") {
1024 $Line .= (
1025 ($last_lon == 1000) || $pause_len
1026 ? join("",
1027 "$svg_start_thing<path\n",
1028 " stroke=\"blue\"\n",
1029 " stroke-width=\"0.001\"\n",
1030 " fill=\"none\"\n",
1031 " d=\"\n",
1032 "M $Dat{'lon'} $Dat{'lat'}\n")
1033 : "L $Dat{'lon'} $Dat{'lat'}\n"
1035 } elsif ($Opt{'output-format'} eq "ygraph") {
1036 if (!length($Dat{'error'})) {
1037 $Dat{'lat'} = num_expand($Dat{'lat'});
1038 $Dat{'lon'} = num_expand($Dat{'lon'});
1039 $Dat{'ele'} = num_expand($Dat{'ele'});
1040 my $Time = $print_time ? ($ep_time - $first_time) * 1 : 0;
1041 $Line .= "\"Time = $Time.0\n$Dat{'lon'} $Dat{'lat'}\n\n";
1043 } elsif ($Opt{'output-format'} eq "csv") {
1044 # {{{
1045 if (!length($Dat{'error'})) {
1046 $Dat{'format'} = "csv";
1047 $Dat{'lat'} = num_expand($Dat{'lat'});
1048 $Dat{'lon'} = num_expand($Dat{'lon'});
1049 $Dat{'ele'} = num_expand($Dat{'ele'});
1050 $Line .= join("\t",
1051 $print_time
1052 ? $Opt{'epoch'}
1053 ? $ep_time
1054 : $Opt{'short-date'}
1055 ? "$Dat{'year'}$Dat{'month'}$Dat{'day'}T" .
1056 "$Dat{'hour'}$Dat{'min'}$Dat{'sec'}Z"
1057 : "$Dat{'year'}-$Dat{'month'}-$Dat{'day'}T" .
1058 "$Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}Z"
1059 : "",
1060 $Dat{'lon'},
1061 $Dat{'lat'},
1062 $print_ele ? $Dat{'ele'} : "", # Elevation
1063 "\n"
1066 # }}}
1067 } elsif ($Opt{'output-format'} eq "pgwtab") {
1068 # FIXME: NOP at the moment.
1069 } else {
1070 die("$progname: \"$Opt{'output-format'}\": " .
1071 "Unknown output format\n");
1073 return($Line);
1074 # }}}
1075 } # gen_entry()
1077 sub pause_entry {
1078 # {{{
1079 my ($pause_len, $ep_time, $last_time) = @_;
1080 my $Line = "";
1081 if ($pause_len) {
1082 if ($Opt{'output-format'} eq "gpsml") {
1083 $Line .= sprintf("<pause>%s</pause>\n",
1084 sec_to_readable($ep_time-$last_time));
1085 } elsif ($Opt{'output-format'} eq "clean") {
1086 $pause_len && ($Line .= "\n");
1087 } elsif ($Opt{'output-format'} eq "csv") {
1088 $Line .= sprintf("# Pause: %s\n# move\n",
1089 sec_to_readable($ep_time-$last_time));
1090 } elsif ($Opt{'output-format'} eq "xgraph") {
1091 $pause_len && ($Line .= "move ");
1094 return($Line);
1095 # }}}
1096 } # pause_entry()
1098 sub ps_header {
1099 # Send a Postscript header to stdout {{{
1100 my ($bl_lon, $bl_lat, $br_lon, $br_lat) = @_;
1101 my $Date = sec_to_string(time);
1102 return(join("",
1103 "%!PS-Adobe-3.0 EPSF-3.0\n",
1104 "%%Creator: gpst\n",
1105 "%%Title:\n",
1106 "%%CreationDate: $Date\n",
1107 "%%BoundingBox: $bl_lon $bl_lat $br_lon $br_lat\n",
1108 "%%DocumentData: Clean7Bit\n",
1109 "%%EndComments\n",
1110 "%%BeginProlog\n",
1111 "/bd { bind def } bind def\n",
1112 "/incompound false def\n",
1113 "/m { moveto } bd\n",
1114 "/l { lineto } bd\n",
1115 "/c { curveto } bd\n",
1116 "/F { incompound not {fill} if } bd\n",
1117 "/f { closepath F } bd\n",
1118 "/S { stroke } bd\n",
1119 "/*u { /incompound true def } bd\n",
1120 "/*U { /incompound false def f} bd\n",
1121 "/k { setcmykcolor } bd\n",
1122 "/K { k } bd\n",
1123 "%%EndProlog\n",
1124 "%%BeginSetup\n",
1125 "%%EndSetup\n",
1127 # }}}
1128 } # ps_header()
1130 sub print_version {
1131 # Print program version {{{
1132 print("$progname v$VERSION\n");
1133 # }}}
1134 } # print_version()
1136 sub usage {
1137 # Send the help message to stdout {{{
1138 my $Retval = shift;
1140 if ($Opt{'verbose'}) {
1141 print("\n");
1142 print_version();
1144 print(<<END);
1146 Converts between various GPS formats.
1148 Usage: $progname [options] [file [files [...]]]
1149 $progname -S [file [files [...]]]
1150 $progname -u [file [files [...]]]
1152 Options:
1154 --chronology
1155 Check for broken chronology, warn about entries with an old
1156 timestamp.
1157 -d, --skip-dups
1158 Skip duplicated coordinates.
1159 -e, --epoch
1160 Use seconds since 1970-01-01 00:00:00 GMT as date format.
1161 --fix
1162 Comment out entries which is obviously wrong. Use together with
1163 --chronology to fix those kind of errors. Does not work with GPX
1164 output yet.
1165 --from-date x
1166 Used by the pgwupd format. Specifies from which date waypoints
1167 should be updated. No checks for valid date format here, let
1168 PostgreSQL take care of that. All variants it understands can be
1169 used here.
1170 -h, --help
1171 Show this help.
1172 --inside
1173 Print only trackpoints inside a rectangle specified by --pos1 and
1174 --pos2.
1175 -n, --undefined x
1176 Use x as undefined value. Default: "$Udef".
1177 -o, --output-format x
1178 Use output format x:
1179 clean
1181 gpsml (Default)
1182 gpstrans
1183 gpx (Not complete)
1184 pgtab
1185 pgwtab
1186 pgwupd
1187 poscount
1188 ps (Unfinished)
1189 svg (Unfinished)
1190 xgraph
1191 ygraph
1192 --outside
1193 Print only trackpoints outside a rectangle specified by --pos1 and
1194 --pos2.
1195 --pos1 x
1196 --pos2 x
1197 Specifies one corner where x is in "lat,lon" format (decimal
1198 degrees, negative for west or south) of area rectangle used by the
1199 --inside and --outside options.
1200 -r, --require x
1201 Specify requirements for trackpoints to be written. x is a string
1202 with the following flags:
1204 Print only waypoints which have an elevation.
1206 Print only waypoints which have a position.
1208 Print only waypoints which have a timestamp.
1209 -R, --round x=y[,x2=y2[...]]
1210 Round trackpoint element x to y decimals. Example:
1211 --round lat=4,lon=5,ele=1
1212 -s, --short-date
1213 Use short date format.
1214 -S, --save-to-file x
1215 Save the unconverted data to a file with a filename starting with
1216 the timestamp of the first trackpoint. The parameter string x is
1217 added at the end of the filename. For the time being this option
1218 will ignore all other options. Note: If several files are specified
1219 on the command line, all data will be saved into only one file. This
1220 behaviour may change in the future.
1221 -t, --create-breaks
1222 Create breaks in track between points with a difference more than
1223 $PAUSE_LIMIT seconds.
1224 -T x, --time-shift x
1225 Move time of trackpoint x seconds forwards or backwards. x can be a
1226 positive or negative integer.
1227 -v, --verbose
1228 Increase level of verbosity. Can be repeated.
1229 --version
1230 Print version information.
1231 -w, --strip-whitespace
1232 Strip all unnecessary whitespace.
1233 -y, --double-y-scale
1234 Double Y scale (latitude) to get it right in gnuplot.
1235 --debug
1236 Print debugging messages.
1239 exit($Retval);
1240 # }}}
1241 } # usage()
1243 sub msg {
1244 # Print a status message to stderr based on verbosity level {{{
1245 my ($verbose_level, $Txt) = @_;
1247 if ($Opt{'verbose'} >= $verbose_level) {
1248 print(STDERR "$progname: $Txt\n");
1250 # }}}
1251 } # msg()
1253 __END__
1255 # Law talk {{{
1256 # Copyleft © Øyvind A. Holm <sunny@sunbase.org>
1258 This program is free software: you can redistribute it and/or modify it
1259 under the terms of the GNU General Public License as published by the
1260 Free Software Foundation, either version 3 of the License, or (at your
1261 option) any later version.
1263 This program is distributed in the hope that it will be useful, but
1264 WITHOUT ANY WARRANTY; without even the implied warranty of
1265 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1266 See the GNU General Public License for more details.
1268 You should have received a copy of the GNU General Public License along
1269 with this program.
1270 If not, see L<http://www.gnu.org/licenses/>.
1271 # }}}
1273 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :