2005-08-18 Yoshinori K. Okuji <okuji@enbug.org>

* normal/misc.c: New file.

        * DISTLIST: Added normal/misc.c.

        * partmap/amiga.c (amiga_partition_map_iterate): Add an argument
        DISK to HOOK. Call HOOK with DISK.
        * partmap/apple.c (apple_partition_map_iterate): Likewise.
        * partmap/pc.c (pc_partition_map_iterate): Likewise.
        * partmap/sun.c (sun_partition_map_iterate): Likewise.

        * normal/menu_entry.c (struct screen): Added a new member
        "completion_shown".
        (completion_buffer): New global variable.
        (make_screen): Set SCREEN->COMPLETION_SHOWN to zero.
        (store_completion): New function.
        (complete): Likewise.
        (clear_completions): Likewise.
        (grub_menu_entry_run): If SCREEN->COMPLETION_SHOWN is non-zero,
        call clear_completions and reset SCREEN->COMPLETION_SHOWN. If C is
        a tab, call complete.

        * normal/completion.c (disk_dev): Removed.
        (print_simple_completion): Likewise.
        (print_partition_completion): Likewise.
        (print_func): New global variable.
        (add_completion): Do not take the arguments WHAT or PRINT any
        longer. Added a new argument TYPE. Instead of printing directly,
        call PRINT_FUNC if not NULL.
        All callers changed.
        (complete_device): Use a local variable DEV instead of
        DISK_DEV. Do not move CURRENT_WORD to the end of a device name.
        (grub_normal_do_completion): Take a new argument HOOK. Do not
        initialize DISK_DEV. Initialize PRINT_FUNC to HOOK. If RET is an
        empty string, return NULL instead.
        All callers changed.

        * normal/cmdline.c (print_completion): New function.

        * kern/partition.c (grub_partition_iterate): Add an argument DISK
        to HOOK.
        All callers changed.

        * kern/disk.c (grub_print_partinfo): Removed.

        * include/grub/partition.h (struct grub_partition_map): Add a new
        argument DISK into HOOK of ITERATE.
        (grub_partition_iterate): Add a new argument DISK to HOOK.

        * include/grub/normal.h (enum grub_completion_type): New enum.
        (grub_completion_type_t): New type.
        (GRUB_COMPLETION_TYPE_COMMAND): New constant.
        (GRUB_COMPLETION_TYPE_DEVICE): Likewise.
        (GRUB_COMPLETION_TYPE_PARTITION): Likewise.
        (GRUB_COMPLETION_TYPE_FILE): Likewise.
        (grub_normal_do_completion): Added a new argument HOOK.
        (grub_normal_print_device_info): New prototype.

        * include/grub/disk.h (grub_print_partinfo): Removed.

        * conf/i386-pc.rmk (grub_emu_SOURCES): Added normal/misc.c.
        (normal_mod_SOURCES): Likewise.
        * conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise.
        (normal_mod_SOURCES): Likewise.

        * commands/ls.c (grub_ls_list_disks): Use
        grub_normal_print_device_info instead of grub_print_partinfo. Free
        PNAME.
        (grub_ls_list_files): Use grub_normal_print_device_info instead of
        duplicating the code.
This commit is contained in:
okuji 2005-08-18 03:14:39 +00:00
parent 0bd41162dd
commit 992ffbbebb
23 changed files with 570 additions and 196 deletions

View file

@ -164,6 +164,46 @@ grub_cmdline_run (int nested)
}
}
/* A completion hook to print items. */
static void
print_completion (const char *item, grub_completion_type_t type, int count)
{
if (count == 0)
{
/* If this is the first time, print a label. */
const char *what;
switch (type)
{
case GRUB_COMPLETION_TYPE_COMMAND:
what = "commands";
break;
case GRUB_COMPLETION_TYPE_DEVICE:
what = "devices";
break;
case GRUB_COMPLETION_TYPE_FILE:
what = "files";
break;
case GRUB_COMPLETION_TYPE_PARTITION:
what = "partitions";
break;
default:
what = "things";
break;
}
grub_printf ("\nPossible %s are:\n", what);
}
if (type == GRUB_COMPLETION_TYPE_PARTITION)
{
grub_normal_print_device_info (item);
grub_errno = GRUB_ERR_NONE;
}
else
grub_printf (" %s", item);
}
/* Get a command-line. If ECHO_CHAR is not zero, echo it instead of input
characters. If READLINE is non-zero, readline-like key bindings are
available. If ESC is pushed, return zero, otherwise return non-zero. */
@ -309,7 +349,8 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
buf[lpos] = '\0';
insert = grub_normal_do_completion (buf, &restore);
insert = grub_normal_do_completion (buf, &restore,
print_completion);
/* Restore the original string. */
buf[lpos] = backup;

