2003-12-03 Marco Gerards <metgerards@student.han.nl>

* fs/ext2.c (pupa_ext2_label): New function.
	(pupa_ext2_fs): Added label.
	* fs/fat.c (pupa_fat_label): New function.
	(pupa_fat_fs): Added label.
	* include/pupa/fs.h (struct pupa_fs): Added prototype label.

	* kern/misc.c (pupa_strndup): New function.
	* include/pupa/misc.h (pupa_strndup): New prototype.

	* include/pupa/normal.h: Include <pupa/err.h>.
	(pupa_set_history): New prototype.
	(pupa_iterate_commands): New prototype.
	* normal/cmdline.c: Include <pupa/machine/partition.h>,
	<pupa/disk.h>, <pupa/file.h>.
	(hist_size): New variable.
	(hist_lines): Likewise.
	(hist_end): Likewise.
	(hist_used): Likewise.
	(pupa_set_history): New function.
	(pupa_history_get): Likewise.
	(pupa_history_add): Likewise.
	(pupa_history_replace): Likewise.
	(pupa_tab_complete): Likewise.
	(pupa_cmdline_run): Added tab completion and history buffer.  Tab
	completion shows partitionnames while completing partitions, this
	feature was suggested by Jeff Bailey.
	* normal/command.c (pupa_iterate_commands): New function.
	* normal/main.c (PUPA_DEFAULT_HISTORY_SIZE): New macro.
	(pupa_normal_init): Initialize history buffer.
	(PUPA_MOD_INIT): Likewise.
	(pupa_normal_fini): Free the history buffer.
	(PUPA_MOD_FINI): Likewise.

	* util/console.c (pupa_ncurses_getkey): Accept 127 as backspace
	key.

	* aclocal.m4 (pupa_I386_CHECK_REGPARM_BUG): New DEFUN.
	* configure.ac [i386]: Check for regparam bug.
	(NESTED_FUNC_ATTR) [! i386]: Defined.
This commit is contained in:
marco_g 2003-12-03 19:17:27 +00:00
parent 1f7315a3de
commit 5aded270b6
15 changed files with 793 additions and 6 deletions

View file

@ -1,3 +1,45 @@
2003-12-03 Marco Gerards <metgerards@student.han.nl>
* fs/ext2.c (pupa_ext2_label): New function.
(pupa_ext2_fs): Added label.
* fs/fat.c (pupa_fat_label): New function.
(pupa_fat_fs): Added label.
* include/pupa/fs.h (struct pupa_fs): Added prototype label.
* kern/misc.c (pupa_strndup): New function.
* include/pupa/misc.h (pupa_strndup): New prototype.
* include/pupa/normal.h: Include <pupa/err.h>.
(pupa_set_history): New prototype.
(pupa_iterate_commands): New prototype.
* normal/cmdline.c: Include <pupa/machine/partition.h>,
<pupa/disk.h>, <pupa/file.h>.
(hist_size): New variable.
(hist_lines): Likewise.
(hist_end): Likewise.
(hist_used): Likewise.
(pupa_set_history): New function.
(pupa_history_get): Likewise.
(pupa_history_add): Likewise.
(pupa_history_replace): Likewise.
(pupa_tab_complete): Likewise.
(pupa_cmdline_run): Added tab completion and history buffer. Tab
completion shows partitionnames while completing partitions, this
feature was suggested by Jeff Bailey.
* normal/command.c (pupa_iterate_commands): New function.
* normal/main.c (PUPA_DEFAULT_HISTORY_SIZE): New macro.
(pupa_normal_init): Initialize history buffer.
(PUPA_MOD_INIT): Likewise.
(pupa_normal_fini): Free the history buffer.
(PUPA_MOD_FINI): Likewise.
* util/console.c (pupa_ncurses_getkey): Accept 127 as backspace
key.
* aclocal.m4 (pupa_I386_CHECK_REGPARM_BUG): New DEFUN.
* configure.ac [i386]: Check for regparam bug.
(NESTED_FUNC_ATTR) [! i386]: Defined.
2003-11-17 Marco Gerards <metgerards@student.han.nl> 2003-11-17 Marco Gerards <metgerards@student.han.nl>
* conf/i386-pc.rmk (sbin_UTILITIES): Added pupa-emu. * conf/i386-pc.rmk (sbin_UTILITIES): Added pupa-emu.

