Use "#!/usr/bin/env perl" in all Perl scripts
[gpstools.git] / gpst-file
blob9f85170a4f89e0f14d77cf34a453ceb482e339e5
1 #!/usr/bin/env perl
3 #=======================================================================
4 # gpst-file
5 # File ID: 86736de4-00a1-11de-acc1-000475e441b9
6 # Generate TAB streams of files with modification time for use with COPY
7 # in Postgres
9 # Character set: UTF-8
10 # ©opyleft 2009– Øyvind A. Holm <sunny@sunbase.org>
11 # License: GNU General Public License version 3 or later, see end of
12 # file for legal stuff.
13 #=======================================================================
15 use strict;
16 use warnings;
17 use Getopt::Long;
19 BEGIN {
20 push(@INC, "$ENV{'HOME'}/bin/src/gpstools");
21 our @version_array;
24 use GPST;
25 use GPSTxml;
27 $| = 1;
29 our $Debug = 0;
30 our $NA = '\N';
31 our %Std = (
33 'output-format' => 'pgtab',
34 'timezone' => '',
37 our %Opt = (
39 'author' => '',
40 'debug' => 0,
41 'description' => '',
42 'help' => 0,
43 'output-format' => $Std{'output-format'},
44 'strip-whitespace' => 0,
45 'timezone' => $Std{'timezone'},
46 'verbose' => 0,
47 'version' => 0,
51 our $progname = $0;
52 $progname =~ s/^.*\/(.*?)$/$1/;
53 our $VERSION = "0.00";
55 Getopt::Long::Configure("bundling");
56 GetOptions(
58 "author|a=s" => \$Opt{'author'},
59 "debug" => \$Opt{'debug'},
60 "description|d=s" => \$Opt{'description'},
61 "help|h" => \$Opt{'help'},
62 "output-format|o=s" => \$Opt{'output-format'},
63 "strip-whitespace|w" => \$Opt{'strip-whitespace'},
64 "timezone|T=s" => \$Opt{'timezone'},
65 "verbose|v+" => \$Opt{'verbose'},
66 "version" => \$Opt{'version'},
68 ) || die("$progname: Option error. Use -h for help.\n");
70 $Opt{'debug'} && ($Debug = 1);
71 $Opt{'help'} && usage(0);
72 if ($Opt{'version'}) {
73 print_version();
74 exit(0);
77 $GPST::Spc = $Opt{'strip-whitespace'} ? "" : " ";
78 my $Spc = $GPST::Spc; # FIXME
79 my $tz_str = "";
80 if (length($Opt{'timezone'})) {
81 if ($Opt{'timezone'} =~ /^[\+\-][0-2][0-9]{3}$/) {
82 $tz_str = $Opt{'timezone'};
83 } elsif ($Opt{'timezone'} =~ /^z$/i) {
84 $tz_str = $Opt{'timezone'};
85 } elsif ($Opt{'timezone'} =~ /^[a-z]+$/i) {
86 $tz_str = " $Opt{'timezone'}";
87 } else {
88 die("$progname: $Opt{'timezone'}: Invalid time zone\n");
90 $tz_str = uc($tz_str);
93 if ($Opt{'output-format'} eq "xml") {
94 print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpstfile>\n");
97 if ($#ARGV < 0) {
98 while (<>) {
99 chomp();
100 print_entry($_);
102 } else {
103 for my $fname (@ARGV) {
104 print_entry($fname);
108 if ($Opt{'output-format'} eq "xml") {
109 print("</gpstfile>\n");
112 sub print_entry {
113 # {{{
114 my $filename = shift;
115 my $Retval = 0;
116 my ($date, $coor) =
117 ('', '');
118 D("filename = '$filename'");
119 if (my @stat_array = stat($filename)) {
120 my @TA = localtime($stat_array[9]);
121 $date = sprintf("%04u-%02u-%02uT%02u:%02u:%02u%s",
122 $TA[5]+1900, $TA[4]+1, $TA[3], $TA[2], $TA[1], $TA[0], $tz_str);
123 D("tz_str = '$tz_str'");
124 $filename =~ s/^.*\/(.*?)$/$1/;
125 my $Output = "";
126 if ($Opt{'output-format'} eq "xml") {
127 if (length("$filename$date")) {
128 $Output = join("",
129 "$Spc$Spc<file>\n",
130 length($filename)
131 ? sprintf("$Spc$Spc$Spc$Spc<filename>%s</filename>\n",
132 txt_to_xml($filename))
133 : "",
134 length($date)
135 ? sprintf("$Spc$Spc$Spc$Spc<date>%s</date>\n",
136 txt_to_xml($date))
137 : "",
138 length($Opt{'description'})
139 ? sprintf("$Spc$Spc$Spc$Spc<desc>%s</desc>\n",
140 txt_to_xml($Opt{'description'}))
141 : "",
142 length($Opt{'author'})
143 ? sprintf("$Spc$Spc$Spc$Spc<author>%s</author>\n",
144 txt_to_xml($Opt{'author'}))
145 : "",
146 "$Spc$Spc</file>\n",
149 } elsif ($Opt{'output-format'} eq "pgtab") {
150 # Version information {{{
151 # Version 1:
152 # "1" \t
153 # date \t
154 # "(lat,lon)"-coordinates \t
155 # description \t
156 # filename \t
157 # author \n
158 # }}}
159 $Output = pgtab_entry(
160 1, # Version number
161 $date,
162 $coor,
163 $Opt{'description'},
164 $filename,
165 $Opt{'author'}
167 } else {
168 die("$progname: $Opt{'output-format'}: Unknown output format\n");
170 print($Output);
171 $Opt{'verbose'} && print(STDERR $Output);
172 } else {
173 warn("$progname: $filename: Cannot stat file: $!\n");
175 return($Retval);
176 # }}}
177 } # print_entry()
179 sub pgtab_entry {
180 # {{{
181 my ($Version, $Date, $Coor, $Descr, $Filename, $Author) = @_;
182 defined($Date) || ($Date = $NA);
183 defined($Coor) || ($Coor = $NA);
184 defined($Descr) || ($Descr = $NA);
185 defined($Filename) || ($Filename = $NA);
186 defined($Author) || ($Author = $NA);
187 my $Retval = "";
188 if ($Version == 1) {
189 $Retval = join("\t",
190 1, # Version number
191 postgresql_copy_safe($Date),
192 length($Coor)
193 ? postgresql_copy_safe($Coor)
194 : $NA,
195 length($Opt{'description'})
196 ? postgresql_copy_safe($Opt{'description'})
197 : $NA,
198 length($Filename)
199 ? postgresql_copy_safe($Filename)
200 : $NA,
201 length($Opt{'author'})
202 ? postgresql_copy_safe($Opt{'author'})
203 : $NA
204 ) . "\n";
206 return($Retval);
207 # }}}
208 } # pgtab_entry()
210 sub print_version {
211 # Print program version {{{
212 print("$progname v$VERSION\n");
213 # }}}
214 } # print_version()
216 sub usage {
217 # Send the help message to stdout {{{
218 my $Retval = shift;
220 if ($Opt{'verbose'}) {
221 print("\n");
222 print_version();
224 print(<<END);
226 Usage: $progname [options] [file [files [...]]]
228 Generate TAB streams with filenames and file modification time for use
229 with PostgreSQL’s COPY command. If no filenames are specified on the
230 command line, file names are read from stdin.
232 Options:
234 -a, --author x
235 Specify author of file.
236 -d, --description x
237 Specify description for file.
238 -h, --help
239 Show this help.
240 -v, --verbose
241 Increase level of verbosity. Can be repeated.
242 -o x, --output-format x
243 Create output of type x:
245 pgtab
246 Default: "$Std{'output-format'}".
247 -T X, --timezone X
248 Prepend X as timezone to the date. Valid formats:
249 UTC offset
250 A '+' or '-' followed by a four-digit number (HHMM) which
251 indicates the offset relative to UTC. Examples:
252 +0000
253 -1600
254 +0630
255 Time zone abbreviation. Examples:
259 -w, --strip-whitespace
260 Strip all unnecessary whitespace.
261 --version
262 Print version information.
263 --debug
264 Print debugging messages.
267 exit($Retval);
268 # }}}
269 } # usage()
271 sub msg {
272 # Print a status message to stderr based on verbosity level {{{
273 my ($verbose_level, $Txt) = @_;
275 if ($Opt{'verbose'} >= $verbose_level) {
276 print(STDERR "$progname: $Txt\n");
278 # }}}
279 } # msg()
281 sub D {
282 # Print a debugging message {{{
283 $Debug || return;
284 my @call_info = caller;
285 chomp(my $Txt = shift);
286 my $File = $call_info[1];
287 $File =~ s#\\#/#g;
288 $File =~ s#^.*/(.*?)$#$1#;
289 print(STDERR "$File:$call_info[2] $$ $Txt\n");
290 return("");
291 # }}}
292 } # D()
294 __END__
296 # Plain Old Documentation (POD) {{{
298 =pod
300 =head1 NAME
304 =head1 SYNOPSIS
306 [options] [file [files [...]]]
308 =head1 DESCRIPTION
312 =head1 OPTIONS
314 =over 4
316 =item B<-h>, B<--help>
318 Print a brief help summary.
320 =item B<-v>, B<--verbose>
322 Increase level of verbosity. Can be repeated.
324 =item B<--version>
326 Print version information.
328 =item B<--debug>
330 Print debugging messages.
332 =back
334 =head1 BUGS
338 =head1 AUTHOR
340 Made by Øyvind A. Holm S<E<lt>sunny@sunbase.orgE<gt>>.
342 =head1 COPYRIGHT
344 Copyleft © Øyvind A. Holm E<lt>sunny@sunbase.orgE<gt>
345 This is free software; see the file F<COPYING> for legalese stuff.
347 =head1 LICENCE
349 This program is free software: you can redistribute it and/or modify it
350 under the terms of the GNU General Public License as published by the
351 Free Software Foundation, either version 3 of the License, or (at your
352 option) any later version.
354 This program is distributed in the hope that it will be useful, but
355 WITHOUT ANY WARRANTY; without even the implied warranty of
356 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
357 See the GNU General Public License for more details.
359 You should have received a copy of the GNU General Public License along
360 with this program.
361 If not, see L<http://www.gnu.org/licenses/>.
363 =head1 SEE ALSO
365 =cut
367 # }}}
369 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :