]> git.proxmox.com Git - grub2.git/blame - grub-core/normal/term.c
Move platform-dependent files from $prefix to $prefix/$platform.
[grub2.git] / grub-core / normal / term.c
CommitLineData
f4c623e1
VS
1/*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
2e713831
VS
19#include <grub/term.h>
20#include <grub/misc.h>
21#include <grub/mm.h>
33c1ed4c
VS
22#include <grub/file.h>
23#include <grub/dl.h>
24#include <grub/env.h>
25#include <grub/normal.h>
dfed5c6b 26#include <grub/charset.h>
6e0632e2 27#include <grub/i18n.h>
2e713831 28
6fcebede
VS
29struct term_state
30{
31 struct term_state *next;
3c69fb81
VS
32 const struct grub_unicode_glyph *backlog_glyphs;
33 const grub_uint32_t *backlog_ucs4;
34 grub_size_t backlog_len;
35
36 void *free;
37 int num_lines;
6fcebede
VS
38 char *term_name;
39};
40
3c69fb81
VS
41static struct term_state *term_states = NULL;
42
f4c623e1
VS
43/* If the more pager is active. */
44static int grub_more;
45
902f75f6
VS
46static void
47putcode_real (grub_uint32_t code, struct grub_term_output *term);
48
5c56cac9
VS
49void
50grub_normal_reset_more (void)
51{
52 static struct term_state *state;
53 for (state = term_states; state; state = state->next)
54 state->num_lines = 0;
55}
56
f4c623e1 57static void
3c69fb81 58print_more (void)
f4c623e1 59{
3c69fb81
VS
60 char key;
61 grub_uint16_t *pos;
62 grub_term_output_t term;
63 grub_uint32_t *unicode_str, *unicode_last_position;
2e713831 64
3c69fb81
VS
65 pos = grub_term_save_pos ();
66
6e0632e2
VS
67 /* TRANSLATORS: This has to fit on one line. It's ok to include few
68 words but don't write poems. */
69 grub_utf8_to_ucs4_alloc (_("--MORE--"), &unicode_str,
3c69fb81 70 &unicode_last_position);
2e713831 71
3c69fb81 72 if (!unicode_str)
f4c623e1 73 {
3c69fb81
VS
74 grub_errno = GRUB_ERR_NONE;
75 return;
76 }
2e713831 77
3c69fb81
VS
78 grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
79
80 FOR_ACTIVE_TERM_OUTPUTS(term)
81 {
82 grub_print_ucs4 (unicode_str, unicode_last_position, 0, 0, term);
83 }
9a9de209 84 grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
2e713831 85
3c69fb81
VS
86 grub_free (unicode_str);
87
88 key = grub_getkey ();
2e713831 89
3c69fb81
VS
90 /* Remove the message. */
91 grub_term_restore_pos (pos);
92 FOR_ACTIVE_TERM_OUTPUTS(term)
93 grub_print_spaces (term, 8);
94 grub_term_restore_pos (pos);
902f75f6 95 grub_free (pos);
2e713831 96
32570200 97 /* Scroll one line or an entire page, depending on the key. */
2e713831 98
5c56cac9 99 if (key == '\r' || key =='\n')
5c56cac9
VS
100 {
101 static struct term_state *state;
102 for (state = term_states; state; state = state->next)
32570200 103 state->num_lines--;
5c56cac9 104 }
32570200
CW
105 else
106 grub_normal_reset_more ();
f4c623e1
VS
107}
108
109void
110grub_set_more (int onoff)
111{
112 if (onoff == 1)
113 grub_more++;
114 else
115 grub_more--;
5c56cac9 116 grub_normal_reset_more ();
c6f2fe52
VS
117}
118
a68c4194
VS
119enum
120 {
121 GRUB_CP437_UPARROW = 0x18,
122 GRUB_CP437_DOWNARROW = 0x19,
123 GRUB_CP437_RIGHTARROW = 0x1a,
124 GRUB_CP437_LEFTARROW = 0x1b,
125 GRUB_CP437_VLINE = 0xb3,
126 GRUB_CP437_CORNER_UR = 0xbf,
127 GRUB_CP437_CORNER_LL = 0xc0,
128 GRUB_CP437_HLINE = 0xc4,
129 GRUB_CP437_CORNER_LR = 0xd9,
130 GRUB_CP437_CORNER_UL = 0xda,
131 };
132
09f9aa3b
VS
133static grub_uint32_t
134map_code (grub_uint32_t in, struct grub_term_output *term)
135{
136 if (in <= 0x7f)
137 return in;
138
139 switch (term->flags & GRUB_TERM_CODE_TYPE_MASK)
140 {
232dbbe5 141 case GRUB_TERM_CODE_TYPE_CP437:
09f9aa3b
VS
142 switch (in)
143 {
b764bff2 144 case GRUB_UNICODE_LEFTARROW:
a68c4194 145 return GRUB_CP437_LEFTARROW;
b764bff2 146 case GRUB_UNICODE_UPARROW:
a68c4194 147 return GRUB_CP437_UPARROW;
b764bff2 148 case GRUB_UNICODE_RIGHTARROW:
a68c4194 149 return GRUB_CP437_RIGHTARROW;
b764bff2 150 case GRUB_UNICODE_DOWNARROW:
a68c4194 151 return GRUB_CP437_DOWNARROW;
b764bff2 152 case GRUB_UNICODE_HLINE:
a68c4194 153 return GRUB_CP437_HLINE;
b764bff2 154 case GRUB_UNICODE_VLINE:
a68c4194 155 return GRUB_CP437_VLINE;
b764bff2 156 case GRUB_UNICODE_CORNER_UL:
a68c4194 157 return GRUB_CP437_CORNER_UL;
b764bff2 158 case GRUB_UNICODE_CORNER_UR:
a68c4194 159 return GRUB_CP437_CORNER_UR;
b764bff2 160 case GRUB_UNICODE_CORNER_LL:
a68c4194 161 return GRUB_CP437_CORNER_LL;
b764bff2 162 case GRUB_UNICODE_CORNER_LR:
a68c4194 163 return GRUB_CP437_CORNER_LR;
09f9aa3b
VS
164 }
165 return '?';
166 case GRUB_TERM_CODE_TYPE_ASCII:
167 /* Better than nothing. */
168 switch (in)
169 {
b764bff2 170 case GRUB_UNICODE_LEFTARROW:
09f9aa3b
VS
171 return '<';
172
b764bff2 173 case GRUB_UNICODE_UPARROW:
09f9aa3b
VS
174 return '^';
175
b764bff2 176 case GRUB_UNICODE_RIGHTARROW:
09f9aa3b
VS
177 return '>';
178
b764bff2 179 case GRUB_UNICODE_DOWNARROW:
09f9aa3b
VS
180 return 'v';
181
b764bff2 182 case GRUB_UNICODE_HLINE:
09f9aa3b
VS
183 return '-';
184
b764bff2 185 case GRUB_UNICODE_VLINE:
09f9aa3b
VS
186 return '|';
187
b764bff2
VS
188 case GRUB_UNICODE_CORNER_UL:
189 case GRUB_UNICODE_CORNER_UR:
190 case GRUB_UNICODE_CORNER_LL:
191 case GRUB_UNICODE_CORNER_LR:
09f9aa3b
VS
192 return '+';
193
194 }
195 return '?';
196 }
197 return in;
198}
199
f4c623e1
VS
200void
201grub_puts_terminal (const char *str, struct grub_term_output *term)
202{
81b0623a 203 grub_uint32_t *unicode_str, *unicode_last_position;
5303b85d 204 grub_error_push ();
81b0623a
VS
205 grub_utf8_to_ucs4_alloc (str, &unicode_str,
206 &unicode_last_position);
5303b85d 207 grub_error_pop ();
902f75f6
VS
208 if (!unicode_str)
209 {
5303b85d 210 for (; *str; str++)
902f75f6 211 {
5303b85d
VS
212 struct grub_unicode_glyph c =
213 {
214 .variant = 0,
215 .attributes = 0,
216 .ncomb = 0,
217 .combining = 0,
218 .estimated_width = 1,
219 .base = *str
220 };
902f75f6 221
5303b85d
VS
222 FOR_ACTIVE_TERM_OUTPUTS(term)
223 {
224 (term->putchar) (term, &c);
225 }
226 if (*str == '\n')
227 {
228 c.base = '\r';
229 FOR_ACTIVE_TERM_OUTPUTS(term)
230 {
231 (term->putchar) (term, &c);
232 }
233 }
902f75f6
VS
234 }
235 return;
236 }
f4c623e1 237
81b0623a
VS
238 grub_print_ucs4 (unicode_str, unicode_last_position, 0, 0, term);
239 grub_free (unicode_str);
f4c623e1
VS
240}
241
242grub_uint16_t *
243grub_term_save_pos (void)
244{
245 struct grub_term_output *cur;
246 unsigned cnt = 0;
247 grub_uint16_t *ret, *ptr;
248
3be7f8de
VS
249 FOR_ACTIVE_TERM_OUTPUTS(cur)
250 cnt++;
f4c623e1
VS
251
252 ret = grub_malloc (cnt * sizeof (ret[0]));
253 if (!ret)
254 return NULL;
255
2e713831 256 ptr = ret;
3be7f8de
VS
257 FOR_ACTIVE_TERM_OUTPUTS(cur)
258 *ptr++ = grub_term_getxy (cur);
f4c623e1
VS
259
260 return ret;
261}
262
263void
264grub_term_restore_pos (grub_uint16_t *pos)
265{
266 struct grub_term_output *cur;
2e713831 267 grub_uint16_t *ptr = pos;
f4c623e1
VS
268
269 if (!pos)
270 return;
271
3be7f8de
VS
272 FOR_ACTIVE_TERM_OUTPUTS(cur)
273 {
274 grub_term_gotoxy (cur, (*ptr & 0xff00) >> 8, *ptr & 0xff);
275 ptr++;
276 }
f4c623e1 277}
33c1ed4c
VS
278
279static void
280grub_terminal_autoload_free (void)
281{
282 struct grub_term_autoload *cur, *next;
283 unsigned i;
284 for (i = 0; i < 2; i++)
285 for (cur = i ? grub_term_input_autoload : grub_term_output_autoload;
286 cur; cur = next)
287 {
288 next = cur->next;
289 grub_free (cur->name);
290 grub_free (cur->modname);
291 grub_free (cur);
292 }
293 grub_term_input_autoload = NULL;
294 grub_term_output_autoload = NULL;
295}
296
33c1ed4c
VS
297/* Read the file terminal.lst for auto-loading. */
298void
027de555 299read_terminal_list (const char *prefix)
33c1ed4c 300{
33c1ed4c
VS
301 char *filename;
302 grub_file_t file;
303 char *buf = NULL;
304
33c1ed4c
VS
305 if (!prefix)
306 {
307 grub_errno = GRUB_ERR_NONE;
308 return;
309 }
310
92cd0f6e
VS
311 filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM
312 "/terminal.lst", prefix);
33c1ed4c
VS
313 if (!filename)
314 {
315 grub_errno = GRUB_ERR_NONE;
316 return;
317 }
318
33c1ed4c 319 file = grub_file_open (filename);
4a8a763c 320 grub_free (filename);
33c1ed4c
VS
321 if (!file)
322 {
323 grub_errno = GRUB_ERR_NONE;
324 return;
325 }
326
327 /* Override previous terminal.lst. */
328 grub_terminal_autoload_free ();
329
330 for (;; grub_free (buf))
331 {
332 char *p, *name;
333 struct grub_term_autoload *cur;
334 struct grub_term_autoload **target = NULL;
335
336 buf = grub_file_getline (file);
337
338 if (! buf)
339 break;
340
341 switch (buf[0])
342 {
343 case 'i':
344 target = &grub_term_input_autoload;
345 break;
346
347 case 'o':
348 target = &grub_term_output_autoload;
349 break;
350 }
351 if (!target)
352 continue;
353
354 name = buf + 1;
355
356 p = grub_strchr (name, ':');
357 if (! p)
358 continue;
359
360 *p = '\0';
361 while (*++p == ' ')
362 ;
363
364 cur = grub_malloc (sizeof (*cur));
365 if (!cur)
366 {
367 grub_errno = GRUB_ERR_NONE;
368 continue;
369 }
370
371 cur->name = grub_strdup (name);
372 if (! name)
373 {
374 grub_errno = GRUB_ERR_NONE;
375 grub_free (cur);
376 continue;
377 }
378
379 cur->modname = grub_strdup (p);
380 if (! cur->modname)
381 {
382 grub_errno = GRUB_ERR_NONE;
33c1ed4c 383 grub_free (cur->name);
e6d983ba 384 grub_free (cur);
33c1ed4c
VS
385 continue;
386 }
387 cur->next = *target;
388 *target = cur;
389 }
390
391 grub_file_close (file);
392
393 grub_errno = GRUB_ERR_NONE;
394}
09f9aa3b
VS
395
396static void
397putglyph (const struct grub_unicode_glyph *c, struct grub_term_output *term)
398{
399 struct grub_unicode_glyph c2 =
400 {
401 .variant = 0,
402 .attributes = 0,
403 .ncomb = 0,
404 .combining = 0,
405 .estimated_width = 1
406 };
407
408 if (c->base == '\t' && term->getxy)
409 {
410 int n;
411
58664b94 412 n = 8 - ((term->getxy (term) >> 8) & 7);
09f9aa3b
VS
413 c2.base = ' ';
414 while (n--)
58664b94 415 (term->putchar) (term, &c2);
09f9aa3b
VS
416
417 return;
418 }
419
420 if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
421 == GRUB_TERM_CODE_TYPE_UTF8_LOGICAL
422 || (term->flags & GRUB_TERM_CODE_TYPE_MASK)
423 == GRUB_TERM_CODE_TYPE_UTF8_VISUAL)
424 {
425 int i;
426 c2.estimated_width = grub_term_getcharwidth (term, c);
427 for (i = -1; i < (int) c->ncomb; i++)
428 {
429 grub_uint8_t u8[20], *ptr;
430 grub_uint32_t code;
431
432 if (i == -1)
433 {
434 code = c->base;
435 if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
a82890ff
VS
436 == GRUB_TERM_CODE_TYPE_UTF8_VISUAL)
437 {
438 if ((c->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR))
439 code = grub_unicode_mirror_code (code);
440 code = grub_unicode_shape_code (code, c->attributes);
441 }
09f9aa3b
VS
442 }
443 else
444 code = c->combining[i].code;
445
446 grub_ucs4_to_utf8 (&code, 1, u8, sizeof (u8));
447
448 for (ptr = u8; *ptr; ptr++)
449 {
450 c2.base = *ptr;
58664b94 451 (term->putchar) (term, &c2);
09f9aa3b
VS
452 c2.estimated_width = 0;
453 }
454 }
455 c2.estimated_width = 1;
456 }
457 else
58664b94 458 (term->putchar) (term, c);
09f9aa3b
VS
459
460 if (c->base == '\n')
461 {
462 c2.base = '\r';
58664b94 463 (term->putchar) (term, &c2);
09f9aa3b
VS
464 }
465}
466
467static void
468putcode_real (grub_uint32_t code, struct grub_term_output *term)
469{
470 struct grub_unicode_glyph c =
471 {
472 .variant = 0,
473 .attributes = 0,
474 .ncomb = 0,
475 .combining = 0,
476 .estimated_width = 1
477 };
478
479 c.base = map_code (code, term);
480 putglyph (&c, term);
481}
482
483/* Put a Unicode character. */
484void
485grub_putcode (grub_uint32_t code, struct grub_term_output *term)
486{
487 /* Combining character by itself? */
488 if (grub_unicode_get_comb_type (code) != GRUB_UNICODE_COMB_NONE)
489 return;
490
491 putcode_real (code, term);
492}
493
3c69fb81
VS
494static grub_ssize_t
495get_maxwidth (struct grub_term_output *term,
496 int margin_left, int margin_right)
497{
498 struct grub_unicode_glyph space_glyph = {
499 .base = ' ',
500 .variant = 0,
501 .attributes = 0,
502 .ncomb = 0,
503 .combining = 0
504 };
505 return (grub_term_width (term)
506 - grub_term_getcharwidth (term, &space_glyph)
507 * (margin_left + margin_right) - 1);
508}
509
510static grub_ssize_t
511get_startwidth (struct grub_term_output *term,
512 int margin_left)
09f9aa3b 513{
58664b94 514 return ((term->getxy (term) >> 8) & 0xff) - margin_left;
3c69fb81
VS
515}
516
517static int
518print_ucs4_terminal (const grub_uint32_t * str,
519 const grub_uint32_t * last_position,
520 int margin_left, int margin_right,
521 struct grub_term_output *term,
8b8a81fa
VS
522 struct term_state *state,
523 int dry_run)
3c69fb81
VS
524{
525 const grub_uint32_t *ptr;
8b8a81fa 526 grub_ssize_t startwidth = dry_run ? 0 : get_startwidth (term, margin_left);
3c69fb81
VS
527 grub_ssize_t line_width = startwidth;
528 grub_ssize_t lastspacewidth = 0;
529 grub_ssize_t max_width = get_maxwidth (term, margin_left, margin_right);
530 const grub_uint32_t *line_start = str, *last_space = str - 1;
8b8a81fa 531 int lines = 0;
3c69fb81
VS
532
533 for (ptr = str; ptr < last_position; ptr++)
534 {
535 grub_ssize_t last_width = 0;
536 if (grub_unicode_get_comb_type (*ptr) == GRUB_UNICODE_COMB_NONE)
537 {
538 struct grub_unicode_glyph c = {
539 .variant = 0,
540 .attributes = 0,
541 .ncomb = 0,
542 .combining = 0
543 };
544 c.base = *ptr;
545 line_width += last_width = grub_term_getcharwidth (term, &c);
546 }
547
548 if (*ptr == ' ')
549 {
550 lastspacewidth = line_width;
551 last_space = ptr;
552 }
553
554 if (line_width > max_width || *ptr == '\n')
555 {
556 const grub_uint32_t *ptr2;
557
558 if (line_width > max_width && last_space > line_start)
559 ptr = last_space;
560 else if (line_width > max_width
6a6f8058 561 && line_start == str && line_width - lastspacewidth < max_width - 5)
3c69fb81
VS
562 {
563 ptr = str;
564 lastspacewidth = startwidth;
565 }
566 else
567 lastspacewidth = line_width - last_width;
568
8b8a81fa 569 lines++;
3c69fb81 570
8b8a81fa 571 if (!dry_run)
3c69fb81 572 {
8b8a81fa
VS
573 for (ptr2 = line_start; ptr2 < ptr; ptr2++)
574 {
575 /* Skip combining characters on non-UTF8 terminals. */
576 if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
577 != GRUB_TERM_CODE_TYPE_UTF8_LOGICAL
578 && grub_unicode_get_comb_type (*ptr2)
579 != GRUB_UNICODE_COMB_NONE)
580 continue;
581 putcode_real (*ptr2, term);
582 }
583
584 grub_print_spaces (term, margin_right);
585 grub_putcode ('\n', term);
586 if (state && ++state->num_lines
587 >= (grub_ssize_t) grub_term_height (term) - 2)
588 {
589 state->backlog_ucs4 = (ptr == last_space || *ptr == '\n')
590 ? ptr + 1 : ptr;
591 state->backlog_len = last_position - state->backlog_ucs4;
592 return 1;
593 }
3c69fb81
VS
594 }
595
596 line_width -= lastspacewidth;
8b8a81fa
VS
597 if (!dry_run)
598 grub_print_spaces (term, margin_left);
3c69fb81
VS
599 if (ptr == last_space || *ptr == '\n')
600 ptr++;
601 line_start = ptr;
602 }
603 }
09f9aa3b 604
8b8a81fa
VS
605 if (line_start < last_position)
606 lines++;
607 if (!dry_run)
608 {
609 const grub_uint32_t *ptr2;
610 for (ptr2 = line_start; ptr2 < last_position; ptr2++)
611 {
612 /* Skip combining characters on non-UTF8 terminals. */
613 if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
614 != GRUB_TERM_CODE_TYPE_UTF8_LOGICAL
615 && grub_unicode_get_comb_type (*ptr2)
616 != GRUB_UNICODE_COMB_NONE)
617 continue;
618 putcode_real (*ptr2, term);
619 }
620 }
621 return dry_run ? lines : 0;
3c69fb81
VS
622}
623
624static struct term_state *
625find_term_state (struct grub_term_output *term)
626{
627 struct term_state *state;
628 for (state = term_states; state; state = state->next)
629 if (grub_strcmp (state->term_name, term->name) == 0)
630 return state;
631
632 state = grub_zalloc (sizeof (*state));
633 if (!state)
634 {
635 grub_errno = GRUB_ERR_NONE;
636 return NULL;
637 }
638
639 state->term_name = grub_strdup (term->name);
640 state->next = term_states;
641 term_states = state;
642
643 return state;
644}
645
646static int
647put_glyphs_terminal (const struct grub_unicode_glyph *visual,
648 grub_ssize_t visual_len,
649 int margin_left, int margin_right,
650 struct grub_term_output *term,
651 struct term_state *state)
652{
653 const struct grub_unicode_glyph *visual_ptr;
654 for (visual_ptr = visual; visual_ptr < visual + visual_len; visual_ptr++)
655 {
656 if (visual_ptr->base == '\n')
657 grub_print_spaces (term, margin_right);
658 putglyph (visual_ptr, term);
3c69fb81 659 if (visual_ptr->base == '\n')
249975ba
VS
660 {
661 if (state && ++state->num_lines
662 >= (grub_ssize_t) grub_term_height (term) - 2)
663 {
664 state->backlog_glyphs = visual_ptr + 1;
d547dc28 665 state->backlog_len = visual_len - (visual_ptr - visual) - 1;
249975ba
VS
666 return 1;
667 }
668
669 grub_print_spaces (term, margin_left);
670 }
3c69fb81
VS
671 grub_free (visual_ptr->combining);
672 }
673 return 0;
674}
675
676static int
677print_backlog (struct grub_term_output *term,
678 int margin_left, int margin_right)
679{
680 struct term_state *state = find_term_state (term);
681
682 if (!state)
683 return 0;
684
685 if (state->backlog_ucs4)
686 {
687 int ret;
688 ret = print_ucs4_terminal (state->backlog_ucs4,
689 state->backlog_ucs4 + state->backlog_len,
8b8a81fa 690 margin_left, margin_right, term, state, 0);
3c69fb81
VS
691 if (!ret)
692 {
693 grub_free (state->free);
694 state->free = NULL;
695 state->backlog_len = 0;
d547dc28 696 state->backlog_ucs4 = 0;
3c69fb81
VS
697 }
698 return ret;
699 }
700
701 if (state->backlog_glyphs)
702 {
703 int ret;
704 ret = put_glyphs_terminal (state->backlog_glyphs,
705 state->backlog_len,
706 margin_left, margin_right, term, state);
707 if (!ret)
708 {
709 grub_free (state->free);
710 state->free = NULL;
711 state->backlog_len = 0;
d547dc28 712 state->backlog_glyphs = 0;
3c69fb81
VS
713 }
714 return ret;
715 }
716
717 return 0;
718}
719
720static int
721print_ucs4_real (const grub_uint32_t * str,
722 const grub_uint32_t * last_position,
723 int margin_left, int margin_right,
8b8a81fa
VS
724 struct grub_term_output *term, int backlog,
725 int dry_run)
3c69fb81
VS
726{
727 struct term_state *state = NULL;
728
8b8a81fa
VS
729 if (!dry_run)
730 {
731 if (backlog)
732 state = find_term_state (term);
09f9aa3b 733
8b8a81fa
VS
734 if (((term->getxy (term) >> 8) & 0xff) < margin_left)
735 grub_print_spaces (term, margin_left - ((term->getxy (term) >> 8) & 0xff));
736 }
09f9aa3b 737
09f9aa3b
VS
738 if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
739 == GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS
740 || (term->flags & GRUB_TERM_CODE_TYPE_MASK)
741 == GRUB_TERM_CODE_TYPE_UTF8_VISUAL)
742 {
743 grub_ssize_t visual_len;
744 struct grub_unicode_glyph *visual;
3c69fb81 745 int ret;
09f9aa3b
VS
746
747 auto grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c);
748 grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c)
749 {
750 return grub_term_getcharwidth (term, c);
751 }
752
753 visual_len = grub_bidi_logical_to_visual (str, last_position - str,
754 &visual, getcharwidth,
3c69fb81
VS
755 get_maxwidth (term,
756 margin_left,
757 margin_right),
758 get_startwidth (term,
759 margin_left));
09f9aa3b
VS
760 if (visual_len < 0)
761 {
762 grub_print_error ();
3c69fb81 763 return 0;
09f9aa3b 764 }
8b8a81fa
VS
765 if (dry_run)
766 {
767 struct grub_unicode_glyph *vptr;
768 ret = 0;
769 for (vptr = visual; vptr < visual + visual_len; vptr++)
770 if (vptr->base == '\n')
771 ret++;
772 if (visual_len && visual[visual_len - 1].base != '\n')
773 ret++;
774 grub_free (visual);
775 }
3c69fb81 776 else
8b8a81fa
VS
777 {
778 ret = put_glyphs_terminal (visual, visual_len, margin_left,
779 margin_right, term, state);
780 if (!ret)
781 grub_free (visual);
782 else
783 state->free = visual;
784 }
3c69fb81 785 return ret;
09f9aa3b 786 }
3c69fb81 787 return print_ucs4_terminal (str, last_position, margin_left, margin_right,
8b8a81fa 788 term, state, dry_run);
3c69fb81 789}
09f9aa3b 790
3c69fb81
VS
791void
792grub_print_ucs4 (const grub_uint32_t * str,
793 const grub_uint32_t * last_position,
794 int margin_left, int margin_right,
795 struct grub_term_output *term)
796{
797 print_ucs4_real (str, last_position, margin_left, margin_right,
8b8a81fa 798 term, 0, 0);
09f9aa3b
VS
799}
800
8b8a81fa
VS
801int
802grub_ucs4_count_lines (const grub_uint32_t * str,
803 const grub_uint32_t * last_position,
804 int margin_left, int margin_right,
805 struct grub_term_output *term)
806{
807 return print_ucs4_real (str, last_position, margin_left, margin_right,
808 term, 0, 1);
809}
3c69fb81 810
09f9aa3b
VS
811void
812grub_xputs_normal (const char *str)
813{
5303b85d 814 grub_uint32_t *unicode_str = NULL, *unicode_last_position;
3c69fb81 815 int backlog = 0;
5303b85d
VS
816 grub_term_output_t term;
817
818 grub_error_push ();
81b0623a 819 grub_utf8_to_ucs4_alloc (str, &unicode_str,
5303b85d
VS
820 &unicode_last_position);
821 grub_error_pop ();
09f9aa3b 822
3c69fb81
VS
823 if (!unicode_str)
824 {
902f75f6
VS
825 for (; *str; str++)
826 {
5303b85d
VS
827 struct grub_unicode_glyph c =
828 {
829 .variant = 0,
830 .attributes = 0,
831 .ncomb = 0,
832 .combining = 0,
833 .estimated_width = 1,
834 .base = *str
835 };
902f75f6
VS
836
837 FOR_ACTIVE_TERM_OUTPUTS(term)
838 {
5303b85d 839 (term->putchar) (term, &c);
902f75f6 840 }
5303b85d
VS
841 if (*str == '\n')
842 {
843 c.base = '\r';
844 FOR_ACTIVE_TERM_OUTPUTS(term)
845 {
846 (term->putchar) (term, &c);
847 }
848 }
902f75f6
VS
849 }
850
3c69fb81
VS
851 return;
852 }
853
09f9aa3b
VS
854 FOR_ACTIVE_TERM_OUTPUTS(term)
855 {
3c69fb81
VS
856 int cur;
857 cur = print_ucs4_real (unicode_str, unicode_last_position, 0, 0,
8b8a81fa 858 term, grub_more, 0);
3c69fb81
VS
859 if (cur)
860 backlog = 1;
09f9aa3b 861 }
3c69fb81
VS
862 while (backlog)
863 {
864 print_more ();
865 backlog = 0;
866 FOR_ACTIVE_TERM_OUTPUTS(term)
867 {
868 int cur;
869 cur = print_backlog (term, 0, 0);
870 if (cur)
871 backlog = 1;
872 }
873 }
81b0623a 874 grub_free (unicode_str);
09f9aa3b 875}
919e37b0
VS
876
877void
878grub_cls (void)
879{
880 struct grub_term_output *term;
881
882 FOR_ACTIVE_TERM_OUTPUTS(term)
883 {
884 if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug")))
885 {
886 grub_putcode ('\n', term);
887 grub_term_refresh (term);
888 }
889 else
890 (term->cls) (term);
891 }
892}