~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

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