Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
--%%%%
--%
--% vtfontlib.lua - functions for dealing with VT fonts
--% Edrx, 2004jan10 (for Lua5)
--%
--%%%%

--% Our types:
--% rawarr:  an array of raw char images, each padded to 32 bytes.
--% rawfont: a string of nchars*height bytes.
--% font:    an array with entries nchars, height, 0..nchars-1 (w/len 32 each).
--% psf:     four magic bytes followed by a rawfont.
--% gridstr: a user-friendly 2D representation, like demo_bigstr.
--% vcsa:    nrows,ncols,crsr_x,crsr_y,nrows*ncols*(char,attr)
--%
--% The conversions (modulo extra info like height and nchars):
--% psffile <-> psf <-> rawfont <-> font <-> gridstr
--%     rawfontfile <-> rawfont
--%         isofont <-> pcfont
--%  pixels <-> byte   bytes <-> hex
--%
--% Here's how to do some of the conversions:
--% psffile -> psf                    readfile(fname)
--% psffile <- psf                    writefile(fname, psf)
--%            psf -> font            psftofont(psf)
--%            psf <- font            fonttopsf(font)
--%                   font -> gridstr fonttogridstr(font, 0, font.nchars-1)
--%                   font <- gridstr gridstrtofont(bigstr, nchars, height)
--%
--% rawfontfile -> rawfont            readfile(fname)
--% rawfontfile <- rawfont            writefile(fname, rawfont)
--%                rawfont -> font    rawfonttofont(rawfont, nchars, height)
--%                rawfont <- font    fonttorawfont(font, font.height)
--%
--% pixels -> byte                    pixelstobyte(pixels)
--% pixels <- byte                    bytetopixels(byte)
--%           bytes -> hex            bytestohex(bytes)
--%           bytes <- hex            hextobytes(hex)

--% "vcsa" corresponds to the contents of a "/dev/vcsann" in Linux,
--% and is used for taking screenshots.

--% «.tools_and_samples» (to "tools_and_samples")
--%  «.demo_bigstr»	(to "demo_bigstr")
--% «.psf_stuff»	(to "psf_stuff")
--%   «.psftofont»	(to "psftofont")
--%   «.fonttopsf»	(to "fonttopsf")
--% «.gridstring_stuff»	(to "gridstring_stuff")
--% «.bigstr_stuff»	(to "bigstr_stuff")
--%   «.bigstrtorawarr»	(to "bigstrtorawarr")
--%   «.bigstrtofont»	(to "bigstrtofont")
--%   «.fonttobigstr»	(to "fonttobigstr")
--% «.other_conversions» (to "other_conversions")
--%   «.rawfonttofont»	(to "rawfonttofont")
--%   «.fonttorawfont»	(to "fonttorawfont")
--%   «.vcsatounix»	(to "vcsatounix")

--% «.explode»		(to "explode")
--% «.split_clines»	(to "split_clines")
--% «.changefont»	(to "changefont")
--% «.makecomposes»	(to "makecomposes")
--% «.trfont»		(to "trfont")
--% «.setfont»		(to "setfont")
--% «.e_scripts»	(to "e_scripts")
--% «.vcsatoBIGstring»	(to "vcsatoBIGstring")


-- «.gridstr-to-rawarr»	(to "gridstr-to-rawarr")



--% (find-lua50file "etc/compat.lua")
--% (find-lua50ref "String Manipulation")

floor   = math.floor
getn    = table.getn
gsub    = string.gsub
strbyte = string.byte
strlen  = string.len
strrep  = string.rep
strsub  = string.sub
tinsert = table.insert

copy = function (arr)
    local newarr = {}
    for key,val in pairs(arr) do newarr[key] = arr[key] end
    return newarr
  end
append = function (table1, table2)
    for i=1,table.getn(table2) do
      table.insert(table1, table2[i])
    end
    return table1
  end


-- (find-vtutil4file "lbitlib.c")
-- (find-vtutil4file "piofontx.c")
assertlbitlib = function ()
    if not band then
      assert(loadlib(scriptdir.."/lbitlib.so", "lua_bitlibopen"))()
    end
  end
assertpiofontx = function ()
    if not piofontx then
      assert(loadlib(scriptdir.."/piofontx.so", "piofontx_init"))()
    end
  end

assertlbitlib()




--%%%%%
--%
--% «tools_and_samples»  (to ".tools_and_samples")
--%
--%%%%%

