grub-0.95

Rudolf Weber rfweber at tesionmail.de
Mon Oct 11 20:32:14 CEST 2004


Hallo,

I adaped the patch for grup for grub-0.95.

The grub in the Dresden CVS don't compile with gcc-3.3. and gcc-3.4.0
(as I tried it)

Grub2 is very promissing, but it don't find the symbol tyble (as I tried
it)
I think it is a good idea to put the Dresdner grub enhancement in the
official grub2.

Greetings
	Rudolf Weber

P.S: My new Notebook boots now from the net and the grub have now
variables ...

P.P.S: I have worked on RACE http://www.infnet.verein.de/produkte/race/
and dream to map ACE/RACE on L4

-- 
--
---------------------------------------------------------------
Rudolf Weber
http://www.infnet.verein.de/~rw 
E-Mail: rfweber at tesionmail.de
-------------- next part --------------
--- ./stage2/asm.S.voros	2004-05-23 18:22:23.000000000 +0200
+++ ./stage2/asm.S	2004-09-11 00:48:08.000000000 +0200
@@ -951,6 +951,8 @@
 
 	pushl	%esi
 	pushl	%ebx
+        pushl   %ecx
+	pushl   %edx
 
 	/* compute the address of disk_address_packet */
 	movl	0x10(%ebp), %eax
@@ -980,6 +982,8 @@
 
 	movb	%dl, %al	/* return value in %eax */
 
+        popl    %edx
+        popl    %ecx
 	popl	%ebx
 	popl	%esi
 	popl	%ebp
@@ -1610,6 +1614,66 @@
 	ret
 
 		
+	ENTRY(reset_vbe_mode)
+	pushl   %ebp
+	movl    %esp, %ebp
+	pushl   %ebx
+	
+	call    EXT_C(prot_to_real)
+	.code16
+	
+	movw    $0x0003, %ax
+	int     $0x10
+	
+	DATA32  call    EXT_C(real_to_prot)
+	.code32
+	
+	popl    %ebx
+	popl    %ebp
+	ret
+	
+	
+	ENTRY(get_vbe_pmif)
+	pushl   %ebp
+	movl    %esp, %ebp
+	pushl   %ebx
+	pushl   %esi
+	pushl   %edi
+	
+	pushl   %ebp
+	
+	call    EXT_C(prot_to_real)
+	.code16
+	
+	movw    $0x4F0A, %ax
+	xorw    %bx,%bx
+	xorw    %di,%di
+	int     $0x10
+	xorl    %ebx,%ebx
+	cmpw    $0x004F,%ax
+	jnz     nopm
+	
+	movw    %es,%bx
+	shll    $16,%ebx
+	movw    %di,%bx
+	
+	nopm:  DATA32  call    EXT_C(real_to_prot)
+	.code32
+	
+	popl    %ebp
+	
+	movl    0x8(%ebp),%eax
+	movl    %ebx,(%eax)
+	movl    0xc(%ebp),%eax
+	andl    $0xFFFF,%ecx
+	movl    %ecx,(%eax)
+	
+	popl    %edi
+	popl    %esi
+	popl    %ebx
+	popl    %ebp
+	ret
+
 /*
  * gateA20(int linear)
  *
--- ./stage2/bios.c.voros	2004-03-27 17:34:04.000000000 +0100
+++ ./stage2/bios.c	2004-09-11 00:59:35.000000000 +0200
@@ -86,6 +86,10 @@
 #ifndef NO_INT13_FALLBACK
       if (err)
 	{
+           /* We can't switch to CHS mode */
+          if (geometry->cylinders == 0)
+             return err;
+
 	  if (geometry->flags & BIOSDISK_FLAG_CDROM)
 	    return err;
 	  
@@ -187,6 +191,7 @@
 
   /* Clear the flags.  */
   geometry->flags = 0;
+  geometry->total_sectors = 0;
   
   if (drive & 0x80)
     {
--- ./stage2/boot.c.voros	2004-03-30 13:44:08.000000000 +0200
+++ ./stage2/boot.c	2004-09-11 01:06:31.000000000 +0200
@@ -769,6 +769,16 @@
   if (!grub_open (module))
     return 0;
 
+  if ((cur_addr + filemax) >= (1024*(1024+mbi.mem_upper)))
+    {
+      printf("Want to load module to 0x%x len 0x%x but only have 0x%x RAM\n",
+            cur_addr, filemax, 1024*(1024+mbi.mem_upper));
+      errnum = ERR_BADMODADDR;
+      grub_close ();
+      return 0;
+    }
+
+
   len = grub_read ((char *) cur_addr, -1);
   if (! len)
     {
@@ -795,6 +805,36 @@
   return 1;
 }
 
+void
+create_vbe_module(void *ctrl_info, int ctrl_info_len,
+                 void *mode_info, int mode_info_len,
+                 int mode, int pmif, int pmif_len,
+                 unsigned int version)
+{
+  /* if we are supposed to load on 4K boundaries */
+  cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
+
+  printf ("   [VESA %d.%d info @ 0x%x, 0x%x bytes]\n",
+      version >> 8, version & 0xFF,
+      cur_addr, ctrl_info_len + mode_info_len);
+
+  grub_memmove((char*)cur_addr, ctrl_info, ctrl_info_len);
+  mbi.vbe_control_info = (int)cur_addr;
+  cur_addr += ctrl_info_len;
+
+  grub_memmove((char*)cur_addr, mode_info, mode_info_len);
+  mbi.vbe_mode_info    = (int)cur_addr;
+  cur_addr += mode_info_len;
+
+  mbi.flags |= MB_INFO_VIDEO_INFO;
+
+  mbi.vbe_mode         = mode;
+  mbi.vbe_interface_seg = (pmif >> 16) & 0xFFFF;
+  mbi.vbe_interface_off =  pmif        & 0xFFFF;
+  mbi.vbe_interface_len = pmif_len;
+}
+
+
 int
 load_initrd (char *initrd)
 {
@@ -854,6 +894,13 @@
 }
 
 
+void
+set_load_addr (int addr)
+{
+  printf ("Setting module load address to 0x%x\n", addr);
+  cur_addr = addr;
+}
+
 #ifdef GRUB_UTIL
 /* Dummy function to fake the *BSD boot.  */
 static void
--- ./stage2/builtins.c.voros	2004-05-14 21:30:52.000000000 +0200
+++ ./stage2/builtins.c	2004-09-11 16:48:30.000000000 +0200
@@ -2542,6 +2542,40 @@
 };
 #endif /* USE_MD5_PASSWORDS */
 
+/* modaddr */
+static int
+modaddr_func (char *arg, int flags)
+{
+  int addr;
+
+  switch (kernel_type)
+    {
+    case KERNEL_TYPE_MULTIBOOT:
+      if (safe_parse_maxint(&arg, &addr))
+       {
+         set_load_addr(addr);
+         break;
+       }
+
+      /* else fallthrough */
+
+    default:
+      errnum = ERR_NEED_MB_KERNEL;
+      return 1;
+    }
+
+  return 0;
+}
+
+static struct builtin builtin_modaddr =
+{
+  "modaddr",
+  modaddr_func,
+  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "modaddr ADDRESS",
+  "Set the load address for the next Multiboot module to ADDRESS"
+};
+
 
 /* module */
 static int
@@ -4664,6 +4698,1005 @@
   " the information about only the mode."
 };
   
