* Test command
@ 2009-02-13 11:39 phcoder
2009-02-13 11:39 ` [PATCH] " phcoder
0 siblings, 1 reply; 8+ messages in thread
From: phcoder @ 2009-02-13 11:39 UTC (permalink / raw)
To: The development of GRUB 2
Hello. Here is an implementation of bash-like "test" command. Many file
tests are omitted because they are useless in grub (e.g. -c test). I
also added 3 extension: lexicographical comparing, prefixed -gt and -lt
(it skips common prefix. Useful for comparing versions. e.g. [ vmlinuz-3
-plt vmlinuz-11 ] is true) and biased -nt/-ot which adds s specified
amount of seconds to mtime.
Regards
Vladimir 'phcoder' Serbinenko
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] Test command
2009-02-13 11:39 Test command phcoder
@ 2009-02-13 11:39 ` phcoder
2009-04-10 22:18 ` phcoder
0 siblings, 1 reply; 8+ messages in thread
From: phcoder @ 2009-02-13 11:39 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 490 bytes --]
Sorry forgot to attach the file
phcoder wrote:
> Hello. Here is an implementation of bash-like "test" command. Many file
> tests are omitted because they are useless in grub (e.g. -c test). I
> also added 3 extension: lexicographical comparing, prefixed -gt and -lt
> (it skips common prefix. Useful for comparing versions. e.g. [ vmlinuz-3
> -plt vmlinuz-11 ] is true) and biased -nt/-ot which adds s specified
> amount of seconds to mtime.
> Regards
> Vladimir 'phcoder' Serbinenko
[-- Attachment #2: test.diff --]
[-- Type: text/x-patch, Size: 12884 bytes --]
Index: commands/test.c
===================================================================
--- commands/test.c (revision 1989)
+++ commands/test.c (working copy)
@@ -23,33 +23,385 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/env.h>
+#include <grub/fs.h>
+#include <grub/device.h>
+#include <grub/file.h>
+/* A simple implementation for signed numbers*/
+static int
+grub_strtosl (char *arg, char **end, int base)
+{
+ if (arg[0] == '-')
+ return -grub_strtoul (arg + 1, end, base);
+ return grub_strtoul (arg, end, base);
+}
+
+/* Parse a test expression startion from *argn*/
+static int
+test_parse (char **args, int *argn, int argc)
+{
+ int ret = 0, discard = 0, invert = 0;
+ int file_exists;
+ struct grub_dirhook_info file_info;
+
+ auto void update_val (int val);
+ auto void get_fileinfo (char *pathname);
+
+ /*Take care of discarding and inverting*/
+ void update_val (int val)
+ {
+ if (!discard)
+ ret = invert ? !val : val;
+ invert = discard = 0;
+ }
+
+ /* Check if file exists and fetch its information */
+ void get_fileinfo (char *pathname)
+ {
+ char *filename, *path;
+ char *device_name;
+ grub_fs_t fs;
+ grub_device_t dev;
+
+ /* A hook for iterating directories */
+ auto int find_file (const char *cur_filename,
+ struct grub_dirhook_info info);
+ int find_file (const char *cur_filename, struct grub_dirhook_info info)
+ {
+ if (info.case_insensitive ? !grub_strcasecmp (cur_filename, filename)
+ :!grub_strcmp (cur_filename, filename))
+ {
+ file_info = info;
+ file_exists = 1;
+ return 1;
+ }
+ return 0;
+ }
+
+
+ file_exists = 0;
+ device_name = grub_file_get_device_name (pathname);
+ dev = grub_device_open (device_name);
+ if (! dev)
+ {
+ grub_free (device_name);
+ return;
+ }
+
+ fs = grub_fs_probe (dev);
+ path = grub_strchr (pathname, ')');
+ if (! path)
+ path = pathname;
+ else
+ path++;
+
+ /* Remove trailing / */
+ while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
+ pathname[grub_strlen (pathname) - 1] = 0;
+
+ /* Split into path and filename*/
+ filename = grub_strrchr (pathname, '/');
+ if (!filename)
+ {
+ path = grub_strdup ("/");
+ filename = pathname;
+ }
+ else
+ {
+ filename++;
+ path = grub_strdup (pathname);
+ path[filename - pathname] = 0;
+ }
+
+ /* It's the whole device*/
+ if (!*pathname)
+ {
+ file_exists = 1;
+ grub_memset (&file_info, 0, sizeof (file_info));
+ /* Root is always a directory */
+ file_info.dir = 1;
+
+ /* Fetch writing time */
+ file_info.mtimeset = 0;
+ if (fs->mtime)
+ {
+ if (! fs->mtime (dev, &file_info.mtime))
+ file_info.mtimeset = 1;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+ else
+ (fs->dir) (dev, path, find_file);
+
+ grub_device_close (dev);
+ grub_free (path);
+ grub_free (device_name);
+ }
+
+ /* Here we have the real parsing */
+ while (*argn < argc)
+ {
+ /* First try 3 argument tests */
+ /* String tests */
+ if (*argn + 2 < argc && (!grub_strcmp (args[*argn + 1], "=")
+ || !grub_strcmp (args[*argn + 1], "==")))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "!="))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: lexicographical sorting */
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "<"))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "<="))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], ">"))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], ">="))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* Number tests */
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-eq"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ == grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-ge"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ >= grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-gt"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ > grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-le"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ <= grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-lt"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ < grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-ne"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ != grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: compare numbers skipping prefixes.
+ Useful for comparing versions. E.g. vmlinuz-2 -plt vmlinuz-11*/
+ if (*argn + 2 < argc && (!grub_strcmp (args[*argn + 1], "-pgt")
+ || !grub_strcmp (args[*argn + 1], "-plt")))
+ {
+ int i;
+ /* Skip common prefix */
+ for (i = 0; args[*argn][i] == args[*argn + 2][i] && args[*argn][i];
+ i++);
+
+ /*Go the digits back*/
+ i--;
+ while (grub_isdigit (args[*argn][i]) && i > 0)
+ i--;
+ i++;
+
+ if (!grub_strcmp (args[*argn + 1], "-pgt"))
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ > grub_strtoul (args[*argn + 2] + i, 0, 0));
+ else
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ < grub_strtoul (args[*argn + 2] + i, 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* -nt and -ot tests. GRUB extension: when doing -?t<bias> bias
+ will be added to the first mtime */
+ if (*argn + 2 < argc && (!grub_memcmp (args[*argn + 1], "-nt", 3)
+ || !grub_memcmp (args[*argn + 1], "-ot", 3)))
+ {
+ struct grub_dirhook_info file1;
+ int file1exists;
+ int bias = 0;
+
+ /* Fetch fileinfo */
+ get_fileinfo (args[*argn]);
+ file1 = file_info;
+ file1exists = file_exists;
+ get_fileinfo (args[*argn + 2]);
+
+ if (args[*argn + 1][3])
+ bias = grub_strtosl (args[*argn + 1] + 3, 0, 0);
+
+ if (!grub_memcmp (args[*argn + 1], "-nt", 3))
+ update_val ((file1exists && ! file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias > file_info.mtime));
+ else
+ update_val ((!file1exists && file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias < file_info.mtime));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* Two-argument tests */
+ /* file tests*/
+ if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-d"))
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists && file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-e"))
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-f"))
+ {
+ get_fileinfo (args[*argn + 1]);
+ /* FIXME: check for other types */
+ update_val (file_exists && !file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-s"))
+ {
+ grub_file_t file;
+ file = grub_file_open (args[*argn + 1]);
+ update_val (file && grub_file_size (file));
+ if (file)
+ grub_file_close (file);
+ grub_errno = GRUB_ERR_NONE;
+ (*argn) += 2;
+ return ret;
+ }
+
+ /* string tests */
+ if (!grub_strcmp (args[*argn], "-n") && *argn + 1 < argc)
+ {
+ update_val (args[*argn + 1][0]);
+
+ (*argn)+=2;
+ continue;
+ }
+ if (!grub_strcmp (args[*argn], "-z") && *argn + 1 < argc)
+ {
+ update_val (!args[*argn + 1][0]);
+ (*argn)+=2;
+ continue;
+ }
+
+ /* Special modifiers*/
+
+ /* End of expression. return to parent*/
+ if (!grub_strcmp (args[*argn], ")"))
+ {
+ (*argn)++;
+ return ret;
+ }
+ /* Recursively invoke if parenthesis */
+ if (!grub_strcmp (args[*argn], "("))
+ {
+ (*argn)++;
+ update_val (test_parse (args, argn, argc));
+ continue;
+ }
+
+ if (!grub_strcmp (args[*argn], "!"))
+ {
+ invert = !invert;
+ (*argn)++;
+ continue;
+ }
+ if (!grub_strcmp (args[*argn], "-a"))
+ {
+ /* if current value is 0 second value is to be discarded */
+ discard = !ret;
+ (*argn)++;
+ continue;
+ }
+ if (!grub_strcmp (args[*argn], "-o"))
+ {
+ /* if current value is 1 second value is to be discarded */
+ discard = ret;
+ (*argn)++;
+ continue;
+ }
+
+ /* To test found. Interpret if as just a string*/
+ update_val (args[*argn][0]);
+ (*argn)++;
+ }
+ return ret;
+}
+
static grub_err_t
grub_cmd_test (struct grub_arg_list *state __attribute__ ((unused)), int argc,
char **args)
{
- char *eq;
- char *eqis;
+ int argn = 0;
- /* XXX: No fancy expression evaluation yet. */
-
- if (argc == 0)
- return 0;
-
- eq = grub_strdup (args[0]);
- eqis = grub_strchr (eq, '=');
- if (! eqis)
- return 0;
+ if (argc >= 1 && !grub_strcmp (args[argc-1], "]"))
+ argc--;
- *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;
+ return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
+ : grub_error (GRUB_ERR_TEST_FAILURE, "false");
}
@@ -57,9 +409,11 @@
GRUB_MOD_INIT(test)
{
(void)mod; /* To stop warning. */
- grub_register_command ("[", grub_cmd_test, GRUB_COMMAND_FLAG_CMDLINE,
+ grub_register_command ("[", grub_cmd_test, GRUB_COMMAND_FLAG_CMDLINE
+ | GRUB_COMMAND_FLAG_NO_ARG_PARSE,
"[ EXPRESSION ]", "Evaluate an expression", 0);
- grub_register_command ("test", grub_cmd_test, GRUB_COMMAND_FLAG_CMDLINE,
+ grub_register_command ("test", grub_cmd_test, GRUB_COMMAND_FLAG_CMDLINE
+ | GRUB_COMMAND_FLAG_NO_ARG_PARSE,
"test EXPRESSION", "Evaluate an expression", 0);
}
Index: include/grub/fs.h
===================================================================
--- include/grub/fs.h (revision 1989)
+++ include/grub/fs.h (working copy)
@@ -27,13 +27,14 @@
/* Forward declaration is required, because of mutual reference. */
struct grub_file;
struct grub_dirhook_info
{
int dir:1;
int mtimeset:1;
+ int case_insensitive:1;
grub_int32_t mtime;
};
/* Filesystem descriptor. */
struct grub_fs
{
Index: fs/fat.c
===================================================================
--- fs/fat.c (revision 1989)
+++ fs/fat.c (working copy)
@@ -594,9 +557,10 @@
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = (dir->attr & GRUB_FAT_ATTR_DIRECTORY);
+ info.case_insensitive = 1;
if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
return 0;
if (*dirname == '\0' && call_hook)
return hook (filename, info);
Index: fs/hfsplus.c
===================================================================
--- fs/hfsplus.c (revision 1989)
+++ fs/hfsplus.c (working copy)
@@ -898,11 +899,12 @@
enum grub_fshelp_filetype filetype,
grub_fshelp_node_t node)
{
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+ info.case_insensitive = !! (filetype & GRUB_FSHELP_CASE_INSENSITIVE);
grub_free (node);
return hook (filename, info);
}
#ifndef GRUB_UTIL
Index: ChangeLog
===================================================================
--- ChangeLog (revision 1989)
+++ ChangeLog (working copy)
@@ -1,3 +1,13 @@
+2009-02-13 Vladimir Serbinenko <phcoder@gmail.com>
+
+ Test command
+
+ * commands/test.c: rewritten to use bash-like test
+ * include/grub/fs.h (struct grub_dirhook_info): new field
+ case_insensitive
+ * fs/hfsplus.c: declare FS as case-insensitive if necessary
+ * fs/fat.c: likewise
+
2009-02-11 Robert Millan <rmh@aybabtu.com>
* util/grub.d/00_header.in: Update old reference to `font' command.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] Test command
2009-02-13 11:39 ` [PATCH] " phcoder
@ 2009-04-10 22:18 ` phcoder
2009-04-11 10:07 ` Yoshinori K. Okuji
0 siblings, 1 reply; 8+ messages in thread
From: phcoder @ 2009-04-10 22:18 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 710 bytes --]
Rediffed. New changelog
2009-04-11 Vladimir Serbinenko <phcoder@gmail.com>
Test command
* commands/test.c: rewritten to use bash-like test
phcoder wrote:
> Sorry forgot to attach the file
> phcoder wrote:
>> Hello. Here is an implementation of bash-like "test" command. Many
>> file tests are omitted because they are useless in grub (e.g. -c
>> test). I also added 3 extension: lexicographical comparing, prefixed
>> -gt and -lt (it skips common prefix. Useful for comparing versions.
>> e.g. [ vmlinuz-3 -plt vmlinuz-11 ] is true) and biased -nt/-ot which
>> adds s specified amount of seconds to mtime.
>> Regards
>> Vladimir 'phcoder' Serbinenko
>
--
Regards
Vladimir 'phcoder' Serbinenko
[-- Attachment #2: test.diff --]
[-- Type: text/x-diff, Size: 10256 bytes --]
diff --git a/commands/test.c b/commands/test.c
index a9c8281..2d8dedd 100644
--- a/commands/test.c
+++ b/commands/test.c
@@ -21,33 +21,385 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/env.h>
+#include <grub/fs.h>
+#include <grub/device.h>
+#include <grub/file.h>
#include <grub/command.h>
+/* A simple implementation for signed numbers*/
+static int
+grub_strtosl (char *arg, char **end, int base)
+{
+ if (arg[0] == '-')
+ return -grub_strtoul (arg + 1, end, base);
+ return grub_strtoul (arg, end, base);
+}
+
+/* Parse a test expression startion from *argn*/
+static int
+test_parse (char **args, int *argn, int argc)
+{
+ int ret = 0, discard = 0, invert = 0;
+ int file_exists;
+ struct grub_dirhook_info file_info;
+
+ auto void update_val (int val);
+ auto void get_fileinfo (char *pathname);
+
+ /*Take care of discarding and inverting*/
+ void update_val (int val)
+ {
+ if (!discard)
+ ret = invert ? !val : val;
+ invert = discard = 0;
+ }
+
+ /* Check if file exists and fetch its information */
+ void get_fileinfo (char *pathname)
+ {
+ char *filename, *path;
+ char *device_name;
+ grub_fs_t fs;
+ grub_device_t dev;
+
+ /* A hook for iterating directories */
+ auto int find_file (const char *cur_filename,
+ struct grub_dirhook_info info);
+ int find_file (const char *cur_filename, struct grub_dirhook_info info)
+ {
+ if (info.case_insensitive ? !grub_strcasecmp (cur_filename, filename)
+ :!grub_strcmp (cur_filename, filename))
+ {
+ file_info = info;
+ file_exists = 1;
+ return 1;
+ }
+ return 0;
+ }
+
+
+ file_exists = 0;
+ device_name = grub_file_get_device_name (pathname);
+ dev = grub_device_open (device_name);
+ if (! dev)
+ {
+ grub_free (device_name);
+ return;
+ }
+
+ fs = grub_fs_probe (dev);
+ path = grub_strchr (pathname, ')');
+ if (! path)
+ path = pathname;
+ else
+ path++;
+
+ /* Remove trailing / */
+ while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
+ pathname[grub_strlen (pathname) - 1] = 0;
+
+ /* Split into path and filename*/
+ filename = grub_strrchr (pathname, '/');
+ if (!filename)
+ {
+ path = grub_strdup ("/");
+ filename = pathname;
+ }
+ else
+ {
+ filename++;
+ path = grub_strdup (pathname);
+ path[filename - pathname] = 0;
+ }
+
+ /* It's the whole device*/
+ if (!*pathname)
+ {
+ file_exists = 1;
+ grub_memset (&file_info, 0, sizeof (file_info));
+ /* Root is always a directory */
+ file_info.dir = 1;
+
+ /* Fetch writing time */
+ file_info.mtimeset = 0;
+ if (fs->mtime)
+ {
+ if (! fs->mtime (dev, &file_info.mtime))
+ file_info.mtimeset = 1;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+ else
+ (fs->dir) (dev, path, find_file);
+
+ grub_device_close (dev);
+ grub_free (path);
+ grub_free (device_name);
+ }
+
+ /* Here we have the real parsing */
+ while (*argn < argc)
+ {
+ /* First try 3 argument tests */
+ /* String tests */
+ if (*argn + 2 < argc && (!grub_strcmp (args[*argn + 1], "=")
+ || !grub_strcmp (args[*argn + 1], "==")))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "!="))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: lexicographical sorting */
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "<"))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "<="))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], ">"))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], ">="))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* Number tests */
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-eq"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ == grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-ge"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ >= grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-gt"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ > grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-le"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ <= grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-lt"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ < grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-ne"))
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ != grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: compare numbers skipping prefixes.
+ Useful for comparing versions. E.g. vmlinuz-2 -plt vmlinuz-11*/
+ if (*argn + 2 < argc && (!grub_strcmp (args[*argn + 1], "-pgt")
+ || !grub_strcmp (args[*argn + 1], "-plt")))
+ {
+ int i;
+ /* Skip common prefix */
+ for (i = 0; args[*argn][i] == args[*argn + 2][i] && args[*argn][i];
+ i++);
+
+ /*Go the digits back*/
+ i--;
+ while (grub_isdigit (args[*argn][i]) && i > 0)
+ i--;
+ i++;
+
+ if (!grub_strcmp (args[*argn + 1], "-pgt"))
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ > grub_strtoul (args[*argn + 2] + i, 0, 0));
+ else
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ < grub_strtoul (args[*argn + 2] + i, 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* -nt and -ot tests. GRUB extension: when doing -?t<bias> bias
+ will be added to the first mtime */
+ if (*argn + 2 < argc && (!grub_memcmp (args[*argn + 1], "-nt", 3)
+ || !grub_memcmp (args[*argn + 1], "-ot", 3)))
+ {
+ struct grub_dirhook_info file1;
+ int file1exists;
+ int bias = 0;
+
+ /* Fetch fileinfo */
+ get_fileinfo (args[*argn]);
+ file1 = file_info;
+ file1exists = file_exists;
+ get_fileinfo (args[*argn + 2]);
+
+ if (args[*argn + 1][3])
+ bias = grub_strtosl (args[*argn + 1] + 3, 0, 0);
+
+ if (!grub_memcmp (args[*argn + 1], "-nt", 3))
+ update_val ((file1exists && ! file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias > file_info.mtime));
+ else
+ update_val ((!file1exists && file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias < file_info.mtime));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* Two-argument tests */
+ /* file tests*/
+ if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-d"))
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists && file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-e"))
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-f"))
+ {
+ get_fileinfo (args[*argn + 1]);
+ /* FIXME: check for other types */
+ update_val (file_exists && !file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-s"))
+ {
+ grub_file_t file;
+ file = grub_file_open (args[*argn + 1]);
+ update_val (file && grub_file_size (file));
+ if (file)
+ grub_file_close (file);
+ grub_errno = GRUB_ERR_NONE;
+ (*argn) += 2;
+ return ret;
+ }
+
+ /* string tests */
+ if (!grub_strcmp (args[*argn], "-n") && *argn + 1 < argc)
+ {
+ update_val (args[*argn + 1][0]);
+
+ (*argn)+=2;
+ continue;
+ }
+ if (!grub_strcmp (args[*argn], "-z") && *argn + 1 < argc)
+ {
+ update_val (!args[*argn + 1][0]);
+ (*argn)+=2;
+ continue;
+ }
+
+ /* Special modifiers*/
+
+ /* End of expression. return to parent*/
+ if (!grub_strcmp (args[*argn], ")"))
+ {
+ (*argn)++;
+ return ret;
+ }
+ /* Recursively invoke if parenthesis */
+ if (!grub_strcmp (args[*argn], "("))
+ {
+ (*argn)++;
+ update_val (test_parse (args, argn, argc));
+ continue;
+ }
+
+ if (!grub_strcmp (args[*argn], "!"))
+ {
+ invert = !invert;
+ (*argn)++;
+ continue;
+ }
+ if (!grub_strcmp (args[*argn], "-a"))
+ {
+ /* if current value is 0 second value is to be discarded */
+ discard = !ret;
+ (*argn)++;
+ continue;
+ }
+ if (!grub_strcmp (args[*argn], "-o"))
+ {
+ /* if current value is 1 second value is to be discarded */
+ discard = ret;
+ (*argn)++;
+ continue;
+ }
+
+ /* To test found. Interpret if as just a string*/
+ update_val (args[*argn][0]);
+ (*argn)++;
+ }
+ return ret;
+}
+
static grub_err_t
grub_cmd_test (grub_command_t cmd __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;
+ int argn = 0;
+
+ if (argc >= 1 && !grub_strcmp (args[argc-1], "]"))
+ argc--;
+
+ return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
+ : grub_error (GRUB_ERR_TEST_FAILURE, "false");
}
static grub_command_t cmd_1, cmd_2;
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] Test command
2009-04-10 22:18 ` phcoder
@ 2009-04-11 10:07 ` Yoshinori K. Okuji
2009-04-11 15:11 ` phcoder
0 siblings, 1 reply; 8+ messages in thread
From: Yoshinori K. Okuji @ 2009-04-11 10:07 UTC (permalink / raw)
To: The development of GRUB 2
On Saturday 11 April 2009 07:18:59 phcoder wrote:
> Rediffed. New changelog
This time, I comment on all style problems.
> diff --git a/commands/test.c b/commands/test.c
> index a9c8281..2d8dedd 100644
> --- a/commands/test.c
> +++ b/commands/test.c
> @@ -21,33 +21,385 @@
> #include <grub/misc.h>
> #include <grub/mm.h>
> #include <grub/env.h>
> +#include <grub/fs.h>
> +#include <grub/device.h>
> +#include <grub/file.h>
> #include <grub/command.h>
>
> +/* A simple implementation for signed numbers*/
Please make a complete sentence by terminating it with a period. Also, put two
space characters before finishing the comment. This is written in the GNU
Coding Standards.
> +static int
> +grub_strtosl (char *arg, char **end, int base)
> +{
> + if (arg[0] == '-')
> + return -grub_strtoul (arg + 1, end, base);
> + return grub_strtoul (arg, end, base);
> +}
> +
> +/* Parse a test expression startion from *argn*/
Same here.
> +static int
> +test_parse (char **args, int *argn, int argc)
> +{
> + int ret = 0, discard = 0, invert = 0;
> + int file_exists;
> + struct grub_dirhook_info file_info;
> +
> + auto void update_val (int val);
> + auto void get_fileinfo (char *pathname);
> +
> + /*Take care of discarding and inverting*/
Please add a space after the asterisk.
> + void update_val (int val)
> + {
> + if (!discard)
Please add a space.
> + ret = invert ? !val : val;
Same here.
> + invert = discard = 0;
> + }
> +
> + /* Check if file exists and fetch its information */
Same here.
> + void get_fileinfo (char *pathname)
> + {
> + char *filename, *path;
> + char *device_name;
> + grub_fs_t fs;
> + grub_device_t dev;
> +
> + /* A hook for iterating directories */
Same here.
> + auto int find_file (const char *cur_filename,
> + struct grub_dirhook_info info);
> + int find_file (const char *cur_filename, struct grub_dirhook_info
> info) + {
> + if (info.case_insensitive ? !grub_strcasecmp (cur_filename,
> filename) + :!grub_strcmp (cur_filename, filename))
I prefer to avoid treating the return value of strcmp/strcasecmp/memcmp as
boolean, because even experts often make mistakes. Please use "== 0" instead.
> + {
> + file_info = info;
> + file_exists = 1;
> + return 1;
> + }
> + return 0;
> + }
> +
> +
> + file_exists = 0;
> + device_name = grub_file_get_device_name (pathname);
> + dev = grub_device_open (device_name);
> + if (! dev)
> + {
> + grub_free (device_name);
> + return;
> + }
> +
> + fs = grub_fs_probe (dev);
> + path = grub_strchr (pathname, ')');
> + if (! path)
> + path = pathname;
> + else
> + path++;
> +
> + /* Remove trailing / */
Same here.
> + while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
> + pathname[grub_strlen (pathname) - 1] = 0;
> +
> + /* Split into path and filename*/
Same here.
> + filename = grub_strrchr (pathname, '/');
> + if (!filename)
Same here.
> + {
> + path = grub_strdup ("/");
> + filename = pathname;
> + }
> + else
> + {
> + filename++;
> + path = grub_strdup (pathname);
> + path[filename - pathname] = 0;
> + }
> +
> + /* It's the whole device*/
Same here.
> + if (!*pathname)
Same here.
> + {
> + file_exists = 1;
> + grub_memset (&file_info, 0, sizeof (file_info));
> + /* Root is always a directory */
Same here.
> + file_info.dir = 1;
> +
> + /* Fetch writing time */
Same here.
> + file_info.mtimeset = 0;
> + if (fs->mtime)
> + {
> + if (! fs->mtime (dev, &file_info.mtime))
> + file_info.mtimeset = 1;
> + grub_errno = GRUB_ERR_NONE;
> + }
> + }
> + else
> + (fs->dir) (dev, path, find_file);
> +
> + grub_device_close (dev);
> + grub_free (path);
> + grub_free (device_name);
> + }
> +
> + /* Here we have the real parsing */
Same here.
> + while (*argn < argc)
> + {
> + /* First try 3 argument tests */
Ditto.
> + /* String tests */
Ditto.
> + if (*argn + 2 < argc && (!grub_strcmp (args[*argn + 1], "=")
> + || !grub_strcmp (args[*argn + 1], "==")))
Ditto.
> + {
> + update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0);
> + (*argn) += 3;
I myself feel that these parentheses are redundant, but I don't know how
others think. For C programmers, it is well known that * has a very high
priority.
> + continue;
> + }
> +
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "!="))
Ditto.
> + {
> + update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0);
> + (*argn) += 3;
> + continue;
> + }
> +
> + /* GRUB extension: lexicographical sorting */
Ditto.
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "<"))
Ditto.
> + {
> + update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0);
> + (*argn) += 3;
> + continue;
> + }
> +
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "<="))
Ditto.
> + {
> + update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0);
> + (*argn) += 3;
> + continue;
> + }
> +
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], ">"))
Ditto.
> + {
> + update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0);
> + (*argn) += 3;
> + continue;
> + }
> +
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], ">="))
Ditto.
> + {
> + update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0);
> + (*argn) += 3;
> + continue;
> + }
> +
> + /* Number tests */
Ditto.
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-eq"))
Ditto.
> + {
> + update_val (grub_strtosl (args[*argn], 0, 0)
> + == grub_strtosl (args[*argn + 2], 0, 0));
> + (*argn) += 3;
> + continue;
> + }
> +
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-ge"))
Ditto.
> + {
> + update_val (grub_strtosl (args[*argn], 0, 0)
> + >= grub_strtosl (args[*argn + 2], 0, 0));
> + (*argn) += 3;
> + continue;
> + }
> +
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-gt"))
Ditto.
> + {
> + update_val (grub_strtosl (args[*argn], 0, 0)
> + > grub_strtosl (args[*argn + 2], 0, 0));
> + (*argn) += 3;
> + continue;
> + }
> +
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-le"))
Ditto.
> + {
> + update_val (grub_strtosl (args[*argn], 0, 0)
> + <= grub_strtosl (args[*argn + 2], 0, 0));
> + (*argn) += 3;
> + continue;
> + }
> +
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-lt"))
Ditto.
> + {
> + update_val (grub_strtosl (args[*argn], 0, 0)
> + < grub_strtosl (args[*argn + 2], 0, 0));
> + (*argn) += 3;
> + continue;
> + }
> +
> + if (*argn + 2 < argc && !grub_strcmp (args[*argn + 1], "-ne"))
Ditto.
> + {
> + update_val (grub_strtosl (args[*argn], 0, 0)
> + != grub_strtosl (args[*argn + 2], 0, 0));
> + (*argn) += 3;
> + continue;
> + }
> +
> + /* GRUB extension: compare numbers skipping prefixes.
> + Useful for comparing versions. E.g. vmlinuz-2 -plt vmlinuz-11*/
Ditto.
> + if (*argn + 2 < argc && (!grub_strcmp (args[*argn + 1], "-pgt")
> + || !grub_strcmp (args[*argn + 1], "-plt")))
Ditto.
> + {
> + int i;
> + /* Skip common prefix */
Ditto.
> + for (i = 0; args[*argn][i] == args[*argn + 2][i] &&
> args[*argn][i]; + i++);
> +
> + /*Go the digits back*/
Ditto.
> + i--;
> + while (grub_isdigit (args[*argn][i]) && i > 0)
> + i--;
> + i++;
> +
> + if (!grub_strcmp (args[*argn + 1], "-pgt"))
Ditto.
> + update_val (grub_strtoul (args[*argn] + i, 0, 0)
> + > grub_strtoul (args[*argn + 2] + i, 0, 0));
> + else
> + update_val (grub_strtoul (args[*argn] + i, 0, 0)
> + < grub_strtoul (args[*argn + 2] + i, 0, 0));
> + (*argn) += 3;
> + continue;
> + }
> +
> + /* -nt and -ot tests. GRUB extension: when doing -?t<bias> bias
> + will be added to the first mtime */
Ditto.
> + if (*argn + 2 < argc && (!grub_memcmp (args[*argn + 1], "-nt", 3)
> + || !grub_memcmp (args[*argn + 1], "-ot",
> 3))) + {
Ditto.
Getting tired, so I skip the same criticism from here.
> + struct grub_dirhook_info file1;
> + int file1exists;
> + int bias = 0;
> +
> + /* Fetch fileinfo */
> + get_fileinfo (args[*argn]);
> + file1 = file_info;
> + file1exists = file_exists;
> + get_fileinfo (args[*argn + 2]);
> +
> + if (args[*argn + 1][3])
> + bias = grub_strtosl (args[*argn + 1] + 3, 0, 0);
> +
> + if (!grub_memcmp (args[*argn + 1], "-nt", 3))
> + update_val ((file1exists && ! file_exists)
> + || (file1.mtimeset && file_info.mtimeset
> + && file1.mtime + bias > file_info.mtime));
> + else
> + update_val ((!file1exists && file_exists)
> + || (file1.mtimeset && file_info.mtimeset
> + && file1.mtime + bias < file_info.mtime));
> + (*argn) += 3;
> + continue;
> + }
> +
> + /* Two-argument tests */
> + /* file tests*/
> + if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-d"))
> + {
> + get_fileinfo (args[*argn + 1]);
> + update_val (file_exists && file_info.dir);
> + (*argn) += 2;
> + return ret;
> + }
> +
> + if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-e"))
> + {
> + get_fileinfo (args[*argn + 1]);
> + update_val (file_exists);
> + (*argn) += 2;
> + return ret;
> + }
> +
> + if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-f"))
> + {
> + get_fileinfo (args[*argn + 1]);
> + /* FIXME: check for other types */
> + update_val (file_exists && !file_info.dir);
> + (*argn) += 2;
> + return ret;
> + }
> +
> + if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-s"))
> + {
> + grub_file_t file;
> + file = grub_file_open (args[*argn + 1]);
> + update_val (file && grub_file_size (file));
This is not very safe, because grub_file_size returns grub_off_t which is a
64-bit unsigned int. By converting it into 32-bit signed int implicitly, the
result can be zero, even when the size is not zero. So it is better to say
explicitly, != 0.
> + if (file)
> + grub_file_close (file);
> + grub_errno = GRUB_ERR_NONE;
> + (*argn) += 2;
> + return ret;
> + }
> +
> + /* string tests */
> + if (!grub_strcmp (args[*argn], "-n") && *argn + 1 < argc)
> + {
> + update_val (args[*argn + 1][0]);
> +
> + (*argn)+=2;
> + continue;
> + }
> + if (!grub_strcmp (args[*argn], "-z") && *argn + 1 < argc)
> + {
> + update_val (!args[*argn + 1][0]);
> + (*argn)+=2;
> + continue;
> + }
> +
> + /* Special modifiers*/
> +
> + /* End of expression. return to parent*/
> + if (!grub_strcmp (args[*argn], ")"))
> + {
> + (*argn)++;
> + return ret;
> + }
> + /* Recursively invoke if parenthesis */
> + if (!grub_strcmp (args[*argn], "("))
> + {
> + (*argn)++;
> + update_val (test_parse (args, argn, argc));
> + continue;
> + }
> +
> + if (!grub_strcmp (args[*argn], "!"))
> + {
> + invert = !invert;
> + (*argn)++;
> + continue;
> + }
> + if (!grub_strcmp (args[*argn], "-a"))
> + {
> + /* if current value is 0 second value is to be discarded */
> + discard = !ret;
> + (*argn)++;
> + continue;
> + }
> + if (!grub_strcmp (args[*argn], "-o"))
> + {
> + /* if current value is 1 second value is to be discarded */
> + discard = ret;
> + (*argn)++;
> + continue;
> + }
> +
> + /* To test found. Interpret if as just a string*/
> + update_val (args[*argn][0]);
> + (*argn)++;
> + }
> + return ret;
> +}
> +
> static grub_err_t
> grub_cmd_test (grub_command_t cmd __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;
> + int argn = 0;
> +
> + if (argc >= 1 && !grub_strcmp (args[argc-1], "]"))
> + argc--;
> +
> + return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
> + : grub_error (GRUB_ERR_TEST_FAILURE, "false");
> }
>
> static grub_command_t cmd_1, cmd_2;
Regards,
Okuji
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] Test command
2009-04-11 10:07 ` Yoshinori K. Okuji
@ 2009-04-11 15:11 ` phcoder
2009-04-14 15:55 ` Yoshinori K. Okuji
0 siblings, 1 reply; 8+ messages in thread
From: phcoder @ 2009-04-11 15:11 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 1114 bytes --]
Updated. Same changelog
>> + {
>> + update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0);
>> + (*argn) += 3;
>
> I myself feel that these parentheses are redundant, but I don't know how
> others think. For C programmers, it is well known that * has a very high
> priority.
These parenthesis are necessary if doing sth like
(*argn)++
since ++ and += are logically and visually similar I prefer to put the
parenthesis
> Getting tired, so I skip the same criticism from here.
Actually it would have been enough to say "same applies further on in patch"
>> + if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-s"))
>> + {
>> + grub_file_t file;
>> + file = grub_file_open (args[*argn + 1]);
>> + update_val (file && grub_file_size (file));
>
> This is not very safe, because grub_file_size returns grub_off_t which is a
> 64-bit unsigned int. By converting it into 32-bit signed int implicitly, the
> result can be zero, even when the size is not zero. So it is better to say
> explicitly, != 0.
>
--
Regards
Vladimir 'phcoder' Serbinenko
[-- Attachment #2: test.diff --]
[-- Type: text/x-diff, Size: 10450 bytes --]
diff --git a/commands/test.c b/commands/test.c
index a9c8281..1ccfe48 100644
--- a/commands/test.c
+++ b/commands/test.c
@@ -21,33 +21,384 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/env.h>
+#include <grub/fs.h>
+#include <grub/device.h>
+#include <grub/file.h>
#include <grub/command.h>
+/* A simple implementation for signed numbers. */
+static int
+grub_strtosl (char *arg, char **end, int base)
+{
+ if (arg[0] == '-')
+ return -grub_strtoul (arg + 1, end, base);
+ return grub_strtoul (arg, end, base);
+}
+
+/* Parse a test expression startion from *argn. */
+static int
+test_parse (char **args, int *argn, int argc)
+{
+ int ret = 0, discard = 0, invert = 0;
+ int file_exists;
+ struct grub_dirhook_info file_info;
+
+ auto void update_val (int val);
+ auto void get_fileinfo (char *pathname);
+
+ /* Take care of discarding and inverting. */
+ void update_val (int val)
+ {
+ if (! discard)
+ ret = invert ? ! val : val;
+ invert = discard = 0;
+ }
+
+ /* Check if file exists and fetch its information. */
+ void get_fileinfo (char *pathname)
+ {
+ char *filename, *path;
+ char *device_name;
+ grub_fs_t fs;
+ grub_device_t dev;
+
+ /* A hook for iterating directories. */
+ auto int find_file (const char *cur_filename,
+ struct grub_dirhook_info info);
+ int find_file (const char *cur_filename, struct grub_dirhook_info info)
+ {
+ if ((info.case_insensitive ? grub_strcasecmp (cur_filename, filename)
+ : grub_strcmp (cur_filename, filename)) == 0)
+ {
+ file_info = info;
+ file_exists = 1;
+ return 1;
+ }
+ return 0;
+ }
+
+ file_exists = 0;
+ device_name = grub_file_get_device_name (pathname);
+ dev = grub_device_open (device_name);
+ if (! dev)
+ {
+ grub_free (device_name);
+ return;
+ }
+
+ fs = grub_fs_probe (dev);
+ path = grub_strchr (pathname, ')');
+ if (! path)
+ path = pathname;
+ else
+ path++;
+
+ /* Remove trailing '/'. */
+ while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
+ pathname[grub_strlen (pathname) - 1] = 0;
+
+ /* Split into path and filename. */
+ filename = grub_strrchr (pathname, '/');
+ if (! filename)
+ {
+ path = grub_strdup ("/");
+ filename = pathname;
+ }
+ else
+ {
+ filename++;
+ path = grub_strdup (pathname);
+ path[filename - pathname] = 0;
+ }
+
+ /* It's the whole device. */
+ if (! *pathname)
+ {
+ file_exists = 1;
+ grub_memset (&file_info, 0, sizeof (file_info));
+ /* Root is always a directory. */
+ file_info.dir = 1;
+
+ /* Fetch writing time. */
+ file_info.mtimeset = 0;
+ if (fs->mtime)
+ {
+ if (! fs->mtime (dev, &file_info.mtime))
+ file_info.mtimeset = 1;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+ else
+ (fs->dir) (dev, path, find_file);
+
+ grub_device_close (dev);
+ grub_free (path);
+ grub_free (device_name);
+ }
+
+ /* Here we have the real parsing. */
+ while (*argn < argc)
+ {
+ /* First try 3 argument tests. */
+ /* String tests. */
+ if (*argn + 2 < argc && (grub_strcmp (args[*argn + 1], "=") == 0
+ || grub_strcmp (args[*argn + 1], "==") == 0))
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], "!=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: lexicographical sorting. */
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], "<") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], "<=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], ">") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], ">=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* Number tests. */
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], "-eq") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ == grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], "-ge") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ >= grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], "-gt") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ > grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], "-le") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ <= grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], "-lt") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ < grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (*argn + 2 < argc && grub_strcmp (args[*argn + 1], "-ne") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ != grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: compare numbers skipping prefixes.
+ Useful for comparing versions. E.g. vmlinuz-2 -plt vmlinuz-11. */
+ if (*argn + 2 < argc && (grub_strcmp (args[*argn + 1], "-pgt") == 0
+ || grub_strcmp (args[*argn + 1], "-plt") == 0))
+ {
+ int i;
+ /* Skip common prefix. */
+ for (i = 0; args[*argn][i] == args[*argn + 2][i] && args[*argn][i];
+ i++);
+
+ /* Go the digits back. */
+ i--;
+ while (grub_isdigit (args[*argn][i]) && i > 0)
+ i--;
+ i++;
+
+ if (grub_strcmp (args[*argn + 1], "-pgt") == 0)
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ > grub_strtoul (args[*argn + 2] + i, 0, 0));
+ else
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ < grub_strtoul (args[*argn + 2] + i, 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* -nt and -ot tests. GRUB extension: when doing -?t<bias> bias
+ will be added to the first mtime. */
+ if (*argn + 2 < argc && (grub_memcmp (args[*argn + 1], "-nt", 3) == 0
+ || grub_memcmp (args[*argn + 1], "-ot", 3) == 0))
+ {
+ struct grub_dirhook_info file1;
+ int file1exists;
+ int bias = 0;
+
+ /* Fetch fileinfo */
+ get_fileinfo (args[*argn]);
+ file1 = file_info;
+ file1exists = file_exists;
+ get_fileinfo (args[*argn + 2]);
+
+ if (args[*argn + 1][3])
+ bias = grub_strtosl (args[*argn + 1] + 3, 0, 0);
+
+ if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0)
+ update_val ((file1exists && ! file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias > file_info.mtime));
+ else
+ update_val ((! file1exists && file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias < file_info.mtime));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* Two-argument tests. */
+ /* file tests. */
+ if (*argn + 1 < argc && grub_strcmp (args[*argn], "-d") == 0)
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists && file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (*argn + 1 < argc && grub_strcmp (args[*argn], "-e") == 0)
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (*argn + 1 < argc && grub_strcmp (args[*argn], "-f") == 0)
+ {
+ get_fileinfo (args[*argn + 1]);
+ /* FIXME: check for other types. */
+ update_val (file_exists && ! file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (*argn + 1 < argc && grub_strcmp (args[*argn], "-s") == 0)
+ {
+ grub_file_t file;
+ file = grub_file_open (args[*argn + 1]);
+ update_val (file && (grub_file_size (file) != 0));
+ if (file)
+ grub_file_close (file);
+ grub_errno = GRUB_ERR_NONE;
+ (*argn) += 2;
+ return ret;
+ }
+
+ /* string tests. */
+ if (grub_strcmp (args[*argn], "-n") == 0 && *argn + 1 < argc)
+ {
+ update_val (args[*argn + 1][0]);
+
+ (*argn) += 2;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-z") == 0 && *argn + 1 < argc)
+ {
+ update_val (! args[*argn + 1][0]);
+ (*argn) += 2;
+ continue;
+ }
+
+ /* Special modifiers. */
+
+ /* End of expression. return to parent. */
+ if (grub_strcmp (args[*argn], ")") == 0)
+ {
+ (*argn)++;
+ return ret;
+ }
+ /* Recursively invoke if parenthesis. */
+ if (grub_strcmp (args[*argn], "(") == 0)
+ {
+ (*argn)++;
+ update_val (test_parse (args, argn, argc));
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn], "!") == 0)
+ {
+ invert = ! invert;
+ (*argn)++;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-a") == 0)
+ {
+ /* if current value is 0 second value is to be discarded */
+ discard = ! ret;
+ (*argn)++;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-o") == 0)
+ {
+ /* If current value is 1 second value is to be discarded. */
+ discard = ret;
+ (*argn)++;
+ continue;
+ }
+
+ /* No test found. Interpret if as just a string. */
+ update_val (args[*argn][0]);
+ (*argn)++;
+ }
+ return ret;
+}
+
static grub_err_t
grub_cmd_test (grub_command_t cmd __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;
+ int argn = 0;
+
+ if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0)
+ argc--;
+
+ return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
+ : grub_error (GRUB_ERR_TEST_FAILURE, "false");
}
static grub_command_t cmd_1, cmd_2;
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] Test command
2009-04-11 15:11 ` phcoder
@ 2009-04-14 15:55 ` Yoshinori K. Okuji
2009-04-16 13:15 ` phcoder
0 siblings, 1 reply; 8+ messages in thread
From: Yoshinori K. Okuji @ 2009-04-14 15:55 UTC (permalink / raw)
To: The development of GRUB 2
On Sunday 12 April 2009 00:11:45 phcoder wrote:
> Updated. Same changelog
>
> >> + {
> >> + update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0);
> >> + (*argn) += 3;
> >
> > I myself feel that these parentheses are redundant, but I don't know how
> > others think. For C programmers, it is well known that * has a very high
> > priority.
>
> These parenthesis are necessary if doing sth like
> (*argn)++
> since ++ and += are logically and visually similar I prefer to put the
> parenthesis
OK.
>
> > Getting tired, so I skip the same criticism from here.
>
> Actually it would have been enough to say "same applies further on in
> patch"
>
> >> + if (*argn + 1 < argc && !grub_strcmp (args[*argn], "-s"))
> >> + {
> >> + grub_file_t file;
> >> + file = grub_file_open (args[*argn + 1]);
> >> + update_val (file && grub_file_size (file));
> >
> > This is not very safe, because grub_file_size returns grub_off_t which is
> > a 64-bit unsigned int. By converting it into 32-bit signed int
> > implicitly, the result can be zero, even when the size is not zero. So it
> > is better to say explicitly, != 0.
BTW, I think you can simplify test_parse. For example, you write "if (*argn +
2 < argc ...)" many times, but it should be possible to test this condition
only once per loop.
Regards,
Okuji
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] Test command
2009-04-14 15:55 ` Yoshinori K. Okuji
@ 2009-04-16 13:15 ` phcoder
2009-04-25 12:29 ` Vladimir Serbinenko
0 siblings, 1 reply; 8+ messages in thread
From: phcoder @ 2009-04-16 13:15 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 485 bytes --]
> BTW, I think you can simplify test_parse. For example, you write "if (*argn +
> 2 < argc ...)" many times, but it should be possible to test this condition
> only once per loop.
Optimised. Perhaps compiler optimised this anyway but it made code more
readable
>
> Regards,
> Okuji
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
--
Regards
Vladimir 'phcoder' Serbinenko
[-- Attachment #2: test.diff --]
[-- Type: text/x-diff, Size: 10585 bytes --]
diff --git a/commands/test.c b/commands/test.c
index a9c8281..8a15d39 100644
--- a/commands/test.c
+++ b/commands/test.c
@@ -21,33 +21,390 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/env.h>
+#include <grub/fs.h>
+#include <grub/device.h>
+#include <grub/file.h>
#include <grub/command.h>
+/* A simple implementation for signed numbers. */
+static int
+grub_strtosl (char *arg, char **end, int base)
+{
+ if (arg[0] == '-')
+ return -grub_strtoul (arg + 1, end, base);
+ return grub_strtoul (arg, end, base);
+}
+
+/* Parse a test expression startion from *argn. */
+static int
+test_parse (char **args, int *argn, int argc)
+{
+ int ret = 0, discard = 0, invert = 0;
+ int file_exists;
+ struct grub_dirhook_info file_info;
+
+ auto void update_val (int val);
+ auto void get_fileinfo (char *pathname);
+
+ /* Take care of discarding and inverting. */
+ void update_val (int val)
+ {
+ if (! discard)
+ ret = invert ? ! val : val;
+ invert = discard = 0;
+ }
+
+ /* Check if file exists and fetch its information. */
+ void get_fileinfo (char *pathname)
+ {
+ char *filename, *path;
+ char *device_name;
+ grub_fs_t fs;
+ grub_device_t dev;
+
+ /* A hook for iterating directories. */
+ auto int find_file (const char *cur_filename,
+ struct grub_dirhook_info info);
+ int find_file (const char *cur_filename, struct grub_dirhook_info info)
+ {
+ if ((info.case_insensitive ? grub_strcasecmp (cur_filename, filename)
+ : grub_strcmp (cur_filename, filename)) == 0)
+ {
+ file_info = info;
+ file_exists = 1;
+ return 1;
+ }
+ return 0;
+ }
+
+ file_exists = 0;
+ device_name = grub_file_get_device_name (pathname);
+ dev = grub_device_open (device_name);
+ if (! dev)
+ {
+ grub_free (device_name);
+ return;
+ }
+
+ fs = grub_fs_probe (dev);
+ path = grub_strchr (pathname, ')');
+ if (! path)
+ path = pathname;
+ else
+ path++;
+
+ /* Remove trailing '/'. */
+ while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
+ pathname[grub_strlen (pathname) - 1] = 0;
+
+ /* Split into path and filename. */
+ filename = grub_strrchr (pathname, '/');
+ if (! filename)
+ {
+ path = grub_strdup ("/");
+ filename = pathname;
+ }
+ else
+ {
+ filename++;
+ path = grub_strdup (pathname);
+ path[filename - pathname] = 0;
+ }
+
+ /* It's the whole device. */
+ if (! *pathname)
+ {
+ file_exists = 1;
+ grub_memset (&file_info, 0, sizeof (file_info));
+ /* Root is always a directory. */
+ file_info.dir = 1;
+
+ /* Fetch writing time. */
+ file_info.mtimeset = 0;
+ if (fs->mtime)
+ {
+ if (! fs->mtime (dev, &file_info.mtime))
+ file_info.mtimeset = 1;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+ else
+ (fs->dir) (dev, path, find_file);
+
+ grub_device_close (dev);
+ grub_free (path);
+ grub_free (device_name);
+ }
+
+ /* Here we have the real parsing. */
+ while (*argn < argc)
+ {
+ /* First try 3 argument tests. */
+ if (*argn + 2 < argc)
+ {
+ /* String tests. */
+ if (grub_strcmp (args[*argn + 1], "=") == 0
+ || grub_strcmp (args[*argn + 1], "==") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "!=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: lexicographical sorting. */
+ if (grub_strcmp (args[*argn + 1], "<") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "<=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], ">") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], ">=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* Number tests. */
+ if (grub_strcmp (args[*argn + 1], "-eq") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ == grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-ge") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ >= grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-gt") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ > grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-le") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ <= grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-lt") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ < grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-ne") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ != grub_strtosl (args[*argn + 2], 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: compare numbers skipping prefixes.
+ Useful for comparing versions. E.g. vmlinuz-2 -plt vmlinuz-11. */
+ if (grub_strcmp (args[*argn + 1], "-pgt") == 0
+ || grub_strcmp (args[*argn + 1], "-plt") == 0)
+ {
+ int i;
+ /* Skip common prefix. */
+ for (i = 0; args[*argn][i] == args[*argn + 2][i]
+ && args[*argn][i]; i++);
+
+ /* Go the digits back. */
+ i--;
+ while (grub_isdigit (args[*argn][i]) && i > 0)
+ i--;
+ i++;
+
+ if (grub_strcmp (args[*argn + 1], "-pgt") == 0)
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ > grub_strtoul (args[*argn + 2] + i, 0, 0));
+ else
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ < grub_strtoul (args[*argn + 2] + i, 0, 0));
+ (*argn) += 3;
+ continue;
+ }
+
+ /* -nt and -ot tests. GRUB extension: when doing -?t<bias> bias
+ will be added to the first mtime. */
+ if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0
+ || grub_memcmp (args[*argn + 1], "-ot", 3) == 0)
+ {
+ struct grub_dirhook_info file1;
+ int file1exists;
+ int bias = 0;
+
+ /* Fetch fileinfo. */
+ get_fileinfo (args[*argn]);
+ file1 = file_info;
+ file1exists = file_exists;
+ get_fileinfo (args[*argn + 2]);
+
+ if (args[*argn + 1][3])
+ bias = grub_strtosl (args[*argn + 1] + 3, 0, 0);
+
+ if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0)
+ update_val ((file1exists && ! file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias > file_info.mtime));
+ else
+ update_val ((! file1exists && file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias < file_info.mtime));
+ (*argn) += 3;
+ continue;
+ }
+ }
+
+ /* Two-argument tests. */
+ if (*argn + 1 < argc)
+ {
+ /* File tests. */
+ if (grub_strcmp (args[*argn], "-d") == 0)
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists && file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (grub_strcmp (args[*argn], "-e") == 0)
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (grub_strcmp (args[*argn], "-f") == 0)
+ {
+ get_fileinfo (args[*argn + 1]);
+ /* FIXME: check for other types. */
+ update_val (file_exists && ! file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (grub_strcmp (args[*argn], "-s") == 0)
+ {
+ grub_file_t file;
+ file = grub_file_open (args[*argn + 1]);
+ update_val (file && (grub_file_size (file) != 0));
+ if (file)
+ grub_file_close (file);
+ grub_errno = GRUB_ERR_NONE;
+ (*argn) += 2;
+ return ret;
+ }
+
+ /* String tests. */
+ if (grub_strcmp (args[*argn], "-n") == 0)
+ {
+ update_val (args[*argn + 1][0]);
+
+ (*argn) += 2;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-z") == 0)
+ {
+ update_val (! args[*argn + 1][0]);
+ (*argn) += 2;
+ continue;
+ }
+ }
+
+ /* Special modifiers. */
+
+ /* End of expression. return to parent. */
+ if (grub_strcmp (args[*argn], ")") == 0)
+ {
+ (*argn)++;
+ return ret;
+ }
+ /* Recursively invoke if parenthesis. */
+ if (grub_strcmp (args[*argn], "(") == 0)
+ {
+ (*argn)++;
+ update_val (test_parse (args, argn, argc));
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn], "!") == 0)
+ {
+ invert = ! invert;
+ (*argn)++;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-a") == 0)
+ {
+ /* If current value is 0 second value is to be discarded. */
+ discard = ! ret;
+ (*argn)++;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-o") == 0)
+ {
+ /* If current value is 1 second value is to be discarded. */
+ discard = ret;
+ (*argn)++;
+ continue;
+ }
+
+ /* No test found. Interpret if as just a string. */
+ update_val (args[*argn][0]);
+ (*argn)++;
+ }
+ return ret;
+}
+
static grub_err_t
grub_cmd_test (grub_command_t cmd __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;
+ int argn = 0;
+
+ if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0)
+ argc--;
+
+ return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
+ : grub_error (GRUB_ERR_TEST_FAILURE, "false");
}
static grub_command_t cmd_1, cmd_2;
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] Test command
2009-04-16 13:15 ` phcoder
@ 2009-04-25 12:29 ` Vladimir Serbinenko
0 siblings, 0 replies; 8+ messages in thread
From: Vladimir Serbinenko @ 2009-04-25 12:29 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 590 bytes --]
commited
On Thu, Apr 16, 2009 at 3:15 PM, phcoder <phcoder@gmail.com> wrote:
> BTW, I think you can simplify test_parse. For example, you write "if (*argn
>> + 2 < argc ...)" many times, but it should be possible to test this
>> condition only once per loop.
>>
> Optimised. Perhaps compiler optimised this anyway but it made code more
> readable
>
>
>> Regards,
>> Okuji
>>
>>
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> http://lists.gnu.org/mailman/listinfo/grub-devel
>>
>
>
> --
>
> Regards
> Vladimir 'phcoder' Serbinenko
>
[-- Attachment #2: Type: text/html, Size: 1422 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2009-04-25 12:29 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-02-13 11:39 Test command phcoder
2009-02-13 11:39 ` [PATCH] " phcoder
2009-04-10 22:18 ` phcoder
2009-04-11 10:07 ` Yoshinori K. Okuji
2009-04-11 15:11 ` phcoder
2009-04-14 15:55 ` Yoshinori K. Okuji
2009-04-16 13:15 ` phcoder
2009-04-25 12:29 ` Vladimir Serbinenko
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.