wiki_info.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /*
  2. * Copyright (c) 2009 Openmoko Inc.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <stddef.h>
  21. #include <stdlib.h>
  22. #include <errno.h>
  23. #include <malloc-simple.h>
  24. #include <file-io.h>
  25. #include "wikilib.h"
  26. #include "lcd_buf_draw.h"
  27. #include "wiki_info.h"
  28. #include "search.h"
  29. #include "search_hash.h"
  30. #include "msg.h"
  31. WIKI_LIST wiki_list[MAX_WIKIS] =
  32. {
  33. { 1, WIKI_CAT_ENCYCLOPAEDIA, "en", "enpedia"},
  34. { 2, WIKI_CAT_ENCYCLOPAEDIA, "es", "espedia"},
  35. { 3, WIKI_CAT_ENCYCLOPAEDIA, "fr", "frpedia"},
  36. { 4, WIKI_CAT_ENCYCLOPAEDIA, "de", "depedia"},
  37. { 5, WIKI_CAT_ENCYCLOPAEDIA, "nl", "nlpedia"},
  38. { 6, WIKI_CAT_ENCYCLOPAEDIA, "pt", "ptpedia"},
  39. { 7, WIKI_CAT_ENCYCLOPAEDIA, "fi", "fipedia"},
  40. { 8, WIKI_CAT_ENCYCLOPAEDIA, "ja", "japedia"},
  41. { 9, WIKI_CAT_ENCYCLOPAEDIA, "da", "dapedia"},
  42. {10, WIKI_CAT_ENCYCLOPAEDIA, "no", "nopedia"},
  43. {11, WIKI_CAT_ENCYCLOPAEDIA, "hu", "hupedia"},
  44. {12, WIKI_CAT_ENCYCLOPAEDIA, "ko", "kopedia"},
  45. {13, WIKI_CAT_ENCYCLOPAEDIA, "el", "elpedia"},
  46. {14, WIKI_CAT_ENCYCLOPAEDIA, "ru", "rupedia"},
  47. {15, WIKI_CAT_ENCYCLOPAEDIA, "zh", "zhpedia"},
  48. {16, WIKI_CAT_ENCYCLOPAEDIA, "cy", "cypedia"},
  49. };
  50. extern int search_interrupted;
  51. int nWikiCount = 0;
  52. int aWikiInfoIdx[MAX_WIKIS_PER_DEVICE]; // index to wiki_info[]
  53. char *aWikiNls[MAX_WIKIS_PER_DEVICE];
  54. long aWikiNlsLen[MAX_WIKIS_PER_DEVICE];
  55. int nCurrentWiki = -1; // index to aWikiInfoIdx[]
  56. bool bWikiIsJapanese = false;
  57. int rendered_wiki_selection_count = -1;
  58. int current_article_wiki_id = 0;
  59. WIKI_LICENSE_DRAW aWikiLicenseDraw[MAX_WIKIS_PER_DEVICE];
  60. char *pWikiIni = NULL;
  61. unsigned int lenWikiIni = 0;
  62. unsigned int sizeWikiIni = 0;
  63. extern int bShowPositioner;
  64. char *get_nls_key_value(char *key, char *key_pairs, long key_pairs_len);
  65. void init_wiki_info(void)
  66. {
  67. int i;
  68. int fd;
  69. char sFilePath[20];
  70. char *p;
  71. int nWikiId;
  72. for (i = 0; i < MAX_WIKIS && nWikiCount < MAX_WIKIS_PER_DEVICE; i++)
  73. {
  74. sprintf(sFilePath, "%s/wiki.idx", wiki_list[i].wiki_folder);
  75. fd = wl_open(sFilePath, WL_O_RDONLY);
  76. if (fd >= 0)
  77. {
  78. aWikiInfoIdx[nWikiCount] = i;
  79. nWikiCount++;
  80. wl_close(fd);
  81. }
  82. }
  83. if (nWikiCount > 0)
  84. {
  85. nCurrentWiki = 0;
  86. fd = wl_open("wiki.ini", WL_O_RDONLY);
  87. if (fd >= 0)
  88. {
  89. wl_fsize(fd, &lenWikiIni);
  90. sizeWikiIni = lenWikiIni + 16; // reserve space for wiki_id key pair
  91. pWikiIni = malloc_simple(sizeWikiIni, MEM_TAG_INDEX_M1);
  92. if (pWikiIni)
  93. {
  94. wl_read(fd, pWikiIni, lenWikiIni);
  95. wl_close(fd);
  96. pWikiIni[lenWikiIni] = '\0';
  97. p = pWikiIni;
  98. while (*p)
  99. {
  100. if (*p == '\r' || *p == '\n')
  101. *p = '\0';
  102. p++;
  103. }
  104. p = get_nls_key_value("positioner", pWikiIni, lenWikiIni);
  105. if (*p)
  106. bShowPositioner = atoi(p);
  107. p = get_nls_key_value("wiki_id", pWikiIni, lenWikiIni);
  108. if (*p)
  109. {
  110. nWikiId = atoi(p);
  111. if (nWikiId > 0)
  112. nCurrentWiki = get_wiki_idx_from_id(nWikiId);
  113. if (nCurrentWiki < 0)
  114. nCurrentWiki = 0;
  115. }
  116. else
  117. {
  118. lenWikiIni = 0; // if no wiki_id entry in wiki.ini, reset the content of wiki.ini
  119. nCurrentWiki = 0;
  120. }
  121. }
  122. }
  123. for (i = 0; i < nWikiCount; i++)
  124. {
  125. aWikiNlsLen[i] = -1;
  126. aWikiLicenseDraw[i].lines = 0;
  127. }
  128. if (!strcmp(wiki_list[aWikiInfoIdx[nCurrentWiki]].wiki_lang, "ja"))
  129. bWikiIsJapanese = true;
  130. else
  131. bWikiIsJapanese = false;
  132. }
  133. else
  134. fatal_error("No wiki found");
  135. }
  136. int get_wiki_idx_by_lang_link(char *lang_link_str)
  137. {
  138. int len;
  139. char *p, *q;
  140. int i;
  141. int current_wiki_cat = -1;
  142. p = strchr(lang_link_str, ':');
  143. q = strchr(lang_link_str, '#');
  144. if (!p || (q && q < p))
  145. p = q;
  146. if (p)
  147. {
  148. int wiki_idx = get_wiki_idx_from_id(current_article_wiki_id);
  149. current_wiki_cat = wiki_list[aWikiInfoIdx[wiki_idx]].wiki_cat;
  150. len = p - lang_link_str;
  151. for (i = 0; i < nWikiCount; i++)
  152. {
  153. if (current_wiki_cat == wiki_list[aWikiInfoIdx[i]].wiki_cat && !strncmp(lang_link_str, wiki_list[aWikiInfoIdx[i]].wiki_lang, len))
  154. return i;
  155. }
  156. }
  157. return -1;
  158. }
  159. bool wiki_lang_exist(char *lang_link_str)
  160. {
  161. if (get_wiki_idx_by_lang_link(lang_link_str) >= 0)
  162. return true;
  163. else
  164. return false;
  165. }
  166. bool wiki_is_japanese()
  167. {
  168. return bWikiIsJapanese;
  169. }
  170. uint32_t wiki_lang_link_search(char *lang_link_str)
  171. {
  172. uint32_t article_idx = 0;
  173. int nTempCurrentWiki = nCurrentWiki;
  174. char *p, *q;
  175. search_interrupted = 0;
  176. if ((nCurrentWiki = get_wiki_idx_by_lang_link(lang_link_str)) >= 0)
  177. {
  178. init_search_hash();
  179. p = strchr(lang_link_str, ':');
  180. q = strchr(lang_link_str, '#');
  181. if (!p || (q && q < p))
  182. p = q;
  183. if (p)
  184. {
  185. if (*p == '#') // actual title is different than title for search
  186. {
  187. q = strchr(p + 1, CHAR_LANGUAGE_LINK_TITLE_DELIMITER); // locate the actual title
  188. if (!q)
  189. q = p;
  190. }
  191. else
  192. q = p;
  193. article_idx = get_article_idx_by_title(p + 1, q + 1);
  194. if (article_idx)
  195. article_idx |= wiki_list[aWikiInfoIdx[nCurrentWiki]].wiki_id << 24;
  196. }
  197. }
  198. nCurrentWiki = nTempCurrentWiki;
  199. return article_idx;
  200. }
  201. char *get_wiki_file_path(int nWikiIdx, char *file_name)
  202. {
  203. static char sFilePath[32];
  204. sprintf(sFilePath, "%s/%s", wiki_list[aWikiInfoIdx[nWikiIdx]].wiki_folder, file_name);
  205. return sFilePath;
  206. }
  207. int get_wiki_count(void)
  208. {
  209. return nWikiCount;
  210. }
  211. int get_wiki_idx_from_id(int wiki_id)
  212. {
  213. int i;
  214. if (wiki_id <= 0)
  215. return nCurrentWiki;
  216. for (i = 0; i < nWikiCount; i++)
  217. {
  218. if (wiki_list[aWikiInfoIdx[i]].wiki_id == wiki_id)
  219. return i;
  220. }
  221. return -1;
  222. }
  223. int get_wiki_id_from_idx(int wiki_idx)
  224. {
  225. if (wiki_idx < nWikiCount)
  226. {
  227. return wiki_list[aWikiInfoIdx[wiki_idx]].wiki_id;
  228. }
  229. return 0;
  230. }
  231. char *get_nls_key_value(char *key, char *key_pairs, long key_pairs_len)
  232. {
  233. int i, j;
  234. int key_len = strlen(key);
  235. int bFound = 0;
  236. i = 0;
  237. while (i < key_pairs_len - key_len - 1 && !bFound)
  238. {
  239. for (j = 0; j < key_len; j++)
  240. {
  241. if (key[j] != key_pairs[i + j])
  242. break;
  243. }
  244. i += j;
  245. if (j == key_len && key_pairs[i] == '=')
  246. {
  247. bFound = 1;
  248. }
  249. else
  250. {
  251. while (key_pairs[i] != '\0')
  252. i++;
  253. while (i < key_pairs_len - key_len - 1 && key_pairs[i] == '\0')
  254. i++;
  255. }
  256. }
  257. if (bFound)
  258. return &key_pairs[i + 1];
  259. else
  260. return "";
  261. }
  262. char *get_nls_text(char *key)
  263. {
  264. int fd;
  265. unsigned int nSize;
  266. char *p;
  267. if (nCurrentWiki < 0)
  268. return "";
  269. else
  270. {
  271. if (aWikiNlsLen[nCurrentWiki] < 0)
  272. {
  273. fd = wl_open(get_wiki_file_path(nCurrentWiki, "wiki.nls"), WL_O_RDONLY);
  274. if (fd >= 0)
  275. {
  276. wl_fsize(fd, &nSize);
  277. aWikiNlsLen[nCurrentWiki] = nSize;
  278. aWikiNls[nCurrentWiki] = malloc_simple(nSize + 1, MEM_TAG_INDEX_M1);
  279. if (aWikiNls[nCurrentWiki])
  280. {
  281. wl_read(fd, aWikiNls[nCurrentWiki], nSize);
  282. wl_close(fd);
  283. aWikiNls[nCurrentWiki][nSize] = '\0';
  284. p = aWikiNls[nCurrentWiki];
  285. while (*p)
  286. {
  287. if (*p == '\r' || *p == '\n')
  288. *p = '\0';
  289. p++;
  290. }
  291. }
  292. else
  293. aWikiNlsLen[nCurrentWiki] = 0;
  294. }
  295. else
  296. {
  297. aWikiNlsLen[nCurrentWiki] = 0;
  298. }
  299. }
  300. if (aWikiNlsLen[nCurrentWiki] == 0)
  301. return "";
  302. return get_nls_key_value(key, aWikiNls[nCurrentWiki], aWikiNlsLen[nCurrentWiki]);
  303. }
  304. }
  305. char *get_lang_link_display_text(char *lang_link_str)
  306. {
  307. int nTempCurrentWiki = nCurrentWiki;
  308. static char lang_str[3];
  309. char *p = NULL;
  310. if ((nCurrentWiki = get_wiki_idx_by_lang_link(lang_link_str)) >= 0)
  311. {
  312. p = get_nls_text("lang_str");
  313. if (p[0] == '\0')
  314. p = NULL;
  315. }
  316. if (!p)
  317. {
  318. memcpy(lang_str, lang_link_str, 2);
  319. lang_str[2] = '\0';
  320. p = lang_str;
  321. }
  322. nCurrentWiki = nTempCurrentWiki;
  323. return p;
  324. }
  325. void wiki_selection(void)
  326. {
  327. rendered_wiki_selection_count = 0;
  328. render_wiki_selection_with_pcf();
  329. }
  330. char *get_wiki_name(int idx)
  331. {
  332. int nTempCurrentWiki = nCurrentWiki;
  333. char *pName;
  334. nCurrentWiki = idx;
  335. pName = get_nls_text("wiki_name");
  336. nCurrentWiki = nTempCurrentWiki;
  337. return pName;
  338. }
  339. void wiki_ini_insert_keypair(char *key, char *keyval)
  340. {
  341. char *p = get_nls_key_value(key, pWikiIni, lenWikiIni);
  342. if (*p)
  343. {
  344. if (strlen(p) < strlen(keyval))
  345. {
  346. int diff = strlen(keyval) - strlen(p);
  347. int move_size;
  348. if (lenWikiIni + diff < sizeWikiIni)
  349. {
  350. move_size = lenWikiIni - (p - pWikiIni);
  351. if (move_size > 0)
  352. memmove(p, p + diff, move_size);
  353. }
  354. }
  355. if (p + strlen(keyval) < pWikiIni + sizeWikiIni - 1)
  356. {
  357. memset(p, 0, strlen(keyval) + 1);
  358. memcpy(p, keyval, strlen(keyval));
  359. }
  360. }
  361. else if (lenWikiIni + strlen(key) + strlen(keyval) + 2 < sizeWikiIni)
  362. {
  363. if (lenWikiIni)
  364. pWikiIni[lenWikiIni++] = '\0'; // make sure the new key pair start with a new line
  365. memcpy(&pWikiIni[lenWikiIni], key, strlen(key));
  366. lenWikiIni += strlen(key);
  367. pWikiIni[lenWikiIni++] = '=';
  368. memcpy(&pWikiIni[lenWikiIni], keyval, strlen(keyval));
  369. lenWikiIni += strlen(keyval);
  370. pWikiIni[lenWikiIni] = '\0';
  371. }
  372. }
  373. void set_wiki(int idx)
  374. {
  375. int fd;
  376. char sWikiId[10];
  377. int i;
  378. char prev_c = 0;
  379. nCurrentWiki = idx;
  380. if (!strcmp(wiki_list[aWikiInfoIdx[nCurrentWiki]].wiki_lang, "ja"))
  381. bWikiIsJapanese = true;
  382. else
  383. bWikiIsJapanese = false;
  384. fd = wl_open("wiki.ini", WL_O_CREATE);
  385. if (fd >= 0)
  386. {
  387. sprintf(sWikiId, "%d", get_wiki_id_from_idx(nCurrentWiki));
  388. wiki_ini_insert_keypair("wiki_id", sWikiId);
  389. for (i = 0; i < lenWikiIni; i++)
  390. {
  391. if (pWikiIni[i] == '\0')
  392. {
  393. if (prev_c != '\0')
  394. wl_write(fd, "\n", 1);
  395. }
  396. else
  397. wl_write(fd, &pWikiIni[i], 1);
  398. prev_c = pWikiIni[i];
  399. }
  400. wl_close(fd);
  401. }
  402. }
  403. void nls_replace_text(char *replace_str, char *out_str)
  404. {
  405. if (!strcmp(replace_str, "title"))
  406. {
  407. extract_title_from_article(NULL, out_str);
  408. while (*out_str)
  409. {
  410. if (*out_str == ' ')
  411. *out_str = '_';
  412. out_str++;
  413. }
  414. }
  415. else
  416. {
  417. strcpy(out_str, replace_str);
  418. }
  419. }
  420. WIKI_LICENSE_DRAW *wiki_license_draw()
  421. {
  422. int wiki_idx = get_wiki_idx_from_id(current_article_wiki_id);
  423. int nTempCurrentWiki = nCurrentWiki;
  424. if (wiki_idx >= 0)
  425. nCurrentWiki = wiki_idx;
  426. // if (!aWikiLicenseDraw[wiki_idx].lines)
  427. {
  428. int y = 0;
  429. int x = 0;
  430. char draw_buf[MAX_LICENSE_TEXT_PIXEL_LINES * LCD_BUF_WIDTH_BYTES];
  431. unsigned char *pLicenseText = get_nls_text("license_text");
  432. char sLicenseTextSegment[MAX_LICENSE_TEXT_LEN];
  433. unsigned char *pLicenseTextSegment;
  434. int line_height = pcfFonts[LICENSE_TEXT_FONT - 1].Fmetrics.linespace;
  435. char str[256];
  436. unsigned char *p, *q;
  437. int bInLink = 0;
  438. int nLinkArticleId = 0;
  439. int width;
  440. int start_x, start_y, end_x, end_y;
  441. int i;
  442. aWikiLicenseDraw[wiki_idx].link_count = 0;
  443. memset(draw_buf, 0, sizeof(draw_buf));
  444. sLicenseTextSegment[0] = '\0';
  445. pLicenseTextSegment = sLicenseTextSegment;
  446. while (*pLicenseText && y < MAX_LICENSE_TEXT_PIXEL_LINES)
  447. {
  448. if (!*pLicenseTextSegment)
  449. {
  450. if (pLicenseText[0] == LICENSE_LINK_START)
  451. {
  452. bInLink = 1;
  453. nLinkArticleId++;
  454. pLicenseText++;
  455. if ((p = strchr(pLicenseText, LICENSE_LINK_END)))
  456. {
  457. memcpy(sLicenseTextSegment, pLicenseText, p - pLicenseText);
  458. sLicenseTextSegment[p - pLicenseText] = '\0';
  459. pLicenseText = p + 1;
  460. }
  461. else
  462. {
  463. strcpy(sLicenseTextSegment, pLicenseText);
  464. pLicenseText += strlen(pLicenseText);
  465. }
  466. }
  467. else if (pLicenseText[0] == NLS_TEXT_REPLACEMENT_START)
  468. {
  469. bInLink = 0;
  470. pLicenseText++;
  471. if ((p = strchr(pLicenseText, NLS_TEXT_REPLACEMENT_END)))
  472. {
  473. memcpy(str, pLicenseText, p - pLicenseText);
  474. str[p - pLicenseText] = '\0';
  475. pLicenseText = p + 1;
  476. }
  477. else
  478. {
  479. strcpy(str, pLicenseText);
  480. pLicenseText += strlen(pLicenseText);
  481. }
  482. nls_replace_text(str, sLicenseTextSegment);
  483. }
  484. else
  485. {
  486. bInLink = 0;
  487. p = strchr(pLicenseText, LICENSE_LINK_START);
  488. q = strchr(pLicenseText, NLS_TEXT_REPLACEMENT_START);
  489. if ((p && q && p > q) || (!p))
  490. p = q;
  491. if (p)
  492. {
  493. memcpy(sLicenseTextSegment, pLicenseText, p - pLicenseText);
  494. sLicenseTextSegment[p - pLicenseText] = '\0';
  495. pLicenseText = p;
  496. }
  497. else
  498. {
  499. strcpy(sLicenseTextSegment, pLicenseText);
  500. pLicenseText += strlen(pLicenseText);
  501. }
  502. }
  503. pLicenseTextSegment = sLicenseTextSegment;
  504. }
  505. while (*pLicenseTextSegment && y < MAX_LICENSE_TEXT_PIXEL_LINES)
  506. {
  507. if (!x)
  508. {
  509. while (*pLicenseTextSegment == ' ')
  510. pLicenseTextSegment++;
  511. }
  512. width = extract_str_fitting_width(&pLicenseTextSegment, str, LCD_BUF_WIDTH_PIXELS - x - LCD_LEFT_MARGIN, LICENSE_TEXT_FONT);
  513. p = str;
  514. buf_draw_UTF8_str_in_copy_buffer(draw_buf, &p, x, LCD_BUF_WIDTH_PIXELS,
  515. y, y + line_height - 1, LCD_LEFT_MARGIN, LICENSE_TEXT_FONT);
  516. if (bInLink && aWikiLicenseDraw[wiki_idx].link_count < MAX_LINKS_IN_LICENSE_TEXT)
  517. {
  518. start_x = x;
  519. start_y = y + 1;
  520. end_x = x + width;
  521. end_y = y + line_height;
  522. aWikiLicenseDraw[wiki_idx].links[aWikiLicenseDraw[wiki_idx].link_count].start_xy = (unsigned long)(start_x | (start_y << 8));
  523. aWikiLicenseDraw[wiki_idx].links[aWikiLicenseDraw[wiki_idx].link_count].end_xy = (unsigned long)(end_x | (end_y << 8));
  524. aWikiLicenseDraw[wiki_idx].links[aWikiLicenseDraw[wiki_idx].link_count++].article_id = nLinkArticleId;
  525. for(i = start_x + LCD_LEFT_MARGIN; i < end_x + LCD_LEFT_MARGIN; i++)
  526. {
  527. lcd_set_pixel(draw_buf, i, end_y + 1);
  528. }
  529. }
  530. if (*pLicenseTextSegment)
  531. {
  532. x = 0;
  533. y += line_height;
  534. }
  535. else
  536. x += width;
  537. }
  538. }
  539. if (x)
  540. y += line_height;
  541. y += SPACE_AFTER_LICENSE_TEXT;
  542. aWikiLicenseDraw[wiki_idx].lines = y;
  543. aWikiLicenseDraw[wiki_idx].buf = malloc_simple(y * LCD_BUF_WIDTH_BYTES, MEM_TAG_INDEX_M1);
  544. memcpy(aWikiLicenseDraw[wiki_idx].buf, draw_buf, y * LCD_BUF_WIDTH_BYTES);
  545. }
  546. nCurrentWiki = nTempCurrentWiki;
  547. return &aWikiLicenseDraw[wiki_idx];
  548. }