--% «demo_bigstr»  (to ".demo_bigstr")
demo_bigstr = [[
+--------+--------+--------+--------+--------+--------+--------+--------+
|     o  | o      |    oo  |        |        |        |        |        |
|    oo  | o      |   oo o |   o    | o   o  |  o  o  |        |o       |
|ooo  o  | ooo    |   oo   |  o o   | o   o  |  o  o  | oo oo  |o       |
|     o  | o o    |   oo   |  o o   |  o o   |  o  o  |o  o  o |oo   oo |
|    ooo | ooo    |   oo   | o   o  |  o o   |  o  o  |o  o  o |o o o   |
|        |   o    |   oo   | o   o  |   o    | oooooo | oo oo  |o o oo  |
|        |   o    | o oo   |        |        |        |        |oo  o   |
|        |        |  oo    |        |        |        |        |    o   |
+--------+--------+--------+--------+--------+--------+--------+--------+
|  oooo  |  oooo  |ooo ooo |        |        |
|  o     |     o  |o     o |        |        |
|  o     |     o  |o     o |        | o   o  |
|  o     |     o  |o     o |oo oooo |o     o |
|        |        |        |o  o o o|o     o |
|        |        |        |o  o o o|o  o  o |
|        |        |        |o  o o o| oo oo  |
|        |        |        |        |        |
+--------+--------+--------+--------+--------+]]


--%%%%
--%
--% pixels <-> byte
--%
--%%%%

bits = {128, 64, 32, 16, 8, 4, 2, 1}
padbytes_zeroes = strrep("\000", 32)

padbytes = function (bytes)
    return strsub(bytes..padbytes_zeroes, 1, 32)
  end
pixelstobyte = function (str)
    local byte, i, bit = 0
    for i, bit in bits do
      if strbyte(str, i) ~= 32 then
        byte = byte + bit
      end
    end
    return byte
  end
bytetopixels = function (byte)
    local str, i, bit = ""
    for i, bit in ipairs(bits) do
      if band(byte, bit) ~= 0 then
        str = str .. "o"
      else
        str = str .. " "
      end
    end
    return str
  end


--%%%%
--%
--% hex <-> bytes
--%
--%%%%

hextable = {
  ["0"]= 0,  ["1"]= 1,  ["2"]= 2,  ["3"]= 3,  ["4"]= 4,
  ["5"]= 5,  ["6"]= 6,  ["7"]= 7,  ["8"]= 8,  ["9"]= 9,
  ["a"]=10,  ["b"]=11,  ["c"]=12,  ["d"]=13,  ["e"]=14,  ["f"]=15, 
  ["A"]=10,  ["B"]=11,  ["C"]=12,  ["D"]=13,  ["E"]=14,  ["F"]=15, 
   [0] ="0",  [1] ="1",  [2] ="2",  [3] ="3",  [4] ="5",
   [5] ="5",  [6] ="6",  [7] ="7",  [8] ="8",  [9] ="9",
  [10] ="a", [11] ="b", [12] ="c", [13] ="d", [14] ="e", [15] ="f"
}
hextobytes = function (hexstr)
    local bytes = ""
    for i=1,strlen(hexstr),2 do
      local h1, h2 = substr(hexstr,i,i), substr(hexstr,i+1,i+1)
      bytes = bytes .. string.char(hextable[h1]*16 + hextable[h2])
    end
    return bytes
  end
bytetohex = function (n)
    return hextable[iand(rshift(n, 4), 15)] .. hextable[iand(n, 15)]
  end
bytestohex = function (bytes)
    local s = ""
    for i=1,strlen(bytes) do
      s = s..bytetohex(string.byte(s, i))
    end
    return s
  end


--%%%%
--%
--% psf <-> font
--%
--%%%%

psftofont = function (psf)
  -- (find-fline "/usr/doc/console-tools/file-formats/psf" "psf_header =")
  local magic1, magic2, filemode, height
  magic1   = strbyte(psf, 1)		-- 0x36
  magic2   = strbyte(psf, 2)		-- 0x04
  filemode = strbyte(psf, 3)		-- 0 means 256 chars, no unicode
  height   = strbyte(psf, 4)		-- in scanlines; typically 8, 14 or 16
  -- I'm not checking magic1, magic2, and filemode yet
  return rawfonttofont(strsub(psf, 5), 256, height)
end
fonttopsf = function (font)
  return string.char(54, 4, 0, font.height) .. fonttorawfont(font, font.height)
