liblouis-rb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +520 -0
  3. data/README.md +100 -0
  4. data/Rakefile +80 -0
  5. data/ext/liblouis/braille_character.c +200 -0
  6. data/ext/liblouis/braille_table.c +198 -0
  7. data/ext/liblouis/braille_text.c +223 -0
  8. data/ext/liblouis/extconf.rb +73 -0
  9. data/ext/liblouis/liblouis.c +168 -0
  10. data/ext/liblouis/liblouis_ext.h +49 -0
  11. data/ext/liblouis/table_source.c +161 -0
  12. data/ext/liblouis/translation.c +443 -0
  13. data/liblouis-rb.gemspec +49 -0
  14. data/spec/liblouis_spec.rb +62 -0
  15. data/test/integration/packaging_test.rb +82 -0
  16. data/test/table_source_cases.rb +9 -0
  17. data/test/test_braille_character.rb +62 -0
  18. data/test/test_braille_table.rb +379 -0
  19. data/test/test_braille_text.rb +30 -0
  20. data/test/test_helper.rb +7 -0
  21. data/test/translation_cases.rb +33 -0
  22. data/vendor/liblouis/COPYING +674 -0
  23. data/vendor/liblouis/COPYING.LESSER +502 -0
  24. data/vendor/liblouis/configure.ac +290 -0
  25. data/vendor/liblouis/liblouis/commonTranslationFunctions.c +95 -0
  26. data/vendor/liblouis/liblouis/compileTranslationTable.c +5515 -0
  27. data/vendor/liblouis/liblouis/internal.h +781 -0
  28. data/vendor/liblouis/liblouis/liblouis.h.in +514 -0
  29. data/vendor/liblouis/liblouis/logging.c +233 -0
  30. data/vendor/liblouis/liblouis/lou_backTranslateString.c +1855 -0
  31. data/vendor/liblouis/liblouis/lou_translateString.c +4177 -0
  32. data/vendor/liblouis/liblouis/maketable.c +463 -0
  33. data/vendor/liblouis/liblouis/metadata.c +1258 -0
  34. data/vendor/liblouis/liblouis/pattern.c +1632 -0
  35. data/vendor/liblouis/liblouis/utils.c +448 -0
  36. data/vendor/liblouis/tables/Es-Es-G0.utb +248 -0
  37. data/vendor/liblouis/tables/IPA-unicode-range.uti +200 -0
  38. data/vendor/liblouis/tables/IPA.utb +164 -0
  39. data/vendor/liblouis/tables/Lv-Lv-g1.utb +509 -0
  40. data/vendor/liblouis/tables/Makefile.am +503 -0
  41. data/vendor/liblouis/tables/Pl-Pl-g1.utb +312 -0
  42. data/vendor/liblouis/tables/README +6 -0
  43. data/vendor/liblouis/tables/afr-za-g1.ctb +63 -0
  44. data/vendor/liblouis/tables/afr-za-g2.ctb +1050 -0
  45. data/vendor/liblouis/tables/akk-borger.utb +997 -0
  46. data/vendor/liblouis/tables/akk.utb +1002 -0
  47. data/vendor/liblouis/tables/ancient-languages-borger.utb +114 -0
  48. data/vendor/liblouis/tables/ancient-languages-us.utb +114 -0
  49. data/vendor/liblouis/tables/ar-ar-comp8.utb +293 -0
  50. data/vendor/liblouis/tables/ar-ar-g1-core.uti +291 -0
  51. data/vendor/liblouis/tables/ar-ar-g1.utb +26 -0
  52. data/vendor/liblouis/tables/ar-ar-g2.ctb +447 -0
  53. data/vendor/liblouis/tables/ar-ar-math.uti +501 -0
  54. data/vendor/liblouis/tables/ar.tbl +17 -0
  55. data/vendor/liblouis/tables/as-in-g1.utb +27 -0
  56. data/vendor/liblouis/tables/as.tbl +18 -0
  57. data/vendor/liblouis/tables/aw-in-g1.utb +27 -0
  58. data/vendor/liblouis/tables/awa.tbl +18 -0
  59. data/vendor/liblouis/tables/ba.utb +64 -0
  60. data/vendor/liblouis/tables/be-in-g1.utb +27 -0
  61. data/vendor/liblouis/tables/bel-comp.utb +42 -0
  62. data/vendor/liblouis/tables/bel-detailed.utb +32 -0
  63. data/vendor/liblouis/tables/bel.utb +61 -0
  64. data/vendor/liblouis/tables/bengali.cti +238 -0
  65. data/vendor/liblouis/tables/bg.ctb +215 -0
  66. data/vendor/liblouis/tables/bg.dis +84 -0
  67. data/vendor/liblouis/tables/bg.tbl +21 -0
  68. data/vendor/liblouis/tables/bg.utb +454 -0
  69. data/vendor/liblouis/tables/bh.ctb +24 -0
  70. data/vendor/liblouis/tables/bh.tbl +17 -0
  71. data/vendor/liblouis/tables/bn.tbl +18 -0
  72. data/vendor/liblouis/tables/bo.ctb +184 -0
  73. data/vendor/liblouis/tables/bo.tbl +21 -0
  74. data/vendor/liblouis/tables/boxes.ctb +162 -0
  75. data/vendor/liblouis/tables/br-in-g1.utb +27 -0
  76. data/vendor/liblouis/tables/bra.tbl +18 -0
  77. data/vendor/liblouis/tables/braille-patterns.cti +287 -0
  78. data/vendor/liblouis/tables/ca-chardefs.cti +225 -0
  79. data/vendor/liblouis/tables/ca-g1.ctb +46 -0
  80. data/vendor/liblouis/tables/ca.tbl +18 -0
  81. data/vendor/liblouis/tables/chr-us-g1.ctb +180 -0
  82. data/vendor/liblouis/tables/ckb-chardefs.cti +219 -0
  83. data/vendor/liblouis/tables/ckb-g1.ctb +31 -0
  84. data/vendor/liblouis/tables/ckb-translation.cti +131 -0
  85. data/vendor/liblouis/tables/ckb.tbl +18 -0
  86. data/vendor/liblouis/tables/compress.cti +44 -0
  87. data/vendor/liblouis/tables/controlchars.cti +27 -0
  88. data/vendor/liblouis/tables/cop-eg-comp8.utb +255 -0
  89. data/vendor/liblouis/tables/cop.utb +231 -0
  90. data/vendor/liblouis/tables/corrections.cti +47 -0
  91. data/vendor/liblouis/tables/countries.cti +263 -0
  92. data/vendor/liblouis/tables/critical-apparatus.uti +54 -0
  93. data/vendor/liblouis/tables/cs-chardefs.cti +385 -0
  94. data/vendor/liblouis/tables/cs-comp8.utb +405 -0
  95. data/vendor/liblouis/tables/cs-g1.ctb +37 -0
  96. data/vendor/liblouis/tables/cs-translation.cti +63 -0
  97. data/vendor/liblouis/tables/cs.tbl +20 -0
  98. data/vendor/liblouis/tables/cuneiform-transliterated-compact.utb +432 -0
  99. data/vendor/liblouis/tables/cuneiform-transliterated.utb +160 -0
  100. data/vendor/liblouis/tables/cy-cy-g1.utb +487 -0
  101. data/vendor/liblouis/tables/cy-cy-g2.ctb +199 -0
  102. data/vendor/liblouis/tables/cy.tbl +19 -0
  103. data/vendor/liblouis/tables/da-dk-6miscChars.cti +385 -0
  104. data/vendor/liblouis/tables/da-dk-6miscChars_1993.cti +412 -0
  105. data/vendor/liblouis/tables/da-dk-8miscChars.cti +90 -0
  106. data/vendor/liblouis/tables/da-dk-8miscChars_1993.cti +102 -0
  107. data/vendor/liblouis/tables/da-dk-g08.ctb +290 -0
  108. data/vendor/liblouis/tables/da-dk-g08_1993.ctb +331 -0
  109. data/vendor/liblouis/tables/da-dk-g16-lit_1993.ctb +294 -0
  110. data/vendor/liblouis/tables/da-dk-g16.ctb +289 -0
  111. data/vendor/liblouis/tables/da-dk-g16_1993.ctb +305 -0
  112. data/vendor/liblouis/tables/da-dk-g18.ctb +545 -0
  113. data/vendor/liblouis/tables/da-dk-g18_1993.ctb +563 -0
  114. data/vendor/liblouis/tables/da-dk-g2.dic +7439 -0
  115. data/vendor/liblouis/tables/da-dk-g26-lit_1993.ctb +898 -0
  116. data/vendor/liblouis/tables/da-dk-g26.ctb +1345 -0
  117. data/vendor/liblouis/tables/da-dk-g26_1993.ctb +1127 -0
  118. data/vendor/liblouis/tables/da-dk-g26l-lit_1993.ctb +588 -0
  119. data/vendor/liblouis/tables/da-dk-g26l_1993.ctb +604 -0
  120. data/vendor/liblouis/tables/da-dk-g28.ctb +2426 -0
  121. data/vendor/liblouis/tables/da-dk-g28_1993.ctb +2063 -0
  122. data/vendor/liblouis/tables/da-dk-g28l_1993.ctb +1594 -0
  123. data/vendor/liblouis/tables/da-dk-octobraille.dis +316 -0
  124. data/vendor/liblouis/tables/da-dk-octobraille_1993.dis +313 -0
  125. data/vendor/liblouis/tables/de-accents-detailed.cti +214 -0
  126. data/vendor/liblouis/tables/de-accents.cti +214 -0
  127. data/vendor/liblouis/tables/de-chardefs6.cti +289 -0
  128. data/vendor/liblouis/tables/de-chardefs8.cti +278 -0
  129. data/vendor/liblouis/tables/de-chess.ctb +37 -0
  130. data/vendor/liblouis/tables/de-comp6.utb +226 -0
  131. data/vendor/liblouis/tables/de-de-comp8.ctb +492 -0
  132. data/vendor/liblouis/tables/de-de.dis +331 -0
  133. data/vendor/liblouis/tables/de-eurobrl6.dis +101 -0
  134. data/vendor/liblouis/tables/de-eurobrl6u.dis +96 -0
  135. data/vendor/liblouis/tables/de-g0-core.uti +732 -0
  136. data/vendor/liblouis/tables/de-g0-detailed.utb +84 -0
  137. data/vendor/liblouis/tables/de-g0.utb +57 -0
  138. data/vendor/liblouis/tables/de-g1-core-patterns.dic +4863 -0
  139. data/vendor/liblouis/tables/de-g1-core.cti +67 -0
  140. data/vendor/liblouis/tables/de-g1-detailed.ctb +79 -0
  141. data/vendor/liblouis/tables/de-g1.ctb +54 -0
  142. data/vendor/liblouis/tables/de-g2-core-patterns.dic +26711 -0
  143. data/vendor/liblouis/tables/de-g2-core.cti +607 -0
  144. data/vendor/liblouis/tables/de-g2-detailed.ctb +60 -0
  145. data/vendor/liblouis/tables/de-g2.ctb +57 -0
  146. data/vendor/liblouis/tables/devanagari.cti +325 -0
  147. data/vendor/liblouis/tables/digits6Dots.uti +30 -0
  148. data/vendor/liblouis/tables/digits6DotsPlusDot6.uti +30 -0
  149. data/vendor/liblouis/tables/digits8Dots.uti +30 -0
  150. data/vendor/liblouis/tables/dra.ctb +23 -0
  151. data/vendor/liblouis/tables/dra.tbl +21 -0
  152. data/vendor/liblouis/tables/el.ctb +775 -0
  153. data/vendor/liblouis/tables/en-GB-g2.ctb +829 -0
  154. data/vendor/liblouis/tables/en-chardefs.cti +193 -0
  155. data/vendor/liblouis/tables/en-chess.ctb +37 -0
  156. data/vendor/liblouis/tables/en-g3-patterns.dic +11194 -0
  157. data/vendor/liblouis/tables/en-g3.ctb +2261 -0
  158. data/vendor/liblouis/tables/en-gb-comp8.ctb +282 -0
  159. data/vendor/liblouis/tables/en-gb-g1.utb +527 -0
  160. data/vendor/liblouis/tables/en-in-g1.ctb +162 -0
  161. data/vendor/liblouis/tables/en-nabcc.utb +166 -0
  162. data/vendor/liblouis/tables/en-nz-g1.utb +65 -0
  163. data/vendor/liblouis/tables/en-nz-g2.ctb +46 -0
  164. data/vendor/liblouis/tables/en-ueb-chardefs.uti +938 -0
  165. data/vendor/liblouis/tables/en-ueb-g1.ctb +167 -0
  166. data/vendor/liblouis/tables/en-ueb-g2.ctb +3925 -0
  167. data/vendor/liblouis/tables/en-ueb-math.ctb +71 -0
  168. data/vendor/liblouis/tables/en-us-brf.dis +102 -0
  169. data/vendor/liblouis/tables/en-us-comp6.ctb +149 -0
  170. data/vendor/liblouis/tables/en-us-comp8-ext.utb +626 -0
  171. data/vendor/liblouis/tables/en-us-comp8.ctb +62 -0
  172. data/vendor/liblouis/tables/en-us-compbrl.uti +69 -0
  173. data/vendor/liblouis/tables/en-us-emphasis.uti +45 -0
  174. data/vendor/liblouis/tables/en-us-g1.ctb +199 -0
  175. data/vendor/liblouis/tables/en-us-g2.ctb +1081 -0
  176. data/vendor/liblouis/tables/en-us-interline.ctb +1126 -0
  177. data/vendor/liblouis/tables/en-us-mathtext.ctb +880 -0
  178. data/vendor/liblouis/tables/en_CA.ctb +195 -0
  179. data/vendor/liblouis/tables/en_CA.tbl +21 -0
  180. data/vendor/liblouis/tables/en_GB.tbl +26 -0
  181. data/vendor/liblouis/tables/en_US-comp8-ext.tbl +15 -0
  182. data/vendor/liblouis/tables/en_US.tbl +26 -0
  183. data/vendor/liblouis/tables/eo-g1-x-system.ctb +85 -0
  184. data/vendor/liblouis/tables/eo-g1.ctb +165 -0
  185. data/vendor/liblouis/tables/eo.tbl +14 -0
  186. data/vendor/liblouis/tables/es-chardefs.cti +206 -0
  187. data/vendor/liblouis/tables/es-g1.ctb +36 -0
  188. data/vendor/liblouis/tables/es-g2.ctb +955 -0
  189. data/vendor/liblouis/tables/es-new.dis +284 -0
  190. data/vendor/liblouis/tables/es-no.utb +79 -0
  191. data/vendor/liblouis/tables/es-old.dis +284 -0
  192. data/vendor/liblouis/tables/es.tbl +19 -0
  193. data/vendor/liblouis/tables/et-6dot.utb +269 -0
  194. data/vendor/liblouis/tables/et-g0.utb +139 -0
  195. data/vendor/liblouis/tables/ethio-g1.ctb +335 -0
  196. data/vendor/liblouis/tables/eurodefs.cti +107 -0
  197. data/vendor/liblouis/tables/fa-ir-comp8.ctb +250 -0
  198. data/vendor/liblouis/tables/fa-ir-g1.utb +311 -0
  199. data/vendor/liblouis/tables/fi-fi-8dot.ctb +278 -0
  200. data/vendor/liblouis/tables/fi.utb +354 -0
  201. data/vendor/liblouis/tables/fil-g2.ctb +491 -0
  202. data/vendor/liblouis/tables/fr-bfu-comp6-puncs-math.uti +351 -0
  203. data/vendor/liblouis/tables/fr-bfu-comp6.utb +238 -0
  204. data/vendor/liblouis/tables/fr-bfu-comp68.cti +251 -0
  205. data/vendor/liblouis/tables/fr-bfu-comp8.utb +323 -0
  206. data/vendor/liblouis/tables/fr-bfu-g2.ctb +4644 -0
  207. data/vendor/liblouis/tables/ga-g1.utb +95 -0
  208. data/vendor/liblouis/tables/ga-g2.ctb +231 -0
  209. data/vendor/liblouis/tables/gd.ctb +123 -0
  210. data/vendor/liblouis/tables/gd.tbl +21 -0
  211. data/vendor/liblouis/tables/gez.tbl +21 -0
  212. data/vendor/liblouis/tables/gon.ctb +25 -0
  213. data/vendor/liblouis/tables/gon.tbl +17 -0
  214. data/vendor/liblouis/tables/gr-pl-comp8.uti +256 -0
  215. data/vendor/liblouis/tables/grc-international-common.uti +104 -0
  216. data/vendor/liblouis/tables/grc-international-composed.uti +268 -0
  217. data/vendor/liblouis/tables/grc-international-decomposed.uti +268 -0
  218. data/vendor/liblouis/tables/grc-international-en-composed.utb +54 -0
  219. data/vendor/liblouis/tables/grc-international-en.utb +206 -0
  220. data/vendor/liblouis/tables/grc-international-es.utb +228 -0
  221. data/vendor/liblouis/tables/gu-in-g1.utb +27 -0
  222. data/vendor/liblouis/tables/gu.tbl +18 -0
  223. data/vendor/liblouis/tables/gujarati.cti +221 -0
  224. data/vendor/liblouis/tables/gurumuki.cti +393 -0
  225. data/vendor/liblouis/tables/haw-us-g1.ctb +54 -0
  226. data/vendor/liblouis/tables/hbo-cantillated-rules.uti +71 -0
  227. data/vendor/liblouis/tables/hbo-cantillated.utb +109 -0
  228. data/vendor/liblouis/tables/hbo-common-rules.uti +152 -0
  229. data/vendor/liblouis/tables/hbo-ihbc-rules.uti +58 -0
  230. data/vendor/liblouis/tables/hbo-slim-rules.uti +68 -0
  231. data/vendor/liblouis/tables/hbo-slim.utb +100 -0
  232. data/vendor/liblouis/tables/hbo.utb +107 -0
  233. data/vendor/liblouis/tables/he-IL-comp8.utb +464 -0
  234. data/vendor/liblouis/tables/he-IL.utb +406 -0
  235. data/vendor/liblouis/tables/he-common-consonants.uti +102 -0
  236. data/vendor/liblouis/tables/he-common-vowels-ihbc.uti +161 -0
  237. data/vendor/liblouis/tables/hi-in-g1.utb +27 -0
  238. data/vendor/liblouis/tables/hi.tbl +18 -0
  239. data/vendor/liblouis/tables/hr-chardefs.cti +278 -0
  240. data/vendor/liblouis/tables/hr-comp8.tbl +21 -0
  241. data/vendor/liblouis/tables/hr-comp8.utb +239 -0
  242. data/vendor/liblouis/tables/hr-digits.uti +40 -0
  243. data/vendor/liblouis/tables/hr-g1.ctb +36 -0
  244. data/vendor/liblouis/tables/hr-g1.tbl +9 -0
  245. data/vendor/liblouis/tables/hr-translation.cti +364 -0
  246. data/vendor/liblouis/tables/ht-frenchcompatibility.uti +61 -0
  247. data/vendor/liblouis/tables/ht-g1.utb +114 -0
  248. data/vendor/liblouis/tables/hu-backtranslate-correction.dis +38 -0
  249. data/vendor/liblouis/tables/hu-backtranslate-word-corrections.cti +4293 -0
  250. data/vendor/liblouis/tables/hu-chardefs.cti +298 -0
  251. data/vendor/liblouis/tables/hu-exceptionwords.cti +3204 -0
  252. data/vendor/liblouis/tables/hu-hu-comp8.ctb +183 -0
  253. data/vendor/liblouis/tables/hu-hu-g1.ctb +129 -0
  254. data/vendor/liblouis/tables/hu-hu-g1_braille_input.cti +486 -0
  255. data/vendor/liblouis/tables/hu-hu-g2.ctb +270 -0
  256. data/vendor/liblouis/tables/hu-hu-g2_exceptions.cti +1164 -0
  257. data/vendor/liblouis/tables/hy.ctb +121 -0
  258. data/vendor/liblouis/tables/hy.tbl +21 -0
  259. data/vendor/liblouis/tables/hyph_cs_CZ.dic +3637 -0
  260. data/vendor/liblouis/tables/hyph_da_DK.dic +8896 -0
  261. data/vendor/liblouis/tables/hyph_de_DE.dic +5799 -0
  262. data/vendor/liblouis/tables/hyph_en_US.dic +5537 -0
  263. data/vendor/liblouis/tables/hyph_eo.dic +1024 -0
  264. data/vendor/liblouis/tables/hyph_es_ES.dic +877 -0
  265. data/vendor/liblouis/tables/hyph_fr_FR.dic +1067 -0
  266. data/vendor/liblouis/tables/hyph_hu_HU.dic +98519 -0
  267. data/vendor/liblouis/tables/hyph_it_IT.dic +410 -0
  268. data/vendor/liblouis/tables/hyph_nb_NO.dic +27142 -0
  269. data/vendor/liblouis/tables/hyph_nl_NL.dic +12725 -0
  270. data/vendor/liblouis/tables/hyph_nn_NO.dic +27142 -0
  271. data/vendor/liblouis/tables/hyph_pl_PL.dic +4074 -0
  272. data/vendor/liblouis/tables/hyph_pt_PT.dic +308 -0
  273. data/vendor/liblouis/tables/hyph_ru.dic +6480 -0
  274. data/vendor/liblouis/tables/hyph_sv_SE.dic +4697 -0
  275. data/vendor/liblouis/tables/is-chardefs6.cti +170 -0
  276. data/vendor/liblouis/tables/is-chardefs8.cti +293 -0
  277. data/vendor/liblouis/tables/is.ctb +157 -0
  278. data/vendor/liblouis/tables/is.tbl +18 -0
  279. data/vendor/liblouis/tables/it-it-comp6.utb +404 -0
  280. data/vendor/liblouis/tables/it-it-comp8.utb +663 -0
  281. data/vendor/liblouis/tables/iu-ca-g1.ctb +236 -0
  282. data/vendor/liblouis/tables/ja-kantenji-ucs2.utb +11448 -0
  283. data/vendor/liblouis/tables/ja-kantenji.utb +53 -0
  284. data/vendor/liblouis/tables/ja-rokutenkanji.utb +8710 -0
  285. data/vendor/liblouis/tables/ka-in-g1.utb +27 -0
  286. data/vendor/liblouis/tables/ka.utb +128 -0
  287. data/vendor/liblouis/tables/kannada.cti +282 -0
  288. data/vendor/liblouis/tables/kh-in-g1.utb +26 -0
  289. data/vendor/liblouis/tables/kha.tbl +18 -0
  290. data/vendor/liblouis/tables/kk.utb +77 -0
  291. data/vendor/liblouis/tables/km-g1.utb +412 -0
  292. data/vendor/liblouis/tables/kmr.tbl +108 -0
  293. data/vendor/liblouis/tables/kn.tbl +18 -0
  294. data/vendor/liblouis/tables/ko-2006-g1.ctb +49 -0
  295. data/vendor/liblouis/tables/ko-2006-g2.ctb +53 -0
  296. data/vendor/liblouis/tables/ko-2006.cti +190 -0
  297. data/vendor/liblouis/tables/ko-chars.cti +15140 -0
  298. data/vendor/liblouis/tables/ko-g1-rules.cti +634 -0
  299. data/vendor/liblouis/tables/ko-g1.ctb +48 -0
  300. data/vendor/liblouis/tables/ko-g2-rules.cti +9263 -0
  301. data/vendor/liblouis/tables/ko-g2.ctb +52 -0
  302. data/vendor/liblouis/tables/ko.cti +223 -0
  303. data/vendor/liblouis/tables/kok.ctb +24 -0
  304. data/vendor/liblouis/tables/kok.tbl +17 -0
  305. data/vendor/liblouis/tables/kru.ctb +24 -0
  306. data/vendor/liblouis/tables/kru.tbl +17 -0
  307. data/vendor/liblouis/tables/ks-in-g1.utb +27 -0
  308. data/vendor/liblouis/tables/latinLetterDef6Dots.uti +78 -0
  309. data/vendor/liblouis/tables/latinLetterDef8Dots.uti +75 -0
  310. data/vendor/liblouis/tables/latinLowercase.uti +389 -0
  311. data/vendor/liblouis/tables/latinUppercaseComp6.uti +78 -0
  312. data/vendor/liblouis/tables/lg-ug-g1.utb +60 -0
  313. data/vendor/liblouis/tables/litdigits6Dots.uti +30 -0
  314. data/vendor/liblouis/tables/litdigits6DotsPlusDot6.uti +30 -0
  315. data/vendor/liblouis/tables/lo-g1.utb +3127 -0
  316. data/vendor/liblouis/tables/loweredDigits6Dots.uti +30 -0
  317. data/vendor/liblouis/tables/loweredDigits8Dots.uti +30 -0
  318. data/vendor/liblouis/tables/lt-6dot.utb +308 -0
  319. data/vendor/liblouis/tables/lt-8dot.utb +281 -0
  320. data/vendor/liblouis/tables/lt.ctb +313 -0
  321. data/vendor/liblouis/tables/lv.tbl +22 -0
  322. data/vendor/liblouis/tables/maketablelist.sh +52 -0
  323. data/vendor/liblouis/tables/malayalam.cti +674 -0
  324. data/vendor/liblouis/tables/mao-nz-g1.ctb +65 -0
  325. data/vendor/liblouis/tables/marburg_single_cell_defs.cti +66 -0
  326. data/vendor/liblouis/tables/marburg_unicode_defs.cti +297 -0
  327. data/vendor/liblouis/tables/mk-g1.utb +240 -0
  328. data/vendor/liblouis/tables/ml-in-g1.utb +27 -0
  329. data/vendor/liblouis/tables/ml.tbl +21 -0
  330. data/vendor/liblouis/tables/mn-MN-common.cti +110 -0
  331. data/vendor/liblouis/tables/mn-MN-g1.utb +52 -0
  332. data/vendor/liblouis/tables/mn-MN-g2.ctb +50 -0
  333. data/vendor/liblouis/tables/mn-in-g1.utb +27 -0
  334. data/vendor/liblouis/tables/mni.tbl +18 -0
  335. data/vendor/liblouis/tables/mr-in-g1.utb +27 -0
  336. data/vendor/liblouis/tables/mr.tbl +18 -0
  337. data/vendor/liblouis/tables/ms-my-g2.ctb +4897 -0
  338. data/vendor/liblouis/tables/mt.ctb +114 -0
  339. data/vendor/liblouis/tables/mt.tbl +21 -0
  340. data/vendor/liblouis/tables/mun.ctb +24 -0
  341. data/vendor/liblouis/tables/mun.tbl +17 -0
  342. data/vendor/liblouis/tables/mwr.ctb +24 -0
  343. data/vendor/liblouis/tables/mwr.tbl +17 -0
  344. data/vendor/liblouis/tables/my-g1.utb +771 -0
  345. data/vendor/liblouis/tables/my-g2.ctb +3805 -0
  346. data/vendor/liblouis/tables/ne.ctb +22 -0
  347. data/vendor/liblouis/tables/ne.tbl +18 -0
  348. data/vendor/liblouis/tables/nemethdefs.cti +382 -0
  349. data/vendor/liblouis/tables/nl-BE.dis +532 -0
  350. data/vendor/liblouis/tables/nl-NL-g0.utb.in +646 -0
  351. data/vendor/liblouis/tables/nl-chardefs.uti.in +455 -0
  352. data/vendor/liblouis/tables/nl-comp8.utb +411 -0
  353. data/vendor/liblouis/tables/nl-print.dis +551 -0
  354. data/vendor/liblouis/tables/nl-unicode.dis +540 -0
  355. data/vendor/liblouis/tables/no-no-8dot-fallback-6dot-g0.utb +59 -0
  356. data/vendor/liblouis/tables/no-no-8dot.utb +629 -0
  357. data/vendor/liblouis/tables/no-no-braillo-047-01.dis +247 -0
  358. data/vendor/liblouis/tables/no-no-chardefs6.uti +305 -0
  359. data/vendor/liblouis/tables/no-no-comp8.ctb +323 -0
  360. data/vendor/liblouis/tables/no-no-cyrillic6dot.uti +95 -0
  361. data/vendor/liblouis/tables/no-no-g0.utb +320 -0
  362. data/vendor/liblouis/tables/no-no-g1.ctb +272 -0
  363. data/vendor/liblouis/tables/no-no-g2.ctb +737 -0
  364. data/vendor/liblouis/tables/no-no-g3.ctb +3597 -0
  365. data/vendor/liblouis/tables/no-no-generic.ctb +295 -0
  366. data/vendor/liblouis/tables/no-no-generic.dis +295 -0
  367. data/vendor/liblouis/tables/no-no-latinLetterDef6Dots_diacritics.uti +852 -0
  368. data/vendor/liblouis/tables/no-no.dis +291 -0
  369. data/vendor/liblouis/tables/np-in-g1.utb +27 -0
  370. data/vendor/liblouis/tables/nso-za-g1.utb +38 -0
  371. data/vendor/liblouis/tables/nso-za-g2.ctb +38 -0
  372. data/vendor/liblouis/tables/ny-mw.utb +70 -0
  373. data/vendor/liblouis/tables/or-in-g1.utb +27 -0
  374. data/vendor/liblouis/tables/or.tbl +18 -0
  375. data/vendor/liblouis/tables/oriya.cti +238 -0
  376. data/vendor/liblouis/tables/ovd-6g0.utb +64 -0
  377. data/vendor/liblouis/tables/ovd-8g0.utb +81 -0
  378. data/vendor/liblouis/tables/pa.tbl +18 -0
  379. data/vendor/liblouis/tables/pi.ctb +24 -0
  380. data/vendor/liblouis/tables/pi.tbl +17 -0
  381. data/vendor/liblouis/tables/pl-pl-comp8.ctb +658 -0
  382. data/vendor/liblouis/tables/pl.tbl +12 -0
  383. data/vendor/liblouis/tables/printables.cti +70 -0
  384. data/vendor/liblouis/tables/pt-comp6.utb +299 -0
  385. data/vendor/liblouis/tables/pt-pt-comp8.ctb +395 -0
  386. data/vendor/liblouis/tables/pt-pt-g1.utb +1312 -0
  387. data/vendor/liblouis/tables/pt-pt-g2.ctb +874 -0
  388. data/vendor/liblouis/tables/pt.tbl +20 -0
  389. data/vendor/liblouis/tables/pu-in-g1.utb +42 -0
  390. data/vendor/liblouis/tables/quotation-marks.uti +30 -0
  391. data/vendor/liblouis/tables/ro-g0.utb +85 -0
  392. data/vendor/liblouis/tables/ro.ctb +126 -0
  393. data/vendor/liblouis/tables/ro.tbl +21 -0
  394. data/vendor/liblouis/tables/ru-brf.dis +116 -0
  395. data/vendor/liblouis/tables/ru-comp6.utb +258 -0
  396. data/vendor/liblouis/tables/ru-comp8.utb +740 -0
  397. data/vendor/liblouis/tables/ru-letters.dis +145 -0
  398. data/vendor/liblouis/tables/ru-litbrl-detailed.utb +77 -0
  399. data/vendor/liblouis/tables/ru-litbrl.ctb +857 -0
  400. data/vendor/liblouis/tables/ru-math.uti +395 -0
  401. data/vendor/liblouis/tables/ru-ru-g1.ctb +804 -0
  402. data/vendor/liblouis/tables/ru-unicode.dis +121 -0
  403. data/vendor/liblouis/tables/rw-rw-g1.utb +133 -0
  404. data/vendor/liblouis/tables/sa-in-g1.utb +27 -0
  405. data/vendor/liblouis/tables/sa.tbl +18 -0
  406. data/vendor/liblouis/tables/sah.utb +72 -0
  407. data/vendor/liblouis/tables/sd.tbl +18 -0
  408. data/vendor/liblouis/tables/se-se.ctb +246 -0
  409. data/vendor/liblouis/tables/se-se.dis +334 -0
  410. data/vendor/liblouis/tables/si-in-g1.utb +27 -0
  411. data/vendor/liblouis/tables/sin.cti +213 -0
  412. data/vendor/liblouis/tables/sin.utb +35 -0
  413. data/vendor/liblouis/tables/sk-g1.ctb +1019 -0
  414. data/vendor/liblouis/tables/sk-sk-g1.utb +206 -0
  415. data/vendor/liblouis/tables/sk-sk.utb +112 -0
  416. data/vendor/liblouis/tables/sl-si-comp8.ctb +204 -0
  417. data/vendor/liblouis/tables/sl-si-g1.utb +471 -0
  418. data/vendor/liblouis/tables/sl.tbl +20 -0
  419. data/vendor/liblouis/tables/smi-6g0.utb +64 -0
  420. data/vendor/liblouis/tables/smi-8g0.utb +61 -0
  421. data/vendor/liblouis/tables/sot-za-g1.ctb +72 -0
  422. data/vendor/liblouis/tables/sot-za-g2.ctb +244 -0
  423. data/vendor/liblouis/tables/spaces.uti +62 -0
  424. data/vendor/liblouis/tables/sr-Cyrl.ctb +59 -0
  425. data/vendor/liblouis/tables/sr-common.cti +161 -0
  426. data/vendor/liblouis/tables/sr-cyrletters.cti +92 -0
  427. data/vendor/liblouis/tables/sr-g1.ctb +57 -0
  428. data/vendor/liblouis/tables/sr-latletters.cti +45 -0
  429. data/vendor/liblouis/tables/sv-1989.ctb +241 -0
  430. data/vendor/liblouis/tables/sv-1996.ctb +180 -0
  431. data/vendor/liblouis/tables/sv-6common.uti +1199 -0
  432. data/vendor/liblouis/tables/sv-6g0d.utb +508 -0
  433. data/vendor/liblouis/tables/sv-6g0p.utb +61 -0
  434. data/vendor/liblouis/tables/sv-6g1.uti +106 -0
  435. data/vendor/liblouis/tables/sv-6g1d.ctb +57 -0
  436. data/vendor/liblouis/tables/sv-6g2.uti +254 -0
  437. data/vendor/liblouis/tables/sv-6g2d.ctb +57 -0
  438. data/vendor/liblouis/tables/sv-8g0d.utb +495 -0
  439. data/vendor/liblouis/tables/sv-8g0n.utb +1236 -0
  440. data/vendor/liblouis/tables/sv-8g1.uti +199 -0
  441. data/vendor/liblouis/tables/sv-8g1d.ctb +73 -0
  442. data/vendor/liblouis/tables/sv-8g1n.ctb +73 -0
  443. data/vendor/liblouis/tables/sv-8g2.uti +486 -0
  444. data/vendor/liblouis/tables/sv-8g2d.ctb +73 -0
  445. data/vendor/liblouis/tables/sv-8g2n.ctb +73 -0
  446. data/vendor/liblouis/tables/sv-g0.utb +65 -0
  447. data/vendor/liblouis/tables/sv-g1.ctb +57 -0
  448. data/vendor/liblouis/tables/sv-g2.ctb +57 -0
  449. data/vendor/liblouis/tables/sv-phon.uti +241 -0
  450. data/vendor/liblouis/tables/sw-ke-g1-2.ctb +90 -0
  451. data/vendor/liblouis/tables/sw-ke-g1-3.ctb +109 -0
  452. data/vendor/liblouis/tables/sw-ke-g1-4.ctb +107 -0
  453. data/vendor/liblouis/tables/sw-ke-g1-5.ctb +73 -0
  454. data/vendor/liblouis/tables/sw-ke-g1.utb +278 -0
  455. data/vendor/liblouis/tables/sw-ke-g2.ctb +276 -0
  456. data/vendor/liblouis/tables/syc.utb +195 -0
  457. data/vendor/liblouis/tables/ta-ta-g1.ctb +167 -0
  458. data/vendor/liblouis/tables/ta.ctb +24 -0
  459. data/vendor/liblouis/tables/ta.tbl +21 -0
  460. data/vendor/liblouis/tables/tamil.cti +86 -0
  461. data/vendor/liblouis/tables/te-in-g1.utb +27 -0
  462. data/vendor/liblouis/tables/te.tbl +18 -0
  463. data/vendor/liblouis/tables/telugu.cti +239 -0
  464. data/vendor/liblouis/tables/text_nabcc.dis +426 -0
  465. data/vendor/liblouis/tables/th-comp8-backward.utb +226 -0
  466. data/vendor/liblouis/tables/th-g0.utb +177 -0
  467. data/vendor/liblouis/tables/th-g1.utb +89 -0
  468. data/vendor/liblouis/tables/th-g1.uti +315 -0
  469. data/vendor/liblouis/tables/th-g2.ctb +616 -0
  470. data/vendor/liblouis/tables/tr-g1.ctb +254 -0
  471. data/vendor/liblouis/tables/tr-g2.ctb +863 -0
  472. data/vendor/liblouis/tables/tr-g2.tbl +20 -0
  473. data/vendor/liblouis/tables/tr.ctb +324 -0
  474. data/vendor/liblouis/tables/tr.tbl +21 -0
  475. data/vendor/liblouis/tables/tsn-za-g1.ctb +33 -0
  476. data/vendor/liblouis/tables/tsn-za-g2.ctb +33 -0
  477. data/vendor/liblouis/tables/tt.utb +74 -0
  478. data/vendor/liblouis/tables/uga.utb +86 -0
  479. data/vendor/liblouis/tables/uk-comp.utb +53 -0
  480. data/vendor/liblouis/tables/uk-detailed.utb +32 -0
  481. data/vendor/liblouis/tables/uk.utb +101 -0
  482. data/vendor/liblouis/tables/ukchardefs.cti +106 -0
  483. data/vendor/liblouis/tables/ukmaths_single_cell_defs.cti +65 -0
  484. data/vendor/liblouis/tables/ukmaths_unicode_defs.cti +298 -0
  485. data/vendor/liblouis/tables/uni-text.dis +330 -0
  486. data/vendor/liblouis/tables/unicode-braille.utb +291 -0
  487. data/vendor/liblouis/tables/unicode-without-blank.dis +24 -0
  488. data/vendor/liblouis/tables/unicode.dis +278 -0
  489. data/vendor/liblouis/tables/ur-pk-g1.utb +248 -0
  490. data/vendor/liblouis/tables/ur-pk-g2.ctb +641 -0
  491. data/vendor/liblouis/tables/us-table.dis +67 -0
  492. data/vendor/liblouis/tables/uz-g1.utb +117 -0
  493. data/vendor/liblouis/tables/ve-za-g1.utb +69 -0
  494. data/vendor/liblouis/tables/ve-za-g2.ctb +208 -0
  495. data/vendor/liblouis/tables/vi-cb8.utb +49 -0
  496. data/vendor/liblouis/tables/vi-charsdef.uti +36 -0
  497. data/vendor/liblouis/tables/vi-lettersdef.uti +401 -0
  498. data/vendor/liblouis/tables/vi-puncsdef.uti +446 -0
  499. data/vendor/liblouis/tables/vi-saigon-g1.ctb +530 -0
  500. data/vendor/liblouis/tables/vi-vn-g0.utb +135 -0
  501. data/vendor/liblouis/tables/vi-vn-g1.ctb +574 -0
  502. data/vendor/liblouis/tables/vi-vn-g2.ctb +743 -0
  503. data/vendor/liblouis/tables/wiskunde-chardefs.cti +261 -0
  504. data/vendor/liblouis/tables/wordcx.dis +91 -0
  505. data/vendor/liblouis/tables/xh-za-g1.utb +61 -0
  506. data/vendor/liblouis/tables/xh-za-g2.ctb +386 -0
  507. data/vendor/liblouis/tables/yi.utb +236 -0
  508. data/vendor/liblouis/tables/zh-chn.ctb +45011 -0
  509. data/vendor/liblouis/tables/zh-hk.ctb +10461 -0
  510. data/vendor/liblouis/tables/zh-tw.ctb +53810 -0
  511. data/vendor/liblouis/tables/zh_CHN.tbl +23 -0
  512. data/vendor/liblouis/tables/zhcn-cbs.ctb +31523 -0
  513. data/vendor/liblouis/tables/zhcn-g1.ctb +26523 -0
  514. data/vendor/liblouis/tables/zhcn-g2.ctb +26519 -0
  515. data/vendor/liblouis/tables/zu-za-g1.utb +33 -0
  516. data/vendor/liblouis/tables/zu-za-g2.ctb +33 -0
  517. metadata +558 -0
