search.c 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494
  1. /*
  2. * Copyright (c) 2009 Openmoko Inc.
  3. *
  4. * Authors Holger Hans Peter Freyther <zecke@openmoko.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "search.h"
  20. #include "msg.h"
  21. #include "wl-keyboard.h"
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <guilib.h>
  25. #include <glyph.h>
  26. #include <lcd.h>
  27. #include <file-io.h>
  28. #include <input.h>
  29. #include <malloc-simple.h>
  30. #include "Alloc.h"
  31. #include "Bra.h"
  32. #include "LzmaDec.h"
  33. #include "wikilib.h"
  34. #include "lcd_buf_draw.h"
  35. #include "bigram.h"
  36. #include "history.h"
  37. #include "wikilib.h"
  38. #include "search_hash.h"
  39. #include "wiki_info.h"
  40. #if !defined(INCLUDED_FROM_KERNEL)
  41. #include "time.h"
  42. #else
  43. #include <tick.h>
  44. #endif
  45. #define DBG_SEARCH 0
  46. #define DELAYED_SEARCH_TIME 0.3
  47. unsigned long time_search_string_changed = 0;
  48. bool search_string_changed = false;
  49. bool search_string_changed_remove = false;
  50. int more_search_results = 0;
  51. extern ARTICLE_LINK articleLink[MAX_ARTICLE_LINKS];
  52. extern int article_link_count;
  53. extern long saved_idx_article;
  54. int search_interrupted = 0;
  55. typedef struct _search_results {
  56. char title[NUMBER_OF_FIRST_PAGE_RESULTS][MAX_TITLE_ACTUAL];
  57. char title_search[NUMBER_OF_FIRST_PAGE_RESULTS][MAX_TITLE_SEARCH];
  58. uint32_t idx_article[NUMBER_OF_FIRST_PAGE_RESULTS]; // index (wiki.idx) for loading the article
  59. uint32_t offset_list[NUMBER_OF_FIRST_PAGE_RESULTS]; // offset (wiki.fnd) of each search title in list
  60. uint32_t offset_next; // offset (wiki.fnd) of the next title after the list
  61. uint32_t count;
  62. uint32_t result_populated;
  63. int32_t cur_selected; // -1 when no selection.
  64. } SEARCH_RESULTS;
  65. static SEARCH_RESULTS *result_list = NULL;
  66. typedef struct _search_info {
  67. int32_t inited;
  68. int32_t fd_pfx;
  69. int32_t fd_idx;
  70. int32_t fd_dat[MAX_DAT_FILES];
  71. uint32_t max_article_idx;
  72. uint32_t prefix_index_table[SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT];
  73. uint32_t b_prefix_index_block_loaded[SEARCH_CHR_COUNT];
  74. char buf[NUMBER_OF_FIRST_PAGE_RESULTS * sizeof(TITLE_SEARCH)]; // buf correspond to result_list
  75. uint32_t buf_len;
  76. uint32_t offset_current; // offset (wiki.fnd) of the content of buffer
  77. } SEARCH_INFO;
  78. static SEARCH_INFO *search_info = NULL;
  79. #define LONGEST_HIRAGANA_ENGLISH_CHARS 4
  80. struct _english_hiragana_mapping {
  81. char *english;
  82. char *hiragana;
  83. char *unified_english;
  84. } english_hiragana_mapping[] = {
  85. {"-", "ー", NULL },
  86. {"a", "あ", NULL },
  87. {"ba", "ば", NULL },
  88. {"bba", "っば" , NULL },
  89. {"bbe", "っべ" , NULL },
  90. {"bbi", "っび" , NULL },
  91. {"bbo", "っぼ" , NULL },
  92. {"bbu", "っぶ", NULL },
  93. {"bbya","っびゃ" , NULL },
  94. {"bbye","っびぇ" , NULL },
  95. {"bbyi","っびぃ" , NULL },
  96. {"bbyo","っびょ" , NULL },
  97. {"bbyu","っびゅ", NULL },
  98. {"be", "べ", NULL },
  99. {"bi", "び", NULL },
  100. {"bo", "ぼ", NULL },
  101. {"bu", "ぶ", NULL },
  102. {"bya", "びゃ", NULL },
  103. {"bye", "びぇ", NULL },
  104. {"byi", "びぃ", NULL },
  105. {"byo", "びょ", NULL },
  106. {"byu", "びゅ", NULL },
  107. {"ccha","っちゃ" , NULL },
  108. {"cche","っちぇ" , NULL },
  109. {"cchi", "っち" , NULL },
  110. {"ccho","っちょ" , NULL },
  111. {"cchu","っちゅ", NULL },
  112. {"ccyi","っちぃ" , NULL },
  113. {"cha", "ちゃ", "cya" },
  114. {"che", "ちぇ", "cye" },
  115. {"chi", "ち", NULL },
  116. {"cho", "ちょ", "cyo" },
  117. {"chu", "ちゅ", "cyu" },
  118. {"cya", "ちゃ", "cya" },
  119. {"cye", "ちぇ", "cye" },
  120. {"cyi", "ちぃ", "cyi" },
  121. {"cyo", "ちょ", "cyo" },
  122. {"cyu", "ちゅ", "cyu" },
  123. {"da", "だ", NULL },
  124. {"dda", "っだ" , NULL },
  125. {"dde", "っで" , NULL },
  126. {"ddha","っでぁ" , NULL },
  127. {"ddhe","っでぇ" , NULL },
  128. {"ddhi","っでぃ" , NULL },
  129. {"ddho","っでょ" , NULL },
  130. {"ddhu","っでゅ", NULL },
  131. {"ddi", "っヂ" , NULL },
  132. {"ddo", "っど" , NULL },
  133. {"ddu", "っづ", NULL },
  134. {"de", "で", NULL },
  135. {"di", "ぢ", NULL },
  136. {"do", "ど", NULL },
  137. {"du", "づ", NULL },
  138. {"e", "え", NULL },
  139. {"fa", "ふぁ", NULL },
  140. {"fe", "ふぇ", NULL },
  141. {"ffa", "っふぁ" , NULL },
  142. {"ffe", "っふぇ" , NULL },
  143. {"ffi", "っふぃ" , NULL },
  144. {"ffo", "っふぉ" , NULL },
  145. {"ffu", "っふ", NULL },
  146. {"ffyu","っふゅ", NULL },
  147. {"fi", "ふぃ", NULL },
  148. {"fo", "ふぉ", NULL },
  149. {"fu", "ふ", NULL },
  150. {"fya", "ふゃ", NULL },
  151. {"fye", "ふぇ", "fe" },
  152. {"fyi", "ふぃ", "fi" },
  153. {"fyo", "ふょ", NULL },
  154. {"fyu", "ふゅ", NULL },
  155. {"ga", "が", NULL },
  156. {"ge", "げ", NULL },
  157. {"gga", "っが" , NULL },
  158. {"gge", "っげ" , NULL },
  159. {"ggha","っぐぁ" , NULL },
  160. {"gghe","っぐぇ" , NULL },
  161. {"gghi","っぐぃ" , NULL },
  162. {"ggho","っぐぉ" , NULL },
  163. {"gghu","っぐぅ", NULL },
  164. {"ggi", "っぎ" , NULL },
  165. {"ggo", "っご" , NULL },
  166. {"ggu", "っぐ", NULL },
  167. {"ggya","っぎゃ" , NULL },
  168. {"ggye","っぎぇ" , NULL },
  169. {"ggyi","っぎぃ" , NULL },
  170. {"ggyo","っぎょ" , NULL },
  171. {"ggyu","っぎゅ", NULL },
  172. {"gi", "ぎ", NULL },
  173. {"go", "ご", NULL },
  174. {"gu", "ぐ", NULL },
  175. {"gya", "ぎゃ", NULL },
  176. {"gye", "ぎぇ", NULL },
  177. {"gyi", "ぎぃ", NULL },
  178. {"gyo", "ぎょ", NULL },
  179. {"gyu", "ぎゅ", NULL },
  180. {"ha", "は", NULL },
  181. {"he", "へ", NULL },
  182. {"hha", "っは" , NULL },
  183. {"hhe", "っへ" , NULL },
  184. {"hhi", "っひ" , NULL },
  185. {"hho", "っほ" , NULL },
  186. {"hhya","っひゃ" , NULL },
  187. {"hhye","っひぇ" , NULL },
  188. {"hhyi","っひぃ" , NULL },
  189. {"hhyo","っひょ" , NULL },
  190. {"hhyu","っひゅ", NULL },
  191. {"hi", "ひ", NULL },
  192. {"ho", "ほ", NULL },
  193. {"hu", "ふ", NULL },
  194. {"hya", "ひゃ", NULL },
  195. {"hye", "ひぇ", NULL },
  196. {"hyi", "ひぃ", NULL },
  197. {"hyo", "ひょ", NULL },
  198. {"hyu", "ひゅ", NULL },
  199. {"i", "い", NULL },
  200. {"ja", "じゃ", NULL },
  201. {"je", "じぇ", NULL },
  202. {"ji", "じ", NULL },
  203. {"jja", "っじゃ" , NULL },
  204. {"jji", "っじ" , NULL },
  205. {"jjo", "っじょ" , NULL },
  206. {"jju", "っじゅ", NULL },
  207. {"jjye","っじぇ" , NULL },
  208. {"jjyi","っじぃ" , NULL },
  209. {"jo", "じょ", NULL },
  210. {"ju", "じゅ", NULL },
  211. {"jya", "じゃ", "ja" },
  212. {"jye", "じぇ", "je" },
  213. {"jyi", "じぃ", NULL },
  214. {"jyo", "じょ", "jo" },
  215. {"jyu", "じゅ", "ju" },
  216. {"ka", "か", NULL },
  217. {"ke", "け", NULL },
  218. {"ki", "き", NULL },
  219. {"kka", "っか" , NULL },
  220. {"kke", "っけ" , NULL },
  221. {"kkha","っくぁ" , NULL },
  222. {"kkhe","っくぇ" , NULL },
  223. {"kkhi","っくぃ" , NULL },
  224. {"kkho","っくぉ" , NULL },
  225. {"kkhu","っくぅ", NULL },
  226. {"kki", "っき" , NULL },
  227. {"kko", "っこ" , NULL },
  228. {"kku", "っく", NULL },
  229. {"kkya","っきぁ" , NULL },
  230. {"kkye","っきぇ" , NULL },
  231. {"kkyi","っきぃ" , NULL },
  232. {"kkyo","っきょ" , NULL },
  233. {"kkyu","っきゅ", NULL },
  234. {"ko", "こ", NULL },
  235. {"ku", "く", NULL },
  236. {"kya", "きゃ", NULL },
  237. {"kye", "きぇ", NULL },
  238. {"kyi", "きぃ", NULL },
  239. {"kyo", "きょ", NULL },
  240. {"kyu", "きゅ", NULL },
  241. {"la", "ら", "ra" },
  242. {"le", "れ", "re" },
  243. {"li", "り", "ri" },
  244. {"lo", "ろ", "ro" },
  245. {"lu", "る", "ru" },
  246. {"lya", "りゃ", "rya" },
  247. {"lye", "りぇ", "rye" },
  248. {"lyi", "りぃ", "ryi" },
  249. {"lyo", "りょ", "ryo" },
  250. {"lyu", "りゅ", "ryu" },
  251. {"ma", "ま", NULL },
  252. {"me", "め", NULL },
  253. {"mi", "み", NULL },
  254. {"mma", "っま" , NULL },
  255. {"mme", "っめ" , NULL },
  256. {"mmi", "っみ" , NULL },
  257. {"mmo", "っも" , NULL },
  258. {"mmu", "っむ", NULL },
  259. {"mmya","っみゃ" , NULL },
  260. {"mmye","っみぇ" , NULL },
  261. {"mmyi","っみぃ" , NULL },
  262. {"mmyo","っみょ" , NULL },
  263. {"mmyu","っみゅ", NULL },
  264. {"mo", "も", NULL },
  265. {"mu", "む", NULL },
  266. {"mya", "みゃ", NULL },
  267. {"mye", "みぇ", NULL },
  268. {"myi", "みぃ", NULL },
  269. {"myo", "みょ", NULL },
  270. {"myu", "みゅ", NULL },
  271. {"na", "な", NULL },
  272. {"ne", "ね", NULL },
  273. {"ni", "に", NULL },
  274. {"nn", "ん", NULL },
  275. {"no", "の", NULL },
  276. {"nu", "ぬ", NULL },
  277. {"nya", "にゃ", NULL },
  278. {"nye", "にぇ", NULL },
  279. {"nyi", "にぃ", NULL },
  280. {"nyo", "にょ", NULL },
  281. {"nyu", "にゅ", NULL },
  282. {"o", "お", NULL },
  283. {"pa", "ぱ", NULL },
  284. {"pe", "ぺ", NULL },
  285. {"pi", "ぴ", NULL },
  286. {"po", "ぽ", NULL },
  287. {"ppa", "っぱ" , NULL },
  288. {"ppe", "っぺ" , NULL },
  289. {"ppi", "っぴ" , NULL },
  290. {"ppo", "っぽ" , NULL },
  291. {"ppu", "っぷ", NULL },
  292. {"ppya","っぴゃ" , NULL },
  293. {"ppye","っぴぇ" , NULL },
  294. {"ppyi","っぴぃ" , NULL },
  295. {"ppyo","っぴょ" , NULL },
  296. {"ppyu","っぴゅ", NULL },
  297. {"pu", "ぷ", NULL },
  298. {"pya", "ぴゃ", NULL },
  299. {"pye", "ぴぇ", NULL },
  300. {"pyi", "ぴぃ", NULL },
  301. {"pyo", "ぴょ", NULL },
  302. {"pyu", "ぴゅ", NULL },
  303. {"ra", "ら", NULL },
  304. {"re", "れ", NULL },
  305. {"ri", "り", NULL },
  306. {"ro", "ろ", NULL },
  307. {"rra", "っら" , NULL },
  308. {"rre", "っれ" , NULL },
  309. {"rri", "っり" , NULL },
  310. {"rro", "っろ" , NULL },
  311. {"rru", "っる", NULL },
  312. {"rrya","っりゃ" , NULL },
  313. {"rrye","っりぇ" , NULL },
  314. {"rryi","っりぃ" , NULL },
  315. {"rryo","っりょ" , NULL },
  316. {"rryu","っりゅ", NULL },
  317. {"ru", "る", NULL },
  318. {"rya", "りゃ", NULL },
  319. {"rye", "りぇ", NULL },
  320. {"ryi", "りぃ", NULL },
  321. {"ryo", "りょ", NULL },
  322. {"ryu", "りゅ", NULL },
  323. {"sa", "さ", NULL },
  324. {"se", "せ", NULL },
  325. {"sha", "しゃ", "sya" },
  326. {"she", "しぇ", "sye" },
  327. {"shi", "し", NULL },
  328. {"sho", "しょ", "syo" },
  329. {"shu", "しゅ", "syu" },
  330. {"si", "し", "shi" },
  331. {"so", "そ", NULL },
  332. {"ssa", "っさ" , NULL },
  333. {"sse", "っせ" , NULL },
  334. {"ssha","っしゃ" , NULL },
  335. {"sshe","っしぇ" , NULL },
  336. {"sshi", "っし" , NULL },
  337. {"ssho","っしょ" , NULL },
  338. {"sshu","っしゅ", NULL },
  339. {"sso", "っそ" , NULL },
  340. {"ssu", "っす", NULL },
  341. {"ssyi","っしぃ" , NULL },
  342. {"su", "す", NULL },
  343. {"sya", "しゃ", NULL },
  344. {"sye", "しぇ", NULL },
  345. {"syi", "しぃ", NULL },
  346. {"syo", "しょ", NULL },
  347. {"syu", "しゅ", NULL },
  348. {"ta", "た", NULL },
  349. {"te", "て", NULL },
  350. {"ti", "ち", NULL },
  351. {"to", "と", NULL },
  352. {"tsu", "つ", NULL },
  353. {"tta", "った" , NULL },
  354. {"tte", "って" , NULL },
  355. {"ttha","ってゃ" , NULL },
  356. {"tthe","ってぇ" , NULL },
  357. {"tthi","ってぃ" , NULL },
  358. {"ttho","ってょ" , NULL },
  359. {"tthu","ってゅ", NULL },
  360. {"tto", "っと" , NULL },
  361. {"tts", "っつ" , NULL },
  362. {"ttsu","っつ", NULL },
  363. {"tu", "つ", "tsu" },
  364. {"tya", "ちゃ", "cya" },
  365. {"tye", "ちぇ", "cye" },
  366. {"tyi", "ちぃ", "cyi" },
  367. {"tyo", "ちょ", "cyo" },
  368. {"tyu", "ちゅ", "cyu" },
  369. {"u", "う", NULL },
  370. {"vva", "っヴぁ" , NULL },
  371. {"vve", "っヴぇ" , NULL },
  372. {"vvi", "っヴぃ" , NULL },
  373. {"vvo", "っヴぉ" , NULL },
  374. {"vvu", "っヴ", NULL },
  375. {"wa", "わ", NULL },
  376. {"we", "うぇ", "whe" },
  377. {"wha", "うぁ", NULL },
  378. {"whe", "うぇ", NULL },
  379. {"whi", "うぃ", NULL },
  380. {"who", "うぉ", NULL },
  381. {"whu", "う", "u" },
  382. {"wi", "うぃ", "whi" },
  383. {"wo", "を", NULL },
  384. {"wu", "う", NULL },
  385. {"wwa", "っわ" , NULL },
  386. {"wwha","っうぁ" , NULL },
  387. {"wwhe","っうぇ" , NULL },
  388. {"wwho","っうぉ" , NULL },
  389. {"wwi", "っうぃ" , NULL },
  390. {"ya", "や", NULL },
  391. {"ye", "いぇ", NULL },
  392. {"yi", "い", NULL },
  393. {"yo", "よ", NULL },
  394. {"yu", "ゆ", NULL },
  395. {"yya", "っや" , NULL },
  396. {"yyo", "っよ" , NULL },
  397. {"yyu", "っゆ", NULL },
  398. {"za", "ざ", NULL },
  399. {"ze", "ぜ", NULL },
  400. {"zi", "じ", NULL },
  401. {"zo", "ぞ", NULL },
  402. {"zu", "ず", NULL },
  403. {"zza", "っざ" , NULL },
  404. {"zze", "っぜ" , NULL },
  405. {"zzo", "っぞ" , NULL },
  406. {"zzu", "っず", NULL },
  407. };
  408. struct _hiragana_english_mapping {
  409. char *english;
  410. char *hiragana;
  411. char *unified_english;
  412. } hiragana_english_mapping[] = {
  413. {"a", "あ" },
  414. {"i", "い" },
  415. {"ye", "いぇ" },
  416. {"u", "う" },
  417. {"wha", "うぁ" },
  418. {"whi", "うぃ" },
  419. {"whe", "うぇ" },
  420. {"who", "うぉ" },
  421. {"e", "え" },
  422. {"o", "お" },
  423. {"ka", "か" },
  424. {"ga", "が" },
  425. {"ki", "き" },
  426. {"kyi", "きぃ" },
  427. {"kye", "きぇ" },
  428. {"kya", "きゃ" },
  429. {"kyu", "きゅ" },
  430. {"kyo", "きょ" },
  431. {"gi", "ぎ" },
  432. {"gyi", "ぎぃ" },
  433. {"gye", "ぎぇ" },
  434. {"gya", "ぎゃ" },
  435. {"gyu", "ぎゅ" },
  436. {"gyo", "ぎょ" },
  437. {"ku", "く" },
  438. {"gu", "ぐ" },
  439. {"ke", "け" },
  440. {"ge", "げ" },
  441. {"ko", "こ" },
  442. {"go", "ご" },
  443. {"sa", "さ" },
  444. {"za", "ざ" },
  445. {"shi", "し" },
  446. {"syi", "しぃ" },
  447. {"sye", "しぇ" },
  448. {"sya", "しゃ" },
  449. {"syu", "しゅ" },
  450. {"syo", "しょ" },
  451. {"ji", "じ" },
  452. {"jyi", "じぃ" },
  453. {"je", "じぇ" },
  454. {"ja", "じゃ" },
  455. {"ju", "じゅ" },
  456. {"jo", "じょ" },
  457. {"su", "す" },
  458. {"zu", "ず" },
  459. {"se", "せ" },
  460. {"ze", "ぜ" },
  461. {"so", "そ" },
  462. {"zo", "ぞ" },
  463. {"ta", "た" },
  464. {"da", "だ" },
  465. {"chi", "ち" },
  466. {"cyi", "ちぃ" },
  467. {"cye", "ちぇ" },
  468. {"che", "ちぇ" },
  469. {"cya", "ちゃ" },
  470. {"cyu", "ちゅ" },
  471. {"cyo", "ちょ" },
  472. {"di", "ぢ" },
  473. {"tsu", "っ" },
  474. {"wwha","っうぁ" },
  475. {"wwi", "っうぃ" },
  476. {"wwhe","っうぇ" },
  477. {"wwho","っうぉ" },
  478. {"kka", "っか" },
  479. {"gga", "っが" },
  480. {"kki", "っき" },
  481. {"kkya","っきぁ" },
  482. {"kkyi","っきぃ" },
  483. {"kkye","っきぇ" },
  484. {"kkyu","っきゅ" },
  485. {"kkyo","っきょ" },
  486. {"ggi", "っぎ" },
  487. {"ggyi","っぎぃ" },
  488. {"ggye","っぎぇ" },
  489. {"ggya","っぎゃ" },
  490. {"ggyu","っぎゅ" },
  491. {"ggyo","っぎょ" },
  492. {"kku", "っく" },
  493. {"kkha","っくぁ" },
  494. {"kkhi","っくぃ" },
  495. {"kkhu","っくぅ" },
  496. {"kkhe","っくぇ" },
  497. {"kkho","っくぉ" },
  498. {"ggu", "っぐ" },
  499. {"ggha","っぐぁ" },
  500. {"gghi","っぐぃ" },
  501. {"gghu","っぐぅ" },
  502. {"gghe","っぐぇ" },
  503. {"ggho","っぐぉ" },
  504. {"kke", "っけ" },
  505. {"gge", "っげ" },
  506. {"kko", "っこ" },
  507. {"ggo", "っご" },
  508. {"ssa", "っさ" },
  509. {"zza", "っざ" },
  510. {"sshi","っし" },
  511. {"ssyi","っしぃ" },
  512. {"sshe","っしぇ" },
  513. {"ssha","っしゃ" },
  514. {"sshu","っしゅ" },
  515. {"ssho","っしょ" },
  516. {"jji", "っじ" },
  517. {"jjyi","っじぃ" },
  518. {"jjye","っじぇ" },
  519. {"jja", "っじゃ" },
  520. {"jju", "っじゅ" },
  521. {"jjo", "っじょ" },
  522. {"ssu", "っす" },
  523. {"zzu", "っず" },
  524. {"sse", "っせ" },
  525. {"zze", "っぜ" },
  526. {"sso", "っそ" },
  527. {"zzo", "っぞ" },
  528. {"tta", "った" },
  529. {"dda", "っだ" },
  530. {"cchi","っち" },
  531. {"ccyi","っちぃ" },
  532. {"cche","っちぇ" },
  533. {"ccha","っちゃ" },
  534. {"cchu","っちゅ" },
  535. {"ccho","っちょ" },
  536. {"ttsu","っつ" },
  537. {"tts", "っつ" },
  538. {"ddu", "っづ" },
  539. {"tte", "って" },
  540. {"tthi","ってぃ" },
  541. {"tthe","ってぇ" },
  542. {"ttha","ってゃ" },
  543. {"tthu","ってゅ" },
  544. {"ttho","ってょ" },
  545. {"dde", "っで" },
  546. {"ddha","っでぁ" },
  547. {"ddhi","っでぃ" },
  548. {"ddhe","っでぇ" },
  549. {"ddhu","っでゅ" },
  550. {"ddho","っでょ" },
  551. {"tto", "っと" },
  552. {"ddo", "っど" },
  553. {"hha", "っは" },
  554. {"bba", "っば" },
  555. {"ppa", "っぱ" },
  556. {"hhi", "っひ" },
  557. {"hhyi","っひぃ" },
  558. {"hhye","っひぇ" },
  559. {"hhya","っひゃ" },
  560. {"hhyu","っひゅ" },
  561. {"hhyo","っひょ" },
  562. {"bbi", "っび" },
  563. {"bbyi","っびぃ" },
  564. {"bbye","っびぇ" },
  565. {"bbya","っびゃ" },
  566. {"bbyu","っびゅ" },
  567. {"bbyo","っびょ" },
  568. {"ppi", "っぴ" },
  569. {"ppyi","っぴぃ" },
  570. {"ppye","っぴぇ" },
  571. {"ppya","っぴゃ" },
  572. {"ppyu","っぴゅ" },
  573. {"ppyo","っぴょ" },
  574. {"ffu", "っふ" },
  575. {"ffu", "っふ" },
  576. {"ffa", "っふぁ" },
  577. {"ffi", "っふぃ" },
  578. {"ffe", "っふぇ" },
  579. {"ffo", "っふぉ" },
  580. {"ffyu","っふゅ" },
  581. {"bbu", "っぶ" },
  582. {"ppu", "っぷ" },
  583. {"hhe", "っへ" },
  584. {"bbe", "っべ" },
  585. {"ppe", "っぺ" },
  586. {"hho", "っほ" },
  587. {"bbo", "っぼ" },
  588. {"ppo", "っぽ" },
  589. {"mma", "っま" },
  590. {"mmi", "っみ" },
  591. {"mmyi","っみぃ" },
  592. {"mmye","っみぇ" },
  593. {"mmya","っみゃ" },
  594. {"mmyu","っみゅ" },
  595. {"mmyo","っみょ" },
  596. {"mmu", "っむ" },
  597. {"mme", "っめ" },
  598. {"mmo", "っも" },
  599. {"yya", "っや" },
  600. {"yyu", "っゆ" },
  601. {"yyo", "っよ" },
  602. {"rra", "っら" },
  603. {"rri", "っり" },
  604. {"rryi","っりぃ" },
  605. {"rrye","っりぇ" },
  606. {"rrya","っりゃ" },
  607. {"rryu","っりゅ" },
  608. {"rryo","っりょ" },
  609. {"rru", "っる" },
  610. {"rru", "っる" },
  611. {"rre", "っれ" },
  612. {"rro", "っろ" },
  613. {"wwa", "っわ" },
  614. {"ddi", "っヂ" },
  615. {"vvu", "っヴ" },
  616. {"vva", "っヴぁ" },
  617. {"vvi", "っヴぃ" },
  618. {"vve", "っヴぇ" },
  619. {"vvo", "っヴぉ" },
  620. {"tsu", "つ" },
  621. {"du", "づ" },
  622. {"te", "て" },
  623. {"de", "で" },
  624. {"to", "と" },
  625. {"do", "ど" },
  626. {"na", "な" },
  627. {"ni", "に" },
  628. {"nyi", "にぃ" },
  629. {"nye", "にぇ" },
  630. {"nya", "にゃ" },
  631. {"nyu", "にゅ" },
  632. {"nyo", "にょ" },
  633. {"nu", "ぬ" },
  634. {"ne", "ね" },
  635. {"no", "の" },
  636. {"ha", "は" },
  637. {"ba", "ば" },
  638. {"pa", "ぱ" },
  639. {"hi", "ひ" },
  640. {"hyi", "ひぃ" },
  641. {"hye", "ひぇ" },
  642. {"hya", "ひゃ" },
  643. {"hyu", "ひゅ" },
  644. {"hyo", "ひょ" },
  645. {"bi", "び" },
  646. {"byi", "びぃ" },
  647. {"bye", "びぇ" },
  648. {"bya", "びゃ" },
  649. {"byu", "びゅ" },
  650. {"byo", "びょ" },
  651. {"pi", "ぴ" },
  652. {"pyi", "ぴぃ" },
  653. {"pye", "ぴぇ" },
  654. {"pya", "ぴゃ" },
  655. {"pyu", "ぴゅ" },
  656. {"pyo", "ぴょ" },
  657. {"fu", "ふ" },
  658. {"fa", "ふぁ" },
  659. {"fi", "ふぃ" },
  660. {"fe", "ふぇ" },
  661. {"fo", "ふぉ" },
  662. {"fyu", "ふゅ" },
  663. {"fyo", "ふょ" },
  664. {"bu", "ぶ" },
  665. {"pu", "ぷ" },
  666. {"he", "へ" },
  667. {"be", "べ" },
  668. {"pe", "ぺ" },
  669. {"ho", "ほ" },
  670. {"bo", "ぼ" },
  671. {"po", "ぽ" },
  672. {"ma", "ま" },
  673. {"mi", "み" },
  674. {"myi", "みぃ" },
  675. {"mye", "みぇ" },
  676. {"mya", "みゃ" },
  677. {"myu", "みゅ" },
  678. {"myo", "みょ" },
  679. {"mu", "む" },
  680. {"me", "め" },
  681. {"mo", "も" },
  682. {"ya", "や" },
  683. {"yu", "ゆ" },
  684. {"yo", "よ" },
  685. {"ra", "ら" },
  686. {"ri", "り" },
  687. {"ryi", "りぃ" },
  688. {"rye", "りぇ" },
  689. {"rya", "りゃ" },
  690. {"ryu", "りゅ" },
  691. {"ryo", "りょ" },
  692. {"ru", "る" },
  693. {"re", "れ" },
  694. {"ro", "ろ" },
  695. {"wa", "わ" },
  696. {"wo", "を" },
  697. {"nn", "ん" },
  698. {"-", "ー" },
  699. };
  700. //#define SIZE_PREFIX_INDEX_TABLE SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * sizeof(long)
  701. //static struct search_state state;
  702. //static struct search_state last_first_hit;
  703. static char search_string[MAX_TITLE_SEARCH];
  704. static int search_string_pos[MAX_TITLE_SEARCH];
  705. static char search_string_hiragana[MAX_TITLE_SEARCH * 3];
  706. static int search_str_len = 0;
  707. static int search_str_converted_len = 0;
  708. static int search_str_hiragana_len = 0;
  709. static char temp_search_string[MAX_TITLE_SEARCH];
  710. static int temp_search_string_pos[MAX_TITLE_SEARCH];
  711. static char temp_search_string_hiragana[MAX_TITLE_SEARCH * 3];
  712. static int temp_search_str_len = 0;
  713. static int temp_search_str_converted_len = 0;
  714. static int temp_search_str_hiragana_len = 0;
  715. //static char s_find_first = 1;
  716. static void *SzAlloc(void *p, size_t size) { p = p; return malloc_simple(size, MEM_TAG_INDEX_M1); }
  717. static void SzFree(void *p, void *address) { p = p; free_simple(address, MEM_TAG_INDEX_M1); }
  718. static ISzAlloc g_Alloc = { SzAlloc, SzFree };
  719. //const char* search_fetch_result()
  720. //{
  721. // DP(DBG_SEARCH, ("O search_fetch_result() called\n"));
  722. // if (search_str_len == 0)
  723. // return NULL;
  724. //#ifdef WOM_ON
  725. // const wom_article_index_t* idx;
  726. // static char result_buf[MAXSTR]; // we know that the returned pointer is copied immediately
  727. // if (s_find_first) {
  728. // s_find_first = 0;
  729. // idx = wom_find_article(g_womh, search_string, search_str_len);
  730. // } else
  731. // idx = wom_get_next_article(g_womh);
  732. // if (!idx) return 0;
  733. // sprintf(result_buf, "%.*s%.6x", idx->uri_len, idx->abbreviated_uri, (unsigned int) idx->offset_into_articles);
  734. // DP(DBG_SEARCH, ("O search_fetch_result() '%s'\n", result_buf));
  735. // return result_buf;
  736. //#else // !WOM_ON
  737. // char* result = search_fast(&global_search, search_string, &state);
  738. // if (s_find_first) {
  739. // s_find_first = 0;
  740. // store_state(&global_search, &state, &last_first_hit);
  741. // }
  742. // return result;
  743. //#endif
  744. //}
  745. void backup_search_criteria()
  746. {
  747. memcpy(temp_search_string, search_string, sizeof(search_string));
  748. memcpy(temp_search_string_pos, search_string_pos, sizeof(search_string_pos));
  749. memcpy(temp_search_string_hiragana, search_string_hiragana, sizeof(search_string_hiragana));
  750. temp_search_str_len = search_str_len;
  751. temp_search_str_converted_len = search_str_converted_len;
  752. temp_search_str_hiragana_len = search_str_hiragana_len;
  753. }
  754. void restore_search_criteria()
  755. {
  756. memcpy(search_string, temp_search_string, sizeof(search_string));
  757. memcpy(search_string_pos, temp_search_string_pos, sizeof(search_string_pos));
  758. memcpy(search_string_hiragana, temp_search_string_hiragana, sizeof(search_string_hiragana));
  759. search_str_len = temp_search_str_len;
  760. search_str_converted_len = temp_search_str_converted_len;
  761. search_str_hiragana_len = temp_search_str_hiragana_len;
  762. }
  763. long result_list_offset_next(void)
  764. {
  765. return result_list->offset_next;
  766. }
  767. long result_list_next_result(long offset_next, long *idxArticle, char *sTitleActual)
  768. {
  769. TITLE_SEARCH titleSearch;
  770. char sTitleSearch[MAX_TITLE_SEARCH];
  771. copy_fnd_to_buf(offset_next, (void *)&titleSearch, sizeof(TITLE_SEARCH));
  772. retrieve_titles_from_fnd(offset_next, sTitleSearch, sTitleActual);
  773. if (!search_string_cmp(sTitleSearch, search_string, search_str_len)) // match!
  774. {
  775. *idxArticle = titleSearch.idxArticle;
  776. offset_next += sizeof(titleSearch.idxArticle) + strlen(titleSearch.sTitleSearch) + 2; // now point to the actual title
  777. offset_next += strlen(&titleSearch.sTitleSearch[strlen(titleSearch.sTitleSearch) + 1]) + 1; // skip the actual title to the next titleSearch
  778. return offset_next;
  779. }
  780. else
  781. return 0;
  782. }
  783. void get_article_title_from_idx(long idx, char *title)
  784. {
  785. ARTICLE_PTR article_ptr;
  786. TITLE_SEARCH title_search;
  787. int wiki_id;
  788. int wiki_idx;
  789. int nTmpeCurrentWiki = nCurrentWiki;
  790. char sTitleSearch[MAX_TITLE_SEARCH];
  791. title[0] = '\0';
  792. wiki_id = idx >> 24;
  793. idx &= 0x00FFFFFF;
  794. if (wiki_id > 0)
  795. {
  796. wiki_idx = get_wiki_idx_from_id(wiki_id);
  797. if (wiki_idx < 0) // wiki not loaded
  798. return;
  799. nCurrentWiki = wiki_idx;
  800. }
  801. wl_seek(search_info[nCurrentWiki].fd_idx, (idx - 1) * sizeof(ARTICLE_PTR) + 4);
  802. wl_read(search_info[nCurrentWiki].fd_idx, (void *)&article_ptr, sizeof(article_ptr));
  803. if (article_ptr.offset_fnd)
  804. {
  805. copy_fnd_to_buf(article_ptr.offset_fnd, (char *)&title_search, sizeof(title_search));
  806. retrieve_titles_from_fnd(article_ptr.offset_fnd, sTitleSearch, title);
  807. title[MAX_TITLE_ACTUAL - 1] = '\0';
  808. }
  809. nCurrentWiki = nTmpeCurrentWiki;
  810. }
  811. void load_prefix_index(int nWikiIdx)
  812. {
  813. int i;
  814. if (!search_info[nWikiIdx].inited)
  815. {
  816. search_info[nWikiIdx].fd_pfx = wl_open(get_wiki_file_path(nWikiIdx, "wiki.pfx"), WL_O_RDONLY);
  817. search_info[nWikiIdx].fd_idx = wl_open(get_wiki_file_path(nWikiIdx, "wiki.idx"), WL_O_RDONLY);
  818. for (i=0; i < MAX_DAT_FILES; i++)
  819. search_info[nWikiIdx].fd_dat[i] = -1;
  820. search_info[nWikiIdx].offset_current = -1;
  821. if (search_info[nWikiIdx].fd_pfx >= 0 && search_info[nWikiIdx].fd_idx >= 0)
  822. {
  823. wl_read(search_info[nWikiIdx].fd_idx, (void *)&search_info[nWikiIdx].max_article_idx, sizeof(search_info[nWikiIdx].max_article_idx));
  824. memset((char *)search_info[nWikiIdx].b_prefix_index_block_loaded, 0, sizeof(search_info[nWikiIdx].b_prefix_index_block_loaded));
  825. search_info[nWikiIdx].inited = 1;
  826. }
  827. else
  828. fatal_error("index file open error");
  829. }
  830. }
  831. void search_init()
  832. {
  833. int i;
  834. int nWikiCount = get_wiki_count();
  835. if (!result_list)
  836. {
  837. result_list = (SEARCH_RESULTS *)malloc_simple(sizeof(SEARCH_RESULTS), MEM_TAG_INDEX_M1);
  838. if (!result_list)
  839. fatal_error("search_init malloc error");
  840. }
  841. if (!search_info)
  842. {
  843. search_info = (SEARCH_INFO *)malloc_simple(sizeof(SEARCH_INFO) * nWikiCount, MEM_TAG_INDEX_M1);
  844. if (!search_info)
  845. fatal_error("search_init malloc error");
  846. else
  847. {
  848. for (i = 0; i < nWikiCount; i++)
  849. {
  850. search_info[i].inited = 0;
  851. }
  852. }
  853. }
  854. load_prefix_index(nCurrentWiki);
  855. result_list->count = 0;
  856. init_search_hash();
  857. }
  858. void memrcpy(char *dest, char *src, int len) // memory copy starting from the last byte
  859. {
  860. if (len >= 0)
  861. {
  862. dest += len - 1;
  863. src += len - 1;
  864. while (len--)
  865. {
  866. *dest = *src;
  867. dest--;
  868. src--;
  869. }
  870. }
  871. }
  872. char article_error[100] = "";
  873. char article_error2[100] = "";
  874. static void print_article_error()
  875. {
  876. char msg[100];
  877. sprintf(msg, "The article, %lx, failed to load.", saved_idx_article);
  878. guilib_fb_lock();
  879. guilib_clear();
  880. render_string(SEARCH_LIST_FONT_IDX, -1, 84, msg, strlen(msg), 0);
  881. render_string(SEARCH_LIST_FONT_IDX, -1, 104, "Please restart your WikiReader and", 34, 0);
  882. render_string(SEARCH_LIST_FONT_IDX, -1, 124, "try again.", 10, 0);
  883. //render_string(SEARCH_LIST_FONT_IDX, -1, 124, article_error, strlen(article_error), 0);
  884. //render_string(SEARCH_LIST_FONT_IDX, -1, 144, article_error2, strlen(article_error2), 0);
  885. guilib_fb_unlock();
  886. }
  887. // check if null terminator exists
  888. int is_proper_string(char *s, int len)
  889. {
  890. while (len >= 0)
  891. {
  892. if (!*s)
  893. return 1;
  894. s++;
  895. len--;
  896. }
  897. return 0;
  898. }
  899. char *strnstr(char *s1, char *s2, int len)
  900. {
  901. int bFound = 0;
  902. int s2_len = strlen(s2);
  903. while (!bFound && len >= s2_len)
  904. {
  905. if (!memcmp(s1, s2, s2_len))
  906. bFound = 1;
  907. else
  908. {
  909. s1++;
  910. len--;
  911. }
  912. }
  913. if (bFound)
  914. return s1;
  915. else
  916. return NULL;
  917. }
  918. // locate the patterh of the beginning of a TITLE_SEARCH structure
  919. // the continuous 8 bytes should look like the following:
  920. // 0xXX00 (null terminated last two bytes of the last TITLE_SEARCH.sTitleActual where XX is not 00) +
  921. // 0xXXXXXX00 (TITLE_SEARCH.idxArticle where XXXXXX is not 000000) +
  922. // 0x00 (TITLE_SEARCH.cZero) +
  923. // 0xXX (Non-zero of TITLE_SEARCH.sTitleSearch)
  924. bool is_title_search_pattern(char *pBuf)
  925. {
  926. if (pBuf[0] && !pBuf[1] && (pBuf[2] || pBuf[3] || pBuf[4]) && !pBuf[5] && !pBuf[6] && pBuf[7])
  927. return true;
  928. else
  929. return false;
  930. }
  931. TITLE_SEARCH *locate_proper_title_search(char *buf_middle, int len)
  932. {
  933. char *pBuf = buf_middle - 2; // including the possible null terminated last two bytes of the last TITLE_SEARCH
  934. // for finding the proper TITLE_SEARCH pattern
  935. int i = 0;
  936. bool bFound = false;
  937. while (!bFound && i < len + 2 - 8) // the pattern consists of 8 bytes
  938. {
  939. if (is_title_search_pattern(&pBuf[i]))
  940. bFound = true;
  941. else
  942. i++;
  943. }
  944. if (bFound)
  945. return (TITLE_SEARCH *)(pBuf + i + 2);
  946. else
  947. return NULL;
  948. }
  949. uint32_t get_article_idx_from_offset_range(char *sInputTitleActual, long offset_fnd_start, long offset_fnd_end)
  950. {
  951. int len;
  952. int rc;
  953. uint32_t article_idx = 0;
  954. char sTitleSearch[MAX_TITLE_SEARCH];
  955. char sTitleActual[MAX_TITLE_ACTUAL];
  956. char buf_middle[sizeof(TITLE_SEARCH) * 2];
  957. long offset_middle;
  958. static TITLE_SEARCH *pTitleSearch;
  959. int offsetNextTitleSearch = 0;
  960. bool bFound = false;
  961. while (!bFound && offset_fnd_start >= 0)
  962. {
  963. if (search_info[nCurrentWiki].offset_current != offset_fnd_start)
  964. {
  965. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  966. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  967. if (search_interrupted)
  968. {
  969. goto out;
  970. }
  971. if (search_info[nCurrentWiki].buf_len < sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero) + 2) // at lease 2 chars for pTitleSearch->sTitleSearch
  972. {
  973. goto out;
  974. }
  975. }
  976. pTitleSearch = (TITLE_SEARCH *)&search_info[nCurrentWiki].buf[offsetNextTitleSearch];
  977. if (offsetNextTitleSearch < search_info[nCurrentWiki].buf_len &&
  978. is_proper_string(pTitleSearch->sTitleSearch, search_info[nCurrentWiki].buf_len - offsetNextTitleSearch -
  979. sizeof(pTitleSearch->idxArticle) - sizeof(pTitleSearch->cZero)))
  980. {
  981. retrieve_titles_from_fnd(offset_fnd_start + offsetNextTitleSearch,
  982. sTitleSearch, sTitleActual);
  983. rc = search_string_cmp(sTitleSearch, search_string, search_str_len);
  984. //#ifndef INCLUDED_FROM_KERNEL
  985. //msg(MSG_INFO, "offset (%x + %x, %x) ", offset_fnd_start, offsetNextTitleSearch, offset_fnd_end);
  986. //msg(MSG_INFO, "rc %d, [%s], [%s], [", rc, sTitleSearch, sTitleActual);
  987. //int i;
  988. //for (i=0;i<search_str_len;i++)
  989. //msg(MSG_INFO, "%c", search_string[i]);
  990. //msg(MSG_INFO, "]\n");
  991. //#endif
  992. if (!rc) // match!
  993. {
  994. if (!strcmp(sTitleActual, sInputTitleActual))
  995. {
  996. article_idx = pTitleSearch->idxArticle;
  997. bFound = true;
  998. }
  999. else
  1000. {
  1001. offset_fnd_end = -1; // start sequential search
  1002. offsetNextTitleSearch += sizeof(pTitleSearch->idxArticle) + strlen(pTitleSearch->sTitleSearch) +
  1003. strlen(&pTitleSearch->sTitleSearch[strlen(pTitleSearch->sTitleSearch) + 1]) + 3;
  1004. offset_fnd_start = offset_fnd_start + offsetNextTitleSearch;
  1005. offsetNextTitleSearch = 0;
  1006. }
  1007. }
  1008. else if (rc < 0)
  1009. {
  1010. if (offset_fnd_end <= 0)
  1011. {
  1012. offsetNextTitleSearch += sizeof(pTitleSearch->idxArticle) + strlen(pTitleSearch->sTitleSearch) +
  1013. strlen(&pTitleSearch->sTitleSearch[strlen(pTitleSearch->sTitleSearch) + 1]) + 3;
  1014. offset_fnd_start = offset_fnd_start + offsetNextTitleSearch;
  1015. }
  1016. else // binary search
  1017. {
  1018. offset_middle = offset_fnd_start + (offset_fnd_end - offset_fnd_start) / 2; // position to the middle of the range
  1019. if (offset_middle <= offset_fnd_start)
  1020. offset_fnd_end = -1;
  1021. else
  1022. {
  1023. len = copy_fnd_to_buf(offset_middle, buf_middle, sizeof(buf_middle));
  1024. if (search_interrupted)
  1025. {
  1026. goto out;
  1027. }
  1028. if (len >= sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero) + 2) // at lease 2 chars for pTitleSearch->sTitleSearch
  1029. {
  1030. pTitleSearch = locate_proper_title_search(buf_middle, len);
  1031. if (pTitleSearch)
  1032. {
  1033. char local_title_search[MAX_TITLE_SEARCH];
  1034. char sTitleActual[MAX_TITLE_ACTUAL];
  1035. offset_middle += (char *)pTitleSearch - buf_middle;
  1036. retrieve_titles_from_fnd(offset_middle, local_title_search, sTitleActual);
  1037. rc = search_string_cmp(local_title_search, search_string, search_str_len);
  1038. if (rc >= 0) // the first mactch will be in front or at offset_middle
  1039. {
  1040. if (offset_middle == offset_fnd_end) // search from offset_fnd_start directly
  1041. offset_fnd_end = -1;
  1042. else
  1043. offset_fnd_end = offset_middle;
  1044. }
  1045. else // the first mactch will be after offset_middle
  1046. {
  1047. offset_fnd_start = offset_middle;
  1048. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  1049. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  1050. if (search_interrupted)
  1051. {
  1052. goto out;
  1053. }
  1054. if (search_info[nCurrentWiki].buf_len <= 0)
  1055. {
  1056. goto out;
  1057. }
  1058. offsetNextTitleSearch = 0;
  1059. }
  1060. }
  1061. }
  1062. else
  1063. offset_fnd_end = -1;
  1064. }
  1065. }
  1066. offsetNextTitleSearch = 0;
  1067. }
  1068. else
  1069. {
  1070. bFound = true; // return 0
  1071. goto out;
  1072. }
  1073. }
  1074. else
  1075. {
  1076. offset_fnd_start = offset_fnd_start + offsetNextTitleSearch;
  1077. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  1078. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  1079. if (search_interrupted)
  1080. {
  1081. goto out;
  1082. }
  1083. if (search_info[nCurrentWiki].buf_len <= 0)
  1084. {
  1085. goto out;
  1086. }
  1087. offsetNextTitleSearch = 0;
  1088. }
  1089. }
  1090. out:
  1091. return article_idx;
  1092. }
  1093. int fetch_search_result(long input_offset_fnd_start, long input_offset_fnd_end, int bInit)
  1094. {
  1095. int len;
  1096. int rc;
  1097. char buf_middle[sizeof(TITLE_SEARCH) * 2];
  1098. long offset_middle;
  1099. static TITLE_SEARCH *pTitleSearch;
  1100. static int offsetNextTitleSearch = 0;
  1101. static long offset_fnd_start = -1;
  1102. static long offset_fnd_end = -1;
  1103. if (bInit)
  1104. {
  1105. result_list->result_populated = 0;
  1106. offset_fnd_start = input_offset_fnd_start;
  1107. offset_fnd_end = input_offset_fnd_end;
  1108. result_list->count = 0;
  1109. offsetNextTitleSearch = 0;
  1110. }
  1111. if (result_list->result_populated || offset_fnd_start < 0)
  1112. return 0;
  1113. if (search_info[nCurrentWiki].offset_current != offset_fnd_start)
  1114. {
  1115. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  1116. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  1117. if (search_interrupted)
  1118. {
  1119. search_interrupted = 7;
  1120. goto interrupted;
  1121. }
  1122. if (search_info[nCurrentWiki].buf_len < sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero) + 2) // at lease 2 chars for pTitleSearch->sTitleSearch
  1123. {
  1124. result_list->result_populated = 1;
  1125. goto out;
  1126. }
  1127. }
  1128. if (!result_list->result_populated)
  1129. {
  1130. pTitleSearch = (TITLE_SEARCH *)&search_info[nCurrentWiki].buf[offsetNextTitleSearch];
  1131. if (offsetNextTitleSearch < search_info[nCurrentWiki].buf_len &&
  1132. is_proper_string(pTitleSearch->sTitleSearch, search_info[nCurrentWiki].buf_len - offsetNextTitleSearch -
  1133. sizeof(pTitleSearch->idxArticle) - sizeof(pTitleSearch->cZero)))
  1134. {
  1135. retrieve_titles_from_fnd(offset_fnd_start + offsetNextTitleSearch,
  1136. result_list->title_search[result_list->count], result_list->title[result_list->count]);
  1137. rc = search_string_cmp(result_list->title_search[result_list->count], search_string, search_str_len);
  1138. //#ifndef INCLUDED_FROM_KERNEL
  1139. //msg(MSG_INFO, "bInit %d, input (%x, %x) ", bInit, input_offset_fnd_start, input_offset_fnd_end);
  1140. //msg(MSG_INFO, "result count %d, offset (%x + %x, %x) ", result_list->count, offset_fnd_start, offsetNextTitleSearch, offset_fnd_end);
  1141. //msg(MSG_INFO, "rc %d, [%s], [%s], [", rc, result_list->title_search[result_list->count], result_list->title[result_list->count]);
  1142. //int i;
  1143. //for (i=0;i<search_str_len;i++)
  1144. //msg(MSG_INFO, "%c", search_string[i]);
  1145. //msg(MSG_INFO, "]\n");
  1146. //#endif
  1147. if (!rc) // match!
  1148. {
  1149. if (!result_list->count)
  1150. {
  1151. offset_fnd_start = offset_fnd_start + offsetNextTitleSearch;
  1152. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  1153. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  1154. if (search_interrupted)
  1155. {
  1156. search_interrupted = 8;
  1157. goto interrupted;
  1158. }
  1159. if (search_info[nCurrentWiki].buf_len < sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero) + 2) // at lease 2 chars for pTitleSearch->sTitleSearch
  1160. {
  1161. result_list->result_populated = 1;
  1162. goto out;
  1163. }
  1164. offsetNextTitleSearch = 0;
  1165. pTitleSearch = (TITLE_SEARCH *)&search_info[nCurrentWiki].buf[offsetNextTitleSearch];
  1166. }
  1167. // use memcpy to avoid "Unaligned data access"
  1168. memcpy((void *)&result_list->idx_article[result_list->count],
  1169. (void *)&pTitleSearch->idxArticle,
  1170. sizeof(result_list->idx_article[result_list->count]));
  1171. result_list->offset_list[result_list->count] = offset_fnd_start + offsetNextTitleSearch;
  1172. offsetNextTitleSearch += sizeof(pTitleSearch->idxArticle) + strlen(pTitleSearch->sTitleSearch) +
  1173. strlen(&pTitleSearch->sTitleSearch[strlen(pTitleSearch->sTitleSearch) + 1]) + 3;
  1174. result_list->offset_next = offset_fnd_start + offsetNextTitleSearch;
  1175. result_list->count++;
  1176. if (result_list->count >= NUMBER_OF_FIRST_PAGE_RESULTS)
  1177. {
  1178. result_list->result_populated = 1;
  1179. goto out;
  1180. }
  1181. }
  1182. else if (rc < 0)
  1183. {
  1184. if (offset_fnd_end <= 0)
  1185. {
  1186. offsetNextTitleSearch += sizeof(pTitleSearch->idxArticle) + strlen(pTitleSearch->sTitleSearch) +
  1187. strlen(&pTitleSearch->sTitleSearch[strlen(pTitleSearch->sTitleSearch) + 1]) + 3;
  1188. offset_fnd_start = offset_fnd_start + offsetNextTitleSearch;
  1189. }
  1190. else // binary search
  1191. {
  1192. offset_middle = offset_fnd_start + (offset_fnd_end - offset_fnd_start) / 2; // position to the middle of the range
  1193. if (offset_middle <= offset_fnd_start)
  1194. offset_fnd_end = -1;
  1195. else
  1196. {
  1197. len = copy_fnd_to_buf(offset_middle, buf_middle, sizeof(buf_middle));
  1198. if (search_interrupted)
  1199. {
  1200. search_interrupted = 9;
  1201. goto interrupted;
  1202. }
  1203. if (len >= sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero) + 2) // at lease 2 chars for pTitleSearch->sTitleSearch
  1204. {
  1205. pTitleSearch = locate_proper_title_search(buf_middle, len);
  1206. if (pTitleSearch)
  1207. {
  1208. char local_title_search[MAX_TITLE_SEARCH];
  1209. char sTitleActual[MAX_TITLE_ACTUAL];
  1210. offset_middle += (char *)pTitleSearch - buf_middle;
  1211. //#ifndef INCLUDED_FROM_KERNEL
  1212. //msg(MSG_INFO, "offset_middle %x\n", offset_middle);
  1213. //#endif
  1214. retrieve_titles_from_fnd(offset_middle, local_title_search, sTitleActual);
  1215. rc = search_string_cmp(local_title_search, search_string, search_str_len);
  1216. //#ifndef INCLUDED_FROM_KERNEL
  1217. //msg(MSG_INFO, "rc %d, [%s], [%s], [", rc, local_title_search, sTitleActual);
  1218. //int i;
  1219. //for (i=0;i<search_str_len;i++)
  1220. //msg(MSG_INFO, "%c", search_string[i]);
  1221. //msg(MSG_INFO, "]\n");
  1222. //#endif
  1223. if (rc >= 0) // the first mactch will be in front or at offset_middle
  1224. {
  1225. if (offset_middle == offset_fnd_end) // search from offset_fnd_start directly
  1226. offset_fnd_end = -1;
  1227. else
  1228. offset_fnd_end = offset_middle;
  1229. }
  1230. else // the first mactch will be after offset_middle
  1231. {
  1232. offset_fnd_start = offset_middle;
  1233. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  1234. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  1235. if (search_interrupted)
  1236. {
  1237. search_interrupted = 10;
  1238. goto interrupted;
  1239. }
  1240. if (search_info[nCurrentWiki].buf_len <= 0)
  1241. {
  1242. result_list->result_populated = 1;
  1243. goto out;
  1244. }
  1245. offsetNextTitleSearch = 0;
  1246. }
  1247. }
  1248. }
  1249. else
  1250. offset_fnd_end = -1;
  1251. }
  1252. }
  1253. offsetNextTitleSearch = 0;
  1254. }
  1255. else
  1256. {
  1257. result_list->result_populated = 1;
  1258. goto out;
  1259. }
  1260. }
  1261. else
  1262. {
  1263. offset_fnd_start = offset_fnd_start + offsetNextTitleSearch;
  1264. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  1265. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  1266. if (search_interrupted)
  1267. {
  1268. search_interrupted = 11;
  1269. goto interrupted;
  1270. }
  1271. if (search_info[nCurrentWiki].buf_len <= 0)
  1272. {
  1273. result_list->result_populated = 1;
  1274. goto out;
  1275. }
  1276. offsetNextTitleSearch = 0;
  1277. }
  1278. }
  1279. out:
  1280. if (result_list->result_populated)
  1281. {
  1282. if (!bInit) // just completed search result
  1283. search_to_be_reloaded(SEARCH_TO_BE_RELOADED_SET, SEARCH_RELOAD_NORMAL);
  1284. return 0;
  1285. }
  1286. else
  1287. {
  1288. return 1;
  1289. }
  1290. interrupted:
  1291. return 1;
  1292. }
  1293. long get_prefix_index_table(int idx_prefix_index_table)
  1294. {
  1295. int idxBlock = idx_prefix_index_table / (SEARCH_CHR_COUNT * SEARCH_CHR_COUNT);
  1296. load_prefix_index(nCurrentWiki);
  1297. if (!search_info[nCurrentWiki].b_prefix_index_block_loaded[idxBlock])
  1298. {
  1299. #ifdef INCLUDED_FROM_KERNEL
  1300. if (wl_input_event_pending())
  1301. search_interrupted = 1;
  1302. #endif
  1303. wl_seek(search_info[nCurrentWiki].fd_pfx,
  1304. idxBlock * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * sizeof(uint32_t));
  1305. wl_read(search_info[nCurrentWiki].fd_pfx,
  1306. &(search_info[nCurrentWiki].prefix_index_table[idxBlock * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT]),
  1307. SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * sizeof(uint32_t));
  1308. search_info[nCurrentWiki].b_prefix_index_block_loaded[idxBlock]++;
  1309. }
  1310. return search_info[nCurrentWiki].prefix_index_table[idx_prefix_index_table];
  1311. }
  1312. long get_search_result_start()
  1313. {
  1314. long offset_search_result_start = -1;
  1315. int idx_prefix_index_table;
  1316. char c1, c2, c3;
  1317. int found = 0;
  1318. /* Disable hashing
  1319. int i;
  1320. int lenCompared;
  1321. int lenCopied;
  1322. */
  1323. long offset;
  1324. /* Disable hashing
  1325. static int lenHashedSearchString = 0;
  1326. static char sHashedSearchString[MAX_SEARCH_STRING_HASHED_LEN];
  1327. static long offsetHasedSearchString[MAX_SEARCH_STRING_HASHED_LEN];
  1328. */
  1329. /* Disable hashing
  1330. if (search_str_len > 3)
  1331. {
  1332. // check the length of the hashed search string can be reused
  1333. if (search_str_len > lenHashedSearchString)
  1334. lenCompared = lenHashedSearchString;
  1335. else
  1336. lenCompared = search_str_len;
  1337. lenHashedSearchString = 0;
  1338. for (i = 0; i < lenCompared; i++)
  1339. {
  1340. if (sHashedSearchString[i] != search_string[i])
  1341. lenHashedSearchString = i;
  1342. }
  1343. // Check if hashed
  1344. if (lenHashedSearchString > 3)
  1345. {
  1346. if (search_str_len > lenHashedSearchString)
  1347. {
  1348. if (search_str_len > MAX_SEARCH_STRING_HASHED_LEN)
  1349. lenCopied = MAX_SEARCH_STRING_HASHED_LEN - lenHashedSearchString;
  1350. else
  1351. lenCopied = search_str_len - lenHashedSearchString;
  1352. memcpy(&sHashedSearchString[lenHashedSearchString], &search_string[lenHashedSearchString], lenCopied);
  1353. // check the extended part first
  1354. for (i = 3; i < lenHashedSearchString + lenCopied; i++)
  1355. {
  1356. if (i >= lenHashedSearchString)
  1357. offsetHasedSearchString[i] = get_search_hash_offset_fnd(sHashedSearchString, i + 1);
  1358. if (search_interrupted)
  1359. {
  1360. search_interrupted = 12;
  1361. goto interrupted;
  1362. }
  1363. if (offsetHasedSearchString[i] &&
  1364. (i >= MAX_SEARCH_STRING_ALL_HASHED_LEN || i == search_str_len - 1))
  1365. {
  1366. found = 1;
  1367. offset_search_result_start = offsetHasedSearchString[i]; // use the longest hashed search string
  1368. }
  1369. }
  1370. lenHashedSearchString += lenCopied;
  1371. }
  1372. if (!found) // not hashed at the extended part
  1373. {
  1374. for (i = 3; i < search_str_len && i < lenHashedSearchString; i++)
  1375. {
  1376. if (offsetHasedSearchString[i] &&
  1377. (i >= MAX_SEARCH_STRING_ALL_HASHED_LEN || i == search_str_len - 1))
  1378. {
  1379. found = 1;
  1380. offset_search_result_start = offsetHasedSearchString[i]; // use the longest hashed search string
  1381. }
  1382. else
  1383. break;
  1384. }
  1385. }
  1386. }
  1387. else
  1388. {
  1389. if (search_str_len > MAX_SEARCH_STRING_HASHED_LEN)
  1390. lenHashedSearchString = MAX_SEARCH_STRING_HASHED_LEN;
  1391. else
  1392. lenHashedSearchString = search_str_len;
  1393. memcpy(sHashedSearchString, search_string, lenHashedSearchString);
  1394. for (i = 3; i < lenHashedSearchString; i++)
  1395. {
  1396. offsetHasedSearchString[i] = get_search_hash_offset_fnd(sHashedSearchString, i + 1);
  1397. if (search_interrupted)
  1398. {
  1399. search_interrupted = 13;
  1400. goto interrupted;
  1401. }
  1402. if (offsetHasedSearchString[i] &&
  1403. (i >= MAX_SEARCH_STRING_ALL_HASHED_LEN || i == search_str_len - 1))
  1404. {
  1405. found = 1;
  1406. offset_search_result_start = offsetHasedSearchString[i]; // use the longest hashed search string
  1407. }
  1408. }
  1409. }
  1410. }
  1411. */
  1412. // if (!found && (3 >= search_str_len || search_str_len > MAX_SEARCH_STRING_ALL_HASHED_LEN))
  1413. if (!found)
  1414. {
  1415. switch(search_str_len)
  1416. {
  1417. case 1:
  1418. c1 = search_string[0];
  1419. c2 = '\0';
  1420. c3 = '\0';
  1421. break;
  1422. case 2:
  1423. c1 = search_string[0];
  1424. c2 = search_string[1];
  1425. c3 = '\0';
  1426. break;
  1427. default:
  1428. c1 = search_string[0];
  1429. c2 = search_string[1];
  1430. c3 = search_string[2];
  1431. break;
  1432. }
  1433. idx_prefix_index_table = bigram_char_idx(c1) * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT +
  1434. bigram_char_idx(c2) * SEARCH_CHR_COUNT + bigram_char_idx(c3);
  1435. if ((offset = get_prefix_index_table(idx_prefix_index_table)))
  1436. {
  1437. found = 1;
  1438. offset_search_result_start = offset;
  1439. }
  1440. if (search_interrupted)
  1441. {
  1442. search_interrupted = 14;
  1443. goto interrupted;
  1444. }
  1445. }
  1446. interrupted:
  1447. return offset_search_result_start;
  1448. }
  1449. int next_search_string(char *local_search_string, int len_local_search_string)
  1450. {
  1451. char *pSupportedChars = SUPPORTED_SEARCH_CHARS;
  1452. int idxChar;
  1453. if (len_local_search_string > MAX_SEARCH_STRING_HASHED_LEN)
  1454. len_local_search_string = MAX_SEARCH_STRING_HASHED_LEN;
  1455. if (len_local_search_string > 0)
  1456. {
  1457. idxChar = 0;
  1458. while (idxChar < strlen(pSupportedChars) && pSupportedChars[idxChar] != local_search_string[len_local_search_string - 1])
  1459. idxChar++;
  1460. if (idxChar >= strlen(pSupportedChars) - 1)
  1461. {
  1462. len_local_search_string--;
  1463. len_local_search_string = next_search_string(local_search_string, len_local_search_string);
  1464. }
  1465. else
  1466. local_search_string[len_local_search_string - 1] = pSupportedChars[idxChar + 1];
  1467. }
  1468. return len_local_search_string;
  1469. }
  1470. long get_search_result_end()
  1471. {
  1472. long offset_search_result_end = -1;
  1473. char local_search_string[MAX_TITLE_SEARCH];
  1474. int len_local_search_string;
  1475. int last_len_local_search_string;
  1476. int found = 0;
  1477. int idx_prefix_index_table;
  1478. char c1, c2, c3;
  1479. long offset;
  1480. if (search_str_len > MAX_SEARCH_STRING_ALL_HASHED_LEN)
  1481. len_local_search_string = MAX_SEARCH_STRING_ALL_HASHED_LEN;
  1482. else
  1483. len_local_search_string = search_str_len;
  1484. memcpy(local_search_string, search_string, len_local_search_string);
  1485. /* disable hashing
  1486. while (!found && len_local_search_string > 3)
  1487. {
  1488. last_len_local_search_string = len_local_search_string;
  1489. len_local_search_string = next_search_string(local_search_string, len_local_search_string);
  1490. if (!memcmp(search_string, local_search_string, len_local_search_string))
  1491. found = 1; // returns -1 directly
  1492. else
  1493. {
  1494. offset_search_result_end = get_search_hash_offset_fnd(local_search_string, len_local_search_string);
  1495. if (search_interrupted)
  1496. {
  1497. search_interrupted = 15;
  1498. goto interrupted;
  1499. }
  1500. if (offset_search_result_end > 0)
  1501. {
  1502. found = 1;
  1503. }
  1504. }
  1505. len_local_search_string = last_len_local_search_string - 1;
  1506. }
  1507. */
  1508. if (!found)
  1509. {
  1510. if (len_local_search_string > 3)
  1511. len_local_search_string = 3;
  1512. while (!found && len_local_search_string > 0)
  1513. {
  1514. last_len_local_search_string = len_local_search_string;
  1515. len_local_search_string = next_search_string(local_search_string, len_local_search_string);
  1516. if (!memcmp(search_string, local_search_string, len_local_search_string))
  1517. found = 1; // returns -1 directly
  1518. else
  1519. {
  1520. switch(len_local_search_string)
  1521. {
  1522. case 1:
  1523. c1 = local_search_string[0];
  1524. c2 = '\0';
  1525. c3 = '\0';
  1526. break;
  1527. case 2:
  1528. c1 = local_search_string[0];
  1529. c2 = local_search_string[1];
  1530. c3 = '\0';
  1531. break;
  1532. default:
  1533. c1 = local_search_string[0];
  1534. c2 = local_search_string[1];
  1535. c3 = local_search_string[2];
  1536. break;
  1537. }
  1538. idx_prefix_index_table = bigram_char_idx(c1) * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT +
  1539. bigram_char_idx(c2) * SEARCH_CHR_COUNT + bigram_char_idx(c3);
  1540. if ((offset = get_prefix_index_table(idx_prefix_index_table)))
  1541. {
  1542. found = 1;
  1543. offset_search_result_end = offset;
  1544. }
  1545. if (search_interrupted)
  1546. {
  1547. search_interrupted = 14;
  1548. goto interrupted;
  1549. }
  1550. // if (search_info[nCurrentWiki].prefix_index_table[idx_prefix_index_table])
  1551. // {
  1552. // found = 1;
  1553. // offset_search_result_end = search_info[nCurrentWiki].prefix_index_table[idx_prefix_index_table];
  1554. // }
  1555. }
  1556. len_local_search_string = last_len_local_search_string - 1;
  1557. }
  1558. }
  1559. interrupted:
  1560. return offset_search_result_end;
  1561. }
  1562. uint32_t get_article_idx_by_title(char *titleSearch, char *titleActual)
  1563. {
  1564. uint32_t article_idx = 0;
  1565. long offset_search_result_start = -1;
  1566. long offset_search_result_end = -1;
  1567. int i = 0;
  1568. backup_search_criteria();
  1569. search_str_len = 0;
  1570. search_str_hiragana_len = 0;
  1571. while (titleSearch[i] && titleSearch[i] != CHAR_LANGUAGE_LINK_TITLE_DELIMITER && search_str_len < MAX_TITLE_SEARCH - 1)
  1572. {
  1573. if (is_supported_search_char(titleSearch[i]))
  1574. {
  1575. if ('A' <= titleSearch[i] && titleSearch[i] <= 'Z')
  1576. search_string[search_str_len++] = 'a' + (titleSearch[i] - 'A');
  1577. else
  1578. search_string[search_str_len++] = titleSearch[i];
  1579. }
  1580. i++;
  1581. }
  1582. if (search_str_len > 0)
  1583. {
  1584. search_string[search_str_len] = '\0';
  1585. offset_search_result_start = get_search_result_start();
  1586. if (!search_interrupted && offset_search_result_start > 0)
  1587. {
  1588. offset_search_result_end = get_search_result_end();
  1589. if (!search_interrupted)
  1590. article_idx = get_article_idx_from_offset_range(titleActual, offset_search_result_start, offset_search_result_end);
  1591. }
  1592. }
  1593. restore_search_criteria();
  1594. return article_idx;
  1595. }
  1596. int search_populate_result()
  1597. {
  1598. int found = 0;
  1599. long offset_search_result_start = -1;
  1600. long offset_search_result_end = -1;
  1601. search_string_changed = false;
  1602. result_list->count = 0;
  1603. result_list->result_populated = 0;
  1604. result_list->cur_selected = -1;
  1605. if (search_str_len > 0)
  1606. {
  1607. offset_search_result_start = get_search_result_start();
  1608. if (search_interrupted)
  1609. {
  1610. search_interrupted = 16;
  1611. goto interrupted;
  1612. }
  1613. if (offset_search_result_start > 0)
  1614. {
  1615. found = 1;
  1616. offset_search_result_end = get_search_result_end();
  1617. if (search_interrupted)
  1618. {
  1619. search_interrupted = 17;
  1620. goto interrupted;
  1621. }
  1622. fetch_search_result(offset_search_result_start, offset_search_result_end, 1);
  1623. if (search_interrupted)
  1624. {
  1625. search_interrupted = 18;
  1626. goto interrupted;
  1627. }
  1628. }
  1629. else
  1630. {
  1631. result_list->result_populated = 1;
  1632. }
  1633. }
  1634. return found;
  1635. interrupted:
  1636. search_string_changed = true;
  1637. return found;
  1638. }
  1639. void capitalize(char *in_str, char *out_str, int len)
  1640. {
  1641. //char cPrev = ' ';
  1642. int i = 0;
  1643. while (i < len)
  1644. {
  1645. //if (cPrev == ' ' && 'a' <= in_str[i] && in_str[i] <= 'z')
  1646. if (i == 0 && 'a' <= in_str[i] && in_str[i] <= 'z')
  1647. out_str[i] = in_str[i] - 32;
  1648. else
  1649. out_str[i] = in_str[i];
  1650. //cPrev = in_str[i];
  1651. i++;
  1652. }
  1653. out_str[i] = '\0';
  1654. }
  1655. char *get_hiragana(char *in_str, int len, int *used_len, char **pEnglish)
  1656. {
  1657. int i;
  1658. int bFound = 0;
  1659. int iStart = 0;
  1660. int iEnd = sizeof(english_hiragana_mapping) / sizeof(struct _english_hiragana_mapping);
  1661. int iMiddle;
  1662. char *pReturn = NULL;
  1663. while (!bFound && iStart < iEnd)
  1664. {
  1665. if (*in_str == english_hiragana_mapping[iStart].english[0])
  1666. bFound = 1;
  1667. else if (*in_str > english_hiragana_mapping[iStart].english[0])
  1668. {
  1669. iMiddle = (iStart + iEnd) / 2;
  1670. if (iMiddle != iStart)
  1671. {
  1672. if (*in_str == english_hiragana_mapping[iMiddle].english[0])
  1673. {
  1674. iStart = iMiddle;
  1675. bFound = 1;
  1676. }
  1677. else if (*in_str > english_hiragana_mapping[iMiddle].english[0])
  1678. iStart = iMiddle;
  1679. else
  1680. iEnd = iMiddle;
  1681. }
  1682. else if (iStart != iEnd)
  1683. {
  1684. iStart = iEnd;
  1685. if (*in_str == english_hiragana_mapping[iEnd].english[0])
  1686. bFound = 1;
  1687. }
  1688. }
  1689. }
  1690. if (bFound) // find the first hiragana_mapping entry with the same starting character as in_str
  1691. {
  1692. while (iStart > 0 && *in_str == english_hiragana_mapping[iStart - 1].english[0])
  1693. iStart--;
  1694. for (i = iStart; i < sizeof(english_hiragana_mapping) / sizeof(struct _english_hiragana_mapping) && *in_str == english_hiragana_mapping[i].english[0]; i++)
  1695. {
  1696. if (len >= strlen(english_hiragana_mapping[i].english) && !strncmp(in_str, english_hiragana_mapping[i].english, strlen(english_hiragana_mapping[i].english)))
  1697. {
  1698. *used_len = strlen(english_hiragana_mapping[i].english);
  1699. if (english_hiragana_mapping[i].unified_english)
  1700. *pEnglish = english_hiragana_mapping[i].unified_english;
  1701. else
  1702. *pEnglish = english_hiragana_mapping[i].english;
  1703. pReturn = english_hiragana_mapping[i].hiragana;
  1704. }
  1705. }
  1706. }
  1707. return pReturn;
  1708. }
  1709. char *get_english(char *in_str, int len, int *used_len)
  1710. {
  1711. int i;
  1712. int bFound = 0;
  1713. int iStart = 0;
  1714. int iEnd = sizeof(hiragana_english_mapping) / sizeof(struct _hiragana_english_mapping);
  1715. int iMiddle;
  1716. char *pReturn = NULL;
  1717. while (!bFound && iStart < iEnd)
  1718. {
  1719. if (*in_str == hiragana_english_mapping[iStart].hiragana[0])
  1720. bFound = 1;
  1721. else if (*in_str > hiragana_english_mapping[iStart].hiragana[0])
  1722. {
  1723. iMiddle = (iStart + iEnd) / 2;
  1724. if (iMiddle != iStart)
  1725. {
  1726. if (*in_str == hiragana_english_mapping[iMiddle].hiragana[0])
  1727. {
  1728. iStart = iMiddle;
  1729. bFound = 1;
  1730. }
  1731. else if (*in_str > hiragana_english_mapping[iMiddle].hiragana[0])
  1732. iStart = iMiddle;
  1733. else
  1734. iEnd = iMiddle;
  1735. }
  1736. else if (iStart != iEnd)
  1737. {
  1738. iStart = iEnd;
  1739. if (*in_str == hiragana_english_mapping[iEnd].hiragana[0])
  1740. bFound = 1;
  1741. }
  1742. }
  1743. }
  1744. if (bFound) // find the first hiragana_mapping entry with the same starting character as in_str
  1745. {
  1746. while (iStart > 0 && *in_str == hiragana_english_mapping[iStart - 1].hiragana[0])
  1747. iStart--;
  1748. for (i = iStart; i < sizeof(hiragana_english_mapping) / sizeof(struct _hiragana_english_mapping) && *in_str == hiragana_english_mapping[i].hiragana[0]; i++)
  1749. {
  1750. if (len >= strlen(hiragana_english_mapping[i].hiragana) && !strncmp(in_str, hiragana_english_mapping[i].hiragana, strlen(hiragana_english_mapping[i].hiragana)))
  1751. {
  1752. *used_len = strlen(hiragana_english_mapping[i].hiragana);
  1753. pReturn = hiragana_english_mapping[i].english;
  1754. }
  1755. }
  1756. }
  1757. return pReturn;
  1758. }
  1759. void search_reload(int flag)
  1760. {
  1761. int screen_display_count = keyboard_get_mode() == KEYBOARD_NONE ?
  1762. NUMBER_OF_FIRST_PAGE_RESULTS : NUMBER_OF_RESULTS_KEYBOARD;
  1763. int y_pos,start_x_search=0;
  1764. int end_y_pos;
  1765. static int last_start_x_search=0;
  1766. char *title;
  1767. char temp_search_string[MAX_TITLE_SEARCH * 3];
  1768. static int bNoResultLastTime = 0;
  1769. int keyboard_mode = keyboard_get_mode();
  1770. char *pMsg;
  1771. more_search_results = 0;
  1772. guilib_fb_lock();
  1773. if (keyboard_mode == KEYBOARD_NONE)
  1774. {
  1775. if (result_list->result_populated || flag == SEARCH_RELOAD_KEEP_REFRESH)
  1776. {
  1777. if (flag == SEARCH_RELOAD_KEEP_RESULT)
  1778. guilib_clear_area(0, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT, 239, LCD_HEIGHT_LINES - 1);
  1779. else
  1780. guilib_clear();
  1781. }
  1782. else
  1783. guilib_clear_area(start_x_search, 0, LCD_BUF_WIDTH_PIXELS, 30);
  1784. }
  1785. else
  1786. {
  1787. if (flag != SEARCH_RELOAD_NO_POPULATE)
  1788. keyboard_key_reset_invert(KEYBOARD_RESET_INVERT_NOW, 0);
  1789. if (flag == SEARCH_RELOAD_KEEP_REFRESH)
  1790. guilib_clear_area(0, 0, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  1791. if(search_string_changed_remove)
  1792. {
  1793. if(!search_str_len)
  1794. start_x_search = 0;
  1795. else
  1796. start_x_search = search_string_pos[search_str_len];
  1797. search_string_changed_remove = false;
  1798. if (start_x_search < LCD_BUF_WIDTH_PIXELS)
  1799. guilib_clear_area(start_x_search, 0, LCD_BUF_WIDTH_PIXELS, 30);
  1800. //else
  1801. //{
  1802. // guilib_clear_area(0, 0, LCD_BUF_WIDTH_PIXELS, 30);
  1803. //}
  1804. }
  1805. // if (result_list->result_populated)
  1806. // guilib_clear_area(0, 35, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  1807. }
  1808. if (!search_str_len)
  1809. {
  1810. search_string_changed = 0;
  1811. bNoResultLastTime = 0;
  1812. result_list->count = 0;
  1813. result_list->result_populated = 1;
  1814. result_list->cur_selected = -1;
  1815. pMsg = get_nls_text("type_a_word");
  1816. render_string_and_clear(SUBTITLE_FONT_IDX, -1, 55, pMsg, strlen(pMsg), 0,
  1817. 0, 35, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  1818. keyboard_paint();
  1819. goto out;
  1820. }
  1821. if (wiki_is_japanese())
  1822. capitalize(search_string_hiragana, temp_search_string, search_str_hiragana_len);
  1823. else
  1824. capitalize(search_string, temp_search_string, search_str_len);
  1825. if (last_start_x_search >= LCD_BUF_WIDTH_PIXELS)
  1826. guilib_clear_area(0, 0, LCD_BUF_WIDTH_PIXELS, 30);
  1827. start_x_search = render_string_right(SEARCH_HEADING_FONT_IDX, LCD_LEFT_MARGIN, LCD_TOP_MARGIN, temp_search_string, strlen(temp_search_string), 0);
  1828. if (last_start_x_search < LCD_BUF_WIDTH_PIXELS && start_x_search >= LCD_BUF_WIDTH_PIXELS)
  1829. {
  1830. guilib_clear_area(0, 0, LCD_BUF_WIDTH_PIXELS, 30);
  1831. start_x_search = render_string_right(SEARCH_HEADING_FONT_IDX, LCD_LEFT_MARGIN, LCD_TOP_MARGIN, temp_search_string, strlen(temp_search_string), 0);
  1832. }
  1833. last_start_x_search = start_x_search;
  1834. search_string_pos[search_str_len]=start_x_search;
  1835. y_pos = RESULT_START;
  1836. if (result_list->result_populated && flag != SEARCH_RELOAD_NO_POPULATE)
  1837. {
  1838. unsigned int i;
  1839. unsigned int count = result_list->count < screen_display_count ?
  1840. result_list->count : screen_display_count;
  1841. if (!result_list->count) {
  1842. if (!bNoResultLastTime)
  1843. {
  1844. guilib_clear_area(0, 35, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  1845. pMsg = get_nls_text("no_results");
  1846. render_string(SEARCH_LIST_FONT_IDX, -1, 55, pMsg, strlen(pMsg), 0);
  1847. bNoResultLastTime = 1;
  1848. }
  1849. goto out;
  1850. }
  1851. bNoResultLastTime = 0;
  1852. article_link_count = 0;
  1853. for (i = 0; i < screen_display_count; i++)
  1854. {
  1855. end_y_pos = y_pos + RESULT_HEIGHT - 1;
  1856. if (screen_display_count < NUMBER_OF_FIRST_PAGE_RESULTS && end_y_pos > LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1)
  1857. end_y_pos = LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1;
  1858. guilib_clear_area(0, y_pos, 239, end_y_pos);
  1859. if (i < count)
  1860. {
  1861. if (keyboard_mode == KEYBOARD_NONE)
  1862. {
  1863. articleLink[article_link_count].start_xy = (unsigned long)((y_pos - 2) << 8); // consider the difference between render_string and draw_string
  1864. articleLink[article_link_count].end_xy = (unsigned long)((LCD_BUF_WIDTH_PIXELS) | ((end_y_pos - 2) << 8));
  1865. articleLink[article_link_count++].article_id = result_list->idx_article[i];
  1866. }
  1867. title = result_list->title[i];
  1868. render_string(SEARCH_LIST_FONT_IDX, LCD_LEFT_MARGIN, y_pos, title, strlen(title), 0);
  1869. }
  1870. y_pos += RESULT_HEIGHT;
  1871. if((y_pos+RESULT_HEIGHT)>guilib_framebuffer_height())
  1872. break;
  1873. }
  1874. if (keyboard_mode == KEYBOARD_NONE)
  1875. {
  1876. if (result_list->count == NUMBER_OF_FIRST_PAGE_RESULTS)
  1877. {
  1878. more_search_results = 1;
  1879. }
  1880. }
  1881. }
  1882. out:
  1883. guilib_fb_unlock();
  1884. }
  1885. void search_to_be_reloaded(int to_be_reloaded_flag, int reload_flag)
  1886. {
  1887. static bool to_be_reloaded = false;
  1888. static int saved_reload_flag;
  1889. switch (to_be_reloaded_flag)
  1890. {
  1891. case SEARCH_TO_BE_RELOADED_CLEAR:
  1892. to_be_reloaded = false;
  1893. break;
  1894. case SEARCH_TO_BE_RELOADED_SET:
  1895. if (reload_flag == SEARCH_RELOAD_NORMAL && keyboard_key_inverted())
  1896. {
  1897. to_be_reloaded = true;
  1898. saved_reload_flag = reload_flag;
  1899. }
  1900. else
  1901. {
  1902. search_reload(reload_flag);
  1903. to_be_reloaded = false;
  1904. }
  1905. break;
  1906. case SEARCH_TO_BE_RELOADED_CHECK:
  1907. if (to_be_reloaded && !keyboard_key_inverted())
  1908. {
  1909. search_reload(saved_reload_flag);
  1910. to_be_reloaded = false;
  1911. }
  1912. break;
  1913. default:
  1914. break;
  1915. }
  1916. }
  1917. void search_result_display()
  1918. {
  1919. int screen_display_count = keyboard_get_mode() == KEYBOARD_NONE ?
  1920. NUMBER_OF_FIRST_PAGE_RESULTS : NUMBER_OF_RESULTS_KEYBOARD;
  1921. int y_pos=0;
  1922. char *title;
  1923. char *pMsg;
  1924. guilib_fb_lock();
  1925. guilib_clear_area(0, RESULT_START, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  1926. if (!search_str_len)
  1927. {
  1928. result_list->count = 0;
  1929. result_list->cur_selected = -1;
  1930. pMsg = get_nls_text("type_a_word");
  1931. render_string_and_clear(SUBTITLE_FONT_IDX, -1, 55, pMsg, strlen(pMsg), 0,
  1932. 0, 35, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  1933. keyboard_paint();
  1934. goto out;
  1935. }
  1936. y_pos = RESULT_START;
  1937. if (result_list->result_populated && !result_list->count) {
  1938. pMsg = get_nls_text("no_results");
  1939. render_string(SEARCH_LIST_FONT_IDX, -1, 55, pMsg, strlen(pMsg), 0);
  1940. goto out;
  1941. }
  1942. if (result_list->count) {
  1943. unsigned int i;
  1944. unsigned int count = result_list->count < screen_display_count ?
  1945. result_list->count : screen_display_count;
  1946. for (i = 0; i < count; i++) {
  1947. title = result_list->title[i];
  1948. render_string(SEARCH_LIST_FONT_IDX, LCD_LEFT_MARGIN, y_pos, title, strlen(title), 0);
  1949. y_pos += RESULT_HEIGHT;
  1950. if((y_pos+RESULT_HEIGHT)>guilib_framebuffer_height())
  1951. break;
  1952. }
  1953. if (result_list->cur_selected >= screen_display_count)
  1954. result_list->cur_selected = screen_display_count - 1;
  1955. invert_selection(result_list->cur_selected, -1, RESULT_START, RESULT_HEIGHT);
  1956. }
  1957. out:
  1958. guilib_fb_unlock();
  1959. }
  1960. void search_hiragana_add_char()
  1961. {
  1962. int i;
  1963. char *pHiragana = NULL;
  1964. int used_len;
  1965. char *pEnglish = NULL;
  1966. if (search_str_len == 1)
  1967. search_str_converted_len = 0;
  1968. if (keyboard_get_mode() == KEYBOARD_CHAR ||
  1969. (search_str_len > 0 && search_string[search_str_len - 1] == '-' && (search_string_hiragana[search_str_hiragana_len - 1] & 0x80)))
  1970. {
  1971. i = search_str_converted_len;
  1972. if (search_str_len - i > LONGEST_HIRAGANA_ENGLISH_CHARS)
  1973. i = search_str_len - LONGEST_HIRAGANA_ENGLISH_CHARS;
  1974. while (i < search_str_len && (search_string[i] == ' ' ||
  1975. !(pHiragana = get_hiragana(&search_string[i], search_str_len - i, &used_len, &pEnglish))))
  1976. i++;
  1977. if (pHiragana)
  1978. {
  1979. memcpy(&search_string_hiragana[search_str_hiragana_len - (search_str_len - i - 1)], pHiragana, strlen(pHiragana) + 1);
  1980. search_str_hiragana_len += - (search_str_len - i - 1) + strlen(pHiragana);
  1981. memcpy(&search_string[i], pEnglish, strlen(pEnglish) + 1);
  1982. search_str_len = i + strlen(pEnglish);
  1983. search_str_converted_len = search_str_len;
  1984. }
  1985. else
  1986. {
  1987. search_string_hiragana[search_str_hiragana_len++] = search_string[search_str_len - 1];
  1988. }
  1989. }
  1990. else
  1991. {
  1992. search_string_hiragana[search_str_hiragana_len++] = search_string[search_str_len - 1];
  1993. search_str_converted_len = search_str_len;
  1994. }
  1995. }
  1996. int search_add_char(char c, unsigned long ev_time)
  1997. {
  1998. (void)ev_time;
  1999. if((c == 0x20 && search_str_len>0 && search_string[search_str_len-1] == 0x20) ||
  2000. (search_str_len >= MAX_TITLE_SEARCH - 2) ||
  2001. (!search_str_len && c == 0x20))
  2002. return -1;
  2003. if (!search_str_len) // clear type_a_word message
  2004. {
  2005. guilib_fb_lock();
  2006. guilib_clear_area(0, 55, 239, 80);
  2007. guilib_fb_unlock();
  2008. }
  2009. if ('A' <= c && c <= 'Z')
  2010. c += 32;
  2011. search_string[search_str_len++] = c;
  2012. search_string[search_str_len] = '\0';
  2013. if (wiki_is_japanese())
  2014. {
  2015. search_hiragana_add_char();
  2016. }
  2017. time_search_string_changed = get_time_ticks();
  2018. search_string_changed = true;
  2019. return 0;
  2020. }
  2021. int check_search_string_change(void)
  2022. {
  2023. if (!search_string_changed)
  2024. return 0;
  2025. if (time_diff(get_time_ticks(), time_search_string_changed) > seconds_to_ticks(DELAYED_SEARCH_TIME))
  2026. {
  2027. search_interrupted = 0;
  2028. search_populate_result();
  2029. if (search_interrupted)
  2030. goto interrupted;
  2031. result_list->cur_selected = -1;
  2032. if (result_list->result_populated)
  2033. search_to_be_reloaded(SEARCH_TO_BE_RELOADED_SET, SEARCH_RELOAD_NORMAL);
  2034. }
  2035. return 1;
  2036. interrupted:
  2037. return 1;
  2038. }
  2039. void search_fetch()
  2040. {
  2041. search_populate_result();
  2042. result_list->cur_selected = -1;
  2043. search_string_changed = false;
  2044. }
  2045. int hiragana_to_english(char *sEnglish, char *sHiragana, int lenHiragana)
  2046. {
  2047. int lenEnglish = 0;
  2048. int i = 0;
  2049. char *pEnglish;
  2050. int used_len;
  2051. while (i < lenHiragana)
  2052. {
  2053. pEnglish = get_english(&sHiragana[i], lenHiragana - i, &used_len);
  2054. if (pEnglish)
  2055. {
  2056. memcpy(&sEnglish[lenEnglish], pEnglish, strlen(pEnglish));
  2057. lenEnglish += strlen(pEnglish);
  2058. i += used_len;
  2059. }
  2060. else
  2061. {
  2062. sEnglish[lenEnglish++] = sHiragana[i++];
  2063. }
  2064. }
  2065. sEnglish[lenEnglish] = '\0';
  2066. return lenEnglish;
  2067. }
  2068. /*
  2069. * return value - 0: remove ok, -1: no key to remove
  2070. */
  2071. int search_remove_char(int bPopulate, unsigned long ev_time)
  2072. {
  2073. (void)ev_time;
  2074. if (search_str_len == 0)
  2075. return -1;
  2076. if (wiki_is_japanese())
  2077. {
  2078. if (!(search_string_hiragana[search_str_hiragana_len - 1] & 0x80))
  2079. {
  2080. search_string[--search_str_len] = '\0';
  2081. search_string_hiragana[--search_str_hiragana_len] = '\0';
  2082. if (search_str_converted_len > search_str_len)
  2083. search_str_converted_len = search_str_len;
  2084. }
  2085. else
  2086. {
  2087. while (search_str_hiragana_len > 0 &&
  2088. ((search_string_hiragana[search_str_hiragana_len - 1] & 0x80) &&
  2089. !(search_string_hiragana[search_str_hiragana_len - 1] & 0x40)))
  2090. search_str_hiragana_len--;
  2091. search_string_hiragana[--search_str_hiragana_len] = '\0';
  2092. search_str_len = hiragana_to_english(search_string, search_string_hiragana, search_str_hiragana_len);
  2093. search_string[search_str_len] = '\0';
  2094. search_str_converted_len = search_str_len;
  2095. }
  2096. }
  2097. else
  2098. search_string[--search_str_len] = '\0';
  2099. if (bPopulate || !search_str_len)
  2100. {
  2101. search_populate_result();
  2102. search_string_changed_remove = true;
  2103. result_list->cur_selected = -1;
  2104. }
  2105. else
  2106. {
  2107. search_string_changed = true;
  2108. search_string_changed_remove = true;
  2109. time_search_string_changed = get_time_ticks();
  2110. }
  2111. return 0;
  2112. }
  2113. TITLE_SEARCH *locate_previous_title(char *buf, int len)
  2114. {
  2115. char *p;
  2116. int bFound = 0;
  2117. if (len > 2)
  2118. {
  2119. p = buf + len - 2;
  2120. len--;
  2121. while (!bFound && len > sizeof(uint32_t))
  2122. {
  2123. if (!*p) {
  2124. bFound = 1;
  2125. p -= sizeof(uint32_t);
  2126. }
  2127. else
  2128. {
  2129. p--;
  2130. len--;
  2131. }
  2132. }
  2133. if (bFound)
  2134. return (TITLE_SEARCH *)p;
  2135. }
  2136. return NULL;
  2137. }
  2138. int search_current_selection(void)
  2139. {
  2140. // const char* title;
  2141. // if (result_list->cur_selected >= result_list->count - result_list->first_item) {
  2142. // DP(DBG_SEARCH, ("O search_current_title() NO TITLE\n"));
  2143. // return NULL;
  2144. // }
  2145. // title = result_list_title(result_list->cur_selected+result_list->first_item);
  2146. // DP(DBG_SEARCH, ("O search_current_title() '%s'\n", title));
  2147. return result_list->cur_selected;
  2148. }
  2149. unsigned int search_result_count()
  2150. {
  2151. return result_list->count;
  2152. }
  2153. int clear_search_string()
  2154. {
  2155. if (search_str_len == 0)
  2156. return -1;
  2157. result_list->count = 0;
  2158. strcpy(search_string,"");
  2159. search_str_len = 0;
  2160. search_str_hiragana_len = 0;
  2161. return 0;
  2162. }
  2163. int get_search_string_len()
  2164. {
  2165. return search_str_len;
  2166. }
  2167. int search_result_selected()
  2168. {
  2169. return result_list->cur_selected;
  2170. }
  2171. extern unsigned char *file_buffer;
  2172. extern int restricted_article;
  2173. extern int current_article_wiki_id;
  2174. char *compressed_buf = NULL;
  2175. int retrieve_article(long idx_article_with_wiki_id)
  2176. {
  2177. ARTICLE_PTR article_ptr;
  2178. long idx_article;
  2179. int nWikiIdx;
  2180. if (!compressed_buf)
  2181. compressed_buf = (char *)malloc_simple(MAX_COMPRESSED_ARTICLE, MEM_TAG_INDEX_M1);
  2182. current_article_wiki_id = (unsigned long)idx_article_with_wiki_id >> 24;
  2183. if (current_article_wiki_id == 0)
  2184. nWikiIdx = nCurrentWiki;
  2185. else
  2186. {
  2187. nWikiIdx = get_wiki_idx_from_id(current_article_wiki_id );
  2188. if (nWikiIdx >= 0)
  2189. load_prefix_index(nWikiIdx);
  2190. else
  2191. {
  2192. print_article_error();
  2193. return -1;
  2194. }
  2195. }
  2196. idx_article = idx_article_with_wiki_id & 0x00FFFFFF;
  2197. if (nWikiIdx >= 0 && compressed_buf && 0 < idx_article && idx_article <= search_info[nWikiIdx].max_article_idx) {
  2198. wl_seek(search_info[nWikiIdx].fd_idx, sizeof(uint32_t) + (idx_article - 1) * sizeof(article_ptr));
  2199. wl_read(search_info[nWikiIdx].fd_idx, &article_ptr, sizeof(article_ptr));
  2200. int dat_file_id = article_ptr.file_id;
  2201. if (search_info[nWikiIdx].fd_dat[dat_file_id] < 0)
  2202. {
  2203. char file_name[13];
  2204. sprintf(file_name, "wiki%d.dat", dat_file_id);
  2205. search_info[nWikiIdx].fd_dat[dat_file_id] = wl_open(get_wiki_file_path(nWikiIdx, file_name),
  2206. WL_O_RDONLY);
  2207. }
  2208. if (search_info[nWikiIdx].fd_dat[dat_file_id] >= 0)
  2209. {
  2210. CONCAT_ARTICLE_INFO concat_article_infos[MAX_ARTICLES_PER_COMPRESSION];
  2211. uint8_t nArticlesConcatnated;
  2212. uint32_t dat_article_len;
  2213. SizeT required_len = 0;
  2214. uint32_t offset = 0;
  2215. int i;
  2216. int idx_concat_article = -1;
  2217. wl_seek(search_info[nWikiIdx].fd_dat[dat_file_id], article_ptr.offset_dat & 0x7FFFFFFF);
  2218. wl_read(search_info[nWikiIdx].fd_dat[dat_file_id], &nArticlesConcatnated,
  2219. sizeof(nArticlesConcatnated));
  2220. wl_read(search_info[nWikiIdx].fd_dat[dat_file_id], &concat_article_infos,
  2221. nArticlesConcatnated * sizeof(CONCAT_ARTICLE_INFO));
  2222. for (i = 0; i < nArticlesConcatnated; i++)
  2223. {
  2224. if (concat_article_infos[i].article_id == idx_article)
  2225. {
  2226. idx_concat_article = i;
  2227. offset = concat_article_infos[i].offset_article & ~0x80000000;
  2228. required_len = offset + concat_article_infos[i].article_len;
  2229. break;
  2230. }
  2231. }
  2232. wl_read(search_info[nWikiIdx].fd_dat[dat_file_id], &dat_article_len, sizeof(dat_article_len));
  2233. wl_read(search_info[nWikiIdx].fd_dat[dat_file_id], compressed_buf, dat_article_len);
  2234. dat_article_len -= LZMA_PROPS_SIZE;
  2235. ELzmaStatus status;
  2236. //SizeT file_buffer_len = FILE_BUFFER_SIZE;
  2237. SizeT compressed_buffer_len = dat_article_len;
  2238. int rc = (int)LzmaDecode(file_buffer,
  2239. &required_len,
  2240. (const Byte *)compressed_buf + LZMA_PROPS_SIZE,
  2241. &compressed_buffer_len,
  2242. (const Byte *)compressed_buf, LZMA_PROPS_SIZE,
  2243. LZMA_FINISH_ANY,
  2244. &status, &g_Alloc);
  2245. if (rc == SZ_OK || rc == SZ_ERROR_INPUT_EOF) // can generate SZ_ERROR_INPUT_EOF but result is OK
  2246. {
  2247. if (idx_concat_article >= 0)
  2248. {
  2249. if (concat_article_infos[idx_concat_article].offset_article & 0x80000000) {
  2250. restricted_article = 1;
  2251. } else {
  2252. restricted_article = 0;
  2253. }
  2254. memcpy(file_buffer, &file_buffer[offset], concat_article_infos[idx_concat_article].article_len);
  2255. file_buffer[concat_article_infos[idx_concat_article].article_len] = '\0';
  2256. return 0;
  2257. }
  2258. }
  2259. }
  2260. }
  2261. print_article_error();
  2262. return -1;
  2263. }
  2264. void search_set_selection(int new_selection)
  2265. {
  2266. result_list->cur_selected = new_selection;
  2267. }
  2268. void search_open_article(int new_selection)
  2269. {
  2270. int list_idx;
  2271. list_idx = new_selection;
  2272. if (list_idx >= NUMBER_OF_FIRST_PAGE_RESULTS)
  2273. list_idx -= NUMBER_OF_FIRST_PAGE_RESULTS;
  2274. display_link_article(result_list->idx_article[list_idx]);
  2275. }
  2276. long find_closest_idx(long idx, char *title)
  2277. {
  2278. ARTICLE_PTR article_ptr;
  2279. TITLE_SEARCH title_search;
  2280. static int count = 0;
  2281. char sTitleSearch[MAX_TITLE_SEARCH];
  2282. title[0] = '\0';
  2283. if (idx > search_info[nCurrentWiki].max_article_idx)
  2284. idx -= search_info[nCurrentWiki].max_article_idx;
  2285. wl_seek(search_info[nCurrentWiki].fd_idx, (idx - 1) * sizeof(ARTICLE_PTR) + sizeof(uint32_t));
  2286. wl_read(search_info[nCurrentWiki].fd_idx, &article_ptr, sizeof(article_ptr));
  2287. if (!article_ptr.offset_fnd)
  2288. {
  2289. if (count < 10)
  2290. {
  2291. count++;
  2292. return find_closest_idx(idx + 1, title);
  2293. }
  2294. else
  2295. {
  2296. count = 0;
  2297. return 0;
  2298. }
  2299. }
  2300. else
  2301. {
  2302. count = 0;
  2303. copy_fnd_to_buf(article_ptr.offset_fnd, (char *)&title_search, sizeof(title_search));
  2304. retrieve_titles_from_fnd(article_ptr.offset_fnd, sTitleSearch, title);
  2305. title[MAX_TITLE_ACTUAL - 1] = '\0';
  2306. return idx;
  2307. }
  2308. }
  2309. #if !defined(INCLUDED_FROM_KERNEL)
  2310. #include <time.h>
  2311. #include <sys/time.h>
  2312. #endif
  2313. extern int last_display_mode;
  2314. void random_article(void)
  2315. {
  2316. long idx_article;
  2317. char title[MAX_TITLE_ACTUAL];
  2318. unsigned long clock_ticks;
  2319. #if defined(INCLUDED_FROM_KERNEL)
  2320. clock_ticks = Tick_get();
  2321. #else
  2322. //clock_ticks = clock(); // this gets CPU time used, it not suitable for random
  2323. struct timeval t; // get elapsed time in us but do not care about overflow
  2324. gettimeofday(&t, NULL); // this more-or-less simulates what happens on WR hardware
  2325. clock_ticks = t.tv_sec * 1000000 + t.tv_usec;
  2326. #endif
  2327. idx_article = clock_ticks % search_info[nCurrentWiki].max_article_idx + 1;
  2328. idx_article = find_closest_idx(idx_article, title);
  2329. if (idx_article)
  2330. {
  2331. last_display_mode = DISPLAY_MODE_INDEX; // for history_save not to log the last article index
  2332. display_link_article(idx_article);
  2333. #ifdef INCLUDED_FROM_KERNEL
  2334. wl_input_reset_random_key(); // only respond to the first random key
  2335. #endif
  2336. }
  2337. }