end





--%%%%%
--%
--% gridstr -> rawarr
--%
--%%%%%
--
-- «gridstr-to-rawarr»  (to ".gridstr-to-rawarr")

stringtolines = function (str)
    local lines = {}
    local rest = string.gsub (str, "([^\n]*)\n", function (line)
        table.insert(lines, line)
      end)
    if rest ~= "" then table.insert(lines, rest) end
    return lines
  end
linetobitmaps = function (line)
    local pattern = "^|([ o][ o][ o][ o][ o][ o][ o][ o])(.*)"
    local bitmaps = {n=0}
    local found, _, bitmap, rest
    while 1 do
      found, _, bitmap, rest = string.find (line, pattern)
      if not found then break end
      table.insert(bitmaps, bitmap)
      line = rest
    end
    return bitmaps
  end
gridstrtorawarr = function (gridstr)
    local lines = stringtolines(gridstr)
    local nlines = table.getn(lines)
    local bitmaps = {}
    for i = 1,nlines do
      table.insert(bitmaps, linetobitmaps(lines[i]))
    end
    local rawchars = {}
    local i = 1
    while i <= nlines do
      if bitmaps[i].n > 0 then
        local nbitmaps = bitmaps[i].n
        local j = i
        while 1 do
          if j+1 <= nlines and bitmaps[j+1].n > 0 then
            assert(nbitmaps == bitmaps[j+1].n, "bad gridstring (line "..j..")")
            j = j+1
          else break
          end
        end
        for h = 1,nbitmaps do
          local bytes = ""
          for k = i,j do
            bytes = bytes..string.char(pixelstobyte(bitmaps[k][h]))
          end
          table.insert(rawchars, padbytes(bytes))
        end
        i = j+1
      else
        i = i+1
      end
    end
    return rawchars
  end


--%%%%
--%
--% gridstr -> font
--%
--%%%%

-- gridstrtofont isn't very useful - gridstrs are used mainly
-- for modifying fonts, not for storing fonts in a readable format.
--
gridstrtofont = function (gridstr, nchars, height)
  local font = {nchars = nchars, height = height}
  local rawarr = bigstrtorawarr(bigstr)
  local i
  if getn(rawarr) ~= nchars then
    printf("Warning: getn(rawarr)=%d, nchars=%d\n", getn(rawarr), nchars)
  end
  for i=0,nchars-1 do
    font[i] = rawarr[i+1]
  end
  return font
end


--%%%%
--%
--% font -> gridstr
--% rawarr -> gridstr
--%
--%%%%

fonttogridstr_horizontalbar = function (nchars)
    return "+" .. strrep("--------+", nchars) .. "\n"
  end
fonttogridstr_bitmaps = function (font, c0, c1, v0, v1)
    local gridstr = ""
    for scanline = v0,v1 do
      gridstr = gridstr .. "|"
      for nchar = c0,c1 do
        gridstr = gridstr..bytetopixels(strbyte(font[nchar], scanline)).."|"
      end
      gridstr = gridstr .. "\n"
    end
    return gridstr
  end
fonttogridstr = function (font, c0, c2, charsperline, height)
    c0 = c0 or 0
    c2 = c2 or font.nchars
    height = height or font.height
    charsperline = charsperline or 8
    local gridstr = fonttogridstr_horizontalbar(min(c2 - c0, charsperline))
    while c0 < c2 do
      local nchars = min(c2 - c0, charsperline)
      gridstr = gridstr ..
        fonttogridstr_bitmaps(font, c0, c0+nchars-1, 1, height) ..
        fonttogridstr_horizontalbar(nchars)
      c0 = c0 + nchars
    end
    return gridstr
  end

rawarrtogridstr = fonttogridstr



--%%%%%
--%
--% font <-> rawfont
--%
--%%%%%

-- a "font" is a table with indices "nchars", "height", 0, 1, 2, ..., 255,
-- where each entry with a numeric index contains a char in raw form,
-- i.e., a string with length 32.
-- a "rawfont" is a string of nchars*height bytes.

rawfonttofont = function (rawfont, nchars, height)
    nchars = nchars or 256
    height = height or floor(strlen(rawfont)/nchars)
    local font = {nchars = nchars, height = height}
    local nchar
    if strlen(rawfont) ~= nchars*height then
      printf("Bad len: rawfont=%d nchars*height=%d\n",
        strlen(rawfont), nchars*height)
    end
    for nchar=0,nchars-1 do
      font[nchar] = padbytes(strsub(rawfont, nchar*height+1, (nchar+1)*height))
    end
    return font
  end
