reader_file.c
上传用户:holyzs
上传日期:2022-06-29
资源大小:2335k
文件大小:17k
源码类别:

编辑器/阅读器

开发平台:

C/C++

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <reader_core.h>
  4. enum {
  5.   ITEMS_PER_PAGE = 12,
  6.   MAX_ITEMS = 256, //max entries in a single directory
  7.   MAX_NAME_LEN = 32, //32 in unicode
  8.   FILENAME_BORDER = 128,
  9.   FILENAME_TAB_SIZE = 8*1024
  10. };
  11. static unsigned short reader_current_file[READER_FILENAME_MAX];
  12. unsigned short reader_current_dir[READER_PATH_MAX];
  13. int reader_file_menu_cursor;
  14. //file names table in unicode for sort, display and handle
  15. static unsigned short uni_names_tab[FILENAME_TAB_SIZE];
  16. #if TRACE_FILENAME || ENABLE_CONSOLE
  17. //buffer for trace out
  18. static unsigned short trace_buf[4*1024];
  19. #endif
  20. #if TRACE_FILENAME
  21. static int trace_ip;
  22. #define TRACE_FN_LEN 128
  23. #endif
  24. /*The file list is limited by 3 elements:
  25. 1. <MAX_ITEMS>, only <MAX_ITEMS> entries will be listed in a single directory
  26. 2. sizeof(uni_names_tab), if the size of lfn of files reached this size,
  27.    no more entries will be listed
  28. */
  29. reader_file_item_t file_menu_items[MAX_ITEMS + 1];
  30. static int n_item, n_pages;
  31. static int roll_name_display;
  32. static int name_cursor;
  33. static int compare_name(const void *f1, const void *f2);
  34. //calculate how many chars can be displayed within 'lim' pixels
  35. static int calc_chars(unsigned short *p, int lim);
  36. static int calc_width(unsigned short *p, int n);
  37. unsigned short *reader_file_get_dir(void) {
  38.   return reader_current_dir;
  39. }
  40. static int is_root_dir(unsigned short *path) {
  41.   return (0 == reader_wcscmp(path, reader_path_root));
  42. }
  43. static int is_upper_dir(unsigned short *path) {
  44.   if (0 == reader_wcscmp(path, reader_path_upper)) {
  45.     return 1;
  46.   }
  47.   return 0;
  48. }
  49. //0 means the file will not be listed
  50. //1 means a file ends with the wanted extension name
  51. //2 means will be listed because is a directory which is not '.'
  52. static int is_file_to_be_listed(unsigned short *filename, struct stat *st) {
  53.   unsigned short *p;
  54.   unsigned short ext1[4] = {'.', 'd', 'r', 0};
  55.   unsigned short ext2[4] = {'.', 'D', 'R', 0};
  56.   unsigned short ext3[5] = {'.', 'd', 'r', 'b', 0};
  57.   unsigned short ext4[5] = {'.', 'D', 'R', 'B', 0};
  58.   //do not list 'this' dir
  59.   if (filename[0] == '.' && filename[1] == 0) {
  60.     return 0;
  61.   }
  62.   //only list files ends with ".dr" or ".DR"
  63.   if (! (st->st_mode & S_IFDIR)) {
  64.     p = reader_wcsrchr(filename, '.');
  65.     if ((p == NULL)) {
  66.       return 0;
  67.     }
  68.     if ((memcmp(p, ext1, 8) != 0)
  69.       && (memcmp(p, ext2, 8) != 0)
  70.       && (memcmp(p, ext3, 10) != 0)
  71.       && (memcmp(p, ext4, 10) != 0)) {
  72.       return 0;
  73.     } else {
  74.       return 1;
  75.     }
  76.   }
  77.   return 2;
  78. }
  79. //This function looks a little weird
  80. //because of the weird activity of chdir() in libfat
  81. //take a look at test_dir() in libfat unit test
  82. //you can find it in test/fat/src/main.c
  83. static int mychdir(unsigned short *path) {
  84.   int ret = 0;
  85.   unsigned short root[] = {'/', '.', 0};
  86. #if ENABLE_CONSOLE
  87.   char *p = "path in mydir:";
  88.   char *p2;
  89.   char *buf = (char *)trace_buf;
  90.   int len = reader_wcslen(path), i;
  91.   strcpy(buf, p);
  92.   p2 = buf + strlen(buf);
  93.   sprintf(p2, "%d", path[0]);
  94.   for (i = 1; i < len; i++) {
  95.     p2 = buf + strlen(buf);
  96.     sprintf(p2, ",%d", path[i]);
  97.   }
  98.   console_log(buf);
  99. #endif
  100.   if (*path == '/') {
  101.     ret = fsal_chdir(root);
  102.     path ++;
  103.   }
  104.   if (*path) {
  105.     ret = fsal_chdir(path);
  106.     if (ret != 0) {
  107.       //restore the working path
  108.       if (reader_current_dir[0] != '') { //has been intialized
  109.         mychdir(reader_current_dir);
  110.       }
  111.     }
  112.   }
  113.   return ret;
  114. }
  115. int reader_file_set_dir(unsigned short *path) {
  116.   int i, len, attr;
  117.   struct stat st;
  118.   unsigned short filename[READER_PATH_MAX];
  119.   int uni_tab_cursor = 0;
  120.   unsigned short *puni = NULL;
  121.   fsal_dir_handle_t dir_handle;
  122.   if (0 != mychdir(path)) {
  123.     return ERR_CHDIR;
  124.   }
  125.   if (path != reader_current_dir) {
  126.     reader_wcsncpy(reader_current_dir, path, READER_PATH_MAX);
  127.   }
  128.   dir_handle = fsal_diropen(reader_path_this);
  129. #if TRACE_FILENAME
  130.   memset(trace_buf, 0, sizeof(trace_buf));
  131.   trace_ip = 0;
  132. #endif
  133.   //calc menu item number and page number
  134.   i = 0;
  135.   while ((i < MAX_ITEMS)
  136.     && (fsal_dirnext(dir_handle, filename, &st) == 0)) {
  137.     if (*filename == 0) {
  138.       //no lfn is found
  139.       continue;
  140.     }
  141. #if TRACE_FILENAME
  142.     if (trace_ip < sizeof(trace_buf)/sizeof(unsigned short) - TRACE_FN_LEN) {
  143.       reader_wcsncpy(&trace_buf[trace_ip], filename, TRACE_FN_LEN);
  144.       trace_ip += (reader_wcslen(filename)+1);
  145.     }
  146. #endif
  147.     attr = is_file_to_be_listed(filename, &st);
  148.     if (attr == 0) {
  149.       continue;
  150.     }
  151.     len = reader_wcslen(filename);
  152.     if (uni_tab_cursor+len+1 > FILENAME_TAB_SIZE) {
  153.       break;
  154.     }
  155.     puni = uni_names_tab+uni_tab_cursor;
  156.     reader_wcsncpy(puni, filename, len);
  157.     puni[len] = 0;
  158.     uni_tab_cursor += len+1; //move over last ''
  159.     READER_TRACEWM((L"uniname=%sn", puni));
  160.     file_menu_items[i].lfn = puni;
  161.     file_menu_items[i].is_folder = (st.st_mode & S_IFDIR);
  162.     file_menu_items[i].size = st.st_size;
  163.     i ++;
  164.   }
  165.   fsal_dirclose(dir_handle);
  166.   n_item = i;
  167.   n_pages = n_item / ITEMS_PER_PAGE + 1;
  168.   if (n_item % ITEMS_PER_PAGE == 0) {
  169.     n_pages --;
  170.   }
  171.   //sort the file items
  172.   qsort(file_menu_items, n_item, sizeof(reader_file_item_t), compare_name);
  173. #if TRACE_FILENAME
  174.   {
  175.     FILE *fd = NULL;
  176.     fd = fopen("console.txt", "a+");
  177.     fprintf(fd, "trace_ip=%dn", trace_ip);
  178.     fclose(fd);
  179.     fd = fopen("fnames", "wb");
  180.     fwrite(trace_buf, 2, trace_ip, fd);
  181.     fclose(fd);
  182.   }
  183. #endif
  184.   return 0;
  185. }
  186. //return if number is found in the given string
  187. //if found any number, output the number to num arg and the substring index that the number begins to prefix arg and return 1
  188. //else return 0
  189. static int look_for_numbers(unsigned short *str, int *prefix, int *num) {
  190.   unsigned short *p, *num_pos;
  191.   int i;
  192.   unsigned short num_buf[MAX_NAME_LEN + 1] = {0};
  193.   p = str;
  194.   i = 0;
  195.   num_pos = NULL;
  196.   while (*p) {
  197.     if (*p >= '0' && *p <= '9') {
  198.       if (num_pos == NULL) {
  199.         num_pos = p;
  200.       }
  201.       if (i < MAX_NAME_LEN) {
  202.         num_buf[i ++] = *p;
  203.       }
  204.     } else if (num_pos != NULL) { //cut the number
  205.       break;
  206.     }
  207.     p ++;
  208.   }
  209.   if (num_pos == NULL) {
  210.     return 0;
  211.   }
  212.   *prefix = num_pos - str;
  213.   *num = reader_atoi(num_buf);
  214.   return 1;
  215. }
  216. static int is_parent_folder(const reader_file_item_t *f) {
  217.   if (! (f->is_folder)) {
  218.     return 0;
  219.   }
  220.   if (0 == reader_wcscmp(f->lfn, reader_path_upper)) {
  221.     return 1;
  222.   }
  223.   return 0;
  224. }
  225. static int compare_name(const void *f1, const void *f2) {
  226.   const reader_file_item_t *p1 = (const reader_file_item_t *)f1;
  227.   const reader_file_item_t *p2 = (const reader_file_item_t *)f2;
  228.   unsigned short *n1, *n2;
  229.   int prefix1 = 0, prefix2 = 0;
  230.   int ret, num1, num2;
  231.   //folders are listed prior to the files
  232.   if (p1->is_folder != p2->is_folder) {
  233.     if (p1->is_folder) {
  234.       return -1;
  235.     }
  236.     return 1;
  237.   }
  238.   //parent folder is listed at the beginning
  239.   if (is_parent_folder(p1)) {
  240.     return -1;
  241.   }
  242.   if (is_parent_folder(p2)) {
  243.     return 1;
  244.   }
  245.   assert (p1->is_folder == p2->is_folder);
  246.   n1 = p1->lfn;
  247.   n2 = p2->lfn;
  248.   //look for numbers in names
  249.   if (0 == look_for_numbers(n1, &prefix1, &num1)) {
  250.     return reader_wcscmp(n1, n2);
  251.   }
  252.   if (0 == look_for_numbers(n2, &prefix2, &num2)) {
  253.     return reader_wcscmp(n1, n2);
  254.   }
  255.   ret = reader_wcscmp_n(n1, prefix1, n2, prefix2);
  256.   if (0 == ret) {
  257.     //same prefix, compare numbers
  258.     if (num1 == num2) {
  259.       //same number, the shorter the bigger because of the prefix 0s
  260.       return reader_wcslen(n2) - reader_wcslen(n1);
  261.     }
  262.     return num1 - num2;
  263.   }
  264.   return ret;
  265. }
  266. int reader_file_into_dir(unsigned short *path) {
  267.   reader_file_item_t *pitem = NULL;
  268.   unsigned short abspath[READER_PATH_MAX];
  269.   int len;
  270.   if (path != NULL) {
  271.     if (is_upper_dir(path)) {
  272.       return reader_file_upper_dir();
  273.     }
  274.     pitem = &file_menu_items[reader_file_menu_cursor];
  275.     reader_wcsncpy(abspath, reader_current_dir, READER_PATH_MAX);
  276.     len = reader_wcslen(abspath);
  277.     //append sub-dir name
  278.     if (abspath[len-1] != '/') {
  279.       //add '/' at the end
  280.       abspath[len++] = '/';
  281.     }
  282.     reader_wcscpy(&abspath[len], pitem->lfn);
  283.     reader_file_set_dir(abspath);
  284.   } else {
  285.     reader_file_set_dir(reader_current_dir);
  286.   }
  287.   reader_file_menu_cursor = 0;
  288.   return 0;
  289. }
  290. void reader_file_init(void) {
  291.   reader_file_set_dir(reader_path_root);
  292.   reader_file_menu_cursor = 0;
  293. }
  294. //return 0 means cursor changed, 1 means remained unchange.
  295. int reader_file_menu_up(void) {
  296.   if (reader_file_menu_cursor > 0) {
  297.     reader_file_menu_cursor --;
  298.     return 0;
  299.   }
  300.   return 1;
  301. }
  302. int reader_file_menu_down(void) {
  303.   if (reader_file_menu_cursor + 1 < n_item) {
  304.     reader_file_menu_cursor ++;
  305.     return 0;
  306.   }
  307.   return 1;
  308. }
  309. int reader_file_menu_prev_page(void) {
  310.   int t = reader_file_menu_cursor;
  311.   reader_file_menu_cursor -= ITEMS_PER_PAGE;
  312.   if (reader_file_menu_cursor < 0) {
  313.     reader_file_menu_cursor = 0;
  314.   }
  315.   return (t == reader_file_menu_cursor);
  316. }
  317. int reader_file_menu_next_page(void) {
  318.   int t = reader_file_menu_cursor;
  319.   reader_file_menu_cursor += ITEMS_PER_PAGE;
  320.   if (reader_file_menu_cursor >= n_item) {
  321.     reader_file_menu_cursor = n_item - 1;
  322.   }
  323.   return (t == reader_file_menu_cursor);
  324. }
  325. int reader_file_current_item(unsigned short *filename) {
  326.   reader_file_item_t *pitem = &file_menu_items[reader_file_menu_cursor];
  327.   int ret = pitem->is_folder;
  328.   if (filename == NULL) {
  329.     return ret;
  330.   }
  331.   reader_wcsncpy(filename, pitem->lfn, READER_FILENAME_MAX);
  332.   return ret;
  333. }
  334. int reader_file_menu_get_cursor_pos(void) {
  335.   return reader_file_menu_cursor % ITEMS_PER_PAGE;
  336. }
  337. int reader_file_menu_get_cursor(void) {
  338.   return reader_file_menu_cursor;
  339. }
  340. int reader_file_menu_set_cursor(int cursor) {
  341.   assert(cursor >= 0);
  342.   if (cursor >= 0 && cursor < n_item) {
  343.     reader_file_menu_cursor = cursor;
  344.     return 0;
  345.   }
  346.   return 1;
  347. }
  348. int reader_file_menu_map_cursor(int y) {
  349.   int y_begin = DEFAULT_FONT_SIZE + LINE_INTERVAL;
  350.   int y_end = READER_SCREEN_HEIGHT - (DEFAULT_FONT_SIZE + LINE_INTERVAL);
  351.   int ret;
  352.   if (y < y_begin || y > y_end) {
  353.     return -1;
  354.   }
  355.   ret = (y - y_begin) / (DEFAULT_FONT_SIZE + LINE_INTERVAL);
  356.   if (ret >= ITEMS_PER_PAGE) {
  357.     ret = ITEMS_PER_PAGE - 1;
  358.   }
  359.   return (reader_file_menu_cursor/ITEMS_PER_PAGE)*ITEMS_PER_PAGE + ret;
  360. }
  361. int reader_file_menu_set_cursor_pos(int pos) {
  362.   int current_page, current_item, new_cursor;
  363.   assert(pos >= 0 && pos < ITEMS_PER_PAGE);
  364.   current_page = reader_file_menu_cursor / ITEMS_PER_PAGE;
  365.   current_item = reader_file_menu_cursor % ITEMS_PER_PAGE;
  366.   if (current_item == pos) {
  367.     return 1;
  368.   }
  369.   new_cursor = current_page * ITEMS_PER_PAGE + pos;
  370.   if (new_cursor < n_item) {
  371.     reader_file_menu_cursor = new_cursor;
  372.     return 0;
  373.   }
  374.   return 1;
  375. }
  376. void reader_file_draw_menu(screen_t screen) {
  377.   int i, j, ibegin, iend, y, nc, n;
  378.   unsigned short tmp_str[16];
  379.   int current_page, current_item;
  380.   unsigned short *p;
  381.   reader_mmi_fill_screen(screen, READER_COLOR_BLACK);
  382.   reader_caption(screen, READER_STR(file_menu_prompt));
  383.   assert(n_item > 0);
  384.   //page number
  385.   current_page = reader_file_menu_cursor / ITEMS_PER_PAGE;
  386.   current_item = reader_file_menu_cursor % ITEMS_PER_PAGE;
  387.   i = reader_itoa(current_page + 1, tmp_str);
  388.   tmp_str[i ++] = '/';
  389.   j = reader_itoa(n_pages, tmp_str + i);
  390.   reader_textout_ex(screen, READER_SCREEN_WIDTH - 1, DEFAULT_HEADER_BLANK, tmp_str, i + j, DEFAULT_FONT_SIZE, READER_COLOR_YELLOW, TEXT_OUT_ALIGN_RIGHT);
  391.   //show cursor
  392.   y = (current_item + 1) * (DEFAULT_FONT_SIZE + LINE_INTERVAL) + DEFAULT_HEADER_BLANK;
  393.   reader_rectangle(screen, 0, y, READER_SCREEN_WIDTH - 1,
  394.                    y + DEFAULT_FONT_SIZE, READER_COLOR_WHITE, 1);
  395.   //show menu items
  396.   ibegin = current_page * ITEMS_PER_PAGE;
  397.   if (current_page == n_pages - 1) { //last page
  398.     iend = n_item;
  399.   } else {
  400.     iend = ibegin + ITEMS_PER_PAGE;
  401.   }
  402. #if TRACE_FILENAME
  403.   memset(trace_buf, 0, sizeof(trace_buf));
  404.   trace_ip = 0;
  405. #endif
  406.   roll_name_display = 0;
  407.   for (i = ibegin, j = 0; i < iend; i ++, j ++) {
  408.     color_t text_color = (j == current_item) ? READER_COLOR_BLACK : READER_COLOR_WHITE;
  409.     int name_begin = (j == current_item) ? name_cursor : 0;
  410.     y = (j + 1) * (DEFAULT_FONT_SIZE + LINE_INTERVAL) + DEFAULT_HEADER_BLANK;
  411.     p = file_menu_items[i].lfn;
  412. #if TRACE_FILENAME
  413.     if (trace_ip < sizeof(trace_buf)-TRACE_FN_LEN) {
  414.       reader_wcscpy(&trace_buf[trace_ip], p);
  415.       trace_ip += (reader_wcslen(p)+1);
  416.     }
  417. #endif
  418.     //show name
  419.     p += name_begin;
  420.     nc = calc_chars(p, FILENAME_BORDER);
  421.     reader_textout_ex(screen, 0, y, p, nc, DEFAULT_FONT_SIZE, text_color, 0);
  422.     if (nc < (int)reader_wcslen(p)) {
  423.       unsigned short append_mark[3];
  424.       append_mark[0] = '.';
  425.       append_mark[1] = '.';
  426.       append_mark[2] = 0;
  427.       if (j == current_item) {
  428.         roll_name_display = 1;
  429.       }
  430.       //append ".."
  431.       reader_textout_ex(screen, calc_width(p, nc), y, append_mark, 2, DEFAULT_FONT_SIZE, text_color, 0);
  432.     }
  433.     //show additional info, file size or <dir>
  434.     if (file_menu_items[i].is_folder) {
  435.       reader_textout_ex(screen, READER_SCREEN_WIDTH - 1, y, READER_STR(dir_mark), reader_wcslen(READER_STR(dir_mark)), DEFAULT_FONT_SIZE, text_color, TEXT_OUT_ALIGN_RIGHT);
  436.     } else {
  437.       int k;
  438.       int len, len_kb;
  439.       //only show length as 0K when the file is empty, or else at least 1K
  440.       len = file_menu_items[i].size;
  441.       if (len == 0) {
  442.         len_kb = 0;
  443.       } else {
  444.         len_kb = len / 1024;
  445.         if (len_kb == 0) {
  446.           len_kb = 1;
  447.         }
  448.       }
  449.       k = reader_itoa(len_kb, tmp_str);
  450.       tmp_str[k ++] = 'K';
  451.       reader_textout_ex(screen, READER_SCREEN_WIDTH - 1, y, tmp_str, k, DEFAULT_FONT_SIZE, text_color, TEXT_OUT_ALIGN_RIGHT);
  452.     }
  453.   }
  454.   //show current path
  455.   //draw path status bg
  456.   y = (ITEMS_PER_PAGE + 1) * (DEFAULT_FONT_SIZE + LINE_INTERVAL) + DEFAULT_HEADER_BLANK - 1;
  457.   reader_rectangle(screen, 0, y, READER_SCREEN_WIDTH - 1,
  458.                    y + DEFAULT_FONT_SIZE + 1, READER_COLOR_BLUE, 1);
  459.   //show dir name
  460.   n = calc_chars(reader_current_dir, READER_SCREEN_WIDTH-DEFAULT_FONT_SIZE);
  461.   reader_textout_ex(screen, 0, y + 1, reader_current_dir, n, DEFAULT_FONT_SIZE, READER_COLOR_YELLOW, 0);
  462.   reader_mmi_trigger_screen_update(screen);
  463.   READER_TRACEM(("roll=%dn", roll_name_display));
  464. #if TRACE_FILENAME
  465.   {
  466.     FILE *fd = NULL;
  467.     fd = fopen("dispname", "wb");
  468.     fwrite(trace_buf, 2, trace_ip, fd);
  469.     fclose(fd);
  470.   }
  471. #endif
  472. }
  473. void reader_file_reset_name_cursor(void) {
  474.   name_cursor = 0;
  475. }
  476. int reader_file_rolling_name(void) {
  477.   return roll_name_display;
  478. }
  479. void reader_file_move_name(int movement) {
  480.   name_cursor += movement;
  481. }
  482. static int calc_chars(unsigned short *p, int lim) {
  483.   int i = 0, len = 0;
  484.   unsigned short c;
  485.   while ((c = p[i]) != 0 && (len < lim)) {
  486.     len += get_chr_width(c, DEFAULT_FONT_SIZE);
  487.     i ++;
  488.   }
  489.   return i;
  490. }
  491. static int calc_width(unsigned short *p, int n) {
  492.   int i;
  493.   int width = 0;
  494.   for (i = 0; i < n; i++) {
  495.     width += get_chr_width(p[i], DEFAULT_FONT_SIZE);
  496.   }
  497.   return width;
  498. }
  499. unsigned short *reader_get_current_file() {
  500.   return reader_current_file;
  501. }
  502. int reader_set_current_file(unsigned short *filename) {
  503.   reader_wcsncpy(reader_current_file, filename, READER_FILENAME_MAX);
  504.   return 0;
  505. }
  506. int reader_file_set_cursor_by_name(unsigned short *filename) {
  507.   int i = 0;
  508.   while (file_menu_items[i].is_folder) {
  509.     i ++;
  510.   }
  511.   while (i < n_item) {
  512.     if (0 == reader_wcscmp(file_menu_items[i].lfn, filename)) {
  513.       reader_file_menu_cursor = i;
  514.       return i;
  515.     }
  516.     i++;
  517.   }
  518.   return -1;
  519. }
  520. int reader_dir_set_cursor_by_name(unsigned short *dirname) {
  521.   int i;
  522.   for (i = 0; (i < n_item) && file_menu_items[i].is_folder; i++) {
  523.     if (0 == reader_wcscmp(file_menu_items[i].lfn, dirname)) {
  524.       reader_file_menu_cursor = i;
  525.       return i;
  526.     }
  527.   }
  528.   return -1;
  529. }
  530. int reader_file_upper_dir(void) {
  531.   unsigned short abspath[READER_PATH_MAX];
  532.   unsigned short prevpath[READER_PATH_MAX];
  533.   int i, len, ret;
  534.   unsigned short *p;
  535.   if (is_root_dir(reader_current_dir)) {
  536.     return 1;
  537.   }
  538.   reader_wcsncpy(abspath, reader_current_dir, READER_PATH_MAX);
  539.   len = reader_wcslen(abspath);
  540.   //remove the pervious directory string
  541.   if (abspath[len-1] == '/') {
  542.     abspath[len-1] = ''; 
  543.   }
  544.   p = reader_wcsrchr(abspath, '/');
  545.   assert(p != NULL);
  546.   reader_wcsncpy(prevpath, &p[1], READER_PATH_MAX);
  547.   if (p == abspath) {
  548.     //keep '/' for root dir
  549.     p[1] = '';
  550.   } else {
  551.     *p = '';
  552.   }
  553.   if (0 != (ret = reader_file_set_dir(abspath))) {
  554.     console_log("upper dir failed.");
  555.     return ret;
  556.   }
  557.   //back to upper dir, locate cursor to the previous dir
  558.   i = reader_dir_set_cursor_by_name(prevpath);
  559.   if (i >= 0) {
  560.     reader_file_menu_cursor = i;
  561.   } else {
  562.     reader_file_menu_cursor = 0;
  563.   }
  564.   return 0;
  565. }