From a82bba15a9c033c7d8ebba4269d24f2bdbf34e00 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sat, 21 Dec 2013 00:19:45 +0100 Subject: [PATCH] sysdb: Use the flex scanner generator for reading input. 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 | 2 + src/Makefile.am | 9 ++- src/tools/sysdb/input.c | 125 ++++++++++++++++++++++++++++++++++++++ src/tools/sysdb/input.h | 66 ++++++++++++++++++++ src/tools/sysdb/main.c | 34 +++-------- src/tools/sysdb/scanner.l | 60 ++++++++++++++++++ 6 files changed, 268 insertions(+), 28 deletions(-) create mode 100644 src/tools/sysdb/input.c create mode 100644 src/tools/sysdb/input.h create mode 100644 src/tools/sysdb/scanner.l diff --git a/.gitignore b/.gitignore index e7c950e..728cb09 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index 3f5a007..fea709e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000..3366fd9 --- /dev/null +++ b/src/tools/sysdb/input.c @@ -0,0 +1,125 @@ +/* + * SysDB - src/tools/sysdb/input.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * 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 +#include + +#include + +#if HAVE_EDITLINE_READLINE_H +# include +# if HAVE_EDITLINE_HISTORY_H +# include +# endif +#elif HAVE_READLINE_READLINE_H +# include +# if HAVE_READLINE_HISTORY_H +# include +# endif +#elif HAVE_READLINE_H +# include +# if HAVE_HISTORY_H +# include +# 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 index 0000000..4632b4f --- /dev/null +++ b/src/tools/sysdb/input.h @@ -0,0 +1,66 @@ +/* + * SysDB - src/tools/sysdb/input.h + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * 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 : */ + diff --git a/src/tools/sysdb/main.c b/src/tools/sysdb/main.c index 0639e5f..d895de7 100644 --- a/src/tools/sysdb/main.c +++ b/src/tools/sysdb/main.c @@ -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 index 0000000..43b248d --- /dev/null +++ b/src/tools/sysdb/scanner.l @@ -0,0 +1,60 @@ +/* + * SysDB - src/tools/sysdb/scanner.l + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * 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 : */ + -- 2.30.2