arabluatex.lua 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. --[[
  2. This file is part of the `arabluatex' package
  3. ArabLuaTeX -- Processing ArabTeX notation under LuaLaTeX
  4. Copyright (C) 2016--2018 Robert Alessi
  5. Please send error reports and suggestions for improvements to Robert
  6. Alessi <alessi@robertalessi.net>
  7. This program is free software: you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation, either version 3 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program. If not, see
  17. <http://www.gnu.org/licenses/>.
  18. --]]
  19. require("arabluatex_voc")
  20. require("arabluatex_fullvoc")
  21. require("arabluatex_novoc")
  22. require("arabluatex_trans")
  23. -- lpeg equivalent for string.gsub()
  24. local function gsub(s, patt, repl)
  25. patt = lpeg.P(patt)
  26. patt = lpeg.Cs((patt / repl + 1)^0)
  27. return lpeg.match(patt, s)
  28. end
  29. -- makeatletter, makeatother
  30. local atletter = "\\makeatletter{}"
  31. local atother = "\\makeatother{}"
  32. -- some basic patterns:
  33. local ascii = lpeg.R("az", "AZ", "@@")
  34. local dblbkslash = lpeg.Cs("\\")
  35. local bsqbrackets = lpeg.Cs{ "[" * ((1 - lpeg.S"[]") + lpeg.V(1))^0 * "]" }
  36. local bcbraces = lpeg.Cs{ "{" * ((1 - lpeg.S"{}") + lpeg.V(1))^0 * "}" }
  37. local spce = lpeg.Cs(" ")
  38. local spcenc = lpeg.P(" ")
  39. local cmdstar = lpeg.Cs(spce * lpeg.P("*"))
  40. local bsqbracketsii = lpeg.Cs(bsqbrackets^-2)
  41. local bcbracesii = lpeg.Cs(bcbraces^-2)
  42. local cmd = lpeg.Cs(dblbkslash * ascii^1 * cmdstar^-1)
  43. local cmdargs = lpeg.Cs(spce^-1 * bsqbracketsii * bcbracesii * bsqbrackets^-1)
  44. local arbargs = lpeg.Cs(spce^-1 * bsqbrackets^-1 * bcbraces)
  45. local baytargs = lpeg.Cs(spce * bcbraces * bsqbrackets^-1 * bcbraces)
  46. local function protectarb(str)
  47. str = string.gsub(str, "(\\arb%s?)(%[.-%])(%b{})", "\\al@brk{\\arb%2%3}")
  48. str = string.gsub(str, "(\\LR%s?)(%b{})", "\\@LR%2")
  49. str = string.gsub(str, "(\\RL%s?)(%b{})", "\\@RL%2")
  50. return str
  51. end
  52. local function unprotectarb(str)
  53. str = string.gsub(str, "(\\@arb)(%[.-%])(%b{})", "\\arb%2%3")
  54. str = string.gsub(str, "(\\@LR)(%b{})", "\\LR%2")
  55. str = string.gsub(str, "(\\@RL)(%b{})", "\\RL%2")
  56. str = gsub(str, lpeg.Cs("\\al@brk") * bcbraces, function(tag, body)
  57. body = string.sub(body, 2, -2)
  58. return string.format("%s", body)
  59. end)
  60. return str
  61. end
  62. -- the following is to be taken out of \arb{}
  63. local outofarb = {
  64. "LRfootnote",
  65. "RLfootnote",
  66. "edtext",
  67. "pstart",
  68. "pend"
  69. }
  70. -- commands the arguments of which must not be processed by arabluatex
  71. -- inside \arb{}. 'albrkcmds' is what is set by default. 'brkcmds'
  72. -- collects the commands set in the preamble with \MkArbBreak{}
  73. local albrkcmds = {
  74. "begin",
  75. "end",
  76. "par",
  77. "LRmarginpar",
  78. "arbmark",
  79. "abjad",
  80. "ayah"
  81. }
  82. local brkcmds = {}
  83. function mkarbbreak(str, opt)
  84. str = str ..","
  85. str = string.gsub(str, "%s+", "")
  86. local fieldstart = 1
  87. if opt == "dflt" then
  88. repeat
  89. local nexti = string.find(str, "%,", fieldstart)
  90. table.insert(brkcmds, string.sub(str, fieldstart, nexti-1))
  91. fieldstart = nexti +1
  92. until fieldstart > string.len(str)
  93. return brkcmds
  94. elseif opt == "out" then
  95. repeat
  96. local nexti = string.find(str, "%,", fieldstart)
  97. table.insert(outofarb, string.sub(str, fieldstart, nexti-1))
  98. fieldstart = nexti +1
  99. until fieldstart > string.len(str)
  100. return outofarb
  101. end
  102. end
  103. local function breakcmd(str)
  104. -- process \item[], then \item[]
  105. str = string.gsub(str, "\\(item.?)(%b[])",
  106. function(tag, body)
  107. body = string.sub(body, 2, -2)
  108. return string.format("\\al@brk{\\item[\\arb{%s}] }", body)
  109. end)
  110. str = string.gsub(str, "(\\item)(%s+)", "%1{}%2")
  111. -- \textcolor
  112. str = string.gsub(str, "\\(textcolor%s?)(%b{})(%b{})",
  113. function(tag, bodycolor, bodytext)
  114. bodycolor = string.sub(bodycolor, 2, -2)
  115. bodytext = string.sub(bodytext, 2, -2)
  116. return string.format("\\al@brk{\\%s{%s}{\\arb{%s}}}", tag, bodycolor, bodytext)
  117. end)
  118. -- commands set by default in outofarb
  119. for i = 1,#outofarb do
  120. str = gsub(str, dblbkslash * lpeg.Cs(outofarb[i]) * cmdargs, "}%1%2%3\\arb{")
  121. end
  122. -- commands set by default in albrkcmds
  123. for i = 1,#albrkcmds do
  124. str = gsub(str, dblbkslash * lpeg.Cs(albrkcmds[i]) * cmdargs, "\\al@brk{%1%2%3}")
  125. end
  126. -- user commands (brkcmds)
  127. if next(brkcmds) == nil then
  128. -- nothing to do
  129. else
  130. for i = 1,#brkcmds do
  131. str = gsub(str, dblbkslash * lpeg.Cs(brkcmds[i]) * cmdargs, "\\al@brk{%1%2%3}")
  132. end
  133. end
  134. return str
  135. end
  136. local function holdcmd(str)
  137. str = gsub(str, lpeg.Cs("\\arb") * bcbraces, function(tag, body)
  138. body = string.sub(body, 2, -2)
  139. body = gsub(body, cmd * spcenc^-1 * bsqbracketsii * spcenc^-1 * bcbraces, function(btag, bopt, bbody)
  140. bbody = string.sub(bbody, 2, -2)
  141. if string.find(btag, "@") then
  142. return holdcmd(string.format("}%s%s{%s}\\arb{", btag, bopt, bbody))
  143. else
  144. return holdcmd(string.format("}%s%s{\\arb{%s}}\\arb{", btag, bopt, bbody))
  145. end
  146. end)
  147. return string.format("%s{%s}", tag, body)
  148. end)
  149. str = string.gsub(str, "\\arb{}", "")
  150. return str
  151. end
  152. local function arbnum(str)
  153. str = string.gsub(str, "([0-9%,%-%/]+)", function(num)
  154. return string.reverse(num)
  155. end)
  156. return str
  157. end
  158. local function indnum(str)
  159. str = string.gsub(str, "([0-9%,%-%/]+)", function(num)
  160. return string.reverse(num)
  161. end)
  162. for i = 1,#numbers do
  163. str = string.gsub(str, numbers[i].a, numbers[i].b)
  164. end
  165. return str
  166. end
  167. local function processdiscretionary(str)
  168. str = string.gsub(str, "\\%-", "\\-{}")
  169. return str
  170. end
  171. local function processarbnull(str, scheme)
  172. if scheme == "buckwalter" then
  173. str = string.gsub(str, "(\\arbnull.?)(%b{})", function(tag, body)
  174. body = string.sub(body, 2, -2)
  175. return string.format("P%sP", body)
  176. end)
  177. else
  178. str = string.gsub(str, "(\\arbnull.?)(%b{})", function(tag, body)
  179. body = string.sub(body, 2, -2)
  180. return string.format("O%sO", body)
  181. end)
  182. end
  183. return str
  184. end
  185. local function takeout_abjad_ayah(str)
  186. str = string.gsub(str, "(\\abjad.?)(%b{})", function(tag, body)
  187. body = string.sub(body, 2, -2)
  188. return string.format("%s", body)
  189. end)
  190. str = string.gsub(str, "(\\ayah.?)(%b{})", function(tag, body)
  191. body = string.sub(body, 2, -2)
  192. if tonumber(body) ~= nil and str.len(body) < 4 then
  193. return string.format("(%s)", body)
  194. else
  195. return "<??>"
  196. end
  197. end)
  198. return str
  199. end
  200. local function takeoutcapetc(str)
  201. str = string.gsub(str, "(\\arb.?%[trans%])(%b{})", function(tag, body)
  202. body = string.sub(body, 2, -2)
  203. body = string.gsub(body, "(\\uc%s?)(%b{})", "\\Uc%2")
  204. return string.format("%s{%s}", tag, body)
  205. end)
  206. str = string.gsub(str, "(\\arbup.?)(%b{})", function(tag, body)
  207. body = string.sub(body, 2, -2)
  208. return string.format("%s", body)
  209. end)
  210. str = string.gsub(str, "(\\uc.?)(%b{})", function(tag, body)
  211. body = string.sub(body, 2, -2)
  212. return string.format("%s", body)
  213. end)
  214. str = string.gsub(str, "\\linebreak", "")
  215. str = string.gsub(str, "\\%-", "")
  216. return str
  217. end
  218. local function checkwrnested(str)
  219. for i = 1,#outofarb do
  220. str = gsub(str, dblbkslash * lpeg.Cs(lpeg.P("LR") + lpeg.P("RL")) * cmdargs,
  221. function(prefix, tag, body)
  222. body = string.sub(body, 2, -2)
  223. if string.find(body, "\\"..outofarb[i]) then
  224. return atletter.."\\al@wrong@nesting{}"..atother
  225. else
  226. -- nothing to do, so proceed.
  227. end
  228. end)
  229. end
  230. return str
  231. end
  232. local function takeoutarb(str)
  233. str = checkwrnested(str)
  234. for i = 1,#outofarb do
  235. str = gsub(str, dblbkslash * lpeg.Cs(outofarb[i]) * cmdargs,
  236. function(prefix, tag, body)
  237. body = gsub(body, lpeg.P("\\arb"), "\\@rb")
  238. return string.format("%s%s%s", prefix, tag, body)
  239. end)
  240. end
  241. str = string.gsub(str, "(\\arb%s?)(%b{})", function(tag, body)
  242. body = string.sub(body, 2, -2)
  243. return string.format("%s", body)
  244. end)
  245. str = string.gsub(str, "\\@rb", "\\arb")
  246. str = "\\arb{"..str.."}"
  247. return str
  248. end
  249. local function voc(str, rules)
  250. str = string.gsub(str, "\\arb(%b{})", function(inside)
  251. inside = string.sub(inside, 2, -2)
  252. for i = 1,#hamza do
  253. inside = string.gsub(inside, hamza[i].a, hamza[i].b)
  254. end
  255. if rules == "idgham" then
  256. for i = 1,#tanwin do
  257. inside = string.gsub(inside, tanwin[i].a, tanwin[i].b)
  258. end
  259. else
  260. for i = 1,#tanwineasy do
  261. inside = string.gsub(inside, tanwineasy[i].a, tanwineasy[i].b)
  262. end
  263. end
  264. for i = 1,#trigraphs do
  265. inside = string.gsub(inside, trigraphs[i].a, trigraphs[i].b)
  266. end
  267. if rules == "idgham" then
  268. for i = 1,#idgham do
  269. inside = string.gsub(inside, idgham[i].a, idgham[i].b)
  270. end
  271. end
  272. for i = 1,#digraphs do
  273. inside = string.gsub(inside, digraphs[i].a, digraphs[i].b)
  274. end
  275. for i = 1,#single do
  276. inside = string.gsub(inside, single[i].a, single[i].b)
  277. end
  278. for i = 1,#longv do
  279. inside = string.gsub(inside, longv[i].a, longv[i].b)
  280. end
  281. for i = 1,#shortv do
  282. inside = string.gsub(inside, shortv[i].a, shortv[i].b)
  283. end
  284. for i = 1,#punctuation do
  285. inside = string.gsub(inside, punctuation[i].a, punctuation[i].b)
  286. end
  287. for i = 1,#null do
  288. inside = string.gsub(inside, null[i].a, null[i].b)
  289. end
  290. inside = indnum(inside)
  291. return string.format("\\arabicfont{}%s", inside)
  292. end)
  293. return str
  294. end
  295. local function voceasy(str)
  296. str = string.gsub(str, "\\arb(%b{})", function(inside)
  297. inside = string.sub(inside, 2, -2)
  298. for i = 1,#hamzaeasy do
  299. inside = string.gsub(inside, hamzaeasy[i].a, hamzaeasy[i].b)
  300. end
  301. for i = 1,#tanwineasy do
  302. inside = string.gsub(inside, tanwineasy[i].a, tanwineasy[i].b)
  303. end
  304. for i = 1,#trigraphseasy do
  305. inside = string.gsub(inside, trigraphseasy[i].a, trigraphseasy[i].b)
  306. end
  307. for i = 1,#digraphs do
  308. inside = string.gsub(inside, digraphs[i].a, digraphs[i].b)
  309. end
  310. for i = 1,#single do
  311. inside = string.gsub(inside, single[i].a, single[i].b)
  312. end
  313. for i = 1,#longv do
  314. inside = string.gsub(inside, longv[i].a, longv[i].b)
  315. end
  316. for i = 1,#shortv do
  317. inside = string.gsub(inside, shortv[i].a, shortv[i].b)
  318. end
  319. for i = 1,#punctuation do
  320. inside = string.gsub(inside, punctuation[i].a, punctuation[i].b)
  321. end
  322. for i = 1,#null do
  323. inside = string.gsub(inside, null[i].a, null[i].b)
  324. end
  325. inside = indnum(inside)
  326. return string.format("\\arabicfont{}%s", inside)
  327. end)
  328. return str
  329. end
  330. local function fullvoc(str, rules)
  331. str = string.gsub(str, "\\arb(%b{})", function(inside)
  332. inside = string.sub(inside, 2, -2)
  333. for i = 1,#hamzafv do
  334. inside = string.gsub(inside, hamzafv[i].a, hamzafv[i].b)
  335. end
  336. if rules == "idgham" then
  337. for i = 1,#tanwinfv do
  338. inside = string.gsub(inside, tanwinfv[i].a, tanwinfv[i].b)
  339. end
  340. else
  341. for i = 1,#tanwinfveasy do
  342. inside = string.gsub(inside, tanwinfveasy[i].a, tanwinfveasy[i].b)
  343. end
  344. end
  345. for i = 1,#trigraphsfv do
  346. inside = string.gsub(inside, trigraphsfv[i].a, trigraphsfv[i].b)
  347. end
  348. if rules == "idgham" then
  349. for i = 1,#idgham do
  350. inside = string.gsub(inside, idgham[i].a, idgham[i].b)
  351. end
  352. end
  353. if rules == "idgham" then
  354. for i = 1,#digraphsfvidgham do
  355. inside = string.gsub(inside, digraphsfvidgham[i].a, digraphsfvidgham[i].b)
  356. end
  357. else
  358. for i = 1,#digraphsfv do
  359. inside = string.gsub(inside, digraphsfv[i].a, digraphsfv[i].b)
  360. end
  361. end
  362. for i = 1,#singlefv do
  363. inside = string.gsub(inside, singlefv[i].a, singlefv[i].b)
  364. end
  365. for i = 1,#longv do
  366. inside = string.gsub(inside, longv[i].a, longv[i].b)
  367. end
  368. for i = 1,#shortv do
  369. inside = string.gsub(inside, shortv[i].a, shortv[i].b)
  370. end
  371. for i = 1,#punctuation do
  372. inside = string.gsub(inside, punctuation[i].a, punctuation[i].b)
  373. end
  374. for i = 1,#null do
  375. inside = string.gsub(inside, null[i].a, null[i].b)
  376. end
  377. inside = indnum(inside)
  378. return string.format("\\arabicfont{}%s", inside)
  379. end)
  380. return str
  381. end
  382. local function fullvoceasy(str, rules)
  383. str = string.gsub(str, "\\arb(%b{})", function(inside)
  384. inside = string.sub(inside, 2, -2)
  385. for i = 1,#hamzafveasy do
  386. inside = string.gsub(inside, hamzafveasy[i].a, hamzafveasy[i].b)
  387. end
  388. for i = 1,#tanwinfveasy do
  389. inside = string.gsub(inside, tanwinfveasy[i].a, tanwinfveasy[i].b)
  390. end
  391. for i = 1,#trigraphsfveasy do
  392. inside = string.gsub(inside, trigraphsfveasy[i].a, trigraphsfveasy[i].b)
  393. end
  394. if rules == "nosukun" then
  395. for i = 1,#digraphsfveasy do
  396. inside = string.gsub(inside, digraphsfveasy[i].a, digraphsfveasy[i].b)
  397. end
  398. else
  399. for i = 1,#digraphsfv do
  400. inside = string.gsub(inside, digraphsfv[i].a, digraphsfv[i].b)
  401. end
  402. end
  403. if rules == "nosukun" then
  404. for i = 1,#singlefveasy do
  405. inside = string.gsub(inside, singlefveasy[i].a, singlefveasy[i].b)
  406. end
  407. else
  408. for i = 1,#singlefv do
  409. inside = string.gsub(inside, singlefv[i].a, singlefv[i].b)
  410. end
  411. end
  412. for i = 1,#longv do
  413. inside = string.gsub(inside, longv[i].a, longv[i].b)
  414. end
  415. for i = 1,#shortv do
  416. inside = string.gsub(inside, shortv[i].a, shortv[i].b)
  417. end
  418. for i = 1,#punctuation do
  419. inside = string.gsub(inside, punctuation[i].a, punctuation[i].b)
  420. end
  421. for i = 1,#null do
  422. inside = string.gsub(inside, null[i].a, null[i].b)
  423. end
  424. inside = indnum(inside)
  425. return string.format("\\arabicfont{}%s", inside)
  426. end)
  427. return str
  428. end
  429. local function novoc(str)
  430. str = string.gsub(str, "\\arb(%b{})", function(inside)
  431. inside = string.sub(inside, 2, -2)
  432. for i = 1,#hamza do
  433. inside = string.gsub(inside, hamza[i].a, hamza[i].b)
  434. end
  435. for i = 1,#tanwinnv do
  436. inside = string.gsub(inside, tanwinnv[i].a, tanwinnv[i].b)
  437. end
  438. for i = 1,#trigraphsnv do
  439. inside = string.gsub(inside, trigraphsnv[i].a, trigraphsnv[i].b)
  440. end
  441. for i = 1,#digraphs do
  442. inside = string.gsub(inside, digraphs[i].a, digraphs[i].b)
  443. end
  444. for i = 1,#single do
  445. inside = string.gsub(inside, single[i].a, single[i].b)
  446. end
  447. for i = 1,#longvnv do
  448. inside = string.gsub(inside, longvnv[i].a, longvnv[i].b)
  449. end
  450. for i = 1,#shortvnv do
  451. inside = string.gsub(inside, shortvnv[i].a, shortvnv[i].b)
  452. end
  453. for i = 1,#punctuation do
  454. inside = string.gsub(inside, punctuation[i].a, punctuation[i].b)
  455. end
  456. for i = 1,#null do
  457. inside = string.gsub(inside, null[i].a, null[i].b)
  458. end
  459. inside = indnum(inside)
  460. return string.format("\\arabicfont{}%s", inside)
  461. end)
  462. return str
  463. end
  464. local function novoceasy(str)
  465. str = string.gsub(str, "\\arb(%b{})", function(inside)
  466. inside = string.sub(inside, 2, -2)
  467. for i = 1,#hamzaeasy do
  468. inside = string.gsub(inside, hamzaeasy[i].a, hamzaeasy[i].b)
  469. end
  470. for i = 1,#tanwinnv do
  471. inside = string.gsub(inside, tanwinnv[i].a, tanwinnv[i].b)
  472. end
  473. for i = 1,#trigraphsnv do
  474. inside = string.gsub(inside, trigraphsnv[i].a, trigraphsnv[i].b)
  475. end
  476. for i = 1,#digraphs do
  477. inside = string.gsub(inside, digraphs[i].a, digraphs[i].b)
  478. end
  479. for i = 1,#single do
  480. inside = string.gsub(inside, single[i].a, single[i].b)
  481. end
  482. for i = 1,#longvnv do
  483. inside = string.gsub(inside, longvnv[i].a, longvnv[i].b)
  484. end
  485. for i = 1,#shortvnv do
  486. inside = string.gsub(inside, shortvnv[i].a, shortvnv[i].b)
  487. end
  488. for i = 1,#punctuation do
  489. inside = string.gsub(inside, punctuation[i].a, punctuation[i].b)
  490. end
  491. for i = 1,#null do
  492. inside = string.gsub(inside, null[i].a, null[i].b)
  493. end
  494. inside = indnum(inside)
  495. return string.format("\\arabicfont{}%s", inside)
  496. end)
  497. return str
  498. end
  499. local function transdmg(str, rules)
  500. str = string.gsub(str, "\\arb(%b{})", function(inside)
  501. inside = string.sub(inside, 2, -2)
  502. for i = 1,#hamzatrdmg do
  503. inside = string.gsub(inside, hamzatrdmg[i].a, hamzatrdmg[i].b)
  504. end
  505. for i = 1,#tanwintrdmg do
  506. inside = string.gsub(inside, tanwintrdmg[i].a, tanwintrdmg[i].b)
  507. end
  508. for i = 1,#trigraphstrdmg do
  509. inside = string.gsub(inside, trigraphstrdmg[i].a, trigraphstrdmg[i].b)
  510. end
  511. if rules == "idgham" then
  512. for i = 1,#idghamtrdmg do
  513. inside = string.gsub(inside, idghamtrdmg[i].a, idghamtrdmg[i].b)
  514. end
  515. end
  516. for i = 1,#digraphstrdmg do
  517. inside = string.gsub(inside, digraphstrdmg[i].a, digraphstrdmg[i].b)
  518. end
  519. for i = 1,#singletrdmg do
  520. inside = string.gsub(inside, singletrdmg[i].a, singletrdmg[i].b)
  521. end
  522. for i = 1,#longvtrdmg do
  523. inside = string.gsub(inside, longvtrdmg[i].a, longvtrdmg[i].b)
  524. end
  525. for i = 1,#shortvtrdmg do
  526. inside = string.gsub(inside, shortvtrdmg[i].a, shortvtrdmg[i].b)
  527. end
  528. for i = 1,#punctuationtr do
  529. inside = string.gsub(inside, punctuationtr[i].a, punctuationtr[i].b)
  530. end
  531. for i = 1,#nulltr do
  532. inside = string.gsub(inside, nulltr[i].a, nulltr[i].b)
  533. end
  534. return string.format("\\txtrans{%s}", inside)
  535. end)
  536. return str
  537. end
  538. local function transloc(str)
  539. str = string.gsub(str, "\\arb(%b{})", function(inside)
  540. inside = string.sub(inside, 2, -2)
  541. for i = 1,#hamzatrloc do
  542. inside = string.gsub(inside, hamzatrloc[i].a, hamzatrloc[i].b)
  543. end
  544. for i = 1,#tanwintrloc do
  545. inside = string.gsub(inside, tanwintrloc[i].a, tanwintrloc[i].b)
  546. end
  547. for i = 1,#trigraphstrloc do
  548. inside = string.gsub(inside, trigraphstrloc[i].a, trigraphstrloc[i].b)
  549. end
  550. for i = 1,#digraphstrloc do
  551. inside = string.gsub(inside, digraphstrloc[i].a, digraphstrloc[i].b)
  552. end
  553. for i = 1,#singletrloc do
  554. inside = string.gsub(inside, singletrloc[i].a, singletrloc[i].b)
  555. end
  556. for i = 1,#longvtrloc do
  557. inside = string.gsub(inside, longvtrloc[i].a, longvtrloc[i].b)
  558. end
  559. for i = 1,#shortvtrloc do
  560. inside = string.gsub(inside, shortvtrloc[i].a, shortvtrloc[i].b)
  561. end
  562. for i = 1,#finaltrloc do
  563. inside = string.gsub(inside, finaltrloc[i].a, finaltrloc[i].b)
  564. end
  565. for i = 1,#punctuationtr do
  566. inside = string.gsub(inside, punctuationtr[i].a, punctuationtr[i].b)
  567. end
  568. for i = 1,#nulltr do
  569. inside = string.gsub(inside, nulltr[i].a, nulltr[i].b)
  570. end
  571. return string.format("\\txtrans{%s}", inside)
  572. end)
  573. return str
  574. end
  575. local function transarabica(str)
  576. str = string.gsub(str, "\\arb(%b{})", function(inside)
  577. inside = string.sub(inside, 2, -2)
  578. for i = 1,#hamzatrarabica do
  579. inside = string.gsub(inside, hamzatrarabica[i].a, hamzatrarabica[i].b)
  580. end
  581. for i = 1,#tanwintrloc do
  582. inside = string.gsub(inside, tanwintrloc[i].a, tanwintrloc[i].b)
  583. end
  584. for i = 1,#trigraphstrarabica do
  585. inside = string.gsub(inside, trigraphstrarabica[i].a, trigraphstrarabica[i].b)
  586. end
  587. for i = 1,#digraphstrarabica do
  588. inside = string.gsub(inside, digraphstrarabica[i].a, digraphstrarabica[i].b)
  589. end
  590. for i = 1,#singletrarabica do
  591. inside = string.gsub(inside, singletrarabica[i].a, singletrarabica[i].b)
  592. end
  593. for i = 1,#longvtrarabica do
  594. inside = string.gsub(inside, longvtrarabica[i].a, longvtrarabica[i].b)
  595. end
  596. for i = 1,#shortvtrloc do
  597. inside = string.gsub(inside, shortvtrloc[i].a, shortvtrloc[i].b)
  598. end
  599. for i = 1,#punctuationtr do
  600. inside = string.gsub(inside, punctuationtr[i].a, punctuationtr[i].b)
  601. end
  602. for i = 1,#nulltr do
  603. inside = string.gsub(inside, nulltr[i].a, nulltr[i].b)
  604. end
  605. return string.format("\\txtrans{%s}", inside)
  606. end)
  607. return str
  608. end
  609. local function processbuckw(str)
  610. str = string.gsub(str, "\\arb(%b{})", function(inside)
  611. inside = string.sub(inside, 2, -2)
  612. for i = 1,#buckwalter do
  613. inside = string.gsub(inside, buckwalter[i].a, buckwalter[i].b)
  614. end
  615. return string.format("\\arb{%s}", inside)
  616. end)
  617. return str
  618. end
  619. -- The following functions produce a copy of the original .tex source
  620. -- file in which all arabtex strings are replaced with Unicode
  621. -- equivalents
  622. local utffilesuffix = "_out"
  623. local export_utf = "no"
  624. function al_utffilesuffix(str)
  625. utffilesuffix = str
  626. return true
  627. end
  628. function al_doexport(str)
  629. export_utf = str
  630. return true
  631. end
  632. function al_openstream()
  633. local f = io.open(tex.jobname..utffilesuffix.."_tmp.tex", "a+")
  634. local preamble = io.open(tex.jobname..".tex", "r")
  635. for line in preamble:lines() do
  636. f:write(line, "\n")
  637. if string.find(line, "^%s-\\begin%s?{document}") then
  638. break
  639. end
  640. end
  641. preamble:close()
  642. f:close()
  643. return true
  644. end
  645. local function processarbtoutf(str)
  646. if export_utf ~= "arabverse" then
  647. str = "\\begin{arabexport}"..str
  648. else end
  649. --[[ -- of no use, see above takeout_abjad_ayah()
  650. str = string.gsub(str, "(\\txtrans%s?)(%b{})", function(tag, body)
  651. body = string.sub(body, 2, -2)
  652. body = string.gsub(body, "(\\abjad%s?)(%b{})", function(btag, bbody)
  653. bbody = string.sub(bbody, 2, -2)
  654. return string.format("%s", bbody)
  655. end)
  656. body = string.gsub(body, "(\\ayah%s?)(%b{})", function(btag, bbody)
  657. bbody = string.sub(bbody, 2, -2)
  658. return string.format("(%s)", bbody)
  659. end)
  660. return string.format("%s{%s}", tag, body)
  661. end)
  662. --]]
  663. str = string.gsub(str, "(\\txarb%s?)(%b{})", function(tag, body)
  664. body = string.sub(body, 2, -2)
  665. body = string.gsub(body, "(\\abjad%s?)(%b{})", function(btag, bbody)
  666. bbody = string.sub(bbody, 2, -2)
  667. if tonumber(bbody) ~= nil then
  668. bbody = abjadify(bbody)
  669. return string.format("\\aemph{\\arb[novoc]{%s}}", bbody)
  670. else
  671. return string.format("%s{%s}", btag, bbody)
  672. end
  673. end)
  674. body = string.gsub(body, "(\\arbmark%s?)(%b{})", function(btag, bbody)
  675. bbody = string.sub(bbody, 2, -2)
  676. return string.format("%s[rl]{%s}", btag, bbody)
  677. end)
  678. body = string.gsub(body, "(\\ayah%s?)(%b{})", function(btag, bbody)
  679. bbody = string.sub(bbody, 2, -2)
  680. return string.format("\\arb[novoc]{%s^^^^06dd}", bbody)
  681. end)
  682. return string.format("%s{%s}", tag, body)
  683. end)
  684. str = string.gsub(str, "(\\bayt)%s?(%b{})(%b[])(%b{})", function(tag, argi, argii, argiii)
  685. argi = string.sub(argi, 2, -2)
  686. argii = string.sub(argii, 2, -2)
  687. argiii = string.sub(argiii, 2, -2)
  688. return string.format("%s*{\\arb{%s}}[\\arb{%s}]{\\arb{%s}}", tag, argi, argii, argiii)
  689. end)
  690. str = string.gsub(str, "(\\bayt)%s?(%b{})(%b{})", function(tag, argi, argii)
  691. argi = string.sub(argi, 2, -2)
  692. argii = string.sub(argii, 2, -2)
  693. return string.format("%s*{\\arb{%s}}{\\arb{%s}}", tag, argi, argii)
  694. end)
  695. str = string.gsub(str, "(\\prname)%s?(%b{})", function(tag, body)
  696. body = string.sub(body, 2, -2)
  697. if string.find(body, "\\uc%s?%b{}") then
  698. return string.format("%s*{%s}", tag, body)
  699. else
  700. return string.format("%s{\\arb[trans]{\\uc{%s}}}", tag, body)
  701. end
  702. end)
  703. str = string.gsub(str, "(\\begin%s?{arab})(%b[])", function(tag, body)
  704. if string.find(body, "trans") then
  705. return string.format("\\par\\bgroup\\setLR\\arb%s{", body)
  706. else
  707. return string.format("\\par\\bgroup\\setRL\\arb%s{", body)
  708. end
  709. end)
  710. str = string.gsub(str, "(\\begin%s?{arab})", "\\par\\bgroup\\arbpardir\\arb{")
  711. str = string.gsub(str, "\\end%s?{arab}", "}\\egroup\\par")
  712. -- This does not work, while the following two do. Look into this later.
  713. -- str = gsub(str, lpeg.Cs("\\arb") * spcenc * bsqbrackets^-1 * bcbraces, function(tag, opt, body)
  714. -- body = string.sub(body, 2, -2)
  715. -- return string.format("%s%s\\@al@pr@ob%s\\@al@pr@cb", tag, opt, body)
  716. -- end)
  717. str = string.gsub(str, "(\\arb%s?)(%b[])(%b{})", function(tag, opt, body)
  718. body = string.sub(body, 2, -2)
  719. return string.format("%s%s\\@al@pr@ob%s\\@al@pr@cb", tag, opt, body)
  720. end)
  721. str = string.gsub(str, "(\\arb)%s?(%b{})", function(tag, body)
  722. body = string.sub(body, 2, -2)
  723. return string.format("%s\\@al@pr@ob%s\\@al@pr@cb", tag, body)
  724. end)
  725. str = string.gsub(str, "(\\arbmark)%s?(%b[])(%b{})", function(tag, opt, body)
  726. body = string.sub(body, 2, -2)
  727. return string.format("%s%s\\@al@pr@ob%s\\@al@pr@cb", tag, opt, body)
  728. end)
  729. str = string.gsub(str, "(\\arbmark)%s?(%b{})", function(tag, body)
  730. body = string.sub(body, 2, -2)
  731. return string.format("%s\\@al@pr@ob%s\\@al@pr@cb", tag, body)
  732. end)
  733. str = string.gsub(str, "(\\[Uu]c)%s?(%b{})", function(tag, body)
  734. body = string.sub(body, 2, -2)
  735. return string.format("%s\\@al@pr@ob%s\\@al@pr@cb", tag, body)
  736. end)
  737. str = string.gsub(str, "{", "\\@al@ob")
  738. str = string.gsub(str, "} ", "\\@al@cb@sp")
  739. str = string.gsub(str, "}", "\\@al@cb")
  740. str = string.gsub(str, "\\@al@pr@ob", "{")
  741. str = string.gsub(str, "\\@al@pr@cb", "}")
  742. str = string.gsub(str, "(%b{})", function(body)
  743. body = string.sub(body, 2, -2)
  744. body = string.gsub(body, "(%s?)(\\@al@ob)", "%1{")
  745. body = string.gsub(body, "(\\@al@cb@sp)", "} ")
  746. body = string.gsub(body, "(\\@al@cb)(%s?)", "}%2")
  747. return string.format("{%s}", body)
  748. end)
  749. if export_utf ~= "arabverse" then
  750. str = str.."\\end{arabexport}"
  751. else end
  752. return str
  753. end
  754. function arbtoutf(str)
  755. str = processarbtoutf(str)
  756. str = "\\ArbOutFile{"..str.."}"
  757. str = string.gsub(str, "(\\ArbOutFile)%s?(%b{})", function(tag, body)
  758. body = string.sub(body, 2, -2)
  759. body = gsub(body, lpeg.Cs("\\arb") * arbargs, "}%1%2\\ArbOutFile{")
  760. return string.format("%s{%s}", tag, body)
  761. end)
  762. str = string.gsub(str, "(\\ArbOutFile)%s?(%b{})", function(tag, body)
  763. body = string.sub(body, 2, -2)
  764. body = string.gsub(body, "(\\[Uu]c)%s?(%b{})", "}%1%2\\ArbOutFile{")
  765. return string.format("%s{%s}", tag, body)
  766. end)
  767. str = string.gsub(str, "(\\ArbOutFile)%s?(%b{})", function(tag, body)
  768. body = string.sub(body, 2, -2)
  769. body = gsub(body, lpeg.Cs("\\arbmark") * arbargs, "}%1%2\\ArbOutFile{")
  770. return string.format("%s{%s}", tag, body)
  771. end)
  772. return str
  773. end
  774. function tooutfile(str, nl)
  775. local f = io.open(tex.jobname..utffilesuffix.."_tmp.tex", "a+")
  776. if nl == "newline" then
  777. f:write(str, "\n\n")
  778. else
  779. f:write(str)
  780. end
  781. f:close()
  782. return str
  783. end
  784. function al_closestream()
  785. local f = io.open(tex.jobname..utffilesuffix.."_tmp.tex", "r")
  786. local o = io.open(tex.jobname..utffilesuffix..".tex", "w")
  787. local t = f:read("*a")
  788. t = string.gsub(t, "\\arabicfont{}", "")
  789. t = string.gsub(t, "\\par ", "\n\n")
  790. t = string.gsub(t, "(\\@al@ob)", "{")
  791. t = string.gsub(t, "(\\@al@cb@sp)", "} ")
  792. t = string.gsub(t, "(\\@al@cb)(%s?)", "}")
  793. t = gsub(t, lpeg.Cs("\\begin") * spcenc^-1 * bcbraces * cmdargs,
  794. "\n%1%2%3\n")
  795. t = string.gsub(t, "(\\\\)(%s?)", "%1\n")
  796. t = string.gsub(t, "(\\\\)(\n)(\\end%s?)(%b{})", "%1%3%4")
  797. t = string.gsub(t, "%s-\n(\\begin%s?)(%b{})", "\n%1%2")
  798. t = string.gsub(t, "(\\item)", "\n%1")
  799. t = string.gsub(t, "\n\n(\\item)", "\n%1")
  800. t = string.gsub(t, "(\\end%s?)(%b{})", "%1%2\n")
  801. t = string.gsub(t, "([^\n]%s-)(\\end)%s?(%b{})", "%1\n%2%3")
  802. t = string.gsub(t, "\n\n\n", "\n\n")
  803. t = string.gsub(t, "(\\txarb%s?%{)(\\txarb%s?)(%b{})(%})",
  804. function(tagio, tagii, body, tagic)
  805. body = string.sub(body, 2, -2)
  806. return
  807. string.format("%s%s%s", tagio, body, tagic)
  808. end)
  809. t = string.gsub(t, "(\\prname%s?%*%{)(\\txtrans%s?)(%b{})(%})",
  810. function(tagio, tagii, body, tagic)
  811. body = string.sub(body, 2, -2)
  812. return string.format("%s%s%s", tagio, body, tagic)
  813. end)
  814. if string.find(t, "\\begin%s?{document}.-\\arb%s?[%[%{]")
  815. or
  816. string.find(t, "\\begin%s?{document}.-\\[Uu]c%s?%b{}")
  817. or
  818. string.find(t, "\\begin%s?{document}.-\\abjad%s?%b{}")
  819. or
  820. string.find(t, "\\begin%s?{document}.-\\ayah%s?%b{}")
  821. then
  822. -- issue a warning:
  823. tex.print([[\unexpanded{\PackageWarningNoLine{arabluatex}{]]
  824. ..
  825. [[There are still 'arabtex' strings to be converted. ]]
  826. ..
  827. [[Please open ]] .. tex.jobname .. utffilesuffix .. ".tex" ..
  828. [[ and compile it one more time}}]])
  829. --
  830. else end
  831. t = t.."\n\\end{document}"
  832. io.write(t)
  833. o:write(t)
  834. f:close()
  835. o:close()
  836. os.remove(tex.jobname..utffilesuffix.."_tmp.tex")
  837. return true
  838. end
  839. -- Process standard arabluatex modes:
  840. function processvoc(str, rules, scheme)
  841. str = takeoutarb(str)
  842. str = processarbnull(str, scheme)
  843. str = takeoutcapetc(str)
  844. str = protectarb(str)
  845. str = breakcmd(str)
  846. str = holdcmd(str)
  847. if scheme == "buckwalter" then
  848. str = processbuckw(str)
  849. else end
  850. if rules == "easy" or rules == "easynosukun" then
  851. str = voceasy(str)
  852. elseif rules == "dflt" or rules == "idgham" then
  853. str = voc(str, rules)
  854. else end
  855. str = unprotectarb(str)
  856. if export_utf == "yes" then
  857. tofile = "\\txarb{"..str.."}"
  858. tooutfile(tofile)
  859. elseif export_utf == "arabverse" then
  860. tofile = "\\txarb{"..str.."}"
  861. tooutfile(tofile)
  862. else
  863. return str
  864. end
  865. return ""
  866. end
  867. function processfullvoc(str, rules, scheme)
  868. str = takeoutarb(str)
  869. str = processarbnull(str, scheme)
  870. str = takeoutcapetc(str)
  871. str = protectarb(str)
  872. str = breakcmd(str)
  873. str = holdcmd(str)
  874. if scheme == "buckwalter" then
  875. str = processbuckw(str)
  876. else end
  877. if rules == "easy" then
  878. str = fullvoceasy(str, "sukun")
  879. elseif rules == "easynosukun" then
  880. str = fullvoceasy(str, "nosukun")
  881. elseif rules == "dflt" or rules == "idgham" then
  882. str = fullvoc(str, rules)
  883. else end
  884. str = unprotectarb(str)
  885. if export_utf == "yes" then
  886. tofile = "\\txarb{"..str.."}"
  887. tooutfile(tofile)
  888. elseif export_utf == "arabverse" then
  889. tofile = "\\txarb{"..str.."}"
  890. tooutfile(tofile)
  891. else
  892. return str
  893. end
  894. return ""
  895. end
  896. function processnovoc(str, rules, scheme)
  897. str = takeoutarb(str)
  898. str = processarbnull(str, scheme)
  899. str = takeoutcapetc(str)
  900. str = protectarb(str)
  901. str = breakcmd(str)
  902. str = holdcmd(str)
  903. if scheme == "buckwalter" then
  904. str = processbuckw(str)
  905. else end
  906. if rules == "easy" or rules == "easynosukun" then
  907. str = novoceasy(str)
  908. elseif rules == "dflt" or rules == "idgham" then
  909. str = novoc(str)
  910. else end
  911. str = unprotectarb(str)
  912. if export_utf == "yes" then
  913. tofile = "\\txarb{"..str.."}"
  914. tooutfile(tofile)
  915. elseif export_utf == "arabverse" then
  916. tofile = "\\txarb{"..str.."}"
  917. tooutfile(tofile)
  918. else
  919. return str
  920. end
  921. return ""
  922. end
  923. function processtrans(str, mode, rules, scheme)
  924. str = takeoutarb(str)
  925. str = processdiscretionary(str)
  926. str = processarbnull(str, scheme)
  927. str = takeout_abjad_ayah(str)
  928. str = protectarb(str)
  929. str = breakcmd(str)
  930. str = holdcmd(str)
  931. if scheme == "buckwalter" then
  932. str = processbuckw(str)
  933. end
  934. if mode == "dmg" then
  935. str = transdmg(str, rules)
  936. elseif mode == "loc" then
  937. str = transloc(str)
  938. elseif mode == "arabica" then
  939. str = transarabica(str)
  940. end
  941. str = unprotectarb(str)
  942. if export_utf == "yes" then
  943. tofile = str
  944. tooutfile(tofile)
  945. elseif export_utf == "arabverse" then
  946. tofile = str
  947. tooutfile(tofile)
  948. else
  949. return str
  950. end
  951. return ""
  952. end
  953. function newarbmark(abbr, rtlmk, ltrmk)
  954. abbr = "@"..abbr
  955. rtlmk = "\\arabicfont{}"..rtlmk
  956. table.insert(arbmarks, {a = abbr, b = rtlmk, c = ltrmk})
  957. table.sort(arbmarks, function(a ,b) return(#a.a > #b.a) end)
  958. return true
  959. end
  960. local function isintable(table, element)
  961. for i = 1,#table do
  962. if table[i].a == element then
  963. return true
  964. end
  965. end
  966. return false
  967. end
  968. function processarbmarks(str, dir)
  969. str = "@"..str
  970. if not isintable(arbmarks, str) then
  971. str = "\\LR{<??>}"..atletter.."\\al@wrong@mark{}"..atother
  972. else
  973. if dir == "lr" then
  974. for i = 1,#arbmarks do
  975. str = string.gsub(str, arbmarks[i].a, arbmarks[i].c)
  976. end
  977. elseif dir == "rl" then
  978. for i = 1,#arbmarks do
  979. str = string.gsub(str, arbmarks[i].a, arbmarks[i].b)
  980. end
  981. elseif tex.textdir == "TLT" then
  982. for i = 1,#arbmarks do
  983. str = string.gsub(str, arbmarks[i].a, arbmarks[i].c)
  984. end
  985. else
  986. for i = 1,#arbmarks do
  987. str = string.gsub(str, arbmarks[i].a, arbmarks[i].b)
  988. end
  989. end
  990. end
  991. if export_utf == "yes" then
  992. tofile = str
  993. tooutfile(tofile)
  994. elseif export_utf == "arabverse" then
  995. tofile = str
  996. tooutfile(tofile)
  997. else
  998. return str
  999. end
  1000. return ""
  1001. end
  1002. function uc(str)
  1003. str = string.gsub(str, "(\\txtrans.?)(%b{})", function(tag, body)
  1004. body = string.sub(body, 2, -2)
  1005. return string.format("%s", body)
  1006. end)
  1007. -- Allah and ibn
  1008. str = string.gsub(str, "(al%-lāh)([uai]?)", "{Allāh%2}")
  1009. str = string.gsub(str, "([%'%-]?)(l%-lāh)([uai]?)", "%1{Llāh%3}")
  1010. str = string.gsub(str, "(%s[%(%<%[]?)([i%']?b[n%.])", "%1{%2}")
  1011. for i = 1,#lcuc do
  1012. str = string.gsub(str, "^([%S]-%-[`']?)"..lcuc[i].a, "{%1"..lcuc[i].b.."}")
  1013. end
  1014. for i = 1,#lcuc do
  1015. str = string.gsub(str, "(%s[%(%<%[]?)([%S]-%-[`']?)"..lcuc[i].a, "%1{%2"..lcuc[i].b.."}")
  1016. end
  1017. for i = 1,#lcuc do
  1018. str = string.gsub(str, "^([%S]-%-ʿ)"..lcuc[i].a, "{%1"..lcuc[i].b.."}")
  1019. end
  1020. for i = 1,#lcuc do
  1021. str = string.gsub(str, "(%s[%(%<%[]?)([%S]-%-ʿ)"..lcuc[i].a, "%1{%2"..lcuc[i].b.."}")
  1022. end
  1023. for i = 1,#lcuc do
  1024. str = string.gsub(str, "^([%S]-%-ʾ)"..lcuc[i].a, "{%1"..lcuc[i].b.."}")
  1025. end
  1026. for i = 1,#lcuc do
  1027. str = string.gsub(str, "(%s[%(%<%[]?)([%S]-%-ʾ)"..lcuc[i].a, "%1{%2"..lcuc[i].b.."}")
  1028. end
  1029. for i = 1,#lcuc do
  1030. str = string.gsub(str, "^([`'])"..lcuc[i].a, "{%1"..lcuc[i].b.."}")
  1031. end
  1032. for i = 1,#lcuc do
  1033. str = string.gsub(str, "(%s[%(%<%[]?)([`'])"..lcuc[i].a, "%1{%2"..lcuc[i].b.."}")
  1034. end
  1035. for i = 1,#lcuc do
  1036. str = string.gsub(str, "^(ʾ)"..lcuc[i].a, "{%1"..lcuc[i].b.."}")
  1037. end
  1038. for i = 1,#lcuc do
  1039. str = string.gsub(str, "(%s[%(%<%[]?)(ʾ)"..lcuc[i].a, "%1{%2"..lcuc[i].b.."}")
  1040. end
  1041. for i = 1,#lcuc do
  1042. str = string.gsub(str, "^(ʿ)"..lcuc[i].a, "{%1"..lcuc[i].b.."}")
  1043. end
  1044. for i = 1,#lcuc do
  1045. str = string.gsub(str, "(%s[%(%<%[]?)(ʿ)"..lcuc[i].a, "%1{%2"..lcuc[i].b.."}")
  1046. end
  1047. for i = 1,#lcuc do
  1048. str = string.gsub(str, "^"..lcuc[i].a, lcuc[i].b)
  1049. end
  1050. for i = 1,#lcuc do
  1051. str = string.gsub(str, "(%s[%(%<%[]?)"..lcuc[i].a, "%1"..lcuc[i].b)
  1052. end
  1053. if export_utf == "yes" then
  1054. tofile = "\\txtrans{"..str.."}"
  1055. tooutfile(tofile)
  1056. elseif export_utf == "arabverse" then
  1057. tofile = "\\txtrans{"..str.."}"
  1058. tooutfile(tofile)
  1059. else
  1060. return "\\txtrans{"..str.."}"
  1061. end
  1062. return ""
  1063. end
  1064. -- this function is adapted from an 'obsolete project' of Khaled
  1065. -- Hosny's that dates back to 2010. Thanks to him.
  1066. -- See https://github.com/khaledhosny/lualatex-arabic
  1067. function abjadify(n)
  1068. local abjadnum = ""
  1069. n = tonumber(n)
  1070. if n >= 1000 then
  1071. for i=1,math.floor(n/1000) do
  1072. abjadnum = abjadnum .. abjad[4][1]
  1073. end
  1074. n = math.fmod(n,1000)
  1075. end
  1076. if n >= 100 then
  1077. abjadnum = abjadnum .. abjad[3][math.floor(n/100)]
  1078. n = math.fmod(n, 100)
  1079. end
  1080. if n >= 10 then
  1081. abjadnum = abjadnum .. abjad[2][math.floor(n/10)]
  1082. n = math.fmod(n, 10)
  1083. end
  1084. if n >= 1 then
  1085. abjadnum = abjadnum .. abjad[1][math.floor(n/1)]
  1086. end
  1087. return "\\arb[novoc]{"..abjadnum.."}"
  1088. end
  1089. function abraces(str)
  1090. if tex.textdir == "TRT" then
  1091. str = "\\}"..str.."\\{"
  1092. elseif tex.textdir == "TLT" then
  1093. str = "\\{"..str.."\\}"
  1094. end
  1095. return str
  1096. end
  1097. function aemph(str, opt)
  1098. if tex.textdir == "TRT" then
  1099. str = "$\\overline{\\text{\\textdir TRT{}"..str.."}}$"
  1100. elseif tex.textdir == "TLT" then
  1101. if opt == "over" then
  1102. str = "$\\overline{\\text{"..str.."}}$"
  1103. else
  1104. str = "$\\underline{\\text{"..str.."}}$"
  1105. end
  1106. end
  1107. return str
  1108. end
  1109. function ayah(str)
  1110. if tonumber(str) ~= nil and str.len(str) < 4 then
  1111. if tex.textdir == "TRT" then
  1112. str = "\\arb[novoc]{"..str.."^^^^06dd}"
  1113. elseif tex.textdir == "TLT" then
  1114. str = "\\arb[trans]{("..str..")}"
  1115. end
  1116. return str
  1117. else
  1118. return "\\LR{<??>}"
  1119. end
  1120. end