fonttorawfont = function (font, scanlines)
    local rawfont = ""
    local nchar
    for nchar=0,font.nchars-1 do
      rawfont = rawfont .. strsub(font[nchar], 1, scanlines)
    end
    return rawfont
  end







--%%%%%
--%
--% Functions for modifying fonts and keymaps
--%
--%%%%%

--% «changefont»  (to ".changefont")
changefont = function (origfont, rawarr, cchars)
  for i=1,getn(cchars) do
    local c = cchars[i]
    if strlen(c) == 1 and c ~= "." then
      origfont[strbyte(c)] = rawarr[i]
    end
  end
  return origfont
end

--% «makecomposes»  (to ".makecomposes")
makecomposes = function (cchars, ckeyps)
  local c, key1, key2, thiscompose
  local composes = ""
  local tickchar = function (c)
      return "'"..gsub(c, "(['\\])", "\\%1").."'"
    end
  for i=1,getn(cchars) do
    c = cchars[i]
    if c ~= "." then
      key1 = strsub(ckeyps[i], 1, 1)
      key2 = strsub(ckeyps[i], 2, 2)
      thiscompose = format("compose %s %s to %s\n",
			   tickchar(key1), tickchar(key2), tickchar(c))
      if strlen(c) == 1 and c ~= "." then
        composes = composes .. thiscompose
      else
        composes = composes .. "# " .. thiscompose
      end
    end
  end
  return composes
end



--%%%%
--%
--% pcfont <-> isofont
--%
--%%%%

-- (find-node "(elisp)Mapping Functions")
-- (find-fline "~/MTA/vtutil")
-- (find-fline "~/MTA/128")
-- (find-fline "~/MTA/128c")
-- (insert (mapconcat (lambda (c1) (format "\\%03d" c1)) "abcd" ""))

highglyphs_iso =
  "\128\129\130\131\132\133\134\135\136\137\138\139\140\141\142\143" ..
  "\144\145\146\147\148\149\150\151\152\153\154\155\156\157\158\159" ..
  "\160\161\162\163\164\165\166\167\168\169\170\171\172\173\174\175" ..
  "\176\177\178\179\180\181\182\183\184\185\186\187\188\189\190\191" ..
  "\192\193\194\195\196\197\198\199\200\201\202\203\204\205\206\207" ..
  "\208\209\210\211\212\213\214\215\216\217\218\219\220\221\222\223" ..
  "\224\225\226\227\228\229\230\231\232\233\234\235\236\237\238\239" ..
  "\240\241\242\243\244\245\246\247\248\249\250\251\252\253\254\255"
highglyphs_pc =
  "\213\159\242\254\196\179\218\191\192\217\195\180\194\193\197\205" ..
  "\186\201\187\200\188\204\185\203\202\206\223\220\219\176\177\178" ..
  "\255\173\189\156\207\190\221\245\249\184\166\174\170\240\169\238" ..
  "\248\241\253\252\239\230\244\250\247\251\167\175\172\171\243\168" ..
  "\183\181\182\199\142\143\146\128\212\144\210\211\222\214\215\216" ..
  "\209\165\227\224\226\229\153\158\157\235\233\234\154\237\232\225" ..
  "\133\160\131\198\132\134\145\135\138\130\136\137\141\161\140\139" ..
  "\208\164\149\162\147\228\148\246\155\151\163\150\129\236\231\152"
trfont = function (font, trstr1, trstr2)
    local newfont = copy(font)
    for i=1,strlen(trstr1) do
      newfont[strbyte(trstr2, i)] = font[strbyte(trstr1, i)]
    end
    return newfont
  end
isofonttopcfont = function (font)
    return trfont(font, highglyphs_iso, highglyphs_pc)
  end
pcfonttoisofont = function (font)
    return trfont(font, highglyphs_pc, highglyphs_iso)
  end

do
local idfont = {}
for i = 128,255 do idfont[i]=i end
local tmpfont = isofonttopcfont(idfont)
local tmpstr = ""
for i = 128,255 do tmpstr = tmpstr..string.char(tmpfont[i]) end
highglyphs_pc_reverse = tmpstr
end


--%%%%
--%
--% setfont
--%
--%%%%