@@ -0,0 +1,4177 @@
1
+ /* liblouis Braille Translation and Back-Translation Library
2
+
3
+ Based on the Linux screenreader BRLTTY, copyright (C) 1999-2006 by The
4
+ BRLTTY Team
5
+
6
+ Copyright (C) 2004, 2005, 2006 ViewPlus Technologies, Inc. www.viewplus.com
7
+ Copyright (C) 2004, 2005, 2006 JJB Software, Inc. www.jjb-software.com
8
+ Copyright (C) 2016 Mike Gray, American Printing House for the Blind
9
+ Copyright (C) 2016 Davy Kager, Dedicon
10
+
11
+ This file is part of liblouis.
12
+
13
+ liblouis is free software: you can redistribute it and/or modify it
14
+ under the terms of the GNU Lesser General Public License as published
15
+ by the Free Software Foundation, either version 2.1 of the License, or
16
+ (at your option) any later version.
17
+
18
+ liblouis is distributed in the hope that it will be useful, but
19
+ WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21
+ Lesser General Public License for more details.
22
+
23
+ You should have received a copy of the GNU Lesser General Public
24
+ License along with liblouis. If not, see <http://www.gnu.org/licenses/>.
25
+ */
26
+
27
+ /**
28
+ * @file
29
+ * @brief Translate to braille
30
+ */
31
+
32
+ #include "config.h"
33
+
34
+ #include <stdio.h>
35
+ #include <stdlib.h>
36
+ #include <string.h>
37
+
38
+ #include "internal.h"
39
+
40
+ /* additional bits in typebuf */
41
+ #define SYLLABLE_MARKER_1 0x2000
42
+ #define SYLLABLE_MARKER_2 0x4000
43
+ #define CAPSEMPH 0x8000
44
+
45
+ #define EMPHASIS 0x3fff // all typeform bits that can be used
46
+
47
+ /* bits for wordBuffer */
48
+ #define WORD_CHAR 0x00000001
49
+ #define WORD_RESET 0x00000002
50
+ #define WORD_WHOLE 0x00000004
51
+
52
+ typedef struct {
53
+ int size;
54
+ widechar **buffers;
55
+ int *inUse;
56
+ widechar *(*alloc)(int index, int length);
57
+ void (*free)(widechar *);
58
+ } StringBufferPool;
59
+
60
+ static widechar *
61
+ allocStringBuffer(int index, int length) {
62
+ return _lou_allocMem(alloc_passbuf, index, 0, length);
63
+ }
64
+
65
+ static const StringBufferPool *stringBufferPool = NULL;
66
+
67
+ static void
68
+ initStringBufferPool() {
69
+ static widechar *stringBuffers[MAXPASSBUF] = { NULL };
70
+ static int stringBuffersInUse[MAXPASSBUF] = { 0 };
71
+ StringBufferPool *pool = malloc(sizeof(StringBufferPool));
72
+ pool->size = MAXPASSBUF;
73
+ pool->buffers = stringBuffers;
74
+ pool->inUse = stringBuffersInUse;
75
+ pool->alloc = &allocStringBuffer;
76
+ pool->free = NULL;
77
+ stringBufferPool = pool;
78
+ }
79
+
80
+ static int
81
+ getStringBuffer(int length) {
82
+ int i;
83
+
84
+ if (!stringBufferPool) initStringBufferPool();
85
+
86
+ for (i = 0; i < stringBufferPool->size; i++) {
87
+ if (!stringBufferPool->inUse[i]) {
88
+ stringBufferPool->buffers[i] = stringBufferPool->alloc(i, length);
89
+ stringBufferPool->inUse[i] = 1;
90
+ return i;
91
+ }
92
+ }
93
+ _lou_outOfMemory();
94
+ return -1;
95
+ }
96
+
97
+ static int
98
+ releaseStringBuffer(int idx) {
99
+ if (!stringBufferPool) {
100
+ _lou_logMessage(LOU_LOG_ERROR,
101
+ "Attempt to free string buffer prior to initialization of pool");
102
+ return 0;
103
+ }
104
+
105
+ if (idx >= 0 && idx < stringBufferPool->size) {
106
+ int inUse = stringBufferPool->inUse[idx];
107
+ if (inUse && stringBufferPool->free)
108
+ stringBufferPool->free(stringBufferPool->buffers[idx]);
109
+ stringBufferPool->inUse[idx] = 0;
110
+ return inUse;
111
+ }
112
+ return 0;
113
+ }
114
+
115
+ typedef struct {
116
+ int bufferIndex;
117
+ const widechar *chars;
118
+ int length;
119
+ } InString;
120
+
121
+ typedef struct {
122
+ int bufferIndex;
123
+ widechar *chars;
124
+ int maxlength;
125
+ int length;
126
+ } OutString;
127
+
128
+ typedef struct {
129
+ int startMatch;
130
+ int startReplace;
131
+ int endReplace;
132
+ int endMatch;
133
+ } PassRuleMatch;
134
+
135
+ static int
136
+ putCharacter(widechar c, const TranslationTableHeader *table, int pos,
137
+ const InString *input, OutString *output, int *posMapping, int *cursorPosition,
138
+ int *cursorStatus, int mode);
139
+ static int
140
+ passDoTest(const TranslationTableHeader *table, int pos, const InString *input,
141
+ int transOpcode, const TranslationTableRule *transRule, int *passCharDots,
142
+ const widechar **passInstructions, int *passIC, PassRuleMatch *match,
143
+ TranslationTableRule **groupingRule, widechar *groupingOp);
144
+ static int
145
+ passDoAction(const TranslationTableHeader *table, const InString **input,
146
+ OutString *output, int *posMapping, int transOpcode,
147
+ const TranslationTableRule **transRule, int passCharDots,
148
+ const widechar *passInstructions, int passIC, int *pos, PassRuleMatch match,
149
+ int *cursorPosition, int *cursorStatus, TranslationTableRule *groupingRule,
150
+ widechar groupingOp, int mode);
151
+
152
+ static const TranslationTableRule **appliedRules;
153
+ static int maxAppliedRules;
154
+ static int appliedRulesCount;
155
+
156
+ static TranslationTableCharacter *
157
+ getChar(widechar c, const TranslationTableHeader *table) {
158
+ static TranslationTableCharacter notFound = { NULL, -1, 0, 0, 0, CTC_Space, 0, 0, 32,
159
+ 0, 0 };
160
+ const TranslationTableOffset bucket = table->characters[_lou_charHash(c)];
161
+ TranslationTableOffset offset = bucket;
162
+ while (offset) {
163
+ TranslationTableCharacter *character =
164
+ (TranslationTableCharacter *)&table->ruleArea[offset];
165
+ if (character->value == c) return character;
166
+ offset = character->next;
167
+ }
168
+ notFound.value = c;
169
+ return &notFound;
170
+ }
171
+
172
+ static TranslationTableCharacter *
173
+ getDots(widechar c, const TranslationTableHeader *table) {
174
+ static TranslationTableCharacter notFound = { NULL, -1, 0, 0, 0, CTC_Space, 0, 0,
175
+ LOU_DOTS, 0, 0 };
176
+ const TranslationTableOffset bucket = table->dots[_lou_charHash(c)];
177
+ TranslationTableOffset offset = bucket;
178
+ while (offset) {
179
+ TranslationTableCharacter *character =
180
+ (TranslationTableCharacter *)&table->ruleArea[offset];
181
+ if (character->value == c) return character;
182
+ offset = character->next;
183
+ }
184
+ notFound.value = c;
185
+ return &notFound;
186
+ }
187
+
188
+ static int
189
+ checkCharAttr(const widechar c, const TranslationTableCharacterAttributes a,
190
+ const TranslationTableHeader *table) {
191
+ return (((getChar(c, table))->attributes & a) ? 1 : 0);
192
+ }
193
+
194
+ static int
195
+ checkDotsAttr(const widechar c, const TranslationTableCharacterAttributes a,
196
+ const TranslationTableHeader *table) {
197
+ return (((getDots(c, table))->attributes & a) ? 1 : 0);
198
+ }
199
+
200
+ static int
201
+ checkCharAttr_safe(const InString *input, int pos,
202
+ const TranslationTableCharacterAttributes a,
203
+ const TranslationTableHeader *table) {
204
+ return ((pos < input->length) ? checkCharAttr(input->chars[pos], a, table) : 0);
205
+ }
206
+
207
+ static int
208
+ findForPassRule(const TranslationTableHeader *table, int pos, int currentPass,
209
+ const InString *input, int *transOpcode, const TranslationTableRule **transRule,
210
+ int *transCharslen, int *passCharDots, widechar const **passInstructions,
211
+ int *passIC, PassRuleMatch *match, TranslationTableRule **groupingRule,
212
+ widechar *groupingOp) {
213
+ int save_transCharslen = *transCharslen;
214
+ const TranslationTableRule *save_transRule = *transRule;
215
+ TranslationTableOpcode save_transOpcode = *transOpcode;
216
+ TranslationTableOffset ruleOffset;
217
+ ruleOffset = table->forPassRules[currentPass];
218
+ *transCharslen = 0;
219
+ while (ruleOffset) {
220
+ *transRule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
221
+ *transOpcode = (*transRule)->opcode;
222
+ if (passDoTest(table, pos, input, *transOpcode, *transRule, passCharDots,
223
+ passInstructions, passIC, match, groupingRule, groupingOp))
224
+ return 1;
225
+ ruleOffset = (*transRule)->charsnext;
226
+ }
227
+ *transCharslen = save_transCharslen;
228
+ *transRule = save_transRule;
229
+ *transOpcode = save_transOpcode;
230
+ return 0;
231
+ }
232
+
233
+ static widechar
234
+ toLowercase(
235
+ const TranslationTableHeader *table, const TranslationTableCharacter *character) {
236
+ if (character->mode & CTC_UpperCase) {
237
+ const TranslationTableCharacter *c = character;
238
+ if (c->basechar) c = (TranslationTableCharacter *)&table->ruleArea[c->basechar];
239
+ while (1) {
240
+ if ((c->mode & (character->mode & ~CTC_UpperCase)) ==
241
+ (character->mode & ~CTC_UpperCase))
242
+ return c->value;
243
+ if (!c->linked) break;
244
+ c = (TranslationTableCharacter *)&table->ruleArea[c->linked];
245
+ }
246
+ }
247
+ return character->value;
248
+ }
249
+
250
+ static int
251
+ compareChars(const widechar *address1, const widechar *address2, int count,
252
+ const TranslationTableHeader *table) {
253
+ int k;
254
+ if (!count) return 0;
255
+ for (k = 0; k < count; k++)
256
+ if (toLowercase(table, getChar(address1[k], table)) !=
257
+ toLowercase(table, getChar(address2[k], table)))
258
+ return 0;
259
+ return 1;
260
+ }
261
+
262
+ static int
263
+ makeCorrections(const TranslationTableHeader *table, const InString *input,
264
+ OutString *output, int *posMapping, formtype *typebuf, int *realInlen,
265
+ int *cursorPosition, int *cursorStatus, int mode) {
266
+ int pos;
267
+ int transOpcode;
268
+ const TranslationTableRule *transRule;
269
+ int transCharslen;
270
+ int passCharDots;
271
+ const widechar *passInstructions;
272
+ int passIC; /* Instruction counter */
273
+ PassRuleMatch patternMatch;
274
+ TranslationTableRule *groupingRule;
275
+ widechar groupingOp;
276
+ const InString *origInput = input;
277
+ if (!table->corrections) return 1;
278
+ pos = 0;
279
+ output->length = 0;
280
+ int posIncremented = 1;
281
+ _lou_resetPassVariables();
282
+ while (pos < input->length) {
283
+ int length = input->length - pos;
284
+ int tryThis = 0;
285
+ // check posIncremented to avoid endless loop
286
+ if (!(posIncremented &&
287
+ findForPassRule(table, pos, 0, input, &transOpcode, &transRule,
288
+ &transCharslen, &passCharDots, &passInstructions, &passIC,
289
+ &patternMatch, &groupingRule, &groupingOp)))
290
+ while (tryThis < 3) {
291
+ TranslationTableOffset ruleOffset = 0;
292
+ switch (tryThis) {
293
+ case 0:
294
+ if (!(length >= 2)) break;
295
+ ruleOffset = table->forRules[_lou_stringHash(
296
+ &input->chars[pos], 1, table)];
297
+ break;
298
+ case 1:
299
+ if (!(length >= 1)) break;
300
+ length = 1;
301
+ ruleOffset = getChar(input->chars[pos], table)->otherRules;
302
+ break;
303
+ case 2: /* No rule found */
304
+ transOpcode = CTO_Always;
305
+ ruleOffset = 0;
306
+ break;
307
+ }
308
+ while (ruleOffset) {
309
+ transRule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
310
+ transOpcode = transRule->opcode;
311
+ transCharslen = transRule->charslen;
312
+ if (tryThis == 1 ||
313
+ (transCharslen <= length &&
314
+ compareChars(&transRule->charsdots[0],
315
+ &input->chars[pos], transCharslen, table))) {
316
+ if (posIncremented && transOpcode == CTO_Correct &&
317
+ passDoTest(table, pos, input, transOpcode, transRule,
318
+ &passCharDots, &passInstructions, &passIC,
319
+ &patternMatch, &groupingRule, &groupingOp)) {
320
+ tryThis = 4;
321
+ break;
322
+ }
323
+ }
324
+ ruleOffset = transRule->charsnext;
325
+ }
326
+ tryThis++;
327
+ }
328
+ posIncremented = 1;
329
+
330
+ switch (transOpcode) {
331
+ case CTO_Always:
332
+ if (output->length >= output->maxlength) goto failure;
333
+ posMapping[output->length] = pos;
334
+ output->chars[output->length++] = input->chars[pos++];
335
+ break;
336
+ case CTO_Correct: {
337
+ const InString *inputBefore = input;
338
+ int posBefore = pos;
339
+ if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
340
+ appliedRules[appliedRulesCount++] = transRule;
341
+ if (!passDoAction(table, &input, output, posMapping, transOpcode, &transRule,
342
+ passCharDots, passInstructions, passIC, &pos, patternMatch,
343
+ cursorPosition, cursorStatus, groupingRule, groupingOp, mode))
344
+ goto failure;
345
+ if (input->bufferIndex != inputBefore->bufferIndex &&
346
+ inputBefore->bufferIndex != origInput->bufferIndex)
347
+ releaseStringBuffer(inputBefore->bufferIndex);
348
+ if (pos == posBefore) posIncremented = 0;
349
+ break;
350
+ }
351
+ default:
352
+ break;
353
+ }
354
+ }
355
+
356
+ { // We have to transform typebuf accordingly
357
+ int k;
358
+ formtype *typebuf_temp;
359
+ if ((typebuf_temp = malloc(output->length * sizeof(formtype))) == NULL)
360
+ _lou_outOfMemory();
361
+ for (k = 0; k < output->length; k++)
362
+ // posMapping will never be < 0 but in theory it could
363
+ if (posMapping[k] < 0)
364
+ typebuf_temp[k] = typebuf[0]; // prepend to next
365
+ else if (posMapping[k] >= input->length)
366
+ typebuf_temp[k] = typebuf[input->length - 1]; // append to previous
367
+ else
368
+ typebuf_temp[k] = typebuf[posMapping[k]];
369
+ memcpy(typebuf, typebuf_temp, output->length * sizeof(formtype));
370
+ free(typebuf_temp);
371
+ }
372
+
373
+ failure:
374
+ *realInlen = pos;
375
+ if (input->bufferIndex != origInput->bufferIndex)
376
+ releaseStringBuffer(input->bufferIndex);
377
+ return 1;
378
+ }
379
+
380
+ static int
381
+ matchCurrentInput(
382
+ const InString *input, int pos, const widechar *passInstructions, int passIC) {
383
+ int k;
384
+ int kk = pos;
385
+ for (k = passIC + 2;
386
+ ((k < passIC + 2 + passInstructions[passIC + 1]) && (kk < input->length));
387
+ k++)
388
+ if (input->chars[kk] == LOU_ENDSEGMENT ||
389
+ passInstructions[k] != input->chars[kk++])
390
+ return 0;
391
+ return 1;
392
+ }
393
+
394
+ static int
395
+ swapTest(int swapIC, int *pos, const TranslationTableHeader *table, const InString *input,
396
+ const widechar *passInstructions) {
397
+ int p = *pos;
398
+ TranslationTableOffset swapRuleOffset;
399
+ TranslationTableRule *swapRule;
400
+ swapRuleOffset = (passInstructions[swapIC + 1] << 16) | passInstructions[swapIC + 2];
401
+ swapRule = (TranslationTableRule *)&table->ruleArea[swapRuleOffset];
402
+ while (p - *pos < passInstructions[swapIC + 3]) {
403
+ int test;
404
+ if (p >= input->length) return 0;
405
+ if (swapRule->opcode == CTO_SwapDd) {
406
+ for (test = 1; test < swapRule->charslen; test += 2) {
407
+ if (input->chars[p] == swapRule->charsdots[test]) break;
408
+ }
409
+ } else {
410
+ for (test = 0; test < swapRule->charslen; test++) {
411
+ if (input->chars[p] == swapRule->charsdots[test]) break;
412
+ }
413
+ }
414
+ if (test >= swapRule->charslen) return 0;
415
+ p++;
416
+ }
417
+ if (passInstructions[swapIC + 3] == passInstructions[swapIC + 4]) {
418
+ *pos = p;
419
+ return 1;
420
+ }
421
+ while (p - *pos < passInstructions[swapIC + 4]) {
422
+ int test;
423
+ if (p >= input->length) {
424
+ *pos = p;
425
+ return 1;
426
+ }
427
+ if (swapRule->opcode == CTO_SwapDd) {
428
+ for (test = 1; test < swapRule->charslen; test += 2) {
429
+ if (input->chars[p] == swapRule->charsdots[test]) break;
430
+ }
431
+ } else {
432
+ for (test = 0; test < swapRule->charslen; test++) {
433
+ if (input->chars[p] == swapRule->charsdots[test]) break;
434
+ }
435
+ }
436
+ if (test >= swapRule->charslen) {
437
+ *pos = p;
438
+ return 1;
439
+ }
440
+ p++;
441
+ }
442
+ *pos = p;
443
+ return 1;
444
+ }
445
+
446
+ static int
447
+ swapReplace(int start, int end, const TranslationTableHeader *table,
448
+ const InString *input, OutString *output, int *posMapping,
449
+ const widechar *passInstructions, int passIC) {
450
+ TranslationTableOffset swapRuleOffset;
451
+ TranslationTableRule *swapRule;
452
+ widechar *replacements;
453
+ int p;
454
+ swapRuleOffset = (passInstructions[passIC + 1] << 16) | passInstructions[passIC + 2];
455
+ swapRule = (TranslationTableRule *)&table->ruleArea[swapRuleOffset];
456
+ replacements = &swapRule->charsdots[swapRule->charslen];
457
+ for (p = start; p < end; p++) {
458
+ int rep;
459
+ int test;
460
+ int k;
461
+ if (swapRule->opcode == CTO_SwapDd) {
462
+ // A sequence of dot patterns is encoded as the length of the first dot
463
+ // pattern (single widechar) followed by the contents of the first dot pattern
464
+ // (one widechar per cell) followed by the length of the second dot pattern,
465
+ // etc. See the function `compileSwapDots'. Because the third operand of a
466
+ // swapdd rule can only contain single-cell dot patterns, the elements at
467
+ // index 0, 2, ... are "1" and the elements at index 1, 3, ... are the dot
468
+ // patterns.
469
+ for (test = 0; test * 2 + 1 < swapRule->charslen; test++)
470
+ if (input->chars[p] == swapRule->charsdots[test * 2 + 1]) break;
471
+ if (test * 2 == swapRule->charslen) continue;
472
+ } else {
473
+ for (test = 0; test < swapRule->charslen; test++)
474
+ if (input->chars[p] == swapRule->charsdots[test]) break;
475
+ if (test == swapRule->charslen) continue;
476
+ }
477
+ k = 0;
478
+ for (rep = 0; rep < test; rep++)
479
+ if (swapRule->opcode == CTO_SwapCc)
480
+ k++;
481
+ else
482
+ k += replacements[k];
483
+ if (swapRule->opcode == CTO_SwapCc) {
484
+ if ((output->length + 1) > output->maxlength) return 0;
485
+ posMapping[output->length] = p;
486
+ output->chars[output->length++] = replacements[k];
487
+ } else {
488
+ int l = replacements[k] - 1;
489
+ int d = output->length + l;
490
+ if (d > output->maxlength) return 0;
491
+ while (--d >= output->length) posMapping[d] = p;
492
+ // if length is negative fail
493
+ int length = l * sizeof(*output->chars);
494
+ if (length < 0) return 0;
495
+ memcpy(&output->chars[output->length], &replacements[k + 1], length);
496
+ output->length += l;
497
+ }
498
+ }
499
+ return 1;
500
+ }
501
+
502
+ static int
503
+ replaceGrouping(const TranslationTableHeader *table, const InString **input,
504
+ OutString *output, int transOpcode, int passCharDots,
505
+ const widechar *passInstructions, int passIC, int startReplace,
506
+ TranslationTableRule *groupingRule, widechar groupingOp) {
507
+ widechar startCharDots = groupingRule->charsdots[2 * passCharDots];
508
+ widechar endCharDots = groupingRule->charsdots[2 * passCharDots + 1];
509
+ int p;
510
+ int level = 0;
511
+ TranslationTableOffset replaceOffset =
512
+ passInstructions[passIC + 1] << 16 | (passInstructions[passIC + 2] & 0xff);
513
+ TranslationTableRule *replaceRule =
514
+ (TranslationTableRule *)&table->ruleArea[replaceOffset];
515
+ widechar replaceStart = replaceRule->charsdots[2 * passCharDots];
516
+ widechar replaceEnd = replaceRule->charsdots[2 * passCharDots + 1];
517
+ if (groupingOp == pass_groupstart) {
518
+ for (p = startReplace + 1; p < (*input)->length; p++) {
519
+ if ((*input)->chars[p] == startCharDots) level--;
520
+ if ((*input)->chars[p] == endCharDots) level++;
521
+ if (level == 1) break;
522
+ }
523
+ if (p == (*input)->length)
524
+ return 0;
525
+ else {
526
+ // Create a new string instead of modifying it. This is slightly less
527
+ // efficient, but makes the code more readable. Grouping is not a much used
528
+ // feature anyway.
529
+ int idx = getStringBuffer((*input)->length);
530
+ widechar *chars = stringBufferPool->buffers[idx];
531
+ memcpy(chars, (*input)->chars, (*input)->length * sizeof(widechar));
532
+ chars[startReplace] = replaceStart;
533
+ chars[p] = replaceEnd;
534
+ static InString stringStore;
535
+ stringStore = (InString){
536
+ .chars = chars, .length = (*input)->length, .bufferIndex = idx
537
+ };
538
+ *input = &stringStore;
539
+ }
540
+ } else {
541
+ if (transOpcode == CTO_Context) {
542
+ startCharDots = groupingRule->charsdots[2];
543
+ endCharDots = groupingRule->charsdots[3];
544
+ replaceStart = replaceRule->charsdots[2];
545
+ replaceEnd = replaceRule->charsdots[3];
546
+ }
547
+ if ((output->length + 1) > output->maxlength) return 0;
548
+ output->chars[output->length] = replaceEnd;
549
+ for (p = output->length - 1; p >= 0; p--) {
550
+ if (output->chars[p] == endCharDots) level--;
551
+ if (output->chars[p] == startCharDots) level++;
552
+ if (level == 1) break;
553
+ }
554
+ if (p < 0) return 0;
555
+ output->chars[p] = replaceStart;
556
+ output->length++;
557
+ }
558
+ return 1;
559
+ }
560
+
561
+ static int
562
+ removeGrouping(const InString **input, OutString *output, int passCharDots,
563
+ int startReplace, TranslationTableRule *groupingRule, widechar groupingOp) {
564
+ widechar startCharDots = groupingRule->charsdots[2 * passCharDots];
565
+ widechar endCharDots = groupingRule->charsdots[2 * passCharDots + 1];
566
+ int p;
567
+ int level = 0;
568
+ if (groupingOp == pass_groupstart) {
569
+ for (p = startReplace + 1; p < (*input)->length; p++) {
570
+ if ((*input)->chars[p] == startCharDots) level--;
571
+ if ((*input)->chars[p] == endCharDots) level++;
572
+ if (level == 1) break;
573
+ }
574
+ if (p == (*input)->length)
575
+ return 0;
576
+ else {
577
+ // Create a new string instead of modifying it. This is slightly less
578
+ // efficient, but makes the code more readable. Grouping is not a much used
579
+ // feature anyway.
580
+ int idx = getStringBuffer((*input)->length);
581
+ widechar *chars = stringBufferPool->buffers[idx];
582
+ int len = 0;
583
+ int k;
584
+ for (k = 0; k < (*input)->length; k++) {
585
+ if (k == p) continue;
586
+ chars[len++] = (*input)->chars[k];
587
+ }
588
+ static InString stringStore;
589
+ stringStore = (InString){ .chars = chars, .length = len, .bufferIndex = idx };
590
+ *input = &stringStore;
591
+ }
592
+ } else {
593
+ for (p = output->length - 1; p >= 0; p--) {
594
+ if (output->chars[p] == endCharDots) level--;
595
+ if (output->chars[p] == startCharDots) level++;
596
+ if (level == 1) break;
597
+ }
598
+ if (p < 0) return 0;
599
+ p++;
600
+ for (; p < output->length; p++) output->chars[p - 1] = output->chars[p];
601
+ output->length--;
602
+ }
603
+ return 1;
604
+ }
605
+
606
+ static int
607
+ doPassSearch(const TranslationTableHeader *table, const InString *input,
608
+ const TranslationTableRule *transRule, int passCharDots, int pos,
609
+ const widechar *passInstructions, int passIC, int *searchIC, int *searchPos,
610
+ TranslationTableRule *groupingRule, widechar groupingOp) {
611
+ int level = 0;
612
+ int k, kk;
613
+ int notOperator = 0; // whether next operand should be reversed
614
+ TranslationTableOffset ruleOffset;
615
+ TranslationTableRule *rule;
616
+ TranslationTableCharacterAttributes attributes;
617
+ while (pos < input->length) {
618
+ *searchIC = passIC + 1;
619
+ *searchPos = pos;
620
+ while (*searchIC < transRule->dotslen) {
621
+ int itsTrue = 1; // whether we have a match or not
622
+ if (*searchPos >= input->length) return 0;
623
+ switch (passInstructions[*searchIC]) {
624
+ case pass_lookback:
625
+ *searchPos -= passInstructions[*searchIC + 1];
626
+ if (*searchPos < 0) {
627
+ *searchPos = 0;
628
+ itsTrue = 0;
629
+ }
630
+ *searchIC += 2;
631
+ break;
632
+ case pass_not:
633
+ notOperator = !notOperator;
634
+ (*searchIC)++;
635
+ continue;
636
+ case pass_string:
637
+ case pass_dots:
638
+ kk = *searchPos;
639
+ for (k = *searchIC + 2;
640
+ k < *searchIC + 2 + passInstructions[*searchIC + 1]; k++)
641
+ if (input->chars[kk] == LOU_ENDSEGMENT ||
642
+ passInstructions[k] != input->chars[kk++]) {
643
+ itsTrue = 0;
644
+ break;
645
+ }
646
+ *searchPos += passInstructions[*searchIC + 1];
647
+ *searchIC += passInstructions[*searchIC + 1] + 2;
648
+ break;
649
+ case pass_startReplace:
650
+ (*searchIC)++;
651
+ break;
652
+ case pass_endReplace:
653
+ (*searchIC)++;
654
+ break;
655
+ case pass_attributes:
656
+ attributes = passInstructions[*searchIC + 1];
657
+ attributes <<= 16;
658
+ attributes |= passInstructions[*searchIC + 2];
659
+ attributes <<= 16;
660
+ attributes |= passInstructions[*searchIC + 3];
661
+ attributes <<= 16;
662
+ attributes |= passInstructions[*searchIC + 4];
663
+ for (k = 0; k < passInstructions[*searchIC + 5]; k++) {
664
+ if (input->chars[*searchPos] == LOU_ENDSEGMENT)
665
+ itsTrue = 0;
666
+ else {
667
+ itsTrue = (passCharDots ? getDots(input->chars[(*searchPos)++],
668
+ table)
669
+ : getChar(input->chars[(*searchPos)++],
670
+ table))
671
+ ->attributes &
672
+ attributes;
673
+ if (notOperator) itsTrue = !itsTrue;
674
+ }
675
+ if (!itsTrue) break;
676
+ }
677
+ if (itsTrue) {
678
+ for (k = passInstructions[*searchIC + 5];
679
+ k < passInstructions[*searchIC + 6]; k++) {
680
+ if (*searchPos >= input->length) return 0;
681
+ if (input->chars[*searchPos] == LOU_ENDSEGMENT) {
682
+ itsTrue = 0;
683
+ break;
684
+ }
685
+ if (!((passCharDots ? getDots(input->chars[*searchPos], table)
686
+ : getChar(input->chars[*searchPos], table))
687
+ ->attributes &
688
+ attributes)) {
689
+ if (!notOperator) break;
690
+ } else if (notOperator)
691
+ break;
692
+ (*searchPos)++;
693
+ }
694
+ }
695
+ notOperator = 0;
696
+ *searchIC += 7;
697
+ break;
698
+ case pass_groupstart:
699
+ case pass_groupend:
700
+ ruleOffset = (passInstructions[*searchIC + 1] << 16) |
701
+ passInstructions[*searchIC + 2];
702
+ rule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
703
+ if (passInstructions[*searchIC] == pass_groupstart)
704
+ itsTrue = (input->chars[*searchPos] ==
705
+ rule->charsdots[2 * passCharDots])
706
+ ? 1
707
+ : 0;
708
+ else
709
+ itsTrue = (input->chars[*searchPos] ==
710
+ rule->charsdots[2 * passCharDots + 1])
711
+ ? 1
712
+ : 0;
713
+ if (groupingRule != NULL && groupingOp == pass_groupstart &&
714
+ rule == groupingRule) {
715
+ if (input->chars[*searchPos] == rule->charsdots[2 * passCharDots])
716
+ level--;
717
+ else if (input->chars[*searchPos] ==
718
+ rule->charsdots[2 * passCharDots + 1])
719
+ level++;
720
+ }
721
+ (*searchPos)++;
722
+ *searchIC += 3;
723
+ break;
724
+ case pass_swap:
725
+ itsTrue = swapTest(*searchIC, searchPos, table, input, passInstructions);
726
+ *searchIC += 5;
727
+ break;
728
+ case pass_endTest:
729
+ if (itsTrue) {
730
+ if ((groupingRule && level == 1) || !groupingRule) return 1;
731
+ }
732
+ *searchIC = transRule->dotslen;
733
+ break;
734
+ default:
735
+ if (_lou_handlePassVariableTest(passInstructions, searchIC, &itsTrue))
736
+ break;
737
+ break;
738
+ }
739
+ if ((!notOperator && !itsTrue) || (notOperator && itsTrue)) break;
740
+ notOperator = 0;
741
+ }
742
+ pos++;
743
+ }
744
+ return 0;
745
+ }
746
+
747
+ static int
748
+ passDoTest(const TranslationTableHeader *table, int pos, const InString *input,
749
+ int transOpcode, const TranslationTableRule *transRule, int *passCharDots,
750
+ widechar const **passInstructions, int *passIC, PassRuleMatch *match,
751
+ TranslationTableRule **groupingRule, widechar *groupingOp) {
752
+ int searchIC, searchPos;
753
+ int k;
754
+ int notOperator = 0; // whether next operand should be reversed
755
+ TranslationTableOffset ruleOffset = 0;
756
+ TranslationTableRule *rule = NULL;
757
+ TranslationTableCharacterAttributes attributes = 0;
758
+ int startMatch = pos;
759
+ int endMatch = pos;
760
+ int startReplace = -1;
761
+ int endReplace = -1;
762
+ *groupingRule = NULL;
763
+ *passInstructions = &transRule->charsdots[transRule->charslen];
764
+ *passIC = 0;
765
+ if (transOpcode == CTO_Context || transOpcode == CTO_Correct)
766
+ *passCharDots = 0;
767
+ else
768
+ *passCharDots = 1;
769
+ while (*passIC < transRule->dotslen) {
770
+ int itsTrue = 1; // whether we have a match or not
771
+ // check if `pos` is within the input string,
772
+ // maybe a unsigned type would be better to omit negative values
773
+ if (pos > input->length || pos < 0) return 0;
774
+ switch ((*passInstructions)[*passIC]) {
775
+ case pass_first:
776
+ if (pos != 0) itsTrue = 0;
777
+ (*passIC)++;
778
+ break;
779
+ case pass_last:
780
+ if (pos != input->length) itsTrue = 0;
781
+ (*passIC)++;
782
+ break;
783
+ case pass_lookback:
784
+ pos -= (*passInstructions)[*passIC + 1];
785
+ if (pos < 0) {
786
+ searchPos = 0;
787
+ itsTrue = 0;
788
+ }
789
+ *passIC += 2;
790
+ break;
791
+ case pass_not:
792
+ notOperator = !notOperator;
793
+ (*passIC)++;
794
+ continue;
795
+ case pass_string:
796
+ case pass_dots:
797
+ itsTrue = matchCurrentInput(input, pos, *passInstructions, *passIC);
798
+ pos += (*passInstructions)[*passIC + 1];
799
+ *passIC += (*passInstructions)[*passIC + 1] + 2;
800
+ break;
801
+ case pass_startReplace:
802
+ startReplace = pos;
803
+ (*passIC)++;
804
+ break;
805
+ case pass_endReplace:
806
+ endReplace = pos;
807
+ (*passIC)++;
808
+ break;
809
+ case pass_attributes:
810
+ attributes = (*passInstructions)[*passIC + 1];
811
+ attributes <<= 16;
812
+ attributes |= (*passInstructions)[*passIC + 2];
813
+ attributes <<= 16;
814
+ attributes |= (*passInstructions)[*passIC + 3];
815
+ attributes <<= 16;
816
+ attributes |= (*passInstructions)[*passIC + 4];
817
+ for (k = 0; k < (*passInstructions)[*passIC + 5]; k++) {
818
+ if (pos >= input->length) {
819
+ itsTrue = 0;
820
+ break;
821
+ }
822
+ if (input->chars[pos] == LOU_ENDSEGMENT) {
823
+ itsTrue = 0;
824
+ break;
825
+ }
826
+ if (!((*passCharDots ? getDots(input->chars[pos], table)
827
+ : getChar(input->chars[pos], table))
828
+ ->attributes &
829
+ attributes)) {
830
+ if (!notOperator) {
831
+ itsTrue = 0;
832
+ break;
833
+ }
834
+ } else if (notOperator) {
835
+ itsTrue = 0;
836
+ break;
837
+ }
838
+ pos++;
839
+ }
840
+ if (itsTrue) {
841
+ for (k = (*passInstructions)[*passIC + 5];
842
+ k < (*passInstructions)[*passIC + 6] && pos < input->length;
843
+ k++) {
844
+ if (input->chars[pos] == LOU_ENDSEGMENT) {
845
+ itsTrue = 0;
846
+ break;
847
+ }
848
+ if (!((*passCharDots ? getDots(input->chars[pos], table)
849
+ : getChar(input->chars[pos], table))
850
+ ->attributes &
851
+ attributes)) {
852
+ if (!notOperator) break;
853
+ } else if (notOperator)
854
+ break;
855
+ pos++;
856
+ }
857
+ }
858
+ notOperator = 0;
859
+ *passIC += 7;
860
+ break;
861
+ case pass_groupstart:
862
+ case pass_groupend:
863
+ ruleOffset = ((*passInstructions)[*passIC + 1] << 16) |
864
+ (*passInstructions)[*passIC + 2];
865
+ rule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
866
+ if (*passIC == 0 ||
867
+ (*passIC > 0 &&
868
+ (*passInstructions)[*passIC - 1] == pass_startReplace)) {
869
+ *groupingRule = rule;
870
+ *groupingOp = (*passInstructions)[*passIC];
871
+ }
872
+ if ((*passInstructions)[*passIC] == pass_groupstart)
873
+ itsTrue =
874
+ (input->chars[pos] == rule->charsdots[2 * *passCharDots]) ? 1 : 0;
875
+ else
876
+ itsTrue = (input->chars[pos] == rule->charsdots[2 * *passCharDots + 1])
877
+ ? 1
878
+ : 0;
879
+ pos++;
880
+ *passIC += 3;
881
+ break;
882
+ case pass_swap:
883
+ itsTrue = swapTest(*passIC, &pos, table, input, *passInstructions);
884
+ *passIC += 5;
885
+ break;
886
+ case pass_search:
887
+ itsTrue = doPassSearch(table, input, transRule, *passCharDots, pos,
888
+ *passInstructions, *passIC, &searchIC, &searchPos, *groupingRule,
889
+ *groupingOp);
890
+ if ((!notOperator && !itsTrue) || (notOperator && itsTrue)) return 0;
891
+ *passIC = searchIC;
892
+ pos = searchPos;
893
+ case pass_endTest:
894
+ (*passIC)++;
895
+ endMatch = pos;
896
+ if (startReplace == -1) {
897
+ startReplace = startMatch;
898
+ endReplace = endMatch;
899
+ }
900
+ // Check whetehr endReplace != -1 while startReplace! = -1
901
+ if (startReplace < startMatch || endReplace == -1)
902
+ return 0;
903
+ else {
904
+ *match = (PassRuleMatch){ .startMatch = startMatch,
905
+ .startReplace = startReplace,
906
+ .endReplace = endReplace,
907
+ .endMatch = endMatch };
908
+ return 1;
909
+ }
910
+ break;
911
+ default:
912
+ if (_lou_handlePassVariableTest(*passInstructions, passIC, &itsTrue)) break;
913
+ return 0;
914
+ }
915
+ if ((!notOperator && !itsTrue) || (notOperator && itsTrue)) return 0;
916
+ notOperator = 0;
917
+ }
918
+ return 0;
919
+ }
920
+
921
+ static int
922
+ copyCharacters(int from, int to, const TranslationTableHeader *table,
923
+ const InString *input, OutString *output, int *posMapping, int transOpcode,
924
+ int *cursorPosition, int *cursorStatus, int mode) {
925
+ if (transOpcode == CTO_Context) {
926
+ while (from < to) {
927
+ if (!putCharacter(input->chars[from], table, from, input, output, posMapping,
928
+ cursorPosition, cursorStatus, mode))
929
+ return 0;
930
+ from++;
931
+ }
932
+ } else {
933
+ if (to > from) {
934
+ if ((output->length + to - from) > output->maxlength) return 0;
935
+ while (to > from) {
936
+ posMapping[output->length] = from;
937
+ output->chars[output->length] = input->chars[from];
938
+ output->length++;
939
+ from++;
940
+ }
941
+ }
942
+ }
943
+
944
+ return 1;
945
+ }
946
+
947
+ static int
948
+ passDoAction(const TranslationTableHeader *table, const InString **input,
949
+ OutString *output, int *posMapping, int transOpcode,
950
+ const TranslationTableRule **transRule, int passCharDots,
951
+ const widechar *passInstructions, int passIC, int *pos, PassRuleMatch match,
952
+ int *cursorPosition, int *cursorStatus, TranslationTableRule *groupingRule,
953
+ widechar groupingOp, int mode) {
954
+ int k;
955
+ TranslationTableOffset ruleOffset = 0;
956
+ TranslationTableRule *rule = NULL;
957
+ int destStartMatch = output->length;
958
+ int destStartReplace;
959
+ int newPos = match.endReplace;
960
+
961
+ if (!copyCharacters(match.startMatch, match.startReplace, table, *input, output,
962
+ posMapping, transOpcode, cursorPosition, cursorStatus, mode))
963
+ return 0;
964
+ destStartReplace = output->length;
965
+
966
+ while (passIC < (*transRule)->dotslen) switch (passInstructions[passIC]) {
967
+ case pass_string:
968
+ case pass_dots:
969
+ if ((output->length + passInstructions[passIC + 1]) > output->maxlength)
970
+ return 0;
971
+ for (k = 0; k < passInstructions[passIC + 1]; ++k)
972
+ posMapping[output->length + k] = match.startReplace;
973
+ memcpy(&output->chars[output->length], &passInstructions[passIC + 2],
974
+ passInstructions[passIC + 1] * CHARSIZE);
975
+ output->length += passInstructions[passIC + 1];
976
+ passIC += passInstructions[passIC + 1] + 2;
977
+ break;
978
+ case pass_groupstart:
979
+ ruleOffset =
980
+ (passInstructions[passIC + 1] << 16) | passInstructions[passIC + 2];
981
+ rule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
982
+ if ((output->length + 1) > output->maxlength) return 0;
983
+ posMapping[output->length] = match.startMatch;
984
+ output->chars[output->length++] = rule->charsdots[2 * passCharDots];
985
+ passIC += 3;
986
+ break;
987
+ case pass_groupend:
988
+ ruleOffset =
989
+ (passInstructions[passIC + 1] << 16) | passInstructions[passIC + 2];
990
+ rule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
991
+ if ((output->length + 1) > output->maxlength) return 0;
992
+ posMapping[output->length] = match.startMatch;
993
+ output->chars[output->length++] = rule->charsdots[2 * passCharDots + 1];
994
+ passIC += 3;
995
+ break;
996
+ case pass_swap:
997
+ if (!swapReplace(match.startReplace, match.endReplace, table, *input, output,
998
+ posMapping, passInstructions, passIC))
999
+ return 0;
1000
+ passIC += 3;
1001
+ break;
1002
+ case pass_groupreplace:
1003
+ if (!groupingRule ||
1004
+ !replaceGrouping(table, input, output, transOpcode, passCharDots,
1005
+ passInstructions, passIC, match.startReplace, groupingRule,
1006
+ groupingOp))
1007
+ return 0;
1008
+ passIC += 3;
1009
+ break;
1010
+ case pass_omit:
1011
+ if (groupingRule)
1012
+ removeGrouping(input, output, passCharDots, match.startReplace,
1013
+ groupingRule, groupingOp);
1014
+ passIC++;
1015
+ break;
1016
+ case pass_copy: {
1017
+ int count = destStartReplace - destStartMatch;
1018
+ if (count > 0) {
1019
+ memmove(&output->chars[destStartMatch], &output->chars[destStartReplace],
1020
+ (output->length - destStartReplace) * sizeof(*output->chars));
1021
+ output->length -= count;
1022
+ destStartReplace = destStartMatch;
1023
+ }
1024
+ }
1025
+
1026
+ if (!copyCharacters(match.startReplace, match.endReplace, table, *input,
1027
+ output, posMapping, transOpcode, cursorPosition, cursorStatus,
1028
+ mode))
1029
+ return 0;
1030
+ newPos = match.endMatch;
1031
+ passIC++;
1032
+ break;
1033
+ default:
1034
+ if (_lou_handlePassVariableAction(passInstructions, &passIC)) break;
1035
+ return 0;
1036
+ }
1037
+ *pos = newPos;
1038
+ return 1;
1039
+ }
1040
+
1041
+ static void
1042
+ passSelectRule(const TranslationTableHeader *table, int pos, int currentPass,
1043
+ const InString *input, int *transOpcode, const TranslationTableRule **transRule,
1044
+ int *transCharslen, int *passCharDots, widechar const **passInstructions,
1045
+ int *passIC, PassRuleMatch *match, TranslationTableRule **groupingRule,
1046
+ widechar *groupingOp) {
1047
+ if (!findForPassRule(table, pos, currentPass, input, transOpcode, transRule,
1048
+ transCharslen, passCharDots, passInstructions, passIC, match,
1049
+ groupingRule, groupingOp)) {
1050
+ *transOpcode = CTO_Always;
1051
+ }
1052
+ }
1053
+
1054
+ static int
1055
+ translatePass(const TranslationTableHeader *table, int currentPass, const InString *input,
1056
+ OutString *output, int *posMapping, int *realInlen, int *cursorPosition,
1057
+ int *cursorStatus, int mode) {
1058
+ int pos;
1059
+ int transOpcode;
1060
+ const TranslationTableRule *transRule;
1061
+ int transCharslen;
1062
+ int passCharDots;
1063
+ const widechar *passInstructions;
1064
+ int passIC; /* Instruction counter */
1065
+ PassRuleMatch patternMatch;
1066
+ TranslationTableRule *groupingRule;
1067
+ widechar groupingOp;
1068
+ const InString *origInput = input;
1069
+ pos = output->length = 0;
1070
+ int posIncremented = 1;
1071
+ _lou_resetPassVariables();
1072
+ while (pos < input->length) { /* the main multipass translation loop */
1073
+ // check posIncremented to avoid endless loop
1074
+ if (!posIncremented)
1075
+ transOpcode = CTO_Always;
1076
+ else
1077
+ passSelectRule(table, pos, currentPass, input, &transOpcode, &transRule,
1078
+ &transCharslen, &passCharDots, &passInstructions, &passIC,
1079
+ &patternMatch, &groupingRule, &groupingOp);
1080
+ posIncremented = 1;
1081
+ switch (transOpcode) {
1082
+ case CTO_Context:
1083
+ case CTO_Pass2:
1084
+ case CTO_Pass3:
1085
+ case CTO_Pass4: {
1086
+ const InString *inputBefore = input;
1087
+ int posBefore = pos;
1088
+ if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
1089
+ appliedRules[appliedRulesCount++] = transRule;
1090
+ if (!passDoAction(table, &input, output, posMapping, transOpcode, &transRule,
1091
+ passCharDots, passInstructions, passIC, &pos, patternMatch,
1092
+ cursorPosition, cursorStatus, groupingRule, groupingOp, mode))
1093
+ goto failure;
1094
+ if (input->bufferIndex != inputBefore->bufferIndex &&
1095
+ inputBefore->bufferIndex != origInput->bufferIndex)
1096
+ releaseStringBuffer(inputBefore->bufferIndex);
1097
+ if (pos == posBefore) posIncremented = 0;
1098
+ break;
1099
+ }
1100
+ case CTO_Always:
1101
+ if ((output->length + 1) > output->maxlength) goto failure;
1102
+ posMapping[output->length] = pos;
1103
+ output->chars[output->length++] = input->chars[pos++];
1104
+ break;
1105
+ default:
1106
+ goto failure;
1107
+ }
1108
+ }
1109
+ failure:
1110
+ if (pos < input->length) {
1111
+ while (checkDotsAttr(input->chars[pos], CTC_Space, table))
1112
+ if (++pos == input->length) break;
1113
+ }
1114
+ *realInlen = pos;
1115
+ if (input->bufferIndex != origInput->bufferIndex)
1116
+ releaseStringBuffer(input->bufferIndex);
1117
+ return 1;
1118
+ }
1119
+
1120
+ #define MIN(a, b) (((a) < (b)) ? (a) : (b))
1121
+
1122
+ static int
1123
+ translateString(const TranslationTableHeader *table, int mode, int currentPass,
1124
+ const InString *input, OutString *output, int *posMapping, formtype *typebuf,
1125
+ unsigned int *wordBuffer, EmphasisInfo *emphasisBuffer, int haveEmphasis,
1126
+ int *realInlen, int *cursorPosition, int *cursorStatus, int compbrlStart,
1127
+ int compbrlEnd);
1128
+
1129
+ int EXPORT_CALL
1130
+ lou_translateString(const char *tableList, const widechar *inbufx, int *inlen,
1131
+ widechar *outbuf, int *outlen, formtype *typeform, char *spacing, int mode) {
1132
+ return lou_translate(tableList, inbufx, inlen, outbuf, outlen, typeform, spacing,
1133
+ NULL, NULL, NULL, mode);
1134
+ }
1135
+
1136
+ int EXPORT_CALL
1137
+ lou_translate(const char *tableList, const widechar *inbufx, int *inlen, widechar *outbuf,
1138
+ int *outlen, formtype *typeform, char *spacing, int *outputPos, int *inputPos,
1139
+ int *cursorPos, int mode) {
1140
+ return _lou_translate(tableList, tableList, inbufx, inlen, outbuf, outlen, typeform,
1141
+ spacing, outputPos, inputPos, cursorPos, mode, NULL, NULL);
1142
+ }
1143
+
1144
+ int EXPORT_CALL
1145
+ _lou_translate(const char *tableList, const char *displayTableList,
1146
+ const widechar *inbufx, int *inlen, widechar *outbuf, int *outlen,
1147
+ formtype *typeform, char *spacing, int *outputPos, int *inputPos, int *cursorPos,
1148
+ int mode, const TranslationTableRule **rules, int *rulesLen) {
1149
+ // int i;
1150
+ // for(i = 0; i < *inlen; i++)
1151
+ // {
1152
+ // outbuf[i] = inbufx[i];
1153
+ // if(inputPos)
1154
+ // inputPos[i] = i;
1155
+ // if(outputPos)
1156
+ // outputPos[i] = i;
1157
+ // }
1158
+ // *inlen = i;
1159
+ // *outlen = i;
1160
+ // return 1;
1161
+ const TranslationTableHeader *table;
1162
+ const DisplayTableHeader *displayTable;
1163
+ InString input;
1164
+ OutString output;
1165
+ // posMapping contains position mapping info between the initial input and the output
1166
+ // of the current pass. It is 1 longer than the output. The values are monotonically
1167
+ // increasing and can range between -1 and the (consumed) input length. At the end the
1168
+ // position info is passed to the user as an inputPos and outputPos array. inputPos
1169
+ // has the length of the final output and has values ranging from 0 to inlen-1.
1170
+ // outputPos has the length of the (consumed) initial input and has values ranging
1171
+ // from 0 to outlen-1.
1172
+ int *posMapping;
1173
+ int *posMapping1;
1174
+ int *posMapping2;
1175
+ int *posMapping3;
1176
+ formtype *typebuf;
1177
+ unsigned int *wordBuffer;
1178
+ EmphasisInfo *emphasisBuffer;
1179
+ int cursorPosition;
1180
+ int cursorStatus;
1181
+ int haveEmphasis;
1182
+ int compbrlStart = -1;
1183
+ int compbrlEnd = -1;
1184
+ int k;
1185
+ int goodTrans = 1;
1186
+ if (tableList == NULL || inbufx == NULL || inlen == NULL || outbuf == NULL ||
1187
+ outlen == NULL)
1188
+ return 0;
1189
+ if (*inlen < 0 || *outlen < 0) return 0;
1190
+ _lou_logMessage(LOU_LOG_ALL, "Performing translation: tableList=%s, inlen=%d",
1191
+ tableList, *inlen);
1192
+ _lou_logWidecharBuf(LOU_LOG_ALL, "Inbuf=", inbufx, *inlen);
1193
+
1194
+ if (!_lou_isValidMode(mode)) {
1195
+ _lou_logMessage(LOU_LOG_ERROR, "Invalid mode parameter: %d", mode);
1196
+ return 0;
1197
+ }
1198
+
1199
+ if (displayTableList == NULL) displayTableList = tableList;
1200
+ _lou_getTable(tableList, displayTableList, &table, &displayTable);
1201
+ if (table == NULL) return 0;
1202
+ k = 0;
1203
+ while (k < *inlen && inbufx[k]) k++;
1204
+ input = (InString){ .chars = inbufx, .length = k, .bufferIndex = -1 };
1205
+ haveEmphasis = 0;
1206
+ if (!(typebuf = _lou_allocMem(alloc_typebuf, 0, input.length, *outlen))) return 0;
1207
+ if (typeform != NULL) {
1208
+ for (k = 0; k < input.length; k++) {
1209
+ typebuf[k] = typeform[k];
1210
+ if (typebuf[k] & EMPHASIS) haveEmphasis = 1;
1211
+ }
1212
+ } else
1213
+ memset(typebuf, 0, input.length * sizeof(formtype));
1214
+
1215
+ if (spacing != NULL)
1216
+ _lou_logMessage(LOU_LOG_WARN,
1217
+ "warning: the spacing parameter is deprecated and ignored; pass NULL");
1218
+ if (outputPos != NULL)
1219
+ for (k = 0; k < input.length; k++) outputPos[k] = -1;
1220
+ if (cursorPos != NULL && *cursorPos >= 0) {
1221
+ cursorStatus = 0;
1222
+ cursorPosition = *cursorPos;
1223
+ if ((mode & (compbrlAtCursor | compbrlLeftCursor))) {
1224
+ compbrlStart = cursorPosition;
1225
+ if (checkCharAttr(input.chars[compbrlStart], CTC_Space, table))
1226
+ /* It would have been simpler to just set compbrlStart and compbrlEnd to
1227
+ * -1 (i.e. disable compbrlAtCursor/compbrlLeftCursor mode) if the cursor
1228
+ * is set on a space. But maybe there are cases where a space in computer
1229
+ * braille does not map to a blank cell, and the user expects to see the
1230
+ * computer braille representation when the space is under the cursor, so
1231
+ * we better leave it as it is.
1232
+ */
1233
+ compbrlEnd = compbrlStart + 1;
1234
+ else {
1235
+ while (compbrlStart >= 0 &&
1236
+ !checkCharAttr(input.chars[compbrlStart], CTC_Space, table))
1237
+ compbrlStart--;
1238
+ compbrlStart++;
1239
+ compbrlEnd = cursorPosition;
1240
+ if (!(mode & compbrlLeftCursor))
1241
+ while (compbrlEnd < input.length &&
1242
+ !checkCharAttr(input.chars[compbrlEnd], CTC_Space, table))
1243
+ compbrlEnd++;
1244
+ }
1245
+ }
1246
+ } else {
1247
+ cursorPosition = -1;
1248
+ cursorStatus = 1; /* so it won't check cursor position */
1249
+ }
1250
+ if (!(posMapping1 = _lou_allocMem(alloc_posMapping1, 0, input.length, *outlen)))
1251
+ return 0;
1252
+ if (table->numPasses > 1 || table->corrections) {
1253
+ if (!(posMapping2 = _lou_allocMem(alloc_posMapping2, 0, input.length, *outlen)))
1254
+ return 0;
1255
+ if (!(posMapping3 = _lou_allocMem(alloc_posMapping3, 0, input.length, *outlen)))
1256
+ return 0;
1257
+ }
1258
+ appliedRulesCount = 0;
1259
+ if (rules != NULL && rulesLen != NULL) {
1260
+ appliedRules = rules;
1261
+ maxAppliedRules = *rulesLen;
1262
+ } else {
1263
+ appliedRules = NULL;
1264
+ maxAppliedRules = 0;
1265
+ }
1266
+ {
1267
+ int idx;
1268
+ if (!stringBufferPool) initStringBufferPool();
1269
+ for (idx = 0; idx < stringBufferPool->size; idx++) releaseStringBuffer(idx);
1270
+ idx = getStringBuffer(*outlen);
1271
+ output = (OutString){ .chars = stringBufferPool->buffers[idx],
1272
+ .maxlength = *outlen,
1273
+ .length = 0,
1274
+ .bufferIndex = idx };
1275
+ }
1276
+ posMapping = posMapping1;
1277
+
1278
+ int currentPass = table->corrections ? 0 : 1;
1279
+ int *passPosMapping = posMapping;
1280
+ while (1) {
1281
+ int realInlen;
1282
+ switch (currentPass) {
1283
+ case 0:
1284
+ goodTrans = makeCorrections(table, &input, &output, passPosMapping, typebuf,
1285
+ &realInlen, &cursorPosition, &cursorStatus, mode);
1286
+ break;
1287
+ case 1: {
1288
+ if (!(wordBuffer = _lou_allocMem(alloc_wordBuffer, 0, input.length, *outlen)))
1289
+ return 0;
1290
+ if (!(emphasisBuffer = _lou_allocMem(
1291
+ alloc_emphasisBuffer, 0, input.length, *outlen)))
1292
+ return 0;
1293
+ goodTrans = translateString(table, mode, currentPass, &input, &output,
1294
+ passPosMapping, typebuf, wordBuffer, emphasisBuffer, haveEmphasis,
1295
+ &realInlen, &cursorPosition, &cursorStatus, compbrlStart, compbrlEnd);
1296
+ break;
1297
+ }
1298
+ default:
1299
+ goodTrans = translatePass(table, currentPass, &input, &output, passPosMapping,
1300
+ &realInlen, &cursorPosition, &cursorStatus, mode);
1301
+ break;
1302
+ }
1303
+ passPosMapping[output.length] = realInlen;
1304
+ if (passPosMapping == posMapping) {
1305
+ passPosMapping = posMapping2;
1306
+ } else {
1307
+ int *prevPosMapping = posMapping3;
1308
+ memcpy((int *)prevPosMapping, posMapping, (*outlen + 1) * sizeof(int));
1309
+ for (k = 0; k <= output.length; k++)
1310
+ if (passPosMapping[k] < 0)
1311
+ posMapping[k] = prevPosMapping[0];
1312
+ else
1313
+ posMapping[k] = prevPosMapping[passPosMapping[k]];
1314
+ }
1315
+ currentPass++;
1316
+ if (currentPass <= table->numPasses && goodTrans) {
1317
+ int idx;
1318
+ releaseStringBuffer(input.bufferIndex);
1319
+ input = (InString){ .chars = output.chars,
1320
+ .length = output.length,
1321
+ .bufferIndex = output.bufferIndex };
1322
+ idx = getStringBuffer(*outlen);
1323
+ output = (OutString){ .chars = stringBufferPool->buffers[idx],
1324
+ .maxlength = *outlen,
1325
+ .length = 0,
1326
+ .bufferIndex = idx };
1327
+ continue;
1328
+ }
1329
+ break;
1330
+ }
1331
+ if (goodTrans) {
1332
+ for (k = 0; k < output.length; k++) {
1333
+ if (typeform != NULL) {
1334
+ if ((output.chars[k] & (LOU_DOT_7 | LOU_DOT_8)))
1335
+ typeform[k] = '8';
1336
+ else
1337
+ typeform[k] = '0';
1338
+ }
1339
+ if ((mode & dotsIO)) {
1340
+ if ((mode & ucBrl))
1341
+ outbuf[k] = ((output.chars[k] & 0xff) | LOU_ROW_BRAILLE);
1342
+ else
1343
+ outbuf[k] = output.chars[k];
1344
+ } else {
1345
+ outbuf[k] = _lou_getCharForDots(output.chars[k], displayTable);
1346
+ if (!outbuf[k]) {
1347
+ // assume that if NUL character is returned, it's because the display
1348
+ // table has no mapping for the dot pattern (not because it maps to
1349
+ // NUL)
1350
+ _lou_logMessage(LOU_LOG_ERROR,
1351
+ "%s: no mapping for dot pattern %s in display table",
1352
+ displayTableList, _lou_showDots(&output.chars[k], 1));
1353
+ return 0;
1354
+ }
1355
+ }
1356
+ }
1357
+ *inlen = posMapping[output.length];
1358
+ *outlen = output.length;
1359
+ // Compute inputPos and outputPos from posMapping. The value at the last index of
1360
+ // posMapping is currectly not used.
1361
+ if (inputPos != NULL) {
1362
+ for (k = 0; k < *outlen; k++)
1363
+ if (posMapping[k] < 0)
1364
+ inputPos[k] = 0;
1365
+ else if (posMapping[k] > *inlen - 1)
1366
+ inputPos[k] = *inlen - 1;
1367
+ else
1368
+ inputPos[k] = posMapping[k];
1369
+ }
1370
+ if (outputPos != NULL) {
1371
+ int inpos = -1;
1372
+ int outpos = -1;
1373
+ for (k = 0; k < *outlen; k++)
1374
+ if (posMapping[k] > inpos) {
1375
+ while (inpos < posMapping[k]) {
1376
+ if (inpos >= 0 && inpos < *inlen)
1377
+ outputPos[inpos] = outpos < 0 ? 0 : outpos;
1378
+ inpos++;
1379
+ }
1380
+ outpos = k;
1381
+ }
1382
+ if (inpos < 0) inpos = 0;
1383
+ while (inpos < *inlen) outputPos[inpos++] = outpos;
1384
+ }
1385
+ }
1386
+ if (cursorPos != NULL && *cursorPos != -1) {
1387
+ if (outputPos != NULL)
1388
+ *cursorPos = outputPos[*cursorPos];
1389
+ else
1390
+ *cursorPos = cursorPosition;
1391
+ }
1392
+ if (rulesLen != NULL) *rulesLen = appliedRulesCount;
1393
+ _lou_logMessage(LOU_LOG_ALL, "Translation complete: outlen=%d", *outlen);
1394
+ _lou_logWidecharBuf(LOU_LOG_ALL, "Outbuf=", (const widechar *)outbuf, *outlen);
1395
+
1396
+ return goodTrans;
1397
+ }
1398
+
1399
+ int EXPORT_CALL
1400
+ lou_translatePrehyphenated(const char *tableList, const widechar *inbufx, int *inlen,
1401
+ widechar *outbuf, int *outlen, formtype *typeform, char *spacing, int *outputPos,
1402
+ int *inputPos, int *cursorPos, char *inputHyphens, char *outputHyphens,
1403
+ int mode) {
1404
+ int rv = 1;
1405
+ int *alloc_inputPos = NULL;
1406
+ if (inputHyphens != NULL) {
1407
+ if (outputHyphens == NULL) return 0;
1408
+ if (inputPos == NULL) {
1409
+ if ((alloc_inputPos = malloc(*outlen * sizeof(int))) == NULL)
1410
+ _lou_outOfMemory();
1411
+ inputPos = alloc_inputPos;
1412
+ }
1413
+ }
1414
+ if (lou_translate(tableList, inbufx, inlen, outbuf, outlen, typeform, spacing,
1415
+ outputPos, inputPos, cursorPos, mode)) {
1416
+ if (inputHyphens != NULL) {
1417
+ int inpos = 0;
1418
+ int outpos;
1419
+ for (outpos = 0; outpos < *outlen; outpos++) {
1420
+ int new_inpos = inputPos[outpos];
1421
+ if (new_inpos < inpos) {
1422
+ rv = 0;
1423
+ break;
1424
+ }
1425
+ if (new_inpos > inpos)
1426
+ outputHyphens[outpos] = inputHyphens[new_inpos];
1427
+ else
1428
+ outputHyphens[outpos] = '0';
1429
+ inpos = new_inpos;
1430
+ }
1431
+ }
1432
+ }
1433
+ if (alloc_inputPos != NULL) free(alloc_inputPos);
1434
+ return rv;
1435
+ }
1436
+
1437
+ static int
1438
+ hyphenateWord(const widechar *word, int wordSize, char *hyphens,
1439
+ const TranslationTableHeader *table) {
1440
+ widechar *prepWord;
1441
+ int i, k, limit;
1442
+ int stateNum;
1443
+ widechar ch;
1444
+ HyphenationState *statesArray =
1445
+ (HyphenationState *)&table->ruleArea[table->hyphenStatesArray];
1446
+ HyphenationState *currentState;
1447
+ HyphenationTrans *transitionsArray;
1448
+ char *hyphenPattern;
1449
+ int patternOffset;
1450
+ if (!table->hyphenStatesArray || (wordSize + 3) > MAXSTRING) return 0;
1451
+ prepWord = (widechar *)calloc(wordSize + 3, sizeof(widechar));
1452
+ /* prepWord is of the format ".hello."
1453
+ * hyphens is the length of the word "hello" "00000" */
1454
+ prepWord[0] = '.';
1455
+ for (i = 0; i < wordSize; i++) {
1456
+ prepWord[i + 1] = toLowercase(table, getChar(word[i], table));
1457
+ hyphens[i] = '0';
1458
+ }
1459
+ prepWord[wordSize + 1] = '.';
1460
+
1461
+ /* now, run the finite state machine */
1462
+ stateNum = 0;
1463
+
1464
+ // we need to walk all of ".hello."
1465
+ for (i = 0; i < wordSize + 2; i++) {
1466
+ ch = prepWord[i];
1467
+ while (1) {
1468
+ if (stateNum == 0xffff) {
1469
+ stateNum = 0;
1470
+ goto nextLetter;
1471
+ }
1472
+ currentState = &statesArray[stateNum];
1473
+ if (currentState->trans.offset) {
1474
+ transitionsArray =
1475
+ (HyphenationTrans *)&table->ruleArea[currentState->trans.offset];
1476
+ for (k = 0; k < currentState->numTrans; k++) {
1477
+ if (transitionsArray[k].ch == ch) {
1478
+ stateNum = transitionsArray[k].newState;
1479
+ goto stateFound;
1480
+ }
1481
+ }
1482
+ }
1483
+ stateNum = currentState->fallbackState;
1484
+ }
1485
+ stateFound:
1486
+ currentState = &statesArray[stateNum];
1487
+ if (currentState->hyphenPattern) {
1488
+ hyphenPattern = (char *)&table->ruleArea[currentState->hyphenPattern];
1489
+ patternOffset = i + 1 - (int)strlen(hyphenPattern);
1490
+
1491
+ /* Need to ensure that we don't overrun hyphens,
1492
+ * in some cases hyphenPattern is longer than the remaining letters,
1493
+ * and if we write out all of it we would have overshot our buffer. */
1494
+ limit = MIN((int)strlen(hyphenPattern), wordSize - patternOffset);
1495
+ for (k = 0; k < limit; k++) {
1496
+ if (hyphens[patternOffset + k] < hyphenPattern[k])
1497
+ hyphens[patternOffset + k] = hyphenPattern[k];
1498
+ }
1499
+ }
1500
+ nextLetter:;
1501
+ }
1502
+ hyphens[wordSize] = 0;
1503
+ free(prepWord);
1504
+ return 1;
1505
+ }
1506
+
1507
+ static int
1508
+ doCompTrans(int start, int end, const TranslationTableHeader *table, int *pos,
1509
+ const InString *input, OutString *output, int *posMapping,
1510
+ EmphasisInfo *emphasisBuffer, const TranslationTableRule **transRule,
1511
+ int *cursorPosition, int *cursorStatus, int mode);
1512
+
1513
+ // The `shift' argument should be used with care because it can mess up the positions
1514
+ // array which is supposed to be monotonically increasing. It is set to -1 in order to
1515
+ // append certain indicators (endemphword, endemph, endemphphrase after, endcapsword,
1516
+ // endcaps, endcapsphrase after) to the preceding character.
1517
+ static int
1518
+ for_updatePositions(const widechar *outChars, int inLength, int outLength, int shift,
1519
+ int pos, const InString *input, OutString *output, int *posMapping,
1520
+ int *cursorPosition, int *cursorStatus) {
1521
+ int k;
1522
+ if ((output->length + outLength) > output->maxlength ||
1523
+ (pos + inLength) > input->length)
1524
+ return 0;
1525
+ memcpy(&output->chars[output->length], outChars, outLength * CHARSIZE);
1526
+ if (!*cursorStatus) {
1527
+ if (*cursorPosition >= pos && *cursorPosition < (pos + inLength)) {
1528
+ *cursorPosition = output->length;
1529
+ *cursorStatus = 1;
1530
+ } else if (input->chars[*cursorPosition] == 0 &&
1531
+ *cursorPosition == (pos + inLength)) {
1532
+ *cursorPosition = output->length + outLength / 2 + 1;
1533
+ *cursorStatus = 1;
1534
+ }
1535
+ } else if (*cursorStatus == 2 && *cursorPosition == pos)
1536
+ *cursorPosition = output->length;
1537
+ for (k = 0; k < outLength; k++) posMapping[output->length + k] = pos + shift;
1538
+ output->length += outLength;
1539
+ return 1;
1540
+ }
1541
+
1542
+ static int
1543
+ syllableBreak(const TranslationTableHeader *table, int pos, const InString *input,
1544
+ int transCharslen) {
1545
+ int wordStart = 0;
1546
+ int wordEnd = 0;
1547
+ int wordSize = 0;
1548
+ int k = 0;
1549
+ char *hyphens = NULL;
1550
+ for (wordStart = pos; wordStart >= 0; wordStart--)
1551
+ if (!((getChar(input->chars[wordStart], table))->attributes & CTC_Letter)) {
1552
+ wordStart++;
1553
+ break;
1554
+ }
1555
+ if (wordStart < 0) wordStart = 0;
1556
+ for (wordEnd = pos; wordEnd < input->length; wordEnd++)
1557
+ if (!((getChar(input->chars[wordEnd], table))->attributes & CTC_Letter)) {
1558
+ wordEnd--;
1559
+ break;
1560
+ }
1561
+ if (wordEnd == input->length) wordEnd--;
1562
+ /* At this stage wordStart is the 0 based index of the first letter in the word,
1563
+ * wordEnd is the 0 based index of the last letter in the word.
1564
+ * example: "hello" wordstart=0, wordEnd=4. */
1565
+ wordSize = wordEnd - wordStart + 1;
1566
+ hyphens = (char *)calloc(wordSize + 1, sizeof(char));
1567
+ if (!hyphenateWord(&input->chars[wordStart], wordSize, hyphens, table)) {
1568
+ free(hyphens);
1569
+ return 0;
1570
+ }
1571
+ int limit = pos - wordStart + transCharslen;
1572
+ if (limit > wordSize) limit = wordSize;
1573
+ for (k = pos - wordStart + 1; k < limit; k++)
1574
+ if (hyphens[k] & 1) {
1575
+ free(hyphens);
1576
+ return 1;
1577
+ }
1578
+ free(hyphens);
1579
+ return 0;
1580
+ }
1581
+
1582
+ static void
1583
+ setBefore(const TranslationTableHeader *table, int pos, const InString *input,
1584
+ TranslationTableCharacterAttributes *beforeAttributes) {
1585
+ widechar before;
1586
+ if (pos >= 2 && input->chars[pos - 1] == LOU_ENDSEGMENT)
1587
+ before = input->chars[pos - 2];
1588
+ else
1589
+ before = (pos == 0) ? ' ' : input->chars[pos - 1];
1590
+ *beforeAttributes = (getChar(before, table))->attributes;
1591
+ }
1592
+
1593
+ static void
1594
+ setAfter(int length, const TranslationTableHeader *table, int pos, const InString *input,
1595
+ TranslationTableCharacterAttributes *afterAttributes) {
1596
+ widechar after;
1597
+ if ((pos + length + 2) < input->length && input->chars[pos + 1] == LOU_ENDSEGMENT)
1598
+ after = input->chars[pos + 2];
1599
+ else
1600
+ after = (pos + length < input->length) ? input->chars[pos + length] : ' ';
1601
+ *afterAttributes = (getChar(after, table))->attributes;
1602
+ }
1603
+
1604
+ static int
1605
+ brailleIndicatorDefined(TranslationTableOffset offset,
1606
+ const TranslationTableHeader *table, const TranslationTableRule **indicRule) {
1607
+ if (!offset) return 0;
1608
+ *indicRule = (TranslationTableRule *)&table->ruleArea[offset];
1609
+ return 1;
1610
+ }
1611
+
1612
+ /**
1613
+ * Return 1 if both `indicator1` and `indicator2` are defined and use the same dot
1614
+ * pattern. Otherwise return 0.
1615
+ */
1616
+ static int
1617
+ isIndicatorEqual(TranslationTableOffset indicator1, TranslationTableOffset indicator2,
1618
+ const TranslationTableHeader *table) {
1619
+ const TranslationTableRule *indicatorRule1;
1620
+ const TranslationTableRule *indicatorRule2;
1621
+
1622
+ if (brailleIndicatorDefined(indicator1, table, &indicatorRule1) &&
1623
+ brailleIndicatorDefined(indicator2, table, &indicatorRule2) &&
1624
+ indicatorRule1->dotslen == indicatorRule2->dotslen &&
1625
+ !memcmp(&indicatorRule1->charsdots[0], &indicatorRule2->charsdots[0],
1626
+ indicatorRule1->dotslen * CHARSIZE)) {
1627
+ return 1;
1628
+ } else {
1629
+ return 0;
1630
+ }
1631
+ }
1632
+
1633
+ static int
1634
+ capsletterDefined(const TranslationTableHeader *table) {
1635
+ return table->emphRules[MAX_EMPH_CLASSES][letterOffset];
1636
+ }
1637
+
1638
+ static int
1639
+ validMatch(const TranslationTableHeader *table, int pos, const InString *input,
1640
+ formtype *typebuf, const TranslationTableRule *transRule, int transCharslen) {
1641
+ /* Analyze the typeform parameter and also check for capitalization */
1642
+ TranslationTableCharacter *inputChar;
1643
+ TranslationTableCharacter *ruleChar;
1644
+ TranslationTableCharacterAttributes prevAttr = 0;
1645
+ int k;
1646
+ int kk = 0;
1647
+ if (!transCharslen) return 0;
1648
+ for (k = pos; k < pos + transCharslen; k++) {
1649
+ if (input->chars[k] == LOU_ENDSEGMENT) {
1650
+ if (k == pos && transCharslen == 1)
1651
+ return 1;
1652
+ else
1653
+ return 0;
1654
+ }
1655
+ inputChar = getChar(input->chars[k], table);
1656
+ if (k == pos) prevAttr = inputChar->attributes;
1657
+ ruleChar = getChar(transRule->charsdots[kk++], table);
1658
+ if (toLowercase(table, inputChar) != toLowercase(table, ruleChar)) return 0;
1659
+ if (typebuf != NULL && (typebuf[pos] & CAPSEMPH) == 0 &&
1660
+ (typebuf[k] | typebuf[pos]) != typebuf[pos])
1661
+ return 0;
1662
+ if (inputChar->attributes != CTC_Letter) {
1663
+ if (k != (pos + 1) && (prevAttr & CTC_Letter) &&
1664
+ (inputChar->attributes & CTC_Letter) &&
1665
+ ((inputChar->attributes &
1666
+ (CTC_LowerCase | CTC_UpperCase | CTC_Letter)) !=
1667
+ (prevAttr & (CTC_LowerCase | CTC_UpperCase | CTC_Letter))))
1668
+ return 0;
1669
+ }
1670
+ prevAttr = inputChar->attributes;
1671
+ }
1672
+ return 1;
1673
+ }
1674
+
1675
+ static int
1676
+ insertNumberSign(const TranslationTableHeader *table, int pos, const InString *input,
1677
+ OutString *output, int *posMapping, int prevTransOpcode, int *cursorPosition,
1678
+ int *cursorStatus, TranslationTableCharacterAttributes beforeAttributes) {
1679
+ const TranslationTableRule *numberSign;
1680
+ if (brailleIndicatorDefined(table->numberSign, table, &numberSign) &&
1681
+ checkCharAttr_safe(input, pos, CTC_Digit, table) &&
1682
+ (prevTransOpcode == CTO_ExactDots ||
1683
+ (!(beforeAttributes & CTC_Digit) && prevTransOpcode != CTO_MidNum))) {
1684
+ if (!for_updatePositions(&numberSign->charsdots[0], 0, numberSign->dotslen, 0,
1685
+ pos, input, output, posMapping, cursorPosition, cursorStatus))
1686
+ return 0;
1687
+ }
1688
+ return 1;
1689
+ }
1690
+
1691
+ static int
1692
+ isNoLetsign(widechar c, const TranslationTableHeader *table) {
1693
+ for (int k = 0; k < table->noLetsignCount; k++)
1694
+ if (c == table->noLetsign[k]) return 1;
1695
+ return 0;
1696
+ }
1697
+
1698
+ static int
1699
+ isNoLetsignBefore(widechar c, const TranslationTableHeader *table) {
1700
+ for (int k = 0; k < table->noLetsignBeforeCount; k++)
1701
+ if (c == table->noLetsignBefore[k]) return 1;
1702
+ return 0;
1703
+ }
1704
+
1705
+ static int
1706
+ isNoLetsignAfter(widechar c, const TranslationTableHeader *table) {
1707
+ for (int k = 0; k < table->noLetsignAfterCount; k++)
1708
+ if (c == table->noLetsignAfter[k]) return 1;
1709
+ return 0;
1710
+ }
1711
+
1712
+ static int
1713
+ insertLetterSign(const TranslationTableHeader *table, int pos, const InString *input,
1714
+ OutString *output, int *posMapping, int transOpcode, int *cursorPosition,
1715
+ int *cursorStatus, TranslationTableCharacterAttributes beforeAttributes) {
1716
+ const TranslationTableRule *letterSign;
1717
+ if (brailleIndicatorDefined(table->letterSign, table, &letterSign)) {
1718
+ if (transOpcode == CTO_Contraction) {
1719
+ if (!for_updatePositions(&letterSign->charsdots[0], 0, letterSign->dotslen, 0,
1720
+ pos, input, output, posMapping, cursorPosition, cursorStatus))
1721
+ return 0;
1722
+ } else if ((checkCharAttr_safe(input, pos, CTC_Letter, table) &&
1723
+ !(beforeAttributes & CTC_Letter)) &&
1724
+ (!checkCharAttr_safe(input, pos + 1, CTC_Letter, table) ||
1725
+ (beforeAttributes & CTC_Digit))) {
1726
+ if (pos > 0 && isNoLetsignBefore(input->chars[pos - 1], table)) return 1;
1727
+ if (isNoLetsign(input->chars[pos], table)) return 1;
1728
+ if (pos + 1 < input->length && isNoLetsignAfter(input->chars[pos + 1], table))
1729
+ return 1;
1730
+ if (!for_updatePositions(&letterSign->charsdots[0], 0, letterSign->dotslen, 0,
1731
+ pos, input, output, posMapping, cursorPosition, cursorStatus))
1732
+ return 0;
1733
+ }
1734
+ }
1735
+ return 1;
1736
+ }
1737
+
1738
+ static int
1739
+ onlyLettersBehind(const TranslationTableHeader *table, int pos, const InString *input,
1740
+ TranslationTableCharacterAttributes beforeAttributes) {
1741
+ /* Actually, spaces, then letters */
1742
+ int k;
1743
+ if (!(beforeAttributes & CTC_Space)) return 0;
1744
+ for (k = pos - 2; k >= 0; k--) {
1745
+ TranslationTableCharacterAttributes attr =
1746
+ (getChar(input->chars[k], table))->attributes;
1747
+ if ((attr & CTC_Space)) continue;
1748
+ if ((attr & CTC_Letter))
1749
+ return 1;
1750
+ else
1751
+ return 0;
1752
+ }
1753
+ return 1;
1754
+ }
1755
+
1756
+ static int
1757
+ onlyLettersAhead(const TranslationTableHeader *table, int pos, const InString *input,
1758
+ int transCharslen, TranslationTableCharacterAttributes afterAttributes) {
1759
+ /* Actullly, spaces, then letters */
1760
+ int k;
1761
+ if (!(afterAttributes & CTC_Space)) return 0;
1762
+ for (k = pos + transCharslen + 1; k < input->length; k++) {
1763
+ TranslationTableCharacterAttributes attr =
1764
+ (getChar(input->chars[k], table))->attributes;
1765
+ if ((attr & CTC_Space)) continue;
1766
+ if ((attr & (CTC_Letter | CTC_LitDigit)))
1767
+ return 1;
1768
+ else
1769
+ return 0;
1770
+ }
1771
+ return 0;
1772
+ }
1773
+
1774
+ static int
1775
+ noCompbrlAhead(const TranslationTableHeader *table, int pos, int mode,
1776
+ const InString *input, int transOpcode, int transCharslen, int cursorPosition) {
1777
+ int start = pos + transCharslen;
1778
+ int end;
1779
+ int p;
1780
+ if (start >= input->length) return 1;
1781
+ while (start < input->length && checkCharAttr(input->chars[start], CTC_Space, table))
1782
+ start++;
1783
+ if (start == input->length ||
1784
+ (transOpcode == CTO_JoinableWord &&
1785
+ (!checkCharAttr(input->chars[start], CTC_Letter | CTC_Digit, table) ||
1786
+ !checkCharAttr(input->chars[start - 1], CTC_Space, table))))
1787
+ return 1;
1788
+ end = start;
1789
+ while (end < input->length && !checkCharAttr(input->chars[end], CTC_Space, table))
1790
+ end++;
1791
+ if ((mode & (compbrlAtCursor | compbrlLeftCursor)) && cursorPosition >= start &&
1792
+ cursorPosition < end)
1793
+ return 0;
1794
+ /* Look ahead for rules with CTO_CompBrl */
1795
+ for (p = start; p < end; p++) {
1796
+ int length = input->length - p;
1797
+ int tryThis;
1798
+ int k;
1799
+ for (tryThis = 0; tryThis < 2; tryThis++) {
1800
+ TranslationTableOffset ruleOffset = 0;
1801
+ TranslationTableRule *testRule;
1802
+ switch (tryThis) {
1803
+ case 0:
1804
+ if (!(length >= 2)) break;
1805
+ ruleOffset = table->forRules[_lou_stringHash(&input->chars[p], 1, table)];
1806
+ break;
1807
+ case 1:
1808
+ if (!(length >= 1)) break;
1809
+ length = 1;
1810
+ ruleOffset = getChar(input->chars[p], table)->otherRules;
1811
+ break;
1812
+ }
1813
+ while (ruleOffset) {
1814
+ const TranslationTableCharacter *character1;
1815
+ const TranslationTableCharacter *character2;
1816
+ testRule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
1817
+ for (k = 0; k < testRule->charslen && k < length; k++) {
1818
+ character1 = getChar(testRule->charsdots[k], table);
1819
+ character2 = getChar(input->chars[p + k], table);
1820
+ if (toLowercase(table, character1) != toLowercase(table, character2))
1821
+ break;
1822
+ }
1823
+ if (tryThis == 1 || k == testRule->charslen) {
1824
+ if (testRule->opcode == CTO_CompBrl) return 0;
1825
+ }
1826
+ ruleOffset = testRule->charsnext;
1827
+ }
1828
+ }
1829
+ }
1830
+ return 1;
1831
+ }
1832
+
1833
+ static int
1834
+ checkEmphasisChange(int pos, int len, const EmphasisInfo *emphasisBuffer) {
1835
+ int i;
1836
+ for (i = pos + 1; i < pos + len; i++)
1837
+ if (emphasisBuffer[i].begin || emphasisBuffer[i].end || emphasisBuffer[i].word ||
1838
+ emphasisBuffer[i].symbol)
1839
+ return 1;
1840
+ return 0;
1841
+ }
1842
+
1843
+ static int
1844
+ isRepeatedWord(const TranslationTableHeader *table, int pos, const InString *input,
1845
+ const EmphasisInfo *emphasisBuffer, int outputLength, const int *posMapping,
1846
+ int transCharslen, int *repwordLength) {
1847
+ /* transCharslen is the length of the character sequence that separates the repeated
1848
+ * parts */
1849
+ int len;
1850
+ /* maximum length that the repeated part can have is determined by how many letters
1851
+ * there are before and after the separator */
1852
+ for (len = 1; pos - len >= 0 && pos + transCharslen + len - 1 < input->length &&
1853
+ checkCharAttr(input->chars[pos - len], CTC_Letter, table) &&
1854
+ checkCharAttr(input->chars[pos + transCharslen + len - 1], CTC_Letter, table);
1855
+ len++);
1856
+ len--;
1857
+ /* now actually compare the parts, starting with the maximal length and making them
1858
+ * shorter if they don't match */
1859
+ while (len > 0) {
1860
+ int start = pos - len;
1861
+ if (compareChars(&input->chars[start], &input->chars[pos + transCharslen], len,
1862
+ table)) {
1863
+ /* part must not start within a contraction */
1864
+ for (int k = outputLength - 1; k >= 0; k--)
1865
+ if (posMapping[k] == start)
1866
+ break;
1867
+ else if (posMapping[k] < start)
1868
+ return 0;
1869
+ /* capitalisation and emphasis may not change except at the beginning of the
1870
+ * parts */
1871
+ if (checkEmphasisChange(start, len + transCharslen, emphasisBuffer) ||
1872
+ checkEmphasisChange(pos + transCharslen, len, emphasisBuffer))
1873
+ return 0;
1874
+ *repwordLength = len;
1875
+ return 1;
1876
+ }
1877
+ len--;
1878
+ }
1879
+ return 0;
1880
+ }
1881
+
1882
+ static int
1883
+ inSequence(const TranslationTableHeader *table, int pos, const InString *input,
1884
+ const TranslationTableRule *transRule) {
1885
+ int i, j, s, match;
1886
+ // TODO: all caps words
1887
+ // const TranslationTableCharacter *c = NULL;
1888
+
1889
+ /* check before sequence */
1890
+ for (i = pos - 1; i >= 0; i--) {
1891
+ if (checkCharAttr(input->chars[i], CTC_SeqBefore, table)) continue;
1892
+ if (!(checkCharAttr(input->chars[i], CTC_Space | CTC_SeqDelimiter, table)))
1893
+ return 0;
1894
+ break;
1895
+ }
1896
+
1897
+ /* check after sequence */
1898
+ for (i = pos + transRule->charslen; i < input->length; i++) {
1899
+ /* check sequence after patterns */
1900
+ if (table->seqPatternsCount) {
1901
+ match = 0;
1902
+ for (j = i, s = 0; j <= input->length && s < table->seqPatternsCount;
1903
+ j++, s++) {
1904
+ /* matching */
1905
+ if (match == 1) {
1906
+ if (table->seqPatterns[s]) {
1907
+ if (input->chars[j] == table->seqPatterns[s])
1908
+ match = 1;
1909
+ else {
1910
+ match = -1;
1911
+ j = i - 1;
1912
+ }
1913
+ }
1914
+
1915
+ /* found match */
1916
+ else {
1917
+ /* pattern at end of input */
1918
+ if (j >= input->length) return 1;
1919
+
1920
+ i = j;
1921
+ break;
1922
+ }
1923
+ }
1924
+
1925
+ /* looking for match */
1926
+ else if (match == 0) {
1927
+ if (table->seqPatterns[s]) {
1928
+ if (input->chars[j] == table->seqPatterns[s])
1929
+ match = 1;
1930
+ else {
1931
+ match = -1;
1932
+ j = i - 1;
1933
+ }
1934
+ }
1935
+ }
1936
+
1937
+ /* next pattarn */
1938
+ else if (match == -1) {
1939
+ if (!table->seqPatterns[s]) {
1940
+ match = 0;
1941
+ j = i - 1;
1942
+ }
1943
+ }
1944
+ }
1945
+ }
1946
+
1947
+ if (checkCharAttr(input->chars[i], CTC_SeqAfter, table)) continue;
1948
+ if (!(checkCharAttr(input->chars[i], CTC_Space | CTC_SeqDelimiter, table)))
1949
+ return 0;
1950
+ break;
1951
+ }
1952
+
1953
+ return 1;
1954
+ }
1955
+
1956
+ static void
1957
+ for_selectRule(const TranslationTableHeader *table, int pos, OutString output,
1958
+ const int *posMapping, int mode, const InString *input, formtype *typebuf,
1959
+ EmphasisInfo *emphasisBuffer, int *transOpcode, int prevTransOpcode,
1960
+ const TranslationTableRule **transRule, int *transCharslen, int *passCharDots,
1961
+ widechar const **passInstructions, int *passIC, PassRuleMatch *patternMatch,
1962
+ int posIncremented, int cursorPosition, int *repwordLength, int dontContract,
1963
+ int compbrlStart, int compbrlEnd,
1964
+ TranslationTableCharacterAttributes beforeAttributes,
1965
+ TranslationTableCharacter **curCharDef, TranslationTableRule **groupingRule,
1966
+ widechar *groupingOp) {
1967
+ /* check for valid Translations. Return value is in transRule. */
1968
+ static TranslationTableRule pseudoRule = { 0 };
1969
+ int length = ((pos < compbrlStart) ? compbrlStart : input->length) - pos;
1970
+ int tryThis;
1971
+ int k;
1972
+ TranslationTableOffset ruleOffset = 0;
1973
+ *curCharDef = getChar(input->chars[pos], table);
1974
+ for (tryThis = 0; tryThis < 3; tryThis++) {
1975
+ switch (tryThis) {
1976
+ case 0:
1977
+ if (!(length >= 2)) break;
1978
+ ruleOffset = table->forRules[_lou_stringHash(&input->chars[pos], 1, table)];
1979
+ break;
1980
+ case 1:
1981
+ if (!(length >= 1)) break;
1982
+ length = 1;
1983
+ ruleOffset = (*curCharDef)->otherRules;
1984
+ break;
1985
+ case 2: /* No rule found */
1986
+ *transRule = &pseudoRule;
1987
+ *transOpcode = pseudoRule.opcode = CTO_None;
1988
+ *transCharslen = pseudoRule.charslen = 1;
1989
+ pseudoRule.charsdots[0] = input->chars[pos];
1990
+ pseudoRule.dotslen = 0;
1991
+ return;
1992
+ }
1993
+ while (ruleOffset) {
1994
+ *transRule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
1995
+ *transOpcode = (*transRule)->opcode;
1996
+ *transCharslen = (*transRule)->charslen;
1997
+ if (tryThis == 1 ||
1998
+ ((*transCharslen <= length) &&
1999
+ validMatch(table, pos, input, typebuf, *transRule,
2000
+ *transCharslen))) {
2001
+ TranslationTableCharacterAttributes afterAttributes;
2002
+ /* check before emphasis match */
2003
+ if ((*transRule)->before & CTC_EmpMatch) {
2004
+ if (emphasisBuffer[pos].begin || emphasisBuffer[pos].end ||
2005
+ emphasisBuffer[pos].word || emphasisBuffer[pos].symbol)
2006
+ break;
2007
+ }
2008
+
2009
+ /* check after emphasis match */
2010
+ if ((*transRule)->after & CTC_EmpMatch) {
2011
+ if (emphasisBuffer[pos + *transCharslen].begin ||
2012
+ emphasisBuffer[pos + *transCharslen].end ||
2013
+ emphasisBuffer[pos + *transCharslen].word ||
2014
+ emphasisBuffer[pos + *transCharslen].symbol)
2015
+ break;
2016
+ }
2017
+
2018
+ /* check this rule */
2019
+ setAfter(*transCharslen, table, pos, input, &afterAttributes);
2020
+ if ((!((*transRule)->after & ~CTC_EmpMatch) ||
2021
+ (beforeAttributes & (*transRule)->after)) &&
2022
+ (!((*transRule)->before & ~CTC_EmpMatch) ||
2023
+ (afterAttributes & (*transRule)->before)))
2024
+ /* check nocross */
2025
+ if (!((*transRule)->nocross &&
2026
+ syllableBreak(table, pos, input, *transCharslen))) {
2027
+ switch (*transOpcode) { /* check validity of this Translation */
2028
+ case CTO_Space:
2029
+ case CTO_Letter:
2030
+ case CTO_UpperCase:
2031
+ case CTO_LowerCase:
2032
+ case CTO_Digit:
2033
+ case CTO_LitDigit:
2034
+ case CTO_Punctuation:
2035
+ case CTO_Math:
2036
+ case CTO_Sign:
2037
+ case CTO_Hyphen:
2038
+ case CTO_Replace:
2039
+ case CTO_CompBrl:
2040
+ return;
2041
+ case CTO_Repeated:
2042
+ if (dontContract || (mode & noContractions)) break;
2043
+ if ((mode & (compbrlAtCursor | compbrlLeftCursor)) &&
2044
+ pos >= compbrlStart && pos <= compbrlEnd)
2045
+ break;
2046
+ return;
2047
+ case CTO_RepWord:
2048
+ case CTO_RepEndWord:
2049
+ if (dontContract || (mode & noContractions)) break;
2050
+ if (isRepeatedWord(table, pos, input, emphasisBuffer,
2051
+ output.length, posMapping, *transCharslen,
2052
+ repwordLength)) {
2053
+ if ((pos > *repwordLength &&
2054
+ checkCharAttr(input->chars[pos -
2055
+ *repwordLength - 1],
2056
+ CTC_Letter, table)) ==
2057
+ (*transOpcode == CTO_RepEndWord)) {
2058
+ return;
2059
+ }
2060
+ }
2061
+ break;
2062
+ case CTO_NoCont:
2063
+ if (dontContract || (mode & noContractions)) break;
2064
+ return;
2065
+ case CTO_Syllable:
2066
+ *transOpcode = CTO_Always;
2067
+ case CTO_Always:
2068
+ if (checkEmphasisChange(pos, *transCharslen, emphasisBuffer))
2069
+ break;
2070
+ if (dontContract || (mode & noContractions)) break;
2071
+ return;
2072
+ case CTO_ExactDots:
2073
+ return;
2074
+ case CTO_Context:
2075
+ // check posIncremented to avoid endless loop
2076
+ if (!posIncremented ||
2077
+ !passDoTest(table, pos, input, *transOpcode,
2078
+ *transRule, passCharDots, passInstructions,
2079
+ passIC, patternMatch, groupingRule,
2080
+ groupingOp))
2081
+ break;
2082
+ return;
2083
+ case CTO_LargeSign:
2084
+ if (dontContract || (mode & noContractions)) break;
2085
+ if (!((beforeAttributes & (CTC_Space | CTC_Punctuation)) ||
2086
+ onlyLettersBehind(
2087
+ table, pos, input, beforeAttributes)) ||
2088
+ !((afterAttributes & CTC_Space) ||
2089
+ prevTransOpcode == CTO_LargeSign) ||
2090
+ (afterAttributes & CTC_Letter) ||
2091
+ !noCompbrlAhead(table, pos, mode, input, *transOpcode,
2092
+ *transCharslen, cursorPosition))
2093
+ *transOpcode = CTO_Always;
2094
+ return;
2095
+ case CTO_WholeWord:
2096
+ if (dontContract || (mode & noContractions)) break;
2097
+ if (checkEmphasisChange(pos, *transCharslen, emphasisBuffer))
2098
+ break;
2099
+ case CTO_Contraction:
2100
+ if (table->usesSequences) {
2101
+ if (inSequence(table, pos, input, *transRule)) return;
2102
+ } else {
2103
+ if ((beforeAttributes & (CTC_Space | CTC_Punctuation)) &&
2104
+ (afterAttributes & (CTC_Space | CTC_Punctuation)))
2105
+ return;
2106
+ }
2107
+ break;
2108
+ case CTO_PartWord:
2109
+ if (dontContract || (mode & noContractions)) break;
2110
+ if ((beforeAttributes & CTC_Letter) ||
2111
+ (afterAttributes & CTC_Letter))
2112
+ return;
2113
+ break;
2114
+ case CTO_JoinNum:
2115
+ if (dontContract || (mode & noContractions)) break;
2116
+ if ((beforeAttributes & (CTC_Space | CTC_Punctuation)) &&
2117
+ (afterAttributes & CTC_Space) &&
2118
+ (output.length + (*transRule)->dotslen <
2119
+ output.maxlength)) {
2120
+ int p = pos + *transCharslen + 1;
2121
+ while (p < input->length) {
2122
+ if (!checkCharAttr(
2123
+ input->chars[p], CTC_Space, table)) {
2124
+ if (checkCharAttr(
2125
+ input->chars[p], CTC_Digit, table))
2126
+ return;
2127
+ break;
2128
+ }
2129
+ p++;
2130
+ }
2131
+ }
2132
+ break;
2133
+ case CTO_LowWord:
2134
+ if (dontContract || (mode & noContractions)) break;
2135
+ if ((beforeAttributes & CTC_Space) &&
2136
+ (afterAttributes & CTC_Space) &&
2137
+ (prevTransOpcode != CTO_JoinableWord))
2138
+ return;
2139
+ break;
2140
+ case CTO_JoinableWord:
2141
+ if (dontContract || (mode & noContractions)) break;
2142
+ if (beforeAttributes & (CTC_Space | CTC_Punctuation) &&
2143
+ onlyLettersAhead(table, pos, input, *transCharslen,
2144
+ afterAttributes) &&
2145
+ noCompbrlAhead(table, pos, mode, input, *transOpcode,
2146
+ *transCharslen, cursorPosition))
2147
+ return;
2148
+ break;
2149
+ case CTO_SuffixableWord:
2150
+ if (dontContract || (mode & noContractions)) break;
2151
+ if ((beforeAttributes &
2152
+ (CTC_Space | CTC_Punctuation |
2153
+ CTC_SeqDelimiter)) &&
2154
+ (afterAttributes &
2155
+ (CTC_Space | CTC_Letter | CTC_Punctuation |
2156
+ CTC_SeqDelimiter)))
2157
+ return;
2158
+ break;
2159
+ case CTO_PrefixableWord:
2160
+ if (dontContract || (mode & noContractions)) break;
2161
+ if ((beforeAttributes &
2162
+ (CTC_Space | CTC_Letter | CTC_Punctuation |
2163
+ CTC_SeqDelimiter)) &&
2164
+ (afterAttributes &
2165
+ (CTC_Space | CTC_Punctuation |
2166
+ CTC_SeqDelimiter)))
2167
+ return;
2168
+ break;
2169
+ case CTO_BegWord:
2170
+ if (dontContract || (mode & noContractions)) break;
2171
+ if ((beforeAttributes & (CTC_Space | CTC_Punctuation)) &&
2172
+ (afterAttributes & CTC_Letter))
2173
+ return;
2174
+ break;
2175
+ case CTO_BegMidWord:
2176
+ if (dontContract || (mode & noContractions)) break;
2177
+ if ((beforeAttributes &
2178
+ (CTC_Letter | CTC_Space | CTC_Punctuation)) &&
2179
+ (afterAttributes & CTC_Letter))
2180
+ return;
2181
+ break;
2182
+ case CTO_MidWord:
2183
+ if (dontContract || (mode & noContractions)) break;
2184
+ if (beforeAttributes & CTC_Letter &&
2185
+ afterAttributes & CTC_Letter)
2186
+ return;
2187
+ break;
2188
+ case CTO_MidEndWord:
2189
+ if (dontContract || (mode & noContractions)) break;
2190
+ if (beforeAttributes & CTC_Letter &&
2191
+ afterAttributes &
2192
+ (CTC_Letter | CTC_Space | CTC_Punctuation))
2193
+ return;
2194
+ break;
2195
+ case CTO_EndWord:
2196
+ if (dontContract || (mode & noContractions)) break;
2197
+ if (beforeAttributes & CTC_Letter &&
2198
+ afterAttributes & (CTC_Space | CTC_Punctuation))
2199
+ return;
2200
+ break;
2201
+ case CTO_BegNum:
2202
+ if (beforeAttributes & (CTC_Space | CTC_Punctuation) &&
2203
+ afterAttributes & CTC_Digit)
2204
+ return;
2205
+ break;
2206
+ case CTO_MidNum:
2207
+ if (prevTransOpcode != CTO_ExactDots &&
2208
+ beforeAttributes & CTC_Digit &&
2209
+ afterAttributes & CTC_Digit)
2210
+ return;
2211
+ break;
2212
+ case CTO_EndNum:
2213
+ if (beforeAttributes & CTC_Digit &&
2214
+ prevTransOpcode != CTO_ExactDots)
2215
+ return;
2216
+ break;
2217
+ case CTO_DecPoint:
2218
+ if (!(afterAttributes & CTC_Digit)) break;
2219
+ if (beforeAttributes & CTC_Digit) *transOpcode = CTO_MidNum;
2220
+ return;
2221
+ case CTO_PrePunc:
2222
+ if (!checkCharAttr(
2223
+ input->chars[pos], CTC_Punctuation, table) ||
2224
+ (pos > 0 &&
2225
+ checkCharAttr(input->chars[pos - 1],
2226
+ CTC_Letter, table)))
2227
+ break;
2228
+ for (k = pos + *transCharslen; k < input->length; k++) {
2229
+ if (checkCharAttr(input->chars[k],
2230
+ (CTC_Letter | CTC_Digit), table))
2231
+ return;
2232
+ if (checkCharAttr(input->chars[k], CTC_Space, table))
2233
+ break;
2234
+ }
2235
+ break;
2236
+ case CTO_PostPunc:
2237
+ if (!checkCharAttr(
2238
+ input->chars[pos], CTC_Punctuation, table) ||
2239
+ (pos < (input->length - 1) &&
2240
+ checkCharAttr(input->chars[pos + 1],
2241
+ CTC_Letter, table)))
2242
+ break;
2243
+ for (k = pos; k >= 0; k--) {
2244
+ if (checkCharAttr(input->chars[k],
2245
+ (CTC_Letter | CTC_Digit), table))
2246
+ return;
2247
+ if (checkCharAttr(input->chars[k], CTC_Space, table))
2248
+ break;
2249
+ }
2250
+ break;
2251
+
2252
+ case CTO_Match: {
2253
+ widechar *patterns, *pattern;
2254
+
2255
+ if (dontContract || (mode & noContractions)) break;
2256
+ if (checkEmphasisChange(pos, *transCharslen, emphasisBuffer))
2257
+ break;
2258
+
2259
+ patterns =
2260
+ (widechar *)&table->ruleArea[(*transRule)->patterns];
2261
+
2262
+ /* check before pattern */
2263
+ pattern = &patterns[1];
2264
+ if (!_lou_pattern_check(
2265
+ input->chars, pos - 1, -1, -1, pattern, table))
2266
+ break;
2267
+
2268
+ /* check after pattern */
2269
+ pattern = &patterns[patterns[0]];
2270
+ if (!_lou_pattern_check(input->chars,
2271
+ pos + (*transRule)->charslen, input->length, 1,
2272
+ pattern, table))
2273
+ break;
2274
+
2275
+ return;
2276
+ }
2277
+
2278
+ default:
2279
+ break;
2280
+ }
2281
+ }
2282
+ }
2283
+ /* Done with checking this rule */
2284
+ ruleOffset = (*transRule)->charsnext;
2285
+ }
2286
+ }
2287
+ }
2288
+
2289
+ static int
2290
+ undefinedCharacter(widechar c, const TranslationTableHeader *table, int pos,
2291
+ const InString *input, OutString *output, int *posMapping, int *cursorPosition,
2292
+ int *cursorStatus, int mode) {
2293
+ /* Display an undefined character in the output buffer */
2294
+ if (table->undefined) {
2295
+ TranslationTableRule *rule =
2296
+ (TranslationTableRule *)&table->ruleArea[table->undefined];
2297
+
2298
+ return for_updatePositions(&rule->charsdots[rule->charslen], rule->charslen,
2299
+ rule->dotslen, 0, pos, input, output, posMapping, cursorPosition,
2300
+ cursorStatus);
2301
+ }
2302
+
2303
+ const char *text = (mode & noUndefined) ? "" : _lou_showString(&c, 1, 1);
2304
+ size_t length = strlen(text);
2305
+ widechar dots[length == 0 ? 1 : length];
2306
+
2307
+ for (unsigned int k = 0; k < length; k += 1) {
2308
+ dots[k] = 0;
2309
+ TranslationTableOffset offset = getChar(text[k], table)->otherRules;
2310
+ while (offset) {
2311
+ const TranslationTableRule *r =
2312
+ (TranslationTableRule *)&table->ruleArea[offset];
2313
+ if (r->opcode >= CTO_Space && r->opcode < CTO_UpLow && r->dotslen == 1) {
2314
+ dots[k] = r->charsdots[1];
2315
+ break;
2316
+ }
2317
+ offset = r->charsnext;
2318
+ }
2319
+ if (!dots[k]) dots[k] = _lou_charToFallbackDots(text[k]);
2320
+ }
2321
+
2322
+ return for_updatePositions(dots, 1, length, 0, pos, input, output, posMapping,
2323
+ cursorPosition, cursorStatus);
2324
+ }
2325
+
2326
+ static int
2327
+ putCharacter(widechar character, const TranslationTableHeader *table, int pos,
2328
+ const InString *input, OutString *output, int *posMapping, int *cursorPosition,
2329
+ int *cursorStatus, int mode) {
2330
+ /* Insert the dots equivalent of a character into the output buffer */
2331
+ TranslationTableCharacter *chardef = getChar(character, table);
2332
+ if (!chardef->definitionRule && chardef->basechar)
2333
+ chardef = (TranslationTableCharacter *)&table->ruleArea[chardef->basechar];
2334
+ if (chardef->definitionRule) {
2335
+ const TranslationTableRule *rule =
2336
+ (TranslationTableRule *)&table->ruleArea[chardef->definitionRule];
2337
+ return for_updatePositions(&rule->charsdots[1], 1, rule->dotslen, 0, pos, input,
2338
+ output, posMapping, cursorPosition, cursorStatus);
2339
+ }
2340
+ return undefinedCharacter(character, table, pos, input, output, posMapping,
2341
+ cursorPosition, cursorStatus, mode);
2342
+ }
2343
+
2344
+ static int
2345
+ putCharacters(const widechar *characters, int count, const TranslationTableHeader *table,
2346
+ int pos, const InString *input, OutString *output, int *posMapping,
2347
+ int *cursorPosition, int *cursorStatus, int mode) {
2348
+ /* Insert the dot equivalents of a series of characters in the output
2349
+ * buffer */
2350
+ int k;
2351
+ for (k = 0; k < count; k++)
2352
+ if (!putCharacter(characters[k], table, pos, input, output, posMapping,
2353
+ cursorPosition, cursorStatus, mode))
2354
+ return 0;
2355
+ return 1;
2356
+ }
2357
+
2358
+ // state at the beginning of the current word, used for back-tracking and also for the
2359
+ // nocont and compbrl rules
2360
+ typedef struct {
2361
+ int inPos; // begin position of the current word in the input
2362
+ int outPos; // begin position of the current word in the output
2363
+ int emphasisInPos; // position of the next character in the input for which to insert
2364
+ // emphasis marks
2365
+ } LastWord;
2366
+
2367
+ static int
2368
+ doCompbrl(const TranslationTableHeader *table, int *pos, const InString *input,
2369
+ OutString *output, int *posMapping, EmphasisInfo *emphasisBuffer,
2370
+ const TranslationTableRule **transRule, int *cursorPosition, int *cursorStatus,
2371
+ const LastWord *lastWord, int *insertEmphasesFrom, int mode) {
2372
+ /* Handle strings containing substrings defined by the compbrl opcode */
2373
+ int stringStart, stringEnd;
2374
+ if (checkCharAttr(input->chars[*pos], CTC_Space, table)) return 1;
2375
+ stringStart = lastWord->outPos ? lastWord->inPos : 0;
2376
+ stringEnd = *pos;
2377
+ while (stringEnd < input->length &&
2378
+ !checkCharAttr(input->chars[stringEnd], CTC_Space, table))
2379
+ stringEnd++;
2380
+ *pos = stringStart;
2381
+ output->length = lastWord->outPos;
2382
+ *insertEmphasesFrom = lastWord->emphasisInPos;
2383
+ return doCompTrans(stringStart, stringEnd, table, pos, input, output, posMapping,
2384
+ emphasisBuffer, transRule, cursorPosition, cursorStatus, mode);
2385
+ }
2386
+
2387
+ static int
2388
+ doCompTrans(int start, int end, const TranslationTableHeader *table, int *pos,
2389
+ const InString *input, OutString *output, int *posMapping,
2390
+ EmphasisInfo *emphasisBuffer, const TranslationTableRule **transRule,
2391
+ int *cursorPosition, int *cursorStatus, int mode) {
2392
+ const TranslationTableRule *indicRule;
2393
+ int k;
2394
+ int haveEndsegment = 0;
2395
+ if (*cursorStatus != 2 && brailleIndicatorDefined(table->begComp, table, &indicRule))
2396
+ if (!for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, *pos,
2397
+ input, output, posMapping, cursorPosition, cursorStatus))
2398
+ return 0;
2399
+ for (k = start; k < end; k++) {
2400
+ TranslationTableOffset compdots = 0;
2401
+ /* HACK: computer braille is one-to-one so it
2402
+ * can't have any emphasis indicators.
2403
+ * A better solution is to treat computer braille as its own mode. */
2404
+ emphasisBuffer[k] = (EmphasisInfo){ 0 };
2405
+ if (input->chars[k] == LOU_ENDSEGMENT) {
2406
+ haveEndsegment = 1;
2407
+ continue;
2408
+ }
2409
+ *pos = k;
2410
+ compdots = getChar(input->chars[k], table)->compRule;
2411
+ if (compdots != 0) {
2412
+ *transRule = (TranslationTableRule *)&table->ruleArea[compdots];
2413
+ if (!for_updatePositions(&(*transRule)->charsdots[(*transRule)->charslen],
2414
+ (*transRule)->charslen, (*transRule)->dotslen, 0, *pos, input,
2415
+ output, posMapping, cursorPosition, cursorStatus))
2416
+ return 0;
2417
+ } else if (!putCharacter(input->chars[k], table, *pos, input, output, posMapping,
2418
+ cursorPosition, cursorStatus, mode))
2419
+ return 0;
2420
+ }
2421
+ if (*cursorStatus != 2 && brailleIndicatorDefined(table->endComp, table, &indicRule))
2422
+ if (!for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, *pos,
2423
+ input, output, posMapping, cursorPosition, cursorStatus))
2424
+ return 0;
2425
+ *pos = end;
2426
+ if (haveEndsegment) {
2427
+ widechar endSegment = LOU_ENDSEGMENT;
2428
+ if (!for_updatePositions(&endSegment, 0, 1, 0, *pos, input, output, posMapping,
2429
+ cursorPosition, cursorStatus))
2430
+ return 0;
2431
+ }
2432
+ return 1;
2433
+ }
2434
+
2435
+ static int
2436
+ doNocont(const TranslationTableHeader *table, int *pos, OutString *output, int mode,
2437
+ const InString *input, const LastWord *lastWord, int *dontContract,
2438
+ int *insertEmphasesFrom) {
2439
+ /* Handle strings containing substrings defined by the nocont opcode */
2440
+ if (checkCharAttr(input->chars[*pos], CTC_Space, table) || *dontContract ||
2441
+ (mode & noContractions))
2442
+ return 1;
2443
+ if (lastWord->outPos) {
2444
+ *pos = lastWord->inPos;
2445
+ output->length = lastWord->outPos;
2446
+ } else {
2447
+ *pos = 0;
2448
+ output->length = 0;
2449
+ }
2450
+ *insertEmphasesFrom = lastWord->emphasisInPos;
2451
+ *dontContract = 1;
2452
+ return 1;
2453
+ }
2454
+
2455
+ static int
2456
+ markSyllables(
2457
+ const TranslationTableHeader *table, const InString *input, formtype *typebuf) {
2458
+ int pos;
2459
+ int k;
2460
+ int currentMark = 0;
2461
+ int const syllable_marks[] = { SYLLABLE_MARKER_1, SYLLABLE_MARKER_2 };
2462
+ int syllable_mark_selector = 0;
2463
+ const TranslationTableRule *transRule;
2464
+ int transOpcode;
2465
+ int transCharslen;
2466
+
2467
+ if (typebuf == NULL || !table->syllables) return 1;
2468
+ pos = 0;
2469
+ while (pos < input->length) { /* the main multipass translation loop */
2470
+ int length = input->length - pos;
2471
+ int tryThis = 0;
2472
+ while (tryThis < 3) {
2473
+ TranslationTableOffset ruleOffset = 0;
2474
+ switch (tryThis) {
2475
+ case 0:
2476
+ if (!(length >= 2)) break;
2477
+ // memory overflow when pos == input->length - 1
2478
+ ruleOffset =
2479
+ table->forRules[_lou_stringHash(&input->chars[pos], 1, table)];
2480
+ break;
2481
+ case 1:
2482
+ if (!(length >= 1)) break;
2483
+ length = 1;
2484
+ ruleOffset = getChar(input->chars[pos], table)->otherRules;
2485
+ break;
2486
+ case 2: /* No rule found */
2487
+ transOpcode = CTO_Always;
2488
+ ruleOffset = 0;
2489
+ break;
2490
+ }
2491
+ while (ruleOffset) {
2492
+ transRule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
2493
+ transOpcode = transRule->opcode;
2494
+ transCharslen = transRule->charslen;
2495
+ if (tryThis == 1 ||
2496
+ (transCharslen <= length &&
2497
+ compareChars(&transRule->charsdots[0], &input->chars[pos],
2498
+ transCharslen, table))) {
2499
+ if (transOpcode == CTO_Syllable) {
2500
+ tryThis = 4;
2501
+ break;
2502
+ }
2503
+ }
2504
+ ruleOffset = transRule->charsnext;
2505
+ }
2506
+ tryThis++;
2507
+ }
2508
+ switch (transOpcode) {
2509
+ case CTO_Always:
2510
+ if (pos >= input->length) return 0;
2511
+ typebuf[pos++] |= currentMark;
2512
+ break;
2513
+ case CTO_Syllable:
2514
+ /* cycle between SYLLABLE_MARKER_1 and SYLLABLE_MARKER_2 so
2515
+ * we can distinguinsh two consequtive syllables */
2516
+ currentMark = syllable_marks[syllable_mark_selector];
2517
+ syllable_mark_selector = (syllable_mark_selector + 1) % 2;
2518
+
2519
+ if ((pos + transCharslen) > input->length) return 0;
2520
+ for (k = 0; k < transCharslen; k++) typebuf[pos++] |= currentMark;
2521
+ break;
2522
+ default:
2523
+ break;
2524
+ }
2525
+ }
2526
+ return 1;
2527
+ }
2528
+
2529
+ static int
2530
+ resetsEmphMode(
2531
+ widechar c, const TranslationTableHeader *table, const EmphasisClass *emphClass) {
2532
+ /* Whether a character cancels word emphasis mode or not. */
2533
+ if (emphClass->mode) {
2534
+ const TranslationTableCharacter *chardef = getChar(c, table);
2535
+ /* the base character of a character belonging to a mode can never cancel the mode
2536
+ */
2537
+ if (chardef->attributes & emphClass->mode)
2538
+ return 0;
2539
+ else {
2540
+ const TranslationTableCharacter *ch = chardef;
2541
+ if (ch->basechar)
2542
+ ch = (TranslationTableCharacter *)&table->ruleArea[ch->basechar];
2543
+ while (ch->linked) {
2544
+ ch = (TranslationTableCharacter *)&table->ruleArea[ch->linked];
2545
+ if ((ch->mode & chardef->mode) == chardef->mode &&
2546
+ ch->attributes & emphClass->mode) {
2547
+ return 0;
2548
+ }
2549
+ }
2550
+ }
2551
+ if (emphClass->mode == CTC_UpperCase) {
2552
+ /* characters that are not letter and not capsmodechars cancel capsword mode
2553
+ */
2554
+ return !checkCharAttr(c, CTC_Letter | CTC_CapsMode, table);
2555
+ } else if (emphClass->mode == CTC_Digit) {
2556
+ /* characters that are not digit or litdigit or numericmodechars cancel
2557
+ * numeric mode */
2558
+ return !checkCharAttr(c,
2559
+ CTC_Digit | CTC_LitDigit | CTC_NumericMode | CTC_MidEndNumericMode,
2560
+ table);
2561
+ } else {
2562
+ /* characters that are not letter cancel other word modes */
2563
+ return !checkCharAttr(c, CTC_Letter, table);
2564
+ }
2565
+ } else {
2566
+ if (checkCharAttr(c, CTC_Letter, table)) /* a letter never cancels emphasis */
2567
+ return 0;
2568
+ const widechar *emphmodechars = table->emphModeChars[emphClass->rule];
2569
+ /* by default (if emphmodechars is not declared) only space cancels emphasis */
2570
+ if (!emphmodechars[0]) return checkCharAttr(c, CTC_Space, table);
2571
+ for (int k = 0; emphmodechars[k]; k++)
2572
+ if (c == emphmodechars[k]) return 0;
2573
+ return 1;
2574
+ }
2575
+ }
2576
+
2577
+ static int
2578
+ isEmphasizable(
2579
+ widechar c, const TranslationTableHeader *table, const EmphasisClass *emphClass) {
2580
+ /* Whether emphasis is indicated on a character or not. */
2581
+ if (emphClass->mode) {
2582
+ /* a character is emphasizable if it belongs to the mode or if it has the same
2583
+ * base as a character that belongs to the mode */
2584
+ const TranslationTableCharacter *chardef = getChar(c, table);
2585
+ if (chardef->basechar)
2586
+ chardef = (TranslationTableCharacter *)&table->ruleArea[chardef->basechar];
2587
+ if (chardef->attributes & emphClass->mode) return 1;
2588
+ while (chardef->linked) {
2589
+ chardef = (TranslationTableCharacter *)&table->ruleArea[chardef->linked];
2590
+ if (chardef->attributes & emphClass->mode) return 1;
2591
+ }
2592
+ return 0;
2593
+ } else {
2594
+ const widechar *noemphchars = table->noEmphChars[emphClass->rule];
2595
+ /* if noemphchars is not declared emphasis is indicated on all characters except
2596
+ * spaces */
2597
+ if (!noemphchars[0]) return !checkCharAttr(c, CTC_Space, table);
2598
+ for (int k = 0; noemphchars[k]; k++)
2599
+ if (c == noemphchars[k]) return 0;
2600
+ return 1;
2601
+ }
2602
+ }
2603
+
2604
+ static int
2605
+ isEmphasized(widechar c, const TranslationTableHeader *table,
2606
+ const EmphasisClass *emphClass, formtype typeform) {
2607
+ /* Whether a character is emphasized or not. */
2608
+ if (!isEmphasizable(c, table, emphClass)) return 0;
2609
+ if (emphClass->mode)
2610
+ return checkCharAttr(c, emphClass->mode, table);
2611
+ else
2612
+ return typeform & emphClass->typeform;
2613
+ }
2614
+
2615
+ static int
2616
+ isEmphSpace(
2617
+ widechar c, const TranslationTableHeader *table, const EmphasisClass *emphClass) {
2618
+ /* For determining word boundaries. */
2619
+ /* Note that this is not the only function that is used for this purpose. In
2620
+ * resolveEmphasisWords the beginning and end of words are further refined based on
2621
+ * the isEmphasizable function. */
2622
+ const int word_enabled = table->emphRules[emphClass->rule][begWordOffset];
2623
+ if (emphClass->mode == CTC_UpperCase) {
2624
+ /* The old behavior was that words are determined by spaces. However for some
2625
+ * tables it is a requirement that words are determined based on letters and
2626
+ * capsmodechars. While the latter probably makes most sense, we don't want to
2627
+ * break the old behavior because there is no easy way to achieve it using
2628
+ * table rules. A good middle ground is to let the behavior depend on the
2629
+ * presence of a capsmodechars rule. */
2630
+ if (!(word_enabled && table->hasCapsModeChars))
2631
+ return checkCharAttr(c, CTC_Space, table);
2632
+ }
2633
+ return !isEmphasizable(c, table, emphClass) &&
2634
+ (!word_enabled || resetsEmphMode(c, table, emphClass));
2635
+ }
2636
+
2637
+ static void
2638
+ resolveEmphasisBeginEnd(EmphasisInfo *buffer, const EmphasisClass *class,
2639
+ const TranslationTableHeader *table, const InString *input,
2640
+ const formtype *typebuf, const unsigned int *wordBuffer) {
2641
+ /* mark emphasized (capitalized) sections, i.e. sections that */
2642
+ /* - start with an emphasized (uppercase) character, */
2643
+ /* - extend as long as no unemphasized (lowercase) character is encountered, and */
2644
+ /* - do not end with a word that contains no emphasized (uppercase) characters */
2645
+ /* in addition, if phrase rules are present, sections are split up as needed so that
2646
+ * they do not end in the middle of a word */
2647
+
2648
+ int last_space = -1; // position of the last encountered space
2649
+ int emph_start = -1; // position of the first emphasized (uppercase) character after
2650
+ // which no unemphasized (lowercase) character was encountered
2651
+ int last_word = -1; // position of the first space following the last encountered
2652
+ // character if that character was emphasized (uppercase)
2653
+ int emph = 0; // whether or not the last encountered character was emphasized
2654
+ // (uppercase) and happened in the current word
2655
+ int phrase_enabled = table->emphRules[class->rule][begPhraseOffset];
2656
+
2657
+ for (int i = 0; i < input->length; i++) {
2658
+ int isSpace = !(wordBuffer[i] & WORD_CHAR);
2659
+ if (isSpace) {
2660
+ /* character is a space */
2661
+ last_space = i;
2662
+ if (emph) {
2663
+ last_word = i;
2664
+ emph = 0;
2665
+ }
2666
+ }
2667
+ /* if character is an emphasized (uppercase) character, emphasis mode begins or
2668
+ * continues */
2669
+ if (!isSpace && isEmphasized(input->chars[i], table, class, typebuf[i])) {
2670
+ if (emph_start < 0) emph_start = i;
2671
+ emph = 1;
2672
+ } else {
2673
+ /* else if emphasis mode has begun, it should continue if there are no
2674
+ * unemphasized (lowercase) characters before the next emphasized (uppercase)
2675
+ * character */
2676
+ /* characters that cancel emphasis mode are handled later in
2677
+ * resolveEmphasisResets (note that letters that are neither uppercase nor
2678
+ * lowercase do not cancel caps mode) */
2679
+ if (!isSpace && isEmphasizable(input->chars[i], table, class)) {
2680
+ if (emph_start >= 0) {
2681
+ buffer[emph_start].begin |= class->value;
2682
+ if (emph) {
2683
+ /* a passage can not end on a word without emphasized (uppercase)
2684
+ * characters, so if emphasis did not start inside the current
2685
+ * word, end it after the last word that contained an emphasized
2686
+ * (uppercase) character, and start over from the beginning of the
2687
+ * current word */
2688
+ if (phrase_enabled && emph_start < last_space) {
2689
+ buffer[last_word].end |= class->value;
2690
+ emph_start = -1;
2691
+ last_word = -1;
2692
+ emph = 0;
2693
+ i = last_space;
2694
+ continue;
2695
+ } else
2696
+ /* don't split into two sections if no phrase rules are
2697
+ * present or emphasis started inside the current word */
2698
+ buffer[i].end |= class->value;
2699
+ } else
2700
+ /* current word had no emphasis yet */
2701
+ buffer[last_word].end |= class->value;
2702
+ emph_start = -1;
2703
+ last_word = -1;
2704
+ emph = 0;
2705
+ }
2706
+ }
2707
+ }
2708
+ }
2709
+
2710
+ /* clean up input->length */
2711
+ if (emph_start >= 0) {
2712
+ buffer[emph_start].begin |= class->value;
2713
+ if (emph)
2714
+ buffer[input->length].end |= class->value;
2715
+ else
2716
+ buffer[last_word].end |= class->value;
2717
+ }
2718
+ }
2719
+
2720
+ static void
2721
+ resolveEmphasisWords(EmphasisInfo *buffer, const EmphasisClass *class,
2722
+ const TranslationTableHeader *table, const InString *input,
2723
+ unsigned int *wordBuffer) {
2724
+ int in_word = 0, in_emp = 0;
2725
+ int word_start = -1; // start position of the current emphasized word section
2726
+ int char_cnt = 0; // number of emphasizable characters within the current emphasized
2727
+ // word section
2728
+ int last_char = -1; // position of the last emphasizable character
2729
+ const TranslationTableOffset *emphRule = table->emphRules[class->rule];
2730
+ int letter_defined = emphRule[letterOffset];
2731
+ int endphraseafter_defined = emphRule[begPhraseOffset] &&
2732
+ (emphRule[endPhraseAfterOffset] || emphRule[endOffset]);
2733
+
2734
+ for (int i = 0; i < input->length; i++) {
2735
+
2736
+ /* check if at beginning of emphasis */
2737
+ if (!in_emp)
2738
+ if (buffer[i].begin & class->value) {
2739
+ in_emp = 1;
2740
+ buffer[i].begin &= ~class->value;
2741
+
2742
+ /* emphasis started inside word (and is therefore not a whole word) */
2743
+ if (in_word) word_start = i;
2744
+
2745
+ /* emphasis started on space */
2746
+ if (!(wordBuffer[i] & WORD_CHAR)) word_start = -1;
2747
+ }
2748
+
2749
+ /* check if at end of emphasis */
2750
+ if (in_emp)
2751
+ if (buffer[i].end & class->value) {
2752
+ in_emp = 0;
2753
+ buffer[i].end &= ~class->value;
2754
+ if (in_word && word_start >= 0) {
2755
+ /* if word is one symbol, turn it into a symbol (unless emphletter is
2756
+ * not defined) */
2757
+ if (letter_defined && char_cnt == 1)
2758
+ buffer[word_start].symbol |= class->value;
2759
+ else {
2760
+ /* else mark the word start point and, if emphasis ended inside a
2761
+ * word, also mark the end point */
2762
+ buffer[word_start].word |= class->value;
2763
+ if (wordBuffer[i] & WORD_CHAR) {
2764
+ buffer[i].end |= class->value;
2765
+ buffer[i].word |= class->value;
2766
+ }
2767
+ }
2768
+ }
2769
+ }
2770
+
2771
+ /* check if at beginning of word (first character that is not a space) */
2772
+ if (!in_word)
2773
+ if (wordBuffer[i] & WORD_CHAR) {
2774
+ /* check if word started on a character that is not emphasizable */
2775
+ if (isEmphasizable(input->chars[i], table, class)) {
2776
+ in_word = 1;
2777
+ if (in_emp) word_start = i;
2778
+ /* remove WORD_CHAR marks at the end of the previous word */
2779
+ for (int j = last_char + 1; j < i; j++) wordBuffer[j] &= ~WORD_CHAR;
2780
+ /* also delete possible word end point */
2781
+ if (last_char >= 0 && !(buffer[last_char].symbol & class->value)) {
2782
+ if ((buffer[last_char].word & class->value) &&
2783
+ !(buffer[last_char].end & class->value))
2784
+ buffer[last_char].symbol |= class->value;
2785
+ for (int j = last_char; j < i - 1; j++)
2786
+ if (buffer[j + 1].end & class->value) {
2787
+ buffer[j + 1].end &= ~class->value;
2788
+ buffer[j + 1].word &= ~class->value;
2789
+ break;
2790
+ }
2791
+ }
2792
+ }
2793
+ }
2794
+
2795
+ /* check if at end of word (last character that is not a space) */
2796
+ if (in_word)
2797
+ if (!(wordBuffer[i] & WORD_CHAR)) {
2798
+ /* made it through whole word */
2799
+ if (in_emp && word_start >= 0) {
2800
+ /* if word is one symbol, turn it into a symbol (unless emphletter is
2801
+ * not defined) */
2802
+ if (letter_defined && char_cnt == 1)
2803
+ buffer[word_start].symbol |= class->value;
2804
+ else
2805
+ /* else mark it as a word */
2806
+ buffer[word_start].word |= class->value;
2807
+ }
2808
+ in_word = 0;
2809
+ word_start = -1;
2810
+ }
2811
+
2812
+ /* count characters within the current emphasized word (section) that are
2813
+ * emphasizable */
2814
+ if (i == word_start) {
2815
+ last_char = i;
2816
+ char_cnt = 1;
2817
+ } else if (in_word &&
2818
+ (endphraseafter_defined /* hack to achieve old behavior of endemphphrase
2819
+ * after: if the last word of the passage ends
2820
+ * with unemphasizable characters, the indicator
2821
+ * is inserted after them */
2822
+ || isEmphasizable(input->chars[i], table, class))) {
2823
+ last_char = i;
2824
+ if (in_emp) char_cnt++;
2825
+ }
2826
+ }
2827
+
2828
+ /* clean up end */
2829
+ if (in_emp) {
2830
+ buffer[input->length].end &= ~class->value;
2831
+
2832
+ if (in_word)
2833
+ if (word_start >= 0) {
2834
+ /* if word is one symbol, turn it into a symbol (unless emphletter is not
2835
+ * defined) */
2836
+ if (letter_defined && char_cnt == 1)
2837
+ buffer[word_start].symbol |= class->value;
2838
+ else
2839
+ /* else mark it as a word */
2840
+ buffer[word_start].word |= class->value;
2841
+ }
2842
+ }
2843
+
2844
+ /* remove WORD_CHAR marks at the end of the previous word */
2845
+ for (int j = last_char + 1; j < input->length; j++) wordBuffer[j] &= ~WORD_CHAR;
2846
+ /* also delete possible word end point */
2847
+ if (last_char >= 0 && !(buffer[last_char].symbol & class->value)) {
2848
+ if ((buffer[last_char].word & class->value) &&
2849
+ !(buffer[last_char].end & class->value))
2850
+ buffer[last_char].symbol |= class->value;
2851
+ for (int j = last_char; j < input->length - 1; j++)
2852
+ if (buffer[j + 1].end & class->value) {
2853
+ buffer[j + 1].end &= ~class->value;
2854
+ buffer[j + 1].word &= ~class->value;
2855
+ break;
2856
+ }
2857
+ }
2858
+
2859
+ /* mark whole words */
2860
+ word_start = -1;
2861
+ for (int i = 0; i < input->length; i++) {
2862
+ if (buffer[i].symbol & class->value) {
2863
+ if ((i == 0 || !(wordBuffer[i - 1] & WORD_CHAR)) &&
2864
+ (i + 1 == input->length || !(wordBuffer[i + 1] & WORD_CHAR)))
2865
+ wordBuffer[i] |= WORD_WHOLE;
2866
+ } else if (buffer[i].word & class->value) {
2867
+ if (buffer[i].end & class->value) {
2868
+ if (word_start >= 0 && wordBuffer[i] & WORD_CHAR)
2869
+ wordBuffer[word_start] &= ~WORD_WHOLE;
2870
+ word_start = -1;
2871
+ } else {
2872
+ if (i == 0 || !(wordBuffer[i - 1] & WORD_CHAR))
2873
+ wordBuffer[i] |= WORD_WHOLE;
2874
+ word_start = i;
2875
+ }
2876
+ }
2877
+ }
2878
+ }
2879
+
2880
+ static void
2881
+ convertToPassage(const int pass_start, const int pass_end, const int word_start,
2882
+ EmphasisInfo *buffer, const EmphasisClass *class,
2883
+ const TranslationTableHeader *table, unsigned int *wordBuffer) {
2884
+ int i;
2885
+ const TranslationTableOffset *emphRule = table->emphRules[class->rule];
2886
+ const TranslationTableRule *indicRule;
2887
+
2888
+ for (i = pass_start; i <= pass_end; i++) {
2889
+ buffer[i].symbol &= ~class->value;
2890
+ buffer[i].word &= ~class->value;
2891
+ wordBuffer[i] &= ~WORD_WHOLE;
2892
+ }
2893
+
2894
+ buffer[pass_start].begin |= class->value;
2895
+ if (brailleIndicatorDefined(emphRule[endOffset], table, &indicRule) ||
2896
+ brailleIndicatorDefined(emphRule[endPhraseAfterOffset], table, &indicRule))
2897
+ buffer[pass_end].end |= class->value;
2898
+ else if (brailleIndicatorDefined(
2899
+ emphRule[endPhraseBeforeOffset], table, &indicRule)) {
2900
+ /* if the phrase end indicator is the same as the word indicator, mark it as a
2901
+ * word so that the resolveEmphasisResets code applies */
2902
+ const TranslationTableRule *begwordRule;
2903
+ if (brailleIndicatorDefined(emphRule[begWordOffset], table, &begwordRule) &&
2904
+ indicRule->dotslen == begwordRule->dotslen &&
2905
+ !memcmp(&indicRule->charsdots[0], &begwordRule->charsdots[0],
2906
+ begwordRule->dotslen * CHARSIZE)) {
2907
+ buffer[word_start].word |= class->value;
2908
+ /* a passage has only whole emphasized words */
2909
+ wordBuffer[word_start] |= WORD_WHOLE;
2910
+ } else {
2911
+ buffer[word_start].end |= class->value;
2912
+ }
2913
+ }
2914
+ }
2915
+
2916
+ static void
2917
+ resolveEmphasisPassages(EmphasisInfo *buffer, const EmphasisClass *class,
2918
+ const TranslationTableHeader *table, const InString *input,
2919
+ unsigned int *wordBuffer) {
2920
+ const TranslationTableOffset *emphRule = table->emphRules[class->rule];
2921
+ int in_word = 0, last_word_start = -1, last_word_end = -1;
2922
+ int in_emph_word = 0, last_emph_symbol = -1;
2923
+ int in_pass = 0, last_pass_word_start = -1, last_pass_word_end = -1, pass_start = -1;
2924
+ unsigned int pass_word_cnt = 0;
2925
+ int endphraseafter_defined = emphRule[endPhraseAfterOffset] || emphRule[endOffset];
2926
+
2927
+ for (int i = 0; i < input->length; i++) {
2928
+
2929
+ /* check if at beginning of word (words are determined by isEmphSpace() and
2930
+ * further refined at the beginning and end of words based on isEmphasizable()) */
2931
+ if (!in_word && wordBuffer[i] & WORD_CHAR) {
2932
+ in_word = 1;
2933
+ last_word_start = i;
2934
+ } else { /* check if at end of word */
2935
+ if (in_word && !(wordBuffer[i] & WORD_CHAR)) {
2936
+ in_word = 0;
2937
+ last_word_end = i;
2938
+ }
2939
+ }
2940
+
2941
+ /* check for symbol or word indicator */
2942
+ if (!in_emph_word &&
2943
+ (buffer[i].symbol & class->value ||
2944
+ (buffer[i].word & class->value &&
2945
+ !(buffer[i].end & class->value)))) {
2946
+ if (buffer[i].symbol & class->value) {
2947
+ last_emph_symbol = i;
2948
+ } else {
2949
+ in_emph_word = 1;
2950
+ }
2951
+ if (in_pass) {
2952
+ /* only whole capitalized words (words without lowercase letters) can be
2953
+ * part of a passage (note that this also includes words without letters
2954
+ * if the next word with letters is a whole word) */
2955
+ if (!class->mode || (wordBuffer[i] & WORD_WHOLE)) {
2956
+ last_pass_word_start = i;
2957
+ pass_word_cnt++;
2958
+ } else
2959
+ goto end_passage;
2960
+ }
2961
+ } else { /* check for word end indicator or word end */
2962
+ if ((in_emph_word &&
2963
+ (buffer[i].word & class->value &&
2964
+ buffer[i].end & class->value)) ||
2965
+ last_word_end == i) {
2966
+ in_emph_word = 0;
2967
+ if (in_pass) {
2968
+ /* only whole capitalized words can be part of a passage */
2969
+ last_pass_word_end = i;
2970
+ }
2971
+ }
2972
+ }
2973
+
2974
+ /* check if possibly at beginning of passage */
2975
+ if (!in_pass && (in_emph_word || last_emph_symbol == i)) {
2976
+ /* only whole capitalized words can be part of a passage */
2977
+ if (!class->mode || (wordBuffer[i] & WORD_WHOLE)) {
2978
+ in_pass = 1;
2979
+ pass_start = i;
2980
+ last_pass_word_start = i;
2981
+ last_pass_word_end = -1;
2982
+ pass_word_cnt = 1;
2983
+ }
2984
+ } else { /* check if at end of passage */
2985
+ if (in_pass) {
2986
+ if (in_word && !(in_emph_word || last_emph_symbol == i)) {
2987
+ end_passage:
2988
+ in_pass = 0;
2989
+ if (last_pass_word_end < last_pass_word_start) {
2990
+ last_pass_word_end = i;
2991
+ }
2992
+ /* it is a passage only if the number of words is greater than or
2993
+ * equal to the minimum length (lencapsphrase / lenemphphrase) */
2994
+ /* if the phrase closing indicator is placed before the last word and
2995
+ * it was not a whole word, the minimum phrase length is increased */
2996
+ if (!endphraseafter_defined && last_pass_word_end != last_word_end) {
2997
+ pass_word_cnt--;
2998
+ }
2999
+ if (pass_word_cnt >= emphRule[lenPhraseOffset])
3000
+ convertToPassage(pass_start, last_pass_word_end,
3001
+ last_pass_word_start, buffer, class, table, wordBuffer);
3002
+ } else if (i == input->length - 1) {
3003
+ if (pass_word_cnt >= emphRule[lenPhraseOffset]) {
3004
+ if (last_pass_word_end < last_pass_word_start) {
3005
+ last_pass_word_end = input->length;
3006
+ }
3007
+ convertToPassage(pass_start, last_pass_word_end,
3008
+ last_pass_word_start, buffer, class, table, wordBuffer);
3009
+ }
3010
+ }
3011
+ }
3012
+ }
3013
+ }
3014
+ }
3015
+
3016
+ static void
3017
+ resolveEmphasisSingleSymbols(
3018
+ EmphasisInfo *buffer, const EmphasisClass *class, const InString *input) {
3019
+ int i;
3020
+
3021
+ for (i = 0; i < input->length; i++) {
3022
+ if (buffer[i].begin & class->value)
3023
+ if (buffer[i + 1].end & class->value) {
3024
+ buffer[i].begin &= ~class->value;
3025
+ buffer[i + 1].end &= ~class->value;
3026
+ buffer[i].symbol |= class->value;
3027
+ }
3028
+ }
3029
+ }
3030
+
3031
+ static void
3032
+ resolveEmphasisAllSymbols(EmphasisInfo *buffer, const EmphasisClass *class,
3033
+ const TranslationTableHeader *table, formtype *typebuf, const InString *input,
3034
+ unsigned int *wordBuffer) {
3035
+
3036
+ /* Mark every emphasized character individually with symbol if begemphword is not
3037
+ * defined (assumes resolveEmphasisWords has not been run) */
3038
+ /* Mark every emphasized character individually with symbol if endemphword is not
3039
+ * defined
3040
+ * and emphasis ends within a word (assumes resolveEmphasisWords has been run) */
3041
+ /* Note that it is possible that emphletter is also not defined, in which case the
3042
+ * emphasis will not be marked at all. */
3043
+
3044
+ const TranslationTableOffset *emphRule = table->emphRules[class->rule];
3045
+ const int begword_enabled = emphRule[begWordOffset];
3046
+ const int endword_enabled = emphRule[endWordOffset];
3047
+
3048
+ if (!begword_enabled) {
3049
+ int in_emph = 0;
3050
+ for (int i = 0; i < input->length; i++) {
3051
+ if (in_emph) {
3052
+ if (buffer[i].end & class->value) {
3053
+ in_emph = 0;
3054
+ buffer[i].end &= ~class->value;
3055
+ }
3056
+ } else {
3057
+ if (buffer[i].begin & class->value) {
3058
+ in_emph = 1;
3059
+ buffer[i].begin &= ~class->value;
3060
+ }
3061
+ }
3062
+ if (in_emph) {
3063
+ buffer[i].symbol |= class->value;
3064
+ }
3065
+ }
3066
+ } else if (!endword_enabled) {
3067
+ int in_pass = 0, in_word = 0, word_start = -1;
3068
+ for (int i = 0; i < input->length; i++) {
3069
+ if (in_pass)
3070
+ if (buffer[i].end & class->value || buffer[i].word & class->value)
3071
+ in_pass = 0;
3072
+ if (!in_pass) {
3073
+ if (buffer[i].begin & class->value)
3074
+ in_pass = 1;
3075
+ else {
3076
+ if (!in_word)
3077
+ if (buffer[i].word & class->value) {
3078
+ in_word = 1;
3079
+ word_start = i;
3080
+ }
3081
+ if (in_word) {
3082
+ if (buffer[i].word & class->value &&
3083
+ buffer[i].end & class->value) {
3084
+ in_word = 0;
3085
+ if (begword_enabled && !endword_enabled) {
3086
+ buffer[i].end &= ~class->value;
3087
+ buffer[i].word &= ~class->value;
3088
+ buffer[word_start].word &= ~class->value;
3089
+ for (int j = word_start; j < i; j++)
3090
+ buffer[j].symbol |= class->value;
3091
+ }
3092
+ } else if (!(wordBuffer[i] & WORD_CHAR)) {
3093
+ in_word = 0;
3094
+ }
3095
+ }
3096
+ }
3097
+ }
3098
+ }
3099
+ }
3100
+ }
3101
+
3102
+ static void
3103
+ resolveEmphasisResets(EmphasisInfo *buffer, const EmphasisClass *class,
3104
+ const TranslationTableHeader *table, const InString *input,
3105
+ unsigned int *wordBuffer) {
3106
+ int in_word = 0, in_pass = 0, word_start = -1, word_reset = 0, letter_cnt = 0,
3107
+ pass_end = -1;
3108
+ int i;
3109
+ int letter_defined = table->emphRules[class->rule][letterOffset];
3110
+
3111
+ for (i = 0; i < input->length; i++) {
3112
+ if (in_pass) {
3113
+ if (buffer[i].end & class->value)
3114
+ in_pass = 0;
3115
+ else if (buffer[i].word & class->value) {
3116
+ /* the passage is ended with a "endphrase before" indicator and this
3117
+ * indicator is the same as the "begword" indicator (see convertToPassage)
3118
+ */
3119
+ in_pass = 0;
3120
+ /* remember this position so that if there is a reset later in this word,
3121
+ * we can remove this indicator */
3122
+ pass_end = i;
3123
+ }
3124
+ }
3125
+ if (!in_pass) {
3126
+ if (buffer[i].begin & class->value) {
3127
+ in_pass = 1;
3128
+ } else {
3129
+ if (!in_word) {
3130
+ if (buffer[i].word & class->value) {
3131
+ /* deal with case when reset was at beginning of word */
3132
+ if (wordBuffer[i] & WORD_RESET ||
3133
+ resetsEmphMode(input->chars[i], table, class)) {
3134
+ if (!letter_defined)
3135
+ /* if emphletter is not defined, use the word indicator */
3136
+ ;
3137
+ else if (pass_end == i)
3138
+ /* also use the word indicator if the reset marks the end
3139
+ * of a passage */
3140
+ ;
3141
+ else {
3142
+ /* use the symbol indicator symbol for the current
3143
+ * character */
3144
+ buffer[i].symbol |= class->value;
3145
+ /* move the word indicator to the next character or remove
3146
+ * it altogether if the next character is a space */
3147
+ if (wordBuffer[i + 1] & WORD_CHAR) {
3148
+ buffer[i + 1].word |= class->value;
3149
+ if (wordBuffer[i] & WORD_WHOLE)
3150
+ wordBuffer[i + 1] |= WORD_WHOLE;
3151
+ if (pass_end == i) pass_end++;
3152
+ }
3153
+ buffer[i].word &= ~class->value;
3154
+ wordBuffer[i] &= ~WORD_WHOLE;
3155
+ continue;
3156
+ }
3157
+ }
3158
+
3159
+ in_word = 1;
3160
+ word_start = i;
3161
+ letter_cnt = 0;
3162
+ word_reset = 0;
3163
+ }
3164
+
3165
+ /* it is possible for a character to have been marked as a symbol when
3166
+ * it should not be one */
3167
+ else if (buffer[i].symbol & class->value) {
3168
+ if (wordBuffer[i] & WORD_RESET ||
3169
+ resetsEmphMode(input->chars[i], table, class))
3170
+ buffer[i].symbol &= ~class->value;
3171
+ }
3172
+ }
3173
+
3174
+ if (in_word) {
3175
+
3176
+ /* at end of word */
3177
+ if (!(wordBuffer[i] & WORD_CHAR) ||
3178
+ (buffer[i].word & class->value &&
3179
+ buffer[i].end & class->value)) {
3180
+ in_word = 0;
3181
+
3182
+ /* check if symbol */
3183
+ if (letter_defined && letter_cnt == 1 && word_start != pass_end) {
3184
+ buffer[word_start].symbol |= class->value;
3185
+ buffer[word_start].word &= ~class->value;
3186
+ wordBuffer[word_start] &= ~WORD_WHOLE;
3187
+ buffer[i].end &= ~class->value;
3188
+ buffer[i].word &= ~class->value;
3189
+ }
3190
+
3191
+ /* if word ended on a reset or last char was a reset, get rid of
3192
+ * end bits */
3193
+ if (word_reset || wordBuffer[i] & WORD_RESET ||
3194
+ resetsEmphMode(input->chars[i], table, class)) {
3195
+ buffer[i].end &= ~class->value;
3196
+ buffer[i].word &= ~class->value;
3197
+ }
3198
+
3199
+ /* if word ended when it began, get rid of all bits */
3200
+ if (i == word_start) {
3201
+ wordBuffer[word_start] &= ~WORD_WHOLE;
3202
+ buffer[i].end &= ~class->value;
3203
+ buffer[i].word &= ~class->value;
3204
+ }
3205
+ } else {
3206
+ /* hit reset */
3207
+ if (wordBuffer[i] & WORD_RESET ||
3208
+ resetsEmphMode(input->chars[i], table, class)) {
3209
+
3210
+ /* check if symbol is not already resetting */
3211
+ if (letter_defined && letter_cnt == 1 &&
3212
+ word_start != pass_end) {
3213
+ buffer[word_start].symbol |= class->value;
3214
+ buffer[word_start].word &= ~class->value;
3215
+ wordBuffer[word_start] &= ~WORD_WHOLE;
3216
+ }
3217
+
3218
+ /* if reset is a letter or emphmodechar, make it the new
3219
+ * word_start */
3220
+ if (!resetsEmphMode(input->chars[i], table, class)) {
3221
+ if (word_start == pass_end)
3222
+ /* move the word marker that ends the passage to the
3223
+ * current position */
3224
+ buffer[pass_end].word &= ~class->value;
3225
+ pass_end = -1;
3226
+ word_reset = 0;
3227
+ word_start = i;
3228
+ letter_cnt = 1;
3229
+ buffer[i].word |= class->value;
3230
+ } else
3231
+ word_reset = 1;
3232
+
3233
+ continue;
3234
+ }
3235
+
3236
+ if (word_reset) {
3237
+ if (word_start == pass_end)
3238
+ /* move the word marker that ends the passage to the
3239
+ * current position */
3240
+ buffer[pass_end].word &= ~class->value;
3241
+ pass_end = -1;
3242
+ word_reset = 0;
3243
+ word_start = i;
3244
+ letter_cnt = 0;
3245
+ buffer[i].word |= class->value;
3246
+ }
3247
+
3248
+ letter_cnt++;
3249
+ }
3250
+ }
3251
+ }
3252
+ }
3253
+ }
3254
+
3255
+ /* clean up end */
3256
+ if (in_word) {
3257
+ /* check if symbol */
3258
+ if (letter_defined && letter_cnt == 1 && word_start != pass_end) {
3259
+ buffer[word_start].symbol |= class->value;
3260
+ buffer[word_start].word &= ~class->value;
3261
+ wordBuffer[word_start] &= ~WORD_WHOLE;
3262
+ buffer[i].end &= ~class->value;
3263
+ buffer[i].word &= ~class->value;
3264
+ }
3265
+
3266
+ if (word_reset) {
3267
+ buffer[i].end &= ~class->value;
3268
+ buffer[i].word &= ~class->value;
3269
+ }
3270
+ }
3271
+ }
3272
+
3273
+ static void
3274
+ markEmphases(const TranslationTableHeader *table, const InString *input,
3275
+ formtype *typebuf, unsigned int *wordBuffer, EmphasisInfo *emphasisBuffer) {
3276
+
3277
+ /* handle capsnocont */
3278
+ if (table->capsNoCont) {
3279
+ int caps_cnt = 0; // number of consecutive characters ending with the current
3280
+ // that are uppercase letters
3281
+ for (int i = 0; i < input->length; i++) {
3282
+ if (checkCharAttr(input->chars[i], CTC_UpperCase, table)) {
3283
+ /* mark two or more consecutive caps with nocont */
3284
+ caps_cnt++;
3285
+ if (caps_cnt >= 2) {
3286
+ typebuf[i] |= no_contract;
3287
+ /* also mark the previous one */
3288
+ if (caps_cnt == 2) typebuf[i - 1] |= no_contract;
3289
+ }
3290
+ } else {
3291
+ caps_cnt = 0;
3292
+ }
3293
+ }
3294
+ }
3295
+
3296
+ for (int j = 0; j < MAX_EMPH_CLASSES + MAX_MODES; j++) {
3297
+ const EmphasisClass *emphClass = j < MAX_EMPH_CLASSES
3298
+ ? &table->emphClasses[j]
3299
+ : &table->modes[j - MAX_EMPH_CLASSES];
3300
+ if (!emphClass->value) continue;
3301
+ const TranslationTableOffset *emphRule = table->emphRules[emphClass->rule];
3302
+
3303
+ /* clear out previous word markings and mark non-space characters in word buffer
3304
+ */
3305
+ for (int i = 0; i < input->length; i++) {
3306
+ if (isEmphSpace(input->chars[i], table, emphClass))
3307
+ wordBuffer[i] &= ~WORD_CHAR;
3308
+ else
3309
+ wordBuffer[i] |= WORD_CHAR;
3310
+ wordBuffer[i] &= ~WORD_WHOLE;
3311
+ }
3312
+
3313
+ /* mark beginning and end points */
3314
+ resolveEmphasisBeginEnd(
3315
+ emphasisBuffer, emphClass, table, input, typebuf, wordBuffer);
3316
+
3317
+ if (emphRule[begWordOffset]) {
3318
+ /* mark word beginning and end points, whole words, and symbols (single
3319
+ * characters) */
3320
+ resolveEmphasisWords(emphasisBuffer, emphClass, table, input, wordBuffer);
3321
+ if (emphRule[lenPhraseOffset])
3322
+ /* remove markings of words that form a passage, and mark the begin and
3323
+ * end of these passages instead */
3324
+ resolveEmphasisPassages(
3325
+ emphasisBuffer, emphClass, table, input, wordBuffer);
3326
+ /* mark where emphasis in a word needs to be retriggered after it was reset */
3327
+ resolveEmphasisResets(emphasisBuffer, emphClass, table, input, wordBuffer);
3328
+ if (!emphRule[endWordOffset])
3329
+ /* if endword is not defined and emphasis ends within a word, mark every
3330
+ * emphasised character individually as symbol */
3331
+ resolveEmphasisAllSymbols(
3332
+ emphasisBuffer, emphClass, table, typebuf, input, wordBuffer);
3333
+ } else if (emphRule[letterOffset]) {
3334
+ if (emphRule[begOffset])
3335
+ resolveEmphasisSingleSymbols(emphasisBuffer, emphClass, input);
3336
+ else
3337
+ resolveEmphasisAllSymbols(
3338
+ emphasisBuffer, emphClass, table, typebuf, input, wordBuffer);
3339
+ }
3340
+ if (emphClass->mode) {
3341
+ /* only mark if actually a capital letter (don't mark spaces or punctuation).
3342
+ */
3343
+ for (int i = 0; i < input->length; i++) {
3344
+ if (emphasisBuffer[i].symbol & emphClass->value) {
3345
+ if (emphClass->mode == CTC_UpperCase) {
3346
+ if (!(typebuf[i] & CAPSEMPH))
3347
+ emphasisBuffer[i].symbol &= ~emphClass->value;
3348
+ } else {
3349
+ if (!checkCharAttr(input->chars[i], emphClass->mode, table))
3350
+ emphasisBuffer[i].symbol &= ~emphClass->value;
3351
+ }
3352
+ }
3353
+ }
3354
+ }
3355
+ }
3356
+ }
3357
+
3358
+ static void
3359
+ insertEmphasisSymbol(const EmphasisInfo *buffer, const int at, const EmphasisClass *class,
3360
+ const TranslationTableHeader *table, int pos, const InString *input,
3361
+ OutString *output, int *posMapping, int *cursorPosition, int *cursorStatus) {
3362
+ if (buffer[at].symbol & class->value) {
3363
+ const TranslationTableRule *indicRule;
3364
+ if (brailleIndicatorDefined(
3365
+ table->emphRules[class->rule][letterOffset], table, &indicRule))
3366
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, pos,
3367
+ input, output, posMapping, cursorPosition, cursorStatus);
3368
+ }
3369
+ }
3370
+
3371
+ static void
3372
+ insertEmphasisBegin(const EmphasisInfo *buffer, const int at, const EmphasisClass *class,
3373
+ const TranslationTableHeader *table, int pos, const InString *input,
3374
+ OutString *output, int *posMapping, int *cursorPosition, int *cursorStatus) {
3375
+ const TranslationTableOffset *emphRule = table->emphRules[class->rule];
3376
+ const TranslationTableRule *indicRule;
3377
+ if (buffer[at].begin & class->value) {
3378
+ if (brailleIndicatorDefined(emphRule[begPhraseOffset], table, &indicRule))
3379
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, pos,
3380
+ input, output, posMapping, cursorPosition, cursorStatus);
3381
+ else if (brailleIndicatorDefined(emphRule[begOffset], table, &indicRule))
3382
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, pos,
3383
+ input, output, posMapping, cursorPosition, cursorStatus);
3384
+ }
3385
+
3386
+ if (buffer[at].word & class->value
3387
+ // && !(buffer[at].begin & class->value)
3388
+ && !(buffer[at].end & class->value)) {
3389
+ if (brailleIndicatorDefined(emphRule[begWordOffset], table, &indicRule))
3390
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, pos,
3391
+ input, output, posMapping, cursorPosition, cursorStatus);
3392
+ }
3393
+ }
3394
+
3395
+ static void
3396
+ insertEmphasisEnd(const EmphasisInfo *buffer, const int at, const EmphasisClass *class,
3397
+ const TranslationTableHeader *table, int pos, const InString *input,
3398
+ OutString *output, int *posMapping, int *cursorPosition, int *cursorStatus) {
3399
+ const TranslationTableOffset *emphRule = table->emphRules[class->rule];
3400
+ if (buffer[at].end & class->value) {
3401
+ const TranslationTableRule *indicRule;
3402
+ if (buffer[at].word & class->value) {
3403
+ if (brailleIndicatorDefined(emphRule[endWordOffset], table, &indicRule))
3404
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, -1,
3405
+ pos, input, output, posMapping, cursorPosition, cursorStatus);
3406
+ } else {
3407
+ if (brailleIndicatorDefined(emphRule[endOffset], table, &indicRule))
3408
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, -1,
3409
+ pos, input, output, posMapping, cursorPosition, cursorStatus);
3410
+ else if (brailleIndicatorDefined(
3411
+ emphRule[endPhraseAfterOffset], table, &indicRule))
3412
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, -1,
3413
+ pos, input, output, posMapping, cursorPosition, cursorStatus);
3414
+ else if (brailleIndicatorDefined(
3415
+ emphRule[endPhraseBeforeOffset], table, &indicRule))
3416
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0,
3417
+ pos, input, output, posMapping, cursorPosition, cursorStatus);
3418
+ }
3419
+ }
3420
+ }
3421
+
3422
+ static int
3423
+ endCount(const EmphasisInfo *buffer, const int at, const EmphasisClass *class) {
3424
+ int i, cnt = 1;
3425
+ if (!(buffer[at].end & class->value)) return 0;
3426
+ for (i = at - 1; i >= 0; i--)
3427
+ if (buffer[i].begin & class->value || buffer[i].word & class->value)
3428
+ break;
3429
+ else
3430
+ cnt++;
3431
+ return cnt;
3432
+ }
3433
+
3434
+ static int
3435
+ beginCount(const EmphasisInfo *buffer, const int at, const EmphasisClass *class,
3436
+ const TranslationTableHeader *table, const InString *input) {
3437
+ if (buffer[at].begin & class->value) {
3438
+ int i, cnt = 1;
3439
+ for (i = at + 1; i < input->length; i++)
3440
+ if (buffer[i].end & class->value)
3441
+ break;
3442
+ else
3443
+ cnt++;
3444
+ return cnt;
3445
+ } else if (buffer[at].word & class->value) {
3446
+ int i, cnt = 1;
3447
+ for (i = at + 1; i < input->length; i++)
3448
+ if (buffer[i].end & class->value)
3449
+ break;
3450
+ else if (checkCharAttr(input->chars[i], CTC_SeqDelimiter, table))
3451
+ break;
3452
+ else if (isEmphSpace(input->chars[i], table, class))
3453
+ break;
3454
+ else
3455
+ cnt++;
3456
+ return cnt;
3457
+ }
3458
+ return 0;
3459
+ }
3460
+
3461
+ static void
3462
+ insertEmphasesAt(int begin, int end, int caps, int other, const int at,
3463
+ const TranslationTableHeader *table, int pos, const InString *input,
3464
+ OutString *output, int *posMapping, const EmphasisInfo *emphasisBuffer,
3465
+ int *cursorPosition, int *cursorStatus) {
3466
+
3467
+ /* The order of inserting the end symbols must be the reverse
3468
+ * of the insertions of the begin symbols so that they will
3469
+ * nest properly when multiple emphases start and end at
3470
+ * the same place */
3471
+ // TODO: ordering with partial word
3472
+
3473
+ if (end && caps)
3474
+ for (int i = 0; i < MAX_MODES; i++) {
3475
+ const EmphasisClass *emphClass = &table->modes[i];
3476
+ if (!emphClass->value) continue;
3477
+ if ((emphasisBuffer[at].begin | emphasisBuffer[at].end |
3478
+ emphasisBuffer[at].word | emphasisBuffer[at].symbol) &
3479
+ emphClass->value)
3480
+ insertEmphasisEnd(emphasisBuffer, at, emphClass, table, pos, input,
3481
+ output, posMapping, cursorPosition, cursorStatus);
3482
+ }
3483
+
3484
+ if (end && other) {
3485
+ int type_counts[MAX_EMPH_CLASSES];
3486
+
3487
+ /* end bits */
3488
+ for (int i = 0; i < MAX_EMPH_CLASSES; i++) {
3489
+ const EmphasisClass *emphClass = &table->emphClasses[i];
3490
+ if (!emphClass->value)
3491
+ type_counts[i] = 0;
3492
+ else
3493
+ type_counts[i] = endCount(emphasisBuffer, at, emphClass);
3494
+ }
3495
+
3496
+ while (1) {
3497
+ int min = -1;
3498
+ for (int i = 0; i < MAX_EMPH_CLASSES; i++)
3499
+ if (type_counts[i] > 0)
3500
+ if (min < 0 || type_counts[i] < type_counts[min]) min = i;
3501
+ if (min < 0) break;
3502
+ type_counts[min] = 0;
3503
+ insertEmphasisEnd(emphasisBuffer, at, &table->emphClasses[min], table, pos,
3504
+ input, output, posMapping, cursorPosition, cursorStatus);
3505
+ }
3506
+ }
3507
+
3508
+ if (begin && other) {
3509
+ int type_counts[MAX_EMPH_CLASSES];
3510
+
3511
+ /* begin and word bits */
3512
+ for (int i = 0; i < MAX_EMPH_CLASSES; i++) {
3513
+ const EmphasisClass *emphClass = &table->emphClasses[i];
3514
+ if (!emphClass->value)
3515
+ type_counts[i] = 0;
3516
+ else
3517
+ type_counts[i] = beginCount(emphasisBuffer, at, emphClass, table, input);
3518
+ }
3519
+
3520
+ while (1) {
3521
+ int max = MAX_EMPH_CLASSES - 1;
3522
+ for (int i = MAX_EMPH_CLASSES - 1; i >= 0; i--)
3523
+ if (type_counts[max] < type_counts[i]) max = i;
3524
+ if (!type_counts[max]) break;
3525
+ type_counts[max] = 0;
3526
+ insertEmphasisBegin(emphasisBuffer, at, &table->emphClasses[max], table, pos,
3527
+ input, output, posMapping, cursorPosition, cursorStatus);
3528
+ }
3529
+
3530
+ /* symbol bits */
3531
+ for (int i = MAX_EMPH_CLASSES - 1; i >= 0; i--)
3532
+ if ((emphasisBuffer[at].begin | emphasisBuffer[at].end |
3533
+ emphasisBuffer[at].word | emphasisBuffer[at].symbol) &
3534
+ table->emphClasses[i].value)
3535
+ insertEmphasisSymbol(emphasisBuffer, at, &table->emphClasses[i], table,
3536
+ pos, input, output, posMapping, cursorPosition, cursorStatus);
3537
+ }
3538
+
3539
+ if (begin && caps) {
3540
+
3541
+ /* insert capitalization last so it will be closest to word */
3542
+ /* other mode indicators are inserted so that those who are defined first are
3543
+ * closest to word */
3544
+ for (int i = MAX_MODES - 1; i >= 0; i--) {
3545
+ const EmphasisClass *emphClass = &table->modes[i];
3546
+ if (!emphClass->value) continue;
3547
+ if ((emphasisBuffer[at].begin | emphasisBuffer[at].end |
3548
+ emphasisBuffer[at].word | emphasisBuffer[at].symbol) &
3549
+ emphClass->value) {
3550
+ insertEmphasisBegin(emphasisBuffer, at, emphClass, table, pos, input,
3551
+ output, posMapping, cursorPosition, cursorStatus);
3552
+ insertEmphasisSymbol(emphasisBuffer, at, emphClass, table, pos, input,
3553
+ output, posMapping, cursorPosition, cursorStatus);
3554
+ }
3555
+ }
3556
+ }
3557
+ }
3558
+
3559
+ static void
3560
+ checkNumericMode(const TranslationTableHeader *table, int pos, const InString *input,
3561
+ OutString *output, int *posMapping, int *cursorPosition, int *cursorStatus,
3562
+ int *dontContract, int *numericMode) {
3563
+ /* check if numeric mode is active and insert number sign and nocontract sign when
3564
+ * needed */
3565
+
3566
+ int i;
3567
+ const TranslationTableRule *indicRule;
3568
+ if (!brailleIndicatorDefined(table->numberSign, table, &indicRule)) return;
3569
+
3570
+ /* not in numeric mode */
3571
+ if (!*numericMode) {
3572
+ if (checkCharAttr(input->chars[pos], CTC_Digit | CTC_LitDigit, table)) {
3573
+ *numericMode = 1;
3574
+ /* if the nocontractsign is defined and it is the same as the nonumsign then
3575
+ disable contraction */
3576
+ if (isIndicatorEqual(table->noContractSign, table->noNumberSign, table))
3577
+ *dontContract = 1;
3578
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, pos,
3579
+ input, output, posMapping, cursorPosition, cursorStatus);
3580
+ } else if (checkCharAttr(input->chars[pos], CTC_NumericMode, table)) {
3581
+ for (i = pos + 1; i < input->length; i++) {
3582
+ if (checkCharAttr(input->chars[i], CTC_Digit | CTC_LitDigit, table)) {
3583
+ *numericMode = 1;
3584
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen,
3585
+ 0, pos, input, output, posMapping, cursorPosition,
3586
+ cursorStatus);
3587
+ break;
3588
+ } else if (!checkCharAttr(input->chars[i], CTC_NumericMode, table))
3589
+ break;
3590
+ }
3591
+ }
3592
+ }
3593
+
3594
+ /* in numeric mode */
3595
+ else {
3596
+ if (!checkCharAttr(input->chars[pos],
3597
+ CTC_Digit | CTC_LitDigit | CTC_NumericMode | CTC_MidEndNumericMode,
3598
+ table)) {
3599
+ *numericMode = 0;
3600
+ if (brailleIndicatorDefined(table->noNumberSign, table, &indicRule))
3601
+ if (checkCharAttr(input->chars[pos], CTC_NumericNoContract, table))
3602
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen,
3603
+ 0, pos, input, output, posMapping, cursorPosition,
3604
+ cursorStatus);
3605
+ }
3606
+ }
3607
+ }
3608
+
3609
+ static int
3610
+ translateString(const TranslationTableHeader *table, int mode, int currentPass,
3611
+ const InString *input, OutString *output, int *posMapping, formtype *typebuf,
3612
+ unsigned int *wordBuffer, EmphasisInfo *emphasisBuffer, int haveEmphasis,
3613
+ int *realInlen, int *cursorPosition, int *cursorStatus, int compbrlStart,
3614
+ int compbrlEnd) {
3615
+ int pos;
3616
+ int transOpcode;
3617
+ int prevTransOpcode;
3618
+ const TranslationTableRule *transRule;
3619
+ int transCharslen;
3620
+ int passCharDots;
3621
+ const widechar *passInstructions;
3622
+ int passIC; /* Instruction counter */
3623
+ PassRuleMatch patternMatch;
3624
+ TranslationTableRule *groupingRule;
3625
+ widechar groupingOp;
3626
+ int numericMode;
3627
+ int dontContract;
3628
+ LastWord lastWord;
3629
+ int insertEmphasesFrom;
3630
+ TranslationTableCharacter *curCharDef;
3631
+ int repwordStart;
3632
+ int repwordLength;
3633
+ const InString *origInput = input;
3634
+ int warnedForNoTranslate = 0;
3635
+ /* Main translation routine */
3636
+ int k;
3637
+ translation_direction = 1;
3638
+ markSyllables(table, input, typebuf);
3639
+ numericMode = 0;
3640
+ lastWord = (LastWord){ 0, 0, 0 };
3641
+ dontContract = 0;
3642
+ prevTransOpcode = CTO_None;
3643
+ pos = output->length = 0;
3644
+ int posIncremented = 1;
3645
+ insertEmphasesFrom = 0;
3646
+ _lou_resetPassVariables();
3647
+ if (typebuf && capsletterDefined(table))
3648
+ for (k = 0; k < input->length; k++)
3649
+ if (checkCharAttr(input->chars[k], CTC_UpperCase, table))
3650
+ typebuf[k] |= CAPSEMPH;
3651
+
3652
+ markEmphases(table, input, typebuf, wordBuffer, emphasisBuffer);
3653
+
3654
+ while (pos <= input->length) { /* the main translation loop */
3655
+ if (pos > 0 &&
3656
+ checkCharAttr(
3657
+ input->chars[pos - 1], CTC_SeqDelimiter | CTC_Space, table) &&
3658
+ (transOpcode != CTO_JoinableWord))
3659
+ lastWord = (LastWord){ pos, output->length, insertEmphasesFrom };
3660
+ if (pos == input->length) break;
3661
+ if (pos >= compbrlStart && pos < compbrlEnd) {
3662
+ int cs = 2; // cursor status for this call
3663
+ if (!doCompTrans(pos, compbrlEnd, table, &pos, input, output, posMapping,
3664
+ emphasisBuffer, &transRule, cursorPosition, &cs, mode))
3665
+ goto failure;
3666
+ continue;
3667
+ }
3668
+ TranslationTableCharacterAttributes beforeAttributes;
3669
+ setBefore(table, pos, input, &beforeAttributes);
3670
+ if (pos >= input->length) break;
3671
+
3672
+ if (!dontContract) dontContract = typebuf[pos] & no_contract;
3673
+ if (typebuf[pos] & no_translate) {
3674
+ if (!warnedForNoTranslate) {
3675
+ _lou_logMessage(LOU_LOG_WARN,
3676
+ "warning: Typeform no_translate is deprecated for input.");
3677
+ warnedForNoTranslate = 1;
3678
+ }
3679
+ if (input->chars[pos] < 32 || input->chars[pos] > 126) goto failure;
3680
+ widechar d = LOU_DOTS;
3681
+ TranslationTableOffset offset = getChar(input->chars[pos], table)->otherRules;
3682
+ while (offset) {
3683
+ const TranslationTableRule *r =
3684
+ (TranslationTableRule *)&table->ruleArea[offset];
3685
+ if (r->opcode >= CTO_Space && r->opcode < CTO_UpLow && r->dotslen == 1) {
3686
+ d = r->charsdots[1];
3687
+ break;
3688
+ }
3689
+ offset = r->charsnext;
3690
+ }
3691
+ if (!for_updatePositions(&d, 1, 1, 0, pos, input, output, posMapping,
3692
+ cursorPosition, cursorStatus))
3693
+ goto failure;
3694
+ pos++;
3695
+ posIncremented = 1;
3696
+ insertEmphasesFrom = pos;
3697
+ continue;
3698
+ }
3699
+ repwordLength = 0;
3700
+ for_selectRule(table, pos, *output, posMapping, mode, input, typebuf,
3701
+ emphasisBuffer, &transOpcode, prevTransOpcode, &transRule, &transCharslen,
3702
+ &passCharDots, &passInstructions, &passIC, &patternMatch, posIncremented,
3703
+ *cursorPosition, &repwordLength, dontContract, compbrlStart, compbrlEnd,
3704
+ beforeAttributes, &curCharDef, &groupingRule, &groupingOp);
3705
+
3706
+ switch (transOpcode) /* Rules that pre-empt context and swap */
3707
+ {
3708
+ case CTO_CompBrl:
3709
+ if (!doCompbrl(table, &pos, input, output, posMapping, emphasisBuffer,
3710
+ &transRule, cursorPosition, cursorStatus, &lastWord,
3711
+ &insertEmphasesFrom, mode))
3712
+ goto failure;
3713
+ continue;
3714
+ default:
3715
+ break;
3716
+ }
3717
+
3718
+ /* Skip repword separator to make caps/emph indicators appear before repword
3719
+ * indicator */
3720
+ if (repwordLength) pos += transCharslen;
3721
+
3722
+ for (int at = insertEmphasesFrom; at <= pos; at++) {
3723
+ /* insert caps end indicator */
3724
+ insertEmphasesAt(0, 1, 1, 0, at, table, pos, input, output, posMapping,
3725
+ emphasisBuffer, cursorPosition, cursorStatus);
3726
+ if (haveEmphasis) {
3727
+ /* insert emphasis end indicator */
3728
+ insertEmphasesAt(0, 1, 0, 1, at, table, pos, input, output, posMapping,
3729
+ emphasisBuffer, cursorPosition, cursorStatus);
3730
+ /* insert emphasis start indicator */
3731
+ insertEmphasesAt(1, 0, 0, 1, at, table, pos, input, output, posMapping,
3732
+ emphasisBuffer, cursorPosition, cursorStatus);
3733
+ }
3734
+ if (at < pos)
3735
+ insertEmphasesAt(1, 0, 1, 0, at, table, pos, input, output, posMapping,
3736
+ emphasisBuffer, cursorPosition, cursorStatus);
3737
+ }
3738
+ insertEmphasesFrom = pos + 1;
3739
+ /* insert grade 1 mode indicator (nocontractsign) before contraction */
3740
+ if (transOpcode == CTO_Contraction) {
3741
+ const TranslationTableRule *indicRule;
3742
+ if (brailleIndicatorDefined(table->noContractSign, table, &indicRule))
3743
+ for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0,
3744
+ pos, input, output, posMapping, cursorPosition, cursorStatus);
3745
+ }
3746
+ /* insert letter sign */
3747
+ if (!insertLetterSign(table, pos, input, output, posMapping, transOpcode,
3748
+ cursorPosition, cursorStatus, beforeAttributes))
3749
+ goto failure;
3750
+ /* insert caps start indicator */
3751
+ insertEmphasesAt(1, 0, 1, 0, pos, table, pos, input, output, posMapping,
3752
+ emphasisBuffer, cursorPosition, cursorStatus);
3753
+ /* insert number sign (not if numericmodechars, midnumericmodechars or
3754
+ * numericnocontchars has been defined) */
3755
+ if (!table->usesNumericMode)
3756
+ if (!insertNumberSign(table, pos, input, output, posMapping, prevTransOpcode,
3757
+ cursorPosition, cursorStatus, beforeAttributes))
3758
+ goto failure;
3759
+ /* insert number sign and number cancel sign (nocontractsign) (only if
3760
+ * numericmodechars, midnumericmodechars or numericnocontchars has been defined)
3761
+ */
3762
+ if (table->usesNumericMode)
3763
+ checkNumericMode(table, pos, input, output, posMapping, cursorPosition,
3764
+ cursorStatus, &dontContract, &numericMode);
3765
+
3766
+ if (transOpcode == CTO_Context ||
3767
+ (posIncremented &&
3768
+ findForPassRule(table, pos, currentPass, input, &transOpcode,
3769
+ &transRule, &transCharslen, &passCharDots,
3770
+ &passInstructions, &passIC, &patternMatch, &groupingRule,
3771
+ &groupingOp))) {
3772
+ posIncremented = 1;
3773
+ switch (transOpcode) {
3774
+ case CTO_Context: {
3775
+ const InString *inputBefore = input;
3776
+ int posBefore = pos;
3777
+ if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
3778
+ appliedRules[appliedRulesCount++] = transRule;
3779
+ if (!passDoAction(table, &input, output, posMapping, transOpcode,
3780
+ &transRule, passCharDots, passInstructions, passIC, &pos,
3781
+ patternMatch, cursorPosition, cursorStatus, groupingRule,
3782
+ groupingOp, mode))
3783
+ goto failure;
3784
+ if (input->bufferIndex != inputBefore->bufferIndex &&
3785
+ inputBefore->bufferIndex != origInput->bufferIndex)
3786
+ releaseStringBuffer(inputBefore->bufferIndex);
3787
+ if (pos == posBefore) posIncremented = 0;
3788
+ continue;
3789
+ }
3790
+ default:
3791
+ break;
3792
+ }
3793
+ } else {
3794
+ if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
3795
+ appliedRules[appliedRulesCount++] = transRule;
3796
+ posIncremented = 1;
3797
+ }
3798
+
3799
+ /* Processing before replacement */
3800
+
3801
+ /* check if leaving no contraction (grade 1) mode */
3802
+ if (checkCharAttr(input->chars[pos], CTC_SeqDelimiter | CTC_Space, table))
3803
+ dontContract = 0;
3804
+
3805
+ switch (transOpcode) {
3806
+ case CTO_EndNum:
3807
+ if (table->letterSign && output->length > 0 &&
3808
+ checkCharAttr(input->chars[pos], CTC_Letter, table))
3809
+ output->length--;
3810
+ break;
3811
+ case CTO_Repeated:
3812
+ case CTO_Space:
3813
+ dontContract = 0;
3814
+ break;
3815
+ case CTO_LargeSign:
3816
+ if (prevTransOpcode == CTO_LargeSign) {
3817
+ int hasEndSegment = 0;
3818
+ while (output->length > 0 &&
3819
+ checkDotsAttr(
3820
+ output->chars[output->length - 1], CTC_Space, table)) {
3821
+ if (output->chars[output->length - 1] == LOU_ENDSEGMENT) {
3822
+ hasEndSegment = 1;
3823
+ }
3824
+ output->length--;
3825
+ }
3826
+ if (hasEndSegment != 0) {
3827
+ output->chars[output->length] = 0xffff;
3828
+ output->length++;
3829
+ }
3830
+ }
3831
+ break;
3832
+ case CTO_DecPoint:
3833
+ if (!table->usesNumericMode && table->numberSign) {
3834
+ TranslationTableRule *numRule =
3835
+ (TranslationTableRule *)&table->ruleArea[table->numberSign];
3836
+ if (!for_updatePositions(&numRule->charsdots[numRule->charslen],
3837
+ numRule->charslen, numRule->dotslen, 0, pos, input, output,
3838
+ posMapping, cursorPosition, cursorStatus))
3839
+ goto failure;
3840
+ }
3841
+ transOpcode = CTO_MidNum;
3842
+ break;
3843
+ case CTO_NoCont:
3844
+ if (!dontContract)
3845
+ doNocont(table, &pos, output, mode, input, &lastWord, &dontContract,
3846
+ &insertEmphasesFrom);
3847
+ continue;
3848
+ case CTO_RepWord:
3849
+ case CTO_RepEndWord:
3850
+ repwordStart = pos - transCharslen - repwordLength;
3851
+ break;
3852
+ default:
3853
+ break;
3854
+ } /* end of action */
3855
+
3856
+ /* replacement processing */
3857
+ switch (transOpcode) {
3858
+ case CTO_Replace:
3859
+ pos += transCharslen;
3860
+ if (!putCharacters(&transRule->charsdots[transCharslen], transRule->dotslen,
3861
+ table, pos, input, output, posMapping, cursorPosition,
3862
+ cursorStatus, mode))
3863
+ goto failure;
3864
+ break;
3865
+ case CTO_None:
3866
+ /* no definition or translation rules found for this character, but it may be
3867
+ * based on another character */
3868
+ if (!putCharacter(input->chars[pos], table, pos, input, output, posMapping,
3869
+ cursorPosition, cursorStatus, mode))
3870
+ goto failure;
3871
+ pos++;
3872
+ break;
3873
+ default: {
3874
+ const widechar *dots = &transRule->charsdots[transCharslen];
3875
+ int dotslen = transRule->dotslen;
3876
+ if (transOpcode == CTO_RepEndWord) {
3877
+ int k;
3878
+ for (k = 1; dots[k] != ','; k++);
3879
+ k++;
3880
+ dots = &dots[k];
3881
+ dotslen -= k;
3882
+ }
3883
+ if (dotslen) {
3884
+ if (repwordLength) {
3885
+ /* repword sepatator is already skipped */
3886
+ if (!for_updatePositions(dots, 0, dotslen, 0, pos, input, output,
3887
+ posMapping, cursorPosition, cursorStatus))
3888
+ goto failure;
3889
+ } else {
3890
+ if (!for_updatePositions(dots, transCharslen, dotslen, 0, pos, input,
3891
+ output, posMapping, cursorPosition, cursorStatus))
3892
+ goto failure;
3893
+ pos += transCharslen;
3894
+ }
3895
+ } else {
3896
+ for (k = 0; k < transCharslen; k++) {
3897
+ if (!putCharacter(input->chars[pos], table, pos, input, output,
3898
+ posMapping, cursorPosition, cursorStatus, mode))
3899
+ goto failure;
3900
+ if (++pos >= input->length) break;
3901
+ }
3902
+ }
3903
+ break;
3904
+ }
3905
+ }
3906
+
3907
+ /* processing after replacement */
3908
+ switch (transOpcode) {
3909
+ case CTO_Repeated: {
3910
+ /* Skip repeated characters. */
3911
+ int srclim = input->length - transCharslen;
3912
+ if (mode & (compbrlAtCursor | compbrlLeftCursor) && compbrlStart < srclim)
3913
+ /* Don't skip characters from compbrlStart onwards. */
3914
+ srclim = compbrlStart - 1;
3915
+ while ((pos <= srclim) &&
3916
+ compareChars(&transRule->charsdots[0], &input->chars[pos],
3917
+ transCharslen, table)) {
3918
+ if (!*cursorStatus && pos <= *cursorPosition &&
3919
+ *cursorPosition < pos + transCharslen) {
3920
+ *cursorStatus = 1;
3921
+ *cursorPosition = output->length - 1;
3922
+ }
3923
+ pos += transCharslen;
3924
+ }
3925
+ break;
3926
+ }
3927
+ case CTO_RepEndWord: {
3928
+ /* Go back and insert dots at repwordStart and update posMapping accordingly
3929
+ */
3930
+ const widechar *dots = &transRule->charsdots[transCharslen];
3931
+ int dotslen;
3932
+ for (dotslen = 1; dots[dotslen] != ','; dotslen++);
3933
+ if ((output->length + dotslen) > output->maxlength) goto failure;
3934
+ int k;
3935
+ for (k = output->length - 1; k >= 0; k--)
3936
+ if (posMapping[k] >= repwordStart) {
3937
+ output->chars[k + dotslen] = output->chars[k];
3938
+ posMapping[k + dotslen] = posMapping[k];
3939
+ } else
3940
+ break;
3941
+ k++;
3942
+ memcpy(&output->chars[k], dots, dotslen * sizeof(*output->chars));
3943
+ for (int l = 0; l < dotslen; l++) posMapping[k + l] = posMapping[k];
3944
+ output->length += dotslen;
3945
+ if (*cursorStatus && *cursorPosition >= k) *cursorPosition += dotslen;
3946
+ }
3947
+ case CTO_RepWord: {
3948
+ /* Skip repeated characters. */
3949
+ int srclim = input->length;
3950
+ if (mode & (compbrlAtCursor | compbrlLeftCursor) && compbrlStart < srclim)
3951
+ /* Don't skip characters from compbrlStart onwards. */
3952
+ srclim = compbrlStart;
3953
+ /* Skip first and subsequent repetitions */
3954
+ /* Loop body is be executed at least once. */
3955
+ int firstRep = 1;
3956
+ while (pos + repwordLength <= srclim &&
3957
+ compareChars(&input->chars[repwordStart], &input->chars[pos],
3958
+ repwordLength, table)) {
3959
+ /* Check that capitalisation and emphasis do not change within or in
3960
+ * between subsequent repetitions. It is allowed to change right before
3961
+ * the first repetition because that can be indicated. That it does not
3962
+ * change within the first repetition is already checked in
3963
+ * isRepeatedWord. */
3964
+ if (!firstRep &&
3965
+ checkEmphasisChange(pos - 1, repwordLength, emphasisBuffer))
3966
+ break;
3967
+ if (!*cursorStatus && *cursorPosition >= pos - transCharslen &&
3968
+ *cursorPosition < pos + repwordLength) {
3969
+ *cursorStatus = 1;
3970
+ *cursorPosition = output->length - 1;
3971
+ }
3972
+ pos += repwordLength;
3973
+ if (pos + transCharslen <= srclim &&
3974
+ !memcmp(transRule->charsdots, &input->chars[pos],
3975
+ transCharslen * sizeof(*transRule->charsdots)))
3976
+ pos += transCharslen;
3977
+ else {
3978
+ pos += transCharslen;
3979
+ break;
3980
+ }
3981
+ firstRep = 0;
3982
+ }
3983
+ pos -= transCharslen;
3984
+ break;
3985
+ }
3986
+ case CTO_JoinNum:
3987
+ case CTO_JoinableWord:
3988
+ while (pos < input->length &&
3989
+ checkCharAttr(input->chars[pos], CTC_Space, table) &&
3990
+ input->chars[pos] != LOU_ENDSEGMENT)
3991
+ pos++;
3992
+ break;
3993
+ default:
3994
+ break;
3995
+ }
3996
+ if ((transOpcode >= CTO_Always && transOpcode <= CTO_None) ||
3997
+ (transOpcode >= CTO_Digit && transOpcode <= CTO_LitDigit))
3998
+ prevTransOpcode = transOpcode;
3999
+ }
4000
+
4001
+ for (int at = insertEmphasesFrom; at <= pos; at++) {
4002
+ /* insert caps end indicator */
4003
+ insertEmphasesAt(0, 1, 1, 0, at, table, pos, input, output, posMapping,
4004
+ emphasisBuffer, cursorPosition, cursorStatus);
4005
+ if (haveEmphasis) {
4006
+ /* insert emphasis end indicator */
4007
+ insertEmphasesAt(0, 1, 0, 1, at, table, pos, input, output, posMapping,
4008
+ emphasisBuffer, cursorPosition, cursorStatus);
4009
+ /* insert emphasis start indicator */
4010
+ insertEmphasesAt(1, 0, 0, 1, at, table, pos, input, output, posMapping,
4011
+ emphasisBuffer, cursorPosition, cursorStatus);
4012
+ }
4013
+ /* insert caps start indicator */
4014
+ insertEmphasesAt(1, 0, 1, 0, at, table, pos, input, output, posMapping,
4015
+ emphasisBuffer, cursorPosition, cursorStatus);
4016
+ }
4017
+
4018
+ failure:
4019
+ if (lastWord.outPos != 0 && pos < input->length &&
4020
+ !checkCharAttr(input->chars[pos], CTC_Space, table)) {
4021
+ pos = lastWord.inPos;
4022
+ output->length = lastWord.outPos;
4023
+ }
4024
+ if (pos < input->length) {
4025
+ while (checkCharAttr(input->chars[pos], CTC_Space, table))
4026
+ if (++pos == input->length) break;
4027
+ }
4028
+ *realInlen = pos;
4029
+ if (input->bufferIndex != origInput->bufferIndex)
4030
+ releaseStringBuffer(input->bufferIndex);
4031
+ return 1;
4032
+ } /* first pass translation completed */
4033
+
4034
+ static int
4035
+ isHyphen(const TranslationTableHeader *table, widechar c) {
4036
+ TranslationTableRule *rule;
4037
+ TranslationTableOffset offset = getChar(c, table)->otherRules;
4038
+ while (offset) {
4039
+ rule = (TranslationTableRule *)&table->ruleArea[offset];
4040
+ if (rule->opcode == CTO_Hyphen) return 1;
4041
+ offset = rule->charsnext;
4042
+ }
4043
+ return 0;
4044
+ }
4045
+
4046
+ /**
4047
+ * Hyphenate an input string which can either be text (mode = 0) or braille (mode = 1). If
4048
+ * the input is braille, back-translation will be performed with `tableList'. The input
4049
+ * string can contain any character (even space), but only break points within words
4050
+ * (between letters) are considered. If the string can not be broken before the character
4051
+ * at index k, the value of `hyphens[k]' is '0'. If it can be broken by inserting a hyphen
4052
+ * at the break point, the value is '1'. If it can be broken without adding a hyphen, the
4053
+ * value is '2'.
4054
+ */
4055
+ int EXPORT_CALL
4056
+ lou_hyphenate(const char *tableList, const widechar *inbuf, int inlen, char *hyphens,
4057
+ int mode) {
4058
+ #define HYPHSTRING 100
4059
+ const TranslationTableHeader *table;
4060
+ widechar textBuffer[HYPHSTRING];
4061
+ char *textHyphens;
4062
+ int *inputPos;
4063
+ int k;
4064
+ int textLen;
4065
+ int wordStart;
4066
+ table = lou_getTable(tableList);
4067
+ if (table == NULL || inbuf == NULL || hyphens == NULL ||
4068
+ table->hyphenStatesArray == 0 || inlen >= HYPHSTRING)
4069
+ return 0;
4070
+ if (mode != 0) {
4071
+ int brailleLen = inlen;
4072
+ textLen = HYPHSTRING;
4073
+ inputPos = malloc(textLen * sizeof(int));
4074
+ if (!lou_backTranslate(tableList, inbuf, &brailleLen, textBuffer, &textLen, NULL,
4075
+ NULL, NULL, inputPos, NULL, 0)) {
4076
+ free(inputPos);
4077
+ return 0;
4078
+ }
4079
+ textHyphens = malloc((textLen + 1) * sizeof(char));
4080
+ } else {
4081
+ memcpy(textBuffer, inbuf, CHARSIZE * inlen);
4082
+ textLen = inlen;
4083
+ textHyphens = hyphens;
4084
+ }
4085
+
4086
+ // initialize hyphens array
4087
+ for (k = 0; k < textLen; k++) textHyphens[k] = '0';
4088
+ textHyphens[k] = 0;
4089
+
4090
+ // for every word part
4091
+ for (wordStart = 0;;) {
4092
+ int wordEnd;
4093
+ // find start of word
4094
+ for (; wordStart < textLen; wordStart++)
4095
+ if ((getChar(textBuffer[wordStart], table))->attributes & CTC_Letter) break;
4096
+ if (wordStart == textLen) break;
4097
+ // find end of word
4098
+ for (wordEnd = wordStart + 1; wordEnd < textLen; wordEnd++)
4099
+ if (!((getChar(textBuffer[wordEnd], table))->attributes & CTC_Letter)) break;
4100
+ // hyphenate
4101
+ if (!hyphenateWord(&textBuffer[wordStart], wordEnd - wordStart,
4102
+ &textHyphens[wordStart], table))
4103
+ return 0;
4104
+ // normalize to '0', '1' or '2'
4105
+ if (wordStart >= 2 && isHyphen(table, textBuffer[wordStart - 1]) &&
4106
+ ((getChar(textBuffer[wordStart - 2], table))->attributes & CTC_Letter))
4107
+ textHyphens[wordStart] = '2';
4108
+ else
4109
+ textHyphens[wordStart] = '0';
4110
+ for (k = wordStart + 1; k < wordEnd; k++)
4111
+ if (textHyphens[k] & 1)
4112
+ textHyphens[k] = '1';
4113
+ else
4114
+ textHyphens[k] = '0';
4115
+ if (wordEnd == textLen) break;
4116
+ textHyphens[wordEnd] = '0'; // because hyphenateWord sets it to 0
4117
+ wordStart = wordEnd + 1;
4118
+ }
4119
+
4120
+ // map hyphen positions if the input was braille
4121
+ if (mode != 0) {
4122
+ for (k = 0; k < inlen; k++) hyphens[k] = '0';
4123
+ hyphens[k] = 0;
4124
+ int prevPos = -1;
4125
+ for (k = 0; k < textLen; k++) {
4126
+ int braillePos = inputPos[k];
4127
+ if (braillePos > inlen || braillePos < 0) break;
4128
+ if (braillePos > prevPos) {
4129
+ hyphens[braillePos] = textHyphens[k];
4130
+ prevPos = braillePos;
4131
+ }
4132
+ }
4133
+ free(textHyphens);
4134
+ free(inputPos);
4135
+ }
4136
+ return 1;
4137
+ }
4138
+
4139
+ int EXPORT_CALL
4140
+ lou_dotsToChar(
4141
+ const char *tableList, widechar *inbuf, widechar *outbuf, int length, int mode) {
4142
+ const DisplayTableHeader *table;
4143
+ int k;
4144
+ widechar dots;
4145
+ if (tableList == NULL || inbuf == NULL || outbuf == NULL) return 0;
4146
+
4147
+ table = _lou_getDisplayTable(tableList);
4148
+ if (table == NULL || length <= 0) return 0;
4149
+ for (k = 0; k < length; k++) {
4150
+ dots = inbuf[k];
4151
+ if (!(dots & LOU_DOTS) &&
4152
+ (dots & 0xff00) == LOU_ROW_BRAILLE) /* Unicode braille */
4153
+ dots = (dots & 0x00ff) | LOU_DOTS;
4154
+ outbuf[k] = _lou_getCharForDots(dots, table);
4155
+ // assume that if NUL character is returned, it's because the display table has no
4156
+ // mapping for the dot pattern (not because it maps to NUL)
4157
+ if (outbuf[k] == '\0') outbuf[k] = ' ';
4158
+ }
4159
+ return 1;
4160
+ }
4161
+
4162
+ int EXPORT_CALL
4163
+ lou_charToDots(const char *tableList, const widechar *inbuf, widechar *outbuf, int length,
4164
+ int mode) {
4165
+ const DisplayTableHeader *table;
4166
+ int k;
4167
+ if (tableList == NULL || inbuf == NULL || outbuf == NULL) return 0;
4168
+
4169
+ table = _lou_getDisplayTable(tableList);
4170
+ if (table == NULL || length <= 0) return 0;
4171
+ for (k = 0; k < length; k++)
4172
+ if ((mode & ucBrl))
4173
+ outbuf[k] = ((_lou_getDotsForChar(inbuf[k], table) & 0xff) | LOU_ROW_BRAILLE);
4174
+ else
4175
+ outbuf[k] = _lou_getDotsForChar(inbuf[k], table);
4176
+ return 1;
4177
+ }