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

« back to all changes in this revision

Viewing changes to grub-core/term/terminfo.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
/* terminfo.c - simple terminfo module */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2003,2004,2005,2007  Free Software Foundation, Inc.
 
5
 *
 
6
 *  GRUB is free software: you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  GRUB is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
/*
 
21
 * This file contains various functions dealing with different
 
22
 * terminal capabilities. For example, vt52 and vt100.
 
23
 */
 
24
 
 
25
#include <grub/types.h>
 
26
#include <grub/misc.h>
 
27
#include <grub/mm.h>
 
28
#include <grub/err.h>
 
29
#include <grub/dl.h>
 
30
#include <grub/term.h>
 
31
#include <grub/terminfo.h>
 
32
#include <grub/tparm.h>
 
33
#include <grub/extcmd.h>
 
34
#include <grub/i18n.h>
 
35
#include <grub/time.h>
 
36
 
 
37
static struct grub_term_output *terminfo_outputs;
 
38
 
 
39
/* Get current terminfo name.  */
 
40
char *
 
41
grub_terminfo_get_current (struct grub_term_output *term)
 
42
{
 
43
  struct grub_terminfo_output_state *data
 
44
    = (struct grub_terminfo_output_state *) term->data;
 
45
  return data->name;
 
46
}
 
47
 
 
48
/* Free *PTR and set *PTR to NULL, to prevent double-free.  */
 
49
static void
 
50
grub_terminfo_free (char **ptr)
 
51
{
 
52
  grub_free (*ptr);
 
53
  *ptr = 0;
 
54
}
 
55
 
 
56
static void
 
57
grub_terminfo_all_free (struct grub_term_output *term)
 
58
{
 
59
  struct grub_terminfo_output_state *data
 
60
    = (struct grub_terminfo_output_state *) term->data;
 
61
 
 
62
  /* Free previously allocated memory.  */
 
63
  grub_terminfo_free (&data->name);
 
64
  grub_terminfo_free (&data->gotoxy);
 
65
  grub_terminfo_free (&data->cls);
 
66
  grub_terminfo_free (&data->reverse_video_on);
 
67
  grub_terminfo_free (&data->reverse_video_off);
 
68
  grub_terminfo_free (&data->cursor_on);
 
69
  grub_terminfo_free (&data->cursor_off);
 
70
}
 
71
 
 
72
/* Set current terminfo type.  */
 
73
grub_err_t
 
74
grub_terminfo_set_current (struct grub_term_output *term,
 
75
                           const char *str)
 