39
aclocal.m4 vendored
View file

@ -290,3 +290,42 @@ else
AC_MSG_ERROR([neither end nor _end is defined]) AC_MSG_ERROR([neither end nor _end is defined])
fi fi
]) ])
dnl Check if the C compiler has a bug while using nested functions when
dnl mregparm is used on the i386. Some gcc versions do not pass the third
dnl parameter correctly to the nested function.
dnl Written by Marco Gerards.
AC_DEFUN(pupa_I386_CHECK_REGPARM_BUG,
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if GCC has the regparm=3 bug])
AC_CACHE_VAL(pupa_cv_i386_check_nested_functions,
[AC_RUN_IFELSE([AC_LANG_SOURCE(
[[int *p;
int
main ()
{
int test;
int __attribute__ ((__regparm__ (3))) nestedfunc (int a, int b, int c)
{
return (&test == p);
}
p = &test;
return nestedfunc (0, 0, 0);
}
]])],
[pupa_cv_i386_check_nested_functions=yes],
[pupa_cv_i386_check_nested_functions=no])])
AC_MSG_RESULT([$pupa_cv_i386_check_nested_functions])
if test "x$pupa_cv_i386_check_nested_functions" = xyes; then
AC_DEFINE([NESTED_FUNC_ATTR],
[__attribute__ ((__regparm__ (2)))],
[Catch gcc bug])
else
AC_DEFINE([NESTED_FUNC_ATTR], [], [Catch gcc bug])
fi
])

View file

