arabluatex.lua 36 KB

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