diff options
Diffstat (limited to 'support/xml2pmx')
-rwxr-xr-x | support/xml2pmx/MacOS/xml2pmx | bin | 139408 -> 139880 bytes | |||
-rw-r--r-- | support/xml2pmx/README | 9 | ||||
-rwxr-xr-x | support/xml2pmx/scripts/musixtex.lua | 634 |
3 files changed, 637 insertions, 6 deletions
diff --git a/support/xml2pmx/MacOS/xml2pmx b/support/xml2pmx/MacOS/xml2pmx Binary files differindex 18c1569b10..8d10563c20 100755 --- a/support/xml2pmx/MacOS/xml2pmx +++ b/support/xml2pmx/MacOS/xml2pmx diff --git a/support/xml2pmx/README b/support/xml2pmx/README index 538e03dced..905f2168d1 100644 --- a/support/xml2pmx/README +++ b/support/xml2pmx/README @@ -1,4 +1,4 @@ -xml2pmx, version 2021-01-23. +xml2pmx, version 2021-02-07. Summary: xml2pmx translates MusicXML into PMX notation. @@ -21,9 +21,6 @@ http://oberon.wikidot.com/oberon-linux-revival-olr Coverage of MusicXML by xml2pmx ******************************* -The following MusicXML features are detected and translated -to PMX: - The following MusicXML features are detected and translated to PMX: - up to 24 staves/voices and 600 bars @@ -57,8 +54,8 @@ relevant folders. To build and install an executable xml2pmx on a system with conventional development tools: - tar xvf xml2pmx-2021-01-23.tar.gz - cd xml2pmx-2021-01-23 + tar xvf xml2pmx-2021-02-07.tar.gz + cd xml2pmx-2021-02-07 ./configure make sudo make install diff --git a/support/xml2pmx/scripts/musixtex.lua b/support/xml2pmx/scripts/musixtex.lua new file mode 100755 index 0000000000..930e90d70f --- /dev/null +++ b/support/xml2pmx/scripts/musixtex.lua @@ -0,0 +1,634 @@ +#!/usr/bin/env texlua + +VERSION = "0.23a" + +--[[ + musixtex.lua: processes MusiXTeX files using xml2pmx and/or prepmx and/or pmxab + and/or autosp as pre-processors (and deletes intermediate files) + + (c) Copyright 2011-2020 Bob Tennent rdt@cs.queensu.ca + and Dirk Laurie dirk.laurie@gmail.com + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +--]] + +--[[ + + ChangeLog: + + version 0.23a 2020-08-14 RDT + pmxprep files now deleted by xml2pmx + + version 0.23 2020-05-21 RDT + added support for xml2pmx pre-preprocessing + + version 0.22 2020-03-20 RDT + add -X option + add -version, --version, -help, --help options + + version 0.21 2018-07-27 RDT + add -P option. + + version 0.20 2018-06-11 RDT + remove .mx1 file before tex processing + + version 0.19 2017-12-10 RDT + Allow non-standard extensions. + Add -M and -A options. + + version 0.18 2017-06-13 RDT + Allow autosp to generate .ltx files + + version 0.17a 2017-01-08 RDT + Added -D option. + Avoid writing or concatenating a nil value. + + version 0.16e 2016-03-02 DL + missing version information (caused by batchmode in 0.16c) fixed + + version 0.16d 2016-03-02 RDT + filename argument in autosp failure message fixed + + version 0.16c 2016-02-24 RDT + -interaction batchmode for -q + report_error reports only the first error + + version 0.16b 2016-02-20 DL + Improved help message as suggested by Bob Tennent. + + version 0.16a 2015-12-30 DL + Corrects bug in -g option reported by Christian Mondrup. + + version 0.16 2015-12-24 DL + Versions read from tempfile and written to musixtex.log. + + version 0.15 2015-12-03 DL + Option -q added, which redirects most screen output into + a temporary file. If an error occurs at the TeX stage, processing + halts immediately and the tail of the log file is sent to stderr. + + version 0.14 2015-12-01 DL + Writes `musixtex.log` and deletes other logfiles (except with -i) + Hierarchy of extensions emphasized in usage() and consistently + used elsewhere. + Unknown option-like arguments reported and ignored, not treated + as filenames + Warnings and error messages generated by musixtex.lua start with + respctively `!` and `!!`. + + version 0.13 2015-11-30 RDT + Process .mtx and .pmx files (suggested by Dirk Laurie) + exit_code is now an error count + Use pmxab exit code to distinguish between errors and warnings + + version 0.12 2015-11-28 RDT + Process .ltx files, with -l implied + + version 0.11 2015-07-16 RDT + Automatic autosp preprocessing. + + version 0.10 2015-04-23 RDT + Add -a option to preprocess using autosp + + version 0.9 2015-02-13 RDT + Add an additional latex pass to resolve cross-references. + Add -e0 option to dvips as given in musixdoc.tex + Add -x option to call makeindex + + version 0.8 2014-05-18 RDT + Add -g option + + version 0.7 2013-12-11 RDT + Add -F fmt option + + version 0.6 2012-09-14 RDT + Add -1 (one-pass [pdf][la]tex processing) option. + + version 0.5 2011-11-28 RDT + Add -i (retain intermediate files) option. + + version 0.4 2011-04-30 RDT + Allow multiple filenames (and options). + Add -f (default) and -l (latex) options. + + version 0.3 2011-04-25 RDT + Add -d (dvipdfm) and -s (stop at dvi) options. + + version 0.2 2011-04-21 RDT + Allow basename.tex as filename. + Add -p option for pdfetex processing. + Add standard -v -h options. +--]] +local orig_print = print + +function usage() + orig_print +[[ +Usage: [texlua] musixtex.lua { option | basename[ .xml | .mtx | .pmx | .aspc | .tex | .ltx] } ... + When no extension is given, extensions are tried in the above order + until a source file is found. Preprocessing goes xml-pmx-tex or mtx-pmx-tex or + aspc-tex, with the entry point determined by the extension. + The normal route after preprocessing goes tex-dvi-ps-pdf, but shorter + routes are also available, see the options. The default 3-pass processing route + for .tex files is etex-musixflx-etex. +Options: -v, --version version + -h, --help help + -l latex source + -p direct tex-pdf (pdftex etc) + -F fmt use fmt as the TeX processor + -d tex-dvi-pdf (using dvipdfm if -D not used) + -D dvixx use dvixx as the dvi processor + -P ps2pdfxx use ps2pdfxx as the Postscript processor + -c preprocess pmx file using pmxchords + -m stop at pmx + -M prepmxx use prepmxx as the mtx preprocessor + -A autospx use autospx as the aspc preprocessor + -X pmxabx use pmxabx as the pmx preprocessor + -L xmlx use xmlx as the xml preprocessor + -t stop at tex/mid + -s stop at dvi + -g stop at ps + -i retain intermediate and log files + -q quiet mode (redirect screen logs, write summary on musixtex.log) + -1 one-pass [pdf][la]tex processing + -x run makeindex + -f restore default processing +Four TeX engines are available via the -l and -p options. + etex default + latex -l + pdfetex -p + pdflatex -l -p +If the -F option is used, options -l and -p need to be set if the engine +name does not contain "latex" and "pdf" respectively. For example, the +above four engines can be replaced by: + -F "luatex --output-format=dvi" + -F "lualatex --output-format=dvi" + -F "luatex" -p + -F "lualatex" -p +]] +end + +function whoami () + print("This is musixtex.lua version ".. VERSION .. ".") +end + +function exists (filename, nolog) + local f = io.open(filename, "r") + if f then + f:close() + if not nolog then musixlog:write("Processing " .. filename,'\n' ) end + return true + else + return false + end +end + +-- System commands for the various programs are mostly +-- set to nil if the step is to be omitted, which can be +-- tested by a simple "if" statement. +-- Exceptions: +-- 'tex' is the command for processing a TeX file, but it is important +-- to know whether the user has explicitly specified an option that +-- affects this choice, in which case the automatic selection of the +-- command is restricted or disabled. +-- force_engine "use the command provided" +-- override records when 'l' and/or 'p' options are in effect +-- 'dvi' is the command for processing a DVI file, but there are two +-- reasons for not needing it and it is important for the automatic +-- selection of a TeX engine to know which is in effect. This is +-- possible by exploiting the the fact that Lua has two false values. +-- dvi == nil "do not produce a DVI file" (but maybe PDF) +-- dvi == false "do not process the DVI file" (but stop after TeX) +local dvips = "dvips -e0" +function defaults() + xml2pmx = "xml2pmx" + prepmx = "prepmx" + pmx = "pmxab" + autosp = "autosp" + tex = "etex" + musixflx = "musixflx" + dvi = dvips + ps2pdf = "ps2pdf" + cleanup = true -- clean up intermediate and log files + index = false + latex = false + force_engine = false -- indicates whether -F is specified + override = "" + passes = 2 + quiet = "" -- set by "-q" +end + +------------------------------------------------------------------------ + +if #arg == 0 then + whoami() + usage() + os.exit(0) +end + +-- Logging on `musixtex.log` everything that is printed, all os calls, +-- and warnings from other log files. + +musixlog = io.open("musixtex.log","w") +if not musixlog then + print"!! Can't open files for writing in current directory, aborting" + os.exit(1) +end + +------------------------------------------------------------------------ + +print = function(...) + orig_print(...) + musixlog:write(...,"\n") -- only the first argument gets written! +end + +local orig_remove = os.remove +remove = function(filename) + if exists(filename,"nolog") then + musixlog:write(" removing ",filename,"\n") + return orig_remove(filename) + end +end + +local orig_execute = os.execute +execute = function(command) + musixlog:write(" ",command,"\n") + return orig_execute(command .. quiet) +end + +function report_warnings(filename,pattern) + local log = io.open(filename) + if not log then + print("! No file "..filename) + return + end + for line in log:lines() do + if line:match(pattern) then + musixlog:write("! "..line,"\n") + end + end +end + +function report_error(filename) + local log = io.open(filename) + if not log then + print("! No file "..filename) + return + end + local trigger = false + for line in log:lines() do + if trigger and line:match"^!" then + -- report just the first error + break + end + trigger = trigger or line:match"^!" + if trigger then + io.stderr:write("! "..line,"\n") + end + end +end + +function process_option(this_arg) + if this_arg == "-v" or this_arg == "-version" or this_arg == "--version" then + os.exit(0) + elseif this_arg == "-h" or this_arg == "-help" or this_arg == "--help" then + usage() + os.exit(0) + elseif this_arg == "-l" then + latex = true + override = override .. 'l' + elseif this_arg == "-p" then + dvi = nil + override = override .. 'p' + elseif this_arg == "-d" then + dvi = "dvipdfm"; ps2pdf = nil + elseif this_arg == "-D" then + narg = narg+1 + dvi = arg[narg] + elseif this_arg == "-c" then + pmx = "pmxchords" + elseif this_arg == "-F" then + narg = narg+1 + tex = arg[narg] + force_engine = true + elseif this_arg == "-s" then + dvi = false; ps2pdf = nil; protect.dvi = true + elseif this_arg == "-g" then + dvi = dvips; ps2pdf = nil; protect.ps = true + elseif this_arg == "-i" then + cleanup = false + elseif this_arg == "-x" then + index = true + elseif this_arg == "-1" then + passes = 1 + elseif this_arg == "-f" then + defaults() + elseif this_arg == "-t" then + tex, dvi, ps2pdf = nil,nil,nil + protect.tex = true + elseif this_arg == "-m" then + pmx, tex, dvi, ps2pdf = nil,nil,nil,nil + protect.pmx = true + elseif this_arg == "-M" then + narg = narg+1 + prepmx = arg[narg] + elseif this_arg == "-A" then + narg = narg+1 + autosp = arg[narg] + elseif this_arg == "-L" then + narg = narg+1 + xml2pmx = arg[narg] + elseif this_arg == "-q" then + if not tempname then + tempname = tempname or os.tmpname() + print("Redirecting screen output to "..tempname) + end + if dvi == dvips then dvi = dvi .. " -q" end + quiet = " >> " .. tempname + elseif this_arg == "-P" then + narg = narg+1 + ps2pdf = arg[narg] + elseif this_arg == "-X" then + narg = narg+1 + pmx = arg[narg] + else + print("! Unknown option "..this_arg.." ignored") + end +end + +function find_file(this_arg) + basename, extension = this_arg:match"(.*)%.(.*)" + extensions = {["xml"] = true, ["mtx"] = true, ["pmx"] = true, ["aspc"] = true, ["tex"] = true, ["ltx"] = true} + if extensions[extension] then + return basename, extension + end + basename, extension = this_arg, null + for ext in ("xml,mtx,pmx,aspc,tex,ltx"):gmatch"[^,]+" do + if exists (basename .. "." .. ext) then + extension = ext + break + end + end + if extension == null then + print("!! No file " .. basename .. ".[xml|mtx|pmx|aspc|tex|ltx]") + exit_code = exit_code+1 + return + end + return basename, extension +end + +function preprocess(basename,extension) + if not (basename and extension) then return end + if extension == "xml" then + if execute(xml2pmx .. " " .. basename .. ".xml" .. " " .. basename .. ".pmx" ) == 0 then + extension = "pmx" + else + print ("!! xml2pmx preprocessing of " .. basename .. ".xml fails.") + return + end + elseif extension == "mtx" then + if execute(prepmx .. " " .. basename ) == 0 then + extension = "pmx" + else + print ("!! prepmx preprocessing of " .. basename .. ".mtx fails.") + return + end + end + if extension == "pmx" then + local OK = true + if pmx then + local code = execute(pmx .. " " .. basename) + local pmxaerr = io.open("pmxaerr.dat", "r") + if (not pmxaerr) then + OK = false + print("!! No pmx log file.") + else + extension = "tex" + local linebuf = pmxaerr:read() + local err = tonumber(linebuf) + if (code == 0) then + if err ~=0 then + print ("! pmx produced a warning on line "..err.. + " of "..basename..".pmx") + end + else + OK = false + print ("!! pmx processing of " .. basename .. ".pmx fails.") + end + pmxaerr:close() + end + end + if not OK then + exit_code = exit_code+1 + return + end + end + if extension == "aspc" then + if execute (autosp .. " " .. basename .. ".aspc" ) == 0 then + if exists ( basename .. ".ltx") + then extension = "ltx" + else extension = "tex" + end + else + print ("!! autosp preprocessing of " .. basename .. ".aspc fails.") + exit_code = exit_code+1 + return + end + end + return extension +end + +function tex_process(tex,basename,extension) + if not (extension == "tex" or extension == "ltx") or not tex then return end + remove(basename .. ".mx1") + remove(basename .. ".mx2") + local filename = basename .. "." ..extension +-- .ltx extension re-selects engine only for the current file, and only +-- if default processing is plain TeX + local latex = latex + if extension == "ltx" then + if not force_engine and not latex then + if dvi then tex = "latex" else tex = "pdflatex" end + end + latex = true + end + if quiet ~= "" then + tex = tex .. " -interaction batchmode" + end + local OK = (execute(tex .. " " .. filename) == 0) + if passes ~= 1 then + OK = OK and (execute(musixflx .. " " .. basename) == 0) + and (execute(tex .. " " .. filename) == 0) + if latex and index then + OK = OK and (execute("makeindex -q " .. basename) == 0) + and (execute(tex .. " " .. filename) == 0) + if exists (basename .. ".toc","nolog") then + -- an extra line for the index will have been added + OK = OK and (execute(tex .. " " .. filename) == 0) + -- there is a tiny possibility that the extra line for the index + -- has changed the pagination. If you feel this should not be + -- ignored, here are the possibilities: + -- a. Do an extra TeX pass regardless. + -- b. Provide a user option -4 to force the extra pass. + -- c. Compare aux files to find out. + end + end + end + if (quiet ~= "") and not OK then + report_error(basename..".log") + end + if OK and latex then + report_warnings(basename..".log","LaTeX.*Warning") + end + if dvi then OK = OK and (execute(dvi .. " " .. basename) == 0) end + if dvi and ps2pdf then + OK = OK and (execute(ps2pdf .. " " .. basename .. ".ps") == 0) + if OK then + print(basename .. ".pdf generated by " .. ps2pdf .. ".") + end + end + if not OK then + print("!! Processing of " .. filename .. " fails.\n") + exit_code = exit_code+1 + end +end + +---- Report version information on musixtex.log + +-- File names and message signatures to be looked for in a TeX log file. +logtargets = { +mtxtex = {"mtx%.tex","mtxTeX"}, +mtxlatex = {"mtxlatex%.sty","mtxLaTeX"}, +pmxtex = {"pmx%.tex","PMX"}, +musixtex = {"musixtex%.tex","MusiXTeX"}, +musixltx = {"musixltx%.tex","MusiXLaTeX"}, +musixlyr = {"musixlyr%.tex","MusiXLYR"} +} + +-- Signatures of messages displayed on standard output by programs +capturetargets = { +MTx = "This is (M%-Tx.->)", +PMX = "This is (PMX[^\n]+)", +pdftex = "This is (pdfTeX[^\n]+)", +musixflx = "Musixflx%S+", +autosp = "This is autosp.*$", +index = "autosp,MTx,PMX,musixflx,pdftex" +} + +function report_texfiles(logname) + local log = logname and io.open(logname) + if not log then return end + local lines = + {"--- TeX files actually included according to "..logname.." ---"} + log = log:read"*a" +-- The following pattern matches filenames input by TeX, even if +-- interrupted by a line break. It may include the first word of +-- an \immediate\write10 message emitted by the file. + for pos,filename in log:gmatch"%(()(%.?[/]%a[%-/%.%w\n]+)" do + local hit + repeat + local oldfilename = filename + filename = oldfilename:match"[^\n]+" -- up to next line break + hit = io.open(filename) -- success if the file exists + if hit then break end + filename = oldfilename:gsub("\n","",1) -- remove line break + until filename==oldfilename + if hit then + for target,sig in pairs(logtargets) do + if filename:match(sig[1]) then + local i,j = log:find(sig[2].."[^\n]+",pos) + if j then lines[#lines+1] = filename.."\n "..log:sub(i,j) end + end + end + end + end + return table.concat(lines,'\n').."\n" +end + +function report_versions(tempname) + if not tempname then return end -- only available with -q + local logs = io.open(tempname) + if not logs then + musixlog:write ("No version information: could not open "..tempname) + return + end + local versions = {} + musixlog:write("--- Programs actually executed according to "..tempname.." ---\n") + for line in logs:lines() do + for target in capturetargets.index:gmatch"[^,]+" do + if not versions[target] then + local found = line:match(capturetargets[target]) + if found then + versions[target] = found + musixlog:write(found,"\n") + end + end + end + end + logs:close() + return +end + +------------------------------------------------------------------------ + +whoami() + +defaults() + +exit_code = 0 +narg = 1 +protect = {} -- extensions not to be deleted, even if cleanup requested + +repeat + this_arg = arg[narg] + if this_arg:match"^%-" then process_option(this_arg) + else + basename, extension = find_file(this_arg) -- nil,nil if not found + if tex then -- tex output enabled, now select engine + if tex:match"pdf" then dvi = nil end + if not dvi then ps2pdf = nil end + -- .ltx extension will be taken into account later, in `process` + -- deduce tex/latex from current engine name if -l is not specified + if not override:match"l" then latex = tex:match"latex" end + if not force_engine then -- select appropriate default engine + if latex then + if dvi==nil then tex = "pdflatex" else tex = "latex" end + else + if dvi==nil then tex = "pdfetex" else tex = "etex" end + end + end + end + extension = preprocess(basename, extension) + tex_process(tex,basename,extension) + if basename and io.open(basename..".log") then -- to be printed later + versions = report_texfiles(basename..".log") + end + if basename and cleanup then + remove("pmxaerr.dat") + for ext in ("mx1,mx2,dvi,ps,idx,log,ilg,pml"):gmatch"[^,]+" do + if not protect[ext] then remove(basename.."."..ext) + end + end + end + protect = {} + end + narg = narg+1 +until narg > #arg + +if versions then musixlog:write(versions) end +report_versions(tempname) +musixlog:close() +os.exit( exit_code ) |