brcm47xx: backport r29923
[openwrt-10.03/.git] / scripts / kconfig.pl
1 #!/usr/bin/env perl
2
3 # Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
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";
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                         next if $mod_plus and $config{$config} and $config{$config} eq "y";
77                         $config{$config} = $cfg{$config};
78                 }
79         }
80         return \%config;
81 }
82
83 sub config_diff($$$) {
84         my $cfg1 = shift;
85         my $cfg2 = shift;
86         my $new_only = shift;
87         my %config;
88         
89         foreach my $config (keys %$cfg2) {
90                 if (!defined($cfg1->{$config}) or $cfg1->{$config} ne $cfg2->{$config}) {
91                         next if $new_only and !defined($cfg1->{$config}) and $cfg2->{$config} eq '#undef';
92                         $config{$config} = $cfg2->{$config};
93                 }
94         }
95         return \%config
96 }
97
98 sub config_sub($$) {
99         my $cfg1 = shift;
100         my $cfg2 = shift;
101         my %config = %{$cfg1};
102         
103         foreach my $config (keys %$cfg2) {
104                 delete $config{$config};
105         }
106         return \%config;
107 }
108
109 sub print_cfgline($$) {
110         my $name = shift;
111         my $val = shift;
112         if ($val eq '#undef' or $val eq 'n') {
113                 print "# $PREFIX$name is not set\n";
114         } else {
115                 print "$PREFIX$name=$val\n";
116         }
117 }
118
119
120 sub dump_config($) {
121         my $cfg = shift;
122         die "argument error in dump_config" unless ($cfg);
123         my %config = %$cfg;
124         foreach my $config (sort keys %config) {
125                 print_cfgline($config, $config{$config});
126         }
127 }
128
129 sub parse_expr {
130         my $pos = shift;
131         my $mod_plus = shift;
132         my $arg = $arg[$$pos++];
133
134         die "Parse error" if (!$arg);
135
136         if ($arg eq '&') {
137                 my $arg1 = parse_expr($pos);
138                 my $arg2 = parse_expr($pos);
139                 return config_and($arg1, $arg2);
140         } elsif ($arg =~ /^\+/) {
141                 my $arg1 = parse_expr($pos);
142                 my $arg2 = parse_expr($pos);
143                 return config_add($arg1, $arg2, 0);
144         } elsif ($arg =~ /^m\+/) {
145                 my $arg1 = parse_expr($pos);
146                 my $arg2 = parse_expr($pos, 1);
147                 return config_add($arg1, $arg2, 1);
148         } elsif ($arg eq '>') {
149                 my $arg1 = parse_expr($pos);
150                 my $arg2 = parse_expr($pos);
151                 return config_diff($arg1, $arg2, 0);
152         } elsif ($arg eq '>+') {
153                 my $arg1 = parse_expr($pos);
154                 my $arg2 = parse_expr($pos);
155                 return config_diff($arg1, $arg2, 1);
156         } elsif ($arg eq '-') {
157                 my $arg1 = parse_expr($pos);
158                 my $arg2 = parse_expr($pos);
159                 return config_sub($arg1, $arg2);
160         } else {
161                 return load_config($arg, $mod_plus);
162         }
163 }
164
165 while (@ARGV > 0 and $ARGV[0] =~ /^-\w+$/) {
166         my $cmd = shift @ARGV;
167         if ($cmd =~ /^-n$/) {
168                 $PREFIX = "";
169         } elsif ($cmd =~ /^-p$/) {
170                 $PREFIX = shift @ARGV;
171         } else {
172                 die "Invalid option: $cmd\n";
173         }
174 }
175 @arg = @ARGV;
176
177 my $pos = 0;
178 dump_config(parse_expr(\$pos));
179 die "Parse error" if ($arg[$pos]);