make getpeername() return the original socket address which before it was intercepted
[hband-tools.git] / tabdata / mrkv2td
blobe63cc81e3af112ff454fe0229dee351d5bab6c54
1 #!/usr/bin/env perl
3 =pod
5 =head1 NAME
7 mrkv2td - Transform multi-record key-value (MRKV) stream to tabular data format.
9 =head1 DESCRIPTION
11 As tabular data format presents field names at the start of transmission,
12 mrkv2td(1) infers them only from the first record,
13 so no need to buffer the whole dataset to find all fields,
14 and it's usual for all records to have all fields anyways.
16 =head1 OPTIONS
18 =over 4
20 =item -s, --separator I<REGEXP>
22 Regexp which separates field name from cell data in MRKV stream.
23 Default is TAB (C<\t>).
25 =item -g, --multiline-glue I<STRING>
27 =item -i, --ignore-non-existing-columns
29 =item -w, --warn-non-existing-columns
31 =item -c, --column I<NAME>
33 Repeatable option.
35 =back
37 =head1 SEE ALSO
39 td2mrkv(1)
41 =cut
43 $OptSeparatorRegexp = "\t";
44 $OptMultilineGlue = "\n";
45 $OptWarnBadColumnNames = 1;
46 $OptFailBadColumnNames = 1;
47 @OptPredefColumns = ();
48 %OptionDefs = (
49 's|separator=s' => \$OptSeparatorRegexp,
50 'g|multiline-glue=s' => \$OptMultilineGlue,
51 'i|ignore-non-existing-columns' => sub { $OptFailBadColumnNames = 0; $OptWarnBadColumnNames = 0; },
52 'w|warn-non-existing-columns' => sub { $OptFailBadColumnNames = 0; $OptWarnBadColumnNames = 1; },
53 'c|column=s@' => \@OptPredefColumns,
56 use Data::Dumper;
57 use List::MoreUtils qw/all any none/;
58 no if ($] >= 5.018), 'warnings' => 'experimental::smartmatch';
59 do '/usr/lib/tool/perl5/tabdata/common.pl' or die "$@";
62 sub flush_record
64 my $record = shift;
66 if(not $header_sent)
68 print join($FS, map {escape_tabdata($_)} @Headers).$RS;
69 $header_sent = 1;
72 print join($FS, map { escape_tabdata($record->{$_}) } @Headers).$RS;
75 @Headers = ();
76 %record = ();
77 $record_num = 0;
78 $header_sent = 0;
80 while(my $line = <STDIN>)
82 chomp $line;
83 if($line eq '')
85 if(not $header_sent)
87 for my $predef_column (@OptPredefColumns)
89 if(not $predef_column ~~ @Headers)
91 push @Headers, $predef_column;
96 if(%record)
98 flush_record(\%record);
99 %record = ();
100 $record_num++;
103 else
105 my ($field, $cell) = split /$OptSeparatorRegexp/, $line, 2;
106 if(exists $record{$field})
108 $record{$field} .= $OptMultilineGlue . $cell;
110 else
112 $record{$field} = $cell;
115 if($record_num == 0)
117 push @Headers, $field;
119 else
121 if(not $field ~~ @Headers)
123 unless($field ~~ @warned_fields)
125 warn "$0: column not defined: $field\n" if $OptWarnBadColumnNames;
126 push @warned_fields, $field_name;
128 die if $OptFailBadColumnNames;
134 if(%record)
136 flush_record(\%record);
137 %record = ();
138 $record_num++;