2 # transpose_table transposes tables, and is released
3 # under the terms of the GPL version 2, or any later version, at your
4 # option. See the file README and COPYING for more information.
5 # Copyright 2011 by Don Armstrong <don@donarmstrong.com>.
6 # $Id: perl_script 1825 2011-01-02 01:53:43Z don $
17 transpose_table - Transposes a table
24 --tsv, -t tab separated value mode (Default)
25 --ssv, -s space separated value mode
26 --csv, -c comma separated value mode
27 --bigfile,-b Big file; use disk
28 --debug, -d debugging level (Default 0)
29 --help, -h display this help
30 --man, -m display manual
38 Debug verbosity. (Default 0)
42 Display brief usage information.
60 use File::Temp qw(tempdir);
62 use MLDBM qw(DB_File Storable);
66 use List::Util qw(max);
68 my %options = (debug => 0,
79 'debug|d+','help|h|?','man|m');
81 pod2usage() if $options{help};
82 pod2usage({verbose=>2}) if $options{man};
84 $DEBUG = $options{debug};
87 if (0 == grep {exists $options{$_}} qw(tsv ssv csv)) {
90 if (1 < grep {exists $options{$_}} qw(tsv ssv csv)) {
91 push @USAGE_ERRORS,"You can only pass one of --tsv, --ssv, or --csv";
95 # we'll use this as a special indicator to read stdin
99 push @USAGE_ERRORS,"Exactly one file must be specified";
102 pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
108 elsif ($options{ssv}) {
113 for my $file (@ARGV) {
115 if (not defined $file) {
116 ...; # not supported yet; STDIN isn't seekable
121 $in = IO::File->new($file,'r') or
122 die "Unable to open $file for reading: $!";
130 if (not defined $end) {
131 $in->seek(0,SEEK_END);
133 $in->seek(0,SEEK_SET);
136 # from the current position, advance to complete the next field
137 my $next_field = advance_to_field($in,$sep_char);
139 # if we're at the end of the file, stop.
140 if (not $first_time and
144 elsif ($cur_row != 0) {
145 print {$out} $sep_char;
147 # write it to the output file
148 print {$out} $next_field;
150 # avoid writing out a newline if the file was totally empty to start with
151 print {$out} "\n" if not $first_time;
155 # if this is the first time through, store this position for
156 # this row, then find the end of the row [field with a \n as a
157 # terminator] and do the next loop; if we hit the end of the
158 # file, we are no longer the first time through.
159 $row[$cur_row] = $in->tell;
161 print STDERR "\r$cur_row";
163 advance_to_field($in,"\n");
164 $first_row_end = $in->tell if not defined $first_row_end;
167 $in->seek($row[0],SEEK_SET);
172 # otherwise, advance to the next row's position
173 $cur_row = ($cur_row + 1) % @row;
174 $in->seek($row[$cur_row],SEEK_SET);
177 print STDERR "\r".$in->tell."/$first_row_end";
183 sub advance_to_field {
192 $escaped = $escaped ? 0 : 1;
194 if (not $escaped and ($char eq $sep or $char eq "\n")) {