1 diff -Nur grub-0.97-dirs/docs/grub.texi grub-0.97-wildcards/docs/grub.texi
2 --- grub-0.97-dirs/docs/grub.texi 2005-08-21 20:31:12.000000000 +0300
3 +++ grub-0.97-wildcards/docs/grub.texi 2005-08-21 20:32:45.000000000 +0300
5 * gfxmenu:: Use graphical menu interface
6 * timeout:: Set the timeout
7 * title:: Start a menu entry
8 +* wildcard:: Define a wildcard boot entry
12 @@ -2190,6 +2191,42 @@
19 +@deffn Command wildcard pathname
20 +Treat this boot entry as a wildcard entry: The
21 +wildcard, title, kernel, and initrd commands (see @ref{Menu-specific
22 +commands} and @ref{Command-line and menu entry commands}) each have an
23 +asterisk (*) in their value. A filename match is performed on the
24 +@var{pathname} of the wildcard command. For each match, the entire boot
25 +entry is duplicated. The part of the filename whcih matches the asterisk
26 +in the wildcard command replaces the asterisks in the title, kernel, and
27 +initrd commands. For example, with the files vmlinuz-2.6.5-1 and
28 +vmlinuz-2.6.8-8 below (hd0,7)/boot, the following entry in the stage 2
33 + wildcard (hd0,7)/boot/vmlinuz-*
34 + kernel (hd0,7)/boot/vmlinuz-* root=/dev/hda8
35 + initrd (hd0,7)/boot/initrd-*
38 +would expand as follows:
42 + wildcard (hd0,7)/boot/vmlinuz-2.6.5-1
43 + kernel (hd0,7)/boot/vmlinuz-2.6.5-1 root=/dev/hda8
44 + initrd (hd0,7)/boot/initrd-2.6.5-1
46 + wildcard (hd0,7)/boot/vmlinuz-2.6.8-8
47 + kernel (hd0,7)/boot/vmlinuz-2.6.8-8 root=/dev/hda8
48 + initrd (hd0,7)/boot/initrd-2.6.8-8
52 @node General commands
53 @section The list of general commands
55 diff -Nur grub-0.97-dirs/netboot/fsys_tftp.c grub-0.97-wildcards/netboot/fsys_tftp.c
56 --- grub-0.97-dirs/netboot/fsys_tftp.c 2005-08-21 20:31:02.000000000 +0300
57 +++ grub-0.97-wildcards/netboot/fsys_tftp.c 2005-08-21 20:32:45.000000000 +0300
59 /* Check if the file DIRNAME really exists. Get the size and save it in
62 -tftp_dir (char *dirname)
63 +tftp_dir (char *dirname, void (*handle)(char *))
70 /* In TFTP, there is no way to know what files exist. */
71 - if (print_possibilities)
75 /* Don't know the size yet. */
76 diff -Nur grub-0.97-dirs/stage2/builtins.c grub-0.97-wildcards/stage2/builtins.c
77 --- grub-0.97-dirs/stage2/builtins.c 2005-08-21 20:31:02.000000000 +0300
78 +++ grub-0.97-wildcards/stage2/builtins.c 2005-08-21 20:32:45.000000000 +0300
79 @@ -4828,6 +4828,49 @@
85 +wildcard_func (char *arg, int flags)
87 +#ifdef DEBUG_WILDCARD
88 + char *w = wildcard (arg);
94 + grub_printf("%s ", w);
95 + w += strlen (w) + 1;
104 + /* This special command is interpreted in the config file parser. */
108 +static struct builtin builtin_wildcard =
112 +#ifndef DEBUG_WILDCARD
115 + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
117 + "Declare this menu entry as a wildcard entry. GLOB is a path containing"
118 + " one asterisk. All files matching this expression are looked up; the"
119 + " menu entry is duplicated for each match with asterisks in other"
120 + " commands replaced by the string matching the asterisk in the wildcard"
126 /* The table of builtin commands. Sorted in dictionary order. */
127 struct builtin *builtin_table[] =
129 @@ -4917,5 +4960,6 @@
136 diff -Nur grub-0.97-dirs/stage2/disk_io.c grub-0.97-wildcards/stage2/disk_io.c
137 --- grub-0.97-dirs/stage2/disk_io.c 2005-08-21 20:31:02.000000000 +0300
138 +++ grub-0.97-wildcards/stage2/disk_io.c 2005-08-21 20:32:45.000000000 +0300
140 void (*disk_read_func) (int, int, int) = NULL;
143 -int print_possibilities;
145 static int do_completion;
147 @@ -1479,7 +1478,7 @@
149 grub_printf (" Possible files are:");
152 + dir (buf, print_a_completion);
154 if (is_completion && *unique_string)
156 @@ -1498,7 +1497,7 @@
161 + dir (buf, print_a_completion);
163 /* Restore the original unique value. */
165 @@ -1626,12 +1625,7 @@
166 if (!errnum && fsys_type == NUM_FSYS)
167 errnum = ERR_FSYS_MOUNT;
170 - /* set "dir" function to open a file */
171 - print_possibilities = 0;
174 - if (!errnum && (*(fsys_table[fsys_type].dir_func)) (filename))
175 + if (!errnum && (*(fsys_table[fsys_type].dir_func)) (filename, NULL))
177 #ifndef NO_DECOMPRESSION
178 return gunzip_test_header ();
179 @@ -1752,7 +1746,7 @@
184 +dir (char *dirname, void (*handle)(char *))
186 #ifndef NO_DECOMPRESSION
188 @@ -1761,19 +1755,18 @@
189 if (!(dirname = setup_part (dirname)))
194 errnum = ERR_BAD_FILENAME;
196 - if (fsys_type == NUM_FSYS)
197 + else if (fsys_type == NUM_FSYS)
198 errnum = ERR_FSYS_MOUNT;
203 - /* set "dir" function to list completions */
204 - print_possibilities = 1;
206 - return (*(fsys_table[fsys_type].dir_func)) (dirname);
209 + fsys_table[fsys_type].dir_func (dirname, handle);
210 + if (errnum == ERR_FILE_NOT_FOUND)
213 + return errnum == 0;
215 #endif /* STAGE1_5 */
217 diff -Nur grub-0.97-dirs/stage2/filesys.h grub-0.97-wildcards/stage2/filesys.h
218 --- grub-0.97-dirs/stage2/filesys.h 2005-08-21 20:31:02.000000000 +0300
219 +++ grub-0.97-wildcards/stage2/filesys.h 2005-08-21 20:32:45.000000000 +0300
221 #define FSYS_FFS_NUM 1
222 int ffs_mount (void);
223 int ffs_read (char *buf, int len);
224 -int ffs_dir (char *dirname);
225 +int ffs_dir (char *dirname, void (*handle)(char *));
226 int ffs_embed (int *start_sector, int needed_sectors);
228 #define FSYS_FFS_NUM 0
230 #define FSYS_UFS2_NUM 1
231 int ufs2_mount (void);
232 int ufs2_read (char *buf, int len);
233 -int ufs2_dir (char *dirname);
234 +int ufs2_dir (char *dirname, void (*handle)(char *));
235 int ufs2_embed (int *start_sector, int needed_sectors);
237 #define FSYS_UFS2_NUM 0
239 #define FSYS_FAT_NUM 1
240 int fat_mount (void);
241 int fat_read (char *buf, int len);
242 -int fat_dir (char *dirname);
243 +int fat_dir (char *dirname, void (*handle)(char *));
245 #define FSYS_FAT_NUM 0
248 #define FSYS_EXT2FS_NUM 1
249 int ext2fs_mount (void);
250 int ext2fs_read (char *buf, int len);
251 -int ext2fs_dir (char *dirname);
252 +int ext2fs_dir (char *dirname, void (*handle)(char *));
254 #define FSYS_EXT2FS_NUM 0
257 #define FSYS_MINIX_NUM 1
258 int minix_mount (void);
259 int minix_read (char *buf, int len);
260 -int minix_dir (char *dirname);
261 +int minix_dir (char *dirname, void (*handle)(char *));
263 #define FSYS_MINIX_NUM 0
266 #define FSYS_REISERFS_NUM 1
267 int reiserfs_mount (void);
268 int reiserfs_read (char *buf, int len);
269 -int reiserfs_dir (char *dirname);
270 +int reiserfs_dir (char *dirname, void (*handle)(char *));
271 int reiserfs_embed (int *start_sector, int needed_sectors);
272 #if defined(__linux__) && defined (GRUB_UTIL)
273 #include <sys/types.h>
275 #define FSYS_VSTAFS_NUM 1
276 int vstafs_mount (void);
277 int vstafs_read (char *buf, int len);
278 -int vstafs_dir (char *dirname);
279 +int vstafs_dir (char *dirname, void (*handle)(char *));
281 #define FSYS_VSTAFS_NUM 0
284 #define FSYS_JFS_NUM 1
285 int jfs_mount (void);
286 int jfs_read (char *buf, int len);
287 -int jfs_dir (char *dirname);
288 +int jfs_dir (char *dirname, void (*handle)(char *));
289 int jfs_embed (int *start_sector, int needed_sectors);
291 #define FSYS_JFS_NUM 0
293 #define FSYS_XFS_NUM 1
294 int xfs_mount (void);
295 int xfs_read (char *buf, int len);
296 -int xfs_dir (char *dirname);
297 +int xfs_dir (char *dirname, void (*handle)(char *));
299 #define FSYS_XFS_NUM 0
302 #define FSYS_TFTP_NUM 1
303 int tftp_mount (void);
304 int tftp_read (char *buf, int len);
305 -int tftp_dir (char *dirname);
306 +int tftp_dir (char *dirname, void (*handle)(char *));
307 void tftp_close (void);
309 #define FSYS_TFTP_NUM 0
311 #define FSYS_ISO9660_NUM 1
312 int iso9660_mount (void);
313 int iso9660_read (char *buf, int len);
314 -int iso9660_dir (char *dirname);
315 +int iso9660_dir (char *dirname, void (*handle)(char *));
317 #define FSYS_ISO9660_NUM 0
319 @@ -160,16 +160,10 @@
321 int (*mount_func) (void);
322 int (*read_func) (char *buf, int len);
323 - int (*dir_func) (char *dirname);
324 + int (*dir_func) (char *dirname, void (*print_one)(char *));
325 void (*close_func) (void);
326 int (*embed_func) (int *start_sector, int needed_sectors);
330 -# define print_possibilities 0
332 -extern int print_possibilities;
336 extern struct fsys_entry fsys_table[NUM_FSYS + 1];
337 diff -Nur grub-0.97-dirs/stage2/fsys_ext2fs.c grub-0.97-wildcards/stage2/fsys_ext2fs.c
338 --- grub-0.97-dirs/stage2/fsys_ext2fs.c 2005-08-21 20:31:02.000000000 +0300
339 +++ grub-0.97-wildcards/stage2/fsys_ext2fs.c 2005-08-21 20:32:45.000000000 +0300
341 * side effects: messes up GROUP_DESC buffer area
344 -ext2fs_dir (char *dirname)
345 +ext2fs_dir (char *dirname, void (*handle)(char *))
347 int current_ino = EXT2_ROOT_INO; /* start at the root */
348 int updir_ino = current_ino; /* the parent of the current directory */
355 current_ino = inode to lookup
356 dirname = pointer to filename component we are cur looking up within
359 if (loc >= INODE->i_size)
361 - if (print_possibilities < 0)
369 - errnum = ERR_FILE_NOT_FOUND;
372 - return (print_possibilities < 0);
373 + errnum = ERR_FILE_NOT_FOUND;
378 /* else, find the (logical) block component of our location */
379 @@ -765,20 +755,15 @@
380 str_chk = substring (dirname, dp->name);
383 - if (print_possibilities && ch != '/'
384 - && (!*dirname || str_chk <= 0))
386 - if (print_possibilities > 0)
387 - print_possibilities = -print_possibilities;
388 - print_a_completion (dp->name);
390 + if (handle && ch != '/' && (!*dirname || str_chk <= 0))
394 dp->name[dp->name_len] = saved_c;
398 - while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
399 + while (!dp->inode || (str_chk || (handle && ch != '/')));
401 current_ino = dp->inode;
402 *(dirname = rest) = ch;
403 diff -Nur grub-0.97-dirs/stage2/fsys_fat.c grub-0.97-wildcards/stage2/fsys_fat.c
404 --- grub-0.97-dirs/stage2/fsys_fat.c 2005-08-21 20:31:02.000000000 +0300
405 +++ grub-0.97-wildcards/stage2/fsys_fat.c 2005-08-21 20:32:45.000000000 +0300
410 -fat_dir (char *dirname)
411 +fat_dir (char *dirname, void (*handle)(char *))
413 char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH];
414 char *filename = (char *) NAME_BUF;
419 - if (print_possibilities && ch != '/')
420 + if (handle && ch != '/')
421 do_possibilities = 1;
429 - if (print_possibilities < 0)
436 -# endif /* STAGE1_5 */
438 errnum = ERR_FILE_NOT_FOUND;
444 if (substring (dirname, filename) <= 0)
446 - if (print_possibilities > 0)
447 - print_possibilities = -print_possibilities;
448 - print_a_completion (filename);
453 # endif /* STAGE1_5 */
454 diff -Nur grub-0.97-dirs/stage2/fsys_ffs.c grub-0.97-wildcards/stage2/fsys_ffs.c
455 --- grub-0.97-dirs/stage2/fsys_ffs.c 2005-08-21 20:31:02.000000000 +0300
456 +++ grub-0.97-wildcards/stage2/fsys_ffs.c 2005-08-21 20:32:45.000000000 +0300
461 -ffs_dir (char *dirname)
462 +ffs_dir (char *dirname, void (*handle)(char *))
465 int block, off, loc, map, ino = ROOTINO;
468 if (loc >= INODE->i_size)
474 - if (print_possibilities < 0)
477 errnum = ERR_FILE_NOT_FOUND;
480 @@ -267,18 +260,13 @@
484 - if (dp->d_ino && print_possibilities && ch != '/'
485 + if (dp->d_ino && handle && ch != '/'
486 && (!*dirname || substring (dirname, dp->d_name) <= 0))
488 - if (print_possibilities > 0)
489 - print_possibilities = -print_possibilities;
491 - print_a_completion (dp->d_name);
493 + handle (dp->d_name);
494 #endif /* STAGE1_5 */
496 while (!dp->d_ino || (substring (dirname, dp->d_name) != 0
497 - || (print_possibilities && ch != '/')));
498 + || (handle && ch != '/')));
500 /* only get here if we have a matching directory entry */
502 diff -Nur grub-0.97-dirs/stage2/fsys_iso9660.c grub-0.97-wildcards/stage2/fsys_iso9660.c
503 --- grub-0.97-dirs/stage2/fsys_iso9660.c 2005-08-21 20:31:02.000000000 +0300
504 +++ grub-0.97-wildcards/stage2/fsys_iso9660.c 2005-08-21 20:32:45.000000000 +0300
509 -iso9660_dir (char *dirname)
510 +iso9660_dir (char *dirname, void (*handle)(char *))
512 struct iso_directory_record *idr;
515 if (name_len >= pathlen
516 && !memcmp(name, dirname, pathlen))
518 - if (dirname[pathlen] == '/' || !print_possibilities)
519 + if (dirname[pathlen] == '/' || !handle)
522 * DIRNAME is directory component of pathname,
524 else /* Completion */
527 - if (print_possibilities > 0)
528 - print_possibilities = -print_possibilities;
529 memcpy(NAME_BUF, name, name_len);
530 NAME_BUF[name_len] = '\0';
531 - print_a_completion (NAME_BUF);
537 size -= ISO_SECTOR_SIZE;
540 - if (dirname[pathlen] == '/' || print_possibilities >= 0)
541 + if (dirname[pathlen] == '/' || handle)
543 errnum = ERR_FILE_NOT_FOUND;
545 diff -Nur grub-0.97-dirs/stage2/fsys_jfs.c grub-0.97-wildcards/stage2/fsys_jfs.c
546 --- grub-0.97-dirs/stage2/fsys_jfs.c 2005-08-21 20:31:02.000000000 +0300
547 +++ grub-0.97-wildcards/stage2/fsys_jfs.c 2005-08-21 20:32:45.000000000 +0300
552 -jfs_dir (char *dirname)
553 +jfs_dir (char *dirname, void (*handle)(char *))
555 char *ptr, *rest, ch;
559 cmp = (!*dirname) ? -1 : substring (dirname, namebuf);
561 - if (print_possibilities && ch != '/'
563 - if (print_possibilities > 0)
564 - print_possibilities = -print_possibilities;
565 - print_a_completion (namebuf);
567 + if (handle && ch != '/' && cmp <= 0)
577 - if (print_possibilities < 0)
580 errnum = ERR_FILE_NOT_FOUND;
583 diff -Nur grub-0.97-dirs/stage2/fsys_minix.c grub-0.97-wildcards/stage2/fsys_minix.c
584 --- grub-0.97-dirs/stage2/fsys_minix.c 2005-08-21 20:31:02.000000000 +0300
585 +++ grub-0.97-wildcards/stage2/fsys_minix.c 2005-08-21 20:32:45.000000000 +0300
587 inode of the file we were trying to look up
588 side effects: none yet */
590 -minix_dir (char *dirname)
591 +minix_dir (char *dirname, void (*handle)(char *))
593 int current_ino = MINIX_ROOT_INO; /* start at the root */
594 int updir_ino = current_ino; /* the parent of the current directory */
597 if (loc >= INODE->i_size)
599 - if (print_possibilities < 0)
607 - errnum = ERR_FILE_NOT_FOUND;
610 - return (print_possibilities < 0);
611 + errnum = ERR_FILE_NOT_FOUND;
616 /* else, find the (logical) block component of our location */
617 @@ -510,20 +501,15 @@
618 str_chk = substring (dirname, dp->name);
621 - if (print_possibilities && ch != '/'
622 - && (!*dirname || str_chk <= 0))
624 - if (print_possibilities > 0)
625 - print_possibilities = -print_possibilities;
626 - print_a_completion (dp->name);
628 + if (handle && ch != '/' && (!*dirname || str_chk <= 0))
632 dp->name[namelen] = saved_c;
636 - while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
637 + while (!dp->inode || (str_chk || (handle && ch != '/')));
639 current_ino = dp->inode;
640 *(dirname = rest) = ch;
641 diff -Nur grub-0.97-dirs/stage2/fsys_reiserfs.c grub-0.97-wildcards/stage2/fsys_reiserfs.c
642 --- grub-0.97-dirs/stage2/fsys_reiserfs.c 2005-08-21 20:31:02.000000000 +0300
643 +++ grub-0.97-wildcards/stage2/fsys_reiserfs.c 2005-08-21 20:32:45.000000000 +0300
645 * the size of the file.
648 -reiserfs_dir (char *dirname)
649 +reiserfs_dir (char *dirname, void (*handle)(char *))
651 struct reiserfs_de_head *de_head;
653 @@ -1123,7 +1123,7 @@
657 - if (print_possibilities && ch != '/')
658 + if (handle && ch != '/')
659 do_possibilities = 1;
660 # endif /* ! STAGE1_5 */
662 @@ -1170,10 +1170,8 @@
666 - if (print_possibilities > 0)
667 - print_possibilities = -print_possibilities;
669 - print_a_completion (filename);
674 @@ -1189,12 +1187,6 @@
680 - if (print_possibilities < 0)
682 -# endif /* ! STAGE1_5 */
684 errnum = ERR_FILE_NOT_FOUND;
687 diff -Nur grub-0.97-dirs/stage2/fsys_ufs2.c grub-0.97-wildcards/stage2/fsys_ufs2.c
688 --- grub-0.97-dirs/stage2/fsys_ufs2.c 2005-08-21 20:31:02.000000000 +0300
689 +++ grub-0.97-wildcards/stage2/fsys_ufs2.c 2005-08-21 20:32:45.000000000 +0300
694 -ufs2_dir (char *dirname)
695 +ufs2_dir (char *dirname, void (*handle)(char *))
698 int block, off, loc, ino = ROOTINO;
701 if (loc >= INODE_UFS2->di_size)
703 - if (print_possibilities < 0)
706 errnum = ERR_FILE_NOT_FOUND;
709 @@ -288,18 +285,13 @@
713 - if (dp->d_ino && print_possibilities && ch != '/'
714 + if (dp->d_ino && handle && ch != '/'
715 && (!*dirname || substring (dirname, dp->d_name) <= 0))
717 - if (print_possibilities > 0)
718 - print_possibilities = -print_possibilities;
720 - print_a_completion (dp->d_name);
722 + handle (dp->d_name);
723 #endif /* STAGE1_5 */
725 while (!dp->d_ino || (substring (dirname, dp->d_name) != 0
726 - || (print_possibilities && ch != '/')));
727 + || (handle && ch != '/')));
729 /* only get here if we have a matching directory entry */
731 diff -Nur grub-0.97-dirs/stage2/fsys_vstafs.c grub-0.97-wildcards/stage2/fsys_vstafs.c
732 --- grub-0.97-dirs/stage2/fsys_vstafs.c 2005-08-21 20:31:02.000000000 +0300
733 +++ grub-0.97-wildcards/stage2/fsys_vstafs.c 2005-08-21 20:32:45.000000000 +0300
738 -vstafs_dir (char *dirname)
739 +vstafs_dir (char *dirname, void (*handle)(char *))
747 - if (print_possibilities && ch != '/'
748 + if (handle && ch != '/'
749 && (! *dirname || strcmp (dirname, d->name) <= 0))
751 - if (print_possibilities > 0)
752 - print_possibilities = -print_possibilities;
754 - printf (" %s", d->name);
758 if (! grub_strcmp (dirname, d->name))
761 *(dirname = fn) = ch;
764 - if (print_possibilities < 0)
770 errnum = ERR_FILE_NOT_FOUND;
773 diff -Nur grub-0.97-dirs/stage2/fsys_xfs.c grub-0.97-wildcards/stage2/fsys_xfs.c
774 --- grub-0.97-dirs/stage2/fsys_xfs.c 2005-08-21 20:31:02.000000000 +0300
775 +++ grub-0.97-wildcards/stage2/fsys_xfs.c 2005-08-21 20:32:45.000000000 +0300
780 -xfs_dir (char *dirname)
781 +xfs_dir (char *dirname, void (*handle)(char *))
783 xfs_ino_t ino, parent_ino, new_ino;
787 cmp = (!*dirname) ? -1 : substring (dirname, name);
789 - if (print_possibilities && ch != '/' && cmp <= 0) {
790 - if (print_possibilities > 0)
791 - print_possibilities = -print_possibilities;
792 - print_a_completion (name);
794 + if (handle && ch != '/' && cmp <= 0)
802 name = next_dentry (&new_ino);
804 - if (print_possibilities < 0)
807 errnum = ERR_FILE_NOT_FOUND;
810 diff -Nur grub-0.97-dirs/stage2/shared.h grub-0.97-wildcards/stage2/shared.h
811 --- grub-0.97-dirs/stage2/shared.h 2005-08-21 20:31:02.000000000 +0300
812 +++ grub-0.97-wildcards/stage2/shared.h 2005-08-21 20:32:45.000000000 +0300
813 @@ -1012,9 +1012,11 @@
815 void grub_close (void);
817 -/* List the contents of the directory that was opened with GRUB_OPEN,
818 - printing all completions. */
819 -int dir (char *dirname);
820 +/* List the contents of DIRECTORY. */
821 +int dir (char *dirname, void (*handle)(char *));
823 +/* Wildcard expand the last pathname component of GLOB. */
824 +char *wildcard (char *glob, int *len);
826 int set_bootdev (int hdbias);
828 diff -Nur grub-0.97-dirs/stage2/stage2.c grub-0.97-wildcards/stage2/stage2.c
829 --- grub-0.97-dirs/stage2/stage2.c 2005-08-21 20:31:02.000000000 +0300
830 +++ grub-0.97-wildcards/stage2/stage2.c 2005-08-21 20:33:24.000000000 +0300
831 @@ -1243,6 +1243,230 @@
835 +char *wildcard_prefix, *wildcard_suffix;
836 +char wildcard_matches[1024], *end_wildcard_matches;
838 +static void wildcard_handler(char *name);
840 +/* Match one directory entry against the current wildcard. If the entry
841 + matches, store it in WILDCARD_MATCHES. Silently ignore entries that
842 + don't fit into WILDCARD_MATCHES anymore. */
844 +wildcard_handler(char *name)
846 + char *n = name, *p = wildcard_prefix;
848 + while (*p && *p == *n)
854 + return; /* prefix mismatch */
856 + p = name + grub_strlen (name) - grub_strlen (wildcard_suffix);
857 + /* [n .. p) is the part matching the asterisk */
859 + if (p < n || grub_strcmp (p, wildcard_suffix) != 0)
860 + return; /* suffix mismatch */
862 + /* store this match */
863 + if (p - n + 1 > sizeof (wildcard_matches) -
864 + (end_wildcard_matches - wildcard_matches))
865 + return; /* out of space */
867 + *end_wildcard_matches++ = *n++;
868 + *end_wildcard_matches++ = 0;
871 +/* Wildcard expand the GLOB argument. Return NULL upon failure, or
872 + a list of 0-terminated expansions, terminated by a zero-length string. */
874 +wildcard (char *glob, int *len)
876 + char path[128], *p;
879 + end_wildcard_matches = wildcard_matches;
880 + if (grub_strlen (glob) + 1 > sizeof (path)) {
881 + errnum = ERR_FILELENGTH;
882 + return NULL; /* cannot handle pathnames this long */
884 + grub_strcpy (path, glob);
888 + wildcard_suffix = p;
889 + while (p > path && *p != '/')
893 + errnum = ERR_BAD_FILETYPE;
894 + return NULL; /* Cannot wildcard device names */
897 + wildcard_prefix = glob + (p - path);
898 + for (p = wildcard_prefix;; p++)
902 + /* We cannot do exact matches: this cannot be represented in the
906 + else if (*p == '*')
909 + wildcard_suffix = p;
914 + ret = dir (path, wildcard_handler);
915 + /* restore original argument */
916 + wildcard_prefix[grub_strlen (wildcard_prefix)] = '*';
919 + *len = end_wildcard_matches - wildcard_matches;
920 + return wildcard_matches;
923 +static int inplace_sort_nextint(char **p);
925 +static int inplace_sort_nextint(char **p)
929 + while (**p && **p < '0' && **p > '9') *p++;
930 + if (!**p) return -1;
931 + while (**p && **p >= '0' && **p <= '9')
933 + i = i * 10 + **p - '0';
939 +static int inplace_sort_strcmp(char *l, char *r);
942 +inplace_sort_strcmp(char *l, char *r)
950 + li = inplace_sort_nextint(&lp);
951 + ri = inplace_sort_nextint(&rp);
952 + if (li > ri) return 1;
953 + if (ri > li) return -1;
955 + while (li != -1 || ri != -1);
959 +#define skip(str) ((str) + grub_strlen (str) + 1)
961 +static void inplace_sort (char *str, int len);
964 +inplace_sort (char *str, int len)
969 + /* we use x as temporary storage */
970 + char *x = str + len;
972 + for (s = str; s < x; s = skip (s))
975 + for (; n >= 2; n--)
980 + for (m = n; m >= 2; m--)
982 + if (inplace_sort_strcmp (s, t) < 0)
984 + int ls = skip (s) - s;
985 + int lt = skip (t) - t;
988 + grub_memmove (s + ls, s + lt, t - (s + ls));
1001 +static int this_config_len (const char *config);
1003 +this_config_len (const char *config)
1005 + const char *c = config;
1013 + return c - config;
1016 +static const char * expand_asterisks (const char *str, int *len,
1017 + const char *subst);
1019 +/* Expand all asterisks (*) in a menu entry or commands section with its
1020 + substitution. Use a backslash as escape character. */
1021 +static const char *
1022 +expand_asterisks (const char *str, int *len, const char *subst)
1024 + static char buffer[1024];
1025 + char *b = buffer, escaped = 0;
1026 + const char *end = str + *len;
1030 + if (*str == '*' && !escaped)
1032 + if (b - buffer + grub_strlen (subst) > sizeof (buffer))
1034 + errnum = ERR_FILELENGTH;
1037 + grub_strcpy (b, subst);
1038 + b += grub_strlen (subst);
1040 + else if (*str == '\\' && !escaped)
1045 + if (b - buffer + 1 > sizeof (buffer))
1047 + errnum = ERR_FILELENGTH;
1054 + *len = b - buffer;
1059 /* This is the starting function in C. */
1062 @@ -1262,6 +1486,97 @@
1063 menu_entries = (char *) MENU_BUF;
1067 + auto void expand_wildcard_entries (void);
1068 + void expand_wildcard_entries (void)
1070 + char *config_entry = config_entries;
1071 + char *menu_entry = menu_entries;
1073 + while (*menu_entry)
1075 + char *command = config_entry;
1079 + char *c = command;
1080 + const char *w = "wildcard";
1082 + while (*w && *c == *w)
1087 + if (*w == 0 && (*c == ' ' || *c == '\t' || *c == '='))
1091 + /* This is a wildcard command. Advance to the argument. */
1092 + while (*c == ' ' || *c == '\t' || *c == '=')
1095 + /* Expand wildcard entry. */
1096 + w = wildcard (c, &wlen);
1098 + inplace_sort (w, wlen);
1100 + /* Remove the wildcard command from the command section;
1101 + it has no meaning beyond the wildcard expansion just
1103 + len = grub_strlen (command) + 1;
1104 + grub_memmove (command, command + len,
1105 + config_len - (command - config_entries));
1106 + config_len -= len;
1110 + /* Insert expansion before the wildcard entry in the
1111 + list of entry names. */
1112 + len = grub_strlen (menu_entry) + 1;
1113 + const char *x = expand_asterisks (menu_entry, &len, w);
1114 + grub_memmove (menu_entry + len, menu_entry,
1115 + menu_len - (menu_entry - menu_entries));
1116 + memcpy (menu_entry, x, len);
1117 + menu_entry += len;
1120 + /* Insert expansion before the wildcard command section
1121 + in the list of command sections. */
1122 + len = this_config_len (config_entry);
1123 + x = expand_asterisks (config_entry, &len, w);
1124 + grub_memmove (config_entry + len, config_entry,
1125 + config_len - (config_entry -
1127 + memcpy (config_entry, x, len);
1128 + config_entry += len;
1129 + config_len += len;
1132 + wlen -= grub_strlen (w) + 1;
1133 + w += grub_strlen (w) + 1;
1136 + /* Remove the wildcard command section; it has just
1138 + len = grub_strlen (menu_entry) + 1;
1139 + grub_memmove (menu_entry, menu_entry + len,
1140 + menu_len - (menu_entry - menu_entries));
1143 + len = this_config_len(config_entry);
1144 + grub_memmove (config_entry, config_entry + len,
1145 + config_len - (config_entry - config_entries));
1146 + config_len -= len;
1150 + command += grub_strlen (command) + 1;
1153 + menu_entry += grub_strlen (menu_entry) + 1;
1154 + config_entry += this_config_len(config_entry);
1158 /* Initialize the environment for restarting Stage 2. */
1159 grub_setjmp (restart_env);
1160 @@ -1414,8 +1729,16 @@
1161 config_len = prev_config_len;
1165 + close_preset_menu ();
1169 menu_entries[menu_len++] = 0;
1170 config_entries[config_len++] = 0;
1172 + expand_wildcard_entries();
1174 grub_memmove (config_entries + config_len, menu_entries,
1176 menu_entries = config_entries + config_len;
1177 @@ -1456,11 +1779,6 @@
1183 - close_preset_menu ();