+/* vbeset MODE */
+static int
+vbeset_func (char *arg, int flags)
+{
+#ifndef GRUB_UTIL
+  int mode_number;
+  int pmif_segoff, pmif_len;
+  struct vbe_controller controller;
+  struct vbe_mode mode;
+
+  if (kernel_type != KERNEL_TYPE_MULTIBOOT)
+    {
+      grub_printf("Multiboot kernel must be loaded before vbeset command\n");
+      errnum = MAX_ERR_NUM;
+      return 1;
+    }
+
+  if (! *arg)
+    {
+      reset_vbe_mode ();
+      return 0;
+    }
+
+  if (! safe_parse_maxint (&arg, &mode_number))
+    return 1;
+
+  /* Preset `VBE2'.  */
+  grub_memmove (controller.signature, "VBE2", 4);
+
+  /* Detect VBE BIOS.  */
+  if (get_vbe_controller_info (&controller) != 0x004F)
+    {
+      grub_printf (" VBE BIOS is not present.\n");
+      return 1;
+    }
+  if (controller.version < 0x0200)
+    {
+      grub_printf (" VBE version %d.%d is not supported.\n",
+                  (int) (controller.version >> 8),
+                  (int) (controller.version & 0xFF));
+      errnum = MAX_ERR_NUM;
+      return 1;
+    }
+
+  if (get_vbe_mode_info (mode_number, &mode) != 0x004F
+      || (mode.mode_attributes & 0x0091) != 0x0091)
+    {
+      grub_printf (" Mode 0x%x is not supported.\n", mode_number);
+      errnum = MAX_ERR_NUM;
+      return 1;
+    }
+
+  /* Now trip to the graphics mode.  */
+  if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F)
+    {
+      grub_printf (" Switching to Mode 0x%x failed.\n", mode_number);
+      errnum = MAX_ERR_NUM;
+      return 1;
+    }
+
+  get_vbe_pmif(&pmif_segoff, &pmif_len);
+  create_vbe_module(&controller, sizeof(struct vbe_controller),
+                   &mode, sizeof(struct vbe_mode),
+                   mode_number, pmif_segoff, pmif_len, controller.version);
+
+  /* mode setting was successful */
+  return 0;
+#else
+  errnum = ERR_BAD_ARGUMENT;
+  return 1;
+#endif
+}
+
+static struct builtin builtin_vbeset =
+{
+  "vbeset",
+  vbeset_func,
+  BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+  "vbeset [MODE]",
+  "Set the VBE mode MODE. If no MODE is given, switch back to text mode."
+};
+
+
+#define VARIABLE_STORE_SIZE 1024
+char variable_store[VARIABLE_STORE_SIZE];
+unsigned int variable_store_actpos; /* Points to the next free entry */
+struct variable_list_struct {
+  char *name;
+  char *value;
+} variable_list[VARIABLES_MAX];
+
+static void var_show(void)
+{
+  int i = 0;
+
+  for (; i < VARIABLES_MAX; i++)
+    if (variable_list[i].name)
+      {
+       grub_printf("%s = %s\n",
+                   variable_list[i].name,
+                   variable_list[i].value);
+      }
+}
+
+static int var_get_index(char *var)
+{
+  int i = 0;
+
+  if (!*var)
+    return -1;
+
+  for (; i < VARIABLES_MAX; i++)
+    if (variable_list[i].name &&
+       grub_strcmp(variable_list[i].name, var) == 0)
+      return i;
+
+  return -1;
+}
+
+char *var_get(char *var)
+{
+  int i;
+
+  if ((i = var_get_index(var)) == -1)
+    return NULL;
+
+  return variable_list[i].value;
+}
+
+static char *var_alloc_mem(unsigned int len)
+{
+  if (VARIABLE_STORE_SIZE < variable_store_actpos + len
+      || !len)
+    return NULL;
+
+  variable_store_actpos += len;
+  return &variable_store[variable_store_actpos - len];
+}
+
+/* Maybe we're implementing "unset" later? */
+static int var_get_free_var(void)
+{
+  int i = 0;
+
+  for (; i < VARIABLES_MAX; i++)
+    if (variable_list[i].name == NULL)
+      return i;
+
+  return -1;
+}
+static inline char *skip_ws(char *s)
+{
+  while (isspace(*s))
+    s++;
+  return s;
+}
+
+static int var_sprint_once(char *buf, char *str)
+{
+  char *b = buf;
+
+  while (*str)
+    {
+      if (*str == '$' && *(str + 1) == '(')
+       {
+         /* Found start of variable */
+         char *end_var;
+         char *c = str + 2;
+
+         end_var = c;
+         while (*end_var && *end_var != ')')
+           end_var++;
+
+         if (*end_var == ')')
+           {
+             char *val;
+
+             /* Copy variable name into var */
+
+              str = end_var + 1;
+
+             *end_var = 0;
+             if ((val = var_get(c)))
+               {
+                 /* All ok, we got it */
+                 /* Copy to buf */
+                 while (*val)
+                   *b++ = *val++;
+
+                 *end_var = ')';
+
+                 continue;
+               }
+             /* else
+               grub_printf("Unknown variable: %var!\n", var); */
+
+             *end_var = ')';
+           }
+       }
+      *b++ = *str++;
+    }
+
+  *b = 0;
+
+  return b - buf;
+}
+
+int var_sprint(char *buf, char *str)
+{
+  int i = 10;
+  /* Waste some stack here... */
+  const int buffer_size = 1000;
+  char buffer[buffer_size];
+
+  grub_strcpy(buf, str);
+
+  /* We're not checking any return values here or any array overflows... :( */
+  do
+    {
+      if (grub_strlen(buf) > buffer_size)
+       {
+         grub_printf("Buffer overflow: %s(%d)\n", __FILE__, __LINE__);
+         while (1) {}
+       }
+
+      grub_strcpy(buffer, buf);
+
+      var_sprint_once(buf, buffer);
+    }
+  while (--i && grub_strcmp(buf, buffer));
+  if (!i)
+    {
+      grub_printf("Possible loop in var_sprintf!\n");
+      getkey();
+    }
+
+  return grub_strlen(buf);
+}
+
+/* Use our own buffer instead of a supplied one and
+ * return the pointer to the buffer and not the bytes
+ * processed. */
+/* We try to detect buffer overruns... */
+static char var_sprint_buffer[1500];
+static const long var_sprint_magic = 0x14233241;
+char *var_sprint_buf(char *str, int *bytes)
+{
+  *(long *)(var_sprint_buffer + sizeof(var_sprint_buffer) - sizeof(var_sprint_magic)) = var_sprint_magic;
+
+  *bytes = var_sprint(var_sprint_buffer, str);
+
+  if (*(long *)(var_sprint_buffer + sizeof(var_sprint_buffer) - sizeof(var_sprint_magic)) != var_sprint_magic)
+    {
+      grub_printf("Possible buffer overrun: %s(%d)\n", __FILE__, __LINE__);
+      while (1) {}
+    }
+  return var_sprint_buffer;
+}
+/* This function just updates the pointer to the value, this value has to
+ * be inside the variable_store */
+static int var_set_no_copy(char *name, char *val)
+{
+  int i;
+
+  if (val < variable_store || val >= (variable_store + VARIABLE_STORE_SIZE))
+    return 1;
+
+  i = var_get_index(name);
+
+  if (i == -1)
+    {
+      /* The variable doesn't exist yet, so we have a new variable */
+      char *a = name;
+
+      /* Some sanity check */
+      while (*a)
+       {
+         if (*a == '(' || *a == ')' || *a == ' ')
+           return 1;
+         a++;
+        }
+
+
+      if ((i = var_get_free_var()) == -1)
+       return 1;
+
+      if ((a = var_alloc_mem(grub_strlen(name) + 1)) == NULL)
+       return 1;
+
+      grub_strcpy(a, name);
+      variable_list[i].name = a;
+    }
+
+  variable_list[i].value = val;
+
+  return 0; /* Ok */
+}
+
+/* XXX: this is a bit code duplication with var_set_no_copy,
+ *      so if someone has some free time, feel free to join this
+ */
+int var_set(char *name, char *value, int parse)
+{
+  int i;
+
+  if (parse)
+    value = var_sprint_buf(value, &i);
+
+  i = var_get_index(name);
+
+  if (i == -1)
+    {
+      /* The variable doesn't exist yet, so we have a new variable */
+      char *a = name;
+
+      /* Some sanity check */
+      while (*a)
+       {
+         if (*a == '(' || *a == ')' || *a == ' ')
+           return 1;
+         a++;
+        }
+
+      if ((i = var_get_free_var()) == -1)
+       return 1;
+
+      if ((a = var_alloc_mem(grub_strlen(name) + 1)) == NULL)
+       return 1;
+
+      grub_strcpy(a, name);
+      variable_list[i].name = a;
+
+      if ((a = var_alloc_mem(grub_strlen(value) + 1)) == NULL)
+       return 1;
+
+      grub_strcpy(a, value);
+      variable_list[i].value = a;
+    }
+  else
+    {
+      /* Variable already exists */
+      if (grub_strlen(variable_list[i].value) >= grub_strlen(value))
+       {
+         /* We can just replace the value but we're potentially
+          * loosing space */
+         grub_strcpy(variable_list[i].value, value);
+       }
+      else
+       {
+         /* New value is longer then the old one, we need to +
+           * allocate a new place and drop the old one (i.e. wasting it) */ 
+         char *a;
+         if ((a = var_alloc_mem(grub_strlen(value) + 1)) == NULL)
+           return 1;
+
+         grub_strcpy(a, value);
+
+         variable_list[i].value = a;
+       }
+    }
+
+  //grub_printf("Saved %s=\"%s\" in slot %d.\n", variable_list[i].name, variable_list[i].value, i + 1);
+  //getkey();
+
+  return 0; /* Ok */
+}
+
+
+static int
+set_func(char *arg, int flags)
+{
+  char *a = arg;
+  char *variable, *value;
+  char *end_variable, end_variable_val;
+  char *end_value, end_value_val;
+  char end_char;
+  int i = 0, parse = 0, emptysetonly = 0;
+
+  a = skip_ws(a);
+
+  if (!*a)
+    {
+      var_show();
+      return 0;
+    }
+
+  variable = a;
+  while (*a && *a != ':' && *a != '=' && *a != ' ')
+    a++;
+  end_variable_val = *a;
+  end_variable = a;
+  a = skip_ws(a);
+
+  if (*a == ':')
+    {
+      parse = 1;
+      a++;
+    }
+  if (*a == '?')
+    {
+      emptysetonly = 1;
+      a++;
+    }
+
+  if (*a != '=')
+    goto bad_arg;
+
+  a++;
+  a = skip_ws(a);
+
+  end_char = ' ';
+  if (*a == '"')
+    {
+      end_char = *a;
+      a++;
+    }
+  /* XXX: add/fix \" and \\ stuff */
+  value = a;
+  while (*a && *a != end_char)
+    a++;
+  end_value_val = *a;
+  end_value = a;
+
+  *end_value = *end_variable = 0;
+
+  if ((emptysetonly && var_get_index(variable) == -1) ||
+      !emptysetonly)
+    i = var_set(variable, value, parse);
+
+  *end_value    = end_value_val;
+  *end_variable = end_variable_val;
+
+  return i;
+
+bad_arg:
+  grub_printf("%s: ERR_BAD_ARGUMENT\n", __func__);
+  getkey();
+  errnum = ERR_BAD_ARGUMENT;
+  return 1;
+}
+
+static struct builtin builtin_set =
+{
+  "set",
+  set_func,
+  BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+  "set var=val",
+  "Set a variable to a value."
+};
+
+static int
+print_func(char *arg, int flags)
+{
+  grub_printf("%s\n", var_sprint_buf(arg, &flags));
+  return 0;
+}
+
+static struct builtin builtin_print =
+{
+  "print",
+  print_func,
+  BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+  "print \"string with vars\"",
+  "Print a string which may contain variables. Variables are enclosed"
+  " in $( and ) (like \"make\")."
+};
+
+static struct builtin builtin_echo =
+{
+  "echo",
+  print_func,
+  BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+  "echo \"string with vars\"",
+  "Alias for \"print\"."
+};
+
+
+
+
+#define TOGGLES 10
+#define MAX_BLOCKS 7
+#define MAX_VAR_PER_BLOCK 4
+
+struct toggle_data_struct {
+  int key; /* int because of F-keys !? */
+  int current_block;
+  char nr_blocks;
+  struct {
+    char nr_vars;
+    struct {
+      int var;         /* index of variable_list */
+      char *value;     /* pointer to value */
+    } var[MAX_VAR_PER_BLOCK];
+  } block[MAX_BLOCKS];
+} toggle_data[TOGGLES];
+int toggles_used = 0;
+
+char toggle_trigger_init_done;
+
+static int get_toggle_slot_for_key(int key)
+{
+  int i = 0;
+
+  for (; i < TOGGLES; i++)
+    if (toggle_data[i].key == key)
+      return i;
+
+  return -1;
+}
+
+int toggle_print_status(int x, int y)
+{
+  /* Basically print all variable which are on the left side on toggles */
+  int printed[VARIABLES_MAX];
+  int printed_something = 0;
+  int i, t, b, v, dummy;
+  const int ylines = 6;
+  int xpos[ylines];
+  int dy = 0;
+
+  for (i = 0; i < ylines; i++)
+    xpos[i] = x;
+  for (i = 0; i < VARIABLES_MAX; i++)
+    printed[i] = 0;
+
+  for (t = 0; t < toggles_used; t++)
+    {
+      for (b = 0; b < toggle_data[t].nr_blocks; b++)
+       {
+         for (v = 0; v < toggle_data[t].block[b].nr_vars; v++)
+           {
+             i = toggle_data[t].block[b].var[v].var;
+             if (!printed[i])
+               {
+                 int len;
+                 char *vals;
+
+                 gotoxy(xpos[dy], y + dy);
+
+                 /* don't use printf here since we need the lengths
+                  * of the printed string and we don't want to use another
+                  * buffer for sprintf
+                  */
+                 grub_putstr(variable_list[i].name);
+                 grub_putchar('=');
+                 len = grub_strlen(variable_list[i].name) + 1;
+
+                 vals = var_sprint_buf(variable_list[i].value, &dummy);
+                 grub_putstr(vals);
+                 len += grub_strlen(vals);
+
+                 xpos[dy] += len + 2;
+
+                 if (++dy == ylines) {
+                   dy = 0;
+                 }
+
+                 printed[i] = printed_something = 1;
+               }
+           }
+       }
+    }
+
+  return printed_something;
+}
+
+static int toggle_do_block(int slot, int block_nr)
+{
+  int v;
+
+  if (slot >= toggles_used || block_nr >= toggle_data[slot].nr_blocks)
+    return 0;
+
+  /* Set all variables in th block block_nr to their new values */
+  for (v = 0; v < toggle_data[slot].block[block_nr].nr_vars; v++)
+    {
+      int l = toggle_data[slot].block[block_nr].var[v].var;
+
+      var_set_no_copy(variable_list[l].name, toggle_data[slot].block[block_nr].var[v].value);
+    }
+
+  return 1; /* Ok */
+}
+static int toggle_find_slot(int key)
+{
+  int i = 0;
+
+  for (; i < toggles_used; i++)
+      if (toggle_data[i].key == key)
+       return i;
+
+  return -1;
+}
+
+int toggle_do_key(int key)
+{
+  int slot;
+
+  if ((slot = toggle_find_slot(key)) == -1)
+    return 0;
+
+  /* Proceed to the next block */
+  if (++toggle_data[slot].current_block == toggle_data[slot].nr_blocks)
+    toggle_data[slot].current_block = 0;
+
+  toggle_do_block(slot, toggle_data[slot].current_block);
+
+  return 1;
+}
+
+static int
+toggle_func(char *arg, int flags)
+{
+  int slot, key, block = 0, i;
+  char *a = arg, *eb;
+  int command;
+  enum {
+    COMMAND_SET,
+    COMMAND_SELECT,
+    COMMAND_TRIGGER,
+  };
+
+  static int process_var(int bl, int var, char *start, char *end)
+  {
+    char *p, origvar, *origvarp, origval, *v;
+
+    //grub_printf("VAR(%d, %d) %s [%d]\n", bl, var, start, end-start+1);
+
+    start = skip_ws(start);
+    p = start;
+    while (p < end && *p != '=' && !isspace(*p))
+      p++;
+
+    origvar = *p;
+    origvarp = p;
+
+    p = skip_ws(p);
+    if (*p != '=')
+      return 1;
+
+    p = skip_ws(p+1);
+
+    // value is now from p to end (both inclusive)
+
+    origval = *(end + 1);
+    *(end + 1) = 0;
+    *origvarp = 0;
+
+    /* See if we already have the same value in that toggle
+     * (in case we're entering a menu multiple time we would
+     *  allocate memory multiple time) */
+
+    if (toggle_data[slot].block[bl].var[var].value &&
+       var_get_index(start) != -1 &&
+       !grub_strcmp(toggle_data[slot].block[bl].var[var].value, p))
+      {
+      }
+    else
+      {
+       /* Allocate space for the value and hang it in */
+       if ((v = var_alloc_mem(grub_strlen(p) + 1)) == NULL)
+         return 1;
+       grub_strcpy(v, p);
+
+       var_set_no_copy(start, v);
+
+       if ((toggle_data[slot].block[bl].var[var].var = var_get_index(start)) == -1)
+         return 1; /* internal error */
+       toggle_data[slot].block[bl].var[var].value = v;
+      }
+
+    *origvarp = origvar;
+    *(end + 1) = origval;
+
+    //grub_printf("slot=%d block=%d var=%d %d=%s\n", slot, bl, var, toggle_data[slot].block[bl].var[var].var, v);
+
+    if (var >= toggle_data[slot].block[bl].nr_vars)
+      toggle_data[slot].block[bl].nr_vars = var + 1;
+
+    return 0;
+  }
+
+  static int process_block(int bl, char *start, char *end)
+  {
+    char *p = start;
+    int var = 0;
+
+    //grub_printf("BL(%d) %s [%d]\n", bl, start, end-start+1);
+
+    while (p <= end)
+      {
+       if (*p == ',' || p == end)
+         {
+           if (var == MAX_VAR_PER_BLOCK)
+             return ERR_WONT_FIT;
+
+           if (process_var(bl, var, start, (p == end) ? p : (p-1)))
+             return ERR_BAD_ARGUMENT;
+
+           var++;
+           start = p + 1;
+         }
+       p++;
+      }
+
+    return 0;
+  }
+
+
+  /* parse args */
+  /* proceed to next arg */
+  while (*a && *a == ' ')
+    a++;
+
+  /* Get command */
+  {
+    eb = a;
+
+    while (!isspace(*eb))
+      eb++;
+
+    if (!isspace(*eb))
+      goto bad_arg;
+
+    //grub_printf("trigger: processing line: %s\n", a);
+
+    *eb = 0;
+
+    if (!grub_strcmp(a, "set"))
+      command = COMMAND_SET;
+    else if (!grub_strcmp(a, "select"))
+      command = COMMAND_SELECT;
+    else if (!grub_strcmp(a, "trigger"))
+      command = COMMAND_TRIGGER;
+    else
+      {
+       grub_printf("toggle: Unknown command!\n");
+        goto bad_arg;
+      }
+    *eb = ' ';
+    a = eb + 1;
+  }
+
+  a = skip_ws(a);
+
+  if (command == COMMAND_SET)
+    {
+
+      if (!*a || !*(a+1))
+       goto bad_arg;
+
+      key = *a;
+      a++;
+
+      //grub_printf("key: %c\n", key);
+
+      /* Find slot for key */
+      slot = get_toggle_slot_for_key(key);
+      if (slot == -1)
+       {
+         /* Get next free toggle_data slot */
+         slot = toggles_used;
+         if (slot == TOGGLES)
+           goto wont_fit;
+         toggle_data[slot].key = key;
+         toggles_used++;
+       }
+
+      /* Reset current slot */
+      toggle_data[slot].nr_blocks = toggle_data[slot].current_block = 0;
+      for (i = 0; i < MAX_VAR_PER_BLOCK; i++)
+       toggle_data[slot].block[i].nr_vars = 0;
+
+      while (*a)
+       {
+         int ret;
+
+         a = skip_ws(a);
+
+         if (*a != '{')
+           goto bad_arg;
+         /* find the correspondig '}' */
+         eb = a++;
+         while (*eb && *eb != '}')
+           eb++;
+         if (*eb != '}')
+           goto bad_arg;
+         /* Now we have the block between a and eb-1 */
+         ret = process_block(block, a, eb-1);
+         if (ret == ERR_WONT_FIT)
+           goto wont_fit;
+         if (ret)
+           goto bad_arg;
+
+         a = eb + 1;
+
+         block++;
+         if (*a) {
+           if (block == MAX_BLOCKS)
+             goto wont_fit;
+         }
+       }
+      toggle_data[slot].nr_blocks = block;
+
+      /* finally, set all vars from the first block */
+      toggle_do_block(slot, 0);
+    }
+  else if (command == COMMAND_SELECT)
+    {
+      while (*a)
+       {
+         int k, b, s;
+
+         /* there's something between a and eb-1 now*/
+         /* *a is a key and *(a+1) == '=' */
+         k = *a++;
+
+         if (*a++ != '=')
+           goto bad_arg;
+
+         if (!safe_parse_maxint(&a, &b))
+           goto bad_arg;
+
+         if ((s = toggle_find_slot(k)) == -1)
+           goto bad_arg;
+
+         if (!toggle_do_block(s, b))
+           goto bad_arg;
+
+          toggle_data[s].current_block = b;
+
+          toggle_data[s].current_block = b;
+
+         a = skip_ws(a);
+       }
+    }
+  else if (command == COMMAND_TRIGGER)
+    {
+      char *vr, *vre, *vl, *vle, *vrval;
+      char o;
+      int cmp;
+      // remaining a(rg) format: VAR==VAL "command"
+      //grub_printf("%s: trigger\n");
+
+      /* Find the '=' */
+      vr = a;
+      while (*a && *a != ' ' && *a != '=')
+       a++;
+
+      if (*a != '=' || *(a+1) != '=')
+       goto bad_arg;
+
+      vre = a;
+
+      if (vr == vre)
+       goto bad_arg;
+
+      a += 2;
+      vl = a;
+
+      while (!isspace(*a))
+       a++;
+
+      vle = a;
+
+      if (vl == vle)
+       goto bad_arg;
+
+
+      *vre = 0;
+      vrval = var_get(vr);
+      *vre = '=';
+
+      if (!vrval)
+          goto bad_arg;
+
+      o = *vle;
+      *vle = 0;
+      cmp = grub_strcmp(vrval, vl);
+      *vle = o;
+
+      a = skip_ws(a);
+
+      if (!cmp)
+        toggle_func(a, 0);
+    }
+
+  return 0;
+
+wont_fit:
+  grub_printf("%s: ERR_WONT_FIT\n", __func__);
+  getkey();
+  errnum = ERR_WONT_FIT;
+  return 1;
+
+bad_arg:
+  grub_printf("%s: ERR_BAD_ARGUMENT\n", __func__);
+  getkey();
+  errnum = ERR_BAD_ARGUMENT;
+  return 1;
+}
+
+void toggle_trigger_init(void)
+{
+  static int detect_vmware(void)
+    {
+#ifndef GRUB_UTIL
+      char *start = (char *)0xc0000;
+      int size = 16 << 10;
+      int i = 0, p = 0;
+      char *s = "VMware, Inc.";
+
+
+      while (i < size)
+       {
+         if (*(start + i) == s[p])
+           {
+             p++;
+             if (!s[p])
+               return 1;
+           }
+         else
+           p = 0;
+         i++;
+       }
+#endif
+      return 0;
+    }
+
+  if (toggle_trigger_init_done)
+    return;
+  toggle_trigger_init_done = 1;
+
+  var_set("TT_VMWARE", (detect_vmware()) ? "1" : "0", 0);
+}
+
+static struct builtin builtin_toggle =
+{
+  "toggle",
+  toggle_func,
+  BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+  "toggle [command] args...",
+  "Doc me."
+};
+
+
+
+
+static char var_expand_line_edit = 1;
+
+char is_var_expand(void)
+{
+  return var_expand_line_edit;
+}
+
+static int
+varexpand_func(char *arg, int flags)
+{
+  static const char *on_vals[]  = { "on",  "true",  "1" };
+  static const char *off_vals[] = { "off", "false", "0" };
+  int i;
+
+  arg = skip_ws(arg);
+
+  for (i = 0; i < sizeof(on_vals) / sizeof(on_vals[0]); i++)
+    if (!grub_memcmp(arg, on_vals[i], sizeof(*on_vals[i])))
+      {
+       var_expand_line_edit = 1;
+       goto out;
+      }
+  for (i = 0; i < sizeof(off_vals) / sizeof(off_vals[0]); i++)
+    if (!grub_memcmp(arg, off_vals[i], sizeof(*off_vals[i])))
+      {
+       var_expand_line_edit = 0;
+       goto out;
+      }
+
+  if (*arg)
+    {
+      grub_printf("Unknown argument: %s\n", arg);
+      return 1;
+    }
+
+  var_expand_line_edit = !var_expand_line_edit;
+
+out:
+  grub_printf("Expansion is %s\n", var_expand_line_edit ? "on" : "off");
+  return 0;
+}
+static struct builtin builtin_varexpand =
+{
+  "varexpand",
+  varexpand_func,
+  BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+  "varexpand [on|off]",
+  "Expand lines in line editing? Default is on. It toggles without arguments."
+};
+
+
 
 /* The table of builtin commands. Sorted in dictionary order.  */
 struct builtin *builtin_table[] =
