improve the completion code.

This commit is contained in:
okuji 1999-09-18 22:28:36 +00:00
parent dc267a70d2
commit dc73edd77c
4 changed files with 250 additions and 130 deletions

View file

@ -1,3 +1,48 @@
1999-09-19 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
The completion code is heavily modified.
* stage2/char_io.c [!STAGE1_5] (get_cmdline): In the completion
code, use COMPLETION_BUFFER to get the completion instead of
writing to BUF directly.
Save the position of a possible equal character after a command
in EQUAL_POS and replace the equal character with a space
temporarily for the code simplicity.
At first, just get completions, and, if there is more than one
completions, then print the list of the completions.
* stage2/disk_io.c [!STAGE1_5] (do_completion): New variable.
[!STAGE1_5] (unique): Moved the definition near the beginning.
[!STAGE1_5] (unique_string): Likewise. And changed the type to
char *.
(check_BSD_parts) [!STAGE1_5]: If DO_COMPLETION is non-zero, do
not print anything.
(real_open_partition) [!STAGE1_5]: Likewise.
[!STAGE1_5] (print_fsys_type): Likewise.
[!STAGE1_5] (print_a_completion): The argument FILENAME is
renamed to NAME.
If DO_COMPLETION is non-zero, get the unique part from NAME and
set UNIQUE_STRING to it.
If DO_COMPLETION is zero, just print NAME.
Do not call printf unconditionally.
[!STAGE1_5] (print_completions): Accept two arguements
IS_FILENAME and IS_COMPLETION instead of FILENAME.
Set UNIQUE_STRING to UNIQUE_BUF.
Set DO_COMPLETION to IS_COMPLETION and set it to zero before
returning.
If IS_FILENAME is zero, then complete builtin commands and
return UNIQUE - 1.
Use BUF instead of FILENAME.
If IS_COMPLETION is non-zero, do not print anything.
Copy UNIQUE_STRING to PTR only if IS_COMPLETION and
*UNIQUE_STRING are non-zero.
* stage2/shared.h (COMPLETION_BUF): New macro.
(COMPLETION_BUFLEN): Likewise.
(UNIQUE_BUF): Likewise.
(UNIQUE_BUFLEN): Likewise.
(MENU_BUF): Set to UNIQUE_BUF + UNIQUE_BUFLEN.
(MENU_BUFLEN): Set to 0x8000 + PASSWORD_BUF - UNIQUE_BUF.
(print_completions): Adjusted to the definition.
1999-09-19 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp> 1999-09-19 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* acinclude.m4 (grub_ASM_PREFIX_REQUIREMENT): Do not call * acinclude.m4 (grub_ASM_PREFIX_REQUIREMENT): Do not call

View file