-- (find-angg "LUA/piofontx.c")
setfont = function (font, forcedheight)
  local rawfont32 = fonttorawfont(font, 32)
  local err
  assertpiofontx()
  err = piofontx(rawfont32, font.nchars, forcedheight or font.height)
  if err then
    printf("piofontx error: %s\n", err)
  end
end

setfont_force = function (font)
  setfont(font, font.height-1)
  setfont(font)
end



--%%%%
--%
--% vcsa -> text / pnm
--% (for screenshots of VTs)
--%
--%%%%

-- vcsatotext takes just the "char" bytes of a vcsa string (i.e., drop
-- the "fg/bg" bytes), trims the lines, and adds the "\n"s; the result
-- is a standard unix text file.
-- (find-angg ".zshrc" "vt")
-- (find-lua50ref "Patterns" "followed by `-'" "shortest")
-- mylua -e 'p(gsub("abcdefg", "(.).", "%1"))'

vcsatotext = function (vcsa)
  local lines, columns, cursorx, cursory =
    strbyte(vcsa, 1), strbyte(vcsa, 2), strbyte(vcsa, 3), strbyte(vcsa, 4)
  local bigstr = ""
  for y=1,lines-1 do
    pairs = strsub(vcsa, y*columns*2+5, (y+1)*columns*2+4)
    str = gsub(pairs, "(.).", "%1")
    str = gsub(str, "(.) -", "%1")
    bigstr = bigstr .. str .. "\n"
  end
  return bigstr
end

--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "vtfontlib.lua"
--        (find-sh "sudo cat /dev/vcsa5")
bigstr = getoutput "sudo cat /dev/vcsa5"
= vcsatotext(bigstr)

--]]



--% (find-k24file "drivers/char/vc_screen.c" "4 bytes lines,columns,x,y")
--% (find-angg "MTA/vtutilsh.c" "vcsa2pnmdata")
--% (find-angg "MTA/vtutil" "vcsa2pnm")
--% (find-status "netpbm-dev")
--% (find-vldifile "netpbm-dev.list")
--% (find-man "5 ppm")

vcsa_colors = {
   [0]=" 0 0 0",  [1]=" 0 0 2",  [2]=" 0 2 0",  [3]=" 0 2 2",
   [4]=" 2 0 0",  [5]=" 2 0 2",  [6]=" 2 1 0",  [7]=" 2 2 2",
   [8]=" 1 1 1",  [9]=" 1 1 3", [10]=" 1 3 1", [11]=" 1 3 3",
  [12]=" 3 1 1", [13]=" 3 1 3", [14]=" 3 3 1", [15]=" 3 3 3",
}
digit_colors = {
       "1", "2", "3", "4", "5", "6", "7",
  "8", "9", "A", "B", "C", "D", "E", "F", [0]="0"
}

wordstoscreenshot = function (words, font, width, colors)
    local bigstr, rowstr, char, attr, charscanline, fg, bg, minirowstr
    bigstr = ""
    for scanline=1,font.height do
      rowstr = ""
      for col=0,strlen(words)/2-1 do
	char = strbyte(words, col*2+1)
	attr = strbyte(words, col*2+2)
	charscanline = strbyte(font[char], scanline)
	bg = colors[rshift(attr, 4)]
	fg = colors[band(attr, 15)]
	minirowstr = ""
	for i,bit in bits do
	  if band(charscanline, bit) ~= 0 then
	    minirowstr = minirowstr .. fg
	  else
	    minirowstr = minirowstr .. bg
	  end
	end
	if width == 9 then
	  minirowstr = minirowstr .. bg
	end
	rowstr = rowstr .. minirowstr
      end
      bigstr = bigstr .. rowstr .. "\n"
    end
  end
vcsatopnm0 = function (vcsa, font, width, colors)
    local lines, columns, cursorx, cursory =
      strbyte(vcsa, 1), strbyte(vcsa, 2), strbyte(vcsa, 3), strbyte(vcsa, 4)
    local header = format("P3\n%d %d\n3\n", columns*width, lines*font.height) 
    local bigstr = ""
    for bigy=0,lines-1 do
      words = strsub(vcsa, bigy*columns*2+5, (bigy+1)*columns*2+4)
      bigstr = bigstr .. wordstoscreenshot(words, font, width, colors)
    end
    return header .. bigstr
  end

