scripts/kconfig.pl: allow regex syntax in filtering out config entries
[openwrt/openwrt.git] / scripts / kconfig.pl
1 #!/usr/bin/env perl
2 #
3 # Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
4 #
5 # This is free software, licensed under the GNU General Public License v2.
6 # See /LICENSE for more information.
7 #
8
9 use warnings;
10 use strict;
11
12 my @arg;
13 my $PREFIX = "CONFIG_";
14
15 sub set_config($$$$) {
16 my $config = shift;
17 my $idx = shift;
18 my $newval = shift;
19 my $mod_plus = shift;
20
21 if (!defined($config->{$idx}) or !$mod_plus or
22 $config->{$idx} eq '#undef' or $newval eq 'y') {
23 $config->{$idx} = $newval;
24 }
25 }
26
27 sub load_config($$) {
28 my $file = shift;
29 my $mod_plus = shift;
30 my %config;
31
32 open FILE, "$file" or die "can't open file '$file'";
33 while (<FILE>) {
34 chomp;
35 /^$PREFIX(.+?)=(.+)/ and do {
36 set_config(\%config, $1, $2, $mod_plus);
37 next;
38 };
39 /^# $PREFIX(.+?) is not set/ and do {
40 set_config(\%config, $1, "#undef", $mod_plus);
41 next;
42 };
43 /^#/ and next;
44 /^(.+)$/ and warn "WARNING: can't parse line: $1\n";
45 }
46 return \%config;
47 }
48
49
50 sub config_and($$) {
51 my $cfg1 = shift;
52 my $cfg2 = shift;
53 my %config;
54
55 foreach my $config (keys %$cfg1) {
56 my $val1 = $cfg1->{$config};
57 my $val2 = $cfg2->{$config};
58 $val2 and ($val1 eq $val2) and do {
59 $config{$config} = $val1;
60 };
61 }
62 return \%config;
63 }
64
65
66 sub config_add($$$) {
67 my $cfg1 = shift;
68 my $cfg2 = shift;
69 my $mod_plus = shift;
70 my %config;
71
72 for ($cfg1, $cfg2) {
73 my %cfg = %$_;
74
75 foreach my $config (keys %cfg) {
76 if ($mod_plus and $config{$config}) {
77 next if $config{$config} eq "y";
78 next if $cfg{$config} eq '#undef';
79 }
80 $config{$config} = $cfg{$config};
81 }
82 }
83 return \%config;
84 }
85
86 sub config_diff($$$) {
87 my $cfg1 = shift;
88 my $cfg2 = shift;
89 my $new_only = shift;
90 my %config;
91
92 foreach my $config (keys %$cfg2) {
93 if (!defined($cfg1->{$config}) or $cfg1->{$config} ne $cfg2->{$config}) {
94 next if $new_only and !defined($cfg1->{$config}) and $cfg2->{$config} eq '#undef';
95 $config{$config} = $cfg2->{$config};
96 }
97 }
98 return \%config
99 }
100
101 sub config_sub($$) {
102 my $cfg1 = shift;
103 my $cfg2 = shift;
104 my %config = %{$cfg1};
105 my @keys = map {
106 my $expr = $_;
107 $expr =~ /[?.*]/ ?
108 map {
109 /^$expr$/ ? $_ : ()
110 } keys %config : $expr;
111 } keys %$cfg2;
112
113 foreach my $config (@keys) {
114 delete $config{$config};
115 }
116 return \%config;
117 }
118
119 sub print_cfgline($$) {
120 my $name = shift;
121 my $val = shift;
122 if ($val eq '#undef' or $val eq 'n') {
123 print "# $PREFIX$name is not set\n";
124 } else {
125 print "$PREFIX$name=$val\n";
126 }
127 }
128
129
130 sub dump_config($) {
131 my $cfg = shift;
132 die "argument error in dump_config" unless ($cfg);
133 my %config = %$cfg;
134 foreach my $config (sort keys %config) {
135 print_cfgline($config, $config{$config});
136 }
137 }
138
139 sub parse_expr {
140 my $pos = shift;
141 my $mod_plus = shift;
142 my $arg = $arg[$$pos++];
143
144 die "Parse error" if (!$arg);
145
146 if ($arg eq '&') {
147 my $arg1 = parse_expr($pos);
148 my $arg2 = parse_expr($pos);
149 return config_and($arg1, $arg2);
150 } elsif ($arg =~ /^\+/) {
151 my $arg1 = parse_expr($pos);
152 my $arg2 = parse_expr($pos);
153 return config_add($arg1, $arg2, 0);
154 } elsif ($arg =~ /^m\+/) {
155 my $arg1 = parse_expr($pos);
156 my $arg2 = parse_expr($pos, 1);
157 return config_add($arg1, $arg2, 1);
158 } elsif ($arg eq '>') {
159 my $arg1 = parse_expr($pos);
160 my $arg2 = parse_expr($pos);
161 return config_diff($arg1, $arg2, 0);
162 } elsif ($arg eq '>+') {
163 my $arg1 = parse_expr($pos);
164 my $arg2 = parse_expr($pos);
165 return config_diff($arg1, $arg2, 1);
166 } elsif ($arg eq '-') {
167 my $arg1 = parse_expr($pos);
168 my $arg2 = parse_expr($pos);
169 return config_sub($arg1, $arg2);
170 } else {
171 return load_config($arg, $mod_plus);
172 }
173 }
174
175 while (@ARGV > 0 and $ARGV[0] =~ /^-\w+$/) {
176 my $cmd = shift @ARGV;
177 if ($cmd =~ /^-n$/) {
178 $PREFIX = "";
179 } elsif ($cmd =~ /^-p$/) {
180 $PREFIX = shift @ARGV;
181 } else {
182 die "Invalid option: $cmd\n";
183 }
184 }
185 @arg = @ARGV;
186
187 my $pos = 0;
188 dump_config(parse_expr(\$pos));
189 die "Parse error" if ($arg[$pos]);