23
23
#include <grub/dl.h>
24
24
#include <grub/env.h>
25
25
#include <grub/normal.h>
27
/* The amount of lines counted by the pager. */
28
static unsigned grub_more_lines;
26
#include <grub/charset.h>
30
struct term_state *next;
31
const struct grub_unicode_glyph *backlog_glyphs;
32
const grub_uint32_t *backlog_ucs4;
33
grub_size_t backlog_len;
40
static struct term_state *term_states = NULL;
30
42
/* If the more pager is active. */
31
43
static int grub_more;
33
static int grub_normal_line_counter = 0;
45
static int grub_normal_char_counter = 0;
36
grub_normal_get_line_counter (void)
38
return grub_normal_line_counter;
48
grub_normal_get_char_counter (void)
50
return grub_normal_char_counter;
54
grub_normal_reset_more (void)
56
static struct term_state *state;
57
for (state = term_states; state; state = state->next)
42
process_newline (void)
44
struct grub_term_output *cur;
47
FOR_ACTIVE_TERM_OUTPUTS(cur)
48
if (grub_term_height (cur) < height)
49
height = grub_term_height (cur);
52
grub_normal_line_counter++;
54
if (grub_more && grub_more_lines >= height - 1)
59
pos = grub_term_save_pos ();
61
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
62
grub_printf ("--MORE--");
63
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
67
/* Remove the message. */
68
grub_term_restore_pos (pos);
70
grub_term_restore_pos (pos);
72
/* Scroll one lines or an entire page, depending on the key. */
73
if (key == '\r' || key =='\n')
74
grub_more_lines = height - 2;
66
grub_term_output_t term;
67
grub_uint32_t *unicode_str, *unicode_last_position;
69
pos = grub_term_save_pos ();
71
grub_utf8_to_ucs4_alloc ("--MORE--", &unicode_str,
72
&unicode_last_position);
76
grub_errno = GRUB_ERR_NONE;
80
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
82
FOR_ACTIVE_TERM_OUTPUTS(term)
84
grub_print_ucs4 (unicode_str, unicode_last_position, 0, 0, term);
86
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
88
grub_free (unicode_str);
92
/* Remove the message. */
93
grub_term_restore_pos (pos);
94
FOR_ACTIVE_TERM_OUTPUTS(term)
95
grub_print_spaces (term, 8);
96
grub_term_restore_pos (pos);
98
/* Scroll one lines or an entire page, depending on the key. */
100
if (key == '\r' || key =='\n')
101
grub_normal_reset_more ();
104
static struct term_state *state;
105
for (state = term_states; state; state = state->next)
106
state->num_lines -= 2;
117
grub_normal_reset_more ();
92
grub_install_newline_hook (void)
122
GRUB_CP437_UPARROW = 0x18,
123
GRUB_CP437_DOWNARROW = 0x19,
124
GRUB_CP437_RIGHTARROW = 0x1a,
125
GRUB_CP437_LEFTARROW = 0x1b,
126
GRUB_CP437_VLINE = 0xb3,
127
GRUB_CP437_CORNER_UR = 0xbf,
128
GRUB_CP437_CORNER_LL = 0xc0,
129
GRUB_CP437_HLINE = 0xc4,
130
GRUB_CP437_CORNER_LR = 0xd9,
131
GRUB_CP437_CORNER_UL = 0xda,
135
map_code (grub_uint32_t in, struct grub_term_output *term)
94
grub_newline_hook = process_newline;
140
switch (term->flags & GRUB_TERM_CODE_TYPE_MASK)
142
case GRUB_TERM_CODE_TYPE_CP437:
145
case GRUB_UNICODE_LEFTARROW:
146
return GRUB_CP437_LEFTARROW;
147
case GRUB_UNICODE_UPARROW:
148
return GRUB_CP437_UPARROW;
149
case GRUB_UNICODE_RIGHTARROW:
150
return GRUB_CP437_RIGHTARROW;
151
case GRUB_UNICODE_DOWNARROW:
152
return GRUB_CP437_DOWNARROW;
153
case GRUB_UNICODE_HLINE:
154
return GRUB_CP437_HLINE;
155
case GRUB_UNICODE_VLINE:
156
return GRUB_CP437_VLINE;
157
case GRUB_UNICODE_CORNER_UL:
158
return GRUB_CP437_CORNER_UL;
159
case GRUB_UNICODE_CORNER_UR:
160
return GRUB_CP437_CORNER_UR;
161
case GRUB_UNICODE_CORNER_LL:
162
return GRUB_CP437_CORNER_LL;
163
case GRUB_UNICODE_CORNER_LR:
164
return GRUB_CP437_CORNER_LR;
167
case GRUB_TERM_CODE_TYPE_ASCII:
168
/* Better than nothing. */
171
case GRUB_UNICODE_LEFTARROW:
174
case GRUB_UNICODE_UPARROW:
177
case GRUB_UNICODE_RIGHTARROW:
180
case GRUB_UNICODE_DOWNARROW:
183
case GRUB_UNICODE_HLINE:
186
case GRUB_UNICODE_VLINE:
189
case GRUB_UNICODE_CORNER_UL:
190
case GRUB_UNICODE_CORNER_UR:
191
case GRUB_UNICODE_CORNER_LL:
192
case GRUB_UNICODE_CORNER_LR:
98
202
grub_puts_terminal (const char *str, struct grub_term_output *term)
102
const grub_uint8_t *ptr = (const grub_uint8_t *) str;
103
const grub_uint8_t *end;
104
end = (const grub_uint8_t *) (str + grub_strlen (str));
204
grub_uint32_t *unicode_str, *unicode_last_position;
205
grub_utf8_to_ucs4_alloc (str, &unicode_str,
206
&unicode_last_position);
108
ret = grub_utf8_to_ucs4 (&code, 1, ptr, end - ptr, &ptr);
109
grub_putcode (code, term);
208
grub_print_ucs4 (unicode_str, unicode_last_position, 0, 0, term);
209
grub_free (unicode_str);
263
362
grub_errno = GRUB_ERR_NONE;
366
putglyph (const struct grub_unicode_glyph *c, struct grub_term_output *term)
368
struct grub_unicode_glyph c2 =
377
grub_normal_char_counter++;
379
if (c->base == '\t' && term->getxy)
383
n = 8 - ((term->getxy (term) >> 8) & 7);
386
(term->putchar) (term, &c2);
391
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
392
== GRUB_TERM_CODE_TYPE_UTF8_LOGICAL
393
|| (term->flags & GRUB_TERM_CODE_TYPE_MASK)
394
== GRUB_TERM_CODE_TYPE_UTF8_VISUAL)
397
c2.estimated_width = grub_term_getcharwidth (term, c);
398
for (i = -1; i < (int) c->ncomb; i++)
400
grub_uint8_t u8[20], *ptr;
406
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
407
== GRUB_TERM_CODE_TYPE_UTF8_VISUAL)
409
if ((c->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR))
410
code = grub_unicode_mirror_code (code);
411
code = grub_unicode_shape_code (code, c->attributes);
415
code = c->combining[i].code;
417
grub_ucs4_to_utf8 (&code, 1, u8, sizeof (u8));
419
for (ptr = u8; *ptr; ptr++)
422
(term->putchar) (term, &c2);
423
c2.estimated_width = 0;
426
c2.estimated_width = 1;
429
(term->putchar) (term, c);
434
(term->putchar) (term, &c2);
439
putcode_real (grub_uint32_t code, struct grub_term_output *term)
441
struct grub_unicode_glyph c =
450
c.base = map_code (code, term);
454
/* Put a Unicode character. */
456
grub_putcode (grub_uint32_t code, struct grub_term_output *term)
458
/* Combining character by itself? */
459
if (grub_unicode_get_comb_type (code) != GRUB_UNICODE_COMB_NONE)
462
putcode_real (code, term);
466
get_maxwidth (struct grub_term_output *term,
467
int margin_left, int margin_right)
469
struct grub_unicode_glyph space_glyph = {
476
return (grub_term_width (term)
477
- grub_term_getcharwidth (term, &space_glyph)
478
* (margin_left + margin_right) - 1);
482
get_startwidth (struct grub_term_output *term,
485
return ((term->getxy (term) >> 8) & 0xff) - margin_left;
489
print_ucs4_terminal (const grub_uint32_t * str,
490
const grub_uint32_t * last_position,
491
int margin_left, int margin_right,
492
struct grub_term_output *term,
493
struct term_state *state)
495
const grub_uint32_t *ptr;
496
grub_ssize_t startwidth = get_startwidth (term, margin_left);
497
grub_ssize_t line_width = startwidth;
498
grub_ssize_t lastspacewidth = 0;
499
grub_ssize_t max_width = get_maxwidth (term, margin_left, margin_right);
500
const grub_uint32_t *line_start = str, *last_space = str - 1;
502
for (ptr = str; ptr < last_position; ptr++)
504
grub_ssize_t last_width = 0;
505
if (grub_unicode_get_comb_type (*ptr) == GRUB_UNICODE_COMB_NONE)
507
struct grub_unicode_glyph c = {
514
line_width += last_width = grub_term_getcharwidth (term, &c);
519
lastspacewidth = line_width;
523
if (line_width > max_width || *ptr == '\n')
525
const grub_uint32_t *ptr2;
527
if (line_width > max_width && last_space > line_start)
529
else if (line_width > max_width
530
&& line_start == str && startwidth != 0)
533
lastspacewidth = startwidth;
536
lastspacewidth = line_width - last_width;
538
for (ptr2 = line_start; ptr2 < ptr; ptr2++)
540
/* Skip combining characters on non-UTF8 terminals. */
541
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
542
!= GRUB_TERM_CODE_TYPE_UTF8_LOGICAL
543
&& grub_unicode_get_comb_type (*ptr2)
544
!= GRUB_UNICODE_COMB_NONE)
546
putcode_real (*ptr2, term);
549
grub_print_spaces (term, margin_right);
550
grub_putcode ('\n', term);
551
if (state && ++state->num_lines
552
>= (grub_ssize_t) grub_term_height (term) - 2)
554
state->backlog_ucs4 = (ptr == last_space || *ptr == '\n')
556
state->backlog_len = last_position - state->backlog_ucs4;
560
line_width -= lastspacewidth;
561
grub_print_spaces (term, margin_left);
562
if (ptr == last_space || *ptr == '\n')
569
const grub_uint32_t *ptr2;
570
for (ptr2 = line_start; ptr2 < last_position; ptr2++)
572
/* Skip combining characters on non-UTF8 terminals. */
573
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
574
!= GRUB_TERM_CODE_TYPE_UTF8_LOGICAL
575
&& grub_unicode_get_comb_type (*ptr2)
576
!= GRUB_UNICODE_COMB_NONE)
578
putcode_real (*ptr2, term);
584
static struct term_state *
585
find_term_state (struct grub_term_output *term)
587
struct term_state *state;
588
for (state = term_states; state; state = state->next)
589
if (grub_strcmp (state->term_name, term->name) == 0)
592
state = grub_zalloc (sizeof (*state));
595
grub_errno = GRUB_ERR_NONE;
599
state->term_name = grub_strdup (term->name);
600
state->next = term_states;
607
put_glyphs_terminal (const struct grub_unicode_glyph *visual,
608
grub_ssize_t visual_len,
609
int margin_left, int margin_right,
610
struct grub_term_output *term,
611
struct term_state *state)
613
const struct grub_unicode_glyph *visual_ptr;
614
for (visual_ptr = visual; visual_ptr < visual + visual_len; visual_ptr++)
616
if (visual_ptr->base == '\n')
617
grub_print_spaces (term, margin_right);
618
putglyph (visual_ptr, term);
619
if (state && ++state->num_lines
620
>= (grub_ssize_t) grub_term_height (term) - 2)
622
state->backlog_glyphs = visual_ptr + 1;
623
state->backlog_len = visual_len - (visual - visual_ptr) - 1;
627
if (visual_ptr->base == '\n')
628
grub_print_spaces (term, margin_left);
629
grub_free (visual_ptr->combining);
635
print_backlog (struct grub_term_output *term,
636
int margin_left, int margin_right)
638
struct term_state *state = find_term_state (term);
643
if (state->backlog_ucs4)
646
ret = print_ucs4_terminal (state->backlog_ucs4,
647
state->backlog_ucs4 + state->backlog_len,
648
margin_left, margin_right, term, state);
651
grub_free (state->free);
653
state->backlog_len = 0;
658
if (state->backlog_glyphs)
661
ret = put_glyphs_terminal (state->backlog_glyphs,
663
margin_left, margin_right, term, state);
666
grub_free (state->free);
668
state->backlog_len = 0;
677
print_ucs4_real (const grub_uint32_t * str,
678
const grub_uint32_t * last_position,
679
int margin_left, int margin_right,
680
struct grub_term_output *term, int backlog)
682
struct term_state *state = NULL;
685
state = find_term_state (term);
687
if (((term->getxy (term) >> 8) & 0xff) < margin_left)
688
grub_print_spaces (term, margin_left - ((term->getxy (term) >> 8) & 0xff));
690
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
691
== GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS
692
|| (term->flags & GRUB_TERM_CODE_TYPE_MASK)
693
== GRUB_TERM_CODE_TYPE_UTF8_VISUAL)
695
grub_ssize_t visual_len;
696
struct grub_unicode_glyph *visual;
699
auto grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c);
700
grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c)
702
return grub_term_getcharwidth (term, c);
705
visual_len = grub_bidi_logical_to_visual (str, last_position - str,
706
&visual, getcharwidth,
710
get_startwidth (term,
717
ret = put_glyphs_terminal (visual, visual_len, margin_left, margin_right,
722
state->free = visual;
725
return print_ucs4_terminal (str, last_position, margin_left, margin_right,
730
grub_print_ucs4 (const grub_uint32_t * str,
731
const grub_uint32_t * last_position,
732
int margin_left, int margin_right,
733
struct grub_term_output *term)
735
print_ucs4_real (str, last_position, margin_left, margin_right,
741
grub_xputs_normal (const char *str)
743
grub_term_output_t term;
744
grub_uint32_t *unicode_str, *unicode_last_position;
746
grub_utf8_to_ucs4_alloc (str, &unicode_str,
747
&unicode_last_position);
751
grub_errno = GRUB_ERR_NONE;
755
FOR_ACTIVE_TERM_OUTPUTS(term)
758
cur = print_ucs4_real (unicode_str, unicode_last_position, 0, 0,
767
FOR_ACTIVE_TERM_OUTPUTS(term)
770
cur = print_backlog (term, 0, 0);
775
grub_free (unicode_str);
781
struct grub_term_output *term;
783
FOR_ACTIVE_TERM_OUTPUTS(term)
785
if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug")))
787
grub_putcode ('\n', term);
788
grub_term_refresh (term);