summaryrefslogtreecommitdiff
path: root/apps/plugins/viewer.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/viewer.c')
-rw-r--r--apps/plugins/viewer.c237
1 files changed, 164 insertions, 73 deletions
diff --git a/apps/plugins/viewer.c b/apps/plugins/viewer.c
index 6822f73868..ebb8865ff9 100644
--- a/apps/plugins/viewer.c
+++ b/apps/plugins/viewer.c
@@ -35,6 +35,7 @@ PLUGIN_HEADER
35#define TOP_SECTOR buffer 35#define TOP_SECTOR buffer
36#define MID_SECTOR (buffer + SMALL_BLOCK_SIZE) 36#define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
37#define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE)) 37#define BOTTOM_SECTOR (buffer + 2*(SMALL_BLOCK_SIZE))
38#define SCROLLBAR_WIDTH 6
38 39
39/* Out-Of-Bounds test for any pointer to data in the buffer */ 40/* Out-Of-Bounds test for any pointer to data in the buffer */
40#define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end) 41#define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end)
@@ -171,6 +172,23 @@ struct preferences {
171 WIDE, 172 WIDE,
172 } view_mode; 173 } view_mode;
173 174
175 enum {
176 ISO_8859_1=0,
177 ISO_8859_7,
178 ISO_8859_8,
179 CP1251,
180 ISO_8859_11,
181 ISO_8859_6,
182 ISO_8859_9,
183 ISO_8859_2,
184 SJIS,
185 GB2312,
186 KSX1001,
187 BIG5,
188 UTF8,
189 ENCODINGS
190 } encoding; /* FIXME: What should default encoding be? */
191
174#ifdef HAVE_LCD_BITMAP 192#ifdef HAVE_LCD_BITMAP
175 enum { 193 enum {
176 SB_OFF=0, 194 SB_OFF=0,
@@ -193,7 +211,7 @@ struct preferences {
193} prefs; 211} prefs;
194 212
195static unsigned char buffer[BUFFER_SIZE + 1]; 213static unsigned char buffer[BUFFER_SIZE + 1];
196static unsigned char line_break[] = {0,0x20,'-',9,0xB,0xC}; 214static unsigned char line_break[] = {0,0x20,9,0xB,0xC,'-'};
197static int display_columns; /* number of (pixel) columns on the display */ 215static int display_columns; /* number of (pixel) columns on the display */
198static int display_lines; /* number of lines on the display */ 216static int display_lines; /* number of lines on the display */
199static int draw_columns; /* number of (pixel) columns available for text */ 217static int draw_columns; /* number of (pixel) columns available for text */
@@ -210,23 +228,60 @@ static unsigned char *next_screen_ptr;
210static unsigned char *next_screen_to_draw_ptr; 228static unsigned char *next_screen_to_draw_ptr;
211static unsigned char *next_line_ptr; 229static unsigned char *next_line_ptr;
212static struct plugin_api* rb; 230static struct plugin_api* rb;
231#ifdef HAVE_LCD_BITMAP
232static struct font *pf;
233#endif
234
235int glyph_width(int ch)
236{
237 if (ch == 0)
238 ch = ' ';
239
240#ifdef HAVE_LCD_BITMAP
241 return rb->font_get_width(pf, ch);
242#else
243 return 1;
244#endif
245}
246
247unsigned char* get_ucs(const unsigned char* str, unsigned short* ch)
248{
249 unsigned char utf8_tmp[6];
250 int count;
251
252 if (prefs.encoding == UTF8)
253 return (unsigned char*)rb->utf8decode(str, ch);
254
255 count = BUFFER_OOB(str+2)? 1:2;
256 rb->iso_decode(str, utf8_tmp, prefs.encoding, count);
257 rb->utf8decode(utf8_tmp, ch);
213 258
214static unsigned char glyph_width[256]; 259 if ((prefs.encoding == SJIS && *str > 0xA0 && *str < 0xE0) || prefs.encoding < SJIS)
260 return (unsigned char*)str+1;
261 else
262 return (unsigned char*)str+2;
263}
215 264
216bool done = false; 265bool done = false;
217int col = 0; 266int col = 0;
218 267
219#define ADVANCE_COUNTERS(c) do { width += glyph_width[c]; k++; } while(0) 268#define ADVANCE_COUNTERS(c) do { width += glyph_width(c); k++; } while(0)
220#define LINE_IS_FULL ((k>MAX_COLUMNS-1) || (width > draw_columns)) 269#define LINE_IS_FULL ((k>MAX_COLUMNS-1) || (width > draw_columns))
221static unsigned char* crop_at_width(const unsigned char* p) 270static unsigned char* crop_at_width(const unsigned char* p)
222{ 271{
223 int k,width; 272 int k,width;
273 unsigned short ch;
274 const unsigned char *oldp = p;
224 275
225 k=width=0; 276 k=width=0;
226 while (!LINE_IS_FULL)
227 ADVANCE_COUNTERS(p[k]);
228 277
229 return (unsigned char*) p+k-1; 278 while (!LINE_IS_FULL) {
279 oldp = p;
280 p = get_ucs(p, &ch);
281 ADVANCE_COUNTERS(ch);
282 }
283
284 return (unsigned char*)oldp;
230} 285}
231 286
232static unsigned char* find_first_feed(const unsigned char* p, int size) 287static unsigned char* find_first_feed(const unsigned char* p, int size)
@@ -257,6 +312,11 @@ static unsigned char* find_last_space(const unsigned char* p, int size)
257 312
258 k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1; 313 k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1;
259 314
315 if (!BUFFER_OOB(&p[size]))
316 for (j=k; j < ((int) sizeof(line_break)) - 1; j++)
317 if (p[size] == line_break[j])
318 return (unsigned char*) p+size;
319
260 for (i=size-1; i>=0; i--) 320 for (i=size-1; i>=0; i--)
261 for (j=k; j < (int) sizeof(line_break); j++) 321 for (j=k; j < (int) sizeof(line_break); j++)
262 if (p[i] == line_break[j]) 322 if (p[i] == line_break[j])
@@ -394,8 +454,8 @@ static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_sho
394 the hyphen on current line (won't apply in WIDE mode, 454 the hyphen on current line (won't apply in WIDE mode,
395 since it's guarenteed there won't be room). */ 455 since it's guarenteed there won't be room). */
396 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */ 456 if (!BUFFER_OOB(next_line)) /* Not Null & not out of bounds */
397 if (next_line[0] == 0 || 457 if (next_line[0] == 0)/* ||
398 (next_line[0] == '-' && next_line-cur_line < draw_columns)) 458 (next_line[0] == '-' && next_line-cur_line < draw_columns)) */
399 next_line++; 459 next_line++;
400 460
401 if (BUFFER_OOB(next_line)) 461 if (BUFFER_OOB(next_line))
@@ -552,9 +612,8 @@ static void viewer_scroll_down(void)
552 612
553#ifdef HAVE_LCD_BITMAP 613#ifdef HAVE_LCD_BITMAP
554static void viewer_scrollbar(void) { 614static void viewer_scrollbar(void) {
555 int w, h, items, min_shown, max_shown; 615 int items, min_shown, max_shown;
556 616
557 rb->lcd_getstringsize("o", &w, &h);
558 items = (int) file_size; /* (SH1 int is same as long) */ 617 items = (int) file_size; /* (SH1 int is same as long) */
559 min_shown = (int) file_pos + (screen_top_ptr - buffer); 618 min_shown = (int) file_pos + (screen_top_ptr - buffer);
560 619
@@ -563,27 +622,28 @@ static void viewer_scrollbar(void) {
563 else 622 else
564 max_shown = min_shown + (next_screen_ptr - screen_top_ptr); 623 max_shown = min_shown + (next_screen_ptr - screen_top_ptr);
565 624
566 rb->scrollbar(0, 0, w-2, LCD_HEIGHT, items, min_shown, max_shown, VERTICAL); 625 rb->scrollbar(0, 0, SCROLLBAR_WIDTH-1, LCD_HEIGHT, items, min_shown, max_shown, VERTICAL);
567} 626}
568#endif 627#endif
569 628
570static void viewer_draw(int col) 629static void viewer_draw(int col)
571{ 630{
572 int i, j, k, line_len, resynch_move, spaces, left_col=0; 631 int i, j, k, line_len, line_width, resynch_move, spaces, left_col=0;
573 int width, extra_spaces, indent_spaces, spaces_per_word; 632 int width, extra_spaces, indent_spaces, spaces_per_word;
574 bool multiple_spacing, line_is_short; 633 bool multiple_spacing, line_is_short;
634 unsigned short ch;
635 unsigned char *str, *oldstr;
575 unsigned char *line_begin; 636 unsigned char *line_begin;
576 unsigned char *line_end; 637 unsigned char *line_end;
577 unsigned char c; 638 unsigned char c;
578 unsigned char scratch_buffer[MAX_COLUMNS + 1]; 639 unsigned char scratch_buffer[MAX_COLUMNS + 1];
579 unsigned char utf8_buffer[MAX_COLUMNS*4 + 1]; 640 unsigned char utf8_buffer[MAX_COLUMNS*4 + 1];
580 int len;
581 unsigned char *endptr; 641 unsigned char *endptr;
582 642
583 /* If col==-1 do all calculations but don't display */ 643 /* If col==-1 do all calculations but don't display */
584 if (col != -1) { 644 if (col != -1) {
585#ifdef HAVE_LCD_BITMAP 645#ifdef HAVE_LCD_BITMAP
586 left_col = prefs.need_scrollbar? 1:0; 646 left_col = prefs.need_scrollbar? SCROLLBAR_WIDTH:0;
587#else 647#else
588 left_col = 0; 648 left_col = 0;
589#endif 649#endif
@@ -629,6 +689,20 @@ static void viewer_draw(int col)
629 } 689 }
630 line_len = line_end - line_begin; 690 line_len = line_end - line_begin;
631 691
692 /* calculate line_len */
693 str = oldstr = line_begin;
694 j = -1;
695 while (str < line_end) {
696 oldstr = str;
697 str = crop_at_width(str);
698 j++;
699 }
700 line_width = j*draw_columns;
701 while (oldstr < line_end) {
702 oldstr = get_ucs(oldstr, &ch);
703 line_width += glyph_width(ch);
704 }
705
632 if (prefs.line_mode == JOIN) { 706 if (prefs.line_mode == JOIN) {
633 if (line_begin[0] == 0) { 707 if (line_begin[0] == 0) {
634 line_begin++; 708 line_begin++;
@@ -661,16 +735,12 @@ static void viewer_draw(int col)
661 break; 735 break;
662 } 736 }
663 } 737 }
664 738 if (col != -1) {
665 if (col != -1) 739 scratch_buffer[k] = 0;
666 if (k > col) { 740 endptr = rb->iso_decode(scratch_buffer + col, utf8_buffer,
667 scratch_buffer[k] = 0; 741 prefs.encoding, k-col);
668 endptr = rb->iso_decode(scratch_buffer + col, utf8_buffer, 742 *endptr = 0;
669 -1, k-col); 743 }
670 *endptr = 0;
671 len = rb->utf8length(utf8_buffer);
672 rb->lcd_puts(left_col, i, utf8_buffer);
673 }
674 } 744 }
675 else if (prefs.line_mode == REFLOW) { 745 else if (prefs.line_mode == REFLOW) {
676 if (line_begin[0] == 0) { 746 if (line_begin[0] == 0) {
@@ -684,12 +754,13 @@ static void viewer_draw(int col)
684 indent_spaces = 0; 754 indent_spaces = 0;
685 if (!line_is_short) { 755 if (!line_is_short) {
686 multiple_spacing = false; 756 multiple_spacing = false;
687 for (j=width=spaces=0; j < line_len; j++) { 757 width=spaces=0;
688 c = line_begin[j]; 758 for (str = line_begin; str < line_end; ) {
689 switch (c) { 759 str = get_ucs(str, &ch);
760 switch (ch) {
690 case ' ': 761 case ' ':
691 case 0: 762 case 0:
692 if ((j==0) && (prefs.word_mode==WRAP)) 763 if ((str == line_begin) && (prefs.word_mode==WRAP))
693 /* special case: indent the paragraph, 764 /* special case: indent the paragraph,
694 * don't count spaces */ 765 * don't count spaces */
695 indent_spaces = par_indent_spaces; 766 indent_spaces = par_indent_spaces;
@@ -699,8 +770,7 @@ static void viewer_draw(int col)
699 break; 770 break;
700 default: 771 default:
701 multiple_spacing = false; 772 multiple_spacing = false;
702 width += glyph_width[c]; 773 width += glyph_width(ch);
703 k++;
704 break; 774 break;
705 } 775 }
706 } 776 }
@@ -708,7 +778,7 @@ static void viewer_draw(int col)
708 778
709 if (spaces) { 779 if (spaces) {
710 /* total number of spaces to insert between words */ 780 /* total number of spaces to insert between words */
711 extra_spaces = (draw_columns-width) / glyph_width[' '] 781 extra_spaces = (draw_columns-width)/glyph_width(' ')
712 - indent_spaces; 782 - indent_spaces;
713 /* number of spaces between each word*/ 783 /* number of spaces between each word*/
714 spaces_per_word = extra_spaces / spaces; 784 spaces_per_word = extra_spaces / spaces;
@@ -754,31 +824,41 @@ static void viewer_draw(int col)
754 } 824 }
755 } 825 }
756 826
757 if (col != -1) 827 if (col != -1) {
758 if (k > col) { 828 scratch_buffer[k] = 0;
759 scratch_buffer[k] = 0; 829 endptr = rb->iso_decode(scratch_buffer + col, utf8_buffer,
760 endptr = rb->iso_decode(scratch_buffer + col, utf8_buffer, 830 prefs.encoding, k-col);
761 -1, k-col); 831 *endptr = 0;
762 *endptr = 0; 832 }
763 len = rb->utf8length(utf8_buffer);
764 rb->lcd_puts(left_col, i, utf8_buffer);
765 }
766 } 833 }
767 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */ 834 else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
768 if (col != -1) 835 if (col != -1)
769 if (line_len > col) { 836 if (line_width > col) {
770 c = line_end[0]; 837 str = oldstr = line_begin;
771 line_end[0] = 0; 838 k = col;
772 endptr = rb->iso_decode(line_begin + col, utf8_buffer, 839 while (k > draw_columns) {
773 -1, line_end-line_begin); 840 str = crop_at_width(str);
841 k -= draw_columns;
842 }
843 width = 0;
844 while (width <= k) {
845 oldstr = str;
846 str = get_ucs(str, &ch);
847 width += glyph_width(ch);
848 }
849 endptr = rb->iso_decode(oldstr, utf8_buffer,
850 prefs.encoding, line_end-oldstr);
774 *endptr = 0; 851 *endptr = 0;
775 len = rb->utf8length(utf8_buffer);
776 rb->lcd_puts(left_col, i, utf8_buffer);
777 line_end[0] = c;
778 } 852 }
779 } 853 }
780 if (line_len > max_line_len) 854 if (col != -1 && line_width > col)
781 max_line_len = line_len; 855#ifdef HAVE_LCD_BITMAP
856 rb->lcd_putsxy(left_col, i*pf->height, utf8_buffer);
857#else
858 rb->lcd_puts(left_col, i, utf8_buffer);
859#endif
860 if (line_width > max_line_len)
861 max_line_len = line_width;
782 862
783 if (i == 0) 863 if (i == 0)
784 next_line_ptr = line_end; 864 next_line_ptr = line_end;
@@ -837,8 +917,8 @@ static void init_need_scrollbar(void) {
837 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */ 917 and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
838 viewer_draw(-1); 918 viewer_draw(-1);
839 prefs.need_scrollbar = NEED_SCROLLBAR(); 919 prefs.need_scrollbar = NEED_SCROLLBAR();
840 draw_columns = prefs.need_scrollbar? display_columns-glyph_width['o'] : display_columns; 920 draw_columns = prefs.need_scrollbar? display_columns-SCROLLBAR_WIDTH : display_columns;
841 par_indent_spaces = draw_columns/(5*glyph_width[' ']); 921 par_indent_spaces = draw_columns/(5*glyph_width(' '));
842} 922}
843#else 923#else
844#define init_need_scrollbar() 924#define init_need_scrollbar()
@@ -847,23 +927,9 @@ static void init_need_scrollbar(void) {
847static bool viewer_init(void) 927static bool viewer_init(void)
848{ 928{
849#ifdef HAVE_LCD_BITMAP 929#ifdef HAVE_LCD_BITMAP
850 int idx, ch;
851 struct font *pf;
852 930
853 pf = rb->font_get(FONT_UI); 931 pf = rb->font_get(FONT_UI);
854 932
855 if (pf->width != NULL)
856 { /* variable pitch font -- fill structure from font width data */
857 ch = pf->defaultchar - pf->firstchar;
858 rb->memset(glyph_width, pf->width[ch], 256);
859 idx = pf->firstchar;
860 rb->memcpy(&glyph_width[idx], pf->width, pf->size);
861 idx += pf->size;
862 rb->memset(&glyph_width[idx], pf->width[ch], 256-idx);
863 }
864 else /* fixed pitch font -- same width for all glyphs */
865 rb->memset(glyph_width, pf->maxwidth, 256);
866
867 display_lines = LCD_HEIGHT / pf->height; 933 display_lines = LCD_HEIGHT / pf->height;
868 display_columns = LCD_WIDTH; 934 display_columns = LCD_WIDTH;
869#else 935#else
@@ -871,7 +937,6 @@ static bool viewer_init(void)
871 display_lines = 2; 937 display_lines = 2;
872 draw_columns = display_columns = 11; 938 draw_columns = display_columns = 11;
873 par_indent_spaces = 2; 939 par_indent_spaces = 2;
874 rb->memset(glyph_width, 1, 256);
875#endif 940#endif
876 941
877 fd = rb->open(file_name, O_RDONLY); 942 fd = rb->open(file_name, O_RDONLY);
@@ -885,6 +950,9 @@ static bool viewer_init(void)
885 /* Init mac_text value used in processing buffer */ 950 /* Init mac_text value used in processing buffer */
886 mac_text = false; 951 mac_text = false;
887 952
953 /* Set codepage to system default */
954 prefs.encoding = rb->global_settings->default_codepage;
955
888 /* Read top of file into buffer; 956 /* Read top of file into buffer;
889 init file_pos, buffer_end, screen_top_ptr */ 957 init file_pos, buffer_end, screen_top_ptr */
890 viewer_top(); 958 viewer_top();
@@ -963,14 +1031,36 @@ static int col_limit(int col)
963 if (col < 0) 1031 if (col < 0)
964 col = 0; 1032 col = 0;
965 else 1033 else
966 if (col > max_line_len - 2) 1034 if (col > max_line_len - 2*glyph_width('o'))
967 col = max_line_len - 2; 1035 col = max_line_len - 2*glyph_width('o');
968 1036
969 return col; 1037 return col;
970} 1038}
971 1039
972/* settings helper functions */ 1040/* settings helper functions */
973 1041
1042static bool encoding_setting(void)
1043{
1044 static const struct opt_items names[] = {
1045 {"ISO-8859-1", -1},
1046 {"ISO-8859-7", -1},
1047 {"ISO-8859-8", -1},
1048 {"CP1251", -1},
1049 {"ISO-8859-11", -1},
1050 {"ISO-8859-6", -1},
1051 {"ISO-8859-9", -1},
1052 {"ISO-8859-2", -1},
1053 {"SJIS", -1},
1054 {"GB-2312", -1},
1055 {"KSX-1001", -1},
1056 {"BIG5", -1},
1057 {"UTF-8", -1},
1058 };
1059
1060 return rb->set_option("Encoding", &prefs.encoding, INT, names,
1061 sizeof(names) / sizeof(names[0]), NULL);
1062}
1063
974static bool word_wrap_setting(void) 1064static bool word_wrap_setting(void)
975{ 1065{
976 static const struct opt_items names[] = { 1066 static const struct opt_items names[] = {
@@ -1055,6 +1145,7 @@ static bool viewer_options_menu(void)
1055 bool result; 1145 bool result;
1056 1146
1057 static const struct menu_item items[] = { 1147 static const struct menu_item items[] = {
1148 {"Encoding", encoding_setting },
1058 {"Word Wrap", word_wrap_setting }, 1149 {"Word Wrap", word_wrap_setting },
1059 {"Line Mode", line_mode_setting }, 1150 {"Line Mode", line_mode_setting },
1060 {"Wide View", view_mode_setting }, 1151 {"Wide View", view_mode_setting },
@@ -1206,7 +1297,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file)
1206 case VIEWER_SCREEN_LEFT | BUTTON_REPEAT: 1297 case VIEWER_SCREEN_LEFT | BUTTON_REPEAT:
1207 if (prefs.view_mode == WIDE) { 1298 if (prefs.view_mode == WIDE) {
1208 /* Screen left */ 1299 /* Screen left */
1209 col -= draw_columns/glyph_width['o']; 1300 col -= draw_columns;
1210 col = col_limit(col); 1301 col = col_limit(col);
1211 } 1302 }
1212 else { /* prefs.view_mode == NARROW */ 1303 else { /* prefs.view_mode == NARROW */
@@ -1221,7 +1312,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file)
1221 case VIEWER_SCREEN_RIGHT | BUTTON_REPEAT: 1312 case VIEWER_SCREEN_RIGHT | BUTTON_REPEAT:
1222 if (prefs.view_mode == WIDE) { 1313 if (prefs.view_mode == WIDE) {
1223 /* Screen right */ 1314 /* Screen right */
1224 col += draw_columns/glyph_width['o']; 1315 col += draw_columns;
1225 col = col_limit(col); 1316 col = col_limit(col);
1226 } 1317 }
1227 else { /* prefs.view_mode == NARROW */ 1318 else { /* prefs.view_mode == NARROW */
@@ -1254,7 +1345,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file)
1254 case VIEWER_COLUMN_LEFT: 1345 case VIEWER_COLUMN_LEFT:
1255 case VIEWER_COLUMN_LEFT | BUTTON_REPEAT: 1346 case VIEWER_COLUMN_LEFT | BUTTON_REPEAT:
1256 /* Scroll left one column */ 1347 /* Scroll left one column */
1257 col--; 1348 col -= glyph_width('o');
1258 col = col_limit(col); 1349 col = col_limit(col);
1259 viewer_draw(col); 1350 viewer_draw(col);
1260 break; 1351 break;
@@ -1262,7 +1353,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* file)
1262 case VIEWER_COLUMN_RIGHT: 1353 case VIEWER_COLUMN_RIGHT:
1263 case VIEWER_COLUMN_RIGHT | BUTTON_REPEAT: 1354 case VIEWER_COLUMN_RIGHT | BUTTON_REPEAT:
1264 /* Scroll right one column */ 1355 /* Scroll right one column */
1265 col++; 1356 col += glyph_width('o');
1266 col = col_limit(col); 1357 col = col_limit(col);
1267 viewer_draw(col); 1358 viewer_draw(col);
1268 break; 1359 break;