76
{
 
77
  struct grub_terminfo_output_state *data
 
78
    = (struct grub_terminfo_output_state *) term->data;
 
79
  /* TODO
 
80
   * Lookup user specified terminfo type. If found, set term variables
 
81
   * as appropriate. Otherwise return an error.
 
82
   *
 
83
   * How should this be done?
 
84
   *  a. A static table included in this module.
 
85
   *     - I do not like this idea.
 
86
   *  b. A table stored in the configuration directory.
 
87
   *     - Users must convert their terminfo settings if we have not already.
 
88
   *  c. Look for terminfo files in the configuration directory.
 
89
   *     - /usr/share/terminfo is 6.3M on my system.
 
90
   *     - /usr/share/terminfo is not on most users boot partition.
 
91
   *     + Copying the terminfo files you want to use to the grub
 
92
   *       configuration directory is easier then (b).
 
93
   *  d. Your idea here.
 
94
   */
 
95
 
 
96
  grub_terminfo_all_free (term);
 
97
 
 
98
  if (grub_strcmp ("vt100", str) == 0)
 
99
    {
 
100
      data->name              = grub_strdup ("vt100");
 
101
      data->gotoxy            = grub_strdup ("\e[%i%p1%d;%p2%dH");
 
102
      data->cls               = grub_strdup ("\e[H\e[J");
 
103
      data->reverse_video_on  = grub_strdup ("\e[7m");
 
104
      data->reverse_video_off = grub_strdup ("\e[m");
 
105
      data->cursor_on         = grub_strdup ("\e[?25h");
 
106
      data->cursor_off        = grub_strdup ("\e[?25l");
 
107
      data->setcolor          = NULL;
 
108
      return grub_errno;
 
109
    }
 
110
 
 
111
  if (grub_strcmp ("vt100-color", str) == 0)
 
112
    {
 
113
      data->name              = grub_strdup ("vt100-color");
 
114
      data->gotoxy            = grub_strdup ("\e[%i%p1%d;%p2%dH");
 
115
      data->cls               = grub_strdup ("\e[H\e[J");
 
116
      data->reverse_video_on  = grub_strdup ("\e[7m");
 
117
      data->reverse_video_off = grub_strdup ("\e[m");
 
118
      data->cursor_on         = grub_strdup ("\e[?25h");
 
119
      data->cursor_off        = grub_strdup ("\e[?25l");
 
120
      data->setcolor          = grub_strdup ("\e[3%p1%dm\e[4%p2%dm");
 
121
      return grub_errno;
 
122
    }
 
123
 
 
124
  if (grub_strcmp ("ieee1275", str) == 0)
 
125
    {
 
126
      data->name              = grub_strdup ("ieee1275");
 
127
      data->gotoxy            = grub_strdup ("\e[%i%p1%d;%p2%dH");
 
128
      /* Clear the screen.  Using serial console, screen(1) only recognizes the
 
129
       * ANSI escape sequence.  Using video console, Apple Open Firmware
 
130
       * (version 3.1.1) only recognizes the literal ^L.  So use both.  */
 
131
      data->cls               = grub_strdup (" \e[2J");
 
132
      data->reverse_video_on  = grub_strdup ("\e[7m");
 
133
      data->reverse_video_off = grub_strdup ("\e[m");
 
134
      data->cursor_on         = grub_strdup ("\e[?25h");
 
135
      data->cursor_off        = grub_strdup ("\e[?25l");
 
136
      data->setcolor          = grub_strdup ("\e[3%p1%dm\e[4%p2%dm");
 
137
      return grub_errno;
 
138
    }
 
139
 
 
140
  if (grub_strcmp ("dumb", str) == 0)
 
141
    {
 
142
      data->name              = grub_strdup ("dumb");
 
143
      data->gotoxy            = NULL;
 
144
      data->cls               = NULL;
 
145
      data->reverse_video_on  = NULL;
 
146
      data->reverse_video_off = NULL;
 
147
      data->cursor_on         = NULL;
 
148
      data->cursor_off        = NULL;
 
149
      data->setcolor          = NULL;
 
150
      return grub_errno;
 
151
    }
 
152
 
 
153
  return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminfo type");
 
154
}
 
155
 
 
156
grub_err_t
 
157
grub_terminfo_output_register (struct grub_term_output *term,
 
158
                               const char *type)
 
159
{
 
160
  grub_err_t err;
 
161
  struct grub_terminfo_output_state *data;
 
162
 
 
163
  err = grub_terminfo_set_current (term, type);
 
164
 
 
165
  if (err)
 
166
    return err;
 
167
 
 
168
  data = (struct grub_terminfo_output_state *) term->data;
 
169
  data->next = terminfo_outputs;
 
170
  terminfo_outputs = term;
 
171
 
 
172
  return GRUB_ERR_NONE;
 
173
}
 
174
 
 
175
grub_err_t
 
176
grub_terminfo_output_unregister (struct grub_term_output *term)
 
177
{
 
178
  struct grub_term_output **ptr;
 
179
 
 
180
  for (ptr = &terminfo_outputs; *ptr;
 
181
       ptr = &((struct grub_terminfo_output_state *) (*ptr)->data)->next)
 
182
    if (*ptr == term)
 
183
      {
 
184
        grub_terminfo_all_free (term);
 
185
        *ptr = ((struct grub_terminfo_output_state *) (*ptr)->data)->next;
 
186
        return GRUB_ERR_NONE;
 
187
      }
 
188
  return grub_error (GRUB_ERR_BAD_ARGUMENT, "terminal not found");
 
189
}
 
190
 
 
191
/* Wrapper for grub_putchar to write strings.  */
 
192
static void
 
193
putstr (struct grub_term_output *term, const char *str)
 
194
{
 
195
  struct grub_terminfo_output_state *data
 
196
    = (struct grub_terminfo_output_state *) term->data;
 
197
  while (*str)
 
198
    data->put (term, *str++);
 
199
}
 
200
 
 
201
grub_uint16_t
 
202
grub_terminfo_getxy (struct grub_term_output *term)
 
203
{
 
204
  struct grub_terminfo_output_state *data
 
205
    = (struct grub_terminfo_output_state *) term->data;
 
206
 
 
207
  return ((data->xpos << 8) | data->ypos);
 
208
}
 