@@ -4691,6 +5724,7 @@
 #ifdef GRUB_UTIL
   &builtin_dump,
 #endif /* GRUB_UTIL */
+  &builtin_echo,
   &builtin_embed,
   &builtin_fallback,
   &builtin_find,
@@ -4714,6 +5748,7 @@
 #ifdef USE_MD5_PASSWORDS
   &builtin_md5crypt,
 #endif /* USE_MD5_PASSWORDS */
+  &builtin_modaddr,
   &builtin_module,
   &builtin_modulenounzip,
   &builtin_pager,
@@ -4721,6 +5756,7 @@
   &builtin_parttype,
   &builtin_password,
   &builtin_pause,
+  &builtin_print,
 #ifdef GRUB_UTIL
   &builtin_quit,
 #endif /* GRUB_UTIL */
@@ -4735,6 +5771,7 @@
 #ifdef SUPPORT_SERIAL
   &builtin_serial,
 #endif /* SUPPORT_SERIAL */
+  &builtin_set,
   &builtin_setkey,
   &builtin_setup,
 #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
@@ -4750,8 +5787,11 @@
 #endif /* SUPPORT_NETBOOT */
   &builtin_timeout,
   &builtin_title,
+  &builtin_toggle,
   &builtin_unhide,
   &builtin_uppermem,
