diff options
-rw-r--r-- | nls/nlsinfo | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/nls/nlsinfo b/nls/nlsinfo new file mode 100644 index 0000000..c7e5772 --- /dev/null +++ b/nls/nlsinfo | |||
@@ -0,0 +1,291 @@ | |||
1 | #!/usr/bin/perl -w | ||
2 | |||
3 | # This perl script is intended to go through the fluxbox source | ||
4 | # code searching for the special NLS strings. It then dumps | ||
5 | # the requested details. | ||
6 | # | ||
7 | # I started trying to write it fairly generic, but it was difficult :-) | ||
8 | # Should be fairly adaptable though | ||
9 | # | ||
10 | # It doesn't currently handle more than one NLS define per line | ||
11 | # => If you get an "undefined" error, its probably 2 on one line | ||
12 | |||
13 | $VERSION = "0.1"; | ||
14 | |||
15 | use strict; | ||
16 | use Getopt::Std; | ||
17 | |||
18 | $Getopt::Std::STANDARD_HELP_VERSION = 1; | ||
19 | |||
20 | # the boolitem and focusitem is pretty dodgy, but it'll do for now | ||
21 | my $match_re = "(?:_FB(?:TK)?TEXT|_BOOLITEM|_FOCUSITEM)"; | ||
22 | # regular expression for not a unquoted quote | ||
23 | my $noquote = q'(?:[^\"]|\\")'; | ||
24 | |||
25 | my $fielddelim = "\0"; | ||
26 | my $recorddelim = "\0"; | ||
27 | |||
28 | ############################# | ||
29 | # Parse and validate arguments | ||
30 | my %opts; | ||
31 | |||
32 | my $command = $0; | ||
33 | $command =~ s,^.*/,,; | ||
34 | |||
35 | my $fullcommand = "$command " . join(" ", @ARGV); | ||
36 | |||
37 | if (!getopts("d:fhn:pr:vFHN:R", \%opts)) { | ||
38 | HELP_MESSAGE("error"); | ||
39 | exit(1); | ||
40 | } | ||
41 | |||
42 | sub HELP_MESSAGE { | ||
43 | my $arg = shift; | ||
44 | my $FD = *STDOUT; | ||
45 | if (defined($arg) && $arg eq "error") { | ||
46 | $FD = *STDERR; | ||
47 | } | ||
48 | |||
49 | print $FD "Usage: $command [options] directory\n"; | ||
50 | print $FD " Where options can be:\n"; | ||
51 | print $FD " -R\tDon't recurse into subdirectories.\n"; | ||
52 | print $FD " -f\tThe argument is a file, not a directory\n"; | ||
53 | print $FD " -F\tPrint full NLS names, not shorthand ones\n"; | ||
54 | print $FD " -d delim\tUse delim as the default delimiter\n"; | ||
55 | print $FD " -r delim\tUse delim as the record delimiter\n"; | ||
56 | print $FD " -n\tHeader name, default FLUXBOX_NLS_HH\n"; | ||
57 | print $FD " -N\tNamespace for header\n"; | ||
58 | print $FD " -v\tverbose output\n"; | ||
59 | print $FD " -h\tPrint this help message\n"; | ||
60 | print $FD "\nPlus one of the following options that direct how to operate:\n"; | ||
61 | print $FD " -H\tGenerate a header file for the strings encountered (-n implied).\n"; | ||
62 | print $FD " -p\tPrint out a null-separated tuple of Set,String,Default,Description\n"; | ||
63 | print $FD " \t\n"; | ||
64 | print $FD "\n"; | ||
65 | |||
66 | } | ||
67 | |||
68 | if (defined($opts{"h"})) { | ||
69 | HELP_MESSAGE(); | ||
70 | exit(0); | ||
71 | } | ||
72 | |||
73 | my $num_modes = 0; | ||
74 | my $mode; | ||
75 | |||
76 | sub mode_opt { | ||
77 | my $opt = shift; | ||
78 | my $modename = shift; | ||
79 | return if (!defined($opts{$opt})); | ||
80 | $num_modes++; | ||
81 | $mode = $modename; | ||
82 | } | ||
83 | |||
84 | mode_opt("H", "header"); | ||
85 | mode_opt("p", "print"); | ||
86 | |||
87 | if ($num_modes == 0) { | ||
88 | print STDERR "Must give one mode of operation!\n"; | ||
89 | HELP_MESSAGE("error"); | ||
90 | exit(1); | ||
91 | } elsif ($num_modes > 1) { | ||
92 | print STDERR "Too many modes of operation - must give exactly one!\n"; | ||
93 | HELP_MESSAGE("error"); | ||
94 | exit(1); | ||
95 | } | ||
96 | |||
97 | my $recurse = 1; | ||
98 | $recurse = 0 if (defined($opts{"R"})); | ||
99 | |||
100 | my $fullnames = 0; | ||
101 | $fullnames = 1 if (defined($opts{"f"}) || $mode eq "header"); | ||
102 | |||
103 | my $headername = "FLUXBOX_NLS_HH"; | ||
104 | $headername = $opts{"n"} if (defined($opts{"n"})); | ||
105 | |||
106 | my $namespace; | ||
107 | $namespace = $opts{"N"} if (defined($opts{"N"})); | ||
108 | |||
109 | my $verbose = 0; | ||
110 | $verbose = 1 if (defined($opts{"v"})); | ||
111 | |||
112 | if (defined($opts{"d"})) { | ||
113 | $fielddelim = $opts{"d"}; | ||
114 | $recorddelim = $opts{"d"}; | ||
115 | } | ||
116 | |||
117 | if (defined($opts{"r"})) { | ||
118 | $recorddelim = $opts{"r"}; | ||
119 | } | ||
120 | |||
121 | |||
122 | if (scalar(@ARGV) == 0) { | ||
123 | print STDERR "Must give one more argument - the directory to scan\n"; | ||
124 | exit(1); | ||
125 | } elsif (scalar(@ARGV) > 1) { | ||
126 | print STDERR "Too many arguments, none expected after directory to scan\n"; | ||
127 | exit(1); | ||
128 | } | ||
129 | |||
130 | |||
131 | my $dir = $ARGV[0]; | ||
132 | my $file; | ||
133 | if (!defined($opts{"f"}) && ! -d $dir ) { | ||
134 | print STDERR "$dir is not a directory, aborting\n"; | ||
135 | exit(2); | ||
136 | } elsif (defined($opts{"f"})) { | ||
137 | $file = $dir; | ||
138 | undef $dir; | ||
139 | $recurse = 0; | ||
140 | |||
141 | if (! -r $file) { | ||
142 | print STDERR "$file is not a readable file, aborting\n"; | ||
143 | exit(2); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | |||
148 | ############################# | ||
149 | # Actually do stuff! (finally...) | ||
150 | |||
151 | my %sets; | ||
152 | |||
153 | if (defined($dir)) { | ||
154 | process_dir($dir); | ||
155 | } else { | ||
156 | process_file($file); | ||
157 | } | ||
158 | |||
159 | # Now we have the data, we need to print it out | ||
160 | eval "mode_$mode()"; | ||
161 | exit(0); | ||
162 | |||
163 | # this function is given the fbtext arguments | ||
164 | # But the first argument is the macro name... | ||
165 | sub store { | ||
166 | my ($type, $set, $str, $default, $desc) = @_; | ||
167 | |||
168 | if ($type eq "_FBTKTEXT") { | ||
169 | $set = "FbTk$set"; | ||
170 | } | ||
171 | |||
172 | if ($fullnames == 1) { | ||
173 | $str = $set . $str; | ||
174 | $set = $set . "Set"; | ||
175 | } | ||
176 | |||
177 | $sets{$set}->{$str}{"default"} = $default; | ||
178 | $sets{$set}->{$str}{"desc"} = $desc; | ||
179 | |||
180 | } | ||
181 | |||
182 | # C strings can just be a bunch of quoted strings adjacent to | ||
183 | # each other. This just puts them all together, removes the quotes | ||
184 | # and unquotes anything we want to. | ||
185 | # there may be newlines embedded... compare everything /s | ||
186 | sub squish { | ||
187 | my $str = shift; | ||
188 | |||
189 | # remove first and last quote | ||
190 | $str =~ s/^\s*\"//s; | ||
191 | $str =~ s/\"\s*$//s; | ||
192 | |||
193 | # now remove any inner quotes and intervening spaces | ||
194 | $str =~ s/([^\\])\"\s*\"/$1/sg; | ||
195 | |||
196 | # finally, unescape any remaining quotes | ||
197 | $str =~ s/\\\"/\"/g; | ||
198 | |||
199 | return $str; | ||
200 | } | ||
201 | |||
202 | sub process_dir { | ||
203 | my $dir = shift; | ||
204 | print STDERR "Processing directory '$dir'\n" if ($verbose == 1); | ||
205 | opendir(DIR, $dir) || die "can't opendir $dir: $!"; | ||
206 | my @files = grep { ( /\.(cc|hh)$/ && -f "$dir/$_" ) || | ||
207 | ( -d "$dir/$_" && $_ !~ /^\.\.?$/ ) | ||
208 | } readdir(DIR); | ||
209 | closedir DIR; | ||
210 | |||
211 | foreach my $file (@files) { | ||
212 | if (-d "$dir/$file") { | ||
213 | process_dir("$dir/$file") if ($recurse == 1); | ||
214 | } else { | ||
215 | process_file("$dir/$file"); | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | # assumptions for now: | ||
221 | # - no more than one NLS thing on any single line | ||
222 | # - internal parenthesis are balanced | ||
223 | # - one nls thing can span several lines | ||
224 | sub process_file { | ||
225 | my $file = shift; | ||
226 | |||
227 | print STDERR "Processing file '$file'\n" if ($verbose == 1); | ||
228 | open(FILE, "<$file") || die "Can't open file $file: $!"; | ||
229 | |||
230 | while (<FILE>) { | ||
231 | chomp; | ||
232 | if (/$match_re/ && $_ !~ /^\#(define|undef)/) { | ||
233 | my $tail = $_; | ||
234 | # strip away leading stuff | ||
235 | # note that this doesn't work with more than one match on a line | ||
236 | $tail =~ s/^.*($match_re)/$1/; | ||
237 | # now we just need to find the end, looking out for any | ||
238 | # quotes | ||
239 | my $end = 0; | ||
240 | my $full = $tail; | ||
241 | while ($end == 0) { | ||
242 | # match the defined macro, plus the first 4 arguments | ||
243 | # (ignore any more), then handle them | ||
244 | if ($full =~ /^($match_re)\(([^,]+),\s*([^,]+),((?:\s*\"$noquote*\")+),((?:\s*"$noquote*")+)\s*(?:,.*)?\)/s ) { | ||
245 | store($1, $2, $3, squish($4), squish($5)); | ||
246 | $end++; | ||
247 | } else { | ||
248 | my $extra = <FILE>; | ||
249 | last if (!defined($extra)); | ||
250 | $full .= $extra; | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | close(FILE); | ||
256 | } | ||
257 | |||
258 | |||
259 | sub mode_print { | ||
260 | foreach my $set (sort keys %sets) { | ||
261 | foreach my $str (sort keys %{$sets{$set}}) { | ||
262 | print $set . $fielddelim . $str . $fielddelim . $sets{$set}->{$str}{"default"} . $fielddelim . $sets{$set}->{$str}{"desc"} . $recorddelim; | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | |||
267 | sub mode_header { | ||
268 | print "// This file generated by $fullcommand, on " . localtime() . "\n\n"; | ||
269 | print "#ifndef $headername\n"; | ||
270 | print "#define $headername\n\n"; | ||
271 | print "namespace $namespace {\n\n" if (defined($namespace)); | ||
272 | print "enum {\n"; | ||
273 | |||
274 | my $setnum = 0; | ||
275 | foreach my $set (sort keys %sets) { | ||
276 | $setnum++; | ||
277 | printf "\t%s = 0x%x,\n", $set, $setnum; | ||
278 | |||
279 | my $strnum = 0; | ||
280 | foreach my $str (sort keys %{$sets{$set}}) { | ||
281 | $strnum++; | ||
282 | printf "\t%s = 0x%x,\n", $str, $strnum; | ||
283 | } | ||
284 | print "\n"; | ||
285 | } | ||
286 | print "\tdummy_not_used = 0 // just for the end\n\n"; | ||
287 | print "}; // end enum\n\n"; | ||
288 | print "}; // end namespace $namespace\n\n" if (defined($namespace)); | ||
289 | print "#endif // $headername\n"; | ||
290 | } | ||
291 | |||