This week only. Pastebin PRO Accounts Christmas Special! Don't miss out!Want more features on Pastebin? Sign Up, it's FREE!
Guest

Untitled

By: a guest on Mar 21st, 2010  |  syntax: None  |  size: 47.10 KB  |  views: 158  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. Index: apps/lang/english.lang
  2. ===================================================================
  3. --- apps/lang/english.lang      (revision 25263)
  4. +++ apps/lang/english.lang      (working copy)
  5. @@ -11028,6 +11028,20 @@
  6.    </voice>
  7.  </phrase>
  8.  <phrase>
  9. +  id: LANG_DICTIONARIES
  10. +  desc: in the main menu
  11. +  user: core
  12. +  <source>
  13. +    *: "Dictionaries"
  14. +  </source>
  15. +  <dest>
  16. +    *: "Dictionaries"
  17. +  </dest>
  18. +  <voice>
  19. +    *: "Dictionaries"
  20. +  </voice>
  21. +</phrase>
  22. +<phrase>
  23.    id: VOICE_OF
  24.    desc: spoken only, as in 3/8 => 3 of 8
  25.    user: core
  26. Index: apps/plugins/dict2.c
  27. ===================================================================
  28. --- apps/plugins/dict2.c        (Revision 0)
  29. +++ apps/plugins/dict2.c        (Revision 0)
  30. @@ -0,0 +1,966 @@
  31. +/***************************************************************************
  32. + *             __________               __   ___.
  33. + *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
  34. + *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
  35. + *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  36. + *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  37. + *                     \/            \/     \/    \/            \/
  38. + * $Id: dict.c 14250 2007-08-08 23:32:35Z peter $
  39. + *
  40. + * Copyright (C) 2005 Tomas Salfischberger, 2006 Timo Horstschäfer
  41. + *
  42. + * All files in this archive are subject to the GNU General Public License.
  43. + * See the file COPYING in the source tree root for full license agreement.
  44. + *
  45. + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  46. + * KIND, either express or implied.
  47. + *
  48. + ****************************************************************************/
  49. +
  50. +#include "plugin.h"
  51. +#include "lib/pluginlib_actions.h"
  52. +#include "lib/configfile.h"
  53. +#include "lib/playback_control.h"
  54. +#include "lib/viewer.h"
  55. +
  56. +#include <ctype.h>
  57. +
  58. +PLUGIN_HEADER
  59. +
  60. +
  61. +#define CONFIG_VERSION  3
  62. +#define CACHE_VERSION   2
  63. +
  64. +//! Global dict variables
  65. +static struct dict_s {
  66. +    char path[255]; /**< Path of current dictionary */
  67. +    char name[255]; /**< Basename of current dictionary */
  68. +
  69. +    int DataLen;
  70. +
  71. +    int fCache;
  72. +    int fIndex;
  73. +    int fDict;
  74. +    //! Current description file (there may be more than one)
  75. +    int fDict_n;
  76. +
  77. +    //! Alphabet offset table
  78. +    int32_t charoft[26];
  79. +} Dict;
  80. +
  81. +#define DESC_BUFFER_ADD 512
  82. +
  83. +#define OFT_DIR ROCKBOX_DIR
  84. +
  85. +#define CONFIG_FILENAME "dict2.cfg"
  86. +#define CONFIG_ITEMS ( sizeof(Conf_data) / sizeof (struct configdata) )
  87. +struct conf_s {
  88. +    int max_list; /**< Max number of articles listed */
  89. +    int viewer_scroll; /**< Number of lines to scroll */
  90. +    int viewer_backlight;
  91. +    int viewer_shortcut;
  92. +} Conf;
  93. +
  94. +struct configdata Conf_data[] = {
  95. +    { TYPE_INT, 1, 50, { .int_p = &Conf.max_list }, "max_list", NULL },
  96. +    { TYPE_INT, 0, 4, { .int_p = &Conf.viewer_scroll }, "scroll", NULL },
  97. +    { TYPE_INT, 0, 2, { .int_p = &Conf.viewer_backlight }, "backlight", NULL },
  98. +    { TYPE_INT, 0, 2, { .int_p = &Conf.viewer_shortcut }, "shortcut", NULL },
  99. +};
  100. +
  101. +#define MAX_LIST_DEFAULT    50
  102. +
  103. +//! Malloc variables
  104. +static struct malloc_s {
  105. +    void *buf;
  106. +    size_t bufsize;
  107. +    size_t bufpos;
  108. +} Malloc;
  109. +
  110. +struct cache_h {
  111. +    char magic[9];
  112. +    uint16_t version;
  113. +    int32_t charoft[26];
  114. +};
  115. +
  116. +static struct cache_h Cache_h = {
  117. +    "DICT_OFT",
  118. +    CACHE_VERSION,
  119. +    { 0 },
  120. +};
  121. +
  122. +//! Length of word_str in stardict's DICT format
  123. +#define WORDLEN 256
  124. +
  125. +//! Rockbox filesize limit
  126. +#define MAX_FILESIZE 2147483647
  127. +
  128. +enum dict_action
  129. +{
  130. +    DICT_USB_CONNECTED = -4,
  131. +    DICT_NOT_FOUND = -2,
  132. +    DICT_QUIT = -3,
  133. +    DICT_ERROR = -1,
  134. +    DICT_OK,
  135. +};
  136. +
  137. +#define VIEWER_NEW (VIEWER_CUSTOM)
  138. +
  139. +/** \brief Data structure in .idx files
  140. + *
  141. + * Structure of .idx files:
  142. + * \code
  143. + *      char[]      name;   // variable length, zero-terminated, UTF-8
  144. + *      uint32_t    offset; // beginning of the article in the .dict file, Big Endian
  145. + *      uint32_t    size;   // article size, Big Endian
  146. + * \endcode
  147. + */
  148. +struct WordData_s
  149. +{
  150. +    uint32_t offset;
  151. +    uint32_t size;
  152. +};
  153. +
  154. +struct WordData
  155. +{
  156. +    uint64_t offset;
  157. +    uint32_t size;
  158. +};
  159. +
  160. +//! Internal structure for the result
  161. +struct DictEntry
  162. +{
  163. +    char name[WORDLEN];
  164. +    int32_t index;
  165. +    struct WordData data;
  166. +};
  167. +
  168. +#ifndef betoh64
  169. +
  170. +#ifdef ROCKBOX_LITTLE_ENDIAN
  171. +static inline uint64_t swap64(uint64_t value)
  172. +{
  173. +    uint64_t hi = swap32(value >> 32);
  174. +    uint64_t lo = swap32(value & 0xffffffff);
  175. +    return (lo << 32) | hi;
  176. +}
  177. +#define betoh64(x) swap64(x)
  178. +#else
  179. +#define betoh64(x) (x)
  180. +#endif
  181. +
  182. +#endif
  183. +
  184. +void str_toupper(const char *src, char *dst)
  185. +{
  186. +    while (*src)
  187. +        *dst++ = toupper(*src++);
  188. +    *dst = '\0';
  189. +}
  190. +
  191. +//! Display an error message
  192. +#define dict_error(...)  \
  193. +    DEBUGF(__VA_ARGS__); DEBUGF("\n"); \
  194. +    LOGF(__VA_ARGS__);   \
  195. +    rb->splashf(HZ, __VA_ARGS__);
  196. +    
  197. +
  198. +//! Initialize the plugin buffer
  199. +void dict_buf_init(void)
  200. +{
  201. +    Malloc.buf = rb->plugin_get_buffer((size_t *)&Malloc.bufsize);
  202. +    Malloc.bufpos = 0;
  203. +}
  204. +
  205. +/** \brief Stack-like malloc
  206. + *
  207. + * This malloc implementation only keeps track of how much memory is allocated
  208. + */
  209. +void *dict_malloc(size_t size)
  210. +{
  211. +    void *p;
  212. +    if (Malloc.bufpos+size <= Malloc.bufsize)
  213. +    {
  214. +        p = Malloc.buf + Malloc.bufpos;
  215. +        if ((int)p%4) { DEBUGF("\n%d %% 4 = %d\n", (int)p, (int)p%4); }
  216. +        Malloc.bufpos += size;
  217. +        return (void *)Malloc.buf + Malloc.bufpos - size;
  218. +    }
  219. +    else
  220. +    {
  221. +        dict_error("Out of Memory");
  222. +        return NULL;
  223. +    }
  224. +}
  225. +
  226. +size_t dict_malloc_align(void)
  227. +{
  228. +    size_t align = 4 - (((size_t)Malloc.buf + Malloc.bufpos) % 4);
  229. +    Malloc.bufpos += align;
  230. +    return align;
  231. +}
  232. +
  233. +/** \brief Stack-like free
  234. + *
  235. + * @param size Nnumber of bytes to free, 0 will free the whole buffer
  236. + */
  237. +void dict_free(size_t size)
  238. +{
  239. +    if (size == 0 || size > Malloc.bufpos)
  240. +        Malloc.bufpos = 0;
  241. +    else
  242. +        Malloc.bufpos -= size;
  243. +}
  244. +
  245. +//! Extract the path and name of the given filename
  246. +void dict_get_name(const char *name)
  247. +{
  248. +    char *slash, *dot;
  249. +    size_t n;
  250. +
  251. +    slash = rb->strrchr(name, '/');
  252. +    dot = rb->strrchr(slash+1, '.');
  253. +    
  254. +    /* get path */
  255. +    n = slash+1-name;
  256. +    rb->strlcpy(Dict.path, name, n);
  257. +    Dict.path[n] = '\0';
  258. +
  259. +    /* get filename without extension */
  260. +    n = dot-slash;
  261. +    rb->strlcpy(Dict.name, slash+1, n);
  262. +    Dict.name[n] = '\0';
  263. +
  264. +    /* get index type */
  265. +    if (rb->strcmp(dot, ".lidx") == 0)
  266. +        Dict.DataLen = sizeof(struct WordData);
  267. +    else
  268. +        Dict.DataLen = sizeof(struct WordData_s);
  269. +}
  270. +
  271. +//! Generates the cache file to the current dictionary
  272. +enum dict_action dict_create_cache(void)
  273. +{
  274. +    uint32_t offset;
  275. +    int len;
  276. +    char word[WORDLEN];
  277. +    enum dict_action ret = DICT_OK;
  278. +    int32_t count;
  279. +    char a_c, a_cur = 'a'-1;
  280. +
  281. +    int button;
  282. +    const struct button_mapping *plugin_contexts[] = {
  283. +        generic_actions,
  284. +    };
  285. +
  286. +    rb->splash(0, "Creating offset table... may take some minutes");
  287. +
  288. +    rb->memset(Cache_h.charoft, 0, sizeof(Cache_h.charoft));
  289. +    /* write dummy header */
  290. +    rb->write(Dict.fCache, &Cache_h, sizeof(struct cache_h));
  291. +
  292. +    offset = count = 0;
  293. +    while (ret == DICT_OK)
  294. +    {
  295. +        /* get name length */
  296. +        len = 0;
  297. +        while (rb->read(Dict.fIndex, &word[len], 1) == 1)
  298. +        {
  299. +            if (word[len++] == '\0' || len >= WORDLEN)
  300. +                break;
  301. +        }
  302. +        if (!len)
  303. +            break;
  304. +
  305. +        /* character offset table */
  306. +        a_c = tolower(word[0]);
  307. +        if (a_c > a_cur && a_c >= 'a' && a_c <= 'z')
  308. +        {
  309. +            LOGF("'%s' (%ld)", word, count);
  310. +            do
  311. +                Cache_h.charoft[++a_cur-'a'] = count;
  312. +            while (a_cur < a_c);
  313. +        }
  314. +
  315. +        /* write current position to file */
  316. +        rb->write(Dict.fCache, &offset, sizeof(uint32_t));
  317. +
  318. +        rb->lseek(Dict.fIndex, Dict.DataLen, SEEK_CUR);
  319. +        offset += Dict.DataLen + len;
  320. +        count++;
  321. +
  322. +        /* don't take over all control */
  323. +        button = pluginlib_getaction(TIMEOUT_NOBLOCK, plugin_contexts, 1);
  324. +        switch (button)
  325. +        {
  326. +            case PLA_QUIT:
  327. +                ret = DICT_ERROR;
  328. +                break;
  329. +            default:
  330. +                if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
  331. +                    ret = DICT_USB_CONNECTED;
  332. +                break;
  333. +        }
  334. +        rb->yield();
  335. +    }
  336. +
  337. +    /* Finish table */
  338. +    if (a_cur < 'z')
  339. +    {
  340. +        do
  341. +            Cache_h.charoft[++a_cur-'a'] = count;
  342. +        while (a_cur < 'z');
  343. +    }
  344. +
  345. +    /* write real header */
  346. +    rb->lseek(Dict.fCache, 0, SEEK_SET);
  347. +    rb->write(Dict.fCache, &Cache_h, sizeof(struct cache_h));
  348. +
  349. +    return ret;
  350. +}
  351. +
  352. +//! Closes all file descriptors
  353. +void dict_close(void)
  354. +{
  355. +    rb->close(Dict.fCache);
  356. +    rb->close(Dict.fIndex);
  357. +    rb->close(Dict.fDict);
  358. +
  359. +    Conf.viewer_scroll    = viewer_get_scroll();
  360. +    Conf.viewer_backlight = viewer_get_backlight();
  361. +    Conf.viewer_shortcut  = viewer_get_shortcut();
  362. +    configfile_save(CONFIG_FILENAME, Conf_data,
  363. +                    CONFIG_ITEMS, CONFIG_VERSION);
  364. +}
  365. +
  366. +enum dict_action dict_open(void)
  367. +{
  368. +    char fn[FAT_FILENAME_BYTES];
  369. +
  370. +    /* index file */
  371. +    if (Dict.DataLen == sizeof(struct WordData))
  372. +        rb->snprintf(fn, sizeof(fn), "%s/%s.lidx", Dict.path, Dict.name); // slash added
  373. +    else
  374. +        rb->snprintf(fn, sizeof(fn), "%s/%s.idx", Dict.path, Dict.name); // slash added
  375. +    Dict.fIndex = rb->open(fn, O_RDONLY);
  376. +    if (Dict.fIndex < 0)
  377. +    {
  378. +        dict_error("Failed to open index file: %s", fn);
  379. +        dict_close();
  380. +        return DICT_ERROR;
  381. +    }
  382. +
  383. +    /* cache file */
  384. +    rb->snprintf(fn, sizeof(fn), "%s/%s.oft", OFT_DIR, Dict.name); // slash added
  385. +    Dict.fCache = rb->open(fn, O_RDONLY);
  386. +    if (Dict.fCache >= 0)
  387. +    {
  388. +        /* check the cache file */
  389. +        struct cache_h header;
  390. +
  391. +        rb->read(Dict.fCache, &header, sizeof(struct cache_h));
  392. +        if (rb->strcmp(header.magic, Cache_h.magic) == 0 &&
  393. +            header.version == Cache_h.version)
  394. +        {
  395. +            rb->memcpy(Dict.charoft, header.charoft, sizeof(Dict.charoft));
  396. +            return PLUGIN_OK;
  397. +        }
  398. +
  399. +        dict_error("Cache file outdated");
  400. +
  401. +        rb->close(Dict.fCache);
  402. +        rb->remove(fn);
  403. +    }
  404. +
  405. +    /* incorrect cache file, create a new one */
  406. +    Dict.fCache = rb->creat(fn);
  407. +    if (Dict.fCache >= 0)
  408. +    {
  409. +        if (dict_create_cache() == DICT_OK)
  410. +        {
  411. +            rb->memcpy(Dict.charoft, Cache_h.charoft, sizeof(Dict.charoft));
  412. +
  413. +            /* reopen read-only */
  414. +            rb->close(Dict.fCache);
  415. +            Dict.fCache = rb->open(fn, O_RDONLY);
  416. +            return DICT_OK;
  417. +        }
  418. +        else
  419. +        {
  420. +            rb->close(Dict.fCache);
  421. +            rb->remove(fn);
  422. +        }
  423. +    }
  424. +
  425. +    dict_error("Failed to open cache file: %s", fn);
  426. +    return DICT_ERROR;
  427. +}
  428. +
  429. +/** \brief Initializes everything related to dict.
  430. + *
  431. + * @param filename Filename of the .idx file for the dictionary
  432. + */
  433. +enum dict_action dict_init(const char *file)
  434. +{
  435. +    /* malloc */
  436. +    dict_buf_init();
  437. +
  438. +    /* variables */
  439. +    Conf.viewer_scroll    = viewer_get_scroll();
  440. +    Conf.viewer_backlight = viewer_get_backlight();
  441. +    Conf.viewer_shortcut  = viewer_get_shortcut();
  442. +    Conf.max_list   = MAX_LIST_DEFAULT;
  443. +    Dict.fDict = Dict.fDict_n = -1;
  444. +
  445. +    /* configuration data */
  446. +    configfile_load(CONFIG_FILENAME, Conf_data,
  447. +                    CONFIG_ITEMS, CONFIG_VERSION);
  448. +
  449. +    /* dict name */
  450. +    dict_get_name(file);
  451. +
  452. +    /* files */
  453. +    return dict_open();
  454. +}
  455. +
  456. +/** \brief Returns offset for an entry in the idx file
  457. + *
  458. + * This function allows random access to the idx file
  459. + */
  460. +uint32_t dict_cache_offset(int32_t index)
  461. +{
  462. +    uint32_t offset;
  463. +
  464. +    /* read offset */
  465. +    rb->lseek(Dict.fCache, sizeof(uint32_t)*index + sizeof(struct cache_h),
  466. +              SEEK_SET);
  467. +    rb->read(Dict.fCache, &offset, sizeof(uint32_t));
  468. +
  469. +    return offset;
  470. +}
  471. +
  472. +//! Compare function, that represents the order in the .idx file
  473. +int dict_index_strcmp(const char *str1, const char *str2)
  474. +{
  475. +    int a;
  476. +
  477. +    a = rb->strcasecmp(str1, str2);
  478. +    if (!a)
  479. +    {
  480. +        return rb->strcmp(str1, str2);
  481. +    }
  482. +    
  483. +    return a;
  484. +}
  485. +
  486. +/** \brief Reads up to n bytes from current fIndex position until a zero occurs
  487. + *
  488. + * \return Number of bytes read.
  489. + */
  490. +int dict_index_gets(char *buf, int n)
  491. +{
  492. +    int i;
  493. +    for (i=0; i<n; i++)
  494. +    {
  495. +        if (!rb->read(Dict.fIndex, buf, 1))
  496. +            break;
  497. +        if (! *buf++)
  498. +        {
  499. +            i++;
  500. +            break;
  501. +        }
  502. +    }
  503. +    return i;
  504. +}
  505. +
  506. +/** \brief Reads up to n bytes from an entry in the idx file until a zero occurs
  507. + *
  508. + * @param index The index in idx t read from.
  509. + * \return Number of bytes read.
  510. + */
  511. +int dict_index_gets_from(int32_t index, char *buf, int n)
  512. +{
  513. +    rb->lseek(Dict.fIndex, dict_cache_offset(index), SEEK_SET);
  514. +    return dict_index_gets(buf, n);
  515. +}
  516. +
  517. +/** \brief Extracts all data about an entry in idx
  518. + *
  519. + * \return length of the article name
  520. + */
  521. +int dict_index_entry(int32_t index, struct DictEntry *out)
  522. +{
  523. +    int size;
  524. +    char buf[sizeof(struct WordData)];
  525. +
  526. +    out->index = index;
  527. +
  528. +    size = dict_index_gets_from(index, out->name, WORDLEN);
  529. +
  530. +    rb->read(Dict.fIndex, buf, Dict.DataLen);
  531. +
  532. +    /* convert to host endianess */
  533. +    if (Dict.DataLen == sizeof(struct WordData))
  534. +    {
  535. +        out->data.offset = betoh64( ((struct WordData *)buf)->offset );
  536. +        out->data.size   = betoh32( ((struct WordData *)buf)->size );
  537. +    }
  538. +    else
  539. +    {
  540. +        out->data.offset = betoh32( ((struct WordData_s *)buf)->offset );
  541. +        out->data.size   = betoh32( ((struct WordData_s *)buf)->size );
  542. +    }
  543. +
  544. +    return size;
  545. +}
  546. +
  547. +/** \brief Binary search function
  548. + *
  549. + * @return If nothing was found, the last probe is returned negative.
  550. + */
  551. +int32_t dict_index_binary_search(const char *search,
  552. +                                 int(*cmpf)(const char *, const char *))
  553. +{
  554. +    char word[WORDLEN];
  555. +    int32_t high, low, probe = 0;
  556. +    int cmp;
  557. +
  558. +    int count = 0;
  559. +
  560. +    int i = tolower(search[0]) - 'a';
  561. +    if (i < 0)
  562. +    {
  563. +        low = -1;
  564. +        high = Dict.charoft[0];
  565. +    }
  566. +    else if (i >= 25)
  567. +    {
  568. +        low = Dict.charoft[25];
  569. +        high = (rb->filesize(Dict.fCache) - sizeof (struct cache_h)) /
  570. +                sizeof(uint32_t);
  571. +    }
  572. +    else
  573. +    {
  574. +        low = Dict.charoft[i] - 1;
  575. +        high = Dict.charoft[i+1] + 1;
  576. +    }
  577. +
  578. +    while (high - low > 1)
  579. +    {
  580. +        count++;
  581. +        probe = (high + low) / 2;
  582. +
  583. +        dict_index_gets_from(probe, word, WORDLEN);
  584. +        LOGF("%ld: '%s'", probe, word);
  585. +
  586. +        /* jump according to the found word. */
  587. +        cmp = cmpf(search, word);
  588. +        if (cmp < 0)
  589. +            high = probe;
  590. +        else if (cmp > 0)
  591. +            low = probe;
  592. +        else
  593. +        {
  594. +            probe = -probe;
  595. +            break;
  596. +        }
  597. +    }
  598. +
  599. +    LOGF("probes: %d", count);
  600. +    return -probe;
  601. +}
  602. +
  603. +/** \brief Shows a selection menu for all articles starting with the given word
  604. + *
  605. + * The selections screen is only displayed, if there's more than one result.
  606. + */
  607. +int32_t dict_index_find_startingWith(const char *search)
  608. +{
  609. +    int32_t index;
  610. +    char buf[WORDLEN];
  611. +    int len, new_len, cmp, needmem;
  612. +    int buffer_size;
  613. +    int n = 0, sel = 0;
  614. +
  615. +    char **items;
  616. +    buffer_size = dict_malloc_align() + Conf.max_list * sizeof(char *);
  617. +    items = (char **) dict_malloc(buffer_size);
  618. +
  619. +    /* make uppercase to find lowest value */
  620. +    str_toupper(search, buf);
  621. +    index = dict_index_binary_search(buf, dict_index_strcmp);
  622. +    if (index < 0)
  623. +        index = -index;
  624. +
  625. +    rb->lseek(Dict.fIndex, dict_cache_offset(index), SEEK_SET);
  626. +
  627. +    /* find all words that start with the word */
  628. +    len = rb->strlen(search);
  629. +    while (n<Conf.max_list)
  630. +    {
  631. +        needmem = new_len = dict_index_gets(buf, WORDLEN);
  632. +        if (!new_len)
  633. +            break;
  634. +        if (needmem%4 > 0)
  635. +            needmem += 4 - needmem%4;
  636. +
  637. +        /* seek to next article name */
  638. +        rb->lseek(Dict.fIndex, Dict.DataLen, SEEK_CUR);
  639. +
  640. +        cmp = rb->strncasecmp(search, buf, len);
  641. +        if (cmp > 0)
  642. +        {
  643. +            index++;
  644. +            continue;
  645. +        }
  646. +        else if (cmp < 0)
  647. +            break;
  648. +
  649. +        items[n] = (char *)dict_malloc(needmem);
  650. +        if (items[n] == NULL)
  651. +            break;
  652. +        buffer_size += needmem;
  653. +
  654. +        rb->strlcpy(items[n], buf, new_len);
  655. +        DEBUGF("%s\n", buf);
  656. +
  657. +        n++;
  658. +    }
  659. +
  660. +    /* show the selection list */
  661. +    if (n > 1)
  662. +    {
  663. +        struct menu_callback_with_desc menu_ = {NULL,"Search Results", Icon_NOICON};
  664. +        struct menu_item_ex menu = {
  665. +            MT_RETURN_ID|MENU_HAS_DESC|MENU_ITEM_COUNT(n),
  666. +            {.strings = (const char **)items},
  667. +            {.callback_and_desc = &menu_}
  668. +        };
  669. +
  670. +        sel = rb->do_menu(&menu, &sel, NULL, true);
  671. +    }
  672. +
  673. +    dict_free(buffer_size);
  674. +
  675. +    if (n == 0)
  676. +        return DICT_NOT_FOUND;
  677. +
  678. +    switch (sel)
  679. +    {
  680. +        case MENU_ATTACHED_USB:
  681. +            return DICT_USB_CONNECTED;
  682. +        case MENU_SELECTED_EXIT: case GO_TO_PREVIOUS: case GO_TO_ROOT:
  683. +            return DICT_QUIT;
  684. +        default:
  685. +            return index + sel;
  686. +    }
  687. +}
  688. +
  689. +//! Wrapper to open the correct .desc file depending on the description offset
  690. +enum dict_action dict_desc_open(int n)
  691. +{
  692. +    char fn[FAT_FILENAME_BYTES];
  693. +
  694. +    if (n == Dict.fDict_n)
  695. +        return DICT_OK;
  696. +
  697. +    if (Dict.fDict > 0)
  698. +        rb->close(Dict.fDict);
  699. +
  700. +    if (n < 1)
  701. +        rb->snprintf(fn, sizeof(fn), "%s/%s.dict", Dict.path, Dict.name);  // slash added
  702. +    else
  703. +        rb->snprintf(fn, sizeof(fn), "%s/%s.dict.%d", Dict.path, Dict.name, n);  // slash added
  704. +
  705. +    Dict.fDict = rb->open(fn, O_RDONLY);
  706. +    if (Dict.fDict < 0)
  707. +    {
  708. +        dict_error("Failed to open description file: %s", fn);
  709. +        return DICT_ERROR;
  710. +    }
  711. +
  712. +    Dict.fDict_n = n;
  713. +
  714. +    return DICT_OK;
  715. +}
  716. +
  717. +/** \brief Reads the article description
  718. + *
  719. + * @param article The article to be read.
  720. + */
  721. +char *dict_desc_read(struct WordData *artl, char *buf)
  722. +{
  723. +    uint64_t offset = artl->offset;
  724. +    int len, n = offset/MAX_FILESIZE;
  725. +
  726. +    if (dict_desc_open(n) != DICT_OK)
  727. +        return NULL;
  728. +
  729. +    offset %= MAX_FILESIZE;
  730. +
  731. +    rb->lseek(Dict.fDict, offset, SEEK_SET);
  732. +    len = rb->read(Dict.fDict, buf, artl->size);
  733. +
  734. +    /* check if article is splitted between two files */
  735. +    if (offset > MAX_FILESIZE - artl->size)
  736. +    {
  737. +        rb->close(Dict.fDict);
  738. +        if (dict_desc_open(++n) != DICT_OK)
  739. +            return NULL;
  740. +
  741. +        rb->read(Dict.fDict, buf+len, artl->size-len);
  742. +    }
  743. +    buf[artl->size] = '\0';
  744. +
  745. +    /* And print it to debug. */
  746. +    DEBUGF("Description: %s\n", buf);
  747. +
  748. +    return buf;
  749. +}
  750. +
  751. +void dict_menu(void)
  752. +{
  753. +    bool quit = false;
  754. +    int selection = 0;
  755. +
  756. +    MENUITEM_STRINGLIST(menu, "DICT Menu", NULL,
  757. +        "Viewer control",
  758. +        "Playback control",
  759. +        "Max listed articles");
  760. +
  761. +    rb->button_clear_queue();
  762. +    rb->sleep(HZ/5);
  763. +    while (!quit) {
  764. +        selection = rb->do_menu(&menu, &selection, NULL, false);
  765. +        switch (selection)
  766. +        {
  767. +            case 0:
  768. +                quit = viewer_menu();
  769. +                break;
  770. +            case 1:
  771. +                quit = playback_control(NULL);
  772. +                break;
  773. +            case 2:
  774. +                quit = rb->set_int("Max listed articles", "", UNIT_INT,
  775. +                                   &Conf.max_list, NULL, 10, 10, 50, NULL);
  776. +                break;
  777. +            default:
  778. +                quit = true;
  779. +                break;
  780. +        }
  781. +    }
  782. +}
  783. +
  784. +void dict_viewer_callback(int button)
  785. +{
  786. +    switch (button)
  787. +    {
  788. +        case PLA_UP: case PLA_UP_REPEAT:
  789. +            viewer_up();
  790. +            break;
  791. +        case PLA_DOWN: case PLA_DOWN_REPEAT:
  792. +            viewer_down();
  793. +            break;
  794. +        case PLA_FIRE:
  795. +            viewer_search();
  796. +            break;
  797. +        case PLA_QUIT:
  798. +            viewer_exit(VIEWER_EXIT);
  799. +            break;
  800. +       case PLA_START:
  801. +           viewer_exit(VIEWER_NEW);
  802. +           break;
  803. +        case PLA_MENU:
  804. +            dict_menu();
  805. +            break;
  806. +#ifdef VIEWER_HAS_SHORTCUT
  807. +        default:
  808. +            if (rb->button_status() & BUTTON_VIEWER_SHORTCUT)
  809. +                viewer_shortcut();
  810. +            break;
  811. +#endif
  812. +
  813. +    }
  814. +}
  815. +
  816. +//! Parses #redirect from MediaWiki
  817. +int parse_mw_redirect(struct DictEntry *a, const char *desc)
  818. +{
  819. +    char *p;
  820. +    int len = 0;
  821. +    int32_t index;
  822. +    static const char redirect[] = "#redirect";
  823. +
  824. +    if ( rb->strncasecmp(desc, redirect, sizeof(redirect)-1) )
  825. +        return 0;
  826. +
  827. +    /* get destination article */
  828. +    p = rb->strchr(desc+sizeof(redirect)-1, '[') + 2;
  829. +    while (p[len] != ']' && p[len] != '#')
  830. +        len++;
  831. +
  832. +    rb->strlcpy(a->name, p, len);
  833. +    a->name[len] = '\0';
  834. +
  835. +    /* replace '_' with ' ' */
  836. +    for (p=a->name; *p; p++)
  837. +    {
  838. +        if (*p == '_')
  839. +            *p = ' ';
  840. +    }
  841. +
  842. +
  843. +    index = dict_index_binary_search(a->name, dict_index_strcmp);
  844. +    if (index < 0)
  845. +    {
  846. +        dict_error("Illegal redirect: %s", a->name);
  847. +        return 0;
  848. +    }
  849. +    dict_index_entry(index, a);
  850. +
  851. +    return 1;
  852. +}
  853. +
  854. +//! Dict main loop
  855. +enum dict_action dict_main(void)
  856. +{
  857. +    struct DictEntry result;
  858. +    char search[WORDLEN], old[WORDLEN];
  859. +    char *desc;
  860. +    int n, desc_size = 0, header_len = 0;
  861. +    bool new_search = false;
  862. +
  863. +    search[0] = '\0';
  864. +
  865. +    viewer_init(rb);
  866. +    viewer_set_scroll(Conf.viewer_scroll);
  867. +    viewer_set_backlight(Conf.viewer_backlight);
  868. +    viewer_set_shortcut(Conf.viewer_shortcut);
  869. +    viewer_set_callback(dict_viewer_callback);
  870. +
  871. +    while (true)
  872. +    {
  873. +#ifndef HAVE_FLASH_STORAGE
  874. +        /* keep the disk running */
  875. +        rb->storage_spindown(255);
  876. +#ifndef SIMULATOR
  877. +//        rb->ata_wakeup();
  878. +#endif
  879. +#endif /*HAVE_FLASH_STORAGE*/
  880. +
  881. +        rb->strcpy(old, search);
  882. +        rb->kbd_input(search, WORDLEN);
  883. +        /* exit if the search string is empty or the user didn't change it */
  884. +        if (!rb->strlen(search) ||
  885. +            (!new_search && !rb->strncmp(old, search, sizeof(old)) ))
  886. +        {
  887. +            return DICT_OK;
  888. +        }
  889. +        new_search = false;
  890. +
  891. +        result.index = dict_index_find_startingWith(search);
  892. +        switch (result.index)
  893. +        {
  894. +            case DICT_NOT_FOUND:
  895. +                dict_error("No results for \"%s\"", search);
  896. +                continue;
  897. +            case DICT_QUIT:
  898. +                continue;
  899. +            case DICT_USB_CONNECTED:
  900. +                return DICT_USB_CONNECTED;
  901. +        }
  902. +
  903. +        /* get result data */
  904. +        dict_index_entry(result.index, &result);
  905. +        do {
  906. +            if (desc_size > 0)
  907. +                dict_free(desc_size);
  908. +
  909. +            /* make title */
  910. +            header_len = rb->strlen(result.name) + 2;
  911. +            /* increase the buffer to put a title in front of the article */
  912. +            desc_size = result.data.size + header_len + 1;
  913. +            desc = (char *)dict_malloc(desc_size);
  914. +
  915. +            /* set desc pointer to beginning of the description */
  916. +            if (!dict_desc_read(&result.data, desc+header_len))
  917. +                return DICT_ERROR;
  918. +
  919. +        } while (parse_mw_redirect(&result, desc+header_len));
  920. +
  921. +        DEBUGF("\
  922. +result:\n\
  923. +    name:   %s\n\
  924. +    index:  %ld\n\
  925. +    offset: %llu (%llx)\n\
  926. +    size:   %lu\n",
  927. +                result.name, result.index, result.data.offset,
  928. +                result.data.offset, result.data.size);
  929. +
  930. +#ifndef HAVE_FLASH_STORAGE
  931. +        rb->storage_spindown(rb->global_settings->disk_spindown);
  932. +#endif
  933. +
  934. +        rb->snprintf(desc, header_len, "%s\n", result.name);
  935. +        desc[header_len-1] = '\n';
  936. +        desc[desc_size-1] = '\0';
  937. +
  938. +        desc_size += dict_malloc_align();
  939. +       n = viewer_set_text(dict_malloc(0), desc);
  940. +        dict_malloc(n);
  941. +        desc_size += n;
  942. +
  943. +        while (!new_search)
  944. +        {
  945. +            switch(viewer_run())
  946. +            {
  947. +                case VIEWER_NEW:
  948. +                    new_search = true;
  949. +                    continue;
  950. +                case VIEWER_ATTACHED_USB:
  951. +                    return DICT_USB_CONNECTED;
  952. +                default:
  953. +                    return DICT_OK;
  954. +            }
  955. +        }
  956. +
  957. +        dict_free(desc_size);
  958. +    }
  959. +}
  960. +
  961. +enum plugin_status plugin_start(const void* file)
  962. +{
  963. +    enum plugin_status ret;
  964. +
  965. +    switch (dict_init(file))
  966. +    {
  967. +        case DICT_ERROR:
  968. +            return PLUGIN_ERROR;
  969. +        case DICT_USB_CONNECTED:
  970. +            return PLUGIN_USB_CONNECTED;
  971. +        default:
  972. +            break;
  973. +    }
  974. +
  975. +    switch (dict_main())
  976. +    {
  977. +        case DICT_OK:
  978. +            ret = PLUGIN_OK;
  979. +            break;
  980. +        case DICT_USB_CONNECTED:
  981. +            ret = PLUGIN_USB_CONNECTED;
  982. +            break;
  983. +        default:
  984. +            ret = PLUGIN_ERROR;
  985. +            break;
  986. +    }
  987. +
  988. +#ifndef HAVE_FLASH_STORAGE
  989. +    /* reset disk setting */
  990. +    rb->storage_spindown(rb->global_settings->disk_spindown);
  991. +#endif
  992. +
  993. +    dict_close();
  994. +
  995. +    return ret;
  996. +}
  997. Index: apps/plugins/lib/viewer.c
  998. ===================================================================
  999. --- apps/plugins/lib/viewer.c   (Revision 0)
  1000. +++ apps/plugins/lib/viewer.c   (Revision 0)
  1001. @@ -0,0 +1,516 @@
  1002. +/***************************************************************************
  1003. +*             __________               __   ___.
  1004. +*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
  1005. +*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
  1006. +*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  1007. +*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  1008. +*                     \/            \/     \/    \/            \/
  1009. +* $Id: viewer.c 12008 2007-01-14 13:48:09Z dave $
  1010. +*
  1011. +* Copyright (C) 2007 Timo Horstschäfer
  1012. +*
  1013. +*
  1014. +* All files in this archive are subject to the GNU General Public License.
  1015. +* See the file COPYING in the source tree root for full license agreement.
  1016. +*
  1017. +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  1018. +* KIND, either express or implied.
  1019. +*
  1020. +****************************************************************************/
  1021. +
  1022. +#include "plugin.h"
  1023. +#include "pluginlib_actions.h"
  1024. +#include "viewer.h"
  1025. +
  1026. +#define VIEWER_LINE_BUF 255
  1027. +#define VIEWER_SCROLLBAR_WIDTH 4
  1028. +#define MAX_SEARCHLEN 255
  1029. +
  1030. +/** text structure */
  1031. +struct viewer_txt
  1032. +{
  1033. +    const char *p;             /**< Text pointer */
  1034. +    int        len;            /**< Text size */
  1035. +    int        pos;            /**< Current line number */
  1036. +
  1037. +    int        lines;          /**< Number of lines */
  1038. +    const char **line;         /**< Array of line pointers */
  1039. +
  1040. +    int        sections;       /**< Number of sections */
  1041. +    int        *section;       /**< Array of section lines */
  1042. +    const char **section_name; /**< Name of each section */
  1043. +};
  1044. +
  1045. +static void viewer_default_callback(int button);
  1046. +
  1047. +static struct viewer_txt *txt;
  1048. +
  1049. +/** Display and character dimensions*/
  1050. +static int                  cols, rows;
  1051. +#ifdef HAVE_REMOTE_LCD
  1052. +static int                  remote_cols, remote_rows;
  1053. +#endif
  1054. +#ifdef HAVE_LCD_BITMAP
  1055. +static int row_height;
  1056. +#endif
  1057. +
  1058. +static char                 search[255];
  1059. +static bool                 quit;
  1060. +static int                  retval;
  1061. +
  1062. +/* Customization (also default settings) */
  1063. +void                        (*viewer_shortcut)(void)
  1064. +                                      = (void *)viewer_menu_search;
  1065. +static void                 (*viewer_callback)(int button)
  1066. +                                      = viewer_default_callback;
  1067. +static int                  scroll    = 0;
  1068. +static int                  backlight = 2;
  1069. +static int                  shortcut  = 0;
  1070. +
  1071. +inline int viewer(const struct plugin_api *newrb, const char *text)
  1072. +{
  1073. +    static long buffer[128];
  1074. +    viewer_init(newrb);
  1075. +    viewer_set_text(buffer, text);
  1076. +    return viewer_run();
  1077. +}
  1078. +
  1079. +/** \brief Returns a pointer to the last character of a line.
  1080. + * @param s Pointer to the actual line.
  1081. + */
  1082. +static char *viewer_endl(const char *s, int width)
  1083. +{
  1084. +    const char *space = NULL;
  1085. +
  1086. +    while (true)
  1087. +    {
  1088. +        if (*s == '\n' || *s == '\0')
  1089. +            return (char *)s;
  1090. +        if (*s == ' ')
  1091. +            space = s;
  1092. +        if (!--width)
  1093. +            break;
  1094. +        s += rb->utf8seek(s, 1);
  1095. +    }
  1096. +
  1097. +    return (char *) ( (space) ? space : s );
  1098. +}
  1099. +
  1100. +/** \brief Draws text on the display.
  1101. + *
  1102. + * Handles newline characters and line wrapping.
  1103. + */
  1104. +static void viewer_draw(const char *s)
  1105. +{
  1106. +    const char *p, *eol;
  1107. +    int line, len;
  1108. +    char buf[VIEWER_LINE_BUF];
  1109. +       int left_margin=0;
  1110. +
  1111. +    rb->lcd_clear_display();
  1112. +
  1113. +    /* Some Rockbox function restore the backlight settings; reset it */
  1114. +    viewer_set_backlight(backlight);
  1115. +
  1116. +#ifdef HAVE_LCD_BITMAP
  1117. +    if (txt->lines > rows)
  1118. +    {
  1119. +        rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN], 0, 0,
  1120. +                                VIEWER_SCROLLBAR_WIDTH-1, LCD_HEIGHT,
  1121. +                                txt->lines+rows-1, txt->pos, txt->pos+rows,
  1122. +                                VERTICAL);
  1123. +        left_margin=VIEWER_SCROLLBAR_WIDTH;
  1124. +    }
  1125. +#endif
  1126. +
  1127. +    /* draw main display */
  1128. +    for (p=s, line=0; line<rows; line++)
  1129. +    {
  1130. +        eol = viewer_endl(p, cols);
  1131. +
  1132. +        len = eol-p;
  1133. +        // if (*eol != '\n' && *eol != '\0') //removed to fix missing last character at eol
  1134. +            len++;
  1135. +
  1136. +        rb->strlcpy(buf, p, len);
  1137. +        buf[len] = '\0';
  1138. +#ifdef HAVE_LCD_BITMAP
  1139. +        rb->lcd_putsxy(left_margin, line*row_height, buf);
  1140. +#else
  1141. +               rb->lcd_puts(0,line,buf);
  1142. +#endif
  1143. +        if (*eol)
  1144. +            p = eol + rb->utf8seek(eol, 1);
  1145. +        else
  1146. +            break;
  1147. +    }
  1148. +
  1149. +    rb->lcd_update();
  1150. +
  1151. +#ifdef HAVE_REMOTE_LCD
  1152. +    rb->lcd_remote_clear_display();
  1153. +
  1154. +    /* draw remote */
  1155. +    for (p=s, line=0; line<remote_rows; line++)
  1156. +    {
  1157. +        eol = viewer_endl(p, remote_cols);
  1158. +
  1159. +        len = eol-p;
  1160. +        if (*eol != '\n' && *eol != '\0')
  1161. +            len++;
  1162. +
  1163. +        rb->strlcpy(buf, p, len);
  1164. +        buf[len] = '\0';
  1165. +
  1166. +        rb->lcd_remote_puts(0, line, buf);
  1167. +
  1168. +        if (*eol)
  1169. +            p = eol + rb->utf8seek(eol, 1);
  1170. +        else
  1171. +            break;
  1172. +    }
  1173. +
  1174. +    rb->lcd_remote_update();
  1175. +#endif
  1176. +}
  1177. +
  1178. +static void viewer_default_callback(int button)
  1179. +{
  1180. +    switch (button)
  1181. +    {
  1182. +        case PLA_UP: case PLA_UP_REPEAT:
  1183. +            viewer_up();
  1184. +            break;
  1185. +        case PLA_DOWN: case PLA_DOWN_REPEAT:
  1186. +            viewer_down();
  1187. +            break;
  1188. +        case PLA_FIRE:
  1189. +            viewer_search();
  1190. +            break;
  1191. +        case PLA_QUIT:
  1192. +            viewer_exit(VIEWER_EXIT);
  1193. +            break;
  1194. +        case PLA_MENU:
  1195. +            viewer_menu();
  1196. +            break;
  1197. +#ifdef VIEWER_HAS_SHORTCUT
  1198. +        default:
  1199. +            /* Could need some better way to access the REC-button */
  1200. +            if (rb->button_status() & BUTTON_VIEWER_SHORTCUT)
  1201. +                viewer_shortcut();
  1202. +            break;
  1203. +#endif
  1204. +    }
  1205. +}
  1206. +
  1207. +void viewer_init(const struct plugin_api *newrb)
  1208. +{
  1209. +    rb = newrb;
  1210. +
  1211. +#ifdef HAVE_LCD_BITMAP
  1212. +    rb->lcd_getstringsize("o", &cols, &row_height);
  1213. +# ifdef HAVE_REMOTE_LCD
  1214. +    remote_cols = LCD_REMOTE_WIDTH / cols;
  1215. +    remote_rows = LCD_REMOTE_HEIGHT / row_height;
  1216. +# endif
  1217. +    cols = (LCD_WIDTH-VIEWER_SCROLLBAR_WIDTH) / cols;
  1218. +    rows = LCD_HEIGHT / row_height;
  1219. +#else
  1220. +    cols = 11;
  1221. +    rows = 2;
  1222. +#endif
  1223. +
  1224. +    viewer_callback = viewer_default_callback;
  1225. +    scroll = 0;
  1226. +}
  1227. +
  1228. +int viewer_run(void)
  1229. +{
  1230. +    int button;
  1231. +    const struct button_mapping *viewer_contexts[] = {
  1232. +        generic_directions,
  1233. +        generic_actions,
  1234. +    };
  1235. +
  1236. +    viewer_redraw();
  1237. +
  1238. +    quit = false;
  1239. +    retval = VIEWER_EXIT;
  1240. +
  1241. +    while (!quit)
  1242. +    {
  1243. +        rb->yield();
  1244. +        button = pluginlib_getaction(HZ, viewer_contexts, 2);
  1245. +
  1246. +        if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
  1247. +            viewer_exit(VIEWER_ATTACHED_USB);
  1248. +
  1249. +        viewer_callback(button);
  1250. +        viewer_redraw();
  1251. +    }
  1252. +
  1253. +    /* restore backlight setting */
  1254. +    rb->backlight_set_timeout(rb->global_settings->backlight_timeout);
  1255. +
  1256. +    return retval;
  1257. +}
  1258. +
  1259. +int viewer_line(const char *p)
  1260. +{
  1261. +    int line;
  1262. +
  1263. +    for (line=0; line<txt->lines; line++)
  1264. +    {
  1265. +        if (p < txt->line[line])
  1266. +            break;
  1267. +    }
  1268. +
  1269. +    return line ? line-1 : line;
  1270. +}
  1271. +
  1272. +int viewer_set_text(void *buffer, const char *text)
  1273. +{
  1274. +    size_t buffer_used;
  1275. +    const char *p;
  1276. +
  1277. +    txt = buffer;
  1278. +    buffer_used = sizeof(struct viewer_txt);
  1279. +
  1280. +    txt->p = text;
  1281. +    txt->len = rb->strlen(txt->p);
  1282. +    txt->pos = 0;
  1283. +
  1284. +    /* Create an array with the pointers to the beginning of each line */
  1285. +    txt->lines = 0;
  1286. +    txt->line = buffer + buffer_used;
  1287. +    for (p = txt->p; *p;)
  1288. +    {
  1289. +        txt->line[txt->lines++] = p;
  1290. +        p = viewer_endl(p, cols);
  1291. +        if (*p)
  1292. +            p += rb->utf8seek(p, 1);
  1293. +    }
  1294. +    buffer_used += txt->lines * sizeof txt->line;
  1295. +    return buffer_used;
  1296. +}
  1297. +
  1298. +void viewer_set_callback(void (*newcallback)(int button))
  1299. +{
  1300. +    viewer_callback = newcallback;
  1301. +}
  1302. +
  1303. +void viewer_set_scroll(int newscroll)
  1304. +{
  1305. +    scroll = newscroll < 0 ? 0 : newscroll;
  1306. +}
  1307. +
  1308. +void viewer_set_pos(int line)
  1309. +{
  1310. +    if (line < 0)
  1311. +        txt->pos = txt->lines-1 - (line%txt->lines);
  1312. +    else if (line >= txt->lines)
  1313. +        txt->pos = txt->lines-1;
  1314. +    else
  1315. +        txt->pos = line;
  1316. +}
  1317. +
  1318. +void viewer_set_backlight(int newbacklight)
  1319. +{
  1320. +    backlight = (newbacklight > 2) ? 2 : newbacklight;
  1321. +    switch (backlight)
  1322. +    {
  1323. +        case 0:
  1324. +            rb->backlight_set_timeout(0);
  1325. +            break;
  1326. +        case 1:
  1327. +            rb->backlight_set_timeout(1);
  1328. +            break;
  1329. +        default:
  1330. +            rb->backlight_set_timeout(rb->global_settings->backlight_timeout);
  1331. +            break;
  1332. +    }
  1333. +}
  1334. +
  1335. +void viewer_set_shortcut(int shortcutindex)
  1336. +{
  1337. +    switch (shortcutindex)
  1338. +    {
  1339. +        default:
  1340. +        case 0:
  1341. +            shortcutindex = 0;
  1342. +            viewer_shortcut = (void *)viewer_menu_search;
  1343. +            break;
  1344. +        case 1:
  1345. +            viewer_shortcut = (void *)viewer_menu_backlight;
  1346. +            break;
  1347. +        case 2:
  1348. +            viewer_shortcut = (void *)viewer_menu_scroll;
  1349. +            break;
  1350. +    }
  1351. +    shortcut = shortcutindex;
  1352. +}
  1353. +
  1354. +int viewer_get_scroll(void)
  1355. +{
  1356. +    return scroll;
  1357. +}
  1358. +
  1359. +int viewer_get_pos(void)
  1360. +{
  1361. +    return txt->pos;
  1362. +}
  1363. +
  1364. +int viewer_get_backlight(void)
  1365. +{
  1366. +    return backlight;
  1367. +}
  1368. +
  1369. +int viewer_get_shortcut(void)
  1370. +{
  1371. +    return shortcut;
  1372. +}
  1373. +
  1374. +void viewer_up(void)
  1375. +{
  1376. +    int n = scroll ? scroll : rows;
  1377. +    txt->pos = (txt->pos < n) ? 0 : txt->pos - n;
  1378. +}
  1379. +
  1380. +void viewer_down(void)
  1381. +{
  1382. +    int n = scroll ? scroll : rows;
  1383. +
  1384. +#ifdef HAVE_REMOTE_LCD
  1385. +    if (txt->lines < remote_rows)
  1386. +#else
  1387. +    if (txt->lines < rows)
  1388. +#endif
  1389. +        return;
  1390. +
  1391. +    if (txt->pos+n >= txt->lines)
  1392. +        txt->pos = txt->lines-1;
  1393. +    else
  1394. +        txt->pos += n;
  1395. +}
  1396. +
  1397. +void viewer_redraw(void)
  1398. +{
  1399. +    viewer_draw(txt->line[txt->pos]);
  1400. +}
  1401. +
  1402. +bool viewer_search(void)
  1403. +{
  1404. +    int line;
  1405. +    const char *p;
  1406. +    size_t n;
  1407. +
  1408. +    if (!search[0])
  1409. +        return false;
  1410. +  
  1411. +    n = rb->strlen(search);
  1412. +    line = (txt->pos == txt->lines-1) ? 0 : txt->pos+1;
  1413. +    p = txt->line[line];
  1414. +    while (true)
  1415. +    {
  1416. +        if (!*p)
  1417. +            p = txt->p;
  1418. +
  1419. +        /* just a slow linear search */
  1420. +        if (rb->strncasecmp(search, p, n) == 0)
  1421. +            break;
  1422. +
  1423. +        if (p == txt->line[txt->pos])
  1424. +            return false;
  1425. +
  1426. +        p += rb->utf8seek(p, 1);
  1427. +    }
  1428. +
  1429. +    viewer_set_pos(viewer_line(p));
  1430. +    return true;
  1431. +}
  1432. +
  1433. +void viewer_exit(int newretval)
  1434. +{
  1435. +    retval = newretval;
  1436. +    quit = true;
  1437. +}
  1438. +
  1439. +/* Viewer menu */
  1440. +bool viewer_menu_search(void)
  1441. +{
  1442. +    rb->kbd_input(search, sizeof(search));
  1443. +    if (viewer_search())
  1444. +        return true;
  1445. +    else
  1446. +    {
  1447. +        rb->splashf(HZ, "\"%s\" not found", search);
  1448. +        return false;
  1449. +    }
  1450. +}
  1451. +
  1452. +bool viewer_menu_scroll(void)
  1453. +{
  1454. +    static const struct opt_items scroll_menu[] = {
  1455. +        { "Full page", -1 },
  1456. +        { "1 line", -1 },
  1457. +        { "2 lines", -1 },
  1458. +        { "3 lines", -1 },
  1459. +        { "4 lines", -1 },
  1460. +        { "5 lines", -1 },
  1461. +    };
  1462. +
  1463. +    return rb->set_option("Scrolling", &scroll, INT, scroll_menu, 6, NULL);
  1464. +}
  1465. +
  1466. +bool viewer_menu_backlight(void)
  1467. +{
  1468. +    static const struct opt_items backlight_menu[] = {
  1469. +        { "Off", -1 },
  1470. +        { "On", -1 },
  1471. +        { "use Rockox setting", -1 },
  1472. +    };
  1473. +
  1474. +    return rb->set_option("Backlight", &backlight, INT, backlight_menu, 3,
  1475. +                          viewer_set_backlight);
  1476. +}
  1477. +
  1478. +bool viewer_menu_shortcut(void)
  1479. +{
  1480. +    static const struct opt_items shortcut_menu[] = {
  1481. +        { "Search...", -1 },
  1482. +        { "Backlight", -1 },
  1483. +        { "Scrolling", -1 },
  1484. +    };
  1485. +
  1486. +    return rb->set_option("REC shortcut", &shortcut, INT, shortcut_menu, 3,
  1487. +                          viewer_set_shortcut);
  1488. +}
  1489. +
  1490. +MENUITEM_FUNCTION(search_item, MENU_FUNC_CHECK_RETVAL, "Search...",
  1491. +                  viewer_menu_search, NULL, NULL, Icon_NOICON);
  1492. +MENUITEM_FUNCTION(scroll_item, 0, "Scrolling",
  1493. +                  viewer_menu_scroll, NULL, NULL, Icon_NOICON);
  1494. +MENUITEM_FUNCTION(backlight_item, 0, "Backlight",
  1495. +                  viewer_menu_backlight, NULL, NULL, Icon_NOICON);
  1496. +MENUITEM_FUNCTION(shortcut_item, 0, "REC shortcut",
  1497. +                  viewer_menu_shortcut, NULL, NULL, Icon_NOICON);
  1498. +
  1499. +#ifdef VIEWER_HAS_SHORTCUT
  1500. +#define VIEWER_SC_ITEM ,&shortcut_item
  1501. +#else
  1502. +#define VIEWER_SC_ITEM
  1503. +#endif
  1504. +MAKE_MENU(viewer_control_menu, "Viewer Control", NULL, Icon_NOICON,
  1505. +            &search_item, &scroll_item, &backlight_item VIEWER_SC_ITEM);
  1506. +
  1507. +bool viewer_menu(void)
  1508. +{
  1509. +    switch(rb->do_menu(&viewer_control_menu, NULL, NULL, false))
  1510. +    {
  1511. +        case MENU_ATTACHED_USB:
  1512. +        case true:
  1513. +            return true;
  1514. +        default:
  1515. +            return false;
  1516. +    }
  1517. +}
  1518. Index: apps/plugins/lib/SOURCES
  1519. ===================================================================
  1520. --- apps/plugins/lib/SOURCES    (revision 25263)
  1521. +++ apps/plugins/lib/SOURCES    (working copy)
  1522. @@ -5,6 +5,7 @@
  1523.  playback_control.c
  1524.  rgb_hsv.c
  1525.  buflib.c
  1526. +viewer.c
  1527.  display_text.c
  1528.  strncpy.c
  1529.  #if defined(HAVE_LCD_BITMAP) && (LCD_DEPTH < 4)
  1530. Index: apps/plugins/lib/viewer.h
  1531. ===================================================================
  1532. --- apps/plugins/lib/viewer.h   (Revision 0)
  1533. +++ apps/plugins/lib/viewer.h   (Revision 0)
  1534. @@ -0,0 +1,84 @@
  1535. +/***************************************************************************
  1536. +*             __________               __   ___.
  1537. +*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
  1538. +*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
  1539. +*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  1540. +*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  1541. +*                     \/            \/     \/    \/            \/
  1542. +* $Id: viewer.h 12008 2007-01-14 13:48:09Z dave $
  1543. +*
  1544. +* Copyright (C) 2007 Timo Horstschäfer
  1545. +*
  1546. +*
  1547. +* All files in this archive are subject to the GNU General Public License.
  1548. +* See the file COPYING in the source tree root for full license agreement.
  1549. +*
  1550. +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  1551. +* KIND, either express or implied.
  1552. +*
  1553. +****************************************************************************/
  1554. +
  1555. +#include "plugin.h"
  1556. +
  1557. +#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
  1558. +    (CONFIG_KEYPAD == IRIVER_H300_PAD) || \
  1559. +    (CONFIG_KEYPAD == SANSA_E200_PAD)
  1560. +#define VIEWER_HAS_SHORTCUT
  1561. +#define BUTTON_VIEWER_SHORTCUT BUTTON_REC
  1562. +#endif
  1563. +
  1564. +/** \brief Shows a text viewer.
  1565. + *
  1566. + * How to view some text:
  1567. + *  viewer(api, textptr);       // Text must be zero-terminated.
  1568. + *
  1569. + * For full control, call each function seperately:
  1570. + *  viewer_init(rb);            // Must be done once in a plugin.
  1571. + *  viewer_set_text(bufferptr, textptr);
  1572. + *  viewer_run();               // Display the text.
  1573. + *
  1574. + * viewer() is just a short form for all three calls.
  1575. + *
  1576. + * @param text Zero-terminated string.
  1577. + */
  1578. +int viewer(const struct plugin_api *api, const char *text);
  1579. +#define VIEWER_ATTACHED_USB (-2)
  1580. +#define VIEWER_EXIT         0
  1581. +#define VIEWER_CUSTOM       (VIEWER_EXIT+1)
  1582. +/**< Use values starting with VIEWER_CUSTOM for your own return values. */
  1583. +
  1584. +void viewer_init(const struct plugin_api *api);
  1585. +int viewer_run(void);
  1586. +
  1587. +/** Get the line to which the address belongs to. */
  1588. +int viewer_line(const char *p);
  1589. +
  1590. +/** Initialize the viewer with a new text.
  1591. + *
  1592. + * @param buffer A small buffer.
  1593. + * @param text   The new text to be displayed.
  1594. + * @return       Needed size of the buffer.
  1595. + */
  1596. +int viewer_set_text(void *buffer, const char *txt);
  1597. +void viewer_set_callback(void (*callback)(int button));
  1598. +void viewer_set_scroll(int newscroll);
  1599. +void viewer_set_pos(int line);
  1600. +void viewer_set_backlight(int newbacklight);
  1601. +void viewer_set_shortcut(int shortcutindex);
  1602. +
  1603. +int viewer_get_scroll(void);
  1604. +int viewer_get_pos(void);
  1605. +int viewer_get_backlight(void);
  1606. +int viewer_get_shortcut(void);
  1607. +
  1608. +/** Functions to control the viewer in the callback function. */
  1609. +void viewer_up(void);
  1610. +void viewer_down(void);
  1611. +bool viewer_search(void);
  1612. +bool viewer_menu(void);
  1613. +void viewer_redraw(void);
  1614. +void (*viewer_shortcut)(void);
  1615. +bool viewer_menu_search(void);
  1616. +bool viewer_menu_scroll(void);
  1617. +bool viewer_menu_backlight(void);
  1618. +void viewer_exit(int retval);
  1619. Index: apps/plugins/SOURCES
  1620. ===================================================================
  1621. --- apps/plugins/SOURCES        (revision 25263)
  1622. +++ apps/plugins/SOURCES        (working copy)
  1623. @@ -3,6 +3,7 @@
  1624.  credits.c
  1625.  cube.c
  1626.  dict.c
  1627. +dict2.c
  1628.  jackpot.c
  1629.  keybox.c
  1630.  logo.c
  1631. Index: apps/plugins/viewers.config
  1632. ===================================================================
  1633. --- apps/plugins/viewers.config (revision 25263)
  1634. +++ apps/plugins/viewers.config (working copy)
  1635. @@ -1,6 +1,8 @@
  1636.  ch8,viewers/chip8,0
  1637.  txt,viewers/viewer,1
  1638.  nfo,viewers/viewer,1
  1639. +idx,viewers/dict2,1
  1640. +lidx,viewers/dict2,1
  1641.  txt,apps/text_editor,2
  1642.  bmp,viewers/bmp,2
  1643.  jpg,viewers/jpeg,2
  1644. Index: apps/settings.h
  1645. ===================================================================
  1646. --- apps/settings.h     (revision 25263)
  1647. +++ apps/settings.h     (working copy)
  1648. @@ -78,6 +78,7 @@
  1649.  #define RECPRESETS_DIR  ROCKBOX_DIR "/recpresets"
  1650.  #define FMPRESET_PATH ROCKBOX_DIR "/fmpresets"
  1651.  #define PLAYLIST_CATALOG_DEFAULT_DIR "/Playlists"
  1652. +#define DICTS_DIR  "/dicts"
  1653.  
  1654.  #define VIEWERS_CONFIG      ROCKBOX_DIR "/viewers.config"
  1655.  #define CONFIGFILE          ROCKBOX_DIR "/config.cfg"
  1656. @@ -147,7 +148,7 @@
  1657.  enum { SHOW_ALL, SHOW_SUPPORTED, SHOW_MUSIC, SHOW_PLAYLIST, SHOW_ID3DB,
  1658.         NUM_FILTER_MODES,
  1659.         SHOW_WPS, SHOW_RWPS, SHOW_SBS, SHOW_RSBS, SHOW_FMR, SHOW_CFG,
  1660. -       SHOW_LNG, SHOW_MOD, SHOW_FONT, SHOW_PLUGINS};
  1661. +       SHOW_LNG, SHOW_MOD, SHOW_FONT, SHOW_DICTS, SHOW_PLUGINS};
  1662.  
  1663.  /* file and dir sort options */
  1664.  enum { SORT_ALPHA, SORT_DATE, SORT_DATE_REVERSED, SORT_TYPE, /* available as settings */
  1665. Index: apps/filetree.c
  1666. ===================================================================
  1667. --- apps/filetree.c     (revision 25263)
  1668. +++ apps/filetree.c     (working copy)
  1669. @@ -327,7 +327,8 @@
  1670.              ((*c->dirfilter == SHOW_MUSIC &&
  1671.               (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO) &&
  1672.               (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_M3U) ||
  1673. -            (*c->dirfilter == SHOW_SUPPORTED && !filetype_supported(dptr->attr)))) ||
  1674. +            ((*c->dirfilter == SHOW_SUPPORTED || *c->dirfilter == SHOW_DICTS)&&
  1675. +             !filetype_supported(dptr->attr)))) ||
  1676.              (*c->dirfilter == SHOW_WPS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_WPS) ||
  1677.  #ifdef HAVE_LCD_BITMAP
  1678.              (*c->dirfilter == SHOW_FONT && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FONT) ||
  1679. @@ -676,6 +677,7 @@
  1680.              if (*c->dirfilter > NUM_FILTER_MODES &&
  1681.                  *c->dirfilter != SHOW_CFG &&
  1682.                  *c->dirfilter != SHOW_FONT &&
  1683. +                *c->dirfilter != SHOW_DICTS &&
  1684.                  *c->dirfilter != SHOW_PLUGINS)
  1685.              {
  1686.                  exit_func = true;
  1687. Index: apps/root_menu.c
  1688. ===================================================================
  1689. --- apps/root_menu.c    (revision 25263)
  1690. +++ apps/root_menu.c    (working copy)
  1691. @@ -243,6 +243,10 @@
  1692.              tc->selected_item = last_db_selection;
  1693.          break;
  1694.  #endif
  1695. +        case GO_TO_BROWSEDICTS:
  1696. +            filter = SHOW_DICTS;
  1697. +            snprintf(folder, MAX_PATH, "%s/", DICTS_DIR);
  1698. +        break;
  1699.          case GO_TO_BROWSEPLUGINS:
  1700.              filter = SHOW_PLUGINS;
  1701.              strlcpy(folder, PLUGIN_DIR, MAX_PATH);
  1702. @@ -396,6 +400,7 @@
  1703.  #endif
  1704.      
  1705.      [GO_TO_RECENTBMARKS] =  { load_bmarks, NULL, &bookmark_settings_menu },
  1706. +    [GO_TO_BROWSEDICTS] = { browser, (void*)GO_TO_BROWSEDICTS, NULL },
  1707.      [GO_TO_BROWSEPLUGINS] = { plugins_menu, NULL, NULL },
  1708.      [GO_TO_PLAYLIST_VIEWER] = { playlist_view, NULL, NULL },
  1709.      
  1710. @@ -410,6 +415,8 @@
  1711.  MENUITEM_RETURNVALUE(db_browser, ID2P(LANG_TAGCACHE), GO_TO_DBBROWSER,
  1712.                          NULL, Icon_Audio);
  1713.  #endif
  1714. +MENUITEM_RETURNVALUE(dicts_browser, ID2P(LANG_DICTIONARIES), GO_TO_BROWSEDICTS,
  1715. +                        NULL, Icon_NOICON);
  1716.  MENUITEM_RETURNVALUE(rocks_browser, ID2P(LANG_PLUGINS), GO_TO_BROWSEPLUGINS,
  1717.                          NULL, Icon_Plugin);
  1718.  static char *get_wps_item_name(int selected_item, void * data, char *buffer)
  1719. @@ -461,7 +468,7 @@
  1720.  #if CONFIG_TUNER
  1721.              &fm,
  1722.  #endif
  1723. -            &playlist_options, &rocks_browser,  &info_menu
  1724. +            &playlist_options, &rocks_browser, &dicts_browser,  &info_menu
  1725.  
  1726.  #ifdef HAVE_LCD_CHARCELLS
  1727.              ,&do_shutdown_item
  1728. Index: apps/root_menu.h
  1729. ===================================================================
  1730. --- apps/root_menu.h    (revision 25263)
  1731. +++ apps/root_menu.h    (working copy)
  1732. @@ -50,6 +50,7 @@
  1733.      /* Do Not add any items above here unless you want it to be able to
  1734.         be the "start screen" after a boot up. The setting in settings_list.c
  1735.         will need editing if this is the case. */
  1736. +    GO_TO_BROWSEDICTS,
  1737.      GO_TO_BROWSEPLUGINS,
  1738.      GO_TO_TIMESCREEN,
  1739.      GO_TO_PLAYLIST_VIEWER,
clone this paste RAW Paste Data