@ -49,6 +49,9 @@
/* Define to 1 if you have the <unistd.h> header file. */ /* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H #undef HAVE_UNISTD_H
/* Catch gcc bug */
#undef NESTED_FUNC_ATTR
/* Define to the address where bug reports for this package should be sent. */ /* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT

84
configure vendored
View file

@ -3253,9 +3253,93 @@ fi
echo "$as_me:$LINENO: result: $pupa_cv_i386_asm_absolute_without_asterisk" >&5 echo "$as_me:$LINENO: result: $pupa_cv_i386_asm_absolute_without_asterisk" >&5
echo "${ECHO_T}$pupa_cv_i386_asm_absolute_without_asterisk" >&6 echo "${ECHO_T}$pupa_cv_i386_asm_absolute_without_asterisk" >&6
echo "$as_me:$LINENO: checking if GCC has the regparm=3 bug" >&5
echo $ECHO_N "checking if GCC has the regparm=3 bug... $ECHO_C" >&6
if test "${pupa_cv_i386_check_nested_functions+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test "$cross_compiling" = yes; then
{ { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
See \`config.log' for more details." >&5
echo "$as_me: error: cannot run test program while cross compiling
See \`config.log' for more details." >&2;}
{ (exit 1); exit 1; }; }
else
cat >conftest.$ac_ext <<_ACEOF
#line $LINENO "configure"
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
int *p;
int
main ()
{
int test;
int __attribute__ ((__regparm__ (3))) nestedfunc (int a, int b, int c)
{
return (&test == p);
}
p = &test;
return nestedfunc (0, 0, 0);
}
_ACEOF
rm -f conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && { ac_try='./conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
pupa_cv_i386_check_nested_functions=yes
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
( exit $ac_status )
pupa_cv_i386_check_nested_functions=no
fi
rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
fi fi
echo "$as_me:$LINENO: result: $pupa_cv_i386_check_nested_functions" >&5
echo "${ECHO_T}$pupa_cv_i386_check_nested_functions" >&6
if test "x$pupa_cv_i386_check_nested_functions" = xyes; then
cat >>confdefs.h <<\_ACEOF
#define NESTED_FUNC_ATTR __attribute__ ((__regparm__ (2)))
_ACEOF
else
cat >>confdefs.h <<\_ACEOF
#define NESTED_FUNC_ATTR
_ACEOF
fi
else
cat >>confdefs.h <<\_ACEOF
#define NESTED_FUNC_ATTR
_ACEOF
fi
# Find a good install program. We prefer a C program (faster), # Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or # so one script is as good as another. But avoid the broken or
# incompatible versions: # incompatible versions:

View file

@ -88,9 +88,11 @@ if test "x$host_cpu" = xi386; then
pupa_I386_ASM_PREFIX_REQUIREMENT pupa_I386_ASM_PREFIX_REQUIREMENT
pupa_I386_ASM_ADDR32 pupa_I386_ASM_ADDR32
pupa_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK pupa_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK
pupa_I386_CHECK_REGPARM_BUG
else
AC_DEFINE([NESTED_FUNC_ATTR], [],[Catch gcc bug])
fi fi
AC_PROG_INSTALL AC_PROG_INSTALL
AC_PROG_MAKE_SET AC_PROG_MAKE_SET
AC_CHECK_TOOL(OBJCOPY, objcopy) AC_CHECK_TOOL(OBJCOPY, objcopy)

View file

@ -687,6 +687,31 @@ pupa_ext2_dir (pupa_device_t device, const char *path,
return pupa_errno; return pupa_errno;
} }
static pupa_err_t
pupa_ext2_label (pupa_device_t device, char **label)
{
struct pupa_ext2_data *data;
pupa_disk_t disk = device->disk;
#ifndef PUPA_UTIL
pupa_dl_ref (my_mod);
#endif
data = pupa_ext2_mount (disk);
if (data)
*label = pupa_strndup (data->sblock.volume_name, 14);
else
*label = 0;
#ifndef PUPA_UTIL
pupa_dl_unref (my_mod);
#endif
pupa_free (data);
return pupa_errno;
}
static struct pupa_fs pupa_ext2_fs = static struct pupa_fs pupa_ext2_fs =
{ {
@ -695,6 +720,7 @@ static struct pupa_fs pupa_ext2_fs =
.open = pupa_ext2_open, .open = pupa_ext2_open,
.read = pupa_ext2_read, .read = pupa_ext2_read,
.close = pupa_ext2_close, .close = pupa_ext2_close,
.label = pupa_ext2_label,
.next = 0 .next = 0
}; };

View file

@ -3,6 +3,7 @@
* PUPA -- Preliminary Universal Programming Architecture for GRUB * PUPA -- Preliminary Universal Programming Architecture for GRUB
* Copyright (C) 2000,2001 Free Software Foundation, Inc. * Copyright (C) 2000,2001 Free Software Foundation, Inc.
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org> * Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
* Copyright (C) 2003 Marco Gerards <metgerards@student.han.nl>.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -771,6 +772,70 @@ pupa_fat_close (pupa_file_t file)
return pupa_errno; return pupa_errno;
} }
static pupa_err_t
pupa_fat_label (pupa_device_t device, char **label)
{
struct pupa_fat_data *data;
pupa_disk_t disk = device->disk;
pupa_ssize_t offset = -sizeof(struct pupa_fat_dir_entry);
#ifndef PUPA_UTIL
pupa_dl_ref (my_mod);
#endif
data = pupa_fat_mount (disk);
if (! data)
goto fail;
if (! (data->attr & PUPA_FAT_ATTR_DIRECTORY))
{
pupa_error (PUPA_ERR_BAD_FILE_TYPE, "not a directory");
return 0;
}
while (1)
{
struct pupa_fat_dir_entry dir;
/* Adjust the offset. */
offset += sizeof (dir);
/* Read a directory entry. */
if ((pupa_fat_read_data (disk, data, 0,
offset, sizeof (dir), (char *) &dir)
!= sizeof (dir))
|| dir.name[0] == 0)
{
if (pupa_errno != PUPA_ERR_NONE)
goto fail;
else
{
*label = 0;
return PUPA_ERR_NONE;
}
}
if (dir.attr == PUPA_FAT_ATTR_VOLUME_ID)
{
*label = pupa_strndup (dir.name, 11);
return PUPA_ERR_NONE;
}
}
*label = 0;
fail:
#ifndef PUPA_UTIL
pupa_dl_unref (my_mod);
#endif
pupa_free (data);
return pupa_errno;
}
static struct pupa_fs pupa_fat_fs = static struct pupa_fs pupa_fat_fs =
{ {
.name = "fat", .name = "fat",
@ -778,6 +843,7 @@ static struct pupa_fs pupa_fat_fs =
.open = pupa_fat_open, .open = pupa_fat_open,
.read = pupa_fat_read, .read = pupa_fat_read,
.close = pupa_fat_close, .close = pupa_fat_close,
.label = pupa_fat_label,
.next = 0 .next = 0
}; };

