Add a joiner to multiinstructions.
[artemus.git] / waste / artemus.pl
blob6003e732fef3b0f8a14d3ecd582757885f92aec1
1 ###########################################
3 # Artemus main processing function
5 ###########################################
6 # -*- Mode: Perl
8 use locale;
10 sub artemus
12 my ($data,%opts)=@_;
13 my ($vars,$inv_vars,$funcs);
15 # abort flag not set
16 $artemus_abort=0;
18 $vars=$opts{'vars'};
19 $funcs=$opts{'funcs'};
21 # special values:
22 # {-\n}, substitutes as \n
23 $vars->{"\\n"}||="\n";
25 # special functions
26 $funcs->{"localtime"}||=sub { scalar(localtime) };
27 $funcs->{"if"}||=sub { $_[0] ? return($_[1]) : return("") };
28 $funcs->{"ifelse"}||=sub { $_[0] ? return($_[1]) : return($_[2]) };
30 $data=artemus_do(undef,$data, %opts);
34 sub artemus_do
36 my ($template,$data,%opts)=@_;
37 my ($vars,$inv_vars,$funcs);
38 my ($unresolved,$cache);
40 # test if the template includes cache info
41 if($data =~ s/{-\\CACHE\|([^}]*)}//)
43 if($template and $opts{'cache_path'})
45 $cache=$1;
46 my ($c)=$opts{'cache_path'};
48 if(-r "$c/$template" and
49 -M "$c/$template" < $cache)
51 open F, "$c/$template";
52 flock F, 1;
53 $data=join("",<F>);
54 close F;
56 return($data);
61 # strip POD documentation
62 if($data =~ /=cut/ and not $opts{'contains_pod'})
64 my (@d);
66 foreach (split("\n",$data))
68 push(@d, $_) unless(/^=/ .. /^=cut/);
71 $data=join("\n",@d);
74 # make hashes comfortable
75 $vars=$opts{'vars'};
76 $inv_vars=$opts{'inv-vars'};
77 $funcs=$opts{'funcs'};
78 $unresolved=$opts{'unresolved'};
80 # if defined, substitute the paragraphs
81 # with the paragraph separator
82 if($opts{'paragraph-separator'})
84 $data =~ s/\n\n/\n$opts{'paragraph-separator'}\n/g;
87 # concat special variables BEGIN & END
88 $data = $vars->{"\\BEGIN"} . $data . $vars->{"\\END"};
90 # inverse substitutions
91 for my $i (keys(%$inv_vars))
93 next if $inv_vars->{$i} =~ /\$/;
94 next if $i =~ /^\-/;
95 $data =~ s/\b($i)\b/\{\-$1\}/g;
98 # main function, variable and include substitutions
99 while($data =~ /{-([^}{]*)}/s)
101 my ($found)=$1;
102 my ($key,@params,$text,$n);
104 ($key,@params)=split(/\|/,$found);
106 # exclude dangerous keys
107 unless($key =~ /^[-\\\w_ \.]+$/)
109 $text=$key;
112 # is it a variable?
113 elsif(defined $vars->{$key})
115 $text=$vars->{$key};
117 for($n=0;$text =~ /\$$n/;$n++)
119 $text =~ s/\$$n/$params[$n]/g;
123 # is it a function?
124 elsif(defined $funcs->{$key})
126 my ($func);
128 $func=$funcs->{$key};
129 $text=&$func(@params);
131 # functions can abort further execution
132 last if $artemus_abort;
134 # is it an include?
135 elsif($opts{'include-path'})
137 foreach my $p (split(/:/,$opts{'include-path'}))
139 if(open(INC, "$p/$key"))
141 $text=join("",<INC>);
142 close INC;
144 for($n=0;$text =~ /\$$n/;$n++)
146 $text =~ s/\$$n/$params[$n]/g;
149 last;
154 unless(defined $text)
156 # print STDERR "unresolved: '$found'\n" if not $quiet;
157 push(@$unresolved,$found);
158 $text=$found;
161 # do the recursivity
162 $text=artemus_do($key,$text,%opts);
164 # make the substitution
165 $data =~ s/{-\Q$found\E}/$text/;
168 # finally, convert end of lines if necessary
169 $data =~ s/\n/\r\n/g if($opts{'use-cr-lf'});
171 # if the template included cache info,
172 # store the result there
173 if($cache)
175 open F, ">".$opts{'cache_path'}."/".$template;
176 flock F,2;
177 print F $data;
178 close F;
181 return($data);