]> git.proxmox.com Git - grub2.git/blob - grub-core/term/terminfo.c
Make color variables global instead of it being per-terminal.
[grub2.git] / grub-core / term / terminfo.c
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 #if defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)
37 #include <grub/ieee1275/ieee1275.h>
38 #endif
39
40 GRUB_MOD_LICENSE ("GPLv3+");
41
42 #define ANSI_C0 0x9b
43 #define ANSI_C0_STR "\x9b"
44
45 static struct grub_term_output *terminfo_outputs;
46
47 /* Get current terminfo name. */
48 char *
49 grub_terminfo_get_current (struct grub_term_output *term)
50 {
51 struct grub_terminfo_output_state *data
52 = (struct grub_terminfo_output_state *) term->data;
53 return data->name;
54 }
55
56 /* Free *PTR and set *PTR to NULL, to prevent double-free. */
57 static void
58 grub_terminfo_free (char **ptr)
59 {
60 grub_free (*ptr);
61 *ptr = 0;
62 }
63
64 static void
65 grub_terminfo_all_free (struct grub_term_output *term)
66 {
67 struct grub_terminfo_output_state *data
68 = (struct grub_terminfo_output_state *) term->data;
69
70 /* Free previously allocated memory. */
71 grub_terminfo_free (&data->name);
72 grub_terminfo_free (&data->gotoxy);
73 grub_terminfo_free (&data->cls);
74 grub_terminfo_free (&data->reverse_video_on);
75 grub_terminfo_free (&data->reverse_video_off);
76 grub_terminfo_free (&data->cursor_on);
77 grub_terminfo_free (&data->cursor_off);
78 }
79
80 /* Set current terminfo type. */
81 grub_err_t
82 grub_terminfo_set_current (struct grub_term_output *term,
83 const char *str)
84 {
85 struct grub_terminfo_output_state *data
86 = (struct grub_terminfo_output_state *) term->data;
87 /* TODO
88 * Lookup user specified terminfo type. If found, set term variables
89 * as appropriate. Otherwise return an error.
90 *
91 * How should this be done?
92 * a. A static table included in this module.
93 * - I do not like this idea.
94 * b. A table stored in the configuration directory.
95 * - Users must convert their terminfo settings if we have not already.
96 * c. Look for terminfo files in the configuration directory.
97 * - /usr/share/terminfo is 6.3M on my system.
98 * - /usr/share/terminfo is not on most users boot partition.
99 * + Copying the terminfo files you want to use to the grub
100 * configuration directory is easier then (b).
101 * d. Your idea here.
102 */
103
104 grub_terminfo_all_free (term);
105
106 if (grub_strcmp ("vt100", str) == 0)
107 {
108 data->name = grub_strdup ("vt100");
109 data->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH");
110 data->cls = grub_strdup ("\e[H\e[J");
111 data->reverse_video_on = grub_strdup ("\e[7m");
112 data->reverse_video_off = grub_strdup ("\e[m");
113 data->cursor_on = grub_strdup ("\e[?25h");
114 data->cursor_off = grub_strdup ("\e[?25l");
115 data->setcolor = NULL;
116 return grub_errno;
117 }
118
119 if (grub_strcmp ("vt100-color", str) == 0)
120 {
121 data->name = grub_strdup ("vt100-color");
122 data->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH");
123 data->cls = grub_strdup ("\e[H\e[J");
124 data->reverse_video_on = grub_strdup ("\e[7m");
125 data->reverse_video_off = grub_strdup ("\e[m");
126 data->cursor_on = grub_strdup ("\e[?25h");
127 data->cursor_off = grub_strdup ("\e[?25l");
128 data->setcolor = grub_strdup ("\e[3%p1%dm\e[4%p2%dm");
129 return grub_errno;
130 }
131
132 if (grub_strcmp ("arc", str) == 0)
133 {
134 data->name = grub_strdup ("arc");
135 data->gotoxy = grub_strdup (ANSI_C0_STR "%i%p1%d;%p2%dH");
136 data->cls = grub_strdup (ANSI_C0_STR "2J");
137 data->reverse_video_on = grub_strdup (ANSI_C0_STR "7m");
138 data->reverse_video_off = grub_strdup (ANSI_C0_STR "0m");
139 data->cursor_on = 0;
140 data->cursor_off = 0;
141 data->setcolor = grub_strdup (ANSI_C0_STR "3%p1%dm"
142 ANSI_C0_STR "4%p2%dm");
143 return grub_errno;
144 }
145
146 if (grub_strcmp ("ieee1275", str) == 0
147 || grub_strcmp ("ieee1275-nocursor", str) == 0)
148 {
149 data->name = grub_strdup ("ieee1275");
150 data->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH");
151 /* Clear the screen. Using serial console, screen(1) only recognizes the
152 * ANSI escape sequence. Using video console, Apple Open Firmware
153 * (version 3.1.1) only recognizes the literal ^L. So use both. */
154 data->cls = grub_strdup ("\f\e[2J");
155 data->reverse_video_on = grub_strdup ("\e[7m");
156 data->reverse_video_off = grub_strdup ("\e[m");
157 if (grub_strcmp ("ieee1275", str) == 0)
158 {
159 data->cursor_on = grub_strdup ("\e[?25h");
160 data->cursor_off = grub_strdup ("\e[?25l");
161 }
162 else
163 {
164 data->cursor_on = 0;
165 data->cursor_off = 0;
166 }
167 data->setcolor = grub_strdup ("\e[3%p1%dm\e[4%p2%dm");
168 return grub_errno;
169 }
170
171 if (grub_strcmp ("dumb", str) == 0)
172 {
173 data->name = grub_strdup ("dumb");
174 data->gotoxy = NULL;
175 data->cls = NULL;
176 data->reverse_video_on = NULL;
177 data->reverse_video_off = NULL;
178 data->cursor_on = NULL;
179 data->cursor_off = NULL;
180 data->setcolor = NULL;
181 return grub_errno;
182 }
183
184 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unknown terminfo type `%s'"),
185 str);
186 }
187
188 grub_err_t
189 grub_terminfo_output_register (struct grub_term_output *term,
190 const char *type)
191 {
192 grub_err_t err;
193 struct grub_terminfo_output_state *data;
194
195 err = grub_terminfo_set_current (term, type);
196
197 if (err)
198 return err;
199
200 data = (struct grub_terminfo_output_state *) term->data;
201 data->next = terminfo_outputs;
202 terminfo_outputs = term;
203
204 return GRUB_ERR_NONE;
205 }
206
207 grub_err_t
208 grub_terminfo_output_unregister (struct grub_term_output *term)
209 {
210 struct grub_term_output **ptr;
211
212 for (ptr = &terminfo_outputs; *ptr;
213 ptr = &((struct grub_terminfo_output_state *) (*ptr)->data)->next)
214 if (*ptr == term)
215 {
216 grub_terminfo_all_free (term);
217 *ptr = ((struct grub_terminfo_output_state *) (*ptr)->data)->next;
218 return GRUB_ERR_NONE;
219 }
220 return grub_error (GRUB_ERR_BUG, "terminal not found");
221 }
222
223 /* Wrapper for grub_putchar to write strings. */
224 static void
225 putstr (struct grub_term_output *term, const char *str)
226 {
227 struct grub_terminfo_output_state *data
228 = (struct grub_terminfo_output_state *) term->data;
229 while (*str)
230 data->put (term, *str++);
231 }
232
233 grub_uint16_t
234 grub_terminfo_getxy (struct grub_term_output *term)
235 {
236 struct grub_terminfo_output_state *data
237 = (struct grub_terminfo_output_state *) term->data;
238
239 return ((data->xpos << 8) | data->ypos);
240 }
241
242 void
243 grub_terminfo_gotoxy (struct grub_term_output *term,
244 grub_uint8_t x, grub_uint8_t y)
245 {
246 struct grub_terminfo_output_state *data
247 = (struct grub_terminfo_output_state *) term->data;
248
249 if (x > grub_term_width (term) || y > grub_term_height (term))
250 {
251 grub_error (GRUB_ERR_BUG, "invalid point (%u,%u)", x, y);
252 return;
253 }
254
255 if (data->gotoxy)
256 putstr (term, grub_terminfo_tparm (data->gotoxy, y, x));
257 else
258 {
259 if ((y == data->ypos) && (x == data->xpos - 1))
260 data->put (term, '\b');
261 }
262
263 data->xpos = x;
264 data->ypos = y;
265 }
266
267 /* Clear the screen. */
268 void
269 grub_terminfo_cls (struct grub_term_output *term)
270 {
271 struct grub_terminfo_output_state *data
272 = (struct grub_terminfo_output_state *) term->data;
273
274 putstr (term, grub_terminfo_tparm (data->cls));
275
276 data->xpos = data->ypos = 0;
277 }
278
279 void
280 grub_terminfo_setcolorstate (struct grub_term_output *term,
281 const grub_term_color_state state)
282 {
283 struct grub_terminfo_output_state *data
284 = (struct grub_terminfo_output_state *) term->data;
285
286 if (data->setcolor)
287 {
288 int fg;
289 int bg;
290 /* Map from VGA to terminal colors. */
291 const int colormap[8]
292 = { 0, /* Black. */
293 4, /* Blue. */
294 2, /* Green. */
295 6, /* Cyan. */
296 1, /* Red. */
297 5, /* Magenta. */
298 3, /* Yellow. */
299 7, /* White. */
300 };
301
302 switch (state)
303 {
304 case GRUB_TERM_COLOR_STANDARD:
305 case GRUB_TERM_COLOR_NORMAL:
306 fg = grub_term_normal_color & 0x0f;
307 bg = grub_term_normal_color >> 4;
308 break;
309 case GRUB_TERM_COLOR_HIGHLIGHT:
310 fg = grub_term_highlight_color & 0x0f;
311 bg = grub_term_highlight_color >> 4;
312 break;
313 default:
314 return;
315 }
316
317 putstr (term, grub_terminfo_tparm (data->setcolor, colormap[fg & 7],
318 colormap[bg & 7]));
319 return;
320 }
321
322 switch (state)
323 {
324 case GRUB_TERM_COLOR_STANDARD:
325 case GRUB_TERM_COLOR_NORMAL:
326 putstr (term, grub_terminfo_tparm (data->reverse_video_off));
327 break;
328 case GRUB_TERM_COLOR_HIGHLIGHT:
329 putstr (term, grub_terminfo_tparm (data->reverse_video_on));
330 break;
331 default:
332 break;
333 }
334 }
335
336 void
337 grub_terminfo_setcursor (struct grub_term_output *term, const int on)
338 {
339 struct grub_terminfo_output_state *data
340 = (struct grub_terminfo_output_state *) term->data;
341
342 if (on)
343 putstr (term, grub_terminfo_tparm (data->cursor_on));
344 else
345 putstr (term, grub_terminfo_tparm (data->cursor_off));
346 }
347
348 /* The terminfo version of putchar. */
349 void
350 grub_terminfo_putchar (struct grub_term_output *term,
351 const struct grub_unicode_glyph *c)
352 {
353 struct grub_terminfo_output_state *data
354 = (struct grub_terminfo_output_state *) term->data;
355
356 /* Keep track of the cursor. */
357 switch (c->base)
358 {
359 case '\a':
360 break;
361
362 case '\b':
363 case 127:
364 if (data->xpos > 0)
365 data->xpos--;
366 break;
367
368 case '\n':
369 if (data->ypos < grub_term_height (term) - 1)
370 data->ypos++;
371 break;
372
373 case '\r':
374 data->xpos = 0;
375 break;
376
377 default:
378 if (data->xpos + c->estimated_width >= grub_term_width (term) + 1)
379 {
380 data->xpos = 0;
381 if (data->ypos < grub_term_height (term) - 1)
382 data->ypos++;
383 data->put (term, '\r');
384 data->put (term, '\n');
385 }
386 data->xpos += c->estimated_width;
387 break;
388 }
389
390 data->put (term, c->base);
391 }
392
393 grub_uint16_t
394 grub_terminfo_getwh (struct grub_term_output *term)
395 {
396 struct grub_terminfo_output_state *data
397 = (struct grub_terminfo_output_state *) term->data;
398
399 return (data->width << 8) | data->height;
400 }
401
402 static void
403 grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len,
404 int (*readkey) (struct grub_term_input *term))
405 {
406 int c;
407
408 #define CONTINUE_READ \
409 { \
410 grub_uint64_t start; \
411 /* On 9600 we have to wait up to 12 milliseconds. */ \
412 start = grub_get_time_ms (); \
413 do \
414 c = readkey (term); \
415 while (c == -1 && grub_get_time_ms () - start < 100); \
416 if (c == -1) \
417 return; \
418 \
419 keys[*len] = c; \
420 (*len)++; \
421 }
422
423 c = readkey (term);
424 if (c < 0)
425 {
426 *len = 0;
427 return;
428 }
429 *len = 1;
430 keys[0] = c;
431 if (c != ANSI_C0 && c != '\e')
432 {
433 /* Backspace: Ctrl-h. */
434 if (c == 0x7f)
435 c = '\b';
436 if (c < 0x20 && c != '\t' && c!= '\b' && c != '\n' && c != '\r')
437 c = GRUB_TERM_CTRL | (c - 1 + 'a');
438 *len = 1;
439 keys[0] = c;
440 return;
441 }
442
443 {
444 static struct
445 {
446 char key;
447 unsigned ascii;
448 }
449 three_code_table[] =
450 {
451 {'4', GRUB_TERM_KEY_DC},
452 {'A', GRUB_TERM_KEY_UP},
453 {'B', GRUB_TERM_KEY_DOWN},
454 {'C', GRUB_TERM_KEY_RIGHT},
455 {'D', GRUB_TERM_KEY_LEFT},
456 {'F', GRUB_TERM_KEY_END},
457 {'H', GRUB_TERM_KEY_HOME},
458 {'K', GRUB_TERM_KEY_END},
459 {'P', GRUB_TERM_KEY_DC},
460 {'?', GRUB_TERM_KEY_PPAGE},
461 {'/', GRUB_TERM_KEY_NPAGE},
462 {'@', GRUB_TERM_KEY_INSERT},
463 };
464
465 static struct
466 {
467 char key;
468 unsigned ascii;
469 }
470 four_code_table[] =
471 {
472 {'1', GRUB_TERM_KEY_HOME},
473 {'3', GRUB_TERM_KEY_DC},
474 {'5', GRUB_TERM_KEY_PPAGE},
475 {'6', GRUB_TERM_KEY_NPAGE}
476 };
477 char fx_key[] =
478 { 'P', 'Q', 'w', 'x', 't', 'u',
479 'q', 'r', 'p', 'M', 'A', 'B' };
480 unsigned fx_code[] =
481 { GRUB_TERM_KEY_F1, GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3,
482 GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, GRUB_TERM_KEY_F6,
483 GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9,
484 GRUB_TERM_KEY_F10, GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12 };
485 unsigned i;
486
487 if (c == '\e')
488 {
489 CONTINUE_READ;
490
491 if (c != '[')
492 return;
493 }
494
495 CONTINUE_READ;
496
497 for (i = 0; i < ARRAY_SIZE (three_code_table); i++)
498 if (three_code_table[i].key == c)
499 {
500 keys[0] = three_code_table[i].ascii;
501 *len = 1;
502 return;
503 }
504
505 switch (c)
506 {
507 case 'O':
508 CONTINUE_READ;
509 for (i = 0; i < ARRAY_SIZE (fx_key); i++)
510 if (fx_key[i] == c)
511 {
512 keys[0] = fx_code[i];
513 *len = 1;
514 return;
515 }
516 return;
517
518 case '0':
519 {
520 int num = 0;
521 CONTINUE_READ;
522 if (c != '0' && c != '1')
523 return;
524 num = (c - '0') * 10;
525 CONTINUE_READ;
526 if (c < '0' || c > '9')
527 return;
528 num += (c - '0');
529 if (num == 0 || num > 12)
530 return;
531 CONTINUE_READ;
532 if (c != 'q')
533 return;
534 keys[0] = fx_code[num - 1];
535 *len = 1;
536 return;
537 }
538
539 default:
540 for (i = 0; i < ARRAY_SIZE (four_code_table); i++)
541 if (four_code_table[i].key == c)
542 {
543 CONTINUE_READ;
544 if (c != '~')
545 return;
546 keys[0] = three_code_table[i].ascii;
547 *len = 1;
548 return;
549 }
550 return;
551 }
552 }
553 #undef CONTINUE_READ
554 }
555
556 /* The terminfo version of getkey. */
557 int
558 grub_terminfo_getkey (struct grub_term_input *termi)
559 {
560 struct grub_terminfo_input_state *data
561 = (struct grub_terminfo_input_state *) (termi->data);
562 if (data->npending)
563 {
564 int ret;
565 data->npending--;
566 ret = data->input_buf[0];
567 grub_memmove (data->input_buf, data->input_buf + 1, data->npending
568 * sizeof (data->input_buf[0]));
569 return ret;
570 }
571
572 grub_terminfo_readkey (termi, data->input_buf,
573 &data->npending, data->readkey);
574
575 #if defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)
576 if (data->npending == 1 && data->input_buf[0] == '\e'
577 && grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_REPEAT)
578 && grub_get_time_ms () - data->last_key_time < 1000
579 && (data->last_key & GRUB_TERM_EXTENDED))
580 {
581 data->npending = 0;
582 data->last_key_time = grub_get_time_ms ();
583 return data->last_key;
584 }
585 #endif
586
587 if (data->npending)
588 {
589 int ret;
590 data->npending--;
591 ret = data->input_buf[0];
592 #if defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)
593 if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_REPEAT))
594 {
595 data->last_key = ret;
596 data->last_key_time = grub_get_time_ms ();
597 }
598 #endif
599 grub_memmove (data->input_buf, data->input_buf + 1, data->npending
600 * sizeof (data->input_buf[0]));
601 return ret;
602 }
603
604 return GRUB_TERM_NO_KEY;
605 }
606
607 grub_err_t
608 grub_terminfo_input_init (struct grub_term_input *termi)
609 {
610 struct grub_terminfo_input_state *data
611 = (struct grub_terminfo_input_state *) (termi->data);
612 data->npending = 0;
613
614 return GRUB_ERR_NONE;
615 }
616
617 grub_err_t
618 grub_terminfo_output_init (struct grub_term_output *term)
619 {
620 grub_terminfo_cls (term);
621 return GRUB_ERR_NONE;
622 }
623
624 /* GRUB Command. */
625
626 static grub_err_t
627 print_terminfo (void)
628 {
629 const char *encoding_names[(GRUB_TERM_CODE_TYPE_MASK
630 >> GRUB_TERM_CODE_TYPE_SHIFT) + 1]
631 = {
632 /* VGA and glyph descriptor types are just for completeness,
633 they are not used on terminfo terminals.
634 */
635 [GRUB_TERM_CODE_TYPE_ASCII >> GRUB_TERM_CODE_TYPE_SHIFT] = _("ASCII"),
636 [GRUB_TERM_CODE_TYPE_CP437 >> GRUB_TERM_CODE_TYPE_SHIFT] = "CP-437",
637 [GRUB_TERM_CODE_TYPE_UTF8_LOGICAL >> GRUB_TERM_CODE_TYPE_SHIFT]
638 = _("UTF-8"),
639 [GRUB_TERM_CODE_TYPE_UTF8_VISUAL >> GRUB_TERM_CODE_TYPE_SHIFT]
640 /* TRANSLATORS: visually ordered UTF-8 is a non-compliant encoding
641 based on UTF-8 with right-to-left languages written in reverse.
642 Used on some terminals. Normal UTF-8 is refered as
643 "logically-ordered UTF-8" by opposition. */
644 = _("visually-ordered UTF-8"),
645 [GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS >> GRUB_TERM_CODE_TYPE_SHIFT]
646 = "Glyph descriptors",
647 _("Unknown encoding"), _("Unknown encoding"), _("Unknown encoding")
648 };
649 struct grub_term_output *cur;
650
651 grub_puts_ (N_("Current terminfo types:"));
652 for (cur = terminfo_outputs; cur;
653 cur = ((struct grub_terminfo_output_state *) cur->data)->next)
654 grub_printf ("%s: %s\t%s\t%dx%d\n", cur->name,
655 grub_terminfo_get_current(cur),
656 encoding_names[(cur->flags & GRUB_TERM_CODE_TYPE_MASK)
657 >> GRUB_TERM_CODE_TYPE_SHIFT],
658 ((struct grub_terminfo_output_state *) cur->data)->width,
659 ((struct grub_terminfo_output_state *) cur->data)->height);
660
661 return GRUB_ERR_NONE;
662 }
663
664 static const struct grub_arg_option options[] =
665 {
666 {"ascii", 'a', 0, N_("Terminal is ASCII-only [default]."), 0, ARG_TYPE_NONE},
667 {"utf8", 'u', 0, N_("Terminal is logical-ordered UTF-8."), 0, ARG_TYPE_NONE},
668 {"visual-utf8", 'v', 0, N_("Terminal is visually-ordered UTF-8."), 0,
669 ARG_TYPE_NONE},
670 {"geometry", 'g', 0, N_("Terminal has specified geometry."),
671 /* TRANSLATORS: "x" has to be entered in, like an identifier, so please don't
672 use better Unicode codepoints. */
673 N_("WIDTHxHEIGHT."), ARG_TYPE_STRING},
674 {0, 0, 0, 0, 0, 0}
675 };
676
677 enum
678 {
679 OPTION_ASCII,
680 OPTION_UTF8,
681 OPTION_VISUAL_UTF8,
682 OPTION_GEOMETRY
683 };
684
685 static grub_err_t
686 grub_cmd_terminfo (grub_extcmd_context_t ctxt, int argc, char **args)
687 {
688 struct grub_term_output *cur;
689 int encoding = GRUB_TERM_CODE_TYPE_ASCII;
690 struct grub_arg_list *state = ctxt->state;
691 int w = 0, h = 0;
692
693 if (argc == 0)
694 return print_terminfo ();
695
696 if (state[OPTION_ASCII].set)
697 encoding = GRUB_TERM_CODE_TYPE_ASCII;
698
699 if (state[OPTION_UTF8].set)
700 encoding = GRUB_TERM_CODE_TYPE_UTF8_LOGICAL;
701
702 if (state[OPTION_VISUAL_UTF8].set)
703 encoding = GRUB_TERM_CODE_TYPE_UTF8_VISUAL;
704
705 if (state[OPTION_GEOMETRY].set)
706 {
707 char *ptr = state[OPTION_GEOMETRY].arg;
708 w = grub_strtoul (ptr, &ptr, 0);
709 if (grub_errno)
710 return grub_errno;
711 if (*ptr != 'x')
712 return grub_error (GRUB_ERR_BAD_ARGUMENT,
713 N_("incorrect terminal dimensions specification"));
714 ptr++;
715 h = grub_strtoul (ptr, &ptr, 0);
716 if (grub_errno)
717 return grub_errno;
718 }
719
720 for (cur = terminfo_outputs; cur;
721 cur = ((struct grub_terminfo_output_state *) cur->data)->next)
722 if (grub_strcmp (args[0], cur->name) == 0
723 || (grub_strcmp (args[0], "ofconsole") == 0
724 && grub_strcmp ("console", cur->name) == 0))
725 {
726 cur->flags = (cur->flags & ~GRUB_TERM_CODE_TYPE_MASK) | encoding;
727
728 if (w && h)
729 {
730 struct grub_terminfo_output_state *data
731 = (struct grub_terminfo_output_state *) cur->data;
732 data->width = w;
733 data->height = h;
734 }
735
736 if (argc == 1)
737 return GRUB_ERR_NONE;
738
739 return grub_terminfo_set_current (cur, args[1]);
740 }
741
742 return grub_error (GRUB_ERR_BAD_ARGUMENT,
743 N_("terminal %s isn't found or it's not handled by terminfo"),
744 args[0]);
745 }
746
747 static grub_extcmd_t cmd;
748
749 #if defined (GRUB_MACHINE_IEEE1275) || defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_ARC)
750 void grub_terminfo_init (void)
751 #else
752 GRUB_MOD_INIT(terminfo)
753 #endif
754 {
755 cmd = grub_register_extcmd ("terminfo", grub_cmd_terminfo, 0,
756 N_("[[-a|-u|-v] [-g WxH] TERM [TYPE]]"),
757 N_("Set terminfo type of TERM to TYPE.\n"),
758 options);
759 }
760
761 #if defined (GRUB_MACHINE_IEEE1275) || defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_ARC)
762 void grub_terminfo_fini (void)
763 #else
764 GRUB_MOD_FINI(terminfo)
765 #endif
766 {
767 grub_unregister_extcmd (cmd);
768 }