+sub globlist_to_pagespec ($) { #{{{
+ my @globlist=split(' ', shift);
+
+ my (@spec, @skip);
+ foreach my $glob (@globlist) {
+ if ($glob=~/^!(.*)/) {
+ push @skip, $glob;
+ }
+ else {
+ push @spec, $glob;
+ }
+ }
+
+ my $spec=join(" or ", @spec);
+ if (@skip) {
+ my $skip=join(" and ", @skip);
+ if (length $spec) {
+ $spec="$skip and ($spec)";
+ }
+ else {
+ $spec=$skip;
+ }
+ }
+ return $spec;
+} #}}}
+
+sub is_globlist ($) { #{{{
+ my $s=shift;
+ $s=~/[^\s]+\s+([^\s]+)/ && $1 ne "and" && $1 ne "or";
+} #}}}
+
+sub safequote ($) { #{{{
+ my $s=shift;
+ $s=~s/[{}]//g;
+ return "q{$s}";
+} #}}}
+
+sub pagespec_merge ($$) { #{{{
+ my $a=shift;
+ my $b=shift;
+
+ return $a if $a eq $b;
+
+ # Support for old-style GlobLists.
+ if (is_globlist($a)) {
+ $a=globlist_to_pagespec($a);
+ }
+ if (is_globlist($b)) {
+ $b=globlist_to_pagespec($b);
+ }
+
+ return "($a) or ($b)";
+} #}}}
+
+sub pagespec_translate ($) { #{{{
+ # This assumes that $page is in scope in the function
+ # that evalulates the translated pagespec code.
+ my $spec=shift;
+
+ # Support for old-style GlobLists.
+ if (is_globlist($spec)) {
+ $spec=globlist_to_pagespec($spec);
+ }
+
+ # Convert spec to perl code.
+ my $code="";
+ while ($spec=~m/\s*(\!|\(|\)|\w+\([^\)]+\)|[^\s()]+)\s*/ig) {
+ my $word=$1;
+ if (lc $word eq "and") {
+ $code.=" &&";
+ }
+ elsif (lc $word eq "or") {
+ $code.=" ||";
+ }
+ elsif ($word eq "(" || $word eq ")" || $word eq "!") {
+ $code.=" ".$word;
+ }
+ elsif ($word =~ /^(link|backlink|created_before|created_after|creation_month|creation_year|creation_day)\((.+)\)$/) {
+ $code.=" match_$1(\$page, ".safequote($2).")";
+ }
+ else {
+ $code.=" match_glob(\$page, ".safequote($word).")";
+ }
+ }
+
+ return $code;
+} #}}}
+
+sub add_depends ($$) { #{{{
+ my $page=shift;
+ my $pagespec=shift;
+
+ if (! exists $depends{$page}) {
+ $depends{$page}=$pagespec;
+ }
+ else {
+ $depends{$page}=pagespec_merge($depends{$page}, $pagespec);
+ }
+} # }}}
+
+sub file_pruned ($$) { #{{{
+ require File::Spec;
+ my $file=File::Spec->canonpath(shift);
+ my $base=File::Spec->canonpath(shift);
+ $file=~s#^\Q$base\E/*##;
+
+ my $regexp='('.join('|', @{$config{wiki_file_prune_regexps}}).')';
+ $file =~ m/$regexp/;
+} #}}}
+
+sub gettext { #{{{
+ # Only use gettext in the rare cases it's needed.
+ # This overrides future calls of this function.
+ if (exists $ENV{LANG} || exists $ENV{LC_ALL} || exists $ENV{LC_MESSAGES}) {
+ eval q{use Locale::gettext};
+ textdomain('ikiwiki');
+ return Locale::gettext::gettext(shift);
+ }
+ else {
+ return shift;
+ }
+} #}}}
+
+sub pagespec_match ($$) { #{{{
+ my $page=shift;
+ my $spec=shift;
+
+ return eval pagespec_translate($spec);
+} #}}}
+
+sub match_glob ($$) { #{{{
+ my $page=shift;
+ my $glob=shift;
+
+ # turn glob into safe regexp
+ $glob=quotemeta($glob);
+ $glob=~s/\\\*/.*/g;
+ $glob=~s/\\\?/./g;
+
+ return $page=~/^$glob$/i;
+} #}}}
+
+sub match_link ($$) { #{{{
+ my $page=shift;
+ my $link=lc(shift);
+
+ my $links = $links{$page} or return undef;
+ foreach my $p (@$links) {
+ return 1 if lc $p eq $link;
+ }
+ return 0;
+} #}}}
+
+sub match_backlink ($$) { #{{{
+ match_link(pop, pop);
+} #}}}
+
+sub match_created_before ($$) { #{{{
+ my $page=shift;
+ my $testpage=shift;
+
+ if (exists $pagectime{$testpage}) {
+ return $pagectime{$page} < $pagectime{$testpage};
+ }
+ else {
+ return 0;
+ }
+} #}}}
+
+sub match_created_after ($$) { #{{{
+ my $page=shift;
+ my $testpage=shift;
+
+ if (exists $pagectime{$testpage}) {
+ return $pagectime{$page} > $pagectime{$testpage};
+ }
+ else {
+ return 0;
+ }
+} #}}}
+
+sub match_creation_day ($$) { #{{{
+ return ((gmtime($pagectime{shift()}))[3] == shift);
+} #}}}
+
+sub match_creation_month ($$) { #{{{
+ return ((gmtime($pagectime{shift()}))[4] + 1 == shift);
+} #}}}
+
+sub match_creation_year ($$) { #{{{
+ return ((gmtime($pagectime{shift()}))[5] + 1900 == shift);
+} #}}}
+