~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/normal/term.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

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