209
 
 
210
void
 
211
grub_terminfo_gotoxy (struct grub_term_output *term,
 
212
                      grub_uint8_t x, grub_uint8_t y)
 
213
{
 
214
  struct grub_terminfo_output_state *data
 
215
    = (struct grub_terminfo_output_state *) term->data;
 
216
 
 
217
  if (x > grub_term_width (term) || y > grub_term_height (term))
 
218
    {
 
219
      grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", x, y);
 
220
      return;
 
221
    }
 
222
 
 
223
  if (data->gotoxy)
 
224
    putstr (term, grub_terminfo_tparm (data->gotoxy, y, x));
 
225
  else
 
226
    {
 
227
      if ((y == data->ypos) && (x == data->xpos - 1))
 
228
        data->put (term, '\b');
 
229
    }
 
230
 
 
231
  data->xpos = x;
 
232
  data->ypos = y;
 
233
}
 
234
 
 
235
/* Clear the screen.  */
 
236
void
 
237
grub_terminfo_cls (struct grub_term_output *term)
 
238
{
 
239
  struct grub_terminfo_output_state *data
 
240
    = (struct grub_terminfo_output_state *) term->data;
 
241
 
 
242
  putstr (term, grub_terminfo_tparm (data->cls));
 
243
 
 
244
  data->xpos = data->ypos = 0;
 
245
}
 
246
 
 
247
void
 
248
grub_terminfo_setcolorstate (struct grub_term_output *term,
 
249
                             const grub_term_color_state state)
 
250
{
 
251
  struct grub_terminfo_output_state *data
 
252
    = (struct grub_terminfo_output_state *) term->data;
 
253
 
 
254
  if (data->setcolor)
 
255
    {
 
256
      int fg;
 
257
      int bg;
 
258
      /* Map from VGA to terminal colors.  */
 
259
      const int colormap[8] 
 
260
        = { 0, /* Black. */
 
261
            4, /* Blue. */
 
262
            2, /* Green. */
 
263
            6, /* Cyan. */
 
264
            1, /* Red.  */
 
265
            5, /* Magenta.  */
 
266
            3, /* Yellow.  */
 
267
            7, /* White.  */
 
268
      };
 
269
 
 
270
      switch (state)
 
271
        {
 
272
        case GRUB_TERM_COLOR_STANDARD:
 
273
        case GRUB_TERM_COLOR_NORMAL:
 
274
          fg = term->normal_color & 0x0f;
 
275
          bg = term->normal_color >> 4;
 
276
          break;
 
277
        case GRUB_TERM_COLOR_HIGHLIGHT:
 
278
          fg = term->highlight_color & 0x0f;
 
279
          bg = term->highlight_color >> 4;
 
280
          break;
 
281
        default:
 
282
          return;
 
283
        }
 
284
 
 
285
      putstr (term, grub_terminfo_tparm (data->setcolor, colormap[fg & 7],
 
286
                                         colormap[bg & 7]));
 
287
      return;
 
288
    }
 
289
 
 
290
  switch (state)
 
291
    {
 
292
    case GRUB_TERM_COLOR_STANDARD:
 
293
    case GRUB_TERM_COLOR_NORMAL:
 
294
      putstr (term, grub_terminfo_tparm (data->reverse_video_off));
 
295
      break;
 
296
    case GRUB_TERM_COLOR_HIGHLIGHT:
 
297
      putstr (term, grub_terminfo_tparm (data->reverse_video_on));
 
298
      break;
 
299
    default:
 
300
      break;
 
301
    }
 
302
}
 
303
 
 
304
void
 
305
grub_terminfo_setcursor (struct grub_term_output *term, const int on)
 
306
{
 
307
  struct grub_terminfo_output_state *data
 
308
    = (struct grub_terminfo_output_state *) term->data;
 
309
 
 
310
  if (on)
 
311
    putstr (term, grub_terminfo_tparm (data->cursor_on));
 
312
  else
 
313
    putstr (term, grub_terminfo_tparm (data->cursor_off));
 
314
}
 
315
 
 
316
/* The terminfo version of putchar.  */
 
317
void
 
318
grub_terminfo_putchar (struct grub_term_output *term,
 
319
                       const struct grub_unicode_glyph *c)
 