+  &builtin_varexpand,
   &builtin_vbeprobe,
+  &builtin_vbeset,
   0
 };
--- ./stage2/cmdline.c.voros	2004-03-18 00:08:48.000000000 +0100
+++ ./stage2/cmdline.c	2004-09-11 01:56:37.000000000 +0200
@@ -134,6 +134,8 @@
     {
       struct builtin *builtin;
       char *arg;
+      int len;
+      char dump[700];
 
       *heap = 0;
       print_error ();
@@ -147,8 +149,10 @@
       if (! heap[0])
 	continue;
 
+      len = var_sprint(dump, heap);
+
       /* Find a builtin.  */
-      builtin = find_command (heap);
+      builtin = find_command (dump);
       if (! builtin)
 	continue;
 
@@ -168,7 +172,7 @@
 	count_lines = 0;
       
       /* Run BUILTIN->FUNC.  */
-      arg = skip_to (1, heap);
+      arg = skip_to (1, dump);
       (builtin->func) (arg, BUILTIN_CMDLINE);
 
       /* Finish the line count.  */
@@ -192,6 +196,8 @@
     {
       struct builtin *builtin;
       char *arg;
+      int len;
+      char dump[700];
 
       print_error ();
 
@@ -228,16 +234,22 @@
 	  grub_memmove (heap, "boot", 5);
 	}
 
+      len = var_sprint(dump, heap);
+
       /* Find a builtin.  */
-      builtin = find_command (heap);
+      builtin = find_command(dump);
       if (! builtin)
 	{
 	  grub_printf ("%s\n", old_entry);
+          grub_printf("dump=%s\n",dump);
 	  continue;
 	}
 
       if (! (builtin->flags & BUILTIN_NO_ECHO))
-	grub_printf ("%s\n", old_entry);
+      {
+	grub_printf ("old_entry=%s\n", old_entry);
+	grub_printf ("dump=%s\n", dump);
+      }
 
       /* If BUILTIN cannot be run in the command-line, skip it.  */
       if (! (builtin->flags & BUILTIN_CMDLINE))
@@ -251,7 +263,7 @@
       buf_drive = -1;
 
       /* Run BUILTIN->FUNC.  */
-      arg = skip_to (1, heap);
+      arg = skip_to (1, dump);
       (builtin->func) (arg, BUILTIN_SCRIPT);
     }
 }
