summaryrefslogtreecommitdiff
path: root/Master
diff options
context:
space:
mode:
authorPiotr Strzelczyk <piotr@eps.gda.pl>2009-11-24 23:00:09 +0000
committerPiotr Strzelczyk <piotr@eps.gda.pl>2009-11-24 23:00:09 +0000
commitc154c7e1c1a36d663a552d592e8998aa7d73ab8b (patch)
tree05dc8cf423b31babefc83ba5bc5654ec807564cd /Master
parent3a0b9cfdd15c0cccd2f094bee11b6a7a1cc5ae02 (diff)
new generic wrapper
git-svn-id: svn://tug.org/texlive/trunk@16155 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r--Master/tlpkg/dev/runscript.dllbin0 -> 3072 bytes
-rw-r--r--Master/tlpkg/dev/runscript.tlu257
2 files changed, 257 insertions, 0 deletions
diff --git a/Master/tlpkg/dev/runscript.dll b/Master/tlpkg/dev/runscript.dll
new file mode 100644
index 00000000000..049c06d6e1a
--- /dev/null
+++ b/Master/tlpkg/dev/runscript.dll
Binary files differ
diff --git a/Master/tlpkg/dev/runscript.tlu b/Master/tlpkg/dev/runscript.tlu
new file mode 100644
index 00000000000..a2010f3478b
--- /dev/null
+++ b/Master/tlpkg/dev/runscript.tlu
@@ -0,0 +1,257 @@
+#!/usr/bin/env texlua
+
+--[===================================================================[--
+
+ Script and program wrappers in TeX Live on Windows
+
+ License
+
+ Public Domain
+ Originally written 2009 by Tomasz M. Trzeciak.
+ Loosely based on 'tl-w32-wrapper.texlua'
+ by Reinhard Kotucha and Norbert Preining.
+
+ Rationale
+
+ Wrappers enable to use scripts on Windows as regular programs.
+ Batch wrappers can be used but they are not as universal as binary
+ ones (there are some odd cases where they don't work) and they pose
+ a security risk. OTOH, it is easier to write and maintain scritps
+ than compiled code and for this reason only a small executable stub
+ is used and the main processing happens in a lua script.
+
+ Structure
+
+ Wrappers consist of a small binary part and a common texlua script.
+ The binary part is further split into .exe stub, which acts as
+ a proxy to the dllrunscript function in the common runscript.dll.
+ This is for maintenance reasons - upgrades can be done by replacement
+ of a single .dll rather than all .exe stubs.
+
+ The dllrunscript function locates 'runscript.tlu' lua script,
+ retrieves the full command line string (to avoid quoting problems)
+ and passes it to the lua script, which is executed within the same
+ process by directly linking with luatex.dll and calling its main-like
+ function dllluatexmain.
+
+ The 'runscript.tlu' script locates a script or program to execute
+ based on argv[0]. The script is written in a cross-platform manner
+ with conditional Windows specific features and should work on *nix
+ when symlinked. As an extra optimization, if the located script is
+ a lua script, it is called without starting a new process.
+
+--]===================================================================]--
+
+--[[
+--os.exit(assert(os.spawn('"..\\tmp (dir)\\hello win.exe" '..table.concat(arg, ' '))))
+--os.exit(assert(os.spawn({'print argv.exe', 'foo', 'bar'})))
+print(unpack(arg,0))
+--print(io.stdin, io.stdout, io.stderr)
+--for k,v in pairs(os.env) do print(k,v) end
+os.exit(0)
+--]]
+--arg[#arg-1] = 'texdoc.exe'
+
+-- The main function of this script; locates script/program to run
+function runscript_find_prog()
+
+ -- TODO: handle the (recursive!) case of runscript.exe => runscript.tlu
+
+ -- function _q adds quotes where necessary
+ -- (names with spaces and spaecial shell characters)
+ local function _q(str)
+ if str and (os.type == 'windows') then
+ str = string.gsub(str, '"', '') -- disallow embedded double quotes
+ --if string.find(str, "[^_%w%-:/\\.]") then
+ if string.find(str, "[%s&|<>]") then
+ return '"'..str..'"'
+ else
+ return str
+ end
+ else
+ return str
+ end
+ end
+
+ -- check if path is absolute (no check if it exists)
+ local function isabspath(fpath)
+ if string.find(fpath, '^[/\\]') or string.find(fpath, '^[a-zA-Z]:[/\\]') then
+ return true
+ else
+ return false
+ end
+ end
+
+ -- search the path variable for a file
+ local function search_path(fname, path)
+ if isabspath(fname) then return fname end
+ local dirsep = (os.type == 'windows') and '\\' or '/'
+ local pathsep = (os.type == 'windows') and ';' or ':'
+ if not path then path = os.getenv('PATH') end
+ for dir in string.gmatch(path, '[^'.. pathsep..']+') do
+ local f = dir..dirsep..fname
+ if lfs.isfile(f) then return f end
+ end
+ return nil, "file not found: "..fname
+ end
+
+ -- locate the program/script to execute
+ local function find_script(progname, BINDIR)
+ if BINDIR then
+ for _, ext in ipairs({'.tlu', '.bat', '.cmd'}) do
+ if lfs.isfile(BINDIR..'/'..progname..ext) then
+ return BINDIR..'/'..progname..ext, ext
+ end
+ end
+ end
+ for _, ext in ipairs({'.tlu', '.texlua', '.lua', '.pl', '.rb', '.py',
+ '.jar', '.bat', '.cmd', '.vbs', '.js', '' }) do
+ local progfullname = kpse.find_file(progname..ext, 'texmfscripts')
+ if progfullname then return progfullname, ext end
+ end
+ return nil, "no appropriate script or program found: "..progname
+ end
+
+ -- convert the #! line to arg table (for scripts w/o extension)
+ -- only the two most common cases are considered:
+ -- #! /path/to/command [options]
+ -- #! /usr/bin/env command [options]
+ -- ([options] after the command are retained as well)
+ local function shebang_cmd(progfullname)
+ local fid = assert(io.open(progfullname, 'r'))
+ local fstln = fid:read('*line')
+ fid:close()
+ if (string.sub(fstln, 1, 2) ~= '#!') then
+ return nil, "don't know how to execute script: "..progfullname
+ end
+ local arglist = string.explode( string.sub(fstln, 3) ) -- split on spaces
+ arglist[1] = string.match(arglist[1], '[^/]+$')
+ if (arglist[1] == 'env') then arglist = {unpack(arglist, 2)} end
+ return arglist
+ end
+
+ -- check if command exist on the path and return it
+ local function chk_cmd(cmd, PATH)
+ local fullcmd = cmd
+ if not isabspath(cmd) then
+ if (os.type == 'windows') and not string.find(cmd, '%.') then
+ fullcmd = fullcmd..'.exe'
+ end
+ fullcmd = search_path(fullcmd, PATH)
+ end
+ if fullcmd then
+ return fullcmd
+ else
+ return nil, 'interpreter program not found (not part of TeX Live): '..cmd
+ end
+ end
+
+ local dirsep, pathsep, _exe = '/', ':', ''
+ local w32arg
+ if (os.type == 'windows') then
+ dirsep, pathsep, _exe = '\\', ';', '.exe'
+ -- on Windows argv[0] and unparsed argument line are passed
+ -- from the .exe stub as the two last arguments
+ w32arg = {[0]=arg[#arg-1], arg[#arg]}
+ arg[0] = arg[#arg-1]
+ arg[#arg] = nil
+ arg[#arg] = nil
+ end
+
+ local progname = string.match(arg[0], '[^/\\]+$')
+ local progext = ''
+ if (os.type == 'windows') then
+ progname = string.gsub(progname, '%.[^.]*$', '') -- remove extension
+ progext = string.match(arg[0], '%.[^.]*$')
+ end
+
+ -- initialize kpathsea
+ kpse.set_program_name(arg[-1], progname)
+ -- get TEXDIR and BINDIR
+ local TEXDIR = kpse.var_value('SELFAUTOPARENT')
+ local BINDIR = kpse.var_value('SELFAUTOLOC')
+ local perlbin = TEXDIR..'/tlpkg/tlperl/bin/perl'.._exe
+
+ local PATH = BINDIR..';'..
+ TEXDIR..'/tlpkg/tlperl/bin;'.. --?
+ TEXDIR..'/tlpkg/tlgs/bin;'.. --?
+ TEXDIR..'/tlpkg/installer;'.. --?
+ TEXDIR..'/tlpkg/installer/wget;'.. --?
+ os.getenv('PATH')
+
+ os.setenv('PATH', PATH);
+ --os.setenv('WGETRC', TEXDIR..'/tlpkg/installer/wgetrc')
+ os.setenv('PERL5LIB', TEXDIR..'/tlpkg/tlperl/lib')
+ os.setenv('GS_LIB', TEXDIR..'/tlpkg/tlgs/lib;'..TEXDIR..'/tlpkg/tlgs/fonts')
+
+ if string.find(TEXDIR, '%-sys$') then -- 'sys' programs
+ os.setenv('TEXMFVAR', kpse.var_value('TEXMFSYSVAR'))
+ os.setenv('TEXMFCONFIG', kpse.var_value('TEXMFSYSCONFIG'))
+ end
+
+
+ local alias_table = {
+ ['fmtutil-sys'] = {[0]=BINDIR..'/fmtutil'.._exe, 'fmtutil'},
+ ['updmap-sys'] = {[0]=perlbin, 'perl',
+ _q(TEXDIR..'/texmf/scripts/tetex/updmap.pl')},
+ ['getnonfreefonts-sys'] = {[0]=perlbin, 'perl',
+ _q(TEXDIR..'/texmf/scripts/getnonfreefonts/getnonfreefonts.pl'), '--sys'},
+ sam2p = {[0]=TEXDIR..'/tlpkg/sam2p/sam2p'.._exe, 'sam2p'},
+ }
+
+ local ext_map = { -- map script extension to command
+ --['.bat'] = {'cmd', '/x', '/c', 'call'},
+ --['.cmd'] = {'cmd', '/x', '/c', 'call'},
+ ['.jar'] = {'java', '-jar'},
+ ['.js'] = {(progext == '.gui') and 'wscript' or 'cscript', '-nologo'},
+ ['.pl'] = {(progext == '.gui') and 'wperl' or 'perl'},
+ ['.py'] = {'python'},
+ ['.rb'] = {'ruby'},
+ ['.vbs'] = {(progext == '.gui') and 'wscript' or 'cscript', '-nologo'},
+ }
+
+ if alias_table[progname] then
+ return alias_table[progname]
+ end
+
+ local progfullname, ext = assert(find_script(progname, BINDIR))
+ local arglist
+ if (ext == '.lua') or (ext == '.tlu') or (ext == '.texlua') then
+ arg[0] = progfullname
+ return progfullname
+ elseif (ext == '.bat') or (ext == '.cmd') then
+ arglist = {[0]=os.getenv('SystemRoot')..'\\System32\\cmd.exe',
+ 'cmd', '/x', '/c', 'call', _q(progfullname)}
+ for _, arg_i in ipairs(arg) do arglist[#arglist+1] = _q(arg_i) end
+ else
+ arglist = (ext == '') and assert(shebang_cmd(progfullname)) or ext_map[ext]
+ arglist[#arglist+1] = _q(progfullname)
+ arglist[0] = assert(chk_cmd(arglist[1], PATH))
+ -- copy arg list starting from 1
+ for _, arg_i in ipairs(w32arg or arg) do arglist[#arglist+1] = arg_i end
+ end
+ return arglist
+
+end
+
+prog = runscript_find_prog()
+
+if type(prog) == 'table' then
+ -- argv table
+ os.exit(assert(os.spawn(prog)))
+elseif type(prog) == 'string' then
+ -- lua script
+ dofile(prog)
+else
+ error("unexpected return value of type: "..type(prog))
+end
+
+--[[
+-- make a copy of _G, so we can recover original global space
+-- to be mounted later on as a clean function environment
+-- (if the located script turns out to be a lua script)
+__G = {}
+for k, v in pairs(_G) do __G[k] = v end
+__G._G = __G
+__G.__G = nil
+--]]