133 |
hist_lines[pos] = grub_strdup (s); |
hist_lines[pos] = grub_strdup (s); |
134 |
} |
} |
135 |
|
|
|
/* 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. */ |
|
|
static char * |
|
|
grub_tab_complete (char *buf, int *restore) |
|
|
{ |
|
|
char *pos = buf; |
|
|
char *path; |
|
|
|
|
|
char *found = 0; |
|
|
int begin; |
|
|
int end; |
|
|
int len; |
|
|
int numfound = 0; |
|
|
|
|
|
/* The disk that is used for grub_partition_iterate. */ |
|
|
grub_device_t partdev; |
|
|
|
|
|
/* String that is added when matched. */ |
|
|
char *matchstr; |
|
|
|
|
|
auto void print_simple_completion (char *comp); |
|
|
auto void print_partition_completion (char *comp); |
|
|
auto int NESTED_FUNC_ATTR add_completion (const char *comp, const char *match, |
|
|
const char *what, |
|
|
void (*print_completion) (char *)); |
|
|
auto int iterate_commands (grub_command_t cmd); |
|
|
auto int iterate_dev (const char *devname); |
|
|
auto int iterate_part (const grub_partition_t p); |
|
|
auto int iterate_dir (const char *filename, int dir); |
|
|
|
|
|
|
|
|
|
|
|
void print_simple_completion (char *comp) |
|
|
{ |
|
|
grub_printf (" %s", comp); |
|
|
} |
|
|
|
|
|
void print_partition_completion (char *comp) |
|
|
{ |
|
|
grub_print_partinfo (partdev, comp); |
|
|
grub_errno = 0; |
|
|
} |
|
|
|
|
|
/* Add a string to the list of possible completions. COMP is the |
|
|
string that should be added. If this string completely matches |
|
|
add the string MATCH to the input after adding COMP. The string |
|
|
WHAT contains a discription of the kind of data that is added. |
|
|
Use PRINT_COMPLETION to show the completions if there are |
|
|
multiple matches. XXX: Because of a bug in gcc it is required to |
|
|
use __regparm__ in some cases. */ |
|
|
|
|
|
int NESTED_FUNC_ATTR add_completion (const char *comp, const char *match, |
|
|
const char *what, |
|
|
void (*print_completion) (char *)) |
|
|
{ |
|
|
/* Bug in strncmp then len ==0. */ |
|
|
if (!len || grub_strncmp (pos, comp, len) == 0) |
|
|
{ |
|
|
numfound++; |
|
|
|
|
|
if (numfound == 1) |
|
|
{ |
|
|
begin = len; |
|
|
found = grub_strdup (comp); |
|
|
end = grub_strlen (found); |
|
|
matchstr = (char *) match; |
|
|
} |
|
|
/* Multiple matches found, print the first instead of completing. */ |
|
|
else if (numfound == 2) |
|
|
{ |
|
|
grub_printf ("\nPossible %s are:\n", what); |
|
|
print_completion (found); |
|
|
} |
|
|
|
|
|
if (numfound > 1) |
|
|
{ |
|
|
char *s1 = found; |
|
|
const char *s2 = comp; |
|
|
int cnt = 0; |
|
|
|
|
|
print_completion ((char *) comp); |
|
|
|
|
|
/* Find out how many characters match. */ |
|
|
while ((cnt < end) && *s1 && *s2 && (*s1 == *s2)) |
|
|
{ |
|
|
s1++; |
|
|
s2++; |
|
|
cnt++; |
|
|
} |
|
|
end = cnt; |
|
|
} |
|
|
} |
|
|
|
|
|
return 0; |
|
|
} |
|
|
|
|
|
int iterate_part (const grub_partition_t p) |
|
|
{ |
|
|
add_completion (grub_partition_get_name (p), ")", "partitions", |
|
|
print_partition_completion); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
int iterate_dir (const char *filename, int dir) |
|
|
{ |
|
|
if (!dir) |
|
|
add_completion (filename, " ", "files", print_simple_completion); |
|
|
else |
|
|
{ |
|
|
char fname[grub_strlen (filename) + 2]; |
|
|
grub_strcpy (fname, filename); |
|
|
grub_sprintf (fname, "%s/", filename); |
|
|
add_completion (fname, "", "files", print_simple_completion); |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
int iterate_dev (const char *devname) |
|
|
{ |
|
|
grub_device_t dev; |
|
|
|
|
|
/* Complete the partition part. */ |
|
|
dev = grub_device_open (devname); |
|
|
|
|
|
if (dev) |
|
|
{ |
|
|
if (dev->disk && dev->disk->has_partitions) |
|
|
add_completion (devname, ",", "disks", print_simple_completion); |
|
|
else |
|
|
add_completion (devname, ")", "disks", print_simple_completion); |
|
|
} |
|
|
|
|
|
grub_errno = GRUB_ERR_NONE; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
int iterate_commands (grub_command_t cmd) |
|
|
{ |
|
|
if (grub_command_find (cmd->name)) |
|
|
{ |
|
|
if (cmd->flags & GRUB_COMMAND_FLAG_CMDLINE) |
|
|
add_completion (cmd->name, " ", "commands", |
|
|
print_simple_completion); |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
/* Remove blank space on the beginning of the line. */ |
|
|
while (*pos == ' ') |
|
|
pos++; |
|
|
|
|
|
/* Check if the string is a command or path. */ |
|
|
path = grub_strchr (pos, ' '); |
|
|
|
|
|
if (!path) |
|
|
{ |
|
|
/* Tab complete a command. */ |
|
|
len = grub_strlen (pos); |
|
|
|
|
|
grub_iterate_commands (iterate_commands); |
|
|
} |
|
|
else |
|
|
{ |
|
|
pos = path; |
|
|
|
|
|
/* Remove blank space on the beginning of the line. */ |
|
|
while (*pos == ' ') |
|
|
pos++; |
|
|
|
|
|
/* Check if this is a completion for a device name. */ |
|
|
if (*pos == '(' && !grub_strchr (pos, ')')) |
|
|
{ |
|
|
/* Check if this is a device or partition. */ |
|
|
char *partition = grub_strchr (++pos, ','); |
|
|
|
|
|
if (!partition) |
|
|
{ |
|
|
/* Complete the disk part. */ |
|
|
len = grub_strlen (pos); |
|
|
grub_disk_dev_iterate (iterate_dev); |
|
|
if (grub_errno) |
|
|
goto fail; |
|
|
} |
|
|
else |
|
|
{ |
|
|
*partition = '\0'; |
|
|
|
|
|
/* Complete the partition part. */ |
|
|
partdev = grub_device_open (pos); |
|
|
*partition = ','; |
|
|
grub_errno = GRUB_ERR_NONE; |
|
|
|
|
|
if (partdev) |
|
|
{ |
|
|
if (partdev->disk && partdev->disk->has_partitions) |
|
|
{ |
|
|
pos = partition + 1; |
|
|
len = grub_strlen (pos); |
|
|
|
|
|
grub_partition_iterate (partdev->disk, iterate_part); |
|
|
if (grub_errno) |
|
|
grub_errno = 0; |
|
|
} |
|
|
|
|
|
grub_device_close (partdev); |
|
|
} |
|
|
else |
|
|
goto fail; |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
char *device = grub_file_get_device_name (pos); |
|
|
grub_device_t dev; |
|
|
grub_fs_t fs; |
|
|
|
|
|
dev = grub_device_open (device); |
|
|
if (!dev) |
|
|
goto fail; |
|
|
|
|
|
fs = grub_fs_probe (dev); |
|
|
if (grub_errno) |
|
|
goto fail; |
|
|
|
|
|
pos = grub_strrchr (pos, '/'); |
|
|
if (pos) |
|
|
{ |
|
|
char *dir; |
|
|
char *dirfile; |
|
|
pos++; |
|
|
len = grub_strlen (pos); |
|
|
|
|
|
dir = grub_strchr (path, '/'); |
|
|
if (!dir) |
|
|
{ |
|
|
*restore = 0; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
dir = grub_strdup (dir); |
|
|
|
|
|
/* Cut away the filename part. */ |
|
|
dirfile = grub_strrchr (dir, '/'); |
|
|
dirfile[1] = '\0'; |
|
|
|
|
|
/* Tab complete a file. */ |
|
|
(fs->dir) (dev, dir, iterate_dir); |
|
|
if (dev) |
|
|
grub_device_close (dev); |
|
|
|
|
|
grub_free (device); |
|
|
grub_free (dir); |
|
|
|
|
|
if (grub_errno) |
|
|
goto fail; |
|
|
} |
|
|
else |
|
|
{ |
|
|
found = grub_strdup ("/"); |
|
|
matchstr = ""; |
|
|
numfound = 1; |
|
|
begin = 0; |
|
|
end = 1; |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
/* If more than one match is found those matches will be printed and |
|
|
the prompt should be restored. */ |
|
|
if (numfound > 1) |
|
|
*restore = 1; |
|
|
else |
|
|
*restore = 0; |
|
|
|
|
|
/* Return the part that matches. */ |
|
|
if (end && found) |
|
|
{ |
|
|
char *insert; |
|
|
insert = grub_malloc (end - begin + 1 + sizeof (matchstr)); |
|
|
grub_strncpy (insert, found + begin, end - begin); |
|
|
insert[end - begin] = '\0'; |
|
|
if (numfound == 1) |
|
|
grub_strcat (insert, matchstr); |
|
|
grub_free (found); |
|
|
|
|
|
return insert; |
|
|
} |
|
|
|
|
|
fail: |
|
|
grub_free (found); |
|
|
grub_errno = GRUB_ERR_NONE; |
|
|
|
|
|
return 0; |
|
|
} |
|
|
|
|
136 |
void |
void |
137 |
grub_cmdline_run (int nested) |
grub_cmdline_run (int nested) |
138 |
{ |
{ |
309 |
buf[lpos] = '\0'; |
buf[lpos] = '\0'; |
310 |
|
|
311 |
|
|
312 |
insert = grub_tab_complete (buf, &restore); |
insert = grub_normal_do_completion (buf, &restore); |
313 |
/* Restore the original string. */ |
/* Restore the original string. */ |
314 |
buf[lpos] = backup; |
buf[lpos] = backup; |
315 |
|
|