--- ./stage2/common.c.voros	2004-03-27 17:25:44.000000000 +0100
+++ ./stage2/common.c	2004-09-11 01:57:47.000000000 +0200
@@ -88,6 +88,7 @@
   [ERR_UNRECOGNIZED] = "Unrecognized command",
   [ERR_WONT_FIT] = "Selected item cannot fit into memory",
   [ERR_WRITE] = "Disk write error",
+  [ERR_BADMODADDR] = "Bad modaddr",
 };
 
 
--- ./stage2/shared.h.voros	2004-05-14 21:38:37.000000000 +0200
+++ ./stage2/shared.h	2004-09-11 16:45:29.000000000 +0200
@@ -541,6 +541,7 @@
   ERR_DEV_NEED_INIT,
   ERR_NO_DISK_SPACE,
   ERR_NUMBER_OVERFLOW,
+  ERR_BADMODADDR,
 
   MAX_ERR_NUM
 } grub_error_t;
@@ -765,6 +766,25 @@
 /* Set VBE mode.  */
 int set_vbe_mode (int mode_number);
 
+/* Switch to text mode */
+void reset_vbe_mode (void);
+
+/* Get VBE pm interface entry */
+void get_vbe_pmif (unsigned int *segoff, unsigned int *len);
+
+/* Variable definitions and functions. */
+#define VARIABLES_MAX          30
+
+char *var_get(char *);
+int var_sprint(char *, char *);
+char *var_sprint_buf(char *, int *);
+int var_set(char *, char *, int);
+int toggle_print_status(int, int);
+int toggle_do_key(int key);
+void toggle_trigger_init(void);
+char is_var_expand(void);
+
+
 /* Return the data area immediately following our code. */
 int get_code_end (void);
 