View file

@ -26,9 +26,6 @@
#include <grub/disk.h>
#include <grub/file.h>
/* The disk that is used for grub_partition_iterate. */
static grub_device_t disk_dev;
/* The current word. */
static char *current_word;
@ -41,29 +38,17 @@ static int num_found;
/* The string to be appended. */
static const char *suffix;
/* The callback function to print items. */
static void (*print_func) (const char *, grub_completion_type_t, int);
static void
print_simple_completion (const char *str)
{
grub_printf (" %s", str);
}
static void
print_partition_completion (const char *str)
{
grub_print_partinfo (disk_dev, (char *) str);
grub_errno = GRUB_ERR_NONE;
}
/* Add a string to the list of possible completions. COMPLETION is the
string that should be added. EXTRA will be appended if COMPLETION
matches uniquely. The string WHAT contains a description of the
kind of data that is added. Use PRINT to show the completions
if there are multiple matches. */
matches uniquely. The type TYPE specifies what kind of data is added. */
static int
add_completion (const char *completion, const char *extra, const char *what,
void (*print) (const char *))
add_completion (const char *completion, const char *extra,
grub_completion_type_t type)
{
if (grub_strncmp (current_word, completion, grub_strlen (current_word)) == 0)
{
@ -79,8 +64,8 @@ add_completion (const char *completion, const char *extra, const char *what,
break;
case 2:
grub_printf ("\nPossible %s are:\n", what);
print (match);
if (print_func)
print_func (match, type, 0);
/* Fall through. */
@ -88,8 +73,9 @@ add_completion (const char *completion, const char *extra, const char *what,
{
char *s = match;
const char *t = completion;
print (completion);
if (print_func)
print_func (completion, type, num_found - 1);
/* Detect the matched portion. */
while (*s && *t && *s == *t)
@ -108,10 +94,30 @@ add_completion (const char *completion, const char *extra, const char *what,
}
static int
iterate_partition (const grub_partition_t p)
iterate_partition (grub_disk_t disk, const grub_partition_t p)
{
return add_completion (grub_partition_get_name (p), ")", "partitions",
print_partition_completion);
const char *disk_name = disk->name;
char *partition_name = grub_partition_get_name (p);
char *name;
int ret;
if (! partition_name)
return 1;
name = grub_malloc (grub_strlen (disk_name) + 1
+ grub_strlen (partition_name) + 1);
if (! name)
{
grub_free (partition_name);
return 1;
}
grub_sprintf (name, "%s,%s", disk_name, partition_name);
grub_free (partition_name);
ret = add_completion (name, ")", GRUB_COMPLETION_TYPE_PARTITION);
grub_free (name);
return ret;
}
static int
@ -119,7 +125,7 @@ iterate_dir (const char *filename, int dir)
{
if (! dir)
{
if (add_completion (filename, " ", "files", print_simple_completion))
if (add_completion (filename, " ", GRUB_COMPLETION_TYPE_FILE))
return 1;
}
else
@ -127,7 +133,7 @@ iterate_dir (const char *filename, int dir)
char fname[grub_strlen (filename) + 2];
grub_sprintf (fname, "%s/", filename);
if (add_completion (fname, "", "files", print_simple_completion))
if (add_completion (fname, "", GRUB_COMPLETION_TYPE_FILE))
return 1;
}
@ -146,14 +152,12 @@ iterate_dev (const char *devname)
{
if (dev->disk && dev->disk->has_partitions)
{
if (add_completion (devname, ",", "devices",
print_simple_completion))
if (add_completion (devname, ",", GRUB_COMPLETION_TYPE_DEVICE))
return 1;
}
else
{
if (add_completion (devname, ")", "devices",
print_simple_completion))
if (add_completion (devname, ")", GRUB_COMPLETION_TYPE_DEVICE))
return 1;
}
}
@ -169,8 +173,7 @@ iterate_command (grub_command_t cmd)
{
if (cmd->flags & GRUB_COMMAND_FLAG_CMDLINE)
{
if (add_completion (cmd->name, " ", "commands",
print_simple_completion))
if (add_completion (cmd->name, " ", GRUB_COMPLETION_TYPE_COMMAND))
return 1;
}
}
@ -184,6 +187,7 @@ complete_device (void)
{
/* Check if this is a device or a partition. */
char *p = grub_strchr (++current_word, ',');
grub_device_t dev;
if (! p)
{
@ -195,24 +199,22 @@ complete_device (void)
{
/* Complete the partition part. */
*p = '\0';
disk_dev = grub_device_open (current_word);
dev = grub_device_open (current_word);
*p = ',';
grub_errno = GRUB_ERR_NONE;
if (disk_dev)
if (dev)
{
if (disk_dev->disk && disk_dev->disk->has_partitions)
if (dev->disk && dev->disk->has_partitions)
{
current_word = p + 1;
if (grub_partition_iterate (disk_dev->disk, iterate_partition))
if (grub_partition_iterate (dev->disk, iterate_partition))
{
grub_device_close (disk_dev);
grub_device_close (dev);
return 1;
}
}
grub_device_close (disk_dev);
grub_device_close (dev);
}
else
return 1;
@ -303,18 +305,19 @@ complete_file (void)
/* Try to complete the string in BUF. Return the characters that
should be added to the string. This command outputs the possible
completions, in that case set RESTORE to 1 so the caller can
restore the prompt. */
completions by calling HOOK, in that case set RESTORE to 1 so the
caller can restore the prompt. */
char *
grub_normal_do_completion (char *buf, int *restore)
grub_normal_do_completion (char *buf, int *restore,
void (*hook) (const char *, grub_completion_type_t, int))
{
char *first_word;
/* Initialize variables. */
disk_dev = 0;
match = 0;
num_found = 0;
suffix = "";
print_func = hook;
*restore = 1;
@ -376,6 +379,12 @@ grub_normal_do_completion (char *buf, int *restore)
grub_free (match);
if (*ret == '\0')
{
grub_free (ret);
return 0;
}
return ret;
}

View file

@ -58,8 +58,13 @@ struct screen
int y;
/* The kill buffer. */
char *killed_text;
/* The flag of a completion window. */
int completion_shown;
};
/* Used for storing completion items temporarily. */
static struct line completion_buffer;
/* Initialize a line. */
static int
init_line (struct line *linep)
@ -422,6 +427,7 @@ make_screen (grub_menu_entry_t entry)
screen->x = 0;
screen->y = 0;
screen->killed_text = 0;
screen->completion_shown = 0;
screen->lines = grub_malloc (sizeof (struct line));
if (! screen->lines)
goto fail;
@ -809,6 +815,163 @@ open_line (struct screen *screen, int update)
return 1;
}
/* A completion hook to print items. */
static void
store_completion (const char *item, grub_completion_type_t type, int count)
{
char *p;
if (count == 0)
{
/* If this is the first time, print a label. */
const char *what;
switch (type)
{
case GRUB_COMPLETION_TYPE_COMMAND:
what = "commands";
break;
case GRUB_COMPLETION_TYPE_DEVICE:
what = "devices";
break;
case GRUB_COMPLETION_TYPE_FILE:
what = "files";
break;
case GRUB_COMPLETION_TYPE_PARTITION:
what = "partitions";
break;
default:
what = "things";
break;
}
grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
grub_printf (" Possible %s are:\n ", what);
}
/* Make sure that the completion buffer has enough room. */
if (completion_buffer.max_len < (completion_buffer.len
+ (int) grub_strlen (item) + 1 + 1))
{
grub_size_t new_len;
new_len = completion_buffer.len + grub_strlen (item) + 80;
p = grub_realloc (completion_buffer.buf, new_len);
if (! p)
{
/* Possibly not fatal. */
grub_errno = GRUB_ERR_NONE;
return;
}
p[completion_buffer.len] = 0;
completion_buffer.buf = p;
completion_buffer.max_len = new_len;
}
p = completion_buffer.buf + completion_buffer.len;
if (completion_buffer.len != 0)
{
*p++ = ' ';
completion_buffer.len++;
}
grub_strcpy (p, item);
completion_buffer.len += grub_strlen (item);
}
static int
complete (struct screen *screen, int continuous, int update)
{
grub_uint16_t pos;
char saved_char;
struct line *linep;
int restore;
char *insert;
static int count = -1;
if (continuous)
count++;
else
count = 0;
pos = grub_getxy ();
grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
completion_buffer.buf = 0;
completion_buffer.len = 0;
completion_buffer.max_len = 0;
linep = screen->lines + screen->line;
saved_char = linep->buf[screen->column];
linep->buf[screen->column] = '\0';
insert = grub_normal_do_completion (linep->buf, &restore, store_completion);
linep->buf[screen->column] = saved_char;
if (restore)
{
char *p = completion_buffer.buf;
screen->completion_shown = 1;
if (p)
{
int num_sections = ((completion_buffer.len + GRUB_TERM_WIDTH - 8 - 1)
/ (GRUB_TERM_WIDTH - 8));
char *endp;
p += (count % num_sections) * (GRUB_TERM_WIDTH - 8);
endp = p + (GRUB_TERM_WIDTH - 8);
if (p != completion_buffer.buf)
grub_putcode (GRUB_TERM_DISP_LEFT);
else
grub_putchar (' ');
while (*p && p < endp)
grub_putchar (*p++);
if (*p)
grub_putcode (GRUB_TERM_DISP_RIGHT);
}
}
grub_gotoxy (pos >> 8, pos & 0xFF);
if (insert)
{
insert_string (screen, insert, update);
count = -1;
grub_free (insert);
}
else if (update)
grub_refresh ();
grub_free (completion_buffer.buf);
return 1;
}
/* Clear displayed completions. */
static void
clear_completions (void)
{
grub_uint16_t pos;
int i, j;
pos = grub_getxy ();
grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
for (i = 0; i < 2; i++)
{
for (j = 0; j < GRUB_TERM_WIDTH - 1; j++)
grub_putchar (' ');
grub_putchar ('\n');
}
grub_gotoxy (pos >> 8, pos & 0xFF);
grub_refresh ();
}
/* Execute the command list in the screen SCREEN. */
static int
run (struct screen *screen)
@ -880,6 +1043,12 @@ grub_menu_entry_run (grub_menu_entry_t entry)
while (1)
{
int c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
if (screen->completion_shown)
{
clear_completions ();
screen->completion_shown = 0;
}
switch (c)
{
@ -914,7 +1083,8 @@ grub_menu_entry_run (grub_menu_entry_t entry)
break;
case '\t': /* C-i */
/* FIXME: Completion */
if (! complete (screen, prev_c == c, 1))
goto fail;
break;
case 4: /* C-d */

70
normal/misc.c Normal file
View file

@ -0,0 +1,70 @@
/* misc.c - miscellaneous functions */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <grub/normal.h>
#include <grub/disk.h>
#include <grub/fs.h>
#include <grub/err.h>
#include <grub/misc.h>
/* Print the information on the device NAME. */
grub_err_t
grub_normal_print_device_info (const char *name)
{
grub_device_t dev;
char *p;
p = grub_strchr (name, ',');
if (p)
grub_printf ("\tPartition %s: ", name);
else
grub_printf ("Device %s: ", name);
dev = grub_device_open (name);
if (! dev)
grub_printf ("Filesystem cannot be accessed");
else if (! dev->disk || ! dev->disk->has_partitions || dev->disk->partition)
{
char *label;
grub_fs_t fs;
fs = grub_fs_probe (dev);
/* Ignore all errors. */
grub_errno = 0;
grub_printf ("Filesystem type %s", fs ? fs->name : "unknown");
if (fs && fs->label)
{
(fs->label) (dev, &label);
if (grub_errno == GRUB_ERR_NONE)
{
if (label && grub_strlen (label))
grub_printf (", Label %s", label);
grub_free (label);
}
grub_errno = GRUB_ERR_NONE;
}
grub_device_close (dev);
}
grub_printf ("\n");
return grub_errno;
}