File stage2-wildcard.diff of Package grub
Index: grub-0.95/stage2/shared.h
===================================================================
--- grub-0.95.orig/stage2/shared.h
+++ grub-0.95/stage2/shared.h
@@ -1008,9 +1008,11 @@ int grub_seek (int offset);
/* Close a file. */
void grub_close (void);
-/* List the contents of the directory that was opened with GRUB_OPEN,
- printing all completions. */
-int dir (char *dirname);
+/* List the contents of DIRECTORY. */
+int dir (char *dirname, void (*handle)(char *));
+
+/* Wildcard expand the last pathname component of GLOB. */
+char *wildcard (char *glob);
int set_bootdev (int hdbias);
Index: grub-0.95/stage2/stage2.c
===================================================================
--- grub-0.95.orig/stage2/stage2.c
+++ grub-0.95/stage2/stage2.c
@@ -1240,6 +1240,192 @@ get_line_from_config (char *cmdline, int
}
+char *wildcard_prefix, *wildcard_suffix;
+char wildcard_matches[1024], *end_wildcard_matches;
+
+static void wildcard_handler(char *name);
+
+/* Match one directory entry against the current wildcard. If the entry
+ matches, store it in WILDCARD_MATCHES. Silently ignore entries that
+ don't fit into WILDCARD_MATCHES anymore. */
+static void
+wildcard_handler(char *name)
+{
+ char *n = name, *p = wildcard_prefix;
+
+ while (*p && *p == *n)
+ {
+ p++;
+ n++;
+ }
+ if (*p)
+ return; /* prefix mismatch */
+
+ p = name + grub_strlen (name) - grub_strlen (wildcard_suffix);
+ /* [n .. p) is the part matching the asterisk */
+
+ if (p <= n || grub_strcmp (p, wildcard_suffix) != 0)
+ return; /* zero-length match or suffix mismatch */
+
+ /* store this match */
+ if (p - n + 2 > sizeof (wildcard_matches) -
+ (end_wildcard_matches - wildcard_matches))
+ return; /* out of space */
+ while (n < p)
+ *end_wildcard_matches++ = *n++;
+ *end_wildcard_matches++ = 0;
+}
+
+/* Wildcard expand the GLOB argument. Return NULL upon failure, or
+ a list of 0-terminated expansions, terminated by a zero-length string. */
+char *
+wildcard (char *glob)
+{
+ char path[128], *p;
+ int ret;
+
+ end_wildcard_matches = wildcard_matches;
+ if (grub_strlen (glob) + 1 > sizeof (path)) {
+ errnum = ERR_FILELENGTH;
+ return NULL; /* cannot handle pathnames this long */
+ }
+ grub_strcpy (path, glob);
+ p = path;
+ while (*p)
+ p++;
+ wildcard_suffix = p;
+ while (p > path && *p != '/')
+ p--;
+ if (*p != '/')
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return NULL; /* Cannot wildcard device names */
+ }
+ *(++p) = 0;
+ wildcard_prefix = glob + (p - path);
+ for (p = wildcard_prefix;; p++)
+ {
+ if (*p == 0)
+ {
+ /* We cannot do exact matches: this cannot be represented in the
+ result list. */
+ return NULL;
+ }
+ else if (*p == '*')
+ {
+ *p++ = 0;
+ wildcard_suffix = p;
+ break;
+ }
+ }
+
+ ret = dir (path, wildcard_handler);
+ /* restore original argument */
+ wildcard_prefix[grub_strlen (wildcard_prefix)] = '*';
+ if (!ret)
+ return NULL;
+ *end_wildcard_matches++ = 0;
+ return wildcard_matches;
+}
+
+#define skip(str) ((str) + grub_strlen (str) + 1)
+
+static void inplace_sort (char *str);
+
+static void
+inplace_sort (char *str)
+{
+ int m, n = 0;
+ char *s, *t, *x;
+
+ for (s = str; *s; s = skip (s))
+ n++;
+
+ /* we use x as temporary storage */
+ x = s + 1;
+
+ for (; n >= 2; n--)
+ {
+ s = str;
+ t = skip (s);
+
+ for (m = n; m >= 2; m--)
+ {
+ if (grub_strcmp (s, t) > 0)
+ {
+ int ls = skip (s) - s;
+ int lt = skip (t) - t;
+
+ memcpy (x, s, ls);
+ grub_memmove (s + ls, s + lt, t - (s + ls));
+ memcpy (s, t, lt);
+ t = t + lt - ls;
+ memcpy (t, x, ls);
+ }
+ s = t;
+ t = skip (t);
+ }
+ }
+}
+
+static int this_config_len (const char *config);
+static int
+this_config_len (const char *config)
+{
+ const char *c = config;
+ while (*c)
+ {
+ while (*c)
+ c++;
+ c++;
+ }
+ c++;
+ return c - config;
+}
+
+static const char * expand_asterisks (const char *str, int *len,
+ const char *subst);
+
+/* Expand all asterisks (*) in a menu entry or commands section with its
+ substitution. Use a backslash as escape character. */
+static const char *
+expand_asterisks (const char *str, int *len, const char *subst)
+{
+ static char buffer[1024];
+ char *b = buffer, escaped = 0;
+ const char *end = str + *len;
+
+ while (str < end)
+ {
+ if (*str == '*' && !escaped)
+ {
+ if (b - buffer + grub_strlen (subst) > sizeof (buffer))
+ {
+ errnum = ERR_FILELENGTH;
+ return NULL;
+ }
+ grub_strcpy (b, subst);
+ b += grub_strlen (subst);
+ }
+ else if (*str == '\\' && !escaped)
+ escaped = 1;
+ else
+ {
+ escaped = 0;
+ if (b - buffer + 1 > sizeof (buffer))
+ {
+ errnum = ERR_FILELENGTH;
+ return NULL;
+ }
+ *b++ = *str;
+ }
+ str++;
+ }
+ *len = b - buffer;
+
+ return buffer;
+}
+
/* This is the starting function in C. */
void
cmain (void)
@@ -1260,6 +1446,96 @@ cmain (void)
init_config ();
}
+ auto void expand_wildcard_entries (void);
+ void expand_wildcard_entries (void)
+ {
+ char *config_entry = config_entries;
+ char *menu_entry = menu_entries;
+
+ while (*menu_entry)
+ {
+ char *command = config_entry;
+
+ do
+ {
+ char *c = command;
+ const char *w = "wildcard";
+
+ while (*w && *c == *w)
+ {
+ c++;
+ w++;
+ }
+ if (*w == 0 && (*c == ' ' || *c == '\t' || *c == '='))
+ {
+ int len;
+
+ /* This is a wildcard command. Advance to the argument. */
+ while (*c == ' ' || *c == '\t' || *c == '=')
+ c++;
+
+ /* Expand wildcard entry. */
+ w = wildcard (c);
+ if (w)
+ inplace_sort (w);
+
+ /* Remove the wildcard command from the command section;
+ it has no meaning beyond the wildcard expansion just
+ performed. */
+ len = grub_strlen (command) + 1;
+ grub_memmove (command, command + len,
+ config_len - (command - config_entries));
+ config_len -= len;
+
+ while (w && *w)
+ {
+ /* Insert expansion before the wildcard entry in the
+ list of entry names. */
+ len = grub_strlen (menu_entry) + 1;
+ const char *x = expand_asterisks (menu_entry, &len, w);
+ grub_memmove (menu_entry + len, menu_entry,
+ menu_len - (menu_entry - menu_entries));
+ memcpy (menu_entry, x, len);
+ menu_entry += len;
+ menu_len += len;
+
+ /* Insert expansion before the wildcard command section
+ in the list of command sections. */
+ len = this_config_len (config_entry);
+ x = expand_asterisks (config_entry, &len, w);
+ grub_memmove (config_entry + len, config_entry,
+ config_len - (config_entry -
+ config_entries));
+ memcpy (config_entry, x, len);
+ config_entry += len;
+ config_len += len;
+
+ num_entries++;
+ w += grub_strlen (w) + 1;
+ }
+
+ /* Remove the wildcard command section; it has just
+ been expanded. */
+ len = grub_strlen (menu_entry) + 1;
+ grub_memmove (menu_entry, menu_entry + len,
+ menu_len - (menu_entry - menu_entries));
+ menu_len -= len;
+
+ len = this_config_len(config_entry);
+ grub_memmove (config_entry, config_entry + len,
+ config_len - (config_entry - config_entries));
+ config_len -= len;
+
+ num_entries--;
+ }
+ command += grub_strlen (command) + 1;
+ }
+ while (*command);
+ menu_entry += grub_strlen (menu_entry) + 1;
+ config_entry += this_config_len(config_entry);
+ }
+ }
+
/* Initialize the environment for restarting Stage 2. */
grub_setjmp (restart_env);
@@ -1379,8 +1655,16 @@ cmain (void)
config_len = prev_config_len;
}
+ if (is_preset)
+ close_preset_menu ();
+ else
+ grub_close ();
+
menu_entries[menu_len++] = 0;
config_entries[config_len++] = 0;
+
+ expand_wildcard_entries();
+
grub_memmove (config_entries + config_len, menu_entries,
menu_len);
menu_entries = config_entries + config_len;
@@ -1395,11 +1679,6 @@ cmain (void)
else
default_entry = fallback_entry;
}
-
- if (is_preset)
- close_preset_menu ();
- else
- grub_close ();
}
while (is_preset);
}
Index: grub-0.95/stage2/builtins.c
===================================================================
--- grub-0.95.orig/stage2/builtins.c
+++ grub-0.95/stage2/builtins.c
@@ -4831,6 +4831,49 @@ static struct builtin builtin_vbeprobe =
};
+/* wildcard */
+ static int
+wildcard_func (char *arg, int flags)
+{
+#ifdef DEBUG_WILDCARD
+ char *w = wildcard (arg);
+
+ if (w)
+ {
+ while (*w)
+ {
+ grub_printf("%s ", w);
+ w += strlen (w) + 1;
+ }
+ grub_printf("\n");
+ return 1;
+ }
+ else
+ print_error();
+#endif
+
+ /* This special command is interpreted in the config file parser. */
+ return 0;
+}
+
+static struct builtin builtin_wildcard =
+ {
+ "wildcard",
+ wildcard_func,
+#ifndef DEBUG_WILDCARD
+ BUILTIN_MENU,
+#else
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "wildcard GLOB",
+ "Declare this menu entry as a wildcard entry. GLOB is a path containing"
+ " one asterisk. All files matching this expression are looked up; the"
+ " menu entry is duplicated for each match with asterisks in other"
+ " commands replaced by the string matching the asterisk in the wildcard"
+ " command."
+#endif
+};
+
+
/* The table of builtin commands. Sorted in dictionary order. */
struct builtin *builtin_table[] =
{
@@ -4920,5 +4963,6 @@ struct builtin *builtin_table[] =
&builtin_unhide,
&builtin_uppermem,
&builtin_vbeprobe,
+ &builtin_wildcard,
0
};