@@ -979,6 +999,12 @@
 
 int load_module (char *module, char *arg);
 int load_initrd (char *initrd);
+void set_load_addr (int addr);
+void create_vbe_module(void *ctrl_info, int ctrl_info_len,
+                      void *mode_info, int mode_info_len,
+                      int mode, int pmif, int pmif_len,
+                      unsigned int version);
+
 
 int check_password(char *entered, char* expected, password_t type);
 #endif
--- ./stage2/stage2.c.voros	2004-03-27 17:09:41.000000000 +0100
+++ ./stage2/stage2.c	2004-09-11 17:19:01.000000000 +0200
@@ -19,6 +19,7 @@
 
 #include <shared.h>
 #include <term.h>
+#define MASTER_CONFIG_FILE "(nd)/grubmenu.lst"
 
 grub_jmp_buf restart_env;
 
@@ -76,6 +77,20 @@
 
 #endif /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */
 
+/* config_file is 128 Bytes long (see grub/asmstub.c) */
+#define CONFIG_FILE_LEN 128
+#define CONFIG_FILE_HISTORY_ENTRIES 10
+struct config_file_history_struct {
+  char filename[CONFIG_FILE_LEN];
+  int entryno;
+  int first_entry;
+};
+static struct config_file_history_struct
+        config_file_history[CONFIG_FILE_HISTORY_ENTRIES];
+static int config_file_history_pos, config_file_history_start,
+       config_file_history_prev_pos;
+static int config_file_history_menu_pos = -1;
+
 static char *
 get_entry (char *list, int num, int nested)
 {
@@ -105,6 +120,7 @@
   if (highlight && current_term->setcolorstate)
     current_term->setcolorstate (COLOR_STATE_HIGHLIGHT);
 
+  entry = var_sprint_buf(entry, &x);
   gotoxy (2, y);
   grub_putchar (' ');
   for (x = 3; x < 75; x++)
@@ -233,12 +249,108 @@
 {
   int c, time1, time2 = -1, first_entry = 0;
   char *cur_entry = 0;
+  char shortcut_buf[5];
+  int sc_matches;
+#define SEARCH_BUF_SIZE 20
+  char search_buf[SEARCH_BUF_SIZE];
+  int search_mode = 0, search_found = 0, search_direction = 0;
+
+  /* nested function, we need the code in multiple places */
+  static void set_bar_to(int i)
+    {
+      first_entry = i - 5;
+      entryno = 5;
+
+      if (first_entry < 0 || num_entries < 13)
+       {
+         entryno = i;
+         first_entry = 0;
+       }
+      else if (num_entries - i < 7)
+       {
+         first_entry = num_entries - 12;
+         entryno = i - first_entry;
+       }
+
+      print_entries (3, 12, first_entry,
+                    entryno, menu_entries);
+    }
+
+  /* search through menu_entries once around */
+  static int search_menu(char *buf, int current, int direction, int advance)
+    {
+      int i;
+      /* make direction a delta */
+      direction = (direction ? -1 : 1);
+
+      if (advance)
+       {
+         /* go to next search item */
+         current += direction;
+
+         /* correct overflows */
+         if (current < 0)
+           current = num_entries - 1;
+         else if (current == num_entries)
+           current = 0;
+       }
+
+      i = current;
+
+      do
+       {
+         int x;
+
+         /* get_entry is probably overkill here... */
+         char *s = var_sprint_buf(get_entry(menu_entries,
+                                            i, 0), &x);
+         for (; *s; s++)
+           {
+             char *sb = buf;
+             char *ss = s;
+             /* incasesensitive search */
+             while (*ss && *sb && grub_tolower(*ss) == *sb)
+               ss++, sb++;
+
+
+             if (!*sb) /* Found something! */
+               {
+                 set_bar_to(i);
+                 return i;
+               }
+           }
+
+         if (direction == -1 && i == 0)
+           i = num_entries;
+         i += direction;
+         if (direction == 1 && i == num_entries)
+           i = 0;
+       }
+      while (i != current);
+
+      /* Found nothing */
+      return -1;
+    }
+
+
+  *shortcut_buf = *search_buf = 0;
+
 
   /*
    *  Main loop for menu UI.
    */
 
 restart:
+
+  if (config_file_history_menu_pos != -1)
+    {
+      /* we're in a history back movement, set menu values to previous ones */
+      entryno     = config_file_history[config_file_history_menu_pos].entryno;
+      first_entry = config_file_history[config_file_history_menu_pos].first_entry;
+      config_file_history_menu_pos = -1;
+    }
+
+
   /* Dumb terminal always use all entries for display 
      invariant for TERM_DUMB: first_entry == 0  */
   if (! (current_term->flags & TERM_DUMB))
@@ -317,15 +429,23 @@
       else
 	{
 	  if (config_entries)
-	    printf ("\
-      Press enter to boot the selected OS, \'e\' to edit the\n\
-      commands before booting, or \'c\' for a command-line.");
+          {
+             if (!toggle_print_status(3, 18))
+             {
+        	 printf ("\n\n\
+      Press enter or %c to boot the selected OS,\n\
+      \'e\' to edit the commands before booting, or\
+      \'c\' for a command-line.");
+             }
+          }
 	  else
+          {
 	    printf ("\
       Press \'b\' to boot, \'e\' to edit the selected command in the\n\
       boot sequence, \'c\' for a command-line, \'o\' to open a new line\n\
       after (\'O\' for before) the selected line, \'d\' to remove the\n\
-      selected line, or escape to go back to the main menu.");
+      selected line, \'/?nN\' to search, or escape to go back to the main menu.");
+          }
 	}
 
       if (current_term->flags & TERM_DUMB)
@@ -366,6 +486,73 @@
 	  
 	  grub_timeout--;
 	}
+menu_restart:
+
+      /* Print the number of the current entry in the right upper corner of
+       * the menu, up to 999 entries are supported, modify the coordinates
+       * and putchar command to add more
+       * Additionally, print the shortcut buffer upper left if there's
+       * something in there */
+      if (! (current_term->flags & TERM_DUMB))
+        {
+         int x=0, i, l;
+
+         if (current_term->setcolorstate)
+           current_term->setcolorstate (COLOR_STATE_NORMAL);
+
+          /* current entry */
+          gotoxy(69, 3);
+          grub_printf("[%d]", first_entry + entryno);
+          grub_putchar(DISP_HORIZ);
+          grub_putchar(DISP_HORIZ);
+
+
+          /* print shortcut buffer */
+          gotoxy(5, 3);
+         if (search_mode)
+          {
+           grub_printf("%c%s%c%c%c%c",
+                       x, search_buf, x = search_direction ? '?' : '/',
+                       DISP_HORIZ,
+                       search_found >= 0 ? DISP_HORIZ : 'X', DISP_HORIZ);
+          }
+         else if (shortcut_buf[0])
+          {
+            grub_printf("<%s..>", shortcut_buf);
+          }
+         else
+          {
+            for (x = 0; x < 24; x++)
+             {
+              grub_putchar(DISP_HORIZ);
+             }
+          }
+         gotoxy(52, 16);
+         l = grub_strlen(search_buf);
+         for (i = SEARCH_BUF_SIZE + 2 -
+                 ((search_found >= 0 && (l || search_mode)) ? l + 2 : 0);
+              i; i--)
+          {
+           grub_putchar(DISP_HORIZ);
+          }
+         if (search_found >= 0 && (l || search_mode))
+           {
+             x = search_direction ? '?' : '/';
+             grub_putchar(x);
+             for (i = 0; i < l; i++)
+              {
+               grub_putchar(search_buf[i]);
+              }
+             grub_putchar(x);
+           }
+
+         if (current_term->setcolorstate)
+          {
+           current_term->setcolorstate (COLOR_STATE_STANDARD);
+          }
+
+          gotoxy(74, 4 + entryno);
+        }
 
       /* Check for a keypress, however if TIMEOUT has been expired
 	 (GRUB_TIMEOUT == -1) relax in GETKEY even if no key has been
@@ -395,9 +582,114 @@
 		gotoxy (74, 4 + entryno);
 	    }
 
+         if (search_mode)
+           {
+             int inplen = grub_strlen(search_buf);
+
+             if (c == '\r' || c == '\n' || c == 27)
+               {
+                 search_mode = 0;
+                 goto menu_restart;
+               }
+             else if (c != 8 && c < ' ') /* any other "move around" key */
+               {
+                 search_mode = 0;
+                 /* fall through to other keys */
+               }
+             else
+               {
+                 if (c == 8) /* Backspace */
+                   {
+                     if (!inplen)
+                       search_mode = 0;
+                     else
+                       search_buf[--inplen] = 0;
+                   }
+                 else if (inplen < sizeof(search_buf) - 1)
+                   {
+                     search_buf[inplen]   = grub_tolower(c);
+                     search_buf[++inplen] = 0;
+                   }
+
+                 if (search_mode)
+                   search_found = search_menu(search_buf,
+                                              first_entry + entryno,
+                                              search_direction, 0);
+
+                 goto menu_restart;
+               }
+           }
+         else if (c == '/' || c == '?')
+           {
+             search_mode = 1;
+             search_direction = (c == '?');
+             *search_buf = search_found = 0;
+           }
+
+         if (c == 'n') /* search again forwards */
+           if (search_found >= 0)
+             search_menu(search_buf, first_entry + entryno,
+                         search_direction, 1);
+
+         if (c == 'N') /* search again backwards */
+           if (search_found >= 0)
+             search_menu(search_buf, first_entry + entryno,
+                         !search_direction, 1);
+
+         if (c >= '0' && c <= '9')
+           {
+             int inplen = grub_strlen(shortcut_buf);
+             int i;
+
+             sc_matches = 0;
+
+             shortcut_buf[inplen]   = c;
+             shortcut_buf[++inplen] = 0;
+
+
+             for (i = 0; i < num_entries; i++)
+               {
+                 char buf[4];
+                 int a = 0;
+
+                 /* no strncmp in grub? do it ourselves */
+                 /* If shortcut_buf is entirely in the beginning
+                  * of buf, mark it as the first valid entry,
+                  * if the first entry is already set, we have at least
+                  * two entries matching, bail out then */
+                 grub_sprintf(buf, "%d", i);
+                 while (shortcut_buf[a] && buf[a] &&
+                     shortcut_buf[a] == buf[a])
+                   a++;
+
+                 if (a == inplen)
+                   {
+                     sc_matches++;
+
+                     if (sc_matches == 1)
+                       set_bar_to(i);
+                     else
+                       break;
+                   }
+               }
+             if (sc_matches <= 1)
+             {
+               shortcut_buf[0] = 0;
+             }
+             if (sc_matches == 1 && config_entries)
+             {
+               c = '\n'; /* Will hit the next check */
+             }
+           }
+         else
+         {
+           shortcut_buf[0] = sc_matches = 0;
+         }
+
+
 	  /* We told them above (at least in SUPPORT_SERIAL) to use
 	     '^' or 'v' so accept these keys.  */
