summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/lua2dox/lua2dox.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/scripts/lua2dox/lua2dox.lua')
-rwxr-xr-xMaster/texmf-dist/scripts/lua2dox/lua2dox.lua618
1 files changed, 618 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/lua2dox/lua2dox.lua b/Master/texmf-dist/scripts/lua2dox/lua2dox.lua
new file mode 100755
index 00000000000..9249baac9cd
--- /dev/null
+++ b/Master/texmf-dist/scripts/lua2dox/lua2dox.lua
@@ -0,0 +1,618 @@
+--[[--------------------------------------------------------------------------
+ -- Copyright (C) 2012 by Simon Dales --
+ -- simon@purrsoft.co.uk --
+ -- --
+ -- This program is free software; you can redistribute it and/or modify --
+ -- it under the terms of the GNU General Public License as published by --
+ -- the Free Software Foundation; either version 2 of the License, or --
+ -- (at your option) any later version. --
+ -- --
+ -- This program is distributed in the hope that it will be useful, --
+ -- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+ -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+ -- GNU General Public License for more details. --
+ -- --
+ -- You should have received a copy of the GNU General Public License --
+ -- along with this program; if not, write to the --
+ -- Free Software Foundation, Inc., --
+ -- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. --
+----------------------------------------------------------------------------]]
+
+--[[!
+ \file
+ \brief a hack lua2dox converter
+ ]]
+
+--[[!
+ \mainpage
+
+
+ A hack lua2dox converter
+ Version 0.1
+
+ This lets us make Doxygen output some documentation to let
+ us develop this code.
+
+ It is partially cribbed from the functionality of lua2dox
+ (http://search.cpan.org/~alec/Doxygen-Lua-0.02/lib/Doxygen/Lua.pm).
+ Found on CPAN when looking for something else; kinda handy.
+
+ Improved from lua2dox to make the doxygen output more friendly.
+ Also it runs faster in lua rather than Perl.
+
+ Because this Perl based system is called "lua2dox"., I have decided to add ".lua" to the name
+ to keep the two separate.
+
+ 0. Ensure doxygen is installed on your system and that you are familiar with its use.
+ Best is to try to make and document some simple C/C++/PHP to see what it produces.
+
+ 1. Run "lua2dox_lua -g" to create a default Doxyfile.
+
+ Then alter it to let it recognise lua. Add the two following lines:
+
+ FILE_PATTERNS = *.lua
+
+ FILTER_PATTERNS = *.lua=lua2dox_filter
+
+ Either add them to the end or find the appropriate entry in Doxyfile.
+
+ 2. When Doxyfile is edited run as "lua2dox_lua"
+
+ When reading source with classes multiple passes are needed.
+ Each pass generates a list of member functions (as a file) that were found on this pass.
+ This list is read in on the next pass.
+ If the class+methods haven't changed this time then you only need to run it once, else run twice.
+
+ The core function reads the input file (filename or stdin) and outputs some pseudo C-ish language.
+ It only has to be good enough for doxygen to see it as legal.
+ Therefore our lua interpreter is fairly limited, but "good enough".
+
+ One limitation is that each line is treated separately (except for long comments).
+ The implication is that class and function declarations must be on the same line.
+ Some functions can have their parameter lists extended over multiple lines to make it look neat.
+ Managing this where there are also some comments is a bit more coding than I want to do at this stage,
+ so it will probably not document accurately if we do do this.
+
+ However I have put in a hack that will insert the "missing" close paren.
+ The effect is that you will get the function documented, but not with the parameter list you might expect.
+
+ Installation:
+
+ Here for linux or unix-like, for any other OS you need to refer to other documentation.
+
+ This file is "lua2dox.lua". It gets called by "lua2dox_lua".
+ Somewhere in your path (e.g. "~/bin" or "/usr/local/bin") put two links to "lua2dox_lua".
+ Names to use are "lua2dox_lua" and "lua2dox_filter".
+
+ Call it as "lua2dox_lua" and the filter that gets called by doxygen is "lua2dox_filter".
+
+ ]]
+
+-- we won't use our library code, so this becomes more portable
+
+local TConfig_config={
+ ['LUA2DOX_COMMENTARY_FILE_IN']='./killme_lua2dox.methods'
+ ,['LUA2DOX_COMMENTARY_FILE_OUT']='./killme_lua2dox.methods.out'
+ }
+
+--! \brief Gets a config val
+local function TConfig_get(Key,Default)
+ local val = TConfig_config[Key]
+ if not val then
+ val = Default
+ end
+ return val
+end
+
+--! \brief sets a config val
+local function TConfig_set(Key,Val)
+ TConfig_config[Key] = Val
+end
+
+--! \brief write to stdout
+--!
+--! writes Str (if not nil)
+local function TIO_write(Str)
+ if (Str) then
+ io.write(Str)
+ end
+end
+
+--! \brief write to stdout
+--!
+--! writelns Str (if not nil) and then an eoln.
+local function TIO_writeln(Str)
+ if (Str) then
+ io.write(Str)
+ end
+ io.write("\n")
+end
+
+--! \brief show error to stdout
+--!
+--! writelns Str (if not nil) and then an eoln.
+local function TIO_showError(Err,Str)
+ local err = Err
+ if not err then
+ err = 1
+ end
+
+ TIO_write('Error (' .. err .. '):')
+ TIO_writeln(Str)
+ return err
+end
+
+--! \brief run system command
+local function TOS_system(Cmd)
+ local errno,str
+ local rtn = os.execute(Cmd)
+ if not (rtn==0) then
+ errno = rtn
+ str = 'an error occured'
+ end
+ return errno,str
+end
+
+--! \brief does file exist?
+local function TOS_fileExists(Filename)
+ local fh = io.open(Filename,'r')
+ if fh~=nil then
+ fh:close()
+ return true
+ end
+ return false
+end
+
+--! \brief get the current time
+local function TClock_GetTimeNow()
+ if os.gettimeofday then
+ return os.gettimeofday()
+ else
+ return os.time()
+ end
+end
+
+--! \brief get a timestamp
+--!
+--! not strictly necessary here but lets us put a timestamp on the end of the output stream.
+--! Note that doxygen won't read this, and being off the end of the true file length (num lines),
+--! it will have no effect.
+--! However it lets us check the output file tail when debugging.
+--!
+local function TClock_getTimeStamp()
+ local now = TClock_GetTimeNow()
+ local fraction_secs = now - math.floor(now)
+ return os.date('%c %Z',now) .. ':' .. fraction_secs
+end
+
+--! \brief trims a string from both ends
+local function TString_trim(Str)
+ return Str:match("^%s*(.-)%s*$")
+end
+
+--! \brief split a string
+--!
+--! \param Str
+--! \param Pattern
+--! \returns table of string fragments
+local function TString_split(Str, Pattern)
+ local splitStr = {}
+ local fpat = "(.-)" .. Pattern
+ local last_end = 1
+ local str, e, cap = string.find(Str,fpat, 1)
+ while str do
+ if str ~= 1 or cap ~= "" then
+ table.insert(splitStr,cap)
+ end
+ last_end = e+1
+ str, e, cap = string.find(Str,fpat, last_end)
+ end
+ if last_end <= #Str then
+ cap = string.sub(Str,last_end)
+ table.insert(splitStr, cap)
+ end
+ return splitStr
+end
+
+--! \brief trim comment off end of string
+--!
+--! If the string has a comment on the end, this trims it off.
+--!
+local function TString_removeCommentFromLine(Line)
+ local pos_comment = string.find(Line,'%-%-')
+ if pos_comment then
+ Line = string.sub(Line,1,pos_comment-1)
+ end
+ return Line
+end
+
+local TClassList_methods = {}
+--! \brief get methods
+local function TClassList_method_get(Klass)
+ return TClassList_methods[Klass]
+end
+
+--! \brief add a method to list of known methods
+local function TClassList_method_add(Klass,Method)
+ local classRec = TClassList_methods[Klass]
+ if not classRec then
+ TClassList_methods[Klass] = {}
+ classRec = TClassList_methods[Klass]
+ end
+ table.insert(classRec,Method)
+end
+
+
+local TCommentary_fh
+
+--! \brief write to output file
+local function TCommentary_writeln(Str)
+ if TCommentary_fh then
+ TCommentary_fh:write(Str .. '\n')
+ end
+end
+
+local TCommentary_fileID
+--! \brief open the commentary save file
+local function TCommentary_open(Filename,InputLuaFilename)
+ TCommentary_fileID = '"' .. InputLuaFilename .. '" : ' .. TClock_getTimeStamp()
+ TCommentary_fh = io.open(Filename,'a+')
+ if TCommentary_fh then
+ TCommentary_writeln('// opened:' .. TCommentary_fileID)
+ end
+end
+
+--! \brief close the methods save file
+local function TCommentary_close()
+ if TCommentary_fh then
+ TCommentary_writeln('// closed: ' .. TCommentary_fileID)
+ TCommentary_fh:close()
+ TCommentary_fh = nil
+ end
+end
+
+--! \brief read stuff from save file
+local function TCommentary_readFileContents(Filename)
+ if TOS_fileExists(Filename) then
+ local klass,method,dot
+ local cmd,colon
+ local k,v,equals
+ for line in io.lines(Filename) do
+ if string.sub(line,1,2)=='//' then
+ -- it's a comment
+ else
+ colon = string.find(line,':')
+ if colon then
+ cmd = string.sub(line,1,colon)
+ line = string.sub(line,colon+1)
+ else
+ cmd = nil
+ end
+ if (cmd == 'method:') then
+ dot = string.find(line,'%.')
+ klass = string.sub(line,1,dot-1)
+ method = string.sub(line,dot+1)
+ TClassList_method_add(klass,method)
+ elseif(cmd == 'set:') then
+ equals = string.find(line,'=')
+ if equals then
+ k = string.sub(line,1,equals-1)
+ v = string.sub(line,equals+1)
+ TConfig_set(k,v)
+ else
+ TConfig_set(line,true)
+ end
+ else -- ignore
+ TIO_write('/* bad command:"' .. line .. '" */')
+ end
+ end
+ end
+ else
+ TIO_write('/* file "' .. Filename .. '" don\'t exist */')
+ end
+end
+
+--! \brief method to save file
+local function TCommentary_addMethod(Klass,Method)
+ if TCommentary_fh then
+ if Klass and Method then
+ if string.find(Klass,'%.') or string.find(Method,'%.') then
+ -- iffy, so we discard it
+ else
+ TCommentary_writeln('method:' .. Klass .. '.' .. Method)
+ end
+ end
+ end
+end
+
+--! \brief output line to stream
+--!
+--! Wraps IO_writeln()
+local function TIO_out2stream(Line)
+ TIO_writeln(Line)
+end
+
+--! \brief suppress line
+local function TIO_out2stream_commented(Line,Prefix,Suffix)
+ local line = Line
+ if (not Prefix) then
+ Prefix=''
+ end
+ line = Prefix .. ':' .. line
+
+ if (Suffix) then
+ line = line .. Suffix
+ end
+ TIO_out2stream('// D' .. line)
+end
+
+
+TCommandline_argv = {}
+--! \brief setup/parse the commandline
+local function TCommandline_setup()
+ local argv1 =arg[1]
+ if not argv1 then
+ argv1 = 'base'
+ end
+ TCommandline_argv_appname = argv1
+
+ local i=2
+ local argvi=1
+ while (argvi) do
+ argvi = arg[i]
+ if argvi then
+ TCommandline_argv[i-1] = argvi
+ i = i + 1
+ end
+ end
+end
+--! setup the commandline now
+TCommandline_setup()
+
+--! \brief get commandline args
+local function TCommandline_getargv()
+ return TCommandline_argv
+end
+
+--! \brief get appname
+local function TApp_get_appname()
+ return TCommandline_argv_appname
+end
+
+--! \brief hack converter from lua to a pseudoC-ish language for doxygen
+--!
+--! This is a hack to make lua readable to doxygen.
+--!
+--! It works well enough to document functions/methods and classes, but not assignments.
+--! Our pseudo-C gets confused if we allow assginments to be shown.
+--! Because these are less interesting than class/functions/methods I have decided to
+--! live with this limitation.
+--!
+local function TApp_lua2dox(FileContents)
+ local err
+ local lines = FileContents
+ local maxi=#lines
+
+ local i = 1
+ local line,head
+ while not err and (i<=maxi) do
+ line = TString_trim(lines[i])
+ if #line==0 then
+ TIO_out2stream()
+ elseif string.sub(line,1,2)=='--' then
+ -- it's a comment of some kind
+ if string.sub(line,1,3)=='--!' then
+ -- it's a magic comment
+ TIO_out2stream('//!' .. string.sub(line,4))
+ elseif string.sub(line,1,4)=='--[[' then
+ -- it's a multiline comment
+ -- read lines to end of comment
+ local hitend
+ local comment = ''
+ line = string.sub(line,5) --.. sep
+ while not err and (i<maxi) and not hitend do
+ comment = comment .. line .. '\n'
+ line = lines[i+1]
+ --if (string.sub(TString_trim(line),1,2)==']]') then
+ if (string.find(line,'\]\]')) then
+ local pos_close = string.find(line,'\]\]')
+ comment = comment .. string.sub(line,1,pos_close-1)
+ hitend=true
+ end
+ i = i + 1
+ end
+ -- got long comment
+ if string.sub(comment,1,1)=='!' then
+ TIO_out2stream('/*' .. comment .. '*/')
+ else
+ TIO_out2stream('/* (longcomment):' .. comment .. '*/')
+ end
+ else
+ -- it's a boring comment
+ TIO_out2stream_commented(line,'--')
+ end
+ elseif string.find(line,'^function%s') or string.find(line,'^local%s+function%s')then
+ -- "function wibble..."
+ -- it's a function declaration
+ -- ....v...
+ local pos_fn = string.find(line,'function')
+ if (pos_fn) then
+ local pos_local = string.find(line,'^local%s+function%s')
+ local fn = TString_removeCommentFromLine(TString_trim(string.sub(line,pos_fn+8)))
+
+ if (string.sub(fn,1,1)=='(') then
+ -- anonymous function
+ TIO_out2stream_commented(line,'anon fn')
+ else
+ --[[
+ we might have extracted a fn def with parameters on multilines
+ The hack is to insert a new close paren with a note to that effect.
+ ]]
+
+ if not string.find(fn,'%)') then
+ fn = fn .. ' ___MissingCloseParenHere___)'
+ end
+
+ local plain_fn_str = 'function ' .. fn .. '{}'
+ if pos_local then
+ plain_fn_str = 'local ' .. plain_fn_str
+ end
+
+ local dot = string.find(fn,'%.')
+ if dot then -- it's a method
+ local klass = string.sub(fn,1,dot-1)
+ local method = string.sub(fn,dot+1)
+ local method_str = klass .. '::' .. method .. '{}'
+ TCommentary_addMethod(klass,method)
+ TIO_out2stream(method_str)
+ else
+ TIO_out2stream(plain_fn_str)
+ end
+ end
+ end
+ elseif string.find(line,'=%s+class%(') then
+ -- it's a class definition
+ line = TString_removeCommentFromLine(line)
+ local klass,parent,pos_class
+ -- ....v...
+ pos_class = string.find(line,'=%s+class%(')
+ klass = TString_trim(string.sub(line,1,pos_class-1))
+ parent = TString_trim(string.sub(line,pos_class+8))
+ parent = string.sub(parent,1,-2)
+
+ line = 'class ' .. klass
+ if (#parent>0) then
+ line = line .. ' :public ' .. parent
+ end
+
+ -- need methods list
+ local methods = TClassList_method_get(klass)
+ local methods_str
+ if methods then
+ methods_str = 'public: '
+ for k,v in pairs(methods) do
+ methods_str = methods_str .. v .. ';'
+ end
+ else
+ methods_str = '/* no methods reported */'
+ end
+ line = line .. '{' .. methods_str .. '}'
+
+ TIO_out2stream(line .. ';',true)
+ else
+ -- we don't know what this line means, so we can probably just comment it out
+ TIO_out2stream_commented(line)
+ end
+
+ i = i + 1
+ end
+ return err
+end
+
+--! \brief run the filter
+--!
+--! \param AppTimestamp application + timestamp for this run
+--! \param Filename the filename or if nil stdin
+--! \param CommentaryFiles names of commentary files
+--! \return err or nil
+--!
+local function TApp_run_filter(AppTimestamp,Filename,CommentaryFiles)
+ local err
+ local filecontents
+ if Filename then
+ -- syphon lines to our table
+ filecontents={}
+ for line in io.lines(Filename) do
+ table.insert(filecontents,line)
+ end
+ else
+ -- get stuff from stdin as a long string (with crlfs etc)
+ filecontents=io.read('*a')
+ -- make it a table of lines
+ filecontents = TString_split(filecontents,'[\n]') -- note this only works for unix files.
+ Filename = 'stdin'
+ end
+
+ if filecontents then
+ TCommentary_readFileContents(CommentaryFiles.infile)
+ TCommentary_open(CommentaryFiles.outfile,Filename)
+
+ err = TApp_lua2dox(filecontents)
+
+ TCommentary_close()
+
+ TIO_writeln('// done (' .. AppTimestamp .. ')')
+ else
+ err = TIO_showError(1,'couldn\'t find any file contents')
+ end
+ return err
+end
+
+--! \brief run doxygen for one
+--!
+--! \param AppTimestamp application + timestamp for this run
+--! \param Argv commandline for this run
+--! \param CommentaryFiles names of commentary files
+--! \return err or nil
+--!
+local function TApp_run_doxygen(AppTimestamp,Argv,CommentaryFiles)
+ local err
+ TIO_writeln('running: ' .. AppTimestamp)
+
+ local argv1 = Argv[1]
+ if argv1=='--help' then
+ local appname = TApp_get_appname()
+ TIO_writeln('Syntax:')
+ TIO_writeln(' ' .. appname .. ' [[-g] [-s]] [<Doxyfile name>]|--help')
+ TIO_writeln(' --help show this text')
+ TIO_writeln(' -g: generate new Doxyfile')
+ TIO_writeln(' -s: generate new Doxyfile without comments')
+ TIO_writeln(' <Doxyfile name>: name of Doxyfile')
+
+ TIO_writeln()
+ TIO_writeln(' For help on doxygen run its help system directly')
+ --! \todo more help here
+ else
+ local cl = 'doxygen'
+ for i,argv_i in ipairs(Argv) do
+ if i>=1 then -- don't want to use this app's name
+ cl = cl .. ' ' .. argv_i
+ end
+ end
+
+ TIO_writeln('about to run "' .. cl .. '"')
+ err = TOS_system(cl)
+
+ if not err then
+ -- cycle commentary files
+ local newComments=CommentaryFiles.outfile
+ local nextRunsComments=CommentaryFiles.infile
+ if TOS_fileExists(newComments) then
+ TIO_writeln('found outfile "' .. newComments .. '"')
+ os.remove(nextRunsComments)
+ TIO_writeln('mv "' .. newComments .. '"-> ' .. nextRunsComments .. '"')
+ os.rename(newComments,nextRunsComments)
+ end
+ end
+ end
+ return err
+end
+
+-- main
+local timestamp = TClock_getTimeStamp()
+local appname = TApp_get_appname()
+local version = '0.1 20120704'
+local appTimestamp = appname .. '(v' .. version .. ') :' .. timestamp
+local commentary_files = {
+ infile=TConfig_get('LUA2DOX_COMMENTARY_FILE_IN')
+ ,outfile=TConfig_get('LUA2DOX_COMMENTARY_FILE_OUT')
+ }
+
+if appname == 'lua2dox_filter' then
+ err = TApp_run_filter(appTimestamp,TCommandline_getargv()[1],commentary_files)
+ TIO_writeln('// do filter')
+else
+ err = TApp_run_doxygen(appTimestamp,TCommandline_getargv(),commentary_files)
+end
+
+--eof \ No newline at end of file