kconfig.pl: fix handling of multiple kmod-* package referencing the same KCONFIG...
[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 %config;
87         
88         foreach my $config (keys %$cfg2) {
89                 if (!defined($cfg1->{$config}) or $cfg1->{$config} ne $cfg2->{$config}) {
90                         $config{$config} = $cfg2->{$config};
91                 }
92         }
93         return \%config
94 }
95
96 sub config_sub($$) {
97         my $cfg1 = shift;
98         my $cfg2 = shift;
99         my %config = %{$cfg1};
100         
101         foreach my $config (keys %$cfg2) {
102                 delete $config{$config};
103         }
104         return \%config;
105 }
106
107 sub print_cfgline($$) {
108         my $name = shift;
109         my $val = shift;
110         if ($val eq '#undef' or $val eq 'n') {
111                 print "# $PREFIX$name is not set\n";
112         } else {
113                 print "$PREFIX$name=$val\n";
114         }
115 }
116
117
118 sub dump_config($) {
119         my $cfg = shift;
120         die "argument error in dump_config" unless ($cfg);
121         my %config = %$cfg;
122         foreach my $config (sort keys %config) {
123                 print_cfgline($config, $config{$config});
124         }
125 }
126
127 sub parse_expr {
128         my $pos = shift;
129         my $mod_plus = shift;
130         my $arg = $arg[$$pos++];
131
132         die "Parse error" if (!$arg);
133
134         if ($arg eq '&') {
135                 my $arg1 = parse_expr($pos);
136                 my $arg2 = parse_expr($pos);
137                 return config_and($arg1, $arg2);
138         } elsif ($arg =~ /^\+/) {
139                 my $arg1 = parse_expr($pos);
140                 my $arg2 = parse_expr($pos);
141                 return config_add($arg1, $arg2, 0);
142         } elsif ($arg =~ /^m\+/) {
143                 my $arg1 = parse_expr($pos);
144                 my $arg2 = parse_expr($pos, 1);
145                 return config_add($arg1, $arg2, 1);
146         } elsif ($arg eq '>') {
147                 my $arg1 = parse_expr($pos);
148                 my $arg2 = parse_expr($pos);
149                 return config_diff($arg1, $arg2);
150         } elsif ($arg eq '-') {
151                 my $arg1 = parse_expr($pos);
152                 my $arg2 = parse_expr($pos);
153                 return config_sub($arg1, $arg2);
154         } else {
155                 return load_config($arg, $mod_plus);
156         }
157 }
158
159 while (@ARGV > 0 and $ARGV[0] =~ /^-\w+$/) {
160         my $cmd = shift @ARGV;
161         if ($cmd =~ /^-n$/) {
162                 $PREFIX = "";
163         } elsif ($cmd =~ /^-p$/) {
164                 $PREFIX = shift @ARGV;
165         } else {
166                 die "Invalid option: $cmd\n";
167         }
168 }
169 @arg = @ARGV;
170
171 my $pos = 0;
172 dump_config(parse_expr(\$pos));
173 die "Parse error" if ($arg[$pos]);