-	  if (c == 16 || c == '^')
+	  if (c == 16 || c == '^' || c == 'k')
 	    {
 	      if (current_term->flags & TERM_DUMB)
 		{
@@ -455,6 +747,35 @@
 	  else if (c == 7)
 	    {
 	      /* Page Up */
+
+             if (first_entry > 11)
+               {
+                 first_entry -= 12;
+                 print_entries (3, 12, first_entry, entryno, menu_entries);
+               }
+             else if (first_entry)
+               {
+                 if (entryno + first_entry - 12 < 0)
+                   entryno = 0;
+                 else
+                   entryno = first_entry + entryno - 12;
+                 first_entry = 0;
+                 print_entries (3, 12, first_entry, entryno, menu_entries);
+               }
+             else if (entryno)
+               {
+                 print_entry (4 + entryno, 0,
+                              get_entry (menu_entries,
+                                         first_entry + entryno,
+                                         0));
+                 entryno = 0;
+                 print_entry (4, 1,
+                              get_entry (menu_entries,
+                                         first_entry,
+                                         0));
+               }
+
+#if 0
 	      first_entry -= 12;
 	      if (first_entry < 0)
 		{
@@ -464,10 +785,39 @@
 		    entryno = 0;
 		}
 	      print_entries (3, 12, first_entry, entryno, menu_entries);
+#endif
 	    }
 	  else if (c == 3)
 	    {
 	      /* Page Down */
+             if (first_entry + 12 < num_entries)
+               {
+                 if (first_entry + 23 < num_entries)
+                   first_entry += 12;
+                 else
+                   {
+                     if (entryno + first_entry + 12 >= num_entries)
+                       entryno = 11;
+                     else
+                       entryno += 24 + first_entry - num_entries;
+                     first_entry = num_entries - 12;
+                   }
+                 print_entries (3, 12, first_entry, entryno, menu_entries);
+               }
+             else if (first_entry + entryno + 1 != num_entries)
+               {
+                 print_entry (4 + entryno, 0,
+                              get_entry (menu_entries,
+                                         first_entry + entryno,
+                                         0));
+                 entryno = num_entries - first_entry - 1;
+                 print_entry (4 + entryno, 1,
+                              get_entry (menu_entries,
+                                         first_entry + entryno,
+                                         0));
+               }
+
+#if 0
 	      first_entry += 12;
 	      if (first_entry + entryno + 1 >= num_entries)
 		{
@@ -477,12 +827,53 @@
 		  entryno = num_entries - first_entry - 1;
 		}
 	      print_entries (3, 12, first_entry, entryno, menu_entries);
+#endif
 	    }
+           if (c == 'M')
+           {
+             grub_memmove(config_file, MASTER_CONFIG_FILE,
+                     grub_strlen(MASTER_CONFIG_FILE) + 1);
+             return;
+           }
+
 
 	  if (config_entries)
 	    {
+#if 0
 	      if ((c == '\n') || (c == '\r') || (c == 6))
 		break;
+#endif
+             if (c == 'r')
+               return;
+
+             if (c == '\n' || c == '\r' || c == 6 || c == 'l')
+               {
+                 config_file_history[config_file_history_prev_pos].entryno =
+                   entryno;
+                 config_file_history[config_file_history_prev_pos].first_entry
+=
+                   first_entry;
+
+                 break;
+                }
+
+             if (c == 2 || c == 'h') /* KEY_LEFT */
+               {
+                 /* go back in history if possible */
+                 int p = config_file_history_prev_pos;
+                 if (p != config_file_history_start)
+                   {
+                     p = (p == 0) ? CONFIG_FILE_HISTORY_ENTRIES - 1 : p - 1;
+                     memmove(config_file, config_file_history[p].filename,
+                         CONFIG_FILE_LEN);
+                     config_file_history_pos = p;
+                     config_file_history_menu_pos = p;
+
+                     return;
+                   }
+               }
+
+              
 	    }
 	  else
 	    {
@@ -663,6 +1054,12 @@
 		      saved_partition = install_partition;
 		      current_drive = GRUB_INVALID_DRIVE;
 
+                      if (is_var_expand())
+                      {
+                          int _s;
+                          new_heap = var_sprint_buf(new_heap, &_s);
+                      }
+
 		      if (! get_cmdline (PACKAGE " edit> ", new_heap,
 					 NEW_HEAPSIZE + 1, 0, 1))
 			{
@@ -704,6 +1101,13 @@
 		  stop ();
 		}
 #endif
+
+             /* Check toggles here so that we don't "overwrite" existing
+              * key binding... (user should choose another key then) */
+             if (toggle_do_key(c))
+             {
+               goto restart;
+             }
 	    }
 	}
     }
