Rewrite `findtext.lua'.

This commit is contained in:
kaeza 2013-10-29 15:54:14 -02:00
parent af31d71d1a
commit 17314b5389
1 changed files with 128 additions and 244 deletions

View File

@ -1,257 +1,141 @@
#! /usr/bin/env lua
local function listdir ( dir )
local LS;
if (os.getenv("WINDIR")) then
LS = 'dir /b %s';
else
LS = 'ls %s';
end
local tmp = os.tmpname();
local r = os.execute(LS:format(dir).." > "..tmp)
if ((r ~= nil) and (r == 0)) then
local list = { };
local f = io.open(tmp);
if (not f) then
os.remove(tmp);
return nil;
end
for line in f:lines() do
list[#list + 1] = line;
end
f:close();
os.remove(tmp);
return list;
end
os.remove(tmp);
return nil;
local me = arg[0]:gsub(".*[/\\](.*)$", "%1")
local function err(fmt, ...)
io.stderr:write(("%s: %s\n"):format(me, fmt:format(...)))
os.exit(1)
end
local function StringOutput ( s, file )
return {
_buf = (s or "");
_file = file;
write = function ( self, ... )
local spc = false;
for _, v in ipairs({...}) do
if (spc) then self._buf = self._buf.." "; end
spc = true;
self._buf = self._buf..tostring(v);
end
end;
print = function ( self, ... )
local spc = false;
for _, v in ipairs({...}) do
if (spc) then self._buf = self._buf.." "; end
spc = true;
self._buf = self._buf..tostring(v);
end
self._buf = self._buf.."\n";
end;
tostring = function ( self )
return self._buf;
end;
flush = function ( self, file )
local f = (file or self._file or io.stdout);
f:write(self._buf);
f:flush();
end;
};
local output
local inputs = { }
local lang
local author
local i = 1
local function usage()
print([[
Usage: ]]..me..[[ [OPTIONS] FILE...
Extract translatable strings from the given FILE(s).
Available options:
-h,--help Show this help screen and exit.
-o,--output X Set output file (default: stdout).
-a,--author X Set author.
-l,--lang X Set language name.
]])
end
local function err_print ( s )
io.stderr:write((s or "").."\n");
while i <= #arg do
local a = arg[i]
if (a == "-h") or (a == "--help") then
usage()
elseif (a == "-o") or (a == "--output") then
i = i + 1
if i > #arg then
err("missing required argument to `%s'", a)
end
output = arg[i]
elseif (a == "-a") or (a == "--author") then
i = i + 1
if i > #arg then
err("missing required argument to `%s'", a)
end
author = arg[i]
elseif (a == "-l") or (a == "--lang") then
i = i + 1
if i > #arg then
err("missing required argument to `%s'", a)
end
lang = arg[i]
elseif a:sub(1, 1) ~= "-" then
table.insert(inputs, a)
else
err("unrecognized option `%s'", a)
end
i = i + 1
end
local function ArgParser ( appname, usageline, description )
return {
prefix = ((appname and (appname..": ")) or "");
description = description;
options = {
{ name = "help";
short = "h";
long = "help";
help = "Show this help screen and exit.";
},
};
values = { };
inputs = { };
no_exit = (appname == nil);
add_option = function ( self, name, short, long, has_arg, arg_name, help )
self.options[#self.options+1] = {
name = name;
short = short;
long = long;
has_arg = has_arg;
arg_name = arg_name;
help = help;
};
end;
parse = function ( self, args, no_exit )
local opts = { };
local inputs = { };
local i = 1;
while (i <= #args) do
local a = args[i];
if (a:sub(1, 1) == '-') then
local found = false;
if ((a == "-h") or (a == "--help")) then
if (no_exit or self.no_exit) then
return nil, "--help";
else
self:show_usage();
os.exit(0);
end
end
for _, opt in ipairs(self.options) do
if ((a == "-"..opt.short) or (a == "--"..opt.long)) then
if (opt.has_arg) then
i = i + 1;
if (not args[i]) then
local msg = self.prefix.."option `"..a.."' requires an argument.";
if (no_exit) then
return nil, msg;
else
err_print(msg);
os.exit(-1);
end
end
opts[opt.name] = args[i];
else
opts[opt.name] = true;
end
found = true;
break;
end
end
if (not found) then
local msg = self.prefix.."unrecognized option `"..a.."'. Try `--help'.";
if (no_exit or self.no_exit) then
return nil, msg;
else
err_print(msg);
os.exit(-1);
end
end
else
inputs[#inputs + 1] = a;
end
i = i + 1;
end
return opts, inputs;
end;
show_usage = function ( self, extramsg )
if (extramsg) then
err_print(self.prefix..extramsg);
end
err_print("Usage: "..appname.." "..(usageline or ""));
if (self.description) then
err_print(self.description)
end
if (#self.options > 0) then
err_print("\nAvailable Options:");
local optwidth = 0;
local optline = { };
for _, opt in ipairs(self.options) do
local sh = (opt.short and "-"..opt.short);
local ln = (opt.long and "--"..opt.long);
local sep = (sh and ln and ",") or " ";
sh = sh or "";
ln = ln or "";
if (opt.long and opt.has_arg) then
ln = ln.." "..opt.arg_name;
end
optline[#optline + 1] = sh..sep..ln;
if (optline[#optline]:len() > optwidth) then
optwidth = optline[#optline]:len();
end
end
for i, opt in ipairs(self.options) do
local sep = string.rep(" ", optwidth - optline[i]:len()).." ";
err_print(" "..optline[i]..sep..opt.help);
end
err_print();
if (self.footer) then
err_print(self.footer.."\n");
end
end
end;
};
if #inputs == 0 then
err("no input files")
end
local function main ( arg )
local APPNAME = "findtext.lua";
local ap = ArgParser(APPNAME, "[OPTIONS] FILES...");
ap:add_option("output", "o", "output", true, "FILE", "Write translated strings to FILE. (default: stdout)");
ap:add_option("langname", "l", "langname", true, "NAME", "Set the language name to NAME.");
ap:add_option("author", "a", "author", true, "NAME", "Set the author to NAME.");
ap:add_option("mail", "m", "mail", true, "EMAIL", "Set the author contact address to EMAIL.");
ap.description = "Finds all the strings that need to be localized, by"..
" searching for things\n like `S(\"foobar\")'.";
ap.footer = "Report bugs to <lkaezadl3@gmail.com>.";
local opts, files = ap:parse(arg);
if (#files == 0) then
files = listdir("*.lua");
if ((not files) or (#files == 0)) then
io.stderr:write(APPNAME..": no input files\n");
os.exit(-1);
end
end
local buffer = StringOutput();
buffer:write("\n");
if (opts.langname) then
buffer:write("# Language: "..opts.langname.."\n");
end
if (opts.author) then
buffer:write("# Author: "..opts.author);
if (opts.mail) then
buffer:write(" <"..opts.mail..">");
end
buffer:write("\n");
end
if (opts.author or opts.langname) then
buffer:write("\n");
end
for _, file in ipairs(files) do
local infile, e = io.open(file);
if (not infile) then
io.stderr:write(APPNAME..": "..e.."\n");
os.exit(1);
end
for line in infile:lines() do
local s = line:match('.-S%("([^"]*)"%).*');
if (s) then
buffer:write(s.." = \n");
end
end
infile:close();
end
local outfile, e;
if (opts.output) then
outfile, e = io.open(opts.output, "w");
if (not outfile) then
io.stderr:write(APPNAME..": "..e.."\n");
os.exit(1);
end
else
outfile = io.stdout;
end
buffer:flush(outfile);
if (outfile ~= io.stdout) then
outfile:close();
end
local outfile = io.stdout
local function printf(fmt, ...)
outfile:write(fmt:format(...))
end
main(arg);
if output then
local e
outfile, e = io.open(output, "w")
if not outfile then
err("error opening file for writing: %s", e)
end
end
if author or lang then
outfile:write("\n")
end
if lang then
printf("# Language: %s\n", lang)
end
if author then
printf("# Author: %s\n", author)
end
if author or lang then
outfile:write("\n")
end
local escapes = {
["\n"] = "\\n",
["="] = "\\=",
["\\"] = "\\\\",
}
local function escape(s)
return s:gsub("[\\\n=]", escapes)
end
local messages = { }
for _, file in ipairs(inputs) do
local infile, e = io.open(file, "r")
if infile then
for line in infile:lines() do
for s in line:gmatch('S%("([^"]*)"%)') do
table.insert(messages, s)
end
end
infile:close()
else
io.stderr:write(("%s: WARNING: error opening file: %s\n"):format(me, e))
end
end
table.sort(messages)
local last_msg
for i, msg in ipairs(messages) do
if msg ~= last_msg then
printf("%s =\n", escape(msg))
end
last_msg = msg
end
if output then
outfile:close()
end
--[[
TESTS:
S("foo") S("bar")
S("bar")
S("foo")
]]