From: marco_g Date: Sun, 6 Nov 2005 22:19:59 +0000 (+0000) Subject: 2005-11-06 Marco Gerards X-Git-Tag: 1.98~2042 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=daac212ae3588792d9fb099e55fa0f3c9d2b3727;p=thirdparty%2Fgrub.git 2005-11-06 Marco Gerards Add initial scripting support. * commands/test.c: New file. * include/grub/script.h: Likewise. * normal/execute.c: Likewise. * normal/function.c: Likewise. * normal/lexer.c: Likewise. * normal/parser.y: Likewise. * normal/script.c: Likewise. * configure.ac: Add `AC_PROG_YACC' test. * conf/i386-pc.rmk (grub_emu_SOURCES): Add `commands/test.c', `normal/execute.c', `normal/lexer.c', `grub_script.tab.c', `normal/function.c' and `normal/script.c'. (normal_mod_SOURCES): `normal/execute.c', `normal/lexer.c', `grub_script.tab.c', `normal/function.c' and `normal/script.c'. (test_mod_SOURCES, test_mod_CFLAGS, test_mod_LDFLAGS): New variables. (pkgdata_MODULES): Add `test.mod'. (grub_script.tab.c): New rule. (grub_script.tab.h): Likewise. * include/grub/err.h (grub_err_t): Add `GRUB_ERR_TEST_FAILURE'. * include/grub/normal.h (grub_test_init): New prototype. (grub_test_fini): Likewise. * normal/command.c: Include . (grub_command_execute): Rewritten. * util/grub-emu.c (main): Call `grub_test_init' and `grub_test_fini'. --- diff --git a/ChangeLog b/ChangeLog index 52eadd6d6..728ef1a47 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2005-11-06 Marco Gerards + + Add initial scripting support. + + * commands/test.c: New file. + * include/grub/script.h: Likewise. + * normal/execute.c: Likewise. + * normal/function.c: Likewise. + * normal/lexer.c: Likewise. + * normal/parser.y: Likewise. + * normal/script.c: Likewise. + + * configure.ac: Add `AC_PROG_YACC' test. + + * conf/i386-pc.rmk (grub_emu_SOURCES): Add `commands/test.c', + `normal/execute.c', `normal/lexer.c', `grub_script.tab.c', + `normal/function.c' and `normal/script.c'. + (normal_mod_SOURCES): `normal/execute.c', `normal/lexer.c', + `grub_script.tab.c', `normal/function.c' and `normal/script.c'. + (test_mod_SOURCES, test_mod_CFLAGS, test_mod_LDFLAGS): New variables. + (pkgdata_MODULES): Add `test.mod'. + (grub_script.tab.c): New rule. + (grub_script.tab.h): Likewise. + + * include/grub/err.h (grub_err_t): Add `GRUB_ERR_TEST_FAILURE'. + + * include/grub/normal.h (grub_test_init): New prototype. + (grub_test_fini): Likewise. + + * normal/command.c: Include . + (grub_command_execute): Rewritten. + + * util/grub-emu.c (main): Call `grub_test_init' and + `grub_test_fini'. + 2005-11-03 Hollis Blanchard * kern/powerpc/ieee1275/init.c (grub_get_rtc): Initialize `msecs' diff --git a/commands/test.c b/commands/test.c new file mode 100644 index 000000000..9ee7abe6d --- /dev/null +++ b/commands/test.c @@ -0,0 +1,89 @@ +/* test.c -- The test command.. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * + * GRUB is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +static grub_err_t +grub_cmd_test (struct grub_arg_list *state __attribute__ ((unused)), int argc, + char **args) + +{ + char *eq; + char *eqis; + + /* XXX: No fancy expression evaluation yet. */ + + if (argc == 0) + return 0; + + eq = grub_strdup (args[0]); + eqis = grub_strchr (eq, '='); + if (! eqis) + return 0; + + *eqis = '\0'; + eqis++; + /* Check an expression in the form `A=B'. */ + if (grub_strcmp (eq, eqis)) + grub_error (GRUB_ERR_TEST_FAILURE, "false"); + grub_free (eq); + + return grub_errno; +} + + + +#ifdef GRUB_UTIL +void +grub_test_init (void) +{ + grub_register_command ("[", grub_cmd_test, GRUB_COMMAND_FLAG_CMDLINE, + "[ EXPRESSION ]", "Evaluate an expression", 0); + grub_register_command ("test", grub_cmd_test, GRUB_COMMAND_FLAG_CMDLINE, + "test EXPRESSION", "Evaluate an expression", 0); +} + +void +grub_test_fini (void) +{ + grub_unregister_command ("["); + grub_unregister_command ("test"); +} +#else /* ! GRUB_UTIL */ +GRUB_MOD_INIT +{ + (void)mod; /* To stop warning. */ + grub_register_command ("[", grub_cmd_test, GRUB_COMMAND_FLAG_CMDLINE, + "[ EXPRESSION ]", "Evaluate an expression", 0); + grub_register_command ("test", grub_cmd_test, GRUB_COMMAND_FLAG_CMDLINE, + "test EXPRESSION", "Evaluate an expression", 0); +} + +GRUB_MOD_FINI +{ + grub_unregister_command ("["); + grub_unregister_command ("test"); +} +#endif /* ! GRUB_UTIL */ diff --git a/conf/i386-pc.mk b/conf/i386-pc.mk index 2af0a7c8c..20afa0777 100644 --- a/conf/i386-pc.mk +++ b/conf/i386-pc.mk @@ -274,6 +274,13 @@ DEFSYMFILES += kernel_syms.lst symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) gensymlist.sh sh $(srcdir)/gensymlist.sh $(filter %.h,$^) > $@ +# For the parser. +grub_script.tab.c: normal/parser.y + $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/normal/parser.y +grub_script.tab.h: normal/parser.y + $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/normal/parser.y + + kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) genkernsyms.sh sh $(srcdir)/genkernsyms.sh $(filter %h,$^) > $@ @@ -748,27 +755,28 @@ grub_probefs-fs_sfs.d: fs/sfs.c # For grub-emu. grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/default.c commands/help.c \ - commands/terminal.c commands/ls.c commands/search.c \ - commands/timeout.c \ + commands/terminal.c commands/ls.c commands/test.c \ + commands/search.c commands/timeout.c \ commands/i386/pc/halt.c commands/i386/pc/reboot.c \ disk/loopback.c \ fs/affs.c fs/ext2.c fs/fat.c fs/fshelp.c fs/hfs.c fs/iso9660.c \ fs/jfs.c fs/minix.c fs/sfs.c fs/ufs.c fs/xfs.c \ io/gzio.c \ kern/device.c kern/disk.c kern/dl.c kern/env.c kern/err.c \ - kern/file.c kern/fs.c kern/loader.c kern/main.c kern/misc.c \ - kern/parser.c kern/partition.c kern/rescue.c kern/term.c \ - normal/arg.c normal/cmdline.c normal/command.c \ + normal/execute.c kern/file.c kern/fs.c normal/lexer.c \ + kern/loader.c kern/main.c kern/misc.c kern/parser.c \ + grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c \ + normal/arg.c normal/cmdline.c normal/command.c normal/function.c\ normal/completion.c normal/context.c normal/main.c \ - normal/menu.c normal/menu_entry.c normal/misc.c \ + normal/menu.c normal/menu_entry.c normal/misc.c normal/script.c \ partmap/amiga.c partmap/apple.c partmap/pc.c partmap/sun.c \ util/console.c util/grub-emu.c util/misc.c \ util/i386/pc/biosdisk.c util/i386/pc/getroot.c \ util/i386/pc/misc.c -CLEANFILES += grub-emu grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_default.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_search.o grub_emu-commands_timeout.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_i386_pc_reboot.o grub_emu-disk_loopback.o grub_emu-fs_affs.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_fshelp.o grub_emu-fs_hfs.o grub_emu-fs_iso9660.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_loader.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_parser.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_completion.o grub_emu-normal_context.o grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_misc.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_i386_pc_biosdisk.o grub_emu-util_i386_pc_getroot.o grub_emu-util_i386_pc_misc.o -MOSTLYCLEANFILES += grub_emu-commands_boot.d grub_emu-commands_cat.d grub_emu-commands_cmp.d grub_emu-commands_configfile.d grub_emu-commands_default.d grub_emu-commands_help.d grub_emu-commands_terminal.d grub_emu-commands_ls.d grub_emu-commands_search.d grub_emu-commands_timeout.d grub_emu-commands_i386_pc_halt.d grub_emu-commands_i386_pc_reboot.d grub_emu-disk_loopback.d grub_emu-fs_affs.d grub_emu-fs_ext2.d grub_emu-fs_fat.d grub_emu-fs_fshelp.d grub_emu-fs_hfs.d grub_emu-fs_iso9660.d grub_emu-fs_jfs.d grub_emu-fs_minix.d grub_emu-fs_sfs.d grub_emu-fs_ufs.d grub_emu-fs_xfs.d grub_emu-io_gzio.d grub_emu-kern_device.d grub_emu-kern_disk.d grub_emu-kern_dl.d grub_emu-kern_env.d grub_emu-kern_err.d grub_emu-kern_file.d grub_emu-kern_fs.d grub_emu-kern_loader.d grub_emu-kern_main.d grub_emu-kern_misc.d grub_emu-kern_parser.d grub_emu-kern_partition.d grub_emu-kern_rescue.d grub_emu-kern_term.d grub_emu-normal_arg.d grub_emu-normal_cmdline.d grub_emu-normal_command.d grub_emu-normal_completion.d grub_emu-normal_context.d grub_emu-normal_main.d grub_emu-normal_menu.d grub_emu-normal_menu_entry.d grub_emu-normal_misc.d grub_emu-partmap_amiga.d grub_emu-partmap_apple.d grub_emu-partmap_pc.d grub_emu-partmap_sun.d grub_emu-util_console.d grub_emu-util_grub_emu.d grub_emu-util_misc.d grub_emu-util_i386_pc_biosdisk.d grub_emu-util_i386_pc_getroot.d grub_emu-util_i386_pc_misc.d +CLEANFILES += grub-emu grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_default.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_test.o grub_emu-commands_search.o grub_emu-commands_timeout.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_i386_pc_reboot.o grub_emu-disk_loopback.o grub_emu-fs_affs.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_fshelp.o grub_emu-fs_hfs.o grub_emu-fs_iso9660.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-normal_execute.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-normal_lexer.o grub_emu-kern_loader.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_parser.o grub_emu-grub_script_tab.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_function.o grub_emu-normal_completion.o grub_emu-normal_context.o grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_misc.o grub_emu-normal_script.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_i386_pc_biosdisk.o grub_emu-util_i386_pc_getroot.o grub_emu-util_i386_pc_misc.o +MOSTLYCLEANFILES += grub_emu-commands_boot.d grub_emu-commands_cat.d grub_emu-commands_cmp.d grub_emu-commands_configfile.d grub_emu-commands_default.d grub_emu-commands_help.d grub_emu-commands_terminal.d grub_emu-commands_ls.d grub_emu-commands_test.d grub_emu-commands_search.d grub_emu-commands_timeout.d grub_emu-commands_i386_pc_halt.d grub_emu-commands_i386_pc_reboot.d grub_emu-disk_loopback.d grub_emu-fs_affs.d grub_emu-fs_ext2.d grub_emu-fs_fat.d grub_emu-fs_fshelp.d grub_emu-fs_hfs.d grub_emu-fs_iso9660.d grub_emu-fs_jfs.d grub_emu-fs_minix.d grub_emu-fs_sfs.d grub_emu-fs_ufs.d grub_emu-fs_xfs.d grub_emu-io_gzio.d grub_emu-kern_device.d grub_emu-kern_disk.d grub_emu-kern_dl.d grub_emu-kern_env.d grub_emu-kern_err.d grub_emu-normal_execute.d grub_emu-kern_file.d grub_emu-kern_fs.d grub_emu-normal_lexer.d grub_emu-kern_loader.d grub_emu-kern_main.d grub_emu-kern_misc.d grub_emu-kern_parser.d grub_emu-grub_script_tab.d grub_emu-kern_partition.d grub_emu-kern_rescue.d grub_emu-kern_term.d grub_emu-normal_arg.d grub_emu-normal_cmdline.d grub_emu-normal_command.d grub_emu-normal_function.d grub_emu-normal_completion.d grub_emu-normal_context.d grub_emu-normal_main.d grub_emu-normal_menu.d grub_emu-normal_menu_entry.d grub_emu-normal_misc.d grub_emu-normal_script.d grub_emu-partmap_amiga.d grub_emu-partmap_apple.d grub_emu-partmap_pc.d grub_emu-partmap_sun.d grub_emu-util_console.d grub_emu-util_grub_emu.d grub_emu-util_misc.d grub_emu-util_i386_pc_biosdisk.d grub_emu-util_i386_pc_getroot.d grub_emu-util_i386_pc_misc.d -grub-emu: grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_default.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_search.o grub_emu-commands_timeout.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_i386_pc_reboot.o grub_emu-disk_loopback.o grub_emu-fs_affs.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_fshelp.o grub_emu-fs_hfs.o grub_emu-fs_iso9660.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_loader.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_parser.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_completion.o grub_emu-normal_context.o grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_misc.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_i386_pc_biosdisk.o grub_emu-util_i386_pc_getroot.o grub_emu-util_i386_pc_misc.o +grub-emu: grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_configfile.o grub_emu-commands_default.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_test.o grub_emu-commands_search.o grub_emu-commands_timeout.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_i386_pc_reboot.o grub_emu-disk_loopback.o grub_emu-fs_affs.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_fshelp.o grub_emu-fs_hfs.o grub_emu-fs_iso9660.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu-fs_sfs.o grub_emu-fs_ufs.o grub_emu-fs_xfs.o grub_emu-io_gzio.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-normal_execute.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-normal_lexer.o grub_emu-kern_loader.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_parser.o grub_emu-grub_script_tab.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_function.o grub_emu-normal_completion.o grub_emu-normal_context.o grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-normal_misc.o grub_emu-normal_script.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-partmap_sun.o grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_i386_pc_biosdisk.o grub_emu-util_i386_pc_getroot.o grub_emu-util_i386_pc_misc.o $(BUILD_CC) -o $@ $^ $(BUILD_LDFLAGS) $(grub_emu_LDFLAGS) grub_emu-commands_boot.o: commands/boot.c @@ -835,6 +843,14 @@ grub_emu-commands_ls.d: commands/ls.c -include grub_emu-commands_ls.d +grub_emu-commands_test.o: commands/test.c + $(BUILD_CC) -Icommands -I$(srcdir)/commands $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< + +grub_emu-commands_test.d: commands/test.c + set -e; $(BUILD_CC) -Icommands -I$(srcdir)/commands $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -M $< | sed 's,test\.o[ :]*,grub_emu-commands_test.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include grub_emu-commands_test.d + grub_emu-commands_search.o: commands/search.c $(BUILD_CC) -Icommands -I$(srcdir)/commands $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< @@ -1011,6 +1027,14 @@ grub_emu-kern_err.d: kern/err.c -include grub_emu-kern_err.d +grub_emu-normal_execute.o: normal/execute.c + $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< + +grub_emu-normal_execute.d: normal/execute.c + set -e; $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -M $< | sed 's,execute\.o[ :]*,grub_emu-normal_execute.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include grub_emu-normal_execute.d + grub_emu-kern_file.o: kern/file.c $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< @@ -1027,6 +1051,14 @@ grub_emu-kern_fs.d: kern/fs.c -include grub_emu-kern_fs.d +grub_emu-normal_lexer.o: normal/lexer.c + $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< + +grub_emu-normal_lexer.d: normal/lexer.c + set -e; $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -M $< | sed 's,lexer\.o[ :]*,grub_emu-normal_lexer.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include grub_emu-normal_lexer.d + grub_emu-kern_loader.o: kern/loader.c $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< @@ -1059,6 +1091,14 @@ grub_emu-kern_parser.d: kern/parser.c -include grub_emu-kern_parser.d +grub_emu-grub_script_tab.o: grub_script.tab.c + $(BUILD_CC) -I. -I$(srcdir)/. $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< + +grub_emu-grub_script_tab.d: grub_script.tab.c + set -e; $(BUILD_CC) -I. -I$(srcdir)/. $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -M $< | sed 's,grub_script\.tab\.o[ :]*,grub_emu-grub_script_tab.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include grub_emu-grub_script_tab.d + grub_emu-kern_partition.o: kern/partition.c $(BUILD_CC) -Ikern -I$(srcdir)/kern $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< @@ -1107,6 +1147,14 @@ grub_emu-normal_command.d: normal/command.c -include grub_emu-normal_command.d +grub_emu-normal_function.o: normal/function.c + $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< + +grub_emu-normal_function.d: normal/function.c + set -e; $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -M $< | sed 's,function\.o[ :]*,grub_emu-normal_function.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include grub_emu-normal_function.d + grub_emu-normal_completion.o: normal/completion.c $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< @@ -1155,6 +1203,14 @@ grub_emu-normal_misc.d: normal/misc.c -include grub_emu-normal_misc.d +grub_emu-normal_script.o: normal/script.c + $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< + +grub_emu-normal_script.d: normal/script.c + set -e; $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -M $< | sed 's,script\.o[ :]*,grub_emu-normal_script.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include grub_emu-normal_script.d + grub_emu-partmap_amiga.o: partmap/amiga.c $(BUILD_CC) -Ipartmap -I$(srcdir)/partmap $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< @@ -1275,7 +1331,7 @@ pkgdata_MODULES = _chain.mod _linux.mod linux.mod fat.mod ufs.mod \ apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \ help.mod default.mod timeout.mod configfile.mod vbe.mod \ vesafb.mod vbetest.mod vbeinfo.mod search.mod gzio.mod \ - terminfo.mod serial.mod xfs.mod affs.mod sfs.mod + terminfo.mod serial.mod xfs.mod affs.mod sfs.mod test.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -1998,11 +2054,12 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS) # For normal.mod. normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ - normal/completion.c normal/context.c normal/main.c \ - normal/menu.c normal/menu_entry.c normal/misc.c \ - normal/i386/setjmp.S -CLEANFILES += normal.mod mod-normal.o mod-normal.c pre-normal.o normal_mod-normal_arg.o normal_mod-normal_cmdline.o normal_mod-normal_command.o normal_mod-normal_completion.o normal_mod-normal_context.o normal_mod-normal_main.o normal_mod-normal_menu.o normal_mod-normal_menu_entry.o normal_mod-normal_misc.o normal_mod-normal_i386_setjmp.o def-normal.lst und-normal.lst -MOSTLYCLEANFILES += normal_mod-normal_arg.d normal_mod-normal_cmdline.d normal_mod-normal_command.d normal_mod-normal_completion.d normal_mod-normal_context.d normal_mod-normal_main.d normal_mod-normal_menu.d normal_mod-normal_menu_entry.d normal_mod-normal_misc.d normal_mod-normal_i386_setjmp.d + normal/completion.c normal/context.c normal/execute.c \ + normal/function.c normal/lexer.c normal/main.c normal/menu.c \ + normal/menu_entry.c normal/misc.c grub_script.tab.c \ + normal/script.c normal/i386/setjmp.S +CLEANFILES += normal.mod mod-normal.o mod-normal.c pre-normal.o normal_mod-normal_arg.o normal_mod-normal_cmdline.o normal_mod-normal_command.o normal_mod-normal_completion.o normal_mod-normal_context.o normal_mod-normal_execute.o normal_mod-normal_function.o normal_mod-normal_lexer.o normal_mod-normal_main.o normal_mod-normal_menu.o normal_mod-normal_menu_entry.o normal_mod-normal_misc.o normal_mod-grub_script_tab.o normal_mod-normal_script.o normal_mod-normal_i386_setjmp.o def-normal.lst und-normal.lst +MOSTLYCLEANFILES += normal_mod-normal_arg.d normal_mod-normal_cmdline.d normal_mod-normal_command.d normal_mod-normal_completion.d normal_mod-normal_context.d normal_mod-normal_execute.d normal_mod-normal_function.d normal_mod-normal_lexer.d normal_mod-normal_main.d normal_mod-normal_menu.d normal_mod-normal_menu_entry.d normal_mod-normal_misc.d normal_mod-grub_script_tab.d normal_mod-normal_script.d normal_mod-normal_i386_setjmp.d DEFSYMFILES += def-normal.lst UNDSYMFILES += und-normal.lst @@ -2011,7 +2068,7 @@ normal.mod: pre-normal.o mod-normal.o $(LD) $(normal_mod_LDFLAGS) $(LDFLAGS) -r -d -o $@ $^ $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@ -pre-normal.o: normal_mod-normal_arg.o normal_mod-normal_cmdline.o normal_mod-normal_command.o normal_mod-normal_completion.o normal_mod-normal_context.o normal_mod-normal_main.o normal_mod-normal_menu.o normal_mod-normal_menu_entry.o normal_mod-normal_misc.o normal_mod-normal_i386_setjmp.o +pre-normal.o: normal_mod-normal_arg.o normal_mod-normal_cmdline.o normal_mod-normal_command.o normal_mod-normal_completion.o normal_mod-normal_context.o normal_mod-normal_execute.o normal_mod-normal_function.o normal_mod-normal_lexer.o normal_mod-normal_main.o normal_mod-normal_menu.o normal_mod-normal_menu_entry.o normal_mod-normal_misc.o normal_mod-grub_script_tab.o normal_mod-normal_script.o normal_mod-normal_i386_setjmp.o -rm -f $@ $(LD) $(normal_mod_LDFLAGS) -r -d -o $@ $^ @@ -2123,6 +2180,63 @@ fs-context.lst: normal/context.c genfslist.sh set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh normal > $@ || (rm -f $@; exit 1) +normal_mod-normal_execute.o: normal/execute.c + $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -c -o $@ $< + +normal_mod-normal_execute.d: normal/execute.c + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -M $< | sed 's,execute\.o[ :]*,normal_mod-normal_execute.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include normal_mod-normal_execute.d + +CLEANFILES += cmd-execute.lst fs-execute.lst +COMMANDFILES += cmd-execute.lst +FSFILES += fs-execute.lst + +cmd-execute.lst: normal/execute.c gencmdlist.sh + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh normal > $@ || (rm -f $@; exit 1) + +fs-execute.lst: normal/execute.c genfslist.sh + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh normal > $@ || (rm -f $@; exit 1) + + +normal_mod-normal_function.o: normal/function.c + $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -c -o $@ $< + +normal_mod-normal_function.d: normal/function.c + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -M $< | sed 's,function\.o[ :]*,normal_mod-normal_function.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include normal_mod-normal_function.d + +CLEANFILES += cmd-function.lst fs-function.lst +COMMANDFILES += cmd-function.lst +FSFILES += fs-function.lst + +cmd-function.lst: normal/function.c gencmdlist.sh + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh normal > $@ || (rm -f $@; exit 1) + +fs-function.lst: normal/function.c genfslist.sh + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh normal > $@ || (rm -f $@; exit 1) + + +normal_mod-normal_lexer.o: normal/lexer.c + $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -c -o $@ $< + +normal_mod-normal_lexer.d: normal/lexer.c + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -M $< | sed 's,lexer\.o[ :]*,normal_mod-normal_lexer.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include normal_mod-normal_lexer.d + +CLEANFILES += cmd-lexer.lst fs-lexer.lst +COMMANDFILES += cmd-lexer.lst +FSFILES += fs-lexer.lst + +cmd-lexer.lst: normal/lexer.c gencmdlist.sh + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh normal > $@ || (rm -f $@; exit 1) + +fs-lexer.lst: normal/lexer.c genfslist.sh + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh normal > $@ || (rm -f $@; exit 1) + + normal_mod-normal_main.o: normal/main.c $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -c -o $@ $< @@ -2199,6 +2313,44 @@ fs-misc.lst: normal/misc.c genfslist.sh set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh normal > $@ || (rm -f $@; exit 1) +normal_mod-grub_script_tab.o: grub_script.tab.c + $(CC) -I. -I$(srcdir)/. $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -c -o $@ $< + +normal_mod-grub_script_tab.d: grub_script.tab.c + set -e; $(CC) -I. -I$(srcdir)/. $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -M $< | sed 's,grub_script\.tab\.o[ :]*,normal_mod-grub_script_tab.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include normal_mod-grub_script_tab.d + +CLEANFILES += cmd-grub_script.tab.lst fs-grub_script.tab.lst +COMMANDFILES += cmd-grub_script.tab.lst +FSFILES += fs-grub_script.tab.lst + +cmd-grub_script.tab.lst: grub_script.tab.c gencmdlist.sh + set -e; $(CC) -I. -I$(srcdir)/. $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh normal > $@ || (rm -f $@; exit 1) + +fs-grub_script.tab.lst: grub_script.tab.c genfslist.sh + set -e; $(CC) -I. -I$(srcdir)/. $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh normal > $@ || (rm -f $@; exit 1) + + +normal_mod-normal_script.o: normal/script.c + $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -c -o $@ $< + +normal_mod-normal_script.d: normal/script.c + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -M $< | sed 's,script\.o[ :]*,normal_mod-normal_script.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include normal_mod-normal_script.d + +CLEANFILES += cmd-script.lst fs-script.lst +COMMANDFILES += cmd-script.lst +FSFILES += fs-script.lst + +cmd-script.lst: normal/script.c gencmdlist.sh + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh normal > $@ || (rm -f $@; exit 1) + +fs-script.lst: normal/script.c genfslist.sh + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh normal > $@ || (rm -f $@; exit 1) + + normal_mod-normal_i386_setjmp.o: normal/i386/setjmp.S $(CC) -Inormal/i386 -I$(srcdir)/normal/i386 $(CPPFLAGS) $(ASFLAGS) $(normal_mod_ASFLAGS) -c -o $@ $< @@ -3719,6 +3871,57 @@ fs-gzio.lst: io/gzio.c genfslist.sh gzio_mod_CFLAGS = $(COMMON_CFLAGS) gzio_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For test.mod. +test_mod_SOURCES = commands/test.c +CLEANFILES += test.mod mod-test.o mod-test.c pre-test.o test_mod-commands_test.o def-test.lst und-test.lst +MOSTLYCLEANFILES += test_mod-commands_test.d +DEFSYMFILES += def-test.lst +UNDSYMFILES += und-test.lst + +test.mod: pre-test.o mod-test.o + -rm -f $@ + $(LD) $(test_mod_LDFLAGS) $(LDFLAGS) -r -d -o $@ $^ + $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@ + +pre-test.o: test_mod-commands_test.o + -rm -f $@ + $(LD) $(test_mod_LDFLAGS) -r -d -o $@ $^ + +mod-test.o: mod-test.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(test_mod_CFLAGS) -c -o $@ $< + +mod-test.c: moddep.lst genmodsrc.sh + sh $(srcdir)/genmodsrc.sh 'test' $< > $@ || (rm -f $@; exit 1) + +def-test.lst: pre-test.o + $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 test/' > $@ + +und-test.lst: pre-test.o + echo 'test' > $@ + $(NM) -u -P -p $< | cut -f1 -d' ' >> $@ + +test_mod-commands_test.o: commands/test.c + $(CC) -Icommands -I$(srcdir)/commands $(CPPFLAGS) $(CFLAGS) $(test_mod_CFLAGS) -c -o $@ $< + +test_mod-commands_test.d: commands/test.c + set -e; $(CC) -Icommands -I$(srcdir)/commands $(CPPFLAGS) $(CFLAGS) $(test_mod_CFLAGS) -M $< | sed 's,test\.o[ :]*,test_mod-commands_test.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include test_mod-commands_test.d + +CLEANFILES += cmd-test.lst fs-test.lst +COMMANDFILES += cmd-test.lst +FSFILES += fs-test.lst + +cmd-test.lst: commands/test.c gencmdlist.sh + set -e; $(CC) -Icommands -I$(srcdir)/commands $(CPPFLAGS) $(CFLAGS) $(test_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh test > $@ || (rm -f $@; exit 1) + +fs-test.lst: commands/test.c genfslist.sh + set -e; $(CC) -Icommands -I$(srcdir)/commands $(CPPFLAGS) $(CFLAGS) $(test_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh test > $@ || (rm -f $@; exit 1) + + +test_mod_CFLAGS = $(COMMON_CFLAGS) +test_mod_LDFLAGS = $(COMMON_LDFLAGS) CLEANFILES += moddep.lst command.lst fs.lst pkgdata_DATA += moddep.lst command.lst fs.lst moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 027c909e7..f24526680 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -46,6 +46,13 @@ DEFSYMFILES += kernel_syms.lst symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) gensymlist.sh sh $(srcdir)/gensymlist.sh $(filter %.h,$^) > $@ +# For the parser. +grub_script.tab.c: normal/parser.y + $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/normal/parser.y +grub_script.tab.h: normal/parser.y + $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/normal/parser.y + + kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) genkernsyms.sh sh $(srcdir)/genkernsyms.sh $(filter %h,$^) > $@ @@ -80,19 +87,20 @@ grub_probefs_SOURCES = util/i386/pc/grub-probefs.c \ # For grub-emu. grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/default.c commands/help.c \ - commands/terminal.c commands/ls.c commands/search.c \ - commands/timeout.c \ + commands/terminal.c commands/ls.c commands/test.c \ + commands/search.c commands/timeout.c \ commands/i386/pc/halt.c commands/i386/pc/reboot.c \ disk/loopback.c \ fs/affs.c fs/ext2.c fs/fat.c fs/fshelp.c fs/hfs.c fs/iso9660.c \ fs/jfs.c fs/minix.c fs/sfs.c fs/ufs.c fs/xfs.c \ io/gzio.c \ kern/device.c kern/disk.c kern/dl.c kern/env.c kern/err.c \ - kern/file.c kern/fs.c kern/loader.c kern/main.c kern/misc.c \ - kern/parser.c kern/partition.c kern/rescue.c kern/term.c \ - normal/arg.c normal/cmdline.c normal/command.c \ + normal/execute.c kern/file.c kern/fs.c normal/lexer.c \ + kern/loader.c kern/main.c kern/misc.c kern/parser.c \ + grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c \ + normal/arg.c normal/cmdline.c normal/command.c normal/function.c\ normal/completion.c normal/context.c normal/main.c \ - normal/menu.c normal/menu_entry.c normal/misc.c \ + normal/menu.c normal/menu_entry.c normal/misc.c normal/script.c \ partmap/amiga.c partmap/apple.c partmap/pc.c partmap/sun.c \ util/console.c util/grub-emu.c util/misc.c \ util/i386/pc/biosdisk.c util/i386/pc/getroot.c \ @@ -117,7 +125,7 @@ pkgdata_MODULES = _chain.mod _linux.mod linux.mod fat.mod ufs.mod \ apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \ help.mod default.mod timeout.mod configfile.mod vbe.mod \ vesafb.mod vbetest.mod vbeinfo.mod search.mod gzio.mod \ - terminfo.mod serial.mod xfs.mod affs.mod sfs.mod + terminfo.mod serial.mod xfs.mod affs.mod sfs.mod test.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -196,9 +204,10 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS) # For normal.mod. normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ - normal/completion.c normal/context.c normal/main.c \ - normal/menu.c normal/menu_entry.c normal/misc.c \ - normal/i386/setjmp.S + normal/completion.c normal/context.c normal/execute.c \ + normal/function.c normal/lexer.c normal/main.c normal/menu.c \ + normal/menu_entry.c normal/misc.c grub_script.tab.c \ + normal/script.c normal/i386/setjmp.S normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_ASFLAGS = $(COMMON_ASFLAGS) -m32 normal_mod_LDFLAGS = $(COMMON_LDFLAGS) @@ -347,3 +356,8 @@ search_mod_LDFLAGS = $(COMMON_LDFLAGS) gzio_mod_SOURCES = io/gzio.c gzio_mod_CFLAGS = $(COMMON_CFLAGS) gzio_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For test.mod. +test_mod_SOURCES = commands/test.c +test_mod_CFLAGS = $(COMMON_CFLAGS) +test_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/configure b/configure index bf208456a..a7d1f4982 100644 --- a/configure +++ b/configure @@ -311,7 +311,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA SET_MAKE OBJCOPY ac_ct_OBJCOPY STRIP ac_ct_STRIP NM ac_ct_NM LD ac_ct_LD RUBY BUILD_CC CPP EGREP LIBLZO LIBCURSES LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT YACC INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA SET_MAKE OBJCOPY ac_ct_OBJCOPY STRIP ac_ct_STRIP NM ac_ct_NM LD ac_ct_LD RUBY BUILD_CC CPP EGREP LIBLZO LIBCURSES LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -2345,6 +2345,47 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_YACC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_YACC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + echo "$as_me:$LINENO: result: $YACC" >&5 +echo "${ECHO_T}$YACC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + # Check whether --enable-largefile or --disable-largefile was given. if test "${enable_largefile+set}" = set; then @@ -7100,6 +7141,7 @@ s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t +s,@YACC@,$YACC,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t diff --git a/configure.ac b/configure.ac index 279726aad..f2f4f541c 100644 --- a/configure.ac +++ b/configure.ac @@ -44,6 +44,7 @@ if test "x$CFLAGS" = x; then fi AC_PROG_CC +AC_PROG_YACC AC_SYS_LARGEFILE # Must be GCC. diff --git a/include/grub/err.h b/include/grub/err.h index 636009033..3ef858225 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -26,6 +26,7 @@ typedef enum { GRUB_ERR_NONE = 0, + GRUB_ERR_TEST_FAILURE, GRUB_ERR_BAD_MODULE, GRUB_ERR_OUT_OF_MEMORY, GRUB_ERR_BAD_FILE_TYPE, diff --git a/include/grub/normal.h b/include/grub/normal.h index 89d0d74ac..9dd7debb2 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -224,6 +224,8 @@ void grub_configfile_init (void); void grub_configfile_fini (void); void grub_search_init (void); void grub_search_fini (void); +void grub_test_init (void); +void grub_test_fini (void); #endif #endif /* ! GRUB_NORMAL_HEADER */ diff --git a/include/grub/script.h b/include/grub/script.h new file mode 100644 index 000000000..6ba0a4cd5 --- /dev/null +++ b/include/grub/script.h @@ -0,0 +1,189 @@ +/* script.h */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include + +struct grub_script_mem; + +/* The generic header for each scripting command or structure. */ +struct grub_script_cmd +{ + /* This function is called to execute the command. */ + grub_err_t (*exec) (struct grub_script_cmd *cmd); + + /* The next command. This can be used by the parent to form a chain + of commands. */ + struct grub_script_cmd *next; +}; + +struct grub_script +{ + struct grub_script_mem *mem; + struct grub_script_cmd *cmd; +}; + +typedef enum +{ + GRUB_SCRIPT_ARG_TYPE_STR, + GRUB_SCRIPT_ARG_TYPE_VAR +} grub_script_arg_type_t; + +/* A part of an argument. */ +struct grub_script_arg +{ + grub_script_arg_type_t type; + + char *str; + + /* Next argument part. */ + struct grub_script_arg *next; +}; + +/* A complete argument. It consists of a list of one or more `struct + grub_script_arg's. */ +struct grub_script_arglist +{ + struct grub_script_arglist *next; + struct grub_script_arg *arg; + /* Only stored in the first link. */ + int argcount; +}; + +/* A single command line. */ +struct grub_script_cmdline +{ + struct grub_script_cmd cmd; + + /* The arguments for this command. */ + struct grub_script_arglist *arglist; + + /* The command name of this command. XXX: Perhaps an argument + should be used for this so we can use variables as command + name. */ + char *cmdname; +}; + +/* A block of commands, this can be used to group commands. */ +struct grub_script_cmdblock +{ + struct grub_script_cmd cmd; + + /* A chain of commands. */ + struct grub_script_cmd *cmdlist; +}; + +/* An if statement. */ +struct grub_script_cmdif +{ + struct grub_script_cmd cmd; + + /* The command used to check if the if is true or false. */ + struct grub_script_cmd *bool; + + /* The code executed in case the result if bool was true. */ + struct grub_script_cmd *true; + + /* The code executed in case the result if bool was false. */ + struct grub_script_cmd *false; +}; + +struct grub_script_arglist * +grub_script_create_arglist (void); + +struct grub_script_arglist * +grub_script_add_arglist (struct grub_script_arglist *list, + struct grub_script_arg *arg); +struct grub_script_cmd * +grub_script_create_cmdline (char *cmdname, + struct grub_script_arglist *arglist); +struct grub_script_cmd * +grub_script_create_cmdblock (void); + +struct grub_script_cmd * +grub_script_create_cmdif (struct grub_script_cmd *bool, + struct grub_script_cmd *true, + struct grub_script_cmd *false); +struct grub_script_cmd * +grub_script_add_cmd (struct grub_script_cmdblock *cmdblock, + struct grub_script_cmd *cmd); +struct grub_script_arg * +grub_script_arg_add (struct grub_script_arg *arg, + grub_script_arg_type_t type, char *str); + +struct grub_script *grub_script_parse (char *script, + grub_err_t (*getline) (char **)); +void grub_script_free (struct grub_script *script); +struct grub_script *grub_script_create (struct grub_script_cmd *cmd, + struct grub_script_mem *mem); + +void grub_script_lexer_init (char *s, grub_err_t (*getline) (char **)); +void grub_script_lexer_ref (void); +void grub_script_lexer_deref (void); + +/* Functions to track allocated memory. */ +void *grub_script_malloc (grub_size_t size); +struct grub_script_mem *grub_script_mem_record (void); +struct grub_script_mem *grub_script_mem_record_stop (struct grub_script_mem *restore); + +/* Functions used by bison. */ +int grub_script_yylex (void); +int grub_script_yyparse (void); +void grub_script_yyerror (char const *err); + +/* Commands to execute, don't use these directly. */ +grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd); +grub_err_t grub_script_execute_cmdblock (struct grub_script_cmd *cmd); +grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd); + +/* Execute any GRUB pre-parsed command or script. */ +grub_err_t grub_script_execute (struct grub_script *script); + +/* This variable points to the parsed command. This is used to + communicate with the bison code. */ +extern struct grub_script_cmd *grub_script_parsed; + + + +/* The function description. */ +struct grub_script_function +{ + /* The name. */ + char *name; + + /* The script function. */ + struct grub_script *func; + + /* The flags. */ + unsigned flags; + + /* The next element. */ + struct grub_script_function *next; + + int references; +}; +typedef struct grub_script_function *grub_script_function_t; + +grub_script_function_t grub_script_function_create (char *functionname, + struct grub_script *cmd); +void grub_script_function_remove (const char *name); +grub_script_function_t grub_script_function_find (char *functionname); +int grub_script_function_iterate (int (*iterate) (grub_script_function_t)); +int grub_script_function_call (grub_script_function_t func, + int argc, char **args); diff --git a/normal/command.c b/normal/command.c index 431c07650..5df26e7c0 100644 --- a/normal/command.c +++ b/normal/command.c @@ -25,6 +25,7 @@ #include #include #include +#include static grub_command_t grub_command_list; @@ -193,42 +194,9 @@ grub_command_execute (char *cmdline, int interactive) return grub_cmdline_get (">", *s, GRUB_MAX_CMDLINE, 0, 1); } - grub_command_t cmd; grub_err_t ret = 0; char *pager; - int num; - char **args; - struct grub_arg_list *state; - struct grub_arg_option *parser; - int maxargs = 0; - char **arglist; - int numargs; - - if (grub_parser_split_cmdline (cmdline, cmdline_get, &num, &args)) - return 0; - - /* In case of an assignment set the environment accordingly instead - of calling a function. */ - if (num == 0 && grub_strchr (args[0], '=')) - { - char *val; - - if (! interactive) - grub_printf ("%s\n", cmdline); - - val = grub_strchr (args[0], '='); - val[0] = 0; - grub_env_set (args[0], val + 1); - val[0] = '='; - return 0; - } - - cmd = grub_command_find (args[0]); - if (! cmd) - return -1; - - if (! (cmd->flags & GRUB_COMMAND_FLAG_NO_ECHO) && ! interactive) - grub_printf ("%s\n", cmdline); + struct grub_script *parsed_script; /* Enable the pager if the environment pager is set to 1. */ if (interactive) @@ -237,27 +205,22 @@ grub_command_execute (char *cmdline, int interactive) pager = 0; if (pager && (! grub_strcmp (pager, "1"))) grub_set_more (1); - - parser = (struct grub_arg_option *) cmd->options; - while (parser && (parser++)->doc) - maxargs++; - state = grub_malloc (sizeof (struct grub_arg_list) * maxargs); - grub_memset (state, 0, sizeof (struct grub_arg_list) * maxargs); - if (! (cmd->flags & GRUB_COMMAND_FLAG_NO_ARG_PARSE)) + /* Parse the script. */ + parsed_script = grub_script_parse (cmdline, cmdline_get); + + if (parsed_script) { - if (grub_arg_parse (cmd, num, &args[1], state, &arglist, &numargs)) - ret = (cmd->func) (state, numargs, arglist); + /* Execute the command(s). */ + grub_script_execute (parsed_script); + + /* The parsed script was executed, throw it away. */ + grub_script_free (parsed_script); } - else - ret = (cmd->func) (state, num, &args[1]); - - grub_free (state); if (pager && (! grub_strcmp (pager, "1"))) grub_set_more (0); - - grub_free (args); + return ret; } diff --git a/normal/execute.c b/normal/execute.c new file mode 100644 index 000000000..98d828e40 --- /dev/null +++ b/normal/execute.c @@ -0,0 +1,204 @@ +/* execute.c -- Execute a GRUB script. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +static int +grub_script_execute_cmd (struct grub_script_cmd *cmd) +{ + if (cmd == 0) + return 0; + cmd->exec (cmd); + + return 0; +} + +/* Parse ARG and return the textual representation. Add strings are + concatenated and all values of the variables are filled in. */ +static char * +grub_script_execute_argument_to_string (struct grub_script_arg *arg) +{ + int size = 0; + char *val; + char *chararg; + struct grub_script_arg *argi; + + /* First determine the size of the argument. */ + for (argi = arg; argi; argi = argi->next) + { + if (argi->type == 1) + { + val = grub_env_get (argi->str); + size += grub_strlen (val); + } + else + size += grub_strlen (argi->str); + } + + /* Create the argument. */ + chararg = grub_malloc (size + 1); + if (! chararg) + return 0; + + *chararg = '\0'; + /* First determine the size of the argument. */ + for (argi = arg; argi; argi = argi->next) + { + if (argi->type == 1) + { + val = grub_env_get (argi->str); + grub_strcat (chararg, val); + } + else + grub_strcat (chararg, argi->str); + } + + return chararg; +} + +/* Execute a single command line. */ +grub_err_t +grub_script_execute_cmdline (struct grub_script_cmd *cmd) +{ + struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd; + struct grub_script_arglist *arglist; + char **args = 0; + int i = 0; + grub_command_t grubcmd; + struct grub_arg_list *state; + struct grub_arg_option *parser; + int maxargs = 0; + char **parsed_arglist; + int numargs; + grub_err_t ret = 0; + int argcount = 0; + grub_script_function_t func = 0; + char errnobuf[6]; + + /* Lookup the command. */ + grubcmd = grub_command_find (cmdline->cmdname); + if (! grubcmd) + { + /* It's not a GRUB command, try all functions. */ + func = grub_script_function_find (cmdline->cmdname); + if (! func) + return 0; + } + + if (cmdline->arglist) + { + argcount = cmdline->arglist->argcount; + + /* Create argv from the arguments. */ + args = grub_malloc (sizeof (char *) * argcount); + for (arglist = cmdline->arglist; arglist; arglist = arglist->next) + { + char *str; + str = grub_script_execute_argument_to_string (arglist->arg); + args[i++] = str; + } + } + + /* Execute the GRUB command or function. */ + if (grubcmd) + { + /* Count the amount of options the command has. */ + parser = (struct grub_arg_option *) grubcmd->options; + while (parser && (parser++)->doc) + maxargs++; + + /* Set up the option state. */ + state = grub_malloc (sizeof (struct grub_arg_list) * maxargs); + grub_memset (state, 0, sizeof (struct grub_arg_list) * maxargs); + + /* Start the command. */ + if (! (grubcmd->flags & GRUB_COMMAND_FLAG_NO_ARG_PARSE)) + { + if (grub_arg_parse (grubcmd, argcount, args, state, &parsed_arglist, &numargs)) + ret = (grubcmd->func) (state, numargs, parsed_arglist); + } + else + ret = (grubcmd->func) (state, argcount, args); + + grub_free (state); + } + else + ret = grub_script_function_call (func, argcount, args); + + /* Free arguments. */ + for (i = 0; i < argcount; i++) + grub_free (args[i]); + grub_free (args); + + grub_sprintf (errnobuf, "%d", ret); + grub_env_set ("?", errnobuf); + + return ret; +} + +/* Execute a block of one or more commands. */ +grub_err_t +grub_script_execute_cmdblock (struct grub_script_cmd *cmd) +{ + struct grub_script_cmdblock *cmdblock = (struct grub_script_cmdblock *) cmd; + + /* Loop over every command and execute it. */ + for (cmd = cmdblock->cmdlist; cmd; cmd = cmd->next) + grub_script_execute_cmd (cmd); + + return 0; +} + +/* Execute an if statement. */ +grub_err_t +grub_script_execute_cmdif (struct grub_script_cmd *cmd) +{ + struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd; + char *bool; + + /* Check if the commands results in a true or a false. The value is + read from the env variable `RESULT'. */ + grub_script_execute_cmd (cmdif->bool); + bool = grub_env_get ("?"); + + /* Execute the `if' or the `else' part depending on the value of + `RESULT'. */ + if (bool && ! grub_strcmp (bool, "0")) + return grub_script_execute_cmd (cmdif->true); + else + return grub_script_execute_cmd (cmdif->false); +} + + + +/* Execute any GRUB pre-parsed command or script. */ +grub_err_t +grub_script_execute (struct grub_script *script) +{ + if (script == 0) + return 0; + + return grub_script_execute_cmd (script->cmd); +} diff --git a/normal/function.c b/normal/function.c new file mode 100644 index 000000000..7ae5c5b11 --- /dev/null +++ b/normal/function.c @@ -0,0 +1,127 @@ +/* script.c */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +static grub_script_function_t grub_script_function_list; + +grub_script_function_t +grub_script_function_create (char *functionname, struct grub_script *cmd) +{ + grub_script_function_t func; + grub_script_function_t *p; + + func = (grub_script_function_t) grub_malloc (sizeof (*func)); + if (! func) + return 0; + + func->name = grub_strdup (functionname); + if (! func->name) + { + grub_free (func); + return 0; + } + + func->func = cmd; + + /* Keep the list sorted for simplicity. */ + p = &grub_script_function_list; + while (*p) + { + if (grub_strcmp ((*p)->name, functionname) >= 0) + break; + + p = &((*p)->next); + } + + /* If the function already exists, overwrite the old function. */ + if (*p && grub_strcmp ((*p)->name, functionname) == 0) + { + grub_script_function_t q; + + q = *p; + grub_script_free (q->func); + q->func = cmd; + grub_free (func); + func = q; + } + else + { + func->next = *p; + *p = func; + } + + return func; +} + +void +grub_script_function_remove (const char *name) +{ + grub_script_function_t *p, q; + + for (p = &grub_script_function_list, q = *p; q; p = &(q->next), q = q->next) + if (grub_strcmp (name, q->name) == 0) + { + *p = q->next; + grub_free (q->name); + grub_script_free (q->func); + grub_free (q); + break; + } +} + +grub_script_function_t +grub_script_function_find (char *functionname) +{ + grub_script_function_t func; + + for (func = grub_script_function_list; func; func = func->next) + if (grub_strcmp (functionname, func->name) == 0) + break; + + if (! func) + grub_error (GRUB_ERR_UNKNOWN_COMMAND, "unknown command `%s'", functionname); + + return func; +} + +int +grub_script_function_iterate (int (*iterate) (grub_script_function_t)) +{ + grub_script_function_t func; + + for (func = grub_script_function_list; func; func = func->next) + if (iterate (func)) + return 1; + + return 0; +} + +int +grub_script_function_call (grub_script_function_t func, + int argc __attribute__((unused)), + char **args __attribute__((unused))) +{ + /* XXX: Arguments are not supported yet. */ + return grub_script_execute (func->func); +} diff --git a/normal/lexer.c b/normal/lexer.c new file mode 100644 index 000000000..968fffa32 --- /dev/null +++ b/normal/lexer.c @@ -0,0 +1,274 @@ +/* lexer.c - The scripting lexer. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "grub_script.tab.h" + +static grub_parser_state_t grub_script_lexer_state; +static int grub_script_lexer_done = 0; +static grub_err_t (*grub_script_lexer_getline) (char **); + +static int +check_varstate (grub_parser_state_t state) +{ + return (state == GRUB_PARSER_STATE_VARNAME + || state == GRUB_PARSER_STATE_VAR + || state == GRUB_PARSER_STATE_QVAR + || state == GRUB_PARSER_STATE_VARNAME2 + || state == GRUB_PARSER_STATE_QVARNAME + || state == GRUB_PARSER_STATE_QVARNAME2); +} + +static int +check_textstate (grub_parser_state_t state) +{ + return (state == GRUB_PARSER_STATE_TEXT + || state == GRUB_PARSER_STATE_QUOTE + || state == GRUB_PARSER_STATE_DQUOTE); +} + +/* The amount of references to the lexer by the parser. If the parser + expects tokens the lexer is referenced. */ +static int grub_script_lexer_refs = 0; +static char *script; +static char *newscript; + +/* XXX: The lexer is not reentrant. */ +void +grub_script_lexer_init (char *s, grub_err_t (*getline) (char **)) +{ + grub_script_lexer_state = GRUB_PARSER_STATE_TEXT; + grub_script_lexer_getline = getline; + grub_script_lexer_refs = 0; + grub_script_lexer_done = 0; + newscript = 0; + script = s; +} + +void +grub_script_lexer_ref (void) +{ + grub_script_lexer_refs++; +} + +void +grub_script_lexer_deref (void) +{ + grub_script_lexer_refs--; +} + +int +grub_script_yylex (void) +{ + grub_parser_state_t newstate; + char use; + char *buffer; + char *bp; + + if (grub_script_lexer_done) + return 0; + + if (! *script) + { + /* Check if more tokens are requested by the parser. */ + if ((grub_script_lexer_refs + || grub_script_lexer_state == GRUB_PARSER_STATE_ESC) + && grub_script_lexer_getline) + { + while (! grub_strlen (script)) + { + grub_free (newscript); + grub_script_lexer_getline (&newscript); + script = newscript; + } + grub_dprintf ("scripting", "token=`\\n'\n"); + if (grub_script_lexer_state != GRUB_PARSER_STATE_ESC) + return '\n'; + } + else + { + grub_free (newscript); + newscript = 0; + grub_script_lexer_done = 1; + grub_dprintf ("scripting", "token=`\\n'\n"); + return '\n'; + } + } + + newstate = grub_parser_cmdline_state (grub_script_lexer_state, *script, &use); + + /* Check if it is a text. */ + if (check_textstate (newstate)) + { + /* In case the string is not quoted, this can be a one char + length symbol. */ + if (newstate == GRUB_PARSER_STATE_TEXT) + { + switch (*script) + { + case ' ': + while (*script) + { + newstate = grub_parser_cmdline_state (grub_script_lexer_state, + *script, &use); + if (! (grub_script_lexer_state == GRUB_PARSER_STATE_TEXT + && *script == ' ')) + { + grub_dprintf ("scripting", "token=` '\n"); + return ' '; + } + grub_script_lexer_state = newstate; + script++; + } + grub_dprintf ("scripting", "token=` '\n"); + return ' '; + case '{': + case '}': + case ';': + case '\n': + grub_dprintf ("scripting", "token=`%c'\n", *script); + return *(script++); + } + } + + /* XXX: Use a better size. */ + buffer = grub_script_malloc (2096); + if (! buffer) + return 0; + + bp = buffer; + + /* Read one token, possible quoted. */ + while (*script) + { + newstate = grub_parser_cmdline_state (grub_script_lexer_state, + *script, &use); + + /* Check if a variable name starts. */ + if (check_varstate (newstate)) + break; + + /* If the string is not quoted or escaped, stop processing + when a special token was found. It will be recognised + next time when this function is called. */ + if (newstate == GRUB_PARSER_STATE_TEXT + && grub_script_lexer_state != GRUB_PARSER_STATE_ESC) + { + int breakout = 0; + + switch (use) + { + case ' ': + case '{': + case '}': + case ';': + case '\n': + breakout = 1; + } + if (breakout) + break; + *(bp++) = use; + } + else if (use) + *(bp++) = use; + + grub_script_lexer_state = newstate; + script++; + } + + /* A string of text was read in. */ + *bp = '\0'; + grub_dprintf ("scripting", "token=`%s'\n", buffer); + grub_script_yylval.string = buffer; + + /* Detect some special tokens. */ + if (! grub_strcmp (buffer, "while")) + return GRUB_PARSER_TOKEN_WHILE; + else if (! grub_strcmp (buffer, "if")) + return GRUB_PARSER_TOKEN_IF; + else if (! grub_strcmp (buffer, "function")) + return GRUB_PARSER_TOKEN_FUNCTION; + else if (! grub_strcmp (buffer, "else")) + return GRUB_PARSER_TOKEN_ELSE; + else if (! grub_strcmp (buffer, "then")) + return GRUB_PARSER_TOKEN_THEN; + else if (! grub_strcmp (buffer, "fi")) + return GRUB_PARSER_TOKEN_FI; + else + return GRUB_PARSER_TOKEN_NAME; + } + else if (newstate == GRUB_PARSER_STATE_VAR + || newstate == GRUB_PARSER_STATE_QVAR) + { + /* XXX: Use a better size. */ + buffer = grub_script_malloc (2096); + if (! buffer) + return 0; + + bp = buffer; + + /* This is a variable, read the variable name. */ + while (*script) + { + newstate = grub_parser_cmdline_state (grub_script_lexer_state, + *script, &use); + + /* Check if this character is not part of the variable name + anymore. */ + if (! (check_varstate (newstate))) + { + if (grub_script_lexer_state == GRUB_PARSER_STATE_VARNAME2 + || grub_script_lexer_state == GRUB_PARSER_STATE_QVARNAME2) + script++; + grub_script_lexer_state = newstate; + break; + } + + if (use) + *(bp++) = use; + script++; + grub_script_lexer_state = newstate; + } + + *bp = '\0'; + grub_script_lexer_state = newstate; + grub_script_yylval.string = buffer; + grub_dprintf ("scripting", "vartoken=`%s'\n", buffer); + + return GRUB_PARSER_TOKEN_VAR; + } + else + { + /* There is either text or a variable name. In the case you + arrive here there is a serious problem with the lexer. */ + grub_error (GRUB_ERR_BAD_ARGUMENT, "Internal error\n"); + return 0; + } +} + +void +grub_script_yyerror (char const *err) +{ + grub_printf (err); +} diff --git a/normal/parser.y b/normal/parser.y new file mode 100644 index 000000000..50fc7c21c --- /dev/null +++ b/normal/parser.y @@ -0,0 +1,191 @@ +/* parser.y - The scripting parser. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +%{ +#include +#include + +#define YYFREE grub_free +#define YYMALLOC grub_malloc + +/* Keep track of the memory allocated for this specific function. */ +static struct grub_script_mem *func_mem = 0; + +%} + +%union { + struct grub_script_cmd *cmd; + struct grub_script_arglist *arglist; + struct grub_script_arg *arg; + char *string; +} + +%token GRUB_PARSER_TOKEN_IF "if" +%token GRUB_PARSER_TOKEN_WHILE "while" +%token GRUB_PARSER_TOKEN_FUNCTION "function" +%token GRUB_PARSER_TOKEN_ELSE "else" +%token GRUB_PARSER_TOKEN_THEN "then" +%token GRUB_PARSER_TOKEN_FI "fi" +%token GRUB_PARSER_TOKEN_NAME +%token GRUB_PARSER_TOKEN_VAR +%type script grubcmd command commands if +%type arguments; +%type argument; +%type "if" "while" "function" "else" "then" "fi" +%type text GRUB_PARSER_TOKEN_NAME GRUB_PARSER_TOKEN_VAR + +%% +/* It should be possible to do this in a clean way... */ +script: commands '\n' + { + grub_script_parsed = $1; + } +; + +/* Some tokens are both used as token or as plain text. XXX: Add all + tokens without causing conflicts. */ +text: GRUB_PARSER_TOKEN_NAME + { + $$ = $1; + } + | "if" + { + $$ = $1; + } + | "while" + { + $$ = $1; + } +; + +ws: /* Empty */ + | ' ' +; + +returns: /* Empty */ + | '\n' +; + +/* An argument can consist of some static text mixed with variables, + for example: `foo${bar}baz'. */ +argument: GRUB_PARSER_TOKEN_VAR + { + $$ = grub_script_arg_add (0, GRUB_SCRIPT_ARG_TYPE_VAR, $1); + } + | text + { + $$ = grub_script_arg_add (0, GRUB_SCRIPT_ARG_TYPE_STR, $1); + } + | argument GRUB_PARSER_TOKEN_VAR + { + $$ = grub_script_arg_add ($1, GRUB_SCRIPT_ARG_TYPE_VAR, $2); + } + | argument text + { + $$ = grub_script_arg_add ($1, GRUB_SCRIPT_ARG_TYPE_STR, $2); + } +; + +arguments: argument + { + $$ = grub_script_add_arglist (0, $1); + } + | arguments ' ' argument + { + $$ = grub_script_add_arglist ($1, $3); + } +; + +grubcmd: ws GRUB_PARSER_TOKEN_NAME ' ' arguments ws + { + $$ = grub_script_create_cmdline ($2, $4); + } + | ws GRUB_PARSER_TOKEN_NAME ws + { + $$ = grub_script_create_cmdline ($2, 0); + } +; + +/* A single command. */ +command: grubcmd { $$ = $1; } + | if { $$ = $1; } + | function { $$ = 0; } +; + +/* A block of commands. */ +commands: command + { + $$ = grub_script_add_cmd (0, $1); + } + | commands ';' command + { + struct grub_script_cmdblock *cmd; + cmd = (struct grub_script_cmdblock *) $1; + $$ = grub_script_add_cmd (cmd, $3); + } + | commands '\n' command + { + struct grub_script_cmdblock *cmd; + cmd = (struct grub_script_cmdblock *) $1; + $$ = grub_script_add_cmd (cmd, $3); + } +; + +/* A function. Carefully save the memory that is allocated. */ +function: "function" ' ' GRUB_PARSER_TOKEN_NAME + { + grub_script_lexer_ref (); + } ws '{' returns + { + /* The first part of the function was recognised. + Now start recording the memory usage to store + this function. */ + func_mem = grub_script_mem_record (); + } commands returns '}' + { + struct grub_script *script; + + /* All the memory usage for parsing this function + was recorded. */ + func_mem = grub_script_mem_record_stop (func_mem); + script = grub_script_create ($9, func_mem); + if (script) + grub_script_function_create ($3, script); + grub_script_lexer_deref (); + } +; + +/* The first part of the if statement. It's used to switch the lexer + to a state in which it demands more tokens. */ +if_statement: "if" { grub_script_lexer_ref (); } +; + +/* The if statement. */ +if: if_statement grubcmd ';' ws "then" returns commands returns "fi" + { + $$ = grub_script_create_cmdif ($2, $7, 0); + grub_script_lexer_deref (); + } + | if_statement grubcmd ';' ws "then" returns commands returns "else" returns commands "fi" + { + $$ = grub_script_create_cmdif ($2, $7, $11); + grub_script_lexer_deref (); + } +; diff --git a/normal/script.c b/normal/script.c new file mode 100644 index 000000000..f14254eeb --- /dev/null +++ b/normal/script.c @@ -0,0 +1,289 @@ +/* script.c -- Functions to create an in memory description of the script. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +/* It is not possible to deallocate the memory when a syntax error was + found. Because of that it is required to keep track of all memory + allocations. The memory is free'ed in case of an error, or + assigned to the parsed script when parsing was successful. */ + +/* The memory that was used while parsing and scanning. */ +static struct grub_script_mem *grub_script_memused; + +/* The result of the parser. */ +struct grub_script_cmd *grub_script_parsed = 0; + +/* In case of the normal malloc, some additional bytes are allocated + for this datastructure. All reserved memory is stored in a linked + list so it can be easily free'ed. The original memory can be found + from &mem. */ +struct grub_script_mem +{ + struct grub_script_mem *next; + char mem; +}; + +/* Return malloc'ed memory and keep track of the allocation. */ +void * +grub_script_malloc (grub_size_t size) +{ + struct grub_script_mem *mem; + mem = (struct grub_script_mem *) grub_malloc (size + sizeof (*mem) + - sizeof (char)); + + grub_dprintf ("scripting", "malloc %p\n", mem); + mem->next = grub_script_memused; + grub_script_memused = mem; + return (void *) &mem->mem; +} + +/* Free all memory described by MEM. */ +static void +grub_script_mem_free (struct grub_script_mem *mem) +{ + struct grub_script_mem *memfree; + + while (mem) + { + memfree = mem->next; + grub_dprintf ("scripting", "free %p\n", mem); + grub_free (mem); + mem = memfree; + } +} + +/* Start recording memory usage. Returns the memory that should be + restored when calling stop. */ +struct grub_script_mem * +grub_script_mem_record (void) +{ + struct grub_script_mem *mem = grub_script_memused; + grub_script_memused = 0; + return mem; +} + +/* Stop recording memory usage. Restore previous recordings using + RESTORE. Return the recorded memory. */ +struct grub_script_mem * +grub_script_mem_record_stop (struct grub_script_mem *restore) +{ + struct grub_script_mem *mem = grub_script_memused; + grub_script_memused = restore; + return mem; +} + +/* Free the memory reserved for CMD and all of it's children. */ +void +grub_script_free (struct grub_script *script) +{ + if (! script) + return; + grub_script_mem_free (script->mem); + grub_free (script); +} + + + +/* Extend the argument arg with a variable or string of text. If ARG + is zero a new list is created. */ +struct grub_script_arg * +grub_script_arg_add (struct grub_script_arg *arg, + grub_script_arg_type_t type, char *str) +{ + struct grub_script_arg *argpart; + struct grub_script_arg *ll; + + argpart = (struct grub_script_arg *) grub_script_malloc (sizeof (*arg)); + argpart->type = type; + argpart->str = str; + argpart->next = 0; + + if (! arg) + return argpart; + + for (ll = arg; ll->next; ll = ll->next); + ll->next = argpart; + + return arg; +} + +/* Add the argument ARG to the end of the argument list LIST. If LIST + is zero, a new list will be created. */ +struct grub_script_arglist * +grub_script_add_arglist (struct grub_script_arglist *list, struct grub_script_arg *arg) +{ + struct grub_script_arglist *link; + struct grub_script_arglist *ll; + + grub_dprintf ("scripting", "arglist\n"); + + link = (struct grub_script_arglist *) grub_script_malloc (sizeof (*link)); + link->next = 0; + link->arg = arg; + link->argcount = 0; + + if (! list) + { + link->argcount++; + return link; + } + + list->argcount++; + + /* Look up the last link in the chain. */ + for (ll = list; ll->next; ll = ll->next); + ll->next = link; + + return list; +} + +/* Create a command that describes a single command line. CMDLINE + contains the name of the command that should be executed. ARGLIST + holds all arguments for this command. */ +struct grub_script_cmd * +grub_script_create_cmdline (char *cmdname, struct grub_script_arglist *arglist) +{ + struct grub_script_cmdline *cmd; + + grub_dprintf ("scripting", "cmdline\n"); + + cmd = grub_script_malloc (sizeof (*cmd)); + cmd->cmd.exec = grub_script_execute_cmdline; +/* cmd->cmd.free = grub_script_free_cmdline; */ + cmd->cmd.next = 0; + cmd->arglist = arglist; + cmd->cmdname = cmdname; + + return (struct grub_script_cmd *) cmd; +} + +/* Create a command that functions as an if statement. If BOOL is + evaluated to true (the value is returned in envvar RESULT), the + interpreter will run the command TRUE, otherwise the interpreter + runs the command FALSE. */ +struct grub_script_cmd * +grub_script_create_cmdif (struct grub_script_cmd *bool, + struct grub_script_cmd *true, + struct grub_script_cmd *false) +{ + struct grub_script_cmdif *cmd; + + grub_dprintf ("scripting", "cmdif\n"); + + cmd = grub_script_malloc (sizeof (*cmd)); + cmd->cmd.exec = grub_script_execute_cmdif; + cmd->cmd.next = 0; + cmd->bool = bool; + cmd->true = true; + cmd->false = false; + + return (struct grub_script_cmd *) cmd; +} + +/* Create a block of commands. CMD contains the command that should + be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new + cmdblock will be created. */ +struct grub_script_cmd * +grub_script_add_cmd (struct grub_script_cmdblock *cmdblock, struct grub_script_cmd *cmd) +{ + grub_dprintf ("scripting", "cmdblock\n"); + + if (! cmd) + return (struct grub_script_cmd *) cmdblock; + + if (! cmdblock) + { + cmdblock = (struct grub_script_cmdblock *) grub_script_malloc (sizeof (*cmdblock)); + cmdblock->cmd.exec = grub_script_execute_cmdblock; + cmdblock->cmd.next = 0; + cmdblock->cmdlist = cmd; + } + else + { + struct grub_script_cmd **last; + for (last = &cmdblock->cmdlist; *last; last = &(*last)->next); + *last = cmd; + } + + cmd->next = 0; + + return (struct grub_script_cmd *) cmdblock; +} + + + +struct grub_script * +grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem) +{ + struct grub_script *parsed; + + parsed = grub_malloc (sizeof (*parsed)); + if (! parsed) + { + grub_script_mem_free (mem); + grub_free (cmd); + + return 0; + } + + parsed->mem = mem; + parsed->cmd = cmd; + + return parsed; +} + +/* Parse the script passed in SCRIPT and return the parsed + datastructure that is ready to be interpreted. */ +struct grub_script * +grub_script_parse (char *script, grub_err_t (*getline) (char **)) +{ + struct grub_script *parsed; + struct grub_script_mem *membackup; + + parsed = grub_malloc (sizeof (*parsed)); + if (! parsed) + return 0; + + /* Initialize the lexer. */ + grub_script_lexer_init (script, getline); + + grub_script_parsed = 0; + + membackup = grub_script_mem_record (); + + /* Parse the script, the result is stored in + `grub_script_parsed'. */ + if (grub_script_yyparse ()) + { + struct grub_script_mem *memfree; + memfree = grub_script_mem_record_stop (membackup); + grub_script_mem_free (memfree); + return 0; + } + + parsed->mem = grub_script_mem_record_stop (membackup); + parsed->cmd = grub_script_parsed; + + return parsed; +} diff --git a/util/grub-emu.c b/util/grub-emu.c index c74d77d86..193a28f2b 100644 --- a/util/grub-emu.c +++ b/util/grub-emu.c @@ -219,6 +219,7 @@ main (int argc, char *argv[]) grub_timeout_init (); grub_configfile_init (); grub_search_init (); + grub_test_init (); /* XXX: Should normal mode be started by default? */ grub_normal_init (); @@ -227,6 +228,7 @@ main (int argc, char *argv[]) if (setjmp (main_env) == 0) grub_main (); + grub_test_fini (); grub_search_fini (); grub_configfile_fini (); grub_timeout_fini ();