~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, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

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
}