@@ -717,11 +1121,17 @@
   
   while (1)
     {
+      int len;
+
       if (config_entries)
+      {
 	printf ("  Booting \'%s\'\n\n",
-		get_entry (menu_entries, first_entry + entryno, 0));
+		var_sprint_buf(get_entry (menu_entries, first_entry + entryno, 0),&len));
+      }
       else
+      {
 	printf ("  Booting command-list\n\n");
+      }
 
       if (! cur_entry)
 	cur_entry = get_entry (config_entries, first_entry + entryno, 1);
@@ -848,6 +1258,9 @@
   /* Initialize the environment for restarting Stage 2.  */
   grub_setjmp (restart_env);
   
+  /* Init toggle triggers. */
+  toggle_trigger_init();
+
   /* Initialize the kill buffer.  */
   *kill_buf = 0;
 
@@ -982,10 +1395,26 @@
 		}
 	      
 	      if (is_preset)
+              {
 		close_preset_menu ();
+              }
 	      else
+              {
 		grub_close ();
 	    }
+
+             /* Save history for config_file */
+             memmove(config_file_history[config_file_history_pos].filename,
+                     config_file,
+                     CONFIG_FILE_LEN);
+             config_file_history_prev_pos = config_file_history_pos;
+             if (++config_file_history_pos == CONFIG_FILE_HISTORY_ENTRIES)
+               config_file_history_pos = 0;
+             if (config_file_history_start == config_file_history_pos &&
+                 ++config_file_history_start == CONFIG_FILE_HISTORY_ENTRIES)
+               config_file_history_start = 0;
+
+	    }
 	  while (is_preset);
 	}
 
--- ./netboot/config.c.voros	2003-07-09 13:45:37.000000000 +0200
+++ ./netboot/config.c	2004-09-10 23:47:17.000000000 +0200
@@ -122,6 +122,12 @@
     "Intel EtherExpressPro100 ID1029", 0, 0, 0, 0},
   { PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ID1030,
     "Intel Corporation 82559 InBusiness 10/100", 0, 0, 0, 0},
+  { PCI_VENDOR_ID_INTEL,       PCI_DEVICE_ID_INTEL_ID1031,
+    "Intel EtherExpressPro100 ID1031", 0, 0, 0, 0},
+  { PCI_VENDOR_ID_INTEL,       PCI_DEVICE_ID_INTEL_ID1039,
+    "Intel EtherExpressPro100 ID1039", 0, 0, 0, 0},
+  { PCI_VENDOR_ID_INTEL,       PCI_DEVICE_ID_INTEL_ID1050,
+    "Intel EtherExpressPro100 82555 10/100", 0, 0, 0, 0},
   { PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82562,
     "Intel EtherExpressPro100 82562EM", 0, 0, 0, 0},
 #endif
@@ -281,6 +287,9 @@
   { PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82559ER,   eepro100_probe },
   { PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ID1029,    eepro100_probe },
   { PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ID1030,    eepro100_probe },
+  { PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ID1031,    eepro100_probe },
+  { PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ID1039,    eepro100_probe },
+  { PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ID1050,    eepro100_probe },
   { PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82562,     eepro100_probe },
 # endif /* INCLUDE_EEPRO100 */
 # ifdef	INCLUDE_EPIC100
--- ./netboot/misc.c.voros	2003-07-09 13:45:37.000000000 +0200
+++ ./netboot/misc.c	2004-09-10 23:53:11.000000000 +0200
@@ -39,7 +39,7 @@
   static const char tiddles[]="-\\|/";
   unsigned long ticks;
 
-  if (debug)
+  /*if (debug) */
     {
       if ((ticks = currticks ()) == lastticks)
 	return;
--- ./netboot/pci.h.voros	2003-07-09 13:45:38.000000000 +0200
+++ ./netboot/pci.h	2004-09-10 23:56:09.000000000 +0200
@@ -129,6 +129,9 @@
 #define PCI_DEVICE_ID_INTEL_82559ER	0x1209
 #define PCI_DEVICE_ID_INTEL_ID1029	0x1029
 #define PCI_DEVICE_ID_INTEL_ID1030	0x1030
+#define PCI_DEVICE_ID_INTEL_ID1031     0x1031
+#define PCI_DEVICE_ID_INTEL_ID1039     0x1039
+#define PCI_DEVICE_ID_INTEL_ID1050     0x1050
 #define PCI_DEVICE_ID_INTEL_82562	0x2449
 #define PCI_VENDOR_ID_AMD		0x1022
 #define PCI_DEVICE_ID_AMD_LANCE		0x2000
--- ./configure.voros	2004-06-13 19:42:59.000000000 +0200
+++ ./configure	2004-09-10 23:16:20.000000000 +0200
@@ -269,8 +269,8 @@
 # Identity of this package.
 PACKAGE_NAME='GRUB'
 PACKAGE_TARNAME='grub'
-PACKAGE_VERSION='0.95'
-PACKAGE_STRING='GRUB 0.95'
+PACKAGE_VERSION='0.95-os'
+PACKAGE_STRING='GRUB 0.95-os'
 PACKAGE_BUGREPORT='bug-grub at gnu.org'
 
 ac_unique_file="stage2/stage2.c"
@@ -780,7 +780,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures GRUB 0.95 to adapt to many kinds of systems.
+\`configure' configures GRUB 0.95-os to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -846,7 +846,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of GRUB 0.95:";;
+     short | recursive ) echo "Configuration of GRUB 0.95-os:";;
    esac
   cat <<\_ACEOF
 
@@ -1039,7 +1039,7 @@
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-GRUB configure 0.95
+GRUB configure 0.95-os
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1053,7 +1053,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by GRUB $as_me 0.95, which was
+It was created by GRUB $as_me 0.95-os, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1691,7 +1691,7 @@
 
 # Define the identity of the package.
  PACKAGE='grub'
- VERSION='0.95'
+ VERSION='0.95-os'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -6543,7 +6543,7 @@
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by GRUB $as_me 0.95, which was
+This file was extended by GRUB $as_me 0.95-os, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -6606,7 +6606,7 @@
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-GRUB config.status 0.95
+GRUB config.status 0.95-os
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 


More information about the l4-hackers mailing list