summaryrefslogtreecommitdiff
path: root/lib/parser.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2003-10-01 10:58:08 -0700
committerLinus Torvalds <torvalds@home.osdl.org>2003-10-01 10:58:08 -0700
commit5221f633a04ed0edf7edc10c07d0e5934abc038c (patch)
tree3d1f11531410e3617070610ed5b78e0b3c44604d /lib/parser.c
parentb2dd867477c080de713e366809b71fd500a6b300 (diff)
[PATCH] table-driven filesystems option parsing
From: "Randy.Dunlap" <rddunlap@osdl.org>, Will Dyson <will_dyson@pobox.com>, me Add generic filesystem options parser (infrastructure) and use it to parse mount options in several filesystems (adfs, affs, autofs, autofs4, ext2, ext3, fat, hfs, hpfs, isofs, jfs, procfs, udf, and ufs). It saves between 128 and 512 bytes per filesystem.
Diffstat (limited to 'lib/parser.c')
-rw-r--r--lib/parser.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/lib/parser.c b/lib/parser.c
new file mode 100644
index 000000000000..858061397fe2
--- /dev/null
+++ b/lib/parser.c
@@ -0,0 +1,138 @@
+/*
+ * lib/parser.c - simple parser for mount, etc. options.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/parser.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+static int match_one(char *s, char *p, substring_t args[])
+{
+ char *meta;
+ int argc = 0;
+
+ if (!p)
+ return 1;
+
+ while(1) {
+ int len = -1;
+ meta = strchr(p, '%');
+ if (!meta)
+ return strcmp(p, s) == 0;
+
+ if (strncmp(p, s, meta-p))
+ return 0;
+
+ s += meta - p;
+ p = meta + 1;
+
+ if (isdigit(*p))
+ len = simple_strtoul(p, &p, 10);
+ else if (*p == '%') {
+ if (*s++ != '%')
+ return 0;
+ continue;
+ }
+
+ if (argc >= MAX_OPT_ARGS)
+ return 0;
+
+ args[argc].from = s;
+ switch (*p++) {
+ case 's':
+ if (len == -1 || len > strlen(s))
+ len = strlen(s);
+ args[argc].to = s + len;
+ break;
+ case 'd':
+ simple_strtol(s, &args[argc].to, 0);
+ goto num;
+ case 'u':
+ simple_strtoul(s, &args[argc].to, 0);
+ goto num;
+ case 'o':
+ simple_strtoul(s, &args[argc].to, 8);
+ goto num;
+ case 'x':
+ simple_strtoul(s, &args[argc].to, 16);
+ num:
+ if (args[argc].to == args[argc].from)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ s = args[argc].to;
+ argc++;
+ }
+}
+
+int match_token(char *s, match_table_t table, substring_t args[])
+{
+ struct match_token *p;
+
+ for (p = table; !match_one(s, p->pattern, args) ; p++)
+ ;
+
+ return p->token;
+}
+
+static int match_number(substring_t *s, int *result, int base)
+{
+ char *endp;
+ char *buf;
+ int ret;
+
+ buf = kmalloc(s->to - s->from + 1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ memcpy(buf, s->from, s->to - s->from);
+ buf[s->to - s->from] = '\0';
+ *result = simple_strtol(buf, &endp, base);
+ ret = 0;
+ if (endp == buf)
+ ret = -EINVAL;
+ kfree(buf);
+ return ret;
+}
+
+int match_int(substring_t *s, int *result)
+{
+ return match_number(s, result, 0);
+}
+
+int match_octal(substring_t *s, int *result)
+{
+ return match_number(s, result, 8);
+}
+
+int match_hex(substring_t *s, int *result)
+{
+ return match_number(s, result, 16);
+}
+
+void match_strcpy(char *to, substring_t *s)
+{
+ memcpy(to, s->from, s->to - s->from);
+ to[s->to - s->from] = '\0';
+}
+
+char *match_strdup(substring_t *s)
+{
+ char *p = kmalloc(s->to - s->from + 1, GFP_KERNEL);
+ if (p)
+ match_strcpy(p, s);
+ return p;
+}
+
+EXPORT_SYMBOL(match_token);
+EXPORT_SYMBOL(match_int);
+EXPORT_SYMBOL(match_octal);
+EXPORT_SYMBOL(match_hex);
+EXPORT_SYMBOL(match_strcpy);
+EXPORT_SYMBOL(match_strdup);