Code

sysdb: Use the flex scanner generator for reading input.
authorSebastian Harl <sh@tokkee.org>
Fri, 20 Dec 2013 23:19:45 +0000 (00:19 +0100)
committerSebastian Harl <sh@tokkee.org>
Fri, 20 Dec 2013 23:19:45 +0000 (00:19 +0100)
The idea is to implement a minimalistic parser which understands all valid
input and which is used to determine if an input line is part of an existing
command or a command on its own. This information will then be used to update
the prompt (and possibly to determine other information as well).

The scanner's YY_INPUT "method" is overwritten in order to use readline and
custom buffering for user input.

.gitignore
src/Makefile.am
src/tools/sysdb/input.c [new file with mode: 0644]
src/tools/sysdb/input.h [new file with mode: 0644]
src/tools/sysdb/main.c
src/tools/sysdb/scanner.l [new file with mode: 0644]

index e7c950e8e2872c07894260f0099af40c0359abc9..728cb094f0920f0c155b12dddb53a6aefbc45e1b 100644 (file)
@@ -32,10 +32,12 @@ ltmain.sh
 src/liboconfig/parser.c
 src/liboconfig/parser.h
 src/liboconfig/scanner.c
+src/tools/sysdb/scanner.c
 src/sysdb
 src/sysdbd
 .dirstamp
 .libs
+*.a
 *.la
 *.lo
 *.o
index 3f5a0071081afd13a71189fb87b6900d20bf9e5e..fea709ecbdf43d4565a1c4b0c8daef2502d85eed 100644 (file)
@@ -83,10 +83,15 @@ bin_PROGRAMS = sysdbd
 if BUILD_CLIENT
 bin_PROGRAMS += sysdb
 
-sysdb_SOURCES = tools/sysdb/main.c include/client/sysdb.h
+# don't use strict CFLAGS for flex code
+noinst_LIBRARIES = sysdb_scanner.a
+sysdb_scanner_a_SOURCES = tools/sysdb/scanner.l
+sysdb_scanner_a_CFLAGS = -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\""
+sysdb_SOURCES = tools/sysdb/main.c include/client/sysdb.h \
+               tools/sysdb/input.c tools/sysdb/input.h
 sysdb_CFLAGS = -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" \
                $(AM_CFLAGS) @READLINE_CFLAGS@
-sysdb_LDADD = libsysdbclient.la @READLINE_LIBS@
+sysdb_LDADD = sysdb_scanner.a libsysdbclient.la @READLINE_LIBS@
 endif
 
 sysdbd_SOURCES = tools/sysdbd/main.c include/sysdb.h \
