From 126281c516caeb172098104034035507b627031f Mon Sep 17 00:00:00 2001 From: Vladimir Volovich Date: Sat, 9 Aug 2008 23:09:24 +0000 Subject: sync linked_scripts with Master tree git-svn-id: svn://tug.org/texlive/trunk@10218 c570f23f-e606-0410-a88d-b1316a301751 --- .../source/texk/texlive/linked_scripts/pdfatfi.pl | 4 +- Build/source/texk/texlive/linked_scripts/ps4pdf | 3 +- .../source/texk/texlive/linked_scripts/texdoc.tlu | 910 ++++++++++++--------- Build/source/texk/texlive/linked_scripts/tlmgr.pl | 138 +++- 4 files changed, 646 insertions(+), 409 deletions(-) (limited to 'Build/source') diff --git a/Build/source/texk/texlive/linked_scripts/pdfatfi.pl b/Build/source/texk/texlive/linked_scripts/pdfatfi.pl index 5c5500b74b1..dec7f96defd 100755 --- a/Build/source/texk/texlive/linked_scripts/pdfatfi.pl +++ b/Build/source/texk/texlive/linked_scripts/pdfatfi.pl @@ -26,8 +26,8 @@ $^W=1; # turn warning on # my $file = "pdfatfi.pl"; my $program = uc($&) if $file =~ /^\w+/; -my $version = "2.3"; -my $date = "2007/04/11"; +my $version = "2.4"; +my $date = "2008/07/29"; my $author = "Heiko Oberdiek"; my $copyright = "Copyright (c) 2005, 2006 by $author."; # diff --git a/Build/source/texk/texlive/linked_scripts/ps4pdf b/Build/source/texk/texlive/linked_scripts/ps4pdf index cbdcb022926..621d3b71ad8 100755 --- a/Build/source/texk/texlive/linked_scripts/ps4pdf +++ b/Build/source/texk/texlive/linked_scripts/ps4pdf @@ -8,6 +8,7 @@ # as suggested by Niall Murphy. # 2006-07-14: Better temp dir handling (suggested by Karl Berry) (RN). # 2006-07-23: New option --Xps2pdf and code cleanup (thanks to Karl Berry) (RN). +# 2008-08-04: Remove the parameter "-Ppdf" from the dvips call (RN). # First, work around bugs/limitations in some shells on some systems: test -f /bin/sh5 && test -z "$RUNNING_SH5" \ @@ -119,7 +120,7 @@ job=`echo "x$1" | sed 's@x@@; s@.*/@@; s@\.[^.]*$@@'` setupTmpDir myexec latex \ "\AtBeginDocument{\RequirePackage{pst-pdf}} \input{$file}" -test -f "$job.dvi" && myexec dvips -Ppdf -o "$job-pics.ps" "$job.dvi" +test -f "$job.dvi" && myexec dvips -o "$job-pics.ps" "$job.dvi" test -f "$job-pics.ps" && myexec ps2pdf \ "$ps2pdf_opts" "$job-pics.ps" "$job-pics.pdf" if $crop; then diff --git a/Build/source/texk/texlive/linked_scripts/texdoc.tlu b/Build/source/texk/texlive/linked_scripts/texdoc.tlu index a19cb333302..e02f496db75 100755 --- a/Build/source/texk/texlive/linked_scripts/texdoc.tlu +++ b/Build/source/texk/texlive/linked_scripts/texdoc.tlu @@ -1,17 +1,18 @@ #!/usr/bin/env texlua --- $Id: texdoc.tlu 9776 2008-07-25 23:58:05Z mpg $ ---[[ Revised by Manuel Pégourié-Gonnard and Reinhard Kotucha, 2008. -First texlua version by Frank Küster (2007) based on the shell script by -Thomas Esser, David Aspinall, and Simon Wilkinson. -Public domain.]] +-- $Id: texdoc.tlu 10142 2008-08-07 16:06:44Z mpg $ -*-Lua-*- +--[[Revised 2008 by Manuel Pégourié-Gonnard + with contributions from Reinhard Kotucha. + First texlua versions by Frank Küster (2007). + Origial shell script by Thomas Esser, David Aspinall, and Simon Wilkinson. + Public domain.]] --[[ Changelog 0.4 2008-07 - moved configuration from texmf.cnf to texdoc.cnf - added an 'alias' feature - - new 'mixed' mode (view or list) - - file lists are now menus (press a key to view results) + - new modes 'mixed' and 'regex' + - file lists are now menus (select number to view results) - changed the search modes to get only the more relevant results (hopefully) - - /!\ zip support disabled by default (see comments below), not portable + - /!\ zip support disabled by default (not portable) (see comments below) 0.3 2007-06-28 - added changelog @@ -29,24 +30,38 @@ Public domain.]] -- some constants progname = 'texdoc' -version = '0.4beta' +version = '0.4' +-- make sure to update setup_config_from_cl() accordingly +-- and set a default value in setup_config_from_defaults() if relevant usage_msg = [[ -Usage: texdoc -h, --help | -V, --version | [option] name(s) - -h|--help Show this help. - -V|--version Print the version of the program. - -v|--verbose Show the command being used to display the documentation. - -a|--alias Use the alias table. - -A|--noalias Don't use the alias table. - -e|--extension Search only for files of given type (extension). - -w|--view Use view mode: start a viewer. - -m|--mixed Use mixed mode (view or list). - -l|--list Use list mode: don't start a viewer. - -s|--search Search for name as a lua regex.]] +Usage: texdoc -h, --help | -v, --version | -f, --files | [option(s)] name(s) + -h, --help Show this short help. + -v, --version Print the version of the program. + -f, --files Print the name of the config files being used. + -e, --extensions=L Require file extensions to be in the list L. + -w, --view Use view mode: start a viewer. + -m, --mixed Use mixed mode (view or list). + -l, --list Use list mode: don't start a viewer. + -s, --search Search for name as a substring. + -r, --regex Search for name as a lua regex. + -a, --alias Use the alias table. + -A, --noalias Don't use the alias table. + -i, --interact Use interactive menus. + -I, --nointeract Use plain lists, no interaction required. + -n, --noise-level=N Set verbosity level to N. +The command `texdoc texdoc' gives you the full user guide in pdf. +Please report bugs and request features at texlive AT tug.org.]] notfound_msg = [[ Sorry, no documentation found for PKGNAME. -Perhap's you'll be more lucky with the CTAN catalogue's search tool at +If you are unsure about the name, try searching CTAN's TeX catalogue at http://ctan.org/search.html#byDescription.]] place_holder = '%%s' -- used for viewer commands +err_priority = { + error = 1, + warning = 2, + info = 3, + debug1 = 4, +} -- zip/gz support -- @@ -79,157 +94,245 @@ end -- functions for the search options ----------------------------------- --- full tree exploration with or without ls-R file - --- check which texmf roots have a ls-R file (returns an iterator for those) --- and which don't (put them in the global no_lsr_trees) (bad) -no_lsr_doctrees = {} -function get_lsr_files () - local lsr_files = {} - local pathlist = kpse.expand_braces('$TEXDOCS') - for path in string.gmatch(pathlist, "[^:;]+") do - path = string.gsub(path,'//$','') - local tree_root - tree_root = string.gsub(path,'doc$','') - tree_root = string.gsub(tree_root,'^!!','') - if lfs.isfile(tree_root .. "ls-R") then - table.insert(lsr_files,tree_root .. "ls-R") +-- BEGIN kpse-like + +-- get global texdocs, do_recurse and must_have_lsr lists from kpse's $TEXDOCS +function get_texdocs () + local sep = (os.type == 'windows') and ';' or ':' + texdocs = kpse.expand_var ("$TEXDOCS") + -- expand the path and turn it into a lua list + texdocs = string.explode (kpse.expand_braces (texdocs), sep) + do_recurse, must_have_lsr = {}, {} -- global + for i, dir in ipairs (texdocs) do + local n + dir, n = string.gsub (dir, '//$', '') + do_recurse[i] = (n == 1) + texdocs[i], n = string.gsub (dir, '^!!', '') + must_have_lsr[i] = (n == 1) + end +end + +-- says if ext is 'good' according to ext_list +function is_good_ext (ext) + for e in list (config.ext_list) do + if e == '*' then + return true + elseif (e == '') and (not ext) then + return true + elseif ext == e then + return true + end + end + return false +end + +-- include a file in the lists if it should be +function process_file (file, pathfile, code, pattern) + local base, ext = string.match(file, '^(.*)%.(.*)$') + if string.find(pathfile, pattern, 1, no_regex) and is_good_ext (ext) + then + if base == pattern then + table.insert(exact_docfiles, code_path (code, pathfile)) else - if not string.match(path,'^%.$') and lfs.isdir(path) then - table.insert(no_lsr_doctrees,path) - end - end -- does lsRfile exist? - end -- for path - local i = 0 - local n = table.getn(lsr_files) - return function () - i = i +1 - if i <= n then return lsr_files[i] end - end -end - --- protect - in patterns instead of trusting the user to do that -function deluaficate(oldpat) - local newpat - -- better use long strings here, no escaping of \ needed there. - newpat = string.gsub(oldpat,'([^\\])%-','%1%%%-') - newpat = string.gsub(newpat,'\\','') - return newpat -end --deluaficate - --- return files in the TEXDOCS tree whose full path matches against pattern -function pattern_search (pattern) - docfiles = {} -- should not be local (used in recurse_tree) - pattern = deluaficate(pattern) - -- populate docfiles list - for database in get_lsr_files() do - local texmf_tree = string.gsub(database,'ls%-R$','') - is_docline = false - local this_dir -- changed to each individual docdir - for line in io.lines(database) do - if string.match(line,'^./') then - -- a directory - this_dir = string.gsub(line,'^./',texmf_tree) - this_dir = string.gsub(this_dir,':$','/') - if string.match(line,'^./doc') then - -- the next file lines are in docdir "this_dir" - is_docline = true - else - is_docline = false - end -- docdir - elseif string.match(line,'^%s*$') then - -- empty line, do nothing - -- now we have only file lines left, are they a docline? - elseif is_docline then - local fullpath = this_dir .. line - if string.match(fullpath, pattern) then - if lfs.isfile(fullpath) then -- cannot know from ls-R - table.insert(docfiles,fullpath) - end - end - end -- line starting with ./ - end -- for line - end -- for database - for no_lsr_dir in list(no_lsr_doctrees) do - recurse_tree(no_lsr_dir, pattern) + table.insert(rel_docfiles, code_path (code, pathfile)) + end end - return docfiles end --- recursively explore a tree and put the file matching pattern in docfiles -function recurse_tree (path, pattern) +-- encodes the base path on two digits and concatenate with filename +-- see real_path() for decoding +function code_path (code, file) + local padding = (code > 9) and '' or '0' + return padding..code..':'..file +end + +-- scan a tree +function scan_tree (code, path, pattern, recurse) for file in lfs.dir(path) do - if file ~= "." and file ~= ".." then - local f = path..'/'..file - local attr = lfs.attributes (f) - if attr then -- else stale symlink - if attr.mode == "directory" then - recurse_tree (f, pattern) - else - if string.match (f, pattern) then - table.insert(docfiles,f) - end - end + if file ~= '.' and file ~= '..' then + local f = (path == '.') and file or path..'/'..file + if lfs.isdir(f) then + if recurse then scan_tree(code, f, pattern, recurse) end + else + process_file(file, f, code, pattern, true) end end end end +-- finds a root with ls-R above path and return it or nil +function lsr_root (path) + if not lfs.isdir (path) then return end + local root, shift = path, '' + if string.sub(root, -1) == '/' then root = string.sub(root, 1, -2) end + while string.find(root, '/', 1, true) do + if lfs.isfile(root..'/ls-R') then + return root, shift + end + local last_comp = string.match(root, '^.*/(.*)$') + -- /!\ cannot put last_comp in a regex: can contain special char + root = string.sub(root, 1, - (#last_comp + 2)) + shift = last_comp..'/'..shift + end +end --- filename and mixed search modes +-- merge two components of a path, taking care of empty components +function merge_path (a, b) + return ((a == '') or (b == '')) and a..b or a..'/'..b +end --- add a dot to ext except if it's empty -function dotted(ext) - if (ext == '') then - return ext - else - return '.'..ext +-- scan a ls-R file +function scan_lsr (code, shift, pattern) + local isdoc = false + local current_dir + local l = #shift + local lsr = assert(io.open('ls-R', 'r')) + local _ = lsr:read('*line') -- throw away first line (comment) + local maybe_dir = true -- next line may be a directory + while true do + local line = lsr:read('*line') + while line == '' do line, maybe_dir = lsr:read('*line'), true end + if line == nil then break end -- EOF + local dir_line = maybe_dir and string.match (line, '^%./(.*):$') + if dir_line then + maybe_dir = false -- next line may not be a dir + if string.sub (dir_line, 1, l) == shift then + isdoc = true + current_dir = string.sub (dir_line, l+1) + is_dir[code_path(code, current_dir)] = true + elseif isdoc then + break -- we're exiting the ./doc (or shift) dir, so it's over + end + elseif isdoc then + process_file (line, merge_path(current_dir, line), code, pattern) + end end + lsr:close() end --- simple search on filename using kpse -function filename_search (filename) - files = {} - for ext in list(config.ext_list) do - found = kpse.find_file(filename .. dotted(ext), - "TeX system documentation") - if found then table.insert(files, found) end +-- find dirfiles according to pattern +function populate_docfiles (pattern) + if not texdocs then get_texdocs() end + rel_docfiles, exact_docfiles = {}, {} -- global + is_dir = {} -- global; is_dir[path] = true iff path is a dir, see scan_lsr + local curr_dir = lfs.currentdir() + for code, docdir in ipairs (texdocs) do + root, shift = lsr_root (docdir) + if root and shift and do_recurse[code] then + assert(lfs.chdir(root)) + scan_lsr(code, shift, pattern) + elseif (not must_have_lsr[code]) and lfs.isdir(docdir) then + assert(lfs.chdir(docdir)) + scan_tree(code, '.', pattern, do_recurse[code]) + end end - return files + assert(lfs.chdir(curr_dir)) + exact_docfiles = rmdirs (exact_docfiles) + rel_docfiles = rmdirs (rel_docfiles) end --- do a filename search and try a full search if unsuccessfull -function mixed_search (filename, alternative) - results = filename_search (filename) - if not results[1] then - print ("texdoc info: No result with simple search, ".. - "trying full search mode.") - results = pattern_search (alternative) +-- END kpse-like + +-- like populate_docfiles, but rel replaces exact if exact is empty +function mixed_populate_docfiles (pattern) + populate_docfiles (pattern) + if not exact_docfiles[1] then + if not string.find (pattern, '/') then + err_print ("No exact match, trying full search mode.", "info") + end + exact_docfiles = rel_docfiles end - return results +end + +-- translate a path as given by populate_docfiles into a real path +-- should never be called before get_texdocs() +function real_path (fake) + local code, file = string.match (fake, '^(.-):(.*)$') + code = tonumber (code) + return win32_hook (texdocs[code]..'/'..file) +end + +-- now a special function that does nothing on Unix +if os.type == "windows" then + function win32_hook (path) + local res = string.gsub (path, '/', '\\') + return res -- get rid of gsub's 2nd arg + end +else + function win32_hook (path) + return path + end +end + +-- remove directories from the files list +function rmdirs (files) + local res = {} + for f in list (files) do + if not is_dir[f] then table.insert(res, f) end + end + return res +end + +-- for sty files, we obviously don't want to look in TEXDOCS... +-- and we don't need a list since those are not duplicated (ahem...) +function populate_docfiles_sty (styname) + exact_docfiles = { kpse.find_file (styname) } + rel_docfiles = {} end -- functions to set config values and aliases --------------------------------------------- --- set a value without overwriting if already set -function set_config_element (key, value) - if config[key] == nil then +-- set a value without overwriting if already set and +-- using to special types: *_list and *_switch +function set_config_element (key, value, file, line) + if config[key] == nil then -- must explicitly test for nil, not false if string.match(key, '_list$') then - -- this is actually a coma-separeted list of values + -- this is actually a coma-separated list of values local values = string.explode(value, ',') + local inverse = {} for i, j in ipairs(values) do values[i] = string.gsub(j, '%s*$', '') values[i] = string.gsub(j, '^%s*', '') + inverse[j] = i end config[key] = values + config[key..'_inv'] = inverse + config[key..'_max'] = #values + elseif string.find (key, '_switch$') then + if value == 'true' then + config[key] = true + elseif value == 'false' then + config[key] = false + else + config_warn (key, value, file, line) + end + elseif string.find (key, '_level$') then + local val = tonumber (value) + if val then + config[key] = val + else + config_warn (key, value, file, line) + end else config[key] = value end end end +-- a helper function for warning messages in the above +function config_warn (key, value, file, line) + local begin = 'illegal value '..value..' for key '..key + local ending = '. Skipping.' + if file and line then + err_print (begin..'\nin '..file..' line '..line..ending, 'warning') + else + err_print (begin..ending, 'warning') + end +end + + -- set a whole list, also whithout overwriting function set_config_list (conf) for key, value in pairs(conf) do @@ -244,71 +347,163 @@ function set_alias (key, value) end end +-- set config from the command line +-- Please make sure to update usage_msg accordingly +-- and set a default value in setup_config_from_defaults() if relevant. +function setup_config_from_cl () + while arg[1] and string.match(arg[1],'^%-') do + curr_arg = table.remove(arg,1) + if (curr_arg == '-h') or (curr_arg == '--help') then + print (usage_msg) + os.exit(0) + elseif (curr_arg == '-v') or (curr_arg == '--version') then + print (progname .. ' version: ' .. version ) + os.exit(0) + elseif (curr_arg == '-f') or (curr_arg == '--files') then + print_config_files () + os.exit(0) + elseif (curr_arg == '-w') or (curr_arg == '--view') then + set_config_element('mode', 'view') + elseif (curr_arg == '-m') or (curr_arg == '--mixed') then + set_config_element('mode', 'mixed') + elseif (curr_arg == '-l') or (curr_arg == '--list') then + set_config_element('mode', 'list') + elseif (curr_arg == '-s') or (curr_arg == '--search') then + set_config_element ('mode', 'search') + elseif (curr_arg == '-r') or (curr_arg == '--regex') then + set_config_element ('mode', 'regex') + elseif (curr_arg == '-I') or (curr_arg == '--nointeract') then + set_config_element('interact_switch', 'false') + elseif (curr_arg == '-i') or (curr_arg == '--interact') then + set_config_element('interact_switch', 'true') + elseif (curr_arg == '-A') or (curr_arg == '--noalias') then + set_config_element('alias_switch', 'false') + elseif (curr_arg == '-a') or (curr_arg == '--alias') then + set_config_element('alias_switch', 'true') + elseif string.match(curr_arg, '^%-n') then + set_config_element('noise_level', + string.gsub(curr_arg, '^%-n=?', '')) + elseif string.match(curr_arg, '^%-%-noise%-level') then + set_config_element('noise_level', + string.gsub(curr_arg, '^%-%-noise%-level=?', '')) + elseif string.match(curr_arg, '^%-e') then + set_config_element('ext_list', + string.gsub(curr_arg, '^%-e=?', '')) + elseif string.match(curr_arg, '^%-%-extensions') then + set_config_element('ext_list', + string.gsub(curr_arg, '^%-%-extensions=?', '')) + else + err_print ("unknow option: "..curr_arg, "error") + print (usage_msg) + os.exit(1) + end + end +end + +-- the default value af config.alias_switch depends on the mode as follows +function alias_from_mode (mode) + if (mode == 'view') or (mode == 'mixed') or (mode == 'list') then + return 'true' + else + return 'false' + end +end + -- set config from environment if available function setup_config_from_env () set_config_list { - viewer_pdf = os.getenv ("PDFVIEWER"), - viewer_ps = os.getenv ("PSVIEWER"), - viewer_dvi = os.getenv ("DVIVIEWER"), - viewer_html = os.getenv ("BROWSER"), - viewer_txt = os.getenv ("PAGER") + viewer_pdf = os.getenv ("PDFVIEWER_texdoc") + or os.getenv ("TEXDOCVIEW_pdf") or os.getenv ("TEXDOC_VIEWER_PDF") + or os.getenv ("PDFVIEWER"), + viewer_ps = os.getenv ("PSVIEWER_texdoc") + or os.getenv ("TEXDOCVIEW_ps") or os.getenv ("TEXDOC_VIEWER_PS") + or os.getenv ("PSVIEWER"), + viewer_dvi = os.getenv ("DVIVIEWER_texdoc") + or os.getenv ("TEXDOCVIEW_dvi") or os.getenv ("TEXDOC_VIEWER_DVI") + or os.getenv ("DVIVIEWER"), + viewer_html = os.getenv ("BROWSER_texdoc") + or os.getenv ("TEXDOCVIEW_html") or os.getenv ("TEXDOC_VIEWER_HTML") + or os.getenv ("BROWSER"), + viewer_txt = os.getenv ("PAGER_texdoc") + or os.getenv ("TEXDOCVIEW_txt") or os.getenv ("TEXDOC_VIEWER_TXT") + or os.getenv ("PAGER"), } end --- set config+aliases from a particular config file if it exists +-- warn about old envvar being in use +function complain_about_old_envvar () + for ext in list {'pdf', 'pds', 'dvi', 'html', 'txt'} do + for var in list + {"TEXDOCVIEW_"..ext, "TEXDOC_VIEWER_"..string.upper(ext) } do + if os.getenv (var) then + err_print ("Environment variable "..var.. + " deprecated. See the manual\n\tsection ?.?, ?.? for details.", + "warning") + end + end + end +end + +-- set config+aliases from a particular config file assumed to exist function read_config_file(configfile) - if (lfs.isfile(configfile)) then -- configfile exists - local cnf = assert(io.open(configfile, 'r')) - local lineno = 0 - while true do - local key, val - local line=cnf:read('*line') - lineno = lineno + 1 - if line == nil then break end -- EOF - line = string.gsub(line, '%s*#.*$', '') -- comments begin with # - line = string.gsub(line, '%s*$', '') -- remove trailing spaces - line = string.gsub(line, '^%s*', '') -- remove leading spaces - key, val=string.match(line, '^([%a%d_]+)%s*=%s*(.+)') - if key and val then - set_config_element(key, val) + local cnf = assert(io.open(configfile, 'r')) + local lineno = 0 + while true do + local key, val + local line=cnf:read('*line') + lineno = lineno + 1 + if line == nil then break end -- EOF + line = string.gsub(line, '%s*#.*$', '') -- comments begin with # + line = string.gsub(line, '%s*$', '') -- remove trailing spaces + line = string.gsub(line, '^%s*', '') -- remove leading spaces + key, val = string.match(line, '^([%a%d_]+)%s*=%s*(.+)') + if key and val then + set_config_element(key, val, configfile, lineno) + else + key, val = string.match(line, '^alias%s+([%a%d_-]+)%s*=%s*(.+)') + if key and val then + set_alias(key, val) else - key, val = string.match(line, '^alias%s+([%a%d_-]+)%s*=%s*(.+)') - if key and val then - set_alias(key, val) - else - if (not string.match (line, '^%s*$')) then - print ('texdoc warning: syntax error in '..configfile.. - ' at line '..lineno..'.') - end + if (not string.match (line, '^%s*$')) then + err_print ('syntax error in '..configfile.. + ' at line '..lineno..'.', 'warning') end end end - cnf:close() end + cnf:close() +end + +-- return a table with config file and if they exist +function get_config_files () + local platform = string.match (kpse.var_value ('SELFAUTOLOC'), '.*/(.*)$') + local TEXMFHOME = kpse.var_value ('TEXMFHOME') + local TEXMFLOCAL = kpse.var_value ('TEXMFLOCAL') + local TEXMFMAIN = kpse.var_value ('TEXMFMAIN') + local config_files = {} + return { + TEXMFHOME .. '/texdoc/texdoc-'..platform..'.cnf', + TEXMFHOME .. '/texdoc/texdoc.cnf', + TEXMFLOCAL .. '/texdoc/texdoc-'..platform..'.cnf', + TEXMFLOCAL .. '/texdoc/texdoc.cnf', + TEXMFMAIN .. '/texdoc/texdoc.cnf' + } end -- set config/aliases from all config files function setup_config_from_files () - local TEXMFHOME, TEXMFLOCAL, TEXMFMAIN - local platform, configfile, configfiles - local ext, command, default_viewer - -- - platform=string.match(kpse.var_value('SELFAUTOLOC'), '.*/(.*)$') - TEXMFHOME=kpse.var_value('TEXMFHOME') - TEXMFLOCAL=kpse.var_value('TEXMFLOCAL') - TEXMFMAIN=kpse.var_value('TEXMFMAIN') - -- - -- the following config files are read if they exist. - configfiles={ - TEXMFHOME ..'/texdoc/texdoc-'..platform..'.cnf', - TEXMFHOME ..'/texdoc/texdoc.cnf', - TEXMFLOCAL..'/texdoc/texdoc-'..platform..'.cnf', - TEXMFLOCAL..'/texdoc/texdoc.cnf', - TEXMFMAIN..'/texdoc/texdoc.cnf' - } - -- - for i, configfile in ipairs(configfiles) do -- process all config files - read_config_file(configfile) + for file in list (get_config_files ()) do + if lfs.isfile(file) then read_config_file (file) end + end +end + +-- now a special information function (see -f,--file option) +function print_config_files () + print "Configuration files are:" + for i, file in ipairs (get_config_files ()) do + local found = lfs.isfile(file) and "(active)" or "(not found)" + local home = (i==2) and "* " or "" -- home conffile is the 2nd + print (home..found, win32_hook(file)) end end @@ -339,19 +534,19 @@ function setup_config_from_defaults() -- probably Windows (or OS/2) -- which commands should we use for unzipping? set_config_list { - viewer_dvi = 'start', - viewer_html = 'start', - viewer_pdf = 'start', - viewer_ps = 'start', - viewer_txt = 'start', + viewer_dvi = 'start ""', + viewer_html = 'start ""', + viewer_pdf = 'start ""', + viewer_ps = 'start ""', + viewer_txt = 'start ""', } else -- since we don't support msdos, if os.type is not windows, it's unix if (os.name == 'macosx') then set_config_list { - viewer_dvi = '(open %s)', - viewer_html = '(open %s)', - viewer_pdf = '(open %s)', - viewer_ps = '(open %s)', + viewer_dvi = 'open', + viewer_html = 'open', + viewer_pdf = 'open', + viewer_ps = 'open', viewer_txt = 'less', } else @@ -396,12 +591,20 @@ function setup_config_from_defaults() } end end + -- then various stuff + set_config_list { + mode = 'view', + interact_switch = 'true', + noise_level = '3', + } + -- must be set after mode! + set_config_element ('alias_switch', alias_from_mode(config.mode)) -- now a particular case for config.ext_list and zip-related stuff -- Note: removed texdoc_formats/zip_formats, gives simpler & generic code if support_zipped then set_config_element('ext_list', 'pdf,pdf.gz,pdf.bz2, html,html.gz,html.bz2, txt,txt.gz,txt.bz2,'.. - 'dvi,dvi.gz,dvi.bz2, ps,ps.gz,ps.bz2') + 'dvi,dvi.gz,dvi.bz2, ps,ps.gz,ps.bz2, ,gz,bz2') set_config_list { unzip_gz = 'gzip -d -c ', unzip_bz2 = 'bzip -d -c ', @@ -409,7 +612,7 @@ function setup_config_from_defaults() rm_dir = 'rmdir' } else - set_config_element('ext_list', 'pdf, html, txt, dvi, ps') + set_config_element('ext_list', 'pdf, html, txt, dvi, ps, ') end end @@ -421,6 +624,7 @@ end -- may uncompress if support_zipped is set (giving the complete filename on the -- command line is unsupported for compressed files by the way) function how_to_view (filename) + filename = real_path(filename) -- TODO: if not filename then ... if support_zipped then ext = string.match(filename,'.*%.(.*)$') zipext = string.match(ext,'^.*%.(.*)') @@ -441,25 +645,19 @@ function how_to_view (filename) .. filename .. ';' .. config.rm_dir .. tmpdir end else - ext = string.match(filename,'.*%.(.*)$') viewer_replacement = filename - viewext = ext - if not viewext then - print ("texdoc warning: cannot determine file type for\n".. - filename..", assuming text.") + -- files without extension are assumed to be text + viewext = string.match(filename,'.*%.(.*)$') or 'txt' + if not config['viewer_'..viewext] then + err_print (": cannot determine type of file\n\t" + ..filename.."Assuming text. Set the `viewer_"..viewext.. + "' variable in texdoc.cnf to avoid this.", "warning") viewext = 'txt' - else if not config['viewer_'..viewext] then - print ("texdoc warning: no "..viewext.." viewer found, ".. - "using text viewer instead.\nYou can select you preffered".. - "with the viewer_"..viewext.." variable in texdoc.cnf.") - viewext = 'fallback' - if not config['viewer_'..viewext] then - print ("texdoc error: text viewer not found. ".. - "Skipping file "..filename..".") - end - end -- viewer for ext - end -- no ext + err_print ("text viewer not found. This ".. + "should not happen, sorry. Skipping\n\t"..filename, "error") + end + end -- viewer for ext end -- zipped or not return config['viewer_'..viewext], viewer_replacement end @@ -475,85 +673,83 @@ function try_viewing (view_command, viewer_replacement) else view_command = view_command..' "'..viewer_replacement..'"' end - if verbose then - print(view_command) - end + err_print(view_command, 'debug1') view_result = os.execute(view_command) if not view_result then - print("texdoc error: the following command failed\n\t" - .. view_command) + err_print ("the following command failed\n\t" + .. view_command, "error") end end return view_result end --- display the results of a search and let user choose -function print_ordered_byext (files_list) - for _, ext in ipairs (config.ext_list) do - if ext == '' then - ext_pattern = '/[^.]*$' - elseif ext == '*' then - ext_pattern = '' - else - ext_pattern = '%.'..ext..'$' - end - for file in list(files_list) do - if string.match (file, ext_pattern) then print (file) end - end - end -end - --- compare two files with the following rule: +-- compare two filenames with the following rule: -- 1. extensions are ordered as in ext_list first, -- 2. then filenames lexicograhpicaly. function file_order (a, b) local ext_a = string.match (a, '^.*%.(.*)$') local ext_b = string.match (b, '^.*%.(.*)$') - if ext_pos(ext_a) < ext_pos(ext_b) then + ext_pos_a = config.ext_list_inv[ext_a] or (config.ext_list_max+1) + ext_pos_b = config.ext_list_inv[ext_b] or (config.ext_list_max+1) + if ext_pos_a < ext_pos_b then return true - elseif ext_pos(ext_a) > ext_pos(ext_b) then + elseif ext_pos_a > ext_pos_b then return false else return (a < b) end end --- return the position of ext in ext_list, and greater value if not in ext_list --- magic inside: compute ext_reverse only once -function ext_pos (ext) - local ext_rev = {} - local max - for i, ext in ipairs (config.ext_list) do - ext_rev[ext] = i - max = i - end - ext_pos = function (e) - return ext_rev[e] or (max + 1) +-- display a table, sorted, numbered with given offset (0 by default), +-- with real path +function display_table (t, offset) + offset = offset or 0 + table.sort(t, file_order) + for i, val in ipairs (t) do + if config.interact_switch then + print (i+offset, real_path(val)) + else + print (real_path(val)) + end end - return ext_pos (ext) end --- print a list of files as a menu -function print_menu (files) - local n = #files - if n > 20 then - io.write (n, " files found. Display the complete list? (y/N) ") - local ans = io.read(1) - if not ((ans == 'y') or (ans == 'Y')) then return end - end - -- table.sort(results, file_order) - for i, file in ipairs (files) do - print (i, file) +-- print a list of files as a menu (with an optional complementary list) +function print_menu (files, comp) + comp = comp or {} + max_lines = tonumber (config.max_lines) or 20 + local f = #files + if config.interact_switch then + local n = f + #comp + if n > max_lines then + io.write (n, " results. Display them all? (y/N) ") + local ans = io.read('*line') + if not ((ans == 'y') or (ans == 'Y')) then return end + end end - io.write ("Please enter the number of the file to view, or 0 to exit: ") - local num = io.read('*number') - if num and files[num] then - print ("Viewing file '"..files[num].."'.") - elseif num ~= 0 then - print ("Incorrect input, skipping.") + display_table (files) + display_table (comp, f) + if config.interact_switch then + io.write ("Please enter the number of the file to view, ", + "anything else to skip: ") + local num = tonumber(io.read('*line')) + if num and (num <= f) and files[num] then + try_viewing (how_to_view (files[num])) + elseif num and comp[num-f] then + try_viewing (how_to_view (comp[num-f])) + end end end +-- error handling +----------------- + +-- exit codes (probably make sense only with a single argument) +-- 0 OK +-- 1 Usage +-- 2 No doc found for at least one arg +-- ? Should do something for viewer problems etc + -- apologize/complain if something went wrong function apologize (reason, name) if reason == 'notfound' then @@ -562,146 +758,132 @@ function apologize (reason, name) print (msg) -- to get rid of gsub's 2nd value else exit_code = 255 - print ('texdoc error: Oops, this should not happen'.. - ' (unknown error code). Sorry.') + err_print ('Oops, this should not happen'.. + ' (unknown error code). Sorry.', 'error') end end - --- END of function definitions: here starts the execution ---=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - --- exit codes (probably make sense only with a single argument) --- 0 OK --- 1 Usage --- 2 No doc found for at least one arg --- ? Should do something for viewer problems etc - --- must have at least one arg -if not arg[1] then - print (usage_msg) - os.exit(1) -end - --- options from command line ----------------------------- - --- there is one boolean switch: verbose --- and config options using the config table, which means the default comes last --- config options are: --- mode ('view'* or 'list' or 'search') --- enable_alias ('true'* or 'false' (string, not boolean)) --- ext_list via the -t option -verbose = false -config = {} -- everything is stored in this table ... -alias = {} -- ... except aliases -while table.maxn(arg) > 0 and string.match(arg[1],'^%-') do - curr_arg = table.remove(arg,1) - if (curr_arg == '-h') or (curr_arg == '--help') then +-- check that arg list is not empty +function assert_arg_not_empty () + if not arg[1] then print (usage_msg) - os.exit(0) - elseif (curr_arg == '-V') or (curr_arg == '--version') then - print (progname .. ' version: ' .. version ) - os.exit(0) - elseif (curr_arg == '-v') or (curr_arg == '--verbose') then - verbose = true - elseif (curr_arg == '-w') or (curr_arg == '--view') then - set_config_element('mode', 'view') - elseif (curr_arg == '-m') or (curr_arg == '--mixed') then - set_config_element('mode', 'mixed') - elseif (curr_arg == '-l') or (curr_arg == '--list') then - set_config_element('mode', 'list') - elseif (curr_arg == '-s') or (curr_arg == '--search') then - set_config_list { mode = 'search', enable_alias = 'false'} - elseif (curr_arg == '-A') or (curr_arg == '--alias') then - set_config_element('enable_alias', 'false') - elseif (curr_arg == '-a') or (curr_arg == '--noalias') then - set_config_element('enable_alias', 'true') - elseif string.match(curr_arg, '^-t') then - set_config_element('ext_list', string.gsub(curr_arg, '^-t=?', '')) - elseif string.match(curr_arg, '^--type') then - set_config_element('ext_list', string.gsub(curr_arg, '^--type=?', '')) - else - print ("texdoc error: unknow option: "..curr_arg) + os.exit(1) end end --- defaults using the config table (ext_list comes later) -set_config_list { - enable_alias = 'true', -- string, not boolean - mode = 'view', -} - --- must have at least one arg left after eating up the options -if not arg[1] then - print (usage_msg) - os.exit(1) +-- generic error display function (see the error_priority constant) +function err_print (msg, lvl) + -- be careful: maybe config.noise_level is not set yet + local noise_level = config.noise_level or 10000 + if err_priority[lvl] <= noise_level then + io.stderr:write ("texdoc "..lvl..": "..msg.."\n") + end end +-- END of function definitions: here starts the execution +--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + -- initialisations ------------------ -- initialize kpathsea kpse.set_program_name(arg[-1], "texdoc") --- config options from env, conf files or defaults +-- config options from command line, env, conf files or defaults +config = {} -- everything is stored in this table ... +alias = {} -- ... except aliases +assert_arg_not_empty () +setup_config_from_cl () +assert_arg_not_empty () setup_config_from_env () +complain_about_old_envvar () setup_config_from_files () setup_config_from_defaults () --- we want an empty string for ext at the beginning, so that it works to specify --- the complete filename (at least in list or view mode). Doesn't matter when --- there's one more empty string, but we can easily avoid two in a row --- TODO: should be dealt with another way -if (config.mode == 'view' or config.mode == 'list') then - if not (config.ext_list[1] == '') then - table.insert(config.ext_list,1,'') - end -end - -- the main loop over the args +------------------------------ + +-- initialising and saving a few values exit_code = 0 +no_regex = true +real_ext_list = config.ext_list +real_populate_docfiles = populate_docfiles +real_mixed_populate_docfiles = mixed_populate_docfiles +real_real_path = real_path + +-- the actual loop for docname in list (arg) do - original_docname = docname - if (alias[docname] and (config.enable_alias == 'true')) then - print ("texdoc info: "..docname.." aliased to "..alias[docname]) + -- inform the user which arg beeing treated if more than one was provided + if arg[2] then + print ("*** Results for: "..docname.." ***") + end + -- applying alias if relevant + if config.alias_switch and alias[docname] then + err_print (docname.." aliased to "..alias[docname], 'info') docname = alias[docname] end - local docfound = false - if (config.mode == 'search') then - results = pattern_search (docname) - if results[1] then - print_menu (results) + -- exceptions for arguments with extension given + if config.mode ~= 'regex' then + docname_base, docname_ext = string.match (docname, '^(.*)%.(.*)$') + if docname_ext == 'sty' then + err_print ("using special search mode for sty files", 'info') + populate_docfiles = populate_docfiles_sty + mixed_populate_docfiles = populate_docfiles_sty + real_path = function (arg) return arg end + elseif docname_ext then + config.ext_list = { docname_ext } + docname = docname_base + end + end + -- main "ifcase mode" construct + if (config.mode == 'regex') then + no_regex = false + populate_docfiles(docname) + if rel_docfiles[1] then + print_menu (rel_docfiles) + else + apologize ('notfound', docname) + end + elseif (config.mode == 'search') then + populate_docfiles(docname) + if exact_docfiles[1] or rel_docfiles[1] then + print_menu (exact_docfiles, rel_docfiles) else apologize ('notfound', docname) end elseif (config.mode == 'list') then - results = mixed_search (docname, original_docname) - if results[1] then - print_menu (results) + mixed_populate_docfiles (docname) + if exact_docfiles[1] then + print_menu (exact_docfiles) else apologize ('notfound', docname) end elseif (config.mode == 'view') then - results = mixed_search (docname, original_docname) - if results[1] then - try_viewing (how_to_view(results[1])) + mixed_populate_docfiles (docname) + if exact_docfiles[1] then + table.sort(exact_docfiles, file_order) + try_viewing (how_to_view(exact_docfiles[1])) else apologize ('notfound', docname) end elseif (config.mode == 'mixed') then - results = mixed_search (docname, original_docname) - if (not results[1]) then -- no results + mixed_populate_docfiles (docname) + if (not exact_docfiles[1]) then -- no results apologize ('notfound', docname) - elseif (not results[2]) then -- 1 result (faster than table.maxn) - local ok = try_viewing (how_to_view(results[1])) + elseif (not exact_docfiles[2]) then -- 1 result + local ok = try_viewing (how_to_view(exact_docfiles[1])) if not ok then apologize ('oops') end - else -- 2 or more results - print_menu (results) + else -- 2 or more results + print_menu (exact_docfiles) end - end -- if construct "case config.mode in" -end -- for docname in arg + end + -- restoring possibly diverted values + config.ext_list = real_ext_list + populate_docfiles = real_populate_docfiles + mixed_populate_docfiles = real_mixed_populate_docfiles + real_path = real_real_path +end os.exit(exit_code) @@ -710,4 +892,4 @@ os.exit(exit_code) -- tab-width: 4 -- indent-tabs-mode: nil -- End: --- vim: sw=4 ts=4 expandtab: +-- vim:sw=4 ts=4 expandtab: diff --git a/Build/source/texk/texlive/linked_scripts/tlmgr.pl b/Build/source/texk/texlive/linked_scripts/tlmgr.pl index 36e13b21e73..4eb2988885d 100755 --- a/Build/source/texk/texlive/linked_scripts/tlmgr.pl +++ b/Build/source/texk/texlive/linked_scripts/tlmgr.pl @@ -1,5 +1,5 @@ #!/usr/bin/env perl -# $Id: tlmgr.pl 9706 2008-07-22 18:30:02Z preining $ +# $Id: tlmgr.pl 10205 2008-08-09 08:10:20Z preining $ # # Copyright 2008 Norbert Preining # This file is licensed under the GNU General Public License version 2 @@ -9,8 +9,15 @@ # - ordering or collections removal (see below for details) # - (?) removal does not remove created format files from TEXMFSYSVAR # - other features: dependency check?, ...? - -my $svnrev = '$Revision: 9706 $'; +# - after install/update show the number of bytes transfered +# (email Rolf Niepraschk) +# - merge tlmgrgui into tlmgr to reduce re-loading of tlpdb again and again +# and reuse the install function +# - move the remove_package function into TLPDB.pm, so that the remove_package +# from TLPDB actually removes the files, too. Maybe some better names +# are necessary. + +my $svnrev = '$Revision: 10205 $'; $svnrev =~ m/: ([0-9]+) /; my $tlmgrrevision = $1; @@ -68,8 +75,15 @@ if (!defined($action) && $opt_gui) { $action = "gui"; } -if ($opt_version) { +if ($opt_version || (defined $action && $action eq "version")) { print "tlmgr revision $tlmgrrevision\n"; + if (open (REL_TL, "$Master/release-texlive.txt")) { + # print first and last lines, which have the TL version info. + my @rel_tl = ; + print $rel_tl[0]; + print $rel_tl[$#rel_tl]; + close (REL_TL); + } exit 0; } @@ -147,7 +161,7 @@ if ($action =~ m/^_include_tlpobj$/) { merge_into(\%ret, action_uninstall()); exit(0); } else { - die "Unknown action: $action"; + die "$0: unknown action: $action\n"; } @@ -262,8 +276,10 @@ sub remove_package { foreach my $d ($tlp->depends) { if ($d eq "$pkg.ARCH") { foreach my $a ($localtlpdb->available_architectures) { - merge_into(\%ret, - &remove_package("$pkg.$a", $localtlpdb, $force)); + if (defined($localtlpdb->get_package("$pkg.$a"))) { + merge_into(\%ret, + &remove_package("$pkg.$a", $localtlpdb, $force)); + } } } } @@ -523,7 +539,7 @@ sub action_restore { } print "Restoring $pkg, $rev from $opt_backupdir/${pkg}_r${rev}.tar.lzma\n"; if (!$opt_dry) { - init_local_db(); + init_local_db(1); # first remove the package, then reinstall it # this way we get rid of useless files # force the deinstallation since we will reinstall it @@ -544,7 +560,7 @@ sub action_restore { } sub action_backup { - init_local_db(); + init_local_db(1); my $opt_dry = 0; my $opt_all = 0; my $opt_backupdir; @@ -582,7 +598,7 @@ sub action_update { if ($opt_gui) { action_gui("update"); } - init_local_db(); + init_local_db(1); # initialize the TLMedia from $location my $opt_nodepends = 0; my $opt_dry = 0; @@ -609,6 +625,7 @@ sub action_update { printf "tlmgr update takes either a list of packages or --all\n"; } my $updater_started = 0; + my $nrupdated = 0; foreach my $pkg (@todo) { next if ($pkg =~ m/^00texlive/); my $tlp = $localtlpdb->get_package($pkg); @@ -624,6 +641,7 @@ sub action_update { } my $mediarev = $mediatlp->revision; if ($rev < $mediarev) { + $nrupdated++; if ($opt_list) { print "$pkg: local: $rev, source: $mediarev\n"; } elsif ($opt_dry) { @@ -722,6 +740,14 @@ EOF ); tlwarn("UPDATER has been created, please execute tlpkg\\installer\\updater.bat\n"); } + if (($nrupdated == 0) && ($tlmediasrc->media ne "NET") && $opt_all) { + # for all but net updates we warn if nothing is updated + tlwarn("\nYour installation is set up to look on the disk for updates.\n"); + tlwarn("If you want to install from the Internet for this one time only, run\n"); + tlwarn(" tlmgr -location $TeXLiveURL\n"); + tlwarn("\nIf you want to change the default for all future updates, run\n"); + tlwarn(" tlmgr option location $TeXLiveURL\n\n"); + } return(\%ret); } @@ -729,7 +755,7 @@ sub action_install { if ($opt_gui) { action_gui("install"); } - init_local_db(); + init_local_db(1); # initialize the TLMedia from $location my $opt_nodepends = 0; my $opt_dry = 0; @@ -850,7 +876,7 @@ sub action_arch { my $opt_dry = 0; Getopt::Long::Configure(qw(no_pass_through)); GetOptions("dry-run" => \$opt_dry) or pod2usage(2); - init_local_db(); + init_local_db(1); $what || ($what = "list"); if ($what =~ m/^list$/i) { # list the available architectures @@ -967,11 +993,19 @@ sub action_generate { } sub init_local_db { + my ($should_i_die) = @_; $localtlpdb = TeXLive::TLPDB->new ("root" => "$Master"); die("cannot find tlpdb!") unless (defined($localtlpdb)); # setup the programs, for win32 we need the shipped wget/lzma etc, so we # pass the location of these files to setup_programs. - setup_programs("$Master/tlpkg/installer", $localtlpdb->option_platform); + if (!setup_programs("$Master/tlpkg/installer", $localtlpdb->option_platform)) { + tlwarn("Couldn't set up the necessary programs.\nInstallation of packages is not supported.\nPlease report to texlive\@tug.org.\n"); + if (defined($should_i_die) && $should_i_die) { + exit 1; + } else { + tlwarn("Continuing anyway ...\n"); + } + } # let cmd line options override the settings in localtlpdb my $loc = $localtlpdb->option_location; if (defined($loc)) { @@ -1235,7 +1269,12 @@ tlmgr [I