-- aliases for protected environments local assert, io_open = assert, io.open -- load the ltn12 module local ltn12 = require("ltn12") -- No more global accesses after this point if _VERSION == "Lua 5.2" then _ENV = nil end -- copy a file copy_file = function(path_src, path_dst) ltn12.pump.all( ltn12.source.file(assert(io_open(path_src, "rb"))), ltn12.sink.file(assert(io_open(path_dst, "wb"))) ) end openFile = function(file) f = io.open(file, "r") filecontent = f:read("*all") local beginDocPosition = filecontent:find('\\begin{document}') if not beginDocPosition then tex.sprint( [[\begingroup\ExplSyntaxOn \msg_fatal:nnn { stripsemantex } { begin_document_not_found } { ]] .. file .. [[ } \endgroup]] ) return end precontent = filecontent:sub(1,beginDocPosition-1) content = filecontent:sub(beginDocPosition,-1) f:close() end closeFile = function(file) f = io.open(file, "w") f:write(precontent .. content) f:close() end removeStricttexFormatting = function(str) -- We do this in case the package "stricttex" was used str = str:gsub('numberZERO','0') str = str:gsub('numberONE','1') str = str:gsub('numberTWO','2') str = str:gsub('numberTHREE','3') str = str:gsub('numberFOUR','4') str = str:gsub('numberFIVE','5') str = str:gsub('numberSIX','6') str = str:gsub('numberSEVEN','7') str = str:gsub('numberEIGHT','8') str = str:gsub('numberNINE','9') str = str:gsub('symbolPRIME','\'') return str end addIDsToRegisters = function(str) str = removeStricttexFormatting(str) content = content:gsub('\\' .. str .. '([^%a])' ,'\\SemantexID{}\\' .. str .. '%1') -- '%f[^%a]' does not work here, as it will not react if the last character of str is a number, -- which stricttex allows. -- Because of this choice, there will be an issue if you use stricttex and let -- \ by a SemanTeX command and \' be a non-SemanTeX command. -- So simply *don't do that*. end removeSuperfluousIDs = function() local p = content:find('([^\\]%%[^\n]-)\\SemantexID{}([^\n]-\n)') while p do content = content:gsub('([^\\]%%[^\n]-)\\SemantexID{}([^\n]-\n)','%1%2') p = content:find('([^\\]%%[^\n]-)\\SemantexID{}([^\n]-\n)') end content = content:gsub('parent(%s*)=(%s*)\\SemantexID{}','parent%1=%2') content = content:gsub('class(%s*)=(%s*)\\SemantexID{}','class%1=%2') content = content:gsub('clone(%s*)=(%s*)\\SemantexID{}','clone%1=%2') content = content:gsub('copy(%s*)=(%s*)\\SemantexID{}','copy%1=%2') content = content:gsub('\\New(%w+)Class(%s*{?)\\SemantexID{}','\\New%1Class%2') content = content:gsub('\\NewObject(%s*{?%s*)\\SemantexID{}(\\%w+%s*}?%s*{?%s*)\\SemantexID{}', '\\NewObject%1%2') content = content:gsub('\\SetupClass(%s*{?%s*)\\SemantexID{}', '\\SetupClass%1') content = content:gsub('\\SetupObject(%s*{?%s*)\\SemantexID{}', '\\SetupObject%1') end addNumbersToIDs = function() local n = 0 local p,q = string.find(content,'\\SemantexID{}') while q do n = n + 1 content = content:sub(1,q-1) .. n .. content:sub(q,-1) p, q = string.find(content,'\\SemantexID{}') end end semantexIDluacommand = function(id, source, output) local p, q = string.find(content, '\\SemantexID{' .. id .. '}') while p do content = content:sub(1,p-1) .. content:sub(q+1,-1) source = source:gsub('%s+', '') -- We do this in case the package "stricttex" was used source = removeStricttexFormatting(source) -- This is because #1's in the code becomes ##1 -- in the .semtex file. source = source:gsub('#(%d)', '%1') local length = source:len() local i = 1 local s while i <= length do s = content:sub(p,p) if s == source:sub(i,i) then content = content:sub(1 , p-1) .. content:sub(p+1, -1) i = i + 1 elseif s:match('%s') then content = content:sub(1, p-1) .. content:sub(p+1, -1) elseif s == '%' then content = content:sub(1 , p-1) .. content:sub(p,-1):gsub('%%.-\n','',1) elseif s == '{' then -- In this case, we remove the corresponding right brace, -- once we find it local netto = 1 -- The current brace group level local q = 0 -- The position we have moved forward so far while netto > 0 do q = q + 1 local e = content:sub(p+q,p+q) if e == '}' then netto = netto - 1 elseif e == '{' then netto = netto + 1 elseif e == '\\' then q = q + 1 elseif e == '%' then content = content:sub(1, p+q-1) .. content:sub(p+q,-1):gsub('%%.-\n','',1) q = q - 1 end end content = content:sub(1,p-1) .. content:sub(p+1,p+q-1) .. content:sub(p+q+1,-1) elseif s == '<' and content:sub(p+1,p+2) == '[>' then content = content:sub(1,p-1) .. content:sub(p+3,-1) i = i + 1 elseif s == '<' and content:sub(p+1,p+2) == ']>' then content = content:sub(1,p-1) .. content:sub(p+3,-1) i = i + 1 elseif source:sub(i,i) == '{' then -- In this case, we remove the corresponding right brace, -- once we find it local netto = 1 -- The current brace group level local q = 0 -- The position we have moved forward so far while netto > 0 do q = q + 1 local e = source:sub(i+q,i+q) if e == '}' then netto = netto - 1 elseif e == '{' then netto = netto + 1 elseif e == '\\' then q = q + 1 -- there is no chance that the source contains an unescaped %, so we do not -- check for this end end source = source:sub(1,i-1) .. source:sub(i+1,i+q-1) .. source:sub(i+q+1,-1) length = source:len() else tex.sprint( [[\begingroup\ExplSyntaxOn \msg_fatal:nnnn { stripsemantex } { source_not_expected } { ]] .. source:sub(i,i) .. [[ } { ]] .. s .. [[ } \endgroup]] ) break end end output = output:gsub('%s*\\sp {', '^{') output = output:gsub('%s*\\sb {', '_{') output = output:gsub('\\mathopen \\big ', '\\bigl') output = output:gsub('\\mathclose \\big ', '\\bigr') output = output:gsub('\\mathopen \\Big ', '\\Bigl') output = output:gsub('\\mathclose \\Big ', '\\Bigr') output = output:gsub('\\mathopen \\bigg ', '\\biggl') output = output:gsub('\\mathclose \\bigg ', '\\biggr') output = output:gsub('\\mathopen \\Bigg ', '\\Biggl') output = output:gsub('\\mathclose \\Bigg ', '\\Biggr') output = output:gsub('\\mathopen %(', '(') output = output:gsub('\\mathclose %)', ')') output = output:gsub('\\mathopen %[', '[') output = output:gsub('\\mathclose %]', ']') output = output:gsub('\\mathopen \\{', '\\{') output = output:gsub('\\mathclose \\}', '\\}') output = output:gsub('\\mathopen \\lbrace', '\\lbrace') output = output:gsub('\\mathclose \\rbrace', '\\rbrace') output = output:gsub('\\mathopen \\lbrack', '\\lbrack') output = output:gsub('\\mathclose \\rbrack', '\\rbrack') output = output:gsub('\\mathopen \\langle', '\\langle') output = output:gsub('\\mathclose \\rangle', '\\rangle') output = output:gsub('\\mathopen \\lvert', '\\lvert') output = output:gsub('\\mathclose \\rvert', '\\rvert') output = output:gsub('\\mathopen \\vert', '\\lvert') output = output:gsub('\\mathclose \\vert', '\\rvert') output = output:gsub('\\mathopen \\lVert', '\\lVert') output = output:gsub('\\mathclose \\rVert', '\\rVert') output = output:gsub('\\mathopen \\Vert', '\\lVert') output = output:gsub('\\mathclose \\Vert', '\\rVert') output = output:gsub('%^{\\prime }', '\'') output = output:gsub('%^{\\prime \\prime }', '\'\'') output = output:gsub('%^{\\prime \\prime \\prime }', '\'\'\'') output = output:gsub('%^{\\prime \\prime \\prime \\prime }', '\'\'\'\'') output = output:gsub('%^{\\prime \\prime \\prime \\prime \\prime }', '\'\'\'\'\'') output = output:gsub('%s+%f[{}%[%]%(%)%$,]','') output = output:gsub('([}%]%)])%f[\\%w%+%-%(%[=]', '%1 ') output = output:gsub(',',', ') output = output:gsub('%s+$', '') -- We now check whether the string we add will follow right -- after a control sequence, causing it to be interpreted -- as part of that control sequence. -- Because we want to allow the user to use stricttex, we -- check for alphanumerical control sequences rather than -- just alphabetic ones. This could add spaces that -- the user might not have intended, but it's a minor issue. if output:sub(1,1):match('%w') and content:sub(1, p-1):match('\\%w+$') then content = content:sub(1,p-1) .. ' ' .. output .. content:sub(p,-1) else content = content:sub(1,p-1) .. output .. content:sub(p,-1) end p, q = string.find(content, '\\SemantexID{' .. id .. '}') end end stripRemainingSemantexIDs = function() content = content:gsub('\\SemantexID{%d+}', '') end removeParenthesisCommands = function() content = content:gsub('\\SemantexMathOpen \\bigg%s?', '\\biggl') content = content:gsub('\\SemantexMathClose \\bigg%s?', '\\biggr') content = content:gsub('\\SemantexMathOpen \\Bigg%s?', '\\Biggl') content = content:gsub('\\SemantexMathClose \\Bigg%s?', '\\Biggr') content = content:gsub('\\SemantexMathOpen \\big%s?', '\\bigl') content = content:gsub('\\SemantexMathClose \\big%s?', '\\bigr') content = content:gsub('\\SemantexMathOpen \\Big%s?', '\\Bigl') content = content:gsub('\\SemantexMathClose \\Big%s?', '\\Bigr') content = content:gsub('\\SemantexMathOpen{} %(', '(') content = content:gsub('%s*\\SemantexMathClose{}%)', ')') content = content:gsub('\\SemantexMathOpen{} %[', '[') content = content:gsub('%s*\\SemantexMathClose{}%]', ']') content = content:gsub('\\SemantexMathOpen{} \\{', '\\{') content = content:gsub('%s*\\SemantexMathClose{} \\}', '\\}') content = content:gsub('\\SemantexMathOpen{} \\lbrace', '\\lbrace') content = content:gsub('\\SemantexMathClose{} \\rbrace', '\\rbrace') content = content:gsub('\\SemantexMathOpen{} \\lbrack', '\\rbrack') content = content:gsub('\\SemantexMathClose{} \\rbrack', '\\rbrack') content = content:gsub('\\SemantexMathOpen{} \\langle', '\\langle') content = content:gsub('\\SemantexMathClose{} \\rangle', '\\rangle') content = content:gsub('\\SemantexMathOpen{} \\lvert', '\\lvert') content = content:gsub('\\SemantexMathClose{} \\rvert', '\\rvert') content = content:gsub('\\SemantexMathOpen{} \\vert', '\\lvert') content = content:gsub('\\SemantexMathClose{} \\vert', '\\rvert') content = content:gsub('\\SemantexMathOpen{} \\lVert', '\\lVert') content = content:gsub('\\SemantexMathClose{} \\rVert', '\\rVert') content = content:gsub('\\SemantexMathOpen{} \\Vert', '\\lVert') content = content:gsub('\\SemantexMathClose{} \\Vert', '\\rVert') content = content:gsub('\\SemantexMathOpen{} .%s?', '') content = content:gsub('\\SemantexMathClose{} .%s?', '') content = content:gsub('\\SemantexMathOpen{}', '\\mathopen ') content = content:gsub('\\SemantexMathClose{}', '\\mathclose ') content = content:gsub('\\SemantexMathOpenAuto%s?', '\\SemantexLeft') content = content:gsub('\\SemantexMathCloseAuto%s?', '\\SemantexRight') content = content:gsub('\\SemantexMathOpenNoPar%s?', '') content = content:gsub('\\SemantexMathCloseNoPar%s?', '') content = content:gsub('\\SemantexMathOpen%s?', '\\mathopen') content = content:gsub('\\SemantexMathClose%s?', '\\mathclose') end stripComments = function() content = content:gsub('\\%%', '\\StripSemantexEscapedPercent') content = content:gsub('(\\%w+)%%.-\n%s*', '%1 ') content = content:gsub('%%.-\n%s*', '') content = content:gsub('\\StripSemantexEscapedPercent', '\\%%') end addSemtexPackageToFile = function() content = [[% The following was added by "stripsemantex": \usepackage{semtex,leftindex,graphicx} \providecommand\SemantexLeft{% \mathopen{}\mathclose\bgroup\left } \providecommand\SemantexRight{% \aftergroup\egroup\right } \makeatletter \DeclareRobustCommand\SemantexBullet{% \mathord{\mathpalette\SemantexBullet@{0.5}}% } \newcommand\SemantexBullet@[2]{% \vcenter{\hbox{\scalebox{#2}{$\m@th#1\bullet$}}}% } \DeclareRobustCommand\SemantexDoubleBullet{\SemantexBullet \SemantexBullet} \makeatother ]] .. content end