320
{
 
321
  struct grub_terminfo_output_state *data
 
322
    = (struct grub_terminfo_output_state *) term->data;
 
323
 
 
324
  /* Keep track of the cursor.  */
 
325
  switch (c->base)
 
326
    {
 
327
    case '\a':
 
328
      break;
 
329
 
 
330
    case '\b':
 
331
    case 127:
 
332
      if (data->xpos > 0)
 
333
        data->xpos--;
 
334
    break;
 
335
 
 
336
    case '\n':
 
337
      if (data->ypos < grub_term_height (term) - 1)
 
338
        data->ypos++;
 
339
      break;
 
340
 
 
341
    case '\r':
 
342
      data->xpos = 0;
 
343
      break;
 
344
 
 
345
    default:
 
346
      if (data->xpos + c->estimated_width >= grub_term_width (term) + 1)
 
347
        {
 
348
          data->xpos = 0;
 
349
          if (data->ypos < grub_term_height (term) - 1)
 
350
            data->ypos++;
 
351
          data->put (term, '\r');
 
352
          data->put (term, '\n');
 
353
        }
 
354
      data->xpos += c->estimated_width;
 
355
      break;
 
356
    }
 
357
 
 
358
  data->put (term, c->base);
 
359
}
 
360
 
 
361
grub_uint16_t
 
362
grub_terminfo_getwh (struct grub_term_output *term)
 
363
{
 
364
  struct grub_terminfo_output_state *data
 
365
    = (struct grub_terminfo_output_state *) term->data;
 
366
 
 
367
  return (data->width << 8) | data->height;
 
368
}
 
369
 
 
370
#define ANSI_C0 0x9b
 
371
 
 
372
static void
 
373
grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len,
 
374
                       int (*readkey) (struct grub_term_input *term))
 
375
{
 
376
  int c;
 
377
 
 
378
#define CONTINUE_READ                                           \
 
379
  {                                                             \
 
380
    grub_uint64_t start;                                        \
 
381
    /* On 9600 we have to wait up to 12 milliseconds.  */       \
 
382
    start = grub_get_time_ms ();                                \
 
383
    do                                                          \
 
384
      c = readkey (term);                                       \
 
385
    while (c == -1 && grub_get_time_ms () - start < 12);        \
 
386
    if (c == -1)                                                \
 
387
      return;                                                   \
 
388
                                                                \
 
389
    keys[*len] = c;                                             \
 
390
    (*len)++;                                                   \
 
391
  }
 
392
 
 
393
  c = readkey (term);
 
394
  if (c < 0)
 
395
    {
 
396
      *len = 0;
 
397
      return;
 
398
    }
 
399
  *len = 1;
 
400
  keys[0] = c;
 
401
  if (c != ANSI_C0 && c != '\e')
 
402
    {
 
403
      /* Backspace: Ctrl-h.  */
 
404
      if (c == 0x7f)
 
405
        c = '\b'; 
 
406
      *len = 1;
 
407
      keys[0] = c;
 
408
      return;
 
409
    }
 
410
 
 
411
  {
 
412
    static struct
 
413
    {
 
414
      char key;
 
415
      unsigned ascii;
 
416
    }
 
417
    three_code_table[] =
 
418
      {
 
419
        {'4', GRUB_TERM_KEY_DC},
 
420
        {'A', GRUB_TERM_KEY_UP},
 
421
        {'B', GRUB_TERM_KEY_DOWN},
 
422
        {'C', GRUB_TERM_KEY_RIGHT},
 
423
        {'D', GRUB_TERM_KEY_LEFT},
 
424
        {'F', GRUB_TERM_KEY_END},
 
425
        {'H', GRUB_TERM_KEY_HOME},
 
426
        {'K', GRUB_TERM_KEY_END},
 
427
        {'P', GRUB_TERM_KEY_DC},
 
428
        {'?', GRUB_TERM_KEY_PPAGE},
 
429
        {'/', GRUB_TERM_KEY_NPAGE}
 
430
      };
 
431
 
 
432
    static struct
 
433
    {
 
434
      char key;
 
435
      unsigned ascii;
 
436
    }
 
437
    four_code_table[] =
 
438
      {
 
439
        {'1', GRUB_TERM_KEY_HOME},
 
440
        {'3', GRUB_TERM_KEY_DC},
 
441
        {'5', GRUB_TERM_KEY_PPAGE},
 
442
        {'6', GRUB_TERM_KEY_NPAGE}
 
443
      };
 
444
    unsigned i;
 
445
 
 
446
    if (c == '\e')
 
447
      {
 
448
        CONTINUE_READ;
 
449
 
 
450
        if (c != '[')
 
451
          return;
 
452
      }
 
453
 
 
454
    CONTINUE_READ;
 
455
        
 
456
    for (i = 0; i < ARRAY_SIZE (three_code_table); i++)
 
457
      if (three_code_table[i].key == c)
 
458
        {
 
459
          keys[0] = three_code_table[i].ascii;
 
460
          *len = 1;
 
461
          return;
 
462
        }
 
463
 
 
464
    for (i = 0; i < ARRAY_SIZE (four_code_table); i++)
 
465
      if (four_code_table[i].key == c)
 
466
        {
 
467
          CONTINUE_READ;
 
468
          if (c != '~')
 
469
            return;
 
470
          keys[0] = three_code_table[i].ascii;
 
471
          *len = 1;
 
472
          return;
 
473
        }
 
474
    return;
 
475
  }
 
476
#undef CONTINUE_READ
 
477
}
 
