File Coverage

blib/lib/Preproc/Tiny.pm
Criterion Covered Total %
statement 44 48 91.6
branch 13 18 72.2
condition 2 4 50.0
subroutine 9 9 100.0
pod 1 5 20.0
total 69 84 82.1


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # Preproc::Tiny - Minimal stand-alone preprocessor for code generation using perl
3             # Copyright (C) 2016 by Paulo Custodio
4             #------------------------------------------------------------------------------
5            
6             package Preproc::Tiny;
7            
8 1     1   62623 use 5.010;
  1         2  
9 1     1   3 use strict;
  1         1  
  1         17  
10 1     1   3 use warnings;
  1         4  
  1         29  
11 1     1   3 use File::Basename;
  1         1  
  1         693  
12            
13             require Exporter;
14            
15             our @ISA = qw( Exporter );
16             our @EXPORT = qw( pp );
17             our $VERSION = '0.02';
18            
19             #------------------------------------------------------------------------------
20             # Code borrowed from Data::Dump
21             #------------------------------------------------------------------------------
22             my %esc = (
23             "\a" => "\\a",
24             "\b" => "\\b",
25             "\t" => "\\t",
26             "\n" => "\\n",
27             "\f" => "\\f",
28             "\r" => "\\r",
29             "\e" => "\\e",
30             );
31            
32             sub quote {
33 58     58 0 113 local($_) = $_[0];
34             # If there are many '"' we might want to use qq() instead
35 58         80 s/([\\\"\@\$])/\\$1/g;
36 58 100       190 return qq("$_") unless /[^\040-\176]/; # fast exit
37            
38 34         195 s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
39            
40             # no need for 3 digits in escape for these
41 34         45 s/([\0-\037])(?!\d)/sprintf('\\%o',ord($1))/eg;
  0         0  
42            
43 34         38 s/([\0-\037\177-\377])/sprintf('\\x%02X',ord($1))/eg;
  0         0  
44 34         34 s/([^\040-\176])/sprintf('\\x{%X}',ord($1))/eg;
  0         0  
45            
46 34         129 return qq("$_");
47             }
48            
49             #------------------------------------------------------------------------------
50             # Path::Tiny spew and slurp
51             #------------------------------------------------------------------------------
52             sub spew {
53 16     16 0 24 my($file, $text) = @_;
54 16 50       926 open(my $fh, '>', $file)
55             or die "Cannot write file $file: $!\n";
56 16         572 print $fh $text;
57             }
58            
59             sub slurp {
60 16     16 0 32 my($file) = @_;
61 16 50       603 open(my $fh, '<', $file)
62             or die "Cannot read file $file: $!\n";
63 16         92 local $/ = undef;
64 16         261 my $text = <$fh>;
65 16         104 close($fh);
66 16         104 return $text;
67             }
68            
69             #------------------------------------------------------------------------------
70             # pp(), the only export
71             #------------------------------------------------------------------------------
72             sub pp {
73 8     8 1 405533 for my $infile (@_) {
74 16 50       343 (my $outfile = $infile) =~ s/\.pp$//i
75             or die "Error: input file needs .pp extension\n";
76 16         70 my $plfile = "$outfile.pl";
77            
78             # build code to pre-process
79 16         43 my $pl = 'my $OUT = "";'."\n";
80            
81 16         121 local $_ = slurp($infile);
82 16         65 while (! at_end($_) ) {
83 90 100       558 if (/\G (?| ^ \@\@ (.*) \n?
    100          
    100          
    50          
84             | \@\@ (.*)
85             ) /gcxim) {
86 16         67 $pl .= $1."\n";
87             }
88             elsif (/\G \[\@> \s* (.*?) (?: -\@\] \s* | \@\] ) /gcxis) {
89 10         22 $pl .= '$OUT .= '.$1.";\n";
90             }
91             elsif (/\G \[\@ \s* (.*?) (?: -\@\] \s* | \@\] ) /gcxis) {
92 22         75 $pl .= $1.";\n";
93             }
94             elsif (/ ( [^\[\@]+ ) /gcxi) {
95 42         98 $pl .= '$OUT .= '.quote($1).";\n";
96             }
97             else {
98 0   0     0 die "$infile: parse error at ".quote(substr($_, pos($_)||0, 100))."\n";
99             }
100             }
101            
102             # build code to generate output file
103 16         27 $pl .= 'open(my $fh, ">", '.quote($outfile).') or die $!;'."\n".
104             'print $fh $OUT;'."\n".
105             "1;\n";
106            
107             # run template
108 16         45 spew($plfile, $pl);
109 16 50       85835 system($^X, $plfile)==0 or die "$infile: parse error\n";
110            
111             # delete temp file
112 16         2145 unlink $plfile;
113             }
114             }
115            
116             sub at_end {
117 106   100 106 0 393 return (pos($_[0])||0) >= length($_[0]);
118             }
119            
120             #------------------------------------------------------------------------------
121             # Run if called as a script
122             #------------------------------------------------------------------------------
123             unless (caller) {
124             @ARGV or die "Usage: ",basename($0)," file.pp...\n";
125             pp(@ARGV);
126             }
127            
128             1;
129             __END__