nls updates -> nlsinfo to search for nls strings in source code
rathnor rathnor
1 files changed,
291 insertions(+),
0 deletions(-)
jump to
A
nls/nlsinfo
@@ -0,0 +1,291 @@
+#!/usr/bin/perl -w + +# This perl script is intended to go through the fluxbox source +# code searching for the special NLS strings. It then dumps +# the requested details. +# +# I started trying to write it fairly generic, but it was difficult :-) +# Should be fairly adaptable though +# +# It doesn't currently handle more than one NLS define per line +# => If you get an "undefined" error, its probably 2 on one line + +$VERSION = "0.1"; + +use strict; +use Getopt::Std; + +$Getopt::Std::STANDARD_HELP_VERSION = 1; + +# the boolitem and focusitem is pretty dodgy, but it'll do for now +my $match_re = "(?:_FB(?:TK)?TEXT|_BOOLITEM|_FOCUSITEM)"; +# regular expression for not a unquoted quote +my $noquote = q'(?:[^\"]|\\")'; + +my $fielddelim = "\0"; +my $recorddelim = "\0"; + +############################# +# Parse and validate arguments +my %opts; + +my $command = $0; +$command =~ s,^.*/,,; + +my $fullcommand = "$command " . join(" ", @ARGV); + +if (!getopts("d:fhn:pr:vFHN:R", \%opts)) { + HELP_MESSAGE("error"); + exit(1); +} + +sub HELP_MESSAGE { + my $arg = shift; + my $FD = *STDOUT; + if (defined($arg) && $arg eq "error") { + $FD = *STDERR; + } + + print $FD "Usage: $command [options] directory\n"; + print $FD " Where options can be:\n"; + print $FD " -R\tDon't recurse into subdirectories.\n"; + print $FD " -f\tThe argument is a file, not a directory\n"; + print $FD " -F\tPrint full NLS names, not shorthand ones\n"; + print $FD " -d delim\tUse delim as the default delimiter\n"; + print $FD " -r delim\tUse delim as the record delimiter\n"; + print $FD " -n\tHeader name, default FLUXBOX_NLS_HH\n"; + print $FD " -N\tNamespace for header\n"; + print $FD " -v\tverbose output\n"; + print $FD " -h\tPrint this help message\n"; + print $FD "\nPlus one of the following options that direct how to operate:\n"; + print $FD " -H\tGenerate a header file for the strings encountered (-n implied).\n"; + print $FD " -p\tPrint out a null-separated tuple of Set,String,Default,Description\n"; + print $FD " \t\n"; + print $FD "\n"; + +} + +if (defined($opts{"h"})) { + HELP_MESSAGE(); + exit(0); +} + +my $num_modes = 0; +my $mode; + +sub mode_opt { + my $opt = shift; + my $modename = shift; + return if (!defined($opts{$opt})); + $num_modes++; + $mode = $modename; +} + +mode_opt("H", "header"); +mode_opt("p", "print"); + +if ($num_modes == 0) { + print STDERR "Must give one mode of operation!\n"; + HELP_MESSAGE("error"); + exit(1); +} elsif ($num_modes > 1) { + print STDERR "Too many modes of operation - must give exactly one!\n"; + HELP_MESSAGE("error"); + exit(1); +} + +my $recurse = 1; +$recurse = 0 if (defined($opts{"R"})); + +my $fullnames = 0; +$fullnames = 1 if (defined($opts{"f"}) || $mode eq "header"); + +my $headername = "FLUXBOX_NLS_HH"; +$headername = $opts{"n"} if (defined($opts{"n"})); + +my $namespace; +$namespace = $opts{"N"} if (defined($opts{"N"})); + +my $verbose = 0; +$verbose = 1 if (defined($opts{"v"})); + +if (defined($opts{"d"})) { + $fielddelim = $opts{"d"}; + $recorddelim = $opts{"d"}; +} + +if (defined($opts{"r"})) { + $recorddelim = $opts{"r"}; +} + + +if (scalar(@ARGV) == 0) { + print STDERR "Must give one more argument - the directory to scan\n"; + exit(1); +} elsif (scalar(@ARGV) > 1) { + print STDERR "Too many arguments, none expected after directory to scan\n"; + exit(1); +} + + +my $dir = $ARGV[0]; +my $file; +if (!defined($opts{"f"}) && ! -d $dir ) { + print STDERR "$dir is not a directory, aborting\n"; + exit(2); +} elsif (defined($opts{"f"})) { + $file = $dir; + undef $dir; + $recurse = 0; + + if (! -r $file) { + print STDERR "$file is not a readable file, aborting\n"; + exit(2); + } +} + + +############################# +# Actually do stuff! (finally...) + +my %sets; + +if (defined($dir)) { + process_dir($dir); +} else { + process_file($file); +} + +# Now we have the data, we need to print it out +eval "mode_$mode()"; +exit(0); + +# this function is given the fbtext arguments +# But the first argument is the macro name... +sub store { + my ($type, $set, $str, $default, $desc) = @_; + + if ($type eq "_FBTKTEXT") { + $set = "FbTk$set"; + } + + if ($fullnames == 1) { + $str = $set . $str; + $set = $set . "Set"; + } + + $sets{$set}->{$str}{"default"} = $default; + $sets{$set}->{$str}{"desc"} = $desc; + +} + +# C strings can just be a bunch of quoted strings adjacent to +# each other. This just puts them all together, removes the quotes +# and unquotes anything we want to. +# there may be newlines embedded... compare everything /s +sub squish { + my $str = shift; + + # remove first and last quote + $str =~ s/^\s*\"//s; + $str =~ s/\"\s*$//s; + + # now remove any inner quotes and intervening spaces + $str =~ s/([^\\])\"\s*\"/$1/sg; + + # finally, unescape any remaining quotes + $str =~ s/\\\"/\"/g; + + return $str; +} + +sub process_dir { + my $dir = shift; + print STDERR "Processing directory '$dir'\n" if ($verbose == 1); + opendir(DIR, $dir) || die "can't opendir $dir: $!"; + my @files = grep { ( /\.(cc|hh)$/ && -f "$dir/$_" ) || + ( -d "$dir/$_" && $_ !~ /^\.\.?$/ ) + } readdir(DIR); + closedir DIR; + + foreach my $file (@files) { + if (-d "$dir/$file") { + process_dir("$dir/$file") if ($recurse == 1); + } else { + process_file("$dir/$file"); + } + } +} + +# assumptions for now: +# - no more than one NLS thing on any single line +# - internal parenthesis are balanced +# - one nls thing can span several lines +sub process_file { + my $file = shift; + + print STDERR "Processing file '$file'\n" if ($verbose == 1); + open(FILE, "<$file") || die "Can't open file $file: $!"; + + while (<FILE>) { + chomp; + if (/$match_re/ && $_ !~ /^\#(define|undef)/) { + my $tail = $_; + # strip away leading stuff + # note that this doesn't work with more than one match on a line + $tail =~ s/^.*($match_re)/$1/; + # now we just need to find the end, looking out for any + # quotes + my $end = 0; + my $full = $tail; + while ($end == 0) { + # match the defined macro, plus the first 4 arguments + # (ignore any more), then handle them + if ($full =~ /^($match_re)\(([^,]+),\s*([^,]+),((?:\s*\"$noquote*\")+),((?:\s*"$noquote*")+)\s*(?:,.*)?\)/s ) { + store($1, $2, $3, squish($4), squish($5)); + $end++; + } else { + my $extra = <FILE>; + last if (!defined($extra)); + $full .= $extra; + } + } + } + } + close(FILE); +} + + +sub mode_print { + foreach my $set (sort keys %sets) { + foreach my $str (sort keys %{$sets{$set}}) { + print $set . $fielddelim . $str . $fielddelim . $sets{$set}->{$str}{"default"} . $fielddelim . $sets{$set}->{$str}{"desc"} . $recorddelim; + } + } +} + +sub mode_header { + print "// This file generated by $fullcommand, on " . localtime() . "\n\n"; + print "#ifndef $headername\n"; + print "#define $headername\n\n"; + print "namespace $namespace {\n\n" if (defined($namespace)); + print "enum {\n"; + + my $setnum = 0; + foreach my $set (sort keys %sets) { + $setnum++; + printf "\t%s = 0x%x,\n", $set, $setnum; + + my $strnum = 0; + foreach my $str (sort keys %{$sets{$set}}) { + $strnum++; + printf "\t%s = 0x%x,\n", $str, $strnum; + } + print "\n"; + } + print "\tdummy_not_used = 0 // just for the end\n\n"; + print "}; // end enum\n\n"; + print "}; // end namespace $namespace\n\n" if (defined($namespace)); + print "#endif // $headername\n"; +} +