search.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373
  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. int search_interrupted = 0;
  54. typedef struct _search_results {
  55. char title[NUMBER_OF_FIRST_PAGE_RESULTS][MAX_TITLE_SEARCH];
  56. uint32_t idx_article[NUMBER_OF_FIRST_PAGE_RESULTS]; // index (wiki.idx) for loading the article
  57. uint32_t offset_list[NUMBER_OF_FIRST_PAGE_RESULTS]; // offset (wiki.fnd) of each search title in list
  58. uint32_t offset_next; // offset (wiki.fnd) of the next title after the list
  59. uint32_t count;
  60. uint32_t result_populated;
  61. int32_t cur_selected; // -1 when no selection.
  62. } SEARCH_RESULTS;
  63. static SEARCH_RESULTS *result_list = NULL;
  64. typedef struct _search_info {
  65. int32_t inited;
  66. int32_t fd_pfx;
  67. int32_t fd_idx;
  68. int32_t fd_dat[MAX_DAT_FILES];
  69. uint32_t max_article_idx;
  70. uint32_t prefix_index_table[SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT];
  71. uint32_t b_prefix_index_block_loaded[SEARCH_CHR_COUNT];
  72. char buf[NUMBER_OF_FIRST_PAGE_RESULTS * sizeof(TITLE_SEARCH)]; // buf correspond to result_list
  73. uint32_t buf_len;
  74. uint32_t offset_current; // offset (wiki.fnd) of the content of buffer
  75. } SEARCH_INFO;
  76. static SEARCH_INFO *search_info = NULL;
  77. #define SIZE_PREFIX_INDEX_TABLE SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * sizeof(long)
  78. //static struct search_state state;
  79. //static struct search_state last_first_hit;
  80. static char search_string[MAX_TITLE_SEARCH];
  81. static int search_string_pos[MAX_TITLE_SEARCH];
  82. static int search_str_len = 0;
  83. //static char s_find_first = 1;
  84. static void *SzAlloc(void *p, size_t size) { p = p; return malloc_simple(size, MEM_TAG_INDEX_M1); }
  85. static void SzFree(void *p, void *address) { p = p; free_simple(address, MEM_TAG_INDEX_M1); }
  86. static ISzAlloc g_Alloc = { SzAlloc, SzFree };
  87. //const char* search_fetch_result()
  88. //{
  89. // DP(DBG_SEARCH, ("O search_fetch_result() called\n"));
  90. // if (search_str_len == 0)
  91. // return NULL;
  92. //#ifdef WOM_ON
  93. // const wom_article_index_t* idx;
  94. // static char result_buf[MAXSTR]; // we know that the returned pointer is copied immediately
  95. // if (s_find_first) {
  96. // s_find_first = 0;
  97. // idx = wom_find_article(g_womh, search_string, search_str_len);
  98. // } else
  99. // idx = wom_get_next_article(g_womh);
  100. // if (!idx) return 0;
  101. // sprintf(result_buf, "%.*s%.6x", idx->uri_len, idx->abbreviated_uri, (unsigned int) idx->offset_into_articles);
  102. // DP(DBG_SEARCH, ("O search_fetch_result() '%s'\n", result_buf));
  103. // return result_buf;
  104. //#else // !WOM_ON
  105. // char* result = search_fast(&global_search, search_string, &state);
  106. // if (s_find_first) {
  107. // s_find_first = 0;
  108. // store_state(&global_search, &state, &last_first_hit);
  109. // }
  110. // return result;
  111. //#endif
  112. //}
  113. long result_list_offset_next(void)
  114. {
  115. return result_list->offset_next;
  116. }
  117. long result_list_next_result(long offset_next, long *idxArticle, char *sTitleSearch)
  118. {
  119. TITLE_SEARCH titleSearch;
  120. copy_fnd_to_buf(offset_next, (void *)&titleSearch, sizeof(TITLE_SEARCH));
  121. bigram_decode(sTitleSearch, titleSearch.sTitleSearch, MAX_TITLE_SEARCH);
  122. if (!search_string_cmp(sTitleSearch, search_string, search_str_len)) // match!
  123. {
  124. *idxArticle = titleSearch.idxArticle;
  125. return offset_next + sizeof(titleSearch.idxArticle) + strlen(titleSearch.sTitleSearch) + 2;
  126. }
  127. else
  128. return 0;
  129. }
  130. void get_article_title_from_idx(long idx, char *title)
  131. {
  132. ARTICLE_PTR article_ptr;
  133. TITLE_SEARCH title_search;
  134. int wiki_id;
  135. int wiki_idx;
  136. int nTmpeCurrentWiki = nCurrentWiki;
  137. title[0] = '\0';
  138. wiki_id = idx >> 24;
  139. idx &= 0x00FFFFFF;
  140. if (wiki_id > 0)
  141. {
  142. wiki_idx = get_wiki_idx_from_id(wiki_id);
  143. if (wiki_idx < 0) // wiki not loaded
  144. return;
  145. nCurrentWiki = wiki_idx;
  146. }
  147. wl_seek(search_info[nCurrentWiki].fd_idx, (idx - 1) * sizeof(ARTICLE_PTR) + 4);
  148. wl_read(search_info[nCurrentWiki].fd_idx, (void *)&article_ptr, sizeof(article_ptr));
  149. if (article_ptr.file_id_compressed_len && article_ptr.offset_fnd)
  150. {
  151. copy_fnd_to_buf(article_ptr.offset_fnd, (char *)&title_search, sizeof(title_search));
  152. bigram_decode(title, title_search.sTitleSearch, MAX_TITLE_SEARCH);
  153. title[MAX_TITLE_SEARCH - 1] = '\0';
  154. }
  155. nCurrentWiki = nTmpeCurrentWiki;
  156. }
  157. void load_prefix_index(int nWikiIdx)
  158. {
  159. int i;
  160. if (!search_info[nWikiIdx].inited)
  161. {
  162. search_info[nWikiIdx].fd_pfx = wl_open(get_wiki_file_path(nWikiIdx, "wiki.pfx"), WL_O_RDONLY);
  163. search_info[nWikiIdx].fd_idx = wl_open(get_wiki_file_path(nWikiIdx, "wiki.idx"), WL_O_RDONLY);
  164. for (i=0; i < MAX_DAT_FILES; i++)
  165. search_info[nWikiIdx].fd_dat[i] = -1;
  166. search_info[nWikiIdx].offset_current = -1;
  167. if (search_info[nWikiIdx].fd_pfx >= 0 && search_info[nWikiIdx].fd_idx >= 0)
  168. {
  169. wl_read(search_info[nWikiIdx].fd_idx, (void *)&search_info[nWikiIdx].max_article_idx, sizeof(search_info[nWikiIdx].max_article_idx));
  170. memset((char *)search_info[nWikiIdx].b_prefix_index_block_loaded, 0, sizeof(search_info[nWikiIdx].b_prefix_index_block_loaded));
  171. search_info[nWikiIdx].inited = 1;
  172. }
  173. else
  174. fatal_error("index file open error");
  175. }
  176. }
  177. void search_init()
  178. {
  179. int i;
  180. int nWikiCount = get_wiki_count();
  181. if (!result_list)
  182. {
  183. result_list = (SEARCH_RESULTS *)malloc_simple(sizeof(SEARCH_RESULTS), MEM_TAG_INDEX_M1);
  184. if (!result_list)
  185. fatal_error("search_init malloc error");
  186. }
  187. if (!search_info)
  188. {
  189. search_info = (SEARCH_INFO *)malloc_simple(sizeof(SEARCH_INFO) * nWikiCount, MEM_TAG_INDEX_M1);
  190. if (!search_info)
  191. fatal_error("search_init malloc error");
  192. else
  193. {
  194. for (i = 0; i < nWikiCount; i++)
  195. {
  196. search_info[i].inited = 0;
  197. }
  198. }
  199. }
  200. load_prefix_index(nCurrentWiki);
  201. result_list->count = 0;
  202. init_search_hash();
  203. }
  204. void memrcpy(char *dest, char *src, int len) // memory copy starting from the last byte
  205. {
  206. if (len >= 0)
  207. {
  208. dest += len - 1;
  209. src += len - 1;
  210. while (len--)
  211. {
  212. *dest = *src;
  213. dest--;
  214. src--;
  215. }
  216. }
  217. }
  218. char article_error[100] = "";
  219. char article_error2[100] = "";
  220. static void print_article_error()
  221. {
  222. guilib_fb_lock();
  223. guilib_clear();
  224. render_string(SEARCH_LIST_FONT_IDX, -1, 84, "The article failed to load.", 27, 0);
  225. render_string(SEARCH_LIST_FONT_IDX, -1, 104, "Please restart your WikiReader and", 34, 0);
  226. render_string(SEARCH_LIST_FONT_IDX, -1, 124, "try again.", 10, 0);
  227. //render_string(SEARCH_LIST_FONT_IDX, -1, 124, article_error, strlen(article_error), 0);
  228. //render_string(SEARCH_LIST_FONT_IDX, -1, 144, article_error2, strlen(article_error2), 0);
  229. guilib_fb_unlock();
  230. }
  231. // check if null terminator exists
  232. int is_proper_string(char *s, int len)
  233. {
  234. while (len >= 0)
  235. {
  236. if (!*s)
  237. return 1;
  238. s++;
  239. len--;
  240. }
  241. return 0;
  242. }
  243. char *strnstr(char *s1, char *s2, int len)
  244. {
  245. int bFound = 0;
  246. int s2_len = strlen(s2);
  247. while (!bFound && len >= s2_len)
  248. {
  249. if (!memcmp(s1, s2, s2_len))
  250. bFound = 1;
  251. else
  252. {
  253. s1++;
  254. len--;
  255. }
  256. }
  257. if (bFound)
  258. return s1;
  259. else
  260. return NULL;
  261. }
  262. char *locate_double_null(char *pBuf, int len)
  263. {
  264. int i = 0;
  265. int bLastCharNull = 0;
  266. int bFound = 0;
  267. while (!bFound && i < len)
  268. {
  269. if (pBuf[i])
  270. bLastCharNull = 0;
  271. else
  272. {
  273. if (bLastCharNull)
  274. bFound = 1;
  275. else
  276. bLastCharNull = 1;
  277. }
  278. i++;
  279. }
  280. if (bFound)
  281. return &pBuf[i-1];
  282. else
  283. return NULL;
  284. }
  285. TITLE_SEARCH *locate_proper_title_search(char *buf_middle, int len)
  286. {
  287. TITLE_SEARCH *pTitleSearch;
  288. char *p;
  289. char *pBuf = buf_middle;
  290. // locate the bouble null character for the end of TITLE_SEARCH.idxArticle and TITLE_SEARCH.cZero
  291. // the last (most significant) byte of idxArticle should always be 0
  292. while (len > 0 && (p = locate_double_null(pBuf, len)))
  293. {
  294. len -= p - pBuf;
  295. while (len > 0 && !(*p))
  296. {
  297. p++;
  298. len--;
  299. }
  300. if (p - pBuf >= sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero))
  301. {
  302. pTitleSearch = (TITLE_SEARCH *)(p - (sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero)));
  303. if (is_proper_string(pTitleSearch->sTitleSearch, len))
  304. return pTitleSearch;
  305. }
  306. pBuf = p;
  307. }
  308. return NULL;
  309. }
  310. int fetch_search_result(long input_offset_fnd_start, long input_offset_fnd_end, int bInit)
  311. {
  312. int len;
  313. int rc;
  314. char buf_middle[sizeof(TITLE_SEARCH) * 2];
  315. long offset_middle;
  316. static TITLE_SEARCH *pTitleSearch;
  317. static int offsetNextTitleSearch = 0;
  318. static long offset_fnd_start = -1;
  319. static long offset_fnd_end = -1;
  320. if (bInit)
  321. {
  322. result_list->result_populated = 0;
  323. offset_fnd_start = input_offset_fnd_start;
  324. offset_fnd_end = input_offset_fnd_end;
  325. result_list->count = 0;
  326. offsetNextTitleSearch = 0;
  327. }
  328. if (result_list->result_populated || offset_fnd_start < 0)
  329. return 0;
  330. if (search_info[nCurrentWiki].offset_current != offset_fnd_start)
  331. {
  332. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  333. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  334. if (search_interrupted)
  335. {
  336. search_interrupted = 7;
  337. goto interrupted;
  338. }
  339. if (search_info[nCurrentWiki].buf_len < sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero) + 2) // at lease 2 chars for pTitleSearch->sTitleSearch
  340. {
  341. result_list->result_populated = 1;
  342. goto out;
  343. }
  344. }
  345. if (!result_list->result_populated)
  346. {
  347. pTitleSearch = (TITLE_SEARCH *)&search_info[nCurrentWiki].buf[offsetNextTitleSearch];
  348. if (offsetNextTitleSearch < search_info[nCurrentWiki].buf_len &&
  349. is_proper_string(pTitleSearch->sTitleSearch, search_info[nCurrentWiki].buf_len - offsetNextTitleSearch -
  350. sizeof(pTitleSearch->idxArticle) - sizeof(pTitleSearch->cZero)))
  351. {
  352. bigram_decode(result_list->title[result_list->count], pTitleSearch->sTitleSearch, MAX_TITLE_SEARCH);
  353. rc = search_string_cmp(result_list->title[result_list->count], search_string, search_str_len);
  354. #ifndef INCLUDED_FROM_KERNEL
  355. msg(MSG_INFO, "rc %d, [%s], [", rc, result_list->title[result_list->count]);
  356. int i;
  357. for (i=0;i<search_str_len;i++)
  358. msg(MSG_INFO, "%c", search_string[i]);
  359. msg(MSG_INFO, "]\n");
  360. #endif
  361. if (!rc) // match!
  362. {
  363. if (!result_list->count)
  364. {
  365. offset_fnd_start = offset_fnd_start + offsetNextTitleSearch;
  366. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  367. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  368. if (search_interrupted)
  369. {
  370. search_interrupted = 8;
  371. goto interrupted;
  372. }
  373. if (search_info[nCurrentWiki].buf_len < sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero) + 2) // at lease 2 chars for pTitleSearch->sTitleSearch
  374. {
  375. result_list->result_populated = 1;
  376. goto out;
  377. }
  378. offsetNextTitleSearch = 0;
  379. pTitleSearch = (TITLE_SEARCH *)&search_info[nCurrentWiki].buf[offsetNextTitleSearch];
  380. }
  381. memcpy((void *)&result_list->idx_article[result_list->count],
  382. (void *)&pTitleSearch->idxArticle, sizeof(long)); // use memcpy to avoid "Unaligned data access"
  383. result_list->offset_list[result_list->count] = offset_fnd_start + offsetNextTitleSearch;
  384. offsetNextTitleSearch += sizeof(pTitleSearch->idxArticle) + strlen(pTitleSearch->sTitleSearch) + 2;
  385. result_list->offset_next = offset_fnd_start + offsetNextTitleSearch;
  386. result_list->count++;
  387. if (result_list->count >= NUMBER_OF_FIRST_PAGE_RESULTS)
  388. {
  389. result_list->result_populated = 1;
  390. goto out;
  391. }
  392. }
  393. else if (rc < 0)
  394. {
  395. if (offset_fnd_end <= 0)
  396. {
  397. offsetNextTitleSearch += sizeof(pTitleSearch->idxArticle) + strlen(pTitleSearch->sTitleSearch) + 2;
  398. offset_fnd_start = offset_fnd_start + offsetNextTitleSearch;
  399. }
  400. else // binary search
  401. {
  402. offset_middle = offset_fnd_start + (offset_fnd_end - offset_fnd_start) / 2 - MAX_TITLE_SEARCH; // position to the middle of the range - max length of title
  403. if (offset_middle <= offset_fnd_start)
  404. offset_fnd_end = -1;
  405. else
  406. {
  407. len = copy_fnd_to_buf(offset_middle, buf_middle, sizeof(buf_middle));
  408. if (search_interrupted)
  409. {
  410. search_interrupted = 9;
  411. goto interrupted;
  412. }
  413. if (len >= sizeof(pTitleSearch->idxArticle) + sizeof(pTitleSearch->cZero) + 2) // at lease 2 chars for pTitleSearch->sTitleSearch
  414. {
  415. pTitleSearch = locate_proper_title_search(buf_middle, len);
  416. if (pTitleSearch)
  417. {
  418. char local_title_search[MAX_TITLE_SEARCH];
  419. offset_middle += (char *)pTitleSearch - buf_middle;
  420. bigram_decode(local_title_search, pTitleSearch->sTitleSearch, MAX_TITLE_SEARCH);
  421. rc = search_string_cmp(local_title_search, search_string, search_str_len);
  422. if (rc >= 0) // the first mactch will be in front or at offset_middle
  423. {
  424. offset_fnd_end = offset_middle;
  425. }
  426. else // the first mactch will be after offset_middle
  427. {
  428. offset_fnd_start = offset_middle;
  429. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  430. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  431. if (search_interrupted)
  432. {
  433. search_interrupted = 10;
  434. goto interrupted;
  435. }
  436. if (search_info[nCurrentWiki].buf_len <= 0)
  437. {
  438. result_list->result_populated = 1;
  439. goto out;
  440. }
  441. offsetNextTitleSearch = 0;
  442. }
  443. }
  444. }
  445. else
  446. offset_fnd_end = -1;
  447. }
  448. }
  449. offsetNextTitleSearch = 0;
  450. }
  451. else
  452. {
  453. result_list->result_populated = 1;
  454. goto out;
  455. }
  456. }
  457. else
  458. {
  459. offset_fnd_start = offset_fnd_start + offsetNextTitleSearch;
  460. search_info[nCurrentWiki].buf_len = copy_fnd_to_buf(offset_fnd_start, search_info[nCurrentWiki].buf, sizeof(search_info[nCurrentWiki].buf));
  461. search_info[nCurrentWiki].offset_current = offset_fnd_start;
  462. if (search_interrupted)
  463. {
  464. search_interrupted = 11;
  465. goto interrupted;
  466. }
  467. if (search_info[nCurrentWiki].buf_len <= 0)
  468. {
  469. result_list->result_populated = 1;
  470. goto out;
  471. }
  472. offsetNextTitleSearch = 0;
  473. }
  474. }
  475. out:
  476. if (result_list->result_populated)
  477. {
  478. if (!bInit) // just completed search result
  479. search_to_be_reloaded(SEARCH_TO_BE_RELOADED_SET, SEARCH_RELOAD_NORMAL);
  480. return 0;
  481. }
  482. else
  483. {
  484. return 1;
  485. }
  486. interrupted:
  487. return 1;
  488. }
  489. long get_prefix_index_table(int idx_prefix_index_table)
  490. {
  491. int idxBlock = idx_prefix_index_table / (SEARCH_CHR_COUNT * SEARCH_CHR_COUNT);
  492. if (!search_info[nCurrentWiki].b_prefix_index_block_loaded[idxBlock])
  493. {
  494. #ifdef INCLUDED_FROM_KERNEL
  495. if (wl_input_event_pending())
  496. search_interrupted = 1;
  497. #endif
  498. wl_seek(search_info[nCurrentWiki].fd_pfx,
  499. idxBlock * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * sizeof(uint32_t));
  500. wl_read(search_info[nCurrentWiki].fd_pfx,
  501. &(search_info[nCurrentWiki].prefix_index_table[idxBlock * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT]),
  502. SEARCH_CHR_COUNT * SEARCH_CHR_COUNT * sizeof(uint32_t));
  503. search_info[nCurrentWiki].b_prefix_index_block_loaded[idxBlock]++;
  504. }
  505. return search_info[nCurrentWiki].prefix_index_table[idx_prefix_index_table];
  506. }
  507. long get_search_result_start()
  508. {
  509. long offset_search_result_start = -1;
  510. int idx_prefix_index_table;
  511. char c1, c2, c3;
  512. int found = 0;
  513. int i;
  514. int lenCompared;
  515. int lenCopied;
  516. long offset;
  517. static int lenHashedSearchString = 0;
  518. static char sHashedSearchString[MAX_SEARCH_STRING_HASHED_LEN];
  519. static long offsetHasedSearchString[MAX_SEARCH_STRING_HASHED_LEN];
  520. if (search_str_len > 3)
  521. {
  522. // check the length of the hashed search string can be reused
  523. if (search_str_len > lenHashedSearchString)
  524. lenCompared = lenHashedSearchString;
  525. else
  526. lenCompared = search_str_len;
  527. lenHashedSearchString = 0;
  528. for (i = 0; i < lenCompared; i++)
  529. {
  530. if (sHashedSearchString[i] != search_string[i])
  531. lenHashedSearchString = i;
  532. }
  533. // Check if hashed
  534. if (lenHashedSearchString > 3)
  535. {
  536. if (search_str_len > lenHashedSearchString)
  537. {
  538. if (search_str_len > MAX_SEARCH_STRING_HASHED_LEN)
  539. lenCopied = MAX_SEARCH_STRING_HASHED_LEN - lenHashedSearchString;
  540. else
  541. lenCopied = search_str_len - lenHashedSearchString;
  542. memcpy(&sHashedSearchString[lenHashedSearchString], &search_string[lenHashedSearchString], lenCopied);
  543. // check the extended part first
  544. for (i = 3; i < lenHashedSearchString + lenCopied; i++)
  545. {
  546. if (i >= lenHashedSearchString)
  547. offsetHasedSearchString[i] = get_search_hash_offset_fnd(sHashedSearchString, i + 1);
  548. if (search_interrupted)
  549. {
  550. search_interrupted = 12;
  551. goto interrupted;
  552. }
  553. if (offsetHasedSearchString[i] &&
  554. (i >= MAX_SEARCH_STRING_ALL_HASHED_LEN || i == search_str_len - 1))
  555. {
  556. found = 1;
  557. offset_search_result_start = offsetHasedSearchString[i]; // use the longest hashed search string
  558. }
  559. }
  560. lenHashedSearchString += lenCopied;
  561. }
  562. if (!found) // not hashed at the extended part
  563. {
  564. for (i = 3; i < search_str_len && i < lenHashedSearchString; i++)
  565. {
  566. if (offsetHasedSearchString[i] &&
  567. (i >= MAX_SEARCH_STRING_ALL_HASHED_LEN || i == search_str_len - 1))
  568. {
  569. found = 1;
  570. offset_search_result_start = offsetHasedSearchString[i]; // use the longest hashed search string
  571. }
  572. else
  573. break;
  574. }
  575. }
  576. }
  577. else
  578. {
  579. if (search_str_len > MAX_SEARCH_STRING_HASHED_LEN)
  580. lenHashedSearchString = MAX_SEARCH_STRING_HASHED_LEN;
  581. else
  582. lenHashedSearchString = search_str_len;
  583. memcpy(sHashedSearchString, search_string, lenHashedSearchString);
  584. for (i = 3; i < lenHashedSearchString; i++)
  585. {
  586. offsetHasedSearchString[i] = get_search_hash_offset_fnd(sHashedSearchString, i + 1);
  587. if (search_interrupted)
  588. {
  589. search_interrupted = 13;
  590. goto interrupted;
  591. }
  592. if (offsetHasedSearchString[i] &&
  593. (i >= MAX_SEARCH_STRING_ALL_HASHED_LEN || i == search_str_len - 1))
  594. {
  595. found = 1;
  596. offset_search_result_start = offsetHasedSearchString[i]; // use the longest hashed search string
  597. }
  598. }
  599. }
  600. }
  601. if (!found && (3 >= search_str_len || search_str_len > MAX_SEARCH_STRING_ALL_HASHED_LEN))
  602. {
  603. switch(search_str_len)
  604. {
  605. case 1:
  606. c1 = search_string[0];
  607. c2 = '\0';
  608. c3 = '\0';
  609. break;
  610. case 2:
  611. c1 = search_string[0];
  612. c2 = search_string[1];
  613. c3 = '\0';
  614. break;
  615. default:
  616. c1 = search_string[0];
  617. c2 = search_string[1];
  618. c3 = search_string[2];
  619. break;
  620. }
  621. idx_prefix_index_table = bigram_char_idx(c1) * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT +
  622. bigram_char_idx(c2) * SEARCH_CHR_COUNT + bigram_char_idx(c3);
  623. if ((offset = get_prefix_index_table(idx_prefix_index_table)))
  624. {
  625. found = 1;
  626. offset_search_result_start = offset;
  627. }
  628. if (search_interrupted)
  629. {
  630. search_interrupted = 14;
  631. goto interrupted;
  632. }
  633. }
  634. interrupted:
  635. return offset_search_result_start;
  636. }
  637. int next_search_string(char *local_search_string, int len_local_search_string)
  638. {
  639. char *pSupportedChars = SUPPORTED_SEARCH_CHARS;
  640. int idxChar;
  641. if (len_local_search_string > MAX_SEARCH_STRING_HASHED_LEN)
  642. len_local_search_string = MAX_SEARCH_STRING_HASHED_LEN;
  643. if (len_local_search_string > 0)
  644. {
  645. idxChar = 0;
  646. while (idxChar < strlen(pSupportedChars) && pSupportedChars[idxChar] != local_search_string[len_local_search_string - 1])
  647. idxChar++;
  648. if (idxChar >= strlen(pSupportedChars) - 1)
  649. {
  650. len_local_search_string--;
  651. len_local_search_string = next_search_string(local_search_string, len_local_search_string);
  652. }
  653. else
  654. local_search_string[len_local_search_string - 1] = pSupportedChars[idxChar + 1];
  655. }
  656. return len_local_search_string;
  657. }
  658. long get_search_result_end()
  659. {
  660. long offset_search_result_end = -1;
  661. char local_search_string[MAX_TITLE_SEARCH];
  662. int len_local_search_string;
  663. int last_len_local_search_string;
  664. int found = 0;
  665. int idx_prefix_index_table;
  666. char c1, c2, c3;
  667. if (search_str_len > MAX_SEARCH_STRING_ALL_HASHED_LEN)
  668. len_local_search_string = MAX_SEARCH_STRING_ALL_HASHED_LEN;
  669. else
  670. len_local_search_string = search_str_len;
  671. memcpy(local_search_string, search_string, len_local_search_string);
  672. while (!found && len_local_search_string > 3)
  673. {
  674. last_len_local_search_string = len_local_search_string;
  675. len_local_search_string = next_search_string(local_search_string, len_local_search_string);
  676. if (!memcmp(search_string, local_search_string, len_local_search_string))
  677. found = 1; // returns -1 directly
  678. else
  679. {
  680. offset_search_result_end = get_search_hash_offset_fnd(local_search_string, len_local_search_string);
  681. if (search_interrupted)
  682. {
  683. search_interrupted = 15;
  684. goto interrupted;
  685. }
  686. if (offset_search_result_end > 0)
  687. {
  688. found = 1;
  689. }
  690. }
  691. len_local_search_string = last_len_local_search_string - 1;
  692. }
  693. if (!found)
  694. {
  695. if (len_local_search_string > 3)
  696. len_local_search_string = 3;
  697. while (!found && len_local_search_string > 0)
  698. {
  699. last_len_local_search_string = len_local_search_string;
  700. len_local_search_string = next_search_string(local_search_string, len_local_search_string);
  701. if (!memcmp(search_string, local_search_string, len_local_search_string))
  702. found = 1; // returns -1 directly
  703. else
  704. {
  705. switch(len_local_search_string)
  706. {
  707. case 1:
  708. c1 = local_search_string[0];
  709. c2 = '\0';
  710. c3 = '\0';
  711. break;
  712. case 2:
  713. c1 = local_search_string[0];
  714. c2 = local_search_string[1];
  715. c3 = '\0';
  716. break;
  717. default:
  718. c1 = local_search_string[0];
  719. c2 = local_search_string[1];
  720. c3 = local_search_string[2];
  721. break;
  722. }
  723. idx_prefix_index_table = bigram_char_idx(c1) * SEARCH_CHR_COUNT * SEARCH_CHR_COUNT +
  724. bigram_char_idx(c2) * SEARCH_CHR_COUNT + bigram_char_idx(c3);
  725. if (search_info[nCurrentWiki].prefix_index_table[idx_prefix_index_table])
  726. {
  727. found = 1;
  728. offset_search_result_end = search_info[nCurrentWiki].prefix_index_table[idx_prefix_index_table];
  729. }
  730. }
  731. len_local_search_string = last_len_local_search_string - 1;
  732. }
  733. }
  734. interrupted:
  735. return offset_search_result_end;
  736. }
  737. int search_populate_result()
  738. {
  739. int found = 0;
  740. long offset_search_result_start = -1;
  741. long offset_search_result_end = -1;
  742. search_string_changed = false;
  743. result_list->count = 0;
  744. result_list->result_populated = 0;
  745. result_list->cur_selected = -1;
  746. if (search_str_len > 0)
  747. {
  748. offset_search_result_start = get_search_result_start();
  749. if (search_interrupted)
  750. {
  751. search_interrupted = 16;
  752. goto interrupted;
  753. }
  754. if (offset_search_result_start > 0)
  755. {
  756. found = 1;
  757. offset_search_result_end = get_search_result_end();
  758. if (search_interrupted)
  759. {
  760. search_interrupted = 17;
  761. goto interrupted;
  762. }
  763. fetch_search_result(offset_search_result_start, offset_search_result_end, 1);
  764. if (search_interrupted)
  765. {
  766. search_interrupted = 18;
  767. goto interrupted;
  768. }
  769. }
  770. else
  771. {
  772. result_list->result_populated = 1;
  773. }
  774. }
  775. return found;
  776. interrupted:
  777. search_string_changed = true;
  778. return found;
  779. }
  780. void capitalize(char *in_str, char *out_str, int len)
  781. {
  782. //char cPrev = ' ';
  783. int i = 0;
  784. while (i < len)
  785. {
  786. //if (cPrev == ' ' && 'a' <= in_str[i] && in_str[i] <= 'z')
  787. if (i == 0 && 'a' <= in_str[i] && in_str[i] <= 'z')
  788. out_str[i] = in_str[i] - 32;
  789. else
  790. out_str[i] = in_str[i];
  791. //cPrev = in_str[i];
  792. i++;
  793. }
  794. out_str[i] = '\0';
  795. }
  796. void search_reload(int flag)
  797. {
  798. int screen_display_count = keyboard_get_mode() == KEYBOARD_NONE ?
  799. NUMBER_OF_FIRST_PAGE_RESULTS : NUMBER_OF_RESULTS_KEYBOARD;
  800. int y_pos,start_x_search=0;
  801. int end_y_pos;
  802. static int last_start_x_search=0;
  803. char *title;
  804. char temp_search_string[MAX_TITLE_SEARCH];
  805. static int bNoResultLastTime = 0;
  806. int keyboard_mode = keyboard_get_mode();
  807. char *pMsg;
  808. more_search_results = 0;
  809. guilib_fb_lock();
  810. if (keyboard_mode == KEYBOARD_NONE)
  811. {
  812. if (result_list->result_populated || flag == SEARCH_RELOAD_KEEP_REFRESH)
  813. {
  814. if (flag == SEARCH_RELOAD_KEEP_RESULT)
  815. guilib_clear_area(0, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT, 239, LCD_HEIGHT_LINES - 1);
  816. else
  817. guilib_clear();
  818. }
  819. else
  820. guilib_clear_area(start_x_search, 0, LCD_BUF_WIDTH_PIXELS, 30);
  821. }
  822. else
  823. {
  824. if (flag != SEARCH_RELOAD_NO_POPULATE)
  825. keyboard_key_reset_invert(KEYBOARD_RESET_INVERT_NOW, 0);
  826. if (flag == SEARCH_RELOAD_KEEP_REFRESH)
  827. guilib_clear_area(0, 0, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  828. if(search_string_changed_remove)
  829. {
  830. if(!search_str_len)
  831. start_x_search = 0;
  832. else
  833. start_x_search = search_string_pos[search_str_len];
  834. search_string_changed_remove = false;
  835. if (start_x_search < LCD_BUF_WIDTH_PIXELS)
  836. guilib_clear_area(start_x_search, 0, LCD_BUF_WIDTH_PIXELS, 30);
  837. //else
  838. //{
  839. // guilib_clear_area(0, 0, LCD_BUF_WIDTH_PIXELS, 30);
  840. //}
  841. }
  842. // if (result_list->result_populated)
  843. // guilib_clear_area(0, 35, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  844. }
  845. if (!search_str_len)
  846. {
  847. search_string_changed = 0;
  848. bNoResultLastTime = 0;
  849. result_list->count = 0;
  850. result_list->result_populated = 1;
  851. result_list->cur_selected = -1;
  852. pMsg = get_nls_text("type_a_word");
  853. render_string_and_clear(SUBTITLE_FONT_IDX, -1, 55, pMsg, strlen(pMsg), 0,
  854. 0, 35, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  855. keyboard_paint();
  856. goto out;
  857. }
  858. capitalize(search_string, temp_search_string, search_str_len);
  859. if (last_start_x_search >= LCD_BUF_WIDTH_PIXELS)
  860. guilib_clear_area(0, 0, LCD_BUF_WIDTH_PIXELS, 30);
  861. start_x_search = render_string_right(SEARCH_HEADING_FONT_IDX, LCD_LEFT_MARGIN, LCD_TOP_MARGIN, temp_search_string, strlen(temp_search_string), 0);
  862. if (last_start_x_search < LCD_BUF_WIDTH_PIXELS && start_x_search >= LCD_BUF_WIDTH_PIXELS)
  863. {
  864. guilib_clear_area(0, 0, LCD_BUF_WIDTH_PIXELS, 30);
  865. start_x_search = render_string_right(SEARCH_HEADING_FONT_IDX, LCD_LEFT_MARGIN, LCD_TOP_MARGIN, temp_search_string, strlen(temp_search_string), 0);
  866. }
  867. last_start_x_search = start_x_search;
  868. search_string_pos[search_str_len]=start_x_search;
  869. y_pos = RESULT_START;
  870. if (result_list->result_populated && flag != SEARCH_RELOAD_NO_POPULATE)
  871. {
  872. unsigned int i;
  873. unsigned int count = result_list->count < screen_display_count ?
  874. result_list->count : screen_display_count;
  875. if (!result_list->count) {
  876. if (!bNoResultLastTime)
  877. {
  878. guilib_clear_area(0, 35, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  879. pMsg = get_nls_text("no_results");
  880. render_string(SEARCH_LIST_FONT_IDX, -1, 55, pMsg, strlen(pMsg), 0);
  881. bNoResultLastTime = 1;
  882. }
  883. goto out;
  884. }
  885. bNoResultLastTime = 0;
  886. article_link_count = 0;
  887. for (i = 0; i < screen_display_count; i++)
  888. {
  889. end_y_pos = y_pos + RESULT_HEIGHT - 1;
  890. if (screen_display_count < NUMBER_OF_FIRST_PAGE_RESULTS && end_y_pos > LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1)
  891. end_y_pos = LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1;
  892. guilib_clear_area(0, y_pos, 239, end_y_pos);
  893. if (i < count)
  894. {
  895. if (keyboard_mode == KEYBOARD_NONE)
  896. {
  897. articleLink[article_link_count].start_xy = (unsigned long)((y_pos - 2) << 8); // consider the difference between render_string and draw_string
  898. articleLink[article_link_count].end_xy = (unsigned long)((LCD_BUF_WIDTH_PIXELS) | ((end_y_pos - 2) << 8));
  899. articleLink[article_link_count++].article_id = result_list->idx_article[i];
  900. }
  901. title = result_list->title[i];
  902. render_string(SEARCH_LIST_FONT_IDX, LCD_LEFT_MARGIN, y_pos, title, strlen(title), 0);
  903. }
  904. y_pos += RESULT_HEIGHT;
  905. if((y_pos+RESULT_HEIGHT)>guilib_framebuffer_height())
  906. break;
  907. }
  908. if (keyboard_mode == KEYBOARD_NONE)
  909. {
  910. if (result_list->count == NUMBER_OF_FIRST_PAGE_RESULTS)
  911. {
  912. more_search_results = 1;
  913. }
  914. }
  915. }
  916. out:
  917. guilib_fb_unlock();
  918. }
  919. void search_to_be_reloaded(int to_be_reloaded_flag, int reload_flag)
  920. {
  921. static bool to_be_reloaded = false;
  922. static int saved_reload_flag;
  923. switch (to_be_reloaded_flag)
  924. {
  925. case SEARCH_TO_BE_RELOADED_CLEAR:
  926. to_be_reloaded = false;
  927. break;
  928. case SEARCH_TO_BE_RELOADED_SET:
  929. if (reload_flag == SEARCH_RELOAD_NORMAL && keyboard_key_inverted())
  930. {
  931. to_be_reloaded = true;
  932. saved_reload_flag = reload_flag;
  933. }
  934. else
  935. {
  936. search_reload(reload_flag);
  937. to_be_reloaded = false;
  938. }
  939. break;
  940. case SEARCH_TO_BE_RELOADED_CHECK:
  941. if (to_be_reloaded && !keyboard_key_inverted())
  942. {
  943. search_reload(saved_reload_flag);
  944. to_be_reloaded = false;
  945. }
  946. break;
  947. default:
  948. break;
  949. }
  950. }
  951. void search_result_display()
  952. {
  953. int screen_display_count = keyboard_get_mode() == KEYBOARD_NONE ?
  954. NUMBER_OF_FIRST_PAGE_RESULTS : NUMBER_OF_RESULTS_KEYBOARD;
  955. int y_pos=0;
  956. char *title;
  957. char *pMsg;
  958. guilib_fb_lock();
  959. guilib_clear_area(0, RESULT_START, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  960. if (!search_str_len)
  961. {
  962. result_list->count = 0;
  963. result_list->cur_selected = -1;
  964. pMsg = get_nls_text("type_a_word");
  965. render_string_and_clear(SUBTITLE_FONT_IDX, -1, 55, pMsg, strlen(pMsg), 0,
  966. 0, 35, 239, LCD_HEIGHT_LINES - KEYBOARD_HEIGHT - 1);
  967. keyboard_paint();
  968. goto out;
  969. }
  970. y_pos = RESULT_START;
  971. if (result_list->result_populated && !result_list->count) {
  972. pMsg = get_nls_text("no_results");
  973. render_string(SEARCH_LIST_FONT_IDX, -1, 55, pMsg, strlen(pMsg), 0);
  974. goto out;
  975. }
  976. if (result_list->count) {
  977. unsigned int i;
  978. unsigned int count = result_list->count < screen_display_count ?
  979. result_list->count : screen_display_count;
  980. for (i = 0; i < count; i++) {
  981. title = result_list->title[i];
  982. render_string(SEARCH_LIST_FONT_IDX, LCD_LEFT_MARGIN, y_pos, title, strlen(title), 0);
  983. y_pos += RESULT_HEIGHT;
  984. if((y_pos+RESULT_HEIGHT)>guilib_framebuffer_height())
  985. break;
  986. }
  987. if (result_list->cur_selected >= screen_display_count)
  988. result_list->cur_selected = screen_display_count - 1;
  989. invert_selection(result_list->cur_selected, -1, RESULT_START, RESULT_HEIGHT);
  990. }
  991. out:
  992. guilib_fb_unlock();
  993. }
  994. int search_add_char(char c, unsigned long ev_time)
  995. {
  996. if((c == 0x20 && search_str_len>0 && search_string[search_str_len-1] == 0x20) ||
  997. (search_str_len >= MAX_TITLE_SEARCH - 2) ||
  998. (!search_str_len && c == 0x20))
  999. return -1;
  1000. if (!search_str_len) // clear type_a_word message
  1001. {
  1002. guilib_fb_lock();
  1003. guilib_clear_area(0, 55, 239, 80);
  1004. guilib_fb_unlock();
  1005. }
  1006. if ('A' <= c && c <= 'Z')
  1007. c += 32;
  1008. search_string[search_str_len++] = c;
  1009. search_string[search_str_len] = '\0';
  1010. time_search_string_changed = get_time_ticks();
  1011. search_string_changed = true;
  1012. return 0;
  1013. }
  1014. int check_search_string_change(void)
  1015. {
  1016. if (!search_string_changed)
  1017. return 0;
  1018. if (time_diff(get_time_ticks(), time_search_string_changed) > seconds_to_ticks(DELAYED_SEARCH_TIME))
  1019. {
  1020. search_interrupted = 0;
  1021. search_populate_result();
  1022. if (search_interrupted)
  1023. goto interrupted;
  1024. result_list->cur_selected = -1;
  1025. if (result_list->result_populated)
  1026. search_to_be_reloaded(SEARCH_TO_BE_RELOADED_SET, SEARCH_RELOAD_NORMAL);
  1027. }
  1028. return 1;
  1029. interrupted:
  1030. return 1;
  1031. }
  1032. void search_fetch()
  1033. {
  1034. search_populate_result();
  1035. result_list->cur_selected = -1;
  1036. search_string_changed = false;
  1037. }
  1038. /*
  1039. * return value - 0: remove ok, -1: no key to remove
  1040. */
  1041. int search_remove_char(int bPopulate, unsigned long ev_time)
  1042. {
  1043. if (search_str_len == 0)
  1044. return -1;
  1045. search_string[--search_str_len] = '\0';
  1046. if (bPopulate || !search_str_len)
  1047. {
  1048. search_populate_result();
  1049. search_string_changed_remove = true;
  1050. result_list->cur_selected = -1;
  1051. }
  1052. else
  1053. {
  1054. search_string_changed = true;
  1055. search_string_changed_remove = true;
  1056. time_search_string_changed = get_time_ticks();
  1057. }
  1058. return 0;
  1059. }
  1060. TITLE_SEARCH *locate_previous_title(char *buf, int len)
  1061. {
  1062. char *p;
  1063. int bFound = 0;
  1064. if (len > 2)
  1065. {
  1066. p = buf + len - 2;
  1067. len--;
  1068. while (!bFound && len > sizeof(long))
  1069. {
  1070. if (!*p) {
  1071. bFound = 1;
  1072. p -= sizeof(long);
  1073. }
  1074. else
  1075. {
  1076. p--;
  1077. len--;
  1078. }
  1079. }
  1080. if (bFound)
  1081. return (TITLE_SEARCH *)p;
  1082. }
  1083. return NULL;
  1084. }
  1085. int search_current_selection(void)
  1086. {
  1087. // const char* title;
  1088. // if (result_list->cur_selected >= result_list->count - result_list->first_item) {
  1089. // DP(DBG_SEARCH, ("O search_current_title() NO TITLE\n"));
  1090. // return NULL;
  1091. // }
  1092. // title = result_list_title(result_list->cur_selected+result_list->first_item);
  1093. // DP(DBG_SEARCH, ("O search_current_title() '%s'\n", title));
  1094. return result_list->cur_selected;
  1095. }
  1096. unsigned int search_result_count()
  1097. {
  1098. return result_list->count;
  1099. }
  1100. int clear_search_string()
  1101. {
  1102. if (search_str_len == 0)
  1103. return -1;
  1104. result_list->count = 0;
  1105. strcpy(search_string,"");
  1106. search_str_len = 0;
  1107. return 0;
  1108. }
  1109. int get_search_string_len()
  1110. {
  1111. return search_str_len;
  1112. }
  1113. int search_result_selected()
  1114. {
  1115. return result_list->cur_selected;
  1116. }
  1117. extern unsigned char * file_buffer;
  1118. extern int restricted_article;
  1119. extern int current_article_wiki_id;
  1120. #define HEAP_ALLOC(var,size) \
  1121. lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
  1122. //static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS);
  1123. char *compressed_buf = NULL;
  1124. int retrieve_article(long idx_article_with_wiki_id)
  1125. {
  1126. ARTICLE_PTR article_ptr;
  1127. int dat_file_id = 0;
  1128. unsigned int dat_article_len = 0;
  1129. char file_name[13];
  1130. unsigned int file_buffer_len = FILE_BUFFER_SIZE;
  1131. //lzo_uint lzo_file_buffer_len = FILE_BUFFER_SIZE;
  1132. int rc = 0;
  1133. ELzmaStatus status;
  1134. Byte propsEncoded[LZMA_PROPS_SIZE];
  1135. unsigned int propsSize;
  1136. long idx_article;
  1137. int nWikiIdx;
  1138. // int open_number = 0;
  1139. if (!compressed_buf)
  1140. compressed_buf = (char *)malloc_simple(MAX_COMPRESSED_ARTICLE, MEM_TAG_INDEX_M1);
  1141. //start:
  1142. current_article_wiki_id = (unsigned long)idx_article_with_wiki_id >> 24;
  1143. if (current_article_wiki_id == 0)
  1144. nWikiIdx = nCurrentWiki;
  1145. else
  1146. {
  1147. nWikiIdx = get_wiki_idx_from_id(current_article_wiki_id );
  1148. if (nWikiIdx >= 0)
  1149. load_prefix_index(nWikiIdx);
  1150. else
  1151. {
  1152. print_article_error();
  1153. return -1;
  1154. }
  1155. }
  1156. idx_article = idx_article_with_wiki_id & 0x00FFFFFF;
  1157. if (nWikiIdx >= 0 && compressed_buf && 0 < idx_article && idx_article <= search_info[nWikiIdx].max_article_idx) {
  1158. wl_seek(search_info[nWikiIdx].fd_idx, sizeof(uint32_t) + (idx_article - 1) * sizeof(article_ptr));
  1159. wl_read(search_info[nWikiIdx].fd_idx, &article_ptr, sizeof(article_ptr));
  1160. dat_file_id = ((article_ptr.file_id_compressed_len & 0x3FFFFFFF)>> 24);
  1161. dat_article_len = article_ptr.file_id_compressed_len & 0x00FFFFFF;
  1162. if (dat_article_len > 0)
  1163. {
  1164. if (search_info[nWikiIdx].fd_dat[dat_file_id] < 0)
  1165. {
  1166. sprintf(file_name, "wiki%d.dat", dat_file_id);
  1167. search_info[nWikiIdx].fd_dat[dat_file_id] = wl_open(get_wiki_file_path(nWikiIdx, file_name), WL_O_RDONLY);
  1168. }
  1169. if (search_info[nWikiIdx].fd_dat[dat_file_id] >= 0)
  1170. {
  1171. if (article_ptr.offset_dat & 0x80000000)
  1172. restricted_article = 1;
  1173. else
  1174. restricted_article = 0;
  1175. wl_seek(search_info[nWikiIdx].fd_dat[dat_file_id], article_ptr.offset_dat & 0x7FFFFFFF);
  1176. wl_read(search_info[nWikiIdx].fd_dat[dat_file_id], compressed_buf, dat_article_len);
  1177. propsSize = (unsigned int)compressed_buf[0];
  1178. memcpy(propsEncoded, compressed_buf + 1, LZMA_PROPS_SIZE);
  1179. dat_article_len -= LZMA_PROPS_SIZE + 1;
  1180. rc = (int)LzmaDecode(file_buffer, &file_buffer_len, compressed_buf + LZMA_PROPS_SIZE + 1, &dat_article_len,
  1181. propsEncoded, propsSize, LZMA_FINISH_ANY, &status, &g_Alloc);
  1182. if (rc == SZ_OK || rc == SZ_ERROR_INPUT_EOF) /* not sure why it generate SZ_ERROR_INPUT_EOF yet but result ok */
  1183. {
  1184. file_buffer[file_buffer_len] = '\0';
  1185. return 0;
  1186. }
  1187. }
  1188. }
  1189. }
  1190. print_article_error();
  1191. return -1;
  1192. }
  1193. void search_set_selection(int new_selection)
  1194. {
  1195. result_list->cur_selected = new_selection;
  1196. }
  1197. void search_open_article(int new_selection)
  1198. {
  1199. int list_idx;
  1200. list_idx = new_selection;
  1201. if (list_idx >= NUMBER_OF_FIRST_PAGE_RESULTS)
  1202. list_idx -= NUMBER_OF_FIRST_PAGE_RESULTS;
  1203. display_link_article(result_list->idx_article[list_idx]);
  1204. }
  1205. long find_closest_idx(long idx, char *title)
  1206. {
  1207. ARTICLE_PTR article_ptr;
  1208. TITLE_SEARCH title_search;
  1209. static int count = 0;
  1210. title[0] = '\0';
  1211. if (idx > search_info[nCurrentWiki].max_article_idx)
  1212. idx -= search_info[nCurrentWiki].max_article_idx;
  1213. wl_seek(search_info[nCurrentWiki].fd_idx, (idx - 1) * sizeof(ARTICLE_PTR) + sizeof(uint32_t));
  1214. wl_read(search_info[nCurrentWiki].fd_idx, &article_ptr, sizeof(article_ptr));
  1215. if (!article_ptr.file_id_compressed_len || !article_ptr.offset_fnd)
  1216. {
  1217. if (count < 10)
  1218. {
  1219. count++;
  1220. return find_closest_idx(idx + 1, title);
  1221. }
  1222. else
  1223. {
  1224. count = 0;
  1225. return 0;
  1226. }
  1227. }
  1228. else
  1229. {
  1230. count = 0;
  1231. copy_fnd_to_buf(article_ptr.offset_fnd, (char *)&title_search, sizeof(title_search));
  1232. bigram_decode(title, title_search.sTitleSearch, MAX_TITLE_SEARCH);
  1233. title[MAX_TITLE_SEARCH - 1] = '\0';
  1234. return idx;
  1235. }
  1236. }
  1237. extern int last_display_mode;
  1238. void random_article(void)
  1239. {
  1240. long idx_article;
  1241. char title[MAX_TITLE_SEARCH];
  1242. unsigned long clock_ticks;
  1243. #ifdef INCLUDED_FROM_KERNEL
  1244. clock_ticks = Tick_get();
  1245. #else
  1246. //clock_ticks = clock(); // this gets CPU time used, it not suitable for random
  1247. struct timeval t; // get elapsed time in us but do not care about overflow
  1248. gettimeofday(&t, NULL); // this more-or-less simulates what happens on WR hardware
  1249. clock_ticks = t.tv_sec * 1000000 + t.tv_usec;
  1250. #endif
  1251. idx_article = clock_ticks % search_info[nCurrentWiki].max_article_idx + 1;
  1252. idx_article = find_closest_idx(idx_article, title);
  1253. if (idx_article)
  1254. {
  1255. last_display_mode = DISPLAY_MODE_INDEX; // for history_save not to log the last article index
  1256. display_link_article(idx_article);
  1257. }
  1258. }