File Coverage

blib/lib/Text/Sprintf/Zenkaku.pm
Criterion Covered Total %
statement 140 140 100.0
branch 54 54 100.0
condition 2 2 100.0
subroutine 9 9 100.0
pod 2 2 100.0
total 207 207 100.0


line stmt bran cond sub pod time code
1             package Text::Sprintf::Zenkaku;
2 3     3   26666 use 5.008001;
  3         9  
3 3     3   10 use strict;
  3         4  
  3         45  
4 3     3   13 use warnings;
  3         3  
  3         71  
5 3     3   512 use utf8;
  3         10  
  3         12  
6 3     3   48 use Carp;
  3         3  
  3         167  
7 3     3   1408 use Encode;
  3         20185  
  3         213  
8              
9             our $VERSION = "0.07";
10              
11 3     3   14 use Exporter 'import';
  3         3  
  3         2705  
12             our @EXPORT_OK = qw(sprintf);
13              
14             our $cp932 = Encode::find_encoding("cp932");
15              
16             our $conversions = $] lt 5.022000 ? qr/\A[cduoxefgXEGbBpn]\Z/ : qr/\A[cduoxefgXEGbBpnaA]\Z/;
17              
18             sub calc_width {
19 114     114 1 109 my ($w, $s) = @_;
20              
21 114         69 my $ofs;
22 114 100       122 if ($w >= 0) {
23 89         338 $ofs = $w - ((length $cp932->encode($s)) - (length $s));
24             } else {
25 25         106 $ofs = (abs $w) - ((length $cp932->encode($s)) - (length $s));
26 25         30 $ofs *= -1;
27             }
28              
29 114         157 return $ofs;
30             }
31              
32             sub sprintf {
33 95     95 1 51015 my @argv = @_;
34 95   100     192 my $fmt = $argv[0] // "";
35              
36 95         80 my $ofs = 0;
37 95         72 my $state = "IDL";
38              
39 95         69 my $index = 1;
40 95         74 my $tmp = "";
41 95         63 my $fmt_new = "";
42 95         80 my $length = length $fmt;
43 95         97 my $is_uniq = {};
44              
45 95         149 while ($ofs < $length) {
46 869         708 my $s = substr $fmt, $ofs, 1;
47 869 100       1358 if ($state eq "IDL") {
    100          
    100          
48 314 100       306 if ($s eq "%") {
49 187         141 $tmp = $s;
50 187         147 $state = "READ_FORMAT";
51             } else {
52 127         118 $fmt_new .= $s;
53             }
54             } elsif ($state eq "READ_FORMAT") {
55 377 100       1310 if ($s eq "%") {
    100          
    100          
    100          
    100          
    100          
56             # 'a percent sign' literal
57 3         3 $fmt_new .= $tmp . $s;
58 3         4 $tmp = "";
59 3         2 $state = "IDL";
60              
61             } elsif ($s eq "s") {
62             # %s
63 123         112 $tmp .= $s;
64              
65 123 100       637 if ($tmp =~ /^%([1-9][0-9]*)\$( *)\*([1-9][0-9]*)\$s$/) {
    100          
    100          
    100          
    100          
    100          
    100          
66 7         19 my $s_index = int $1;
67 7         8 my $space = $2;
68 7         9 my $w_index = int $3;
69              
70 7         10 my $s = $_[$s_index];
71 7         9 my $w = $_[$w_index];
72              
73 7         13 my $width = calc_width($w, $s);
74 7 100       16 if (not exists $is_uniq->{$w_index}) {
75 6         8 $argv[$w_index] = $width;
76 6         12 $is_uniq->{$w_index}++;
77             } else {
78 1         3 $tmp = '%' . $s_index . '$' . $space . $width . 's';
79             }
80              
81             } elsif ($tmp =~ /^%([1-9][0-9]*)\$( *)\*s$/) {
82 2         4 my $s_index = int $1;
83 2         4 my $space = $2;
84 2         2 my $w_index = $index;
85              
86 2         3 my $s = $_[$s_index];
87 2         3 my $w = $_[$w_index];
88              
89 2         5 my $width = calc_width($w, $s);
90 2 100       29 if (not exists $is_uniq->{$w_index}) {
91 1         3 $argv[$w_index] = $width;
92 1         2 $is_uniq->{$w_index}++;
93             } else {
94 1         3 $tmp = '%' . $s_index . '$' . $space . $width . 's';
95             }
96 2         2 $index++;
97              
98             } elsif ($tmp =~ /^%([1-9][0-9]*)\$( *)(-?[0-9]+)s$/) {
99 2         4 my $s_index = int $1;
100 2         2 my $space = $2;
101              
102 2         2 my $s = $_[$s_index];
103 2         3 my $w = $3;
104              
105 2         3 $w = calc_width($w, $s);
106              
107 2         5 $tmp = '%' . $s_index . '$' . $space . $w . 's';
108 2         1 $index++;
109              
110             } elsif ($tmp =~ /^%([1-9][0-9]*)\$( *)s$/) {
111             # do nothing
112 1         2 $index++;
113              
114             } elsif ($tmp =~ /^%( *)\*([1-9][0-9]*)\$s$/) {
115 9         7 my $s_index = $index;
116 9         14 my $space = $1;
117 9         13 my $w_index = int $2;
118              
119 9         10 my $s = $_[$s_index];
120 9         9 my $w = $_[$w_index];
121              
122 9         12 my $width = calc_width($w, $s);
123 9 100       19 if (not exists $is_uniq->{$w_index}) {
124 8         7 $argv[$w_index] = $width;
125 8         15 $is_uniq->{$w_index}++;
126             } else {
127 1         3 $tmp = '%' . $space . $width . 's';
128             }
129 9         8 $index++;
130              
131             } elsif ($tmp =~ /^%( *)\*s$/) {
132 4         7 my $s_index = $index + 1;
133 4         6 my $space = $1;
134 4         5 my $w_index = $index;
135 4         3 $index++;
136              
137 4         5 my $s = $_[$s_index];
138 4         5 my $w = $_[$w_index];
139              
140 4         7 my $width = calc_width($w, $s);
141              
142 4 100       8 if (not exists $is_uniq->{$w_index}) {
143 2         3 $argv[$w_index] = $width;
144 2         5 $is_uniq->{$w_index}++;
145             } else {
146             #$tmp = '%' . $space . $width . 's';
147 2         2 $argv[$w_index] = $width;
148 2         3 $is_uniq->{$w_index}++;
149             }
150 4         4 $index++;
151              
152             } elsif ($tmp =~ /^%( *)(-?[0-9]+)s$/) {
153 90         133 my $space = $1;
154              
155 90         83 my $s = $_[$index];
156 90         131 my $w = int $2;
157              
158 90         115 $w = calc_width($w, $s);
159              
160 90         122 $tmp = '%' . $space . $w . 's';
161 90         73 $index++;
162              
163             } else {
164             # do nothing
165 8         6 $index++;
166              
167             }
168              
169 123         91 $fmt_new .= $tmp;
170 123         80 $tmp = "";
171 123         90 $state = "IDL";
172             } elsif ($s =~ /$conversions/) {
173             # %c, %d, %u, %o, %x, %e, %f, %g, ...
174 59         64 $fmt_new .= $tmp . $s;
175 59         47 $tmp = "";
176 59         33 $index++;
177 59         47 $state = "IDL";
178             } elsif ($s eq "*") {
179 27         24 $tmp .= $s;
180 27         25 $state = "READ_ARGUMENT_NUMBER";
181             } elsif ($s =~ /\A[0-9]\Z/) {
182 109         100 $tmp .= $s;
183 109         88 $state = "READ_FORMAT_OR_ARGUMENT_NUMBER";
184             } elsif ($s =~ /\A[-+ #\.v]\Z/) {
185 55         46 $tmp .= $s;
186 55 100       97 if ($tmp =~ /\*v/) {
187 2         2 $index++;
188             }
189             } else {
190 1         20 croak "not supported : $fmt";
191             }
192             } elsif ($state eq "READ_ARGUMENT_NUMBER") {
193 46 100       80 if ($s =~ /\A[0-9]\Z/) {
    100          
194 19         18 $tmp .= $s;
195             } elsif ($s eq '$') {
196 19         16 $tmp .= $s;
197 19         14 $state = "READ_FORMAT";
198             } else {
199 8         7 $state = "READ_FORMAT";
200             #$index++;
201 8         12 next;
202             }
203             } else {
204             # $state eq "READ_FORMAT_OR_ARGUMENT_NUMBER"
205 132 100       258 if ($s =~ /\A[0-9]\Z/) {
    100          
206 23         20 $tmp .= $s;
207             } elsif ($s eq '$') {
208 12         12 $tmp .= $s;
209 12         12 $state = "READ_FORMAT";
210             } else {
211 97         60 $state = "READ_FORMAT";
212 97         142 next;
213             }
214             }
215 763         953 $ofs++;
216             }
217              
218 94         69 $fmt_new .= $tmp;
219              
220 94         84 shift @argv;
221 94         756 return CORE::sprintf $fmt_new, @argv;
222             }
223              
224             1;
225             __END__