File Coverage

blib/lib/Fortran/F90Format.pm
Criterion Covered Total %
statement 6 283 2.1
branch 0 148 0.0
condition 0 52 0.0
subroutine 2 16 12.5
pod 3 14 21.4
total 11 513 2.1


line stmt bran cond sub pod time code
1             package Fortran::F90Format;
2              
3 1     1   12580 use Carp;
  1         2  
  1         599  
4              
5             our $VERSION = '0.40';
6              
7             sub new {
8 0     0 1   my $class = shift;
9 0           my $self = {};
10              
11 0           bless $self,$class;
12              
13 0           return $self->init(@_)
14              
15             }
16              
17             sub init {
18 0     0 0   my $self = shift;
19 0           my %opt = (
20             fmt => '',
21             @_,
22             );
23 0 0         croak "No format string !\n" unless $opt{fmt};
24 0           $self->{for_fmt} = $opt{fmt};
25 0 0         if ( $self->{for_fmt} ne '*' ) {
26 0           $self->parse();
27             }
28 0           return $self
29             }
30             sub read {
31 0     0 1   my $self = shift;
32 0           my $line = shift;
33 0           my $val =[] ;
34 0 0         if ( $self->{for_fmt} eq '*' ) {
35 0           $val = $self->parse_val($line);
36             }
37             else {
38 0           $val = [ unpack($self->{pack_fmt},$line) ];
39             }
40 0 0         return wantarray ? @$val : $val;
41             }
42             sub for2for {
43 0     0 0   my $self = shift;
44 0           my $f = shift;
45 0           my $p=[];
46 0           my ($n,$w,$m,$d,$e,$ed)=('')x6;
47 0 0         if ( $f =~ /^(\'|\").+(\'|\")$/ ) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
48 0           $f=~ s/^(\'|\")//;
49 0           $f=~ s/(\'|\")$//;
50 0           push @$p ,( {str => $f } );
51 0           return $p
52             }
53             elsif( $f =~ /^(\d+)(H)/i ){
54 0           my $l = $1;
55 0           $f =~ s/^\d+[Hh]//;
56 0           push @$p ,( {str => pack("a$l",$f) } );
57 0           return $p
58             }
59 1     1   1025 elsif ( $f =~ /^(\p{Letter})+$/ ) {
  1         11  
  1         13  
60 0           $n=1; $ed = $1;
  0            
61             }
62             elsif ( $f =~ /^(\p{Letter})+(\d+)$/ ) {
63 0           $n = 1; $ed = $1; $w=$2;
  0            
  0            
64             }
65             elsif ( $f =~ /^(\p{Letter})+(\d+)\.(\d+)$/ ) {
66 0           $n = 1; $ed = $1; $w=$2;$d=$3;
  0            
  0            
  0            
67             }
68             elsif ( $f =~ /^(\p{Letter})+(\d+)\.(\d+)(E|e)(\d+)$/ ) {
69 0           $n = 1; $ed = $1; $w=$2; $d=$3;$e=$5;
  0            
  0            
  0            
  0            
70             }
71             elsif ( $f =~ /^(\d+)(\p{Letter})+$/ ) {
72 0           $n = $1; $ed = $2;
  0            
73             }
74             elsif ( $f =~ /^(\d+)(\p{Letter})+(\d+)$/ ) {
75 0           $n = $1; $ed = $2; $w=$3;
  0            
  0            
76             }
77             elsif ( $f =~ /^(\d+)(\p{Letter})+(\d+)\.(\d+)$/ ) {
78 0           $n = $1; $ed = $2; $w=$3; $d=$4;
  0            
  0            
  0            
79             }
80             elsif ( $f =~ /^(\d+)(\p{Letter})+(\d+)\.(\d+)(E|e)(\d+)$/ ) {
81 0           $n = $1; $ed = $2; $w=$3; $d=$4;$e=$6;
  0            
  0            
  0            
  0            
82             }
83 0           push @$p , ( { ed => $ed , w => $w , d => $d , e => $e } ) x $n;
84 0           return $p
85             }
86             sub wrt_F {
87 0     0 0   my $h = shift;
88 0           my $val = shift;
89 0           my ($l,$r,$sign,$int,$dot,$frac)=('')x6;
90 0           my @fn;
91 0           my $fmt = '%';
92 0           $val=sprintf "% .*f",length(trim($val))+3,$val;
93 0           $val=~ /(-|\+| )(\d+)(\.)(\d+)/;
94 0           $l = $h->{d}+1;
95 0           $sign = $1; $int=$2; $dot=$3; $frac=pack("A$l",$4);
  0            
  0            
  0            
96 0           @fn=split('',pack("A$l",$4));
97 0           $sign =~ s/(\+| )//;
98 0 0         $int = '' if ! $int;
99 0 0 0       if ( $frac == 0 && ! $int ) {
100 0           $sign = '';
101 0           $int = '0';
102             }
103 0           $r = $h->{w} - length("$sign$int$dot") - $h->{d};
104 0 0         if ( $r < 0 ) { return '*'x$h->{w}; }
  0            
105 0           $frac = join('',@fn[0..$h->{d}-1]);
106 0 0         $frac++ if $fn[$#fn] >= 5;
107 0           $frac = pack("a$h->{d}",$frac);
108 0           $val = sprintf "% $h->{w}s","$sign$int$dot$frac";
109 0           return $val
110             }
111             sub wrt_E {
112 0     0 0   my $h = shift;
113 0           my $val = shift;
114 0           my ($sign,$int,$dot,$frac,$e_d,$e_d_s,$exp)=('')x7;
115 0           $val=sprintf "% .*e",$h->{w}+1,$val;
116 0           $val =~ /(-|\+| )(\d+)(\.)(\d+)([Ee])(\+|-)(\d+)/;
117 0 0         $sign = $1 eq ' ' ? '' : $1 ;
118 0           $int = $2;
119 0           $dot = $3;
120 0           $frac = $4;
121 0           $e_d = $5;
122 0           $e_d_s = $6;
123 0           $exp = $7;
124 0 0 0       $exp-- if $int && $e_d_s eq '-';
125 0 0 0       $exp++ if $int && $e_d_s eq '+';
126 0           $e_d = $h->{ed};
127 0 0 0       if ( $h->{e} ) {
    0          
    0          
128 0 0         if ( $exp <= (10**$h->{e}-1) ) {
129 0           $exp = sprintf("%0$h->{e}d",$exp);
130             }
131             }elsif ( $exp <= 99 ) {
132 0           $exp = sprintf("%02d",$exp);
133             }elsif( 99 < $exp && $exp <= 999 ) {
134 0           $exp = sprintf("%03d",$exp);
135             }
136 0           $frac="$int$frac";
137 0           $l=$h->{d}+1;
138 0           @fn=split('',pack("A$l",$frac));
139 0           $frac = join('',@fn[0..$#fn-1]);
140 0 0         $frac++ if $fn[$#fn] >= 5;
141 0           $frac = pack("a$h->{d}",$frac);
142 0           my $v= sprintf("% $h->{w}s","${sign}0.$frac$e_d$e_d_s$exp");
143 0           return $v
144             }
145             sub wrt_I {
146 0     0 0   my $h = shift;
147 0           my $val = shift;
148 0           my $int = abs($val);
149 0 0         croak "Bad integer $val\n" if int($val) != $val ;
150 0           my $plus = '';
151 0 0         my $sign = $val < 0 ? '-' : $plus;
152            
153 0           my ($w,$d);
154 0   0       $w= $h->{w} || 7;
155 0   0       $d = $h->{d} || '';
156 0 0         if ( ! $d ) {
157 0 0         if ( $val ) {
158 0           $val = sprintf ( "%*d",$w,$val) ;
159             }else {
160 0 0         if ( $d eq '' ) {
161 0           $val = sprintf ( "% *d",$w,0);
162             } else {
163 0           $val = sprintf ( "% *s",$w,' ');
164             }
165             }
166             } else {
167 0           $val = sprintf( "%*.*d",$w,$d,$val);
168             }
169 0 0 0       if ( $d > $w || length("$sign$int") > $w ) {
170 0           $val = '*'x$w;
171             }
172 0           return $val
173             }
174             sub wrt_X {
175 0     0 0   my $h = shift;
176 0   0       my $w = $h->{w}||1;
177 0           my $n = $w;
178 0           return ' 'x$n
179             }
180             sub wrt_A {
181 0     0 0   my $h = shift;
182 0           my $val = shift;
183 0 0         if ( $h->{w} ) {
184 0           return pack("a$h->{w}",sprintf ("% *s",$h->{w},"$val") );
185             } else {
186 0           return sprintf('%s',$val);
187             }
188             }
189              
190             sub write {
191 0     0 1   my $self = shift;
192 0           my @vals = @_;
193 0           my ($i,$j,$ed);
194 0 0         if ( $self->{for_fmt} eq '*' ) {
195 0           return "@vals\n";
196             }
197 0           my $out='';
198 0           foreach my $f ( @{$self->{for_array}} ){
  0            
199 0           $ed = uc $f->{ed};
200 0 0         if( $ed eq 'X' ){
    0          
201 0           $out .= wrt_X($f);
202             }elsif ( exists $f->{str} ) {
203 0           $out .= $f->{str};
204             }else{
205 0 0 0       if ( $ed eq 'A' ) {
    0          
    0          
    0          
206 0           $out .= wrt_A($f,$vals[$i]);
207             }elsif ( $ed eq 'I' ) {
208 0           $out .= wrt_I($f,$vals[$i]);
209             }elsif ( $ed eq 'F' ) {
210 0           $out .= wrt_F($f,$vals[$i]);
211             }elsif( $ed eq 'E' || $ed eq 'D'){
212 0           $out .= wrt_E($f,$vals[$i]);
213             }
214 0 0         last if $i++ > $#vals;
215             }
216             }
217 0           return "$out\n"
218             }
219              
220             sub parse {
221 0     0 0   my $self= shift;
222 0   0       my $fmt = shift || $self->{for_fmt};
223 0           my @chars = split '',$fmt;
224 0           my @vars;
225 0           my ($c,$r,$t,$d,@desc,$s);
226 0           my (@rep,@tok,@stack);
227 0           while ( @chars ) {
228 0           $c = shift @chars;
229 0           $s.=$c;
230 0 0 0       if ( ($c eq "'" || $c eq "\"") && ! $t ) {
    0 0        
    0 0        
    0          
    0          
231 0           $t=$c;
232 0           my $ch = shift @chars;
233 0           while ( $ch ne $c ) {
234 0           $t.=$ch;
235 0 0         $ch = @chars ? shift @chars :
236             croak "unfinished quotedstring:|$t|\n";
237             }
238 0           $t.=$ch;
239 0 0         if ( ! @rep ) {
    0          
240 0 0         push @stack,$t if $t;
241             } elsif ( @tok ) {
242 0 0         unshift @tok,$t if $t;
243             }
244 0           $t='';
245             } elsif ( "$t$c" =~ /^\d+$/ && $chars[0] =~ /H/i ) {
246 0           my $n = "$t$c";
247 0           my $h = shift @chars;
248 0           my $ch = shift @chars;
249 0           for ( 1..$n-1 ) { $ch.=shift @chars; }
  0            
250 0 0         if ( ! @rep ) {
    0          
251 0           push @stack,"$n$h$ch";
252             } elsif ( @tok ) {
253 0           unshift @tok,"$n$h$ch";
254             }
255 0           $t='';
256             } elsif ( $c eq '(' ) { #begin nested record
257 0 0         if ( ! $t ) { $t=1 };
  0            
258 0           unshift @rep,$t;
259 0           unshift @tok,$c;
260 0           $t='';
261             } elsif ( $c eq ')') { # end processing nested record
262 0           $r = shift @rep;
263 0 0         unshift @tok,$t if $t;
264 0           $d = shift @tok;
265 0           while ( $d ne '(' ) {
266 0           unshift @desc,$d;
267 0           $d = shift @tok;
268             }
269 0           $t= join('__,__',(@desc)x($r));
270 0           @desc=();
271 0 0         if ( ! @rep ) {
272 0           my @bits = split(/__,__/,$t);
273 0 0         push @stack,@bits if $t;
274             } else {
275 0 0         unshift @tok, $t if $t;
276             }
277 0           $t='';
278             } elsif ( $c eq ',' ) { # save token
279 0 0         if ( ! @rep ) {
    0          
280 0 0         push @stack,$t if $t;
281             } elsif ( @tok ) {
282 0 0         unshift @tok,$t if $t;
283             }
284 0           $t='';
285             } else {
286 0 0         $t.=$c if $c ne ' ';
287             }
288             }
289 0 0         push @stack,$t if $t;
290 0           my (@pack,@for);
291 0           foreach my $v ( @stack ) {
292 0           push @for, @{$self->for2for($v)};
  0            
293 0           push @pack, $self->for2pack($v);
294             }
295 0           $self->{for_fmt} = join(',',@stack);
296 0           $self->{for_array} = \@for;
297 0           $self->{pack_fmt} = join(" ",@pack);
298 0           $self->{pack_array} = \@pack;
299             }
300              
301             sub for2pack {
302 0     0 0   my $self = shift;
303 0           my $f = shift;
304 0           my $p='';
305 0 0         if ( $f =~ /^(\'|\").*(\'|\")$/ ) {
    0          
306 0           $f=~ s/^(\'|\")//;
307 0           $f=~ s/(\'|\")$//;
308 0           $p='x'.length($f);
309 0           return $p
310             }elsif( $f =~ /^\d+[H]/i ){
311 0           $f =~ s/^\d+[Hh]//;
312 0           $p='x'.length($f);
313 0           return $p
314             }
315 0           $f =~ /(\p{Letter}+)/;
316 0           my $d=$1;
317 0           my ($n,$w)=split(/\p{Letter}+/,$f);
318 0   0       $n||=1 ;
319 0 0         if ( $d =~ /(A|B|D|E|F|G|Q|I|L|O|Z)/i ) {
    0          
320 0 0         $w = abs(int($w)) if $w;
321 0 0 0       $w = '*' if ! $w && uc($d) eq 'A';
322 0   0       $w||=1 ;
323 0           $d = 'a';
324 0           $p = join(' ',("$d$w")x$n);
325             } elsif ( $d =~ /X/i ) {
326 0   0       $w||=1 ;
327 0           $w = abs(int($w));
328 0           $d ='x';
329 0           $p = "$d$w"x$n;
330 0           $p = join(' ',("$d$w")x$n);
331             }
332 0           return $p
333             }
334              
335             sub parse_val {
336 0     0 0   my $self = shift;
337 0           my $val = shift;
338 0   0       my $var = shift ||'';
339 0           my $values = [];
340 0           my $all = $val ;
341 0           my $ok = 1;
342 0 0         return [$val] if $val =~ /\.(true|false)\./i ;
343 0           while ( $val =~ / (\s*,\s*|\s*) # match starting null value
344             ((\s*\d+\s*)\*|) # match multiplier
345             ( # begin matching values
346             \s*\'.*?\'\s* | # quoted string
347             \s*\w+\s* | # quoted string
348             [DdEe_0-9\.\-\+\:]+ | # numeric variable
349             \s*\( # start complex number
350             [\s0-9\.DdEeIi\-\+]+ # real part
351             \s* , \s* # comma
352             [\s0-9\.DdEeIi\-\+]+ # imaginary part
353             \)\s* | # end complex number
354             \s*,\s* # separator
355             ) # end matching values
356             ( # begin separators:
357             \s*,\s* | # match null value ',,'
358             \s* | # blanks spaces,tabs,etc
359             $ # end of string or new line
360             ) # end separators
361             /xmsg ) {
362 0           my $nv = $1;
363 0           my $ntimes = $2;
364 0   0       my $n = $3 || 1;
365 0           my $c = $4 ;
366 0           my $sep = $5;
367 0           my $pv = $c;
368 0           $nv = trim($nv);
369 0 0         push @$values,$nv if $nv;
370            
371 0           $pv =~ s/(\+|\(|\)|\.)/\\$1/g;
372 0           $ntimes =~ s/(\*)/\\$1/g;
373 0           $all =~ s/($nv$ntimes$pv$sep)?//;
374 0 0 0       $ok = ! $sep && $c eq ',' ? 0 : 1;
375 0 0         push @$values,(trim($c))x($n) if $ok ;
376             }
377 0           return $values
378             }
379              
380              
381             sub trim {
382 0     0 0   my $s = shift;
383 0           $s =~ s/^\s+//;
384 0           $s =~ s/\s+$//;
385 0           return $s
386             }
387              
388             1;
389              
390             __DATA__