478
 
 
479
/* The terminfo version of getkey.  */
 
480
int
 
481
grub_terminfo_getkey (struct grub_term_input *termi)
 
482
{
 
483
  struct grub_terminfo_input_state *data
 
484
    = (struct grub_terminfo_input_state *) (termi->data);
 
485
  if (data->npending)
 
486
    {
 
487
      data->npending--;
 
488
      grub_memmove (data->input_buf, data->input_buf + 1, data->npending);
 
489
      return data->input_buf[0];
 
490
    }
 
491
 
 
492
  grub_terminfo_readkey (termi, data->input_buf,
 
493
                         &data->npending, data->readkey);
 
494
 
 
495
  if (data->npending)
 
496
    {
 
497
      data->npending--;
 
498
      grub_memmove (data->input_buf, data->input_buf + 1, data->npending);
 
499
      return data->input_buf[0];
 
500
    }
 
501
 
 
502
  return GRUB_TERM_NO_KEY;
 
503
}
 
504
 
 
505
grub_err_t
 
506
grub_terminfo_input_init (struct grub_term_input *termi)
 
507
{
 
508
  struct grub_terminfo_input_state *data
 
509
    = (struct grub_terminfo_input_state *) (termi->data);
 
510
  data->npending = 0;
 
511
 
 
512
  return GRUB_ERR_NONE;
 
513
}
 
514
 
 
515
/* GRUB Command.  */
 
516
 
 
517
static grub_err_t
 
518
print_terminfo (void)
 
519
{
 
520
  const char *encoding_names[(GRUB_TERM_CODE_TYPE_MASK 
 
521
                              >> GRUB_TERM_CODE_TYPE_SHIFT) + 1]
 
522
    = {
 
523
    /* VGA and glyph descriptor types are just for completeness,
 
524
       they are not used on terminfo terminals.
 
525
    */
 
526
    [GRUB_TERM_CODE_TYPE_ASCII >> GRUB_TERM_CODE_TYPE_SHIFT] = _("ASCII"),
 
527
    [GRUB_TERM_CODE_TYPE_CP437 >> GRUB_TERM_CODE_TYPE_SHIFT] = "CP-437",
 
528
    [GRUB_TERM_CODE_TYPE_UTF8_LOGICAL >> GRUB_TERM_CODE_TYPE_SHIFT]
 
529
    = _("UTF-8"),
 
530
    [GRUB_TERM_CODE_TYPE_UTF8_VISUAL >> GRUB_TERM_CODE_TYPE_SHIFT]
 
531
    = _("UTF-8 visual"),
 
532
    [GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS >> GRUB_TERM_CODE_TYPE_SHIFT]
 
533
    = "Glyph descriptors",
 
534
    _("Unknown"), _("Unknown"), _("Unknown")
 
535
  };
 
536
  struct grub_term_output *cur;
 
537
 
 
538
  grub_printf ("Current terminfo types: \n");
 
539
  for (cur = terminfo_outputs; cur;
 
540
       cur = ((struct grub_terminfo_output_state *) cur->data)->next)
 
541
    grub_printf ("%s: %s\t%s\n", cur->name,
 
542
                 grub_terminfo_get_current(cur),
 
543
                 encoding_names[(cur->flags & GRUB_TERM_CODE_TYPE_MASK)
 
544
                                >> GRUB_TERM_CODE_TYPE_SHIFT]);
 
545
 
 
546
  return GRUB_ERR_NONE;
 
547
}
 