@ -373,57 +373,65 @@ get_cmdline (char *prompt, char *cmdline, int maxlen,
{ {
case 9: /* TAB lists completions */ case 9: /* TAB lists completions */
{ {
int i, j = 0, llen_old = llen; int i;
/* POS points to the first space after a command. */
int pos = 0;
int ret;
char *completion_buffer = (char *) COMPLETION_BUF;
int equal_pos = -1;
int is_filename;
/* Find the first word. */ /* Find the first word. */
while (buf[j] == ' ') while (buf[pos] == ' ')
j++; pos++;
while (buf[j] && buf[j] != '=' && buf[j] != ' ') while (buf[pos] && buf[pos] != '=' && buf[pos] != ' ')
j++; pos++;
is_filename = (lpos > pos);
/* Since the command line cannot have a '\n', we're OK to /* Find the position of the equal character after a
use C. */ command, and replace it with a space. */
c = buf[lpos]; for (i = pos; buf[i] && buf[i] != ' '; i++)
if (buf[i] == '=')
cl_kill_to_end (); {
equal_pos = i;
/* goto part after line here */ buf[i] = ' ';
yend = ((llen + plen) / 79) + ystart; break;
putchar ('\n'); }
gotoxy (0, getxy () & 0xff);
/* Find the position of the first character in this
word. */
if (lpos > j) for (i = lpos; i > 0 && buf[i - 1] != ' '; i--)
;
/* Copy this word to COMPLETION_BUFFER and do the
completion. */
grub_memmove (completion_buffer, buf + i, lpos - i);
completion_buffer[lpos - i] = 0;
ret = print_completions (is_filename, 1);
if (ret >= 0)
{ {
for (i = lpos; i > 0 && buf[i - 1] != ' '; i--); /* Found, so insert COMPLETION_BUFFER. */
if (i <= j) cl_insert (completion_buffer + lpos - i);
i = j + 1;
/* print possible completions */
print_completions (buf + i);
/* if somebody in print_completions has added something,
account for that */
while (buf[lpos])
lpos++, llen_old++;
}
else
{
/* Print the command list. */
struct builtin **builtin;
for (builtin = builtin_table; *builtin != 0; builtin++) if (ret > 0)
{ {
/* Do not print the name if it cannot be run in /* There is more than one candidates, so print
the command-line interface. */ the list. */
if (! ((*builtin)->flags & BUILTIN_CMDLINE))
continue;
grub_printf ("%s ", (*builtin)->name); /* Go to the part after the line here. */
yend = ((llen + plen) / 79) + ystart;
grub_putchar ('\n');
gotoxy (0, getxy () & 0xff);
print_completions (is_filename, 0);
} }
} }
/* restore command-line */ /* Restore the command-line. */
buf[lpos] = c; if (equal_pos >= 0)
llen = llen_old; buf[equal_pos] = '=';
cl_init (); cl_init ();
} }
break; break;

View file

@ -30,6 +30,11 @@ void (*debug_fs) (int) = NULL;
void (*debug_fs_func) (int) = NULL; void (*debug_fs_func) (int) = NULL;
int print_possibilities; int print_possibilities;
static int do_completion;
static int unique;
static char *unique_string;
#endif #endif
int fsmax; int fsmax;
@ -406,10 +411,13 @@ check_BSD_parts (int flags)
{ {
if (!got_part) if (!got_part)
{ {
printf ("[BSD sub-partitions immediately follow]\n"); if (! do_completion)
printf ("[BSD sub-partitions immediately follow]\n");
got_part = 1; got_part = 1;
} }
printf (" BSD Partition num: \'%c\', ", part_no + 'a');
if (! do_completion)
printf (" BSD Partition num: \'%c\', ", part_no + 'a');
check_and_print_mount (); check_and_print_mount ();
} }
else else
@ -537,7 +545,8 @@ real_open_partition (int flags)
else if (flags) else if (flags)
{ {
current_partition |= 0xFFFF; current_partition |= 0xFFFF;
printf (" Partition num: %d, ", slice_no); if (! do_completion)
printf (" Partition num: %d, ", slice_no);
if (! IS_PC_SLICE_TYPE_BSD (current_slice)) if (! IS_PC_SLICE_TYPE_BSD (current_slice))
check_and_print_mount (); check_and_print_mount ();
else else
@ -632,10 +641,6 @@ open_partition (void)
/* XX used for device completion in 'set_device' and 'print_completions' */ /* XX used for device completion in 'set_device' and 'print_completions' */
static int incomplete, disk_choice; static int incomplete, disk_choice;
#ifndef STAGE1_5
static int unique;
static char unique_string[128]; /* XXX Don't know yet */
#endif
static enum static enum
{ {
PART_UNSPECIFIED = 0, PART_UNSPECIFIED = 0,
@ -957,48 +962,51 @@ setup_part (char *filename)
void void
print_fsys_type (void) print_fsys_type (void)
{ {
printf (" Filesystem type "); if (! do_completion)
{
if (fsys_type != NUM_FSYS) printf (" Filesystem type ");
printf ("is %s, ", fsys_table[fsys_type].name);
else if (fsys_type != NUM_FSYS)
printf ("unknown, "); printf ("is %s, ", fsys_table[fsys_type].name);
else
if (current_partition == 0xFFFFFF) printf ("unknown, ");
printf ("using whole disk\n");
else if (current_partition == 0xFFFFFF)
printf ("partition type 0x%x\n", current_slice); printf ("using whole disk\n");
else
printf ("partition type 0x%x\n", current_slice);
}
} }
#endif /* STAGE1_5 */ #endif /* STAGE1_5 */
#ifndef STAGE1_5 #ifndef STAGE1_5
/* /* If DO_COMPLETION is true, just print NAME. Otherwise save the unique
* print_a_completion saves what has been printed to unique_string part into UNIQUE_STRING. */
* printf's with a leading ' '.
*/
void void
print_a_completion (char *filename) print_a_completion (char *name)
{ {
char *f = filename; if (do_completion)
char *u = unique_string;
if (! *u && unique == 0)
{ {
/* copy first string, this is unique. */ char *buf = unique_string;
while ((*u++ = *f++))
; if (! unique)
while ((*buf++ = *name++))
;
else
{
while (*buf && (*buf == *name))
{
buf++;
name++;
}
/* mismatch, strip it. */
*buf = '\0';
}
} }
else else
{ grub_printf (" %s", name);
while (*u && (*u == *f))
u++, f++;
/* mismatch, strip it. */
*u = '\0';
}
unique++; unique++;
printf (" %s", filename);
} }
/* /*
@ -1006,27 +1014,66 @@ print_a_completion (char *filename)
* any sane combination of the two. * any sane combination of the two.
*/ */
void int
print_completions (char *filename) print_completions (int is_filename, int is_completion)
{ {
char *ptr = filename; char *buf = (char *) COMPLETION_BUF;
char *ptr = buf;
*unique_string = '\0'; unique_string = (char *) UNIQUE_BUF;
*unique_string = 0;
unique = 0; unique = 0;
do_completion = is_completion;
if (*filename == '/' || (ptr = set_device (filename)) || incomplete) if (! is_filename)
{
/* Print the completions of builtin commands. */
struct builtin **builtin;
if (! is_completion)
grub_printf (" Possible commands are:");
for (builtin = builtin_table; (*builtin); builtin++)
{
/* If *BUILTIN cannot be run in the command-line, skip it. */
if (! ((*builtin)->flags & BUILTIN_CMDLINE))
continue;
if (substring (buf, (*builtin)->name) <= 0)
print_a_completion ((*builtin)->name);
}
if (is_completion && *unique_string)
{
if (unique == 1)
{
char *u = unique_string + grub_strlen (unique_string);
*u++ = ' ';
*u = 0;
}
grub_strcpy (buf, unique_string);
}
do_completion = 0;
return unique - 1;
}
if (*buf == '/' || (ptr = set_device (buf)) || incomplete)
{ {
errnum = 0; errnum = 0;
if (*filename != '/' && (incomplete || !*ptr)) if (*buf != '/' && (incomplete || ! *ptr))
{ {
if (!part_choice) if (! part_choice)
{ {
/* disk completions */ /* disk completions */
int disk_no, i, j; int disk_no, i, j;
struct geometry geom; struct geometry geom;
printf (" Possible disks are: "); if (! is_completion)
grub_printf (" Possible disks are: ");
for (i = (ptr && (*(ptr-2) == 'h' && *(ptr-1) == 'd') ? 1 : 0); for (i = (ptr && (*(ptr-2) == 'h' && *(ptr-1) == 'd') ? 1 : 0);
i < (ptr && (*(ptr-2) == 'f' && *(ptr-1) == 'd') ? 1 : 2); i < (ptr && (*(ptr-2) == 'f' && *(ptr-1) == 'd') ? 1 : 2);
@ -1035,8 +1082,8 @@ print_completions (char *filename)
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
{ {
disk_no = (i * 0x80) + j; disk_no = (i * 0x80) + j;
if ((disk_choice || disk_no == current_drive) && if ((disk_choice || disk_no == current_drive)
! get_diskinfo (disk_no, &geom)) && ! get_diskinfo (disk_no, &geom))
{ {
char dev_name[4]; char dev_name[4];
@ -1049,32 +1096,36 @@ print_completions (char *filename)
} }
} }
ptr = filename; if (is_completion && *unique_string)
while (*ptr != '(') {
ptr--; ptr = buf;
ptr++; while (*ptr != '(')
{ ptr--;
char *u = unique_string; ptr++;
while ((*ptr++ = *u++)) {
; char *u = unique_string;
ptr--; while ((*ptr++ = *u++))
} ;
ptr--; ptr--;
if ((*(ptr - 2) == 'h') && (*(ptr - 1) == 'd') }
&& ('0' <= *ptr && *ptr <= '8')) ptr--;
*(ptr + 1) = ',', *(ptr + 2) = '\0'; if ((*(ptr - 2) == 'h') && (*(ptr - 1) == 'd')
if ((*(ptr - 2) == 'f') && (*(ptr - 1) == 'd') && ('0' <= *ptr && *ptr <= '8'))
&& ('0' <= *ptr && *ptr <= '8')) *(ptr + 1) = ',', *(ptr + 2) = '\0';
*(ptr + 1) = ')', *(ptr + 2) = '\0'; if ((*(ptr - 2) == 'f') && (*(ptr - 1) == 'd')
&& ('0' <= *ptr && *ptr <= '8'))
putchar ('\n'); *(ptr + 1) = ')', *(ptr + 2) = '\0';
grub_putchar ('\n');
}
} }
else else
{ {
/* partition completions */ /* partition completions */
if (part_choice == PART_DISK) if (part_choice == PART_DISK)
{ {
printf (" Possible partitions are:\n"); if (! is_completion)
grub_printf (" Possible partitions are:\n");
real_open_partition (1); real_open_partition (1);
} }
else else
@ -1084,7 +1135,7 @@ print_completions (char *filename)
check_and_print_mount (); check_and_print_mount ();
/* FIXME: Can talk about linux only, do we need /* FIXME: Can talk about linux only, do we need
to know about syntax here? */ to know about syntax here? */
ptr = filename; ptr = buf;
while (*ptr) while (*ptr)
ptr++; ptr++;
if (*(ptr - 1) != ')') if (*(ptr - 1) != ')')
@ -1098,28 +1149,36 @@ print_completions (char *filename)
else if (*ptr == '/') else if (*ptr == '/')
{ {
/* filename completions */ /* filename completions */
printf (" Possible files are:"); if (! is_completion)
dir (filename); grub_printf (" Possible files are:");
{
char *u = unique_string; dir (buf);
if (is_completion && *unique_string)
{
ptr += grub_strlen (ptr);
while (*ptr != '/')
ptr--;
ptr++;
if (unique == 1)
{
char *u = unique_string + grub_strlen (unique_string);
*u++ = ' ';
*u = 0;
}
if (*u) grub_strcpy (ptr, unique_string);
{ }
while (*ptr++)
;
while (*ptr != '/')
ptr--;
ptr++;
while ((*ptr++ = *u++))
;
}
}
} }
else else
errnum = ERR_BAD_FILENAME; errnum = ERR_BAD_FILENAME;
} }
print_error (); print_error ();
do_completion = 0;
return unique - 1;
} }
#endif /* STAGE1_5 */ #endif /* STAGE1_5 */

View file

@ -105,9 +105,17 @@ extern char *grub_scratch_mem;
#define HISTORY_SIZE 5 #define HISTORY_SIZE 5
#define HISTORY_BUFLEN (MAX_CMDLINE * HISTORY_SIZE) #define HISTORY_BUFLEN (MAX_CMDLINE * HISTORY_SIZE)
/* The buffer for the completion. */
#define COMPLETION_BUF (HISTORY_BUF + HISTORY_BUFLEN)
#define COMPLETION_BUFLEN MAX_CMDLINE
/* The buffer for the unique string. */
#define UNIQUE_BUF (COMPLETION_BUF + COMPLETION_BUFLEN)
#define UNIQUE_BUFLEN MAX_CMDLINE
/* The buffer for the menu entries. */ /* The buffer for the menu entries. */
#define MENU_BUF (HISTORY_BUF + HISTORY_BUFLEN) #define MENU_BUF (UNIQUE_BUF + UNIQUE_BUFLEN)
#define MENU_BUFLEN (0x8000 + PASSWORD_BUF - HISTORY_BUF) #define MENU_BUFLEN (0x8000 + PASSWORD_BUF - UNIQUE_BUF)
/* /*
* Linux setup parameters * Linux setup parameters
@ -659,7 +667,7 @@ void print_fsys_type (void);
/* Display device and filename completions. */ /* Display device and filename completions. */
void print_a_completion (char *filename); void print_a_completion (char *filename);
void print_completions (char *filename); int print_completions (int is_filename, int is_completion);
/* Copies the current partition data to the desired address. */ /* Copies the current partition data to the desired address. */
void copy_current_part_entry (char *buf); void copy_current_part_entry (char *buf);