/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/script_sh.h>
enum update_mode
{
};
struct line
{
/* The line buffer. */
char *buf;
/* The length of the line. */
int len;
/* The maximum length of the line. */
int max_len;
};
struct per_term_screen
{
/* The X coordinate. */
int x;
/* The Y coordinate. */
int y;
/* Number of entries. */
int num_entries;
};
struct screen
{
/* The array of lines. */
/* The number of lines. */
int num_lines;
/* The current column. */
int column;
/* The real column. */
int real_column;
/* The current line. */
int line;
/* The kill buffer. */
char *killed_text;
/* The flag of a completion window. */
int completion_shown;
int submenu;
unsigned nterms;
};
/* Used for storing completion items temporarily. */
static int completion_type;
/* Initialize a line. */
static int
{
return 0;
return 1;
}
/* Allocate extra space if necessary. */
static int
{
{
return 0;
}
return 1;
}
/* Return the number of lines occupied by this line on the screen. */
static int
{
}
/* Print a line. */
static void
struct per_term_screen *term_screen)
{
y + GRUB_TERM_FIRST_ENTRY_Y);
{
char *p, c;
c = *p;
*p = 0;
*p = c;
}
else
{
int i;
char *p, c;
c = *p;
*p = 0;
*p = c;
for (i = 0;
i++)
}
}
/* Print an empty line. */
static void
{
int i;
y + GRUB_TERM_FIRST_ENTRY_Y);
}
/* Print an up arrow. */
static void
{
if (flag)
else
}
/* Print a down arrow. */
static void
{
+ term_screen->num_entries);
if (flag)
else
}
/* Draw the lines of the screen SCREEN. */
static void
int region_start, int region_column,
{
int up_flag = 0;
int down_flag = 0;
int y;
int i;
/* Check if scrolling is necessary. */
{
if (term_screen->y < 0)
term_screen->y = 0;
else
region_start = 0;
region_column = 0;
up = 1;
down = 1;
}
{
/* Draw lines. This code is tricky, because this must calculate logical
positions. */
while (y > 0)
{
i--;
linep--;
}
if (y < 0 || i > 0)
up_flag = 1;
do
{
int column;
break;
for (column = 0;
&& y < term_screen->num_entries;
{
if (y < 0)
continue;
if (i == region_start)
{
if (region_column >= column
< (column
else if (region_column < column)
}
}
if (y == term_screen->num_entries)
{
down_flag = 1;
}
linep++;
i++;
for (; y < term_screen->num_entries; y++)
print_empty_line (y, term_screen);
}
while (y < term_screen->num_entries);
/* Draw up and down arrows. */
if (up)
if (down)
}
/* Place the cursor. */
+ term_screen->x,
}
static void
int region_start, int region_column,
{
unsigned i;
}
static int
{
int region_column = 0;
unsigned i;
{
down[i] = 0;
}
while (*s)
{
if (*s == '\n')
{
/* LF is special because it creates a new line. */
int size;
/* Make a new line. */
return 0;
/* Scroll down. */
* sizeof (struct line)));
return 0;
/* Fold the line. */
return 0;
size);
/* Update a dirty region. */
{
}
{
}
/* Move the cursor. */
{
}
s++;
}
else
{
/* All but LF. */
const char *p;
int size;
/* Find a string delimited by LF. */
p = grub_strchr (s, '\n');
if (! p)
p = s + grub_strlen (s);
/* Insert the string. */
size = p - s;
return 0;
s,
size);
/* Update the dirty region. */
{
}
{
}
mode[i] = SINGLE_LINE;
/* Move the cursor. */
{
}
s = p;
}
}
if (update)
return 1;
}
/* Release the resource allocated for SCREEN. */
static void
{
int i;
{
if (linep)
}
}
/* Make a new screen. */
static struct screen *
{
unsigned i;
/* Initialize the screen. */
if (! screen)
return 0;
goto fail;
/* Initialize the first line which must be always present. */
goto fail;
/* Reset the cursor position. */
screen->real_column = 0;
{
}
return screen;
fail:
return 0;
}
static int
{
unsigned i;
{
{
{
}
}
}
{
{
}
}
if (update)
return 1;
}
static int
{
unsigned i;
{
{
{
}
}
}
{
{
}
}
if (update)
return 1;
}
static int
{
unsigned i;
{
int col;
/* How many physical lines from the current position
to the first physical line? */
else
{
int dy;
/* How many physical lines from the current position
to the last physical line? */
}
}
else
{
{
}
}
if (update)
return 1;
}
static int
{
unsigned i;
{
/* How many physical lines from the current position
to the last physical line? */
linep++;
else
{
int dy;
/* How many physical lines from the current position
to the first physical line? */
}
}
else
{
int l, s;
{
}
}
if (update)
return 1;
}
static int
{
unsigned i;
int col;
{
}
if (update)
return 1;
}
static int
{
unsigned i;
int col;
{
}
if (update)
return 1;
}
static int
{
int column = 0;
{
unsigned i;
if (update)
{
{
else
}
}
}
{
return 0;
next_linep + 1,
* sizeof (struct line));
if (update)
}
return 1;
}
static int
{
int saved_column;
int saved_line;
if (! backward_char (screen, 0))
return 0;
return 0;
return 1;
}
static int
{
char *p;
int size;
int offset;
p = screen->killed_text;
if (! continuous && p)
p[0] = '\0';
if (p)
offset = grub_strlen (p);
else
offset = 0;
if (size > 0)
{
unsigned i;
if (! p)
return 0;
screen->killed_text = p;
if (update)
{
{
else
}
}
}
{
if (! p)
return 0;
p[offset] = '\n';
screen->killed_text = p;
}
return 1;
}
static int
{
if (screen->killed_text)
return 1;
}
static int
{
unsigned i;
return 0;
if (! backward_char (screen, 0))
return 0;
if (update)
return 1;
}
/* A completion hook to print items. */
static void
{
char *p;
/* Make sure that the completion buffer has enough room. */
{
if (! p)
{
/* Possibly not fatal. */
return;
}
p[completion_buffer.len] = 0;
completion_buffer.buf = p;
}
if (completion_buffer.len != 0)
{
*p++ = ' ';
}
grub_strcpy (p, item);
}
static int
{
char saved_char;
int restore;
char *insert;
unsigned i;
if (continuous)
count++;
else
count = 0;
completion_buffer.buf = 0;
completion_buffer.len = 0;
completion_buffer.max_len = 0;
if (completion_buffer.buf)
{
if (!ucs4)
{
grub_print_error ();
return 1;
}
buflen, 0);
if (restore)
{
- 8 - 1)
- 8));
grub_uint32_t *p = ucs4;
switch (completion_type)
{
grub_puts_terminal (_("Possible commands are:"),
break;
grub_puts_terminal (_("Possible devices are:"),
break;
grub_puts_terminal (_("Possible files are:"),
break;
grub_puts_terminal (_("Possible partitions are:"),
break;
grub_puts_terminal (_("Possible arguments are:"),
break;
default:
grub_puts_terminal (_("Possible things are:"),
break;
}
p += (count % num_sections)
if (p != ucs4)
else
}
}
if (insert)
{
count = -1;
}
else if (update)
grub_refresh ();
return 1;
}
/* Clear displayed completions. */
static void
{
unsigned i, j;
for (i = 0; i < 2; i++)
{
}
}
static void
{
unsigned i;
}
/* Execute the command list in the screen SCREEN. */
static int
{
char *script;
int errs_before;
auto char * editor_getsource (void);
char * editor_getsource (void)
{
int i;
int size = 0;
char *source;
if (! source)
return NULL;
size = 0;
{
}
return source;
}
grub_cls ();
grub_printf (" ");
grub_printf ("\n\n");
{
if (! menu)
return 0;
}
/* Execute the script, line for line. */
script = editor_getsource ();
if (! script)
return 0;
if (errs_before != grub_err_printed_errors)
/* Implicit execution of boot, only if something is loaded. */
grub_command_execute ("boot", 0, 0);
{
{
}
}
if (grub_errno != GRUB_ERR_NONE)
{
grub_print_error ();
}
return 1;
}
/* Edit a menu entry with an Emacs-like interface. */
void
{
int prev_c;
unsigned i;
if (err)
{
grub_print_error ();
return;
}
if (! screen)
return;
{
grub_print_error ();
return;
}
i = 0;
{
i++;
}
/* Draw the screen. */
prev_c = '\0';
while (1)
{
int c = grub_getkey ();
if (screen->completion_shown)
{
screen->completion_shown = 0;
}
{
return;
}
switch (c)
{
case GRUB_TERM_KEY_UP:
case GRUB_TERM_CTRL | 'p':
goto fail;
break;
case GRUB_TERM_CTRL | 'n':
case GRUB_TERM_KEY_DOWN:
goto fail;
break;
case GRUB_TERM_CTRL | 'f':
case GRUB_TERM_KEY_RIGHT:
goto fail;
break;
case GRUB_TERM_CTRL | 'b':
case GRUB_TERM_KEY_LEFT:
goto fail;
break;
case GRUB_TERM_CTRL | 'a':
case GRUB_TERM_KEY_HOME:
goto fail;
break;
case GRUB_TERM_CTRL | 'e':
case GRUB_TERM_KEY_END:
goto fail;
break;
case GRUB_TERM_CTRL | 'i':
case '\t':
goto fail;
break;
case GRUB_TERM_CTRL | 'd':
case GRUB_TERM_KEY_DC:
goto fail;
break;
case GRUB_TERM_CTRL | 'h':
case '\b':
goto fail;
break;
case GRUB_TERM_CTRL | 'k':
goto fail;
break;
case GRUB_TERM_CTRL | 'u':
/* FIXME: What behavior is good for this key? */
break;
case GRUB_TERM_CTRL | 'y':
goto fail;
break;
case GRUB_TERM_CTRL | 'l':
/* FIXME: centering. */
goto refresh;
case GRUB_TERM_CTRL | 'o':
goto fail;
break;
case '\n':
case '\r':
goto fail;
break;
case '\e':
return;
case GRUB_TERM_CTRL | 'c':
case GRUB_TERM_KEY_F2:
grub_cmdline_run (1);
goto refresh;
case GRUB_TERM_CTRL | 'x':
case GRUB_TERM_KEY_F10:
goto refresh;
case GRUB_TERM_CTRL | 'r':
case GRUB_TERM_CTRL | 's':
case GRUB_TERM_CTRL | 't':
/* FIXME */
break;
default:
if (grub_isprint (c))
{
buf[0] = c;
goto fail;
}
break;
}
prev_c = c;
}
fail:
grub_cls ();
grub_print_error ();
grub_xputs ("\n");
(void) grub_getkey ();
}