548
 
 
549
static const struct grub_arg_option options[] =
 
550
{
 
551
  {"ascii", 'a', 0, N_("Terminal is ASCII-only [default]."),  0, ARG_TYPE_NONE},
 
552
  {"utf8",  'u', 0, N_("Terminal is logical-ordered UTF-8."), 0, ARG_TYPE_NONE},
 
553
  {"visual-utf8", 'v', 0, N_("Terminal is visually-ordered UTF-8."), 0,
 
554
   ARG_TYPE_NONE},
 
555
  {"geometry", 'g', 0, N_("Terminal has given geometry."),
 
556
   N_("WIDTHxHEIGHT."), ARG_TYPE_STRING},
 
557
  {0, 0, 0, 0, 0, 0}
 
558
};
 
559
 
 
560
enum
 
561
  {
 
562
    OPTION_ASCII,
 
563
    OPTION_UTF8,
 
564
    OPTION_VISUAL_UTF8,
 
565
    OPTION_GEOMETRY
 
566
  };
 
567
 
 
568
static grub_err_t
 
569
grub_cmd_terminfo (grub_extcmd_context_t ctxt, int argc, char **args)
 
570
{
 
571
  struct grub_term_output *cur;
 
572
  int encoding = GRUB_TERM_CODE_TYPE_ASCII;
 
573
  struct grub_arg_list *state = ctxt->state;
 
574
  int w = 0, h = 0;
 
575
 
 
576
  if (argc == 0)
 
577
    return print_terminfo ();
 
578
 
 
579
  if (state[OPTION_ASCII].set)
 
580
    encoding = GRUB_TERM_CODE_TYPE_ASCII;
 
581
 
 
582
  if (state[OPTION_UTF8].set)
 
583
    encoding = GRUB_TERM_CODE_TYPE_UTF8_LOGICAL;
 
584
 
 
585
  if (state[OPTION_VISUAL_UTF8].set)
 
586
    encoding = GRUB_TERM_CODE_TYPE_UTF8_VISUAL;
 
587
 
 
588
  if (state[OPTION_GEOMETRY].set)
 
589
    {
 
590
      char *ptr = state[OPTION_GEOMETRY].arg;
 
591
      w = grub_strtoul (ptr, &ptr, 0);
 
592
      if (grub_errno)
 
593
        return grub_errno;
 
594
      if (*ptr != 'x')
 
595
        return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
596
                           "incorrect geometry specification");
 
597
      ptr++;
 
598
      h = grub_strtoul (ptr, &ptr, 0);
 
599
      if (grub_errno)
 
600
        return grub_errno;
 
601
    }
 
602
 
 
603
  for (cur = terminfo_outputs; cur;
 
604
       cur = ((struct grub_terminfo_output_state *) cur->data)->next)
 
605
    if (grub_strcmp (args[0], cur->name) == 0)
 
606
      {
 
607
        cur->flags = (cur->flags & ~GRUB_TERM_CODE_TYPE_MASK) | encoding;
 
608
 
 
609
        if (w && h)
 
610
          {
 
611
            struct grub_terminfo_output_state *data
 
612
              = (struct grub_terminfo_output_state *) cur->data;
 
613
            data->width = w;
 
614
            data->height = h;
 
615
          }
 
616
 
 
617
        if (argc == 1)
 
618
          return GRUB_ERR_NONE;
 
619
 
 
620
        return grub_terminfo_set_current (cur, args[1]);
 
621
      }
 
622
 
 
623
  return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
624
                     "no terminal %s found or it's not handled by terminfo",
 
625
                     args[0]);
 
626
}
 
627
 
 
628
static grub_extcmd_t cmd;
 
629
 
 
630
GRUB_MOD_INIT(terminfo)
 
631
{
 
632
  cmd = grub_register_extcmd ("terminfo", grub_cmd_terminfo, 0,
 
633
                              N_("[[-a|-u|-v] [-g WxH] TERM [TYPE]]"),
 
634
                              N_("Set terminfo type of TERM  to TYPE.\n"),
 
635
                              options);
 
636
}
 
637
 
 
638
GRUB_MOD_FINI(terminfo)
 
639
{
 
640
  grub_unregister_extcmd (cmd);
 
641
}