diff --git a/src/tools/sysdb/input.c b/src/tools/sysdb/input.c
new file mode 100644 (file)
index 0000000..3366fd9
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * SysDB - src/tools/sysdb/input.c
+ * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#      include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "tools/sysdb/input.h"
+
+#include "utils/strbuf.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#if HAVE_EDITLINE_READLINE_H
+#      include <editline/readline.h>
+#      if HAVE_EDITLINE_HISTORY_H
+#              include <editline/history.h>
+#      endif
+#elif HAVE_READLINE_READLINE_H
+#      include <readline/readline.h>
+#      if HAVE_READLINE_HISTORY_H
+#              include <readline/history.h>
+#      endif
+#elif HAVE_READLINE_H
+#      include <readline.h>
+#      if HAVE_HISTORY_H
+#              include <history.h>
+#      endif
+#endif /* READLINEs */
+
+/*
+ * private helper functions
+ */
+
+static size_t
+input_readline(sdb_strbuf_t *buf)
+{
+       const char *prompt = "sysdb=> ";
+       char *line;
+
+       size_t len;
+
+       if (sdb_strbuf_len(buf))
+               prompt = "sysdb-> ";
+
+       line = readline(prompt);
+
+       if (! line)
+               return 0;
+
+       len = strlen(line);
+
+       sdb_strbuf_append(buf, line);
+       free(line);
+       return len;
+} /* input_readline */
+
+/*
+ * API
+ */
+
+ssize_t
+sdb_input_readline(sdb_input_t *input, char *buf,
+               int *n_chars, size_t max_chars)
+{
+       const char *query;
+       size_t buflen, len;
+
+       buflen = sdb_strbuf_len(input->buf);
+       len = buflen - input->tokenizer_pos;
+
+       if (! len) {
+               size_t n = input_readline(input->buf);
+               if (! n) {
+                       *n_chars = 0; /* YY_NULL */
+                       return 0;
+               }
+               buflen += n;
+               len += n;
+       }
+
+       query = sdb_strbuf_string(input->buf);
+
+       len = (len < max_chars) ? len : max_chars;
+       strncpy(buf, sdb_strbuf_string(input->buf) + input->tokenizer_pos, len);
+       input->tokenizer_pos += len;
+       *n_chars = (int)len;
+
+       /* XXX */
+       if (! strchr(query, (int)';'))
+               return (ssize_t)len;
+       sdb_strbuf_clear(input->buf);
+       input->tokenizer_pos = 0;
+       return (ssize_t)len;
+} /* sdb_input_readline */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/tools/sysdb/input.h b/src/tools/sysdb/input.h
new file mode 100644 (file)
index 0000000..4632b4f
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * SysDB - src/tools/sysdb/input.h
+ * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "utils/strbuf.h"
+
+#ifndef SYSDB_INPUT_H
+#define SYSDB_INPUT_H 1
+
+typedef struct {
+       sdb_strbuf_t *buf;
+
+       size_t tokenizer_pos;
+} sdb_input_t;
+
+#define SDB_INPUT_INIT { NULL, 0 }
+
+/*
+ * sdb_input_readline:
+ * This function is supposed to be used with a flex scanner's YY_INPUT. It
+ * reads input from the user using reading() and places available input in the
+ * specified buffer, returning the number of bytes in 'n_chars' (no more than
+ * 'max_chars'.
+ *
+ * Returns:
+ *  - The number of newly read bytes.
+ *  - A negative value in case of an error.
+ */
+ssize_t
+sdb_input_readline(sdb_input_t *input, char *buf,
+               int *n_chars, size_t max_chars);
+
+/*
+ * scanner
+ */
+
+void
+sdb_input_set(sdb_input_t *new_input);
+
+#endif /* SYSDB_INPUT_H */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
index 0639e5f74829042a4e3a8532b97f6ee74d853236..d895de7184cb9bdb7cea1bf8b98db2939151e272 100644 (file)
@@ -29,6 +29,8 @@
 #      include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#include "tools/sysdb/input.h"
+
 #include "client/sysdb.h"
 #include "client/sock.h"
 #include "utils/error.h"
@@ -76,6 +78,8 @@
 #      define DEFAULT_SOCKET "unix:"LOCALSTATEDIR"/run/sysdbd.sock"
 #endif
 
+extern int yylex(void);
+
 static void
 exit_usage(char *name, int status)
 {
@@ -171,7 +175,7 @@ main(int argc, char **argv)
        const char *homedir;
        char hist_file[1024] = "";
 
-       sdb_strbuf_t *buf;
+       sdb_input_t input = SDB_INPUT_INIT;
 
        while (42) {
                int opt = getopt(argc, argv, "H:U:hV");
@@ -238,31 +242,9 @@ main(int argc, char **argv)
                }
        }
 
-       buf = sdb_strbuf_create(1024);
-
-       while (42) {
-               const char *prompt = "sysdb=> ";
-               const char *query;
-               char *input;
-
-               if (sdb_strbuf_len(buf))
-                       prompt = "sysdb-> ";
-
-               input = readline(prompt);
-
-               if (! input)
-                       break;
-
-               sdb_strbuf_append(buf, input);
-               free(input);
-
-               query = sdb_strbuf_string(buf);
-               if (! strchr(query, (int)';'))
-                       continue;
-
-               /* XXX */
-               sdb_strbuf_clear(buf);
-       }
+       input.buf = sdb_strbuf_create(2048);
+       sdb_input_set(&input);
+       yylex();
 
        if (hist_file[0] != '\0') {
                errno = 0;
diff --git a/src/tools/sysdb/scanner.l b/src/tools/sysdb/scanner.l
new file mode 100644 (file)
index 0000000..43b248d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SysDB - src/tools/sysdb/scanner.l
+ * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include "tools/sysdb/input.h"
+
+#ifdef YY_INPUT
+#      undef YY_INPUT
+#endif
+#define YY_INPUT(buf, result, max_size) \
+       do { \
+               sdb_input_readline(sdb_input, (buf), &(result), (max_size)); \
+       } while (0)
+
+static sdb_input_t *sdb_input;
+%}
+
+%option interactive
+%option yylineno
+%option noyywrap
+%option verbose
+
+%%
+
+. { /* do nothing */ }
+
+%%
+
+void
+sdb_input_set(sdb_input_t *new_input)
+{
+       sdb_input = new_input;
+} /* sdb_input_set */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+