vcsatopnm = function (vcsa, font, width, colors)
  local lines, columns, cursorx, cursory =
    strbyte(vcsa, 1), strbyte(vcsa, 2), strbyte(vcsa, 3), strbyte(vcsa, 4)
  local header = format("P3\n%d %d\n3\n", columns*width, lines*font.height) 
  local bigstr = ""
  local bigy, rowpairs, bigrowstr, scanline, rowstr, col, char, attr,
        charscanline, fg, bg, minirowstr, i, bit
  for bigy=0,lines-1 do
    rowpairs = strsub(vcsa, bigy*columns*2+5, (bigy+1)*columns*2+4)
    bigrowstr = ""
    for scanline=1,font.height do
      rowstr = ""
      for col=0,columns-1 do
	char = strbyte(rowpairs, col*2+1)
	attr = strbyte(rowpairs, col*2+2)
	-- px(char, scanline)
	charscanline = strbyte(font[char], scanline)
	bg = colors[rshift(attr, 4)]
	fg = colors[band(attr, 15)]
	minirowstr = ""
	for i,bit in bits do
	  if band(charscanline, bit) ~= 0 then
	    minirowstr = minirowstr .. fg
	  else
	    minirowstr = minirowstr .. bg
	  end
	end
	if width == 9 then
	  minirowstr = minirowstr .. bg
	end
	rowstr = rowstr .. minirowstr
      end
      bigrowstr = bigrowstr .. rowstr .. "\n"
    end
    bigstr = bigstr .. bigrowstr
  end
  return header .. bigstr
end



--%%%%
--%
--% loadfont and savefont
--%
--%%%%

loadfont = function (fname)
    local str = readfile(fname)
    if band(strlen(str), 255) == 0 then
      return rawfonttofont(str)
    elseif band(strlen(str), 255) == 4 then
      return psftofont(str)
    end
    printf("loadfont: str is not a font (len=%d\n)", strlen(str))
  end
savefont = function (font, fname, charsperline)
    if strsub(fname, -4) == ".psf" then
      writefile(fname, fonttopsf(font))
      printf("Saved as psf:         %s\n", fname)
    elseif strsub(fname, -5) == ".grid" then
      writefile(fname, fonttogridstr(font, nil, nil, charsperline))
      printf("Saved as grid:        %s\n", fname)
    else
      writefile(fname, fonttorawfont(font, font.height))
      printf("Saved as raw font:    %s\n", fname)
    end
  end


--%%%%
--%
--% functions dealing with modifying chars in a font
--%
--%%%%

isdefinablechar = function (str)
    if string.find(str, "^[\001-\031\127-\255]$") then return true end
  end
iscomposepair = function (str)
    if string.find(str, "^[ -~][ -~]$") then return true end
  end

mathcharstuff = function (gridstr, ...)
    local strarr1 = {}
    local strarr2 = {}
    local strarr3 = {}
    for i=1,getn(arg),3 do append(strarr1, split(arg[i])) end
    for i=2,getn(arg),3 do append(strarr2, split(arg[i])) end
    for i=3,getn(arg),3 do append(strarr3, split(arg[i])) end
    return gridstrtorawarr(gridstr), strarr1, strarr2, strarr3
  end
modifyfont = function (font, mimages, mchars)
    for i=1,getn(mimages) do
      local c = mchars[i]
      if isdefinablechar(c) then
        font[strbyte(c)] = mimages[i]
      end
    end
  end

-- These ones should be moved elsewhere, but they're still experimental
Modifyfont = function ()
    modifyfont(FONT, MIMAGES, MCHARS)
  end
Prepidtom = function ()
    IDTOM = IDTOM or {}
    for i=1,getn(MIMAGES) do
      local c, name, pair = MCHARS[i], MNAMES[i], MPAIRS[i]
      if isdefinablechar(c) then IDTOM[c] = i end
      if iscomposepair(pair) then IDTOM[pair] = i end
      IDTOM[name] = i
    end
  end


--%%%%
--%
--% functions for making "compose.el"'s compose tables
--%
--%%%%

quote = function (str)
    return string.gsub(str, "([\\\"])", "\\%1")
  end
transformlines = function (str, f)
    local newstr = ""
    for _,line in ipairs(stringtolines(str)) do
      newstr = newstr .. f(line) .. "\n"
    end
    return newstr
  end
composeslinetoelline = function (str)
    local compstr = ""
    for _,w in split(str) do
      if string.len(w) == 1 then 
        compstr = compstr .. " ?" .. quote(w)
      else
        compstr = compstr .. "  \"" .. quote(w) .."\""
      end
    end
    return compstr
  end
