diff options
Diffstat (limited to 'macros/jptex/latex/jlreq/luajfm2pl.lua')
-rw-r--r-- | macros/jptex/latex/jlreq/luajfm2pl.lua | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/macros/jptex/latex/jlreq/luajfm2pl.lua b/macros/jptex/latex/jlreq/luajfm2pl.lua new file mode 100644 index 0000000000..5aceea506d --- /dev/null +++ b/macros/jptex/latex/jlreq/luajfm2pl.lua @@ -0,0 +1,342 @@ +kpse.set_program_name("texlua","lualatex") + +no_jis_chars = {'⦅','〘','〖','«','〝','⦆','〙','〗','»','〟','‼','⁇','⁈','⁉','〳','〴','〵','〻','ゕ','ゖ','ㇰ','ㇱ','ㇲ','ㇳ','ㇴ','ㇵ','ㇶ','ㇷ','ㇸ','ㇹ','ㇺ','ㇻ','ㇼ','ㇽ','ㇾ','ㇿ','ㇷ゚','€','№','㏋','ℓ','㌃','㌍','㌔','㌘','㌢','㌣','㌦','㌧','㌫','㌶','㌻','㍉','㍊','㍍','㍑','㍗','㎎','㎏','㎜','㎝','㎞','㎡','㏄','ゔ','か゚','き゚','く゚','け゚','こ゚','ヷ','ヸ','ヹ','ヺ','カ゚','キ゚','ク゚','ケ゚','コ゚','セ゚','ツ゚','ト゚','゠','–'} + +if arg[1] == nil then + print('Usage: texlua luajfm2pl.lua [--noutf] <JFM for LuaTeX-ja> [<PL file name>]') + os.exit(0) +end + +local luajfm +if arg[1] ~= "--noutf" then + no_jis_chars = {} + luajfm = arg[1] + outputfile = arg[2] +else + luajfm = arg[2] + outputfile = arg[3] +end + +local jfmfile = kpse.find_file("jfm-" .. luajfm .. ".lua") +if jfmfile == nil then + print("JFM " .. luajfm .. " is not found") + os.exit(1) +end + +--. JFMロード +jfm = nil +luatexja = {} +luatexja.jfont = {} + +function luatexja.jfont.define_jfm(j) + jfm = j +end + +dofile(jfmfile) + +local fp = nil +if outputfile == nil then + fp = io.stdout +else + local msg + fp,msg = io.open(outputfile,"w") + if fp == nil then + print(msg) + os.exit(1) + end +end + + +--. 関数群 +local function merge_sort(list,from,to,comp) + local tmplist = {} + if to - from > 1 then + local mid = math.floor((to + from)/2) + merge_sort(list,from,mid,comp) + merge_sort(list,mid+1,to,comp) + local left = from + local right = mid + 1 + local i = 1 + while left <= mid or right <= to do + if left > mid then + tmplist[i] = list[right] + right = right + 1 + elseif right > to then + tmplist[i] = list[left] + left = left + 1 + elseif comp(list[right],list[left]) == true then + tmplist[i] = list[right] + right = right + 1 + else + tmplist[i] = list[left] + left = left + 1 + end + i = i + 1 + end + for j = from,to do + list[j] = tmplist[j - from + 1] + end + elseif to - from == 1 then + if comp(list[to],list[from]) then + list[to],list[from] = list[from],list[to] + end + end + return list +end + +function stable_sort(list,comp) + if comp == nil then comp = function(a,b) return a < b end end + return merge_sort(list,1,#list,comp) +end + +local function array_uniq(t) + local n = 1 + for i = 1,#t do + local newone = true + for j = 1,n - 1 do + if t[i] == t[j] then + newone = false + break + end + end + if newone == true then + t[n] = t[i] + n = n + 1 + end + end + local m = #t + for i = n,m do table.remove(t) end + return t +end + +local function exists(t,v) + for _,val in pairs(t) do + if v == val then return true end + end + return false +end + + +local function isempty(t) return next(t) == nil end +local function isemptyornil(t) return t == nil or isempty(t) end + +--. JFMの改変 +-- デフォルト値の設定 +for cls,val in pairs(jfm) do + if type(cls) == "number" then + if val.width == nil then jfm[cls].width = 1 end + if val.height == nil then + if jfm.dir == 'tate' then jfm[cls].height = 0.5 + else jfm[cls].height = 0.88 end + end + if val.depth == nil then + if jfm.dir == 'tate' then jfm[cls].depth = 0.5 + else jfm[cls].depth = 0.12 end + end + if val.italic == nil then jfm[cls].italic = 0 end + end +end + +-- charsを書き出す文字列に変換しておく. +local no_jis_chars_hash = {} +for _,c in ipairs(no_jis_chars) do no_jis_chars_hash[c] = true end + +alcharclass = nil +noxalcharclass = nil + +for class,val in pairs(jfm) do + if type(class) ~= "number" or class == 0 then goto continue end + local chars = {} + for _,c in ipairs(val.chars) do + local ac = nil + -- 'alchar'や'nox_alchar'が入っているクラスを記憶 + if c == 'alchar' then alcharclass = class + elseif c == 'nox_alchar' then noxalcharclass = class + elseif unicode.utf8.len(c) == 1 then ac = c + elseif unicode.utf8.len(c) == 2 then + local cs = {} + for _,cc in string.utfcharacters(c) do + table.insert(cs,cc) + end + if cs[2] == "*" then ac = cs[1] end + end + if no_jis_chars_hash[ac] ~= true then table.insert(chars,ac) end + end + chars = array_uniq(chars) + -- charsが空になった場合は消しておく + if class ~= alcharclass and class ~= noxalcharclass and isempty(chars) == true then + io.stderr:write("Class " .. class .. " has no char, so we omit it\n") + jfm[class] = nil + else jfm[class].chars = table.concat(chars," ") end + ::continue:: +end + + +if alcharclass == noxalcharclass then noxalcharclass = nil end +for _,class in ipairs({alcharclass,noxalcharclass}) do + if class ~= nil then + if jfm[class].chars == "" then + io.stderr:write("Class " .. class .. " has only Alchar, so we omit it\n") + jfm[class] = nil + end + end +end + + +-- 存在しないクラスに対するglue/kernは消す +for _,gluekern in ipairs({"glue","kern"}) do + for class,val in pairs(jfm) do + if type(class) == "number" and val[gluekern] ~= nil then + for target,_ in pairs(val[gluekern]) do + if jfm[target] == nil then + io.stderr:write("Class " .. tostring(target) .. " does not exist, the corresponding " .. gluekern .. " in Class " .. tostring(class) .. " is omitted\n") + jfm[class][gluekern][target] = nil + end + end + end + end +end + +-- glueやkernが同じ挙動であるか調べる +function isthesamespace(gluekern,clses,c1,c2) + return isthesamespace_before(gluekern,c1,c2) and isthesamespace_after(gluekern,clses,c1,c2) +end +-- c1,c2を前とするグルーが同じか. +function isthesamespace_before(gluekern,c1,c2) + -- 片方がnilの場合 + if jfm[c1][gluekern] == jfm[c2][gluekern] then return true end + if jfm[c1][gluekern] == nil or jfm[c2][gluekern] == nil then return false end + --この段階で両方tableなはず + local targetclses = {} -- c1とc2のglueやkernのunion + for c,_ in pairs(jfm[c1][gluekern]) do table.insert(targetclses,c) end + for c,_ in pairs(jfm[c2][gluekern]) do table.insert(targetclses,c) end + targetclses = array_uniq(targetclses) + for _,chk in ipairs(targetclses) do + if jfm[c1][gluekern][chk] == jfm[c2][gluekern][chk] then goto continue end + if jfm[c1][gluekern][chk] == nil or jfm[c2][gluekern][chk] == nil then return false end + if type(jfm[c1][gluekern][chk]) == "number" or type(jfm[c2][gluekern][chk]) == "number" then return false end + if jfm[c1][gluekern][chk][1] ~= jfm[c2][gluekern][chk][1] then return false end + if gluekern == "glue" then + if jfm[c1][gluekern][chk][2] ~= jfm[c2][gluekern][chk][2] or jfm[c1][gluekern][chk][3] ~= jfm[c2][gluekern][chk][3] then return false end + end + ::continue:: + end + return true +end + +function isthesamespace_after(gluekern,clses,c1,c2) + for _,c in pairs(clses) do + if jfm[c][gluekern] == nil then goto continue end + if jfm[c][gluekern][c1] == jfm[c][gluekern][c2] then goto continue end + if jfm[c][gluekern][c1] == nil or jfm[c][gluekern][c2] == nil then return false end + if type(jfm[c][gluekern][c1]) == "number" or type(jfm[c][gluekern][c2]) == "number" then return false end + if jfm[c][gluekern][c1][1] ~= jfm[c][gluekern][c2][1] then return false end + if kernglue == "glue" then + if jfm[c][gluekern][c1][2] ~= jfm[c][gluekern][c2][2] or jfm[c][gluekern][c1][3] ~= jfm[c][gluekern][c2][3] then return false end + end + ::continue:: + end + return true +end + +-- 同じ挙動を示すクラスをまとめる +local classes = {} +for k,_ in pairs(jfm) do if type(k) == "number" then table.insert(classes,k) end end +classes = stable_sort(classes) +for _,from in pairs(classes) do + for index,to in pairs(classes) do + if to <= from or to == 0 or from == 0 then goto continue end + if jfm[from].width ~= jfm[to].width or jfm[from].height ~= jfm[to].height or jfm[from].depth ~= jfm[to].depth or jfm[from].italic ~= jfm[to].italic then goto continue end + if isthesamespace("glue",classes,from,to) and isthesamespace("kern",classes,from,to) then + io.stderr:write("Class " .. tostring(to) .. " is merged to Class " .. tostring(from) .. "\n") + jfm[from].chars = jfm[from].chars .. " " .. jfm[to].chars + jfm[to] = nil + classes[index] = nil + for _,cls in pairs(classes) do + if jfm[cls].glue ~= nil then jfm[cls].glue[to] = nil end + if jfm[cls].kern ~= nil then jfm[cls].kern[to] = nil end + end + end + ::continue:: + end +end + +-- 番号を連続的にする. +-- classmaptable[JFM内クラス番号] = JPL内クラス番号 +classes = {} +for k,_ in pairs(jfm) do if type(k) == "number" then table.insert(classes,k) end end +classes = stable_sort(classes) +local classmaptable = {} +local jplclass = 1 +for _,class in ipairs(classes) do + if type(class) == "number" then + if class == 0 then classmaptable[class] = 0 + else + if class ~= jplclass then + io.stderr:write("Class " .. tostring(class) .. " is mapped to Class " .. tostring(jplclass) .. "\n") + end + classmaptable[class] = jplclass + jplclass = jplclass + 1 + end + end +end + + +fp:write("(COMMENT JPL file from jfm-" .. luajfm .. ".lua)\n") +fp:write("(CODINGSCHEME TEX KANJI TEXT)\n") +fp:write("(DIRECTION " .. string.upper(jfm.dir) .. ")\n") +-- fp:write("(DESIGNSIZE R 10.0)\n") +fp:write("(FONTDIMEN \n") +fp:write(" (SLANT R 0.0)\n") +fp:write(" (SPACE R " .. tostring(jfm.kanjiskip[1]) .. ")\n") +fp:write(" (STRETCH R " .. tostring(jfm.kanjiskip[2]) .. ")\n") +fp:write(" (SHRINK R " .. tostring(jfm.kanjiskip[3]) .. ")\n") +fp:write(" (XHEIGHT R " .. tostring(jfm.zh) .. ")\n") +fp:write(" (QUAD R " .. tostring(jfm.zw) .. ")\n") +fp:write(" (EXTRASPACE R " .. tostring(jfm.xkanjiskip[1]) .. ")\n") +-- 下二つはFONTDIMENの下で良いのかな? +fp:write(" (EXTRASTRETCH R " .. tostring(jfm.xkanjiskip[2]) .. ")\n") +fp:write(" (EXTRASHRINK R " .. tostring(jfm.xkanjiskip[3]) .. ")\n") +fp:write(")\n") + +classes = {} +for k,_ in pairs(jfm) do if type(k) == "number" then table.insert(classes,k) end end +classes = stable_sort(classes,function(a,b) return classmaptable[a] < classmaptable[b] end) + +for _,class in ipairs(classes) do + if class ~= 0 then + fp:write("(CHARSINTYPE D " .. tostring(classmaptable[class]) .. "\n " .. jfm[class].chars .. "\n)\n") + end + fp:write("(TYPE D " .. tostring(classmaptable[class]) .. "\n") + fp:write(" (CHARWD R " .. tostring(jfm[class].width) .. ")\n") + fp:write(" (CHARHT R " .. tostring(jfm[class].height) .. ")\n") + fp:write(" (CHARDP R " .. tostring(jfm[class].depth) .. ")\n") + fp:write(" (CHARIC R " .. tostring(jfm[class].italic) .. ")\n") + fp:write(")\n") + ::continue:: +end + +fp:write("(GLUEKERN\n") +for _,class in ipairs(classes) do + if (jfm[class].glue == nil or isempty(jfm[class].glue) == true) and (jfm[class].kern == nil or (type(jfm[class].kern) == "table" and isempty(jfm[class].kern) == true)) then goto continue end + fp:write(" (LABEL D " .. tostring(classmaptable[class]) .. ")\n") + if jfm[class].glue ~= nil then + for _,targetcls in ipairs(classes) do + if jfm[class].glue[targetcls] ~= nil then + fp:write(" (GLUE D " .. tostring(classmaptable[targetcls]) .. " R " .. tostring(jfm[class].glue[targetcls][1]) .. " R " .. tostring(jfm[class].glue[targetcls][2]) .. " R " .. tostring(jfm[class].glue[targetcls][3]) .. ")\n") + end + end + end + if jfm[class].kern ~= nil then + for _,targetcls in ipairs(classes) do + if jfm[class].kern[targetcls] ~= nil then + fp:write(" (KRN D " .. tostring(classmaptable[targetcls]) .. " R ") + if type(kernval) == "number" then fp:write(tostring(jfm[class],kern[targetcls]) .. ")\n") + else fp:write(tostring(jfm[class].kern[targetcls][1]) .. ")\n") end + end + end + end + fp:write(" (STOP)\n") + ::continue:: +end +fp:write(")\n") |