File Coverage

blib/lib/Video/DVDRip/CPAN/Scanf.pm
Criterion Covered Total %
statement 12 77 15.5
branch 0 48 0.0
condition n/a
subroutine 4 11 36.3
pod 0 5 0.0
total 16 141 11.3


line stmt bran cond sub pod time code
1             package Video::DVDRip::CPAN::Scanf;
2 1     1   6 use Locale::TextDomain qw (video.dvdrip);
  1         2  
  1         7  
3              
4             # This is the unmodified String::Scanf module from Jarkko Hietaniemi
5             # which is just included into this distribution to keep the dependencies
6             # low. According credits are noted in the COPYRIGHT file.
7              
8 1     1   197 use strict;
  1         2  
  1         35  
9              
10 1     1   5 use vars qw($VERSION @ISA @EXPORT);
  1         2  
  1         156  
11              
12             $VERSION = '2.0';
13              
14             require Exporter;
15             @ISA = qw(Exporter);
16             @EXPORT = qw(sscanf);
17              
18             =pod
19              
20             =head1 NAME
21              
22             String::Scanf - emulate sscanf() of the C library
23              
24             =head1 SYNOPSIS
25              
26             use String::Scanf; # imports sscanf()
27              
28             ($a, $b, $c, $d) = sscanf("%d+%d %f-%s", $input);
29             ($e, $f, $g, $h) = sscanf("%x %o %s:%3c"); # input defaults to $_
30              
31             $r = String::Scanf::format_to_re($f);
32              
33             or
34              
35             # works only for Perl 5.005
36             use String::Scanf qw(); # import nothing
37              
38             my $s1 = String::Scanf->new("%d+%d %f-%s");
39             my $s2 = String::Scanf->new("%x %o %s:%3c");
40              
41             ($a, $b, $c, $d) = $s1->sscanf($input);
42             ($e, $f, $g, $h) = $s2->sscanf(); # input defaults to $_
43              
44             =head1 DESCRIPTION
45              
46             String::Scanf supports scanning strings for data using formats
47             similar to the libc/stdio sscanf().
48              
49             The supported sscanf() formats are as follows:
50              
51             =over 4
52              
53             =item %d
54              
55             Decimal integer, with optional plus or minus sign.
56              
57             =item %u
58              
59             Decimal unsigned integer, with optional plus sign.
60              
61             =item %x
62              
63             Hexadecimal unsigned integer, with optional "0x" or "0x" in front.
64              
65             =item %o
66              
67             Octal unsigned integer.
68              
69             =item %e %f %g
70              
71             (The [efg] work identically.)
72              
73             Decimal floating point number, with optional plus or minus sign,
74             in any of these formats:
75              
76             1
77             1.
78             1.23
79             .23
80             1e45
81             1.e45
82             1.23e45
83             .23e45
84              
85             The exponent has an optional plus or minus sign, and the C may also be C.
86              
87             The various borderline cases like C and C are not recognized.
88              
89             =item %s
90              
91             A non-whitespace string.
92              
93             =item %c
94              
95             A string of characters. An array reference is returned containing
96             the numerical values of the characters.
97              
98             =item %%
99              
100             A literal C<%>.
101              
102             =back
103              
104             The sscanf() formats [pnSC] are not supported.
105              
106             The C<%s> and C<%c> have an optional maximum width, e.g. C<%4s>,
107             in which case at most so many characters are consumed (but fewer
108             characters are also accecpted).
109              
110             The numeric formats may also have such a width but it is ignored.
111              
112             The numeric formats may have C<[hl> before the main option, e.g. C<%hd>,
113             but since such widths have no meaning in Perl, they are ignored.
114              
115             Non-format parts of the parameter string are matched literally
116             (e.g. C<:> matches as C<:>),
117             expect that any whitespace is matched as any whitespace
118             (e.g. C< > matches as C<\s+>).
119              
120             =head1 WARNING
121              
122             The numeric formats match only something that looks like a number,
123             they do not care whether it fits into the numbers of Perl. In other
124             words, C<123e456789> is valid for C, but quite probably it
125             won't fit into your Perl's numbers. Consider using the various
126             Math::* modules instead.
127              
128             =head1 AUTHOR, COPYRIGHT AND LICENSE
129              
130             Jarkko Hietaniemi
131              
132             Copyright (c) 2002 Jarkko Hietaniemi. All rights reserved.
133              
134             This program is free software; you can redistribute it and/or modify
135             it under the same terms as Perl itself.
136              
137             =cut
138              
139 1     1   5 use Carp;
  1         2  
  1         1239  
140              
141             sub _format_to_re {
142 0     0     my $format = shift;
143              
144 0           my $re = '';
145 0           my $ix = 0;
146 0           my @fmt;
147             my @reo;
148 0           my $dx = '\d+(?:_\d+)*';
149              
150 0           while ($format =~
151             /(%(?:(?:(\d+)\$)?(\d*)([hl]?[diuoxefg]|[pnsScC%]))|%(\d*)(\[.+?\])|(.+?))/g) {
152 0 0         if (defined $2) { # Reordering.
153 0           $reo[$ix] = $2 - 1;
154             } else {
155 0           $reo[$ix] = $ix;
156             }
157 0 0         if (defined $1) {
158 0 0         if (defined $4) {
    0          
    0          
159 0           my $e;
160 0           my ($w, $f) = ($3, $4);
161 0           $f =~ s/^[hl]//;
162 0 0         if ($f =~ /^[pnSC]$/) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
163 0           croak __x("'{function}' not supported", function => $f);
164             } elsif ($f =~ /^[di]$/) {
165 0           $e = "[-+]?$dx";
166             } elsif ($f eq 'x') {
167 0           $e = '(?:0[xX])?[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*';
168             } elsif ($f eq 'o') {
169 0           $e = '[0-7]+(?:_[0-7]+)*';
170             } elsif ($f =~ /^[efg]$/) {
171 0           $e = "[-+]?(?:(?:$dx(?:\\.(?:$dx)?)?|\\.$dx)(?:[eE][-+]?$dx)?)";
172             } elsif ($f eq 'u') {
173 0           $e = "\\+?$dx";
174             } elsif ($f eq 's') {
175 0 0         $e = $w ? "\\S{0,$w}" : "\\S*";
176             } elsif ($f eq 'c') {
177 0 0         $e = $w ? ".{0,$w}" : ".*";
178             }
179 0 0         if ($f !~ /^[cC%]$/) {
180 0           $re .= '\s*';
181             }
182 0           $re .= "($e)";
183 0           $fmt[$ix++] = $f;
184             } elsif (defined $6) { # [...]
185 0 0         $re .= $5 ? "(${6}{0,$5})" : "($6+)";
186 0           $fmt[$ix++] = '[';
187             } elsif (defined $7) { # Literal.
188 0           my $lit = $7;
189 0 0         if ($lit =~ /^\s+$/) {
190 0           $re .= '\s+';
191             } else {
192 0           $lit =~ s/(.)/\\$1/g;
193 0           $re .= $lit;
194             }
195             }
196             }
197             }
198              
199 0           $re =~ s/\\s\*\\s\+/\\s+/g;
200 0           $re =~ s/\\s\+\\s\*/\\s+/g;
201              
202 0           return ($re, \@fmt, \@reo);
203             }
204              
205             sub format_to_re {
206 0     0 0   my ($re) = _format_to_re $_[0];
207 0           return $re;
208             }
209              
210             sub _match {
211 0     0     my ($format, $re, $fmt, $reo, $data) = @_;
212 0           my @matches = ($data =~ /$re/);
213              
214 0           my $ix;
215 0           for ($ix = 0; $ix < @matches; $ix++) {
216 0 0         if ($fmt->[$ix] eq 'c') {
    0          
217 0           $matches[$ix] = [ map { ord } split //, $matches[$ix] ];
  0            
218             } elsif ($fmt->[$ix] =~ /^[diuoxefg]$/) {
219 0           $matches[$ix] =~ tr/_//d;
220             }
221 0 0         if ($fmt->[$ix] eq 'x') {
    0          
222 0           $matches[$ix] =~ s/^0[xX]//;
223 0           $matches[$ix] = hex $matches[$ix];
224             } elsif ($fmt->[$ix] eq 'o') {
225 0           $matches[$ix] = oct $matches[$ix];
226             }
227             }
228 0           @matches = @matches[@$reo];
229              
230 0           return @matches;
231             }
232              
233             sub new {
234 0     0 0   require 5.005; sub qr {}
  0     0 0    
235 0           my ($class, $format) = @_;
236 0           my ($re, $fmt, $reo) = _format_to_re $format;
237 0           bless [ $format, qr/$re/, $fmt, $reo ], $class;
238             }
239              
240             sub format {
241 0     0 0   $_[0]->[0];
242             }
243              
244             sub sscanf {
245 0     0 0   my $self = shift;
246 0 0         my $data = @_ ? shift : $_;
247 0 0         if (ref $self) {
248 0           return _match(@{ $self }, $data);
  0            
249             }
250 0           _match($self, _format_to_re($self), $data);
251             }
252              
253             1;