composestoel = function (composes, setq)
    setq = setq or "setq composes-localmath"
    local comment = transformlines(composes, function (line)
        return ";;" .. line
      end)
    local elpairs = transformlines(composes, composeslinetoelline)
    return format("%s;;\n" ..
                  "(%s '(\n%s))\n" ..
                  "(composes-update)\n", comment, setq, elpairs)
  end

COMPOSES = ""
COMPOSESN = 0	-- number of compose pairs in the last line of COMPOSES

Addcompose = function (pair, c, maxwidth)
    if pair and c and iscomposepair(pair) and isdefinablechar(c) then
      COMPOSES = COMPOSES .. "  " .. pair .. " " .. c
      COMPOSESN = COMPOSESN + 1
    end
    if maxwidth and COMPOSESN >= maxwidth then
      COMPOSES = COMPOSES .. "\n"
      COMPOSESN = 0
    end
    return COMPOSES
  end

Addcomposechars = function (chars, maxwidth)
    for i=1,strlen(chars) do
      local c = strsub(chars, i, i)
      print(c, c == "\n")
      if c == "\n" then
	Addcompose(nil, nil, 0)
      elseif isdefinablechar(c) then
        Addcompose(MPAIRS[IDTOM[c]], c, maxwidth or 8)
      end
    end
    return COMPOSES
  end

Mcomposes = function ()
    for i=1,getn(MIMAGES) do
      Addcompose(MPAIRS[i], MCHARS[i], 8)
    end
    return Addcompose(nil, nil, 1)
  end

Composestoel = function (setq) return composestoel(COMPOSES, setq) end

--[[
#*
cd ~/vtutil4/
lua50 vtutil.lua -e 'Prepidtom();print(Mcomposes())' > ~/o
lua50 vtutil.lua -e 'Prepidtom();Mcomposes();print(Composestoel())' > ~/o2
# (find-fline "~/o")
# (find-fline "~/o2")
#*
cd ~/vtutil4/
lua50 vtutil.lua -e '
  Prepidtom();
  Addcomposechars([=[
ýÝÎþÌ¢
§®∧⊃¨
©³¿ÅÐ
ñÞ¤¥Ë¸Ñ
¯¦÷­£î
ÞåÆØð
ÛÏ]=]);
  writefile("/tmp/o",Composestoel())
'
# (find-fline "/tmp/o")
#*
--]]



--%%%%
--%
--% functions using global variables
--%
--%%%%

Pctoiso = function () FONT = pcfonttoisofont(FONT) end

Loadfont = function (fname) FONT = loadfont(fname) end
Loadpcfont = function (fname) Loadfont(fname); Pctoiso() end
Writefont = function (fname, charsperline)
    savefont(FONT, fname, charsperline)
  end

Setfont = function () setfont(FONT) end

Readvcsa = function (devfname) VCSA = readfile(devfname) end
Vcsatotext = function () TEXT = vcsatotext(VCSA) end
Vcsatopnm = function (width)
    PNM = vcsatopnm(VCSA, FONT, width or 9, vcsa_colors)
  end





-- (find-luafile "README.rttpatch")
-- (find-luanode "For Statement")
-- (find-luanode "strbyte")
-- (find-lua50ref "Lexical Conventions" "long comment")
--[[
#*
cd ~/vtutil4/
lua50 vtutil.lua -e '
  Loadfont("ega1-iso.8");
  Modifyfont();
  Writefont("isomath.8")
'
#*
cd ~/vtutil4/
lua50 vtutil.lua -e 'Readvcsa("/dev/vcsa5");Vcsatotext();print(TEXT)'
#*
cd ~/vtutil4/
lua50 vtutil.lua -e '
  Readvcsa("/dev/vcsa1");Loadfont("isomath.8");
  Vcsatopnm();writefile("/tmp/v.pnm",PNM)
'
cd /tmp/
pnmtojpeg v.pnm > v.jpeg
pnmtopng  v.pnm > v.png
rm -fv /tmp/.xvpics/v.*
ls -l v.*
#*
--]]


--  ee-imenu-re:          "\n\\([A-Za-z0-9_]+\\) ="
--  ee-comment-format:    "-- %s\n"


--  Local Variables:
--  coding:               raw-text-unix
--  ee-anchor-format:     "\n%s ="
--  ee-anchor-format:     "«%s»"
--  End: