summaryrefslogtreecommitdiffabout
path: root/lib/Apache/Config/Preproc/ifdefine.pm
blob: 5bf3a3f0335a8801e3285847b42109bc154a5de7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package Apache::Config::Preproc::ifdefine;
use strict;
use warnings;
use Carp;

sub new {
    my $class = shift;
    my $conf = shift;
    my $self = bless {}, $class;
    @{$self->{D}}{@_} = (1) x @_;
    return $self;
}

sub find_define {
    my ($self,$elt,$id) = @_;

    while (my $p = $elt->parent) {
	if (grep {
	      (split /\s+/, $_->value)[0] eq $id
	    } $p->directive('define')) {
	    return 1;
	}
    }
    return;
}

sub _changed_in_section {
    my ($self, $section, $id, $before) = @_;
    foreach my $d (reverse $section->select) {
	if ($before) {
	    if ($d == $before) {
		$before = undef;
	    }
	    next;
	}
	
	if ($d->type eq 'directive') {
	    if ($d->name =~ m/^(un)?define$/i && $d->value eq $id) {
		if ($1) {
		    $self->undefine($id);
		} else {
		    $self->define($id);
		}
		return 1;
	    }
	} elsif ($d->type eq 'section' && lc($d->name) eq 'virtualhost') {
	    # Need to descend into VirtualHost, because accorind to the
	    # Apache docs
            # see (https://httpd.apache.org/docs/2.4/mod/core.html#define):
	    # 
	    #   While [the Define] directive is supported in virtual host
	    #   context, the changes it makes are visible to any later
	    #   configuration directives, beyond any enclosing virtual host.
	    #
	    # The same is said about the UnDefine directive.
	    
	    return 1 if $self->_changed_in_section($d, $id);
	}
    }
    return 0;
}

sub is_defined {
    my ($self,$id,$d) = @_;

    unless ($self->{D}{$id}) {
	my $before = $d;
	while ($d = $d->parent) {
	    last if $self->_changed_in_section($d, $id, $before);
	    $before = undef;
	}
    }
    return $self->{D}{$id};
}

sub define {
    my ($self,$id) = @_;
    $self->{D}{$id} = 1;
}

sub undefine {
    my ($self,$id) = @_;
    delete $self->{D}{$id};
}

sub expand {
    my ($self, $d, $repl) = @_;
    if ($d->type eq 'section') {
	if (lc($d->name) eq 'ifdefine') {
	    my $id = $d->value;
	    my $negate = $id =~ s/^!//;
	    my $res = $self->is_defined($id, $d);
	    $res = !$res if $negate;
	    if ($res) {
		push @$repl, $d->select;
	    }
	    return 1;
	}
    }
    if ($d->type eq 'directive') {
	my $name = lc($d->name);
	if ($name eq 'define') {
	    $self->define($d->value);
	    return 1;
	} elsif ($name eq 'undefine') {
	    $self->undefine($d->value);
	    return 1;
	}
    }
    return 0;
}

1;
__END__

=head1 NAME    

Apache::Config::Preproc::ifdefine - expand IfDefine sections

=head1 SYNOPSIS

    $x = new Apache::Config::Preproc '/path/to/httpd.conf',
               -expand => [ qw(ifdefine) ];

    $x = new Apache::Config::Preproc '/path/to/httpd.conf',
               -expand => [
                   { ifdefine => [qw(SYM1 SYM2)] }
               ];

=head1 DESCRIPTION

Eliminates the B<Define> and B<UnDefine> statements and expands the
B<E<lt>IfDefineE<gt>> statements in the Apache configuration parse
tree. Optional arguments to the constructor are treated as the names
of symbols to define (similar to the B<httpd> B<-D> options).    
    
    

Return to:

Send suggestions and report system problems to the System administrator.