#!/bin/lua
--[[
# encoding: utf-8
#
# usage: ptt [-h] foo.tt
#
# ptt: coded by Kenji Arisawa
# version 4.0
# date: 2014/10/05
# Email: arisawa@aichi-u.ac.jp
#
--]]
version="4.0a" -- version No. used in comment of generated text
sub=string.sub
find=string.find
gsub=string.gsub
match=string.match
gmatch=string.gmatch
format=string.format
concat=table.concat
int=tonumber
dbg=print
push=table.insert
str=require("str")
trim=str.trim
xfind=str.xfind
rfind=str.rfind
split=str.split
xsplit=str.xsplit
trans=str.trans
-- constant values to make codes easy to read
-- don't change
dquote='"' -- double quote
tab="\t"
quof=false
h1opt={l=true,t=true} -- ptt option
-- l=true -- logo print
-- t=true -- toc print
-- e=false -- english
-- q=false -- quote
-- our preference
encoding="utf-8" -- encoding in tt text
lang="ja" -- default language; japanese mode; not "jp"!
-- initial values
hdr={} -- HTML header
rdic={}
udic={[" & "]='&', [" < "]='<', [" > "]='>'} -- user's dictionary
ldic={} -- label dictionary
label=nil
ritmode=false
toc={n=0} -- table of contents
seccnt={0,0,0} -- section counter initial value
h1p=false -- H1 is printed
nline=0 -- next line to be read
dline=1 -- debug point. last block command
dd=nil -- controls DD+: part
-- end of initial values
-- start of some generic functions
--
function printf(fmt,...)
io.write(format(fmt,...))
end
function pline(fmt,...)
if dd == nil then
io.write(format(fmt.."\n",...))
else
dd = dd .. format(fmt,...) -- ???
end
end
function errf(fmt,...) -- error with format
io.stderr:write(format(fmt,...))
end
function sysfatal(s)
errf("error: %s\n",s)
os.exit()
end
function merge(...) -- merge tables
t={}
u={...}
for n=1,#u do
for k,v in pairs(u[n]) do
t[k] = v
end
end
return t
end
-- end generic functions
-- start ptt5 special functions
--
function rquote(s) -- replace double quote to "“" and "”" pair
-- s=gsub(s,"(.*) \"([^\"]*)\"","%1 “%2”")
s=gsub(s," \"([^\"]*)\""," “%1”")
return s
end
function gline()
-- global nline
nline=nline+1
return lines[nline]
end
function ugline()
-- global nline
if nline>1 then
nline=nline-1
end
end
function subline(s)
-- global nline
lines[nline] = s
end
function logo()
---- change as you like ----
pline('')
pline('
')
---- end of change ------
end
function head(title)
local bo
if ritmode == true then
pline(hdr[1])
table.remove(hdr,1)
end
pline('')
pline('
') line=gline() while line ~= term do -- dbg(line) pline("%s", t2h(line)) line=gline() end pline("") end function ul(s) -- unordered list pline("
%s %s
%s
',repl(s)) end function bcent(s) -- center block o,term,a = opt(s) if a then block(term,format('\
| \n' ,im[3],fn,fn)
end
pline("
%s | ' , im[1]) end pline("
%s",repl(s)) end function bquote(s) -- block quote o,t,a=opt(s) if a then block(t,"
\n","") else block(t,"
\n","") end end function raw(s) pline(s) end function braw(term) line=gline() while line ~= term do pline("%s", line) line=gline() end end function tablth(line,cl,sep) local args,tr,hs,v,t,n,n1,n2,n3 --dbg("### tablth:",line) --dbg("## tablth:",sep) args=split(line,sep) -- header -- for k,v in pairs(args) do dbg("## tablth",k,v) end --[[ # format of table header: # name:<[width] # left align # name:>[width] # right align # name:[width] # center align # name:-[width] # hidden # name # center align # where [ ] is a meta symbol that denotes option # width must be in unit of pixel --]] tr={["<"]="left",[">"]="right",[""]="center",["-"]="hidden"} hs={} --dbg("## tablth",#args) for n=1,#args do v={} -- default v.align="center" -- alignment v.width="0" -- width, string t=trim(args[n]) v.name=t n1,n2,n3=match(t,"(.*):([<>-]?)([%d]*)") --dbg("## tablth",n,n1,n2,n3) if n1 then v.name=n1 v.align=tr[n2] v.width=n3 end hs[n]=v end -- count emty names and put them to colspan -- "hidden" must be skipped m=0 for n=1,#args do --dbg(n,hs[n].name,hs[n].align) if hs[n].name ~= "" then m = 1 break end end if m > 0 then pline("
\t%s', t2h(s)) line=gline() while line and sub(line,1,1)==tab do pline("\t%s", t2h(sub(line,2))) line=gline() end pline("") ugline() end function urll(s) -- url link -- translate http://HOST to: -- http://HOST -- http://HOST must be at the beginning of line -- Lua does not have '|', so '(%s|^)' is not allowed s = gsub(s,'%s(https?://[^%s"{}()%[%]\\|^`]+)', ' %1') s = gsub(s,'^(https?://[^%s"{}()%[%]\\|^`]+)', '%1') return s end function repl(s) if s == nil then return s end s=trans(s,udic) -- s=gsub(s,rdic) -- s=replace(s,k,udic[k]) s = urll(s) if quof then s = rquote(s) end return s end function t2h(s) -- text to html -- order is matter ! local t={["&"]="&", ["<"]="<", [">"]=">"} s=gsub(s,"[&<>]",t) return s end function rit(line) -- rit block while sub(line,-2) ~= "}$" do pline("%s", line) line=gline() end pline("%s", line) end function pmatch(line,dic) -- dic: pattern dic -- return: key,func,opt if dic == nil then return nil,nil,nil end for k,v in pairs(dic) do if sub(line,1,#k) == k then return k,v,sub(line,#k+1) end end end function bline(line,pdic,opt) -- opt: for what? local m while not eol(line) do pline("%s
")
break
end
if ritmode==true and sub(line,1,2)=="${" then
rit(line)
break
end
line = gsub(line,refp,function (m)
return ldic[m]
end
)
subline(line)
m,f,o = pmatch(line,pat)
if m then
--dbg("# DEBUG:", line)
--dbg("# DEBUG:m:",m)
if f==obsolete then
f(line)
else
f(trim(o))
end
break
end
m = match(line,spec)
--dbg("DBG1:",m,line)
if m and spectagtab[m] then
--dbg("DBG2:",line)
pline("%s",line)
t = format("%s>",m)
braw(t) -- block raw output until t. t is the terminator
pline(t)
break
end
if match(line,uncook) then
if sub(line,-2) ~= "}" then
pline("%s",line)
end
break
end
if match(line,obrace) then
--dbg("DBG3:",line)
pline("%s",line)
line=gline()
while not match(line,cbrace) do
pline("%s",line)
line=gline()
end
pline("%s",line)
break
end
pline("%s ')
end
function mkdic(pat)
local pdic={}
for k,v in pairs(pat) do
pdic[k] = v
end
return pdic
end
-- pat0 is used elsewhere
-- pat1 is allowed in some block commands
pat1= { -- RE pattern
["- "]=item, -- special
["HR:"]=obsolete, -- hr,
["UL:"]=ul,
["OL:"]=ol,
["DL:"]=dl,
[tab]=pre, -- special
["I:"]=img,
["II:"]=bimg,
["C:"]=cent,
["CC:"]=bcent,
["#:"]=com,
["##:"]=bcom,
["N:"]=note,
["NN:"]=bnote,
["Q:"]=quote,
["QQ:"]=bquote,
["P:"]=code,
["Ta:"]=tabl,
["!:"]= raw,
["!!:"]=braw,
["-a:"]=obsolete, --actm,
["+a:"]=obsolete, --actp,
["A:"]=obsolete,
["AI:"]=obsolete,
["AI:"]=obsolete,
["B:"]=obsolete,
["T:"]=obsolete,
["R:"]=obsolete
}
-- outermost level tags
pat2= {
-- H1: is special
["H4:"]=h4,
["H3:"]=h3,
["H2:"]=h2,
["D:"]=define,
["DD:"]=bsdef,
["DD+:"]=bpdef,
}
-- pat3 is used for making toc.
-- then H1:,.. in comments etc must be skipped
pat3={
["!!:"]=bcom,
["P:"]=bcom,
["##:"]=bcom,
["NN:"]=bcom,
["QQ:"]=bcom,
["II:"]=bcom,
["CC:"]=bcom,
["DD:"]=bcom1,
["DD+:"]=bcom1,
}
pat4={ -- header level tags, they may be before "H1:"
["In:"]=inc, -- include
["KW:"]=kw,
["D:"]=define,
["DD:"]=bsdef,
["DD+:"]=bsdef,
}
pat0=merge(pat1,pat2) -- keep this order
-- we define some tags in ptt
ptth="^(\t|- |[^ ]:|[^ ][^ ][+]?:) *(.*[^ ]|) *$"
spectags="script|style|iframe|textarea|form|pre|select|table|ul|ol|dl"
t=split(spectags,"|")
spectagtab={}
for k,v in pairs(t) do
spectagtab[v]=true
end
spec="^<(%w+)[^<>]*>%s*$" -- special tags
obrace="^<[^>]*$"
cbrace="^.*>.*$"
uncook="^<.*>$" -- don't cook the line "< .... >"
inbrac=".*<[^>]*$" -- in < >
labp="
",repl(line))
break
end
line=gline()
--dbg("DBG4:",line)
end
end
function init(bob) -- make toc, label
-- global toc, label
local cnt,line,m,s,sid,key,r,k
-- we must read whole data below "H1:" to construct toc etc
--
nline=bob
line=gline()
while line do
--dbg(line)
-- we must skip pat3
k,m=pmatch(line,pat3)
if m then -- enter pat3
m(sub(line,#k+1))
else -- out of pat3
--dbg(line)
m,f,o = pmatch(line,pat2)
if m then
if match(m,"D:") then
-- o is "{ " for example
f(o)
end
if match(m,"H[234]:") then
sid=inc_seccnt(m) -- something like "1.1.2"
toc[sid]=trim(sub(line,4))
toc.n = toc.n + 1
label=sid -- ??? this result is not used
end
end
line = gsub(line,labp,function (m)
-- Let
")
t={}
for k,v in pairs(toc) do
push(t,k)
end
table.sort(t,compf)
for k,s in ipairs(t) do -- s is something like "1.1.2"
if match(s,"^%d+%.0+%.0+$") then
pline('
")
pline('