View file

@ -2,6 +2,7 @@
/* /*
* PUPA -- Preliminary Universal Programming Architecture for GRUB * PUPA -- Preliminary Universal Programming Architecture for GRUB
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org> * Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
* Copyright (C) 2003 Marco Gerards <metgerards@student.han.nl>.
* *
* PUPA is free software; you can redistribute it and/or modify * PUPA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -46,6 +47,11 @@ struct pupa_fs
/* Close the file FILE. */ /* Close the file FILE. */
pupa_err_t (*close) (struct pupa_file *file); pupa_err_t (*close) (struct pupa_file *file);
/* Return the label of the device DEVICE in LABEL. The label is
returned in a pupa_malloc'ed buffer and should be freed by the
caller. */
pupa_err_t (*label) (pupa_device_t device, char **label);
/* The next filesystem. */ /* The next filesystem. */
struct pupa_fs *next; struct pupa_fs *next;

View file

@ -47,6 +47,7 @@ int EXPORT_FUNC(pupa_isalpha) (int c);
int EXPORT_FUNC(pupa_tolower) (int c); int EXPORT_FUNC(pupa_tolower) (int c);
unsigned long EXPORT_FUNC(pupa_strtoul) (const char *str, char **end, int base); unsigned long EXPORT_FUNC(pupa_strtoul) (const char *str, char **end, int base);
char *EXPORT_FUNC(pupa_strdup) (const char *s); char *EXPORT_FUNC(pupa_strdup) (const char *s);
char *EXPORT_FUNC(pupa_strndup) (const char *s, pupa_size_t n);
void *EXPORT_FUNC(pupa_memset) (void *s, int c, pupa_size_t n); void *EXPORT_FUNC(pupa_memset) (void *s, int c, pupa_size_t n);
pupa_size_t EXPORT_FUNC(pupa_strlen) (const char *s); pupa_size_t EXPORT_FUNC(pupa_strlen) (const char *s);
int EXPORT_FUNC(pupa_printf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); int EXPORT_FUNC(pupa_printf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));

View file

@ -2,6 +2,7 @@
/* /*
* PUPA -- Preliminary Universal Programming Architecture for GRUB * PUPA -- Preliminary Universal Programming Architecture for GRUB
* Copyright (C) 2002,2003 Yoshinori K. Okuji <okuji@enbug.org> * Copyright (C) 2002,2003 Yoshinori K. Okuji <okuji@enbug.org>
* Copyright (C) 2003 Marco Gerards <metgerards@student.han.nl>.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -23,6 +24,7 @@
#include <pupa/setjmp.h> #include <pupa/setjmp.h>
#include <pupa/symbol.h> #include <pupa/symbol.h>
#include <pupa/err.h>
/* The maximum size of a command-line. */ /* The maximum size of a command-line. */
#define PUPA_MAX_CMDLINE 1600 #define PUPA_MAX_CMDLINE 1600
@ -125,6 +127,8 @@ void EXPORT_FUNC(pupa_register_command) (const char *name,
const char *description); const char *description);
void EXPORT_FUNC(pupa_unregister_command) (const char *name); void EXPORT_FUNC(pupa_unregister_command) (const char *name);
pupa_command_t pupa_command_find (char *cmdline); pupa_command_t pupa_command_find (char *cmdline);
pupa_err_t pupa_set_history (int newsize);
int pupa_iterate_commands (int (*iterate) (pupa_command_t));
int pupa_command_execute (char *cmdline); int pupa_command_execute (char *cmdline);
void pupa_command_init (void); void pupa_command_init (void);
void pupa_normal_init_page (void); void pupa_normal_init_page (void);

View file

@ -301,6 +301,23 @@ pupa_strdup (const char *s)
return pupa_memcpy (p, s, len); return pupa_memcpy (p, s, len);
} }
char *
pupa_strndup (const char *s, pupa_size_t n)
{
pupa_size_t len = 0;
char *p = (char *) s;
while (*(p++) && len < n)
len++;
len = pupa_strlen (s) + 1;
p = (char *) pupa_malloc (len);
if (! p)
return 0;
return pupa_memcpy (p, s, len);
}
void * void *
pupa_memset (void *s, int c, pupa_size_t n) pupa_memset (void *s, int c, pupa_size_t n)
{ {

View file

@ -2,6 +2,7 @@
* PUPA -- Preliminary Universal Programming Architecture for GRUB * PUPA -- Preliminary Universal Programming Architecture for GRUB
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
* Copyright (C) 2003 Yoshinori K. Okuji <okuji@enbug.org> * Copyright (C) 2003 Yoshinori K. Okuji <okuji@enbug.org>
* Copyright (C) 2003 Marco Gerards <metgerards@student.han.nl>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -24,9 +25,429 @@
#include <pupa/err.h> #include <pupa/err.h>
#include <pupa/types.h> #include <pupa/types.h>
#include <pupa/mm.h> #include <pupa/mm.h>
#include <pupa/machine/partition.h>
#include <pupa/disk.h>
#include <pupa/file.h>
static char *kill_buf; static char *kill_buf;
static int hist_size;
static char **hist_lines = 0;
static int hist_pos = 0;
static int hist_end = 0;
static int hist_used = 0;
pupa_err_t
pupa_set_history (int newsize)
{
char **old_hist_lines = hist_lines;
hist_lines = pupa_malloc (sizeof (char *) * newsize);
/* Copy the old lines into the new buffer. */
if (old_hist_lines)
{
/* Remove the lines that don't fit in the new buffer. */
if (newsize < hist_used)
{
int i;
int delsize = hist_used - newsize;
hist_used = newsize;
for (i = 0; i < delsize; i++)
{
int pos = hist_end - i;
if (pos > hist_size)
pos -= hist_size;
pupa_free (old_hist_lines[pos]);
}
hist_end -= delsize;
if (hist_end < 0)
hist_end = hist_size - hist_end;
}
if (hist_pos < hist_end)
pupa_memmove (hist_lines, old_hist_lines + hist_pos,
(hist_end - hist_pos) * sizeof (char *));
else
{
/* Copy the first part. */
pupa_memmove (hist_lines, old_hist_lines,
hist_pos * sizeof (char *));
/* Copy the last part. */
pupa_memmove (hist_lines + hist_pos, old_hist_lines + hist_pos,
(hist_size - hist_pos) * sizeof (char *));
}
}
pupa_free (old_hist_lines);
hist_size = newsize;
hist_pos = 0;
hist_end = hist_used;
return 0;
}
/* Get the entry POS from the history where `0' is the newest
entry. */
static char *
pupa_history_get (int pos)
{
pos = (hist_pos + pos) % hist_size;
return hist_lines[pos];
}
/* Insert a new history line S on the top of the history. */
static void
pupa_history_add (char *s)
{
/* Remove the oldest entry in the history to make room for a new
entry. */
if (hist_used + 1 > hist_size)
{
hist_end--;
if (hist_end < 0)
hist_end = hist_size + hist_end;
pupa_free (hist_lines[hist_end]);
}
else
hist_used++;
/* Move to the next position. */
hist_pos--;
if (hist_pos < 0)
hist_pos = hist_size + hist_pos;
/* Insert into history. */
hist_lines[hist_pos] = pupa_strdup (s);
}
/* Replace the history entry on position POS with the string S. */
static void
pupa_history_replace (int pos, char *s)
{
pos = (hist_pos + pos) % hist_size;
pupa_free (hist_lines[pos]);
hist_lines[pos] = pupa_strdup (s);
}
/* 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 *
pupa_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 pupa_partition_iterate. */
pupa_device_t partdev;
/* String that is added when matched. */
char *matchstr;
void print_simple_completion (char *comp)
{
pupa_printf (" %s", comp);
}
void print_partition_completion (char *comp)
{
pupa_fs_t fs = 0;
pupa_device_t part;
char devname[20];
pupa_sprintf (devname, "%s,%s", partdev->disk->name, comp);
part = pupa_device_open (devname);
if (!part)
pupa_printf ("\n\tPartition num:%s, Filesystem cannot be accessed",
comp);
else
{
char *label;
fs = pupa_fs_probe (part);
/* Ignore all errors. */
pupa_errno = 0;
pupa_printf ("\n\tPartition num:%s, Filesystem type %s",
comp, fs ? fs->name : "Unknown");
if (fs)
{
(fs->label) (part, &label);
if (pupa_errno == PUPA_ERR_NONE)
{
if (label && pupa_strlen (label))
pupa_printf (", Label: %s", label);
pupa_free (label);
}
pupa_errno = PUPA_ERR_NONE;
}
pupa_device_close (part);
}
}
/* 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 || pupa_strncmp (pos, comp, len) == 0)
{
numfound++;
if (numfound == 1)
{
begin = len;
found = pupa_strdup (comp);
end = pupa_strlen (found);
matchstr = (char *) match;
}
/* Multiple matches found, print the first instead of completing. */
else if (numfound == 2)
{
pupa_printf ("\nPossible %s are: ", 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 pupa_partition_t p)
{
add_completion (pupa_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[pupa_strlen (filename) + 2];
pupa_strcpy (fname, filename);
pupa_sprintf (fname, "%s/", filename);
add_completion (fname, "", "files", print_simple_completion);
}
return 0;
}
int iterate_dev (const char *devname)
{
pupa_device_t dev;
/* Complete the partition part. */
dev = pupa_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);
}
return 0;
}
int iterate_commands (pupa_command_t cmd)
{
if (cmd->flags & PUPA_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 = pupa_strchr (pos, ' ');
if (!path)
{
/* Tab complete a command. */
len = pupa_strlen (pos);
pupa_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 == '(' && !pupa_strchr (pos, ')'))
{
/* Check if this is a device or partition. */
char *partition = pupa_strchr (++pos, ',');
if (!partition)
{
/* Complete the disk part. */
len = pupa_strlen (pos);
pupa_disk_dev_iterate (iterate_dev);
if (pupa_errno)
goto fail;
}
else
{
*partition = '\0';
/* Complete the partition part. */
partdev = pupa_device_open (pos);
*partition = ',';
pupa_errno = PUPA_ERR_NONE;
if (partdev)
{
if (partdev->disk && partdev->disk->has_partitions)
{
pos = partition + 1;
len = pupa_strlen (pos);
pupa_partition_iterate (partdev->disk, iterate_part);
if (pupa_errno)
pupa_errno = 0;
}
pupa_device_close (partdev);
}
else
goto fail;
}
}
else
{
char *device = pupa_file_get_device_name (pos);
pupa_device_t dev;
pupa_fs_t fs;
dev = pupa_device_open (device);
if (!dev)
goto fail;
fs = pupa_fs_probe (dev);
if (pupa_errno)
goto fail;
pos = pupa_strrchr (pos, '/');
if (pos)
{
char *dir;
char *dirfile;
pos++;
len = pupa_strlen (pos);
dir = pupa_strchr (path, '/');
if (!dir)
{
*restore = 0;
return 0;
}
dir = pupa_strdup (dir);
/* Cut away the filename part. */
dirfile = pupa_strrchr (dir, '/');
dirfile[1] = '\0';
/* Tab complete a file. */
(fs->dir) (dev, dir, iterate_dir);
if (dev)
pupa_device_close (dev);
pupa_free (device);
pupa_free (dir);
if (pupa_errno)
goto fail;
}
else
{
found = pupa_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 = pupa_malloc (end - begin + 1 + sizeof (matchstr));
pupa_strncpy (insert, found + begin, end - begin);
insert[end - begin] = '\0';
if (numfound == 1)
pupa_strcat (insert, matchstr);
pupa_free (found);
return insert;
}
fail:
pupa_free (found);
pupa_errno = PUPA_ERR_NONE;
return 0;
}
void void
pupa_cmdline_run (int nested) pupa_cmdline_run (int nested)
{ {
@ -82,6 +503,7 @@ pupa_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
pupa_size_t plen; pupa_size_t plen;
char buf[max_len]; char buf[max_len];
int key; int key;
int histpos = 0;
auto void cl_insert (const char *str); auto void cl_insert (const char *str);
auto void cl_delete (unsigned len); auto void cl_delete (unsigned len);
auto void cl_print (int pos, int c); auto void cl_print (int pos, int c);
@ -167,6 +589,8 @@ pupa_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
cl_insert (cmdline); cl_insert (cmdline);
pupa_history_add (buf);
while ((key = PUPA_TERM_ASCII_CHAR (pupa_getkey ())) != '\n' && key != '\r') while ((key = PUPA_TERM_ASCII_CHAR (pupa_getkey ())) != '\n' && key != '\r')
{ {
if (readline) if (readline)
@ -200,7 +624,34 @@ pupa_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
break; break;
case 9: /* Ctrl-i or TAB */ case 9: /* Ctrl-i or TAB */
/* FIXME */ {
char *insert;
int restore;
/* Backup the next character and make it 0 so it will
be easy to use string functions. */
char backup = buf[lpos];
buf[lpos] = '\0';
insert = pupa_tab_complete (buf, &restore);
/* Restore the original string. */
buf[lpos] = backup;
if (restore)
{
/* Restore the prompt. */
pupa_printf ("\n%s%s", prompt, buf);
xpos = plen;
ystart = ypos = (pupa_getxy () & 0xFF);
}
if (insert)
{
cl_insert (insert);
pupa_free (insert);
}
}
break; break;
case 11: /* Ctrl-k */ case 11: /* Ctrl-k */
@ -217,11 +668,34 @@ pupa_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
break; break;
case 14: /* Ctrl-n */ case 14: /* Ctrl-n */
/* FIXME */ {
break; char *hist;
lpos = 0;
if (histpos > 0)
histpos--;
cl_delete (llen);
hist = pupa_history_get (histpos);
cl_insert (hist);
break;
}
case 16: /* Ctrl-p */ case 16: /* Ctrl-p */
/* FIXME */ {
char *hist;
lpos = 0;
if (histpos < hist_used - 1)
histpos++;
cl_delete (llen);
hist = pupa_history_get (histpos);
cl_insert (hist);
}
break; break;
case 21: /* Ctrl-u */ case 21: /* Ctrl-u */
@ -282,6 +756,8 @@ pupa_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
} }
break; break;
} }
pupa_history_replace (histpos, buf);
} }
pupa_putchar ('\n'); pupa_putchar ('\n');

View file

@ -1,6 +1,7 @@
/* /*
* PUPA -- Preliminary Universal Programming Architecture for GRUB * PUPA -- Preliminary Universal Programming Architecture for GRUB
* Copyright (C) 2003 Yoshinori K. Okuji <okuji@enbug.org> * Copyright (C) 2003 Yoshinori K. Okuji <okuji@enbug.org>
* Copyright (C) 2003 Marco Gerards <metgerards@student.han.nl>.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -95,6 +96,15 @@ pupa_command_find (char *cmdline)
return cmd; return cmd;
} }
int
pupa_iterate_commands (int (*iterate) (pupa_command_t))
{
pupa_command_t cmd;
for (cmd = pupa_command_list; cmd; cmd = cmd->next)
iterate (cmd);
return 0;
}
int int
pupa_command_execute (char *cmdline) pupa_command_execute (char *cmdline)
{ {

View file

@ -3,6 +3,7 @@
* PUPA -- Preliminary Universal Programming Architecture for GRUB * PUPA -- Preliminary Universal Programming Architecture for GRUB
* Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. * Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
* Copyright (C) 2002,2003 Yoshinori K. Okuji <okuji@enbug.org> * Copyright (C) 2002,2003 Yoshinori K. Okuji <okuji@enbug.org>
* Copyright (C) 2003 Marco Gerards <metgerards@student.han.nl>.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -30,6 +31,8 @@
pupa_jmp_buf pupa_exit_env; pupa_jmp_buf pupa_exit_env;
#define PUPA_DEFAULT_HISTORY_SIZE 50
/* Read a line from the file FILE. */ /* Read a line from the file FILE. */
static int static int
get_line (pupa_file_t file, char cmdline[], int max_len) get_line (pupa_file_t file, char cmdline[], int max_len)
@ -332,11 +335,12 @@ pupa_rescue_cmd_normal (int argc, char *argv[])
pupa_enter_normal_mode (argv[0]); pupa_enter_normal_mode (argv[0]);
} }
#ifdef PUPA_UTIL #ifdef PUPA_UTIL
void void
pupa_normal_init (void) pupa_normal_init (void)
{ {
pupa_set_history (PUPA_DEFAULT_HISTORY_SIZE);
/* Register a command "normal" for the rescue mode. */ /* Register a command "normal" for the rescue mode. */
pupa_rescue_register_command ("normal", pupa_rescue_cmd_normal, pupa_rescue_register_command ("normal", pupa_rescue_cmd_normal,
"enter normal mode"); "enter normal mode");
@ -349,6 +353,7 @@ pupa_normal_init (void)
void void
pupa_normal_fini (void) pupa_normal_fini (void)
{ {
pupa_set_history (0);
pupa_rescue_unregister_command ("normal"); pupa_rescue_unregister_command ("normal");
} }
@ -358,6 +363,8 @@ PUPA_MOD_INIT
/* Normal mode shouldn't be unloaded. */ /* Normal mode shouldn't be unloaded. */
pupa_dl_ref (mod); pupa_dl_ref (mod);
pupa_set_history (PUPA_DEFAULT_HISTORY_SIZE);
/* Register a command "normal" for the rescue mode. */ /* Register a command "normal" for the rescue mode. */
pupa_rescue_register_command ("normal", pupa_rescue_cmd_normal, pupa_rescue_register_command ("normal", pupa_rescue_cmd_normal,
"enter normal mode"); "enter normal mode");
@ -368,6 +375,7 @@ PUPA_MOD_INIT
PUPA_MOD_FINI PUPA_MOD_FINI
{ {
pupa_set_history (0);
pupa_rescue_unregister_command ("normal"); pupa_rescue_unregister_command ("normal");
} }
#endif /* ! PUPA_UTIL */ #endif /* ! PUPA_UTIL */

View file

@ -95,6 +95,9 @@ pupa_ncurses_getkey (void)
break; break;
case KEY_BACKSPACE: case KEY_BACKSPACE:
/* XXX: For some reason ncurses on xterm does not return
KEY_BACKSPACE. */
case 127:
c = PUPA_CONSOLE_KEY_BACKSPACE; c = PUPA_CONSOLE_KEY_BACKSPACE;
break; break;