From b01ff57775258c8df4c486b0962fc67cfdfef439 Mon Sep 17 00:00:00 2001
From: Andre Noll <maan@systemlinux.org>
Date: Fri, 20 Jun 2008 10:40:13 +0200
Subject: [PATCH] Add rudimentary interactive support.

This needs much more work..
---
 .gitignore    |   2 +-
 Makefile      |  17 +++++++-
 adu.c         |   4 +-
 adu.ggo       |  10 ++++-
 adu.h         |   1 +
 interactive.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++
 select.ggo    |  72 +++++++++++++++++++++++++++++++++
 7 files changed, 208 insertions(+), 5 deletions(-)
 create mode 100644 interactive.c
 create mode 100644 select.ggo

diff --git a/.gitignore b/.gitignore
index 743f60e..617d85d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
 *.[oa]
 foo*
 bar*
-cmdline.[ch]
+*cmdline.[ch]
 GPATH
 GRTAGS
 GSYMS
diff --git a/Makefile b/Makefile
index 5e425da..2429a67 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
-objects := adu.o string.o cmdline.o fd.o select.o create.o
+objects := adu.o string.o cmdline.o fd.o select.o create.o interactive.o select.cmdline.o
 all: adu
+version := 0.0.2
 
 DEBUG_CPPFLAGS += -Wno-sign-compare -g -Wunused -Wundef -W
 DEBUG_CPPFLAGS += -Wredundant-decls
@@ -14,6 +15,7 @@ CPPFLAGS += -Wunused-macros
 CPPFLAGS += -Wbad-function-cast
 CPPFLAGS += -D_LARGEFILE64_SOURCE
 CPPFLAGS += $(shell getconf LFS64_CFLAGS)
+CPPFLAGS += -DVERSION='"$(version)"'
 
 LDFLAGS += -D_LARGEFILE64_SOURCE
 LDFLAGS += $(shell getconf LFS64_LDFLAGS)
@@ -38,5 +40,18 @@ cmdline.c cmdline.h: adu.ggo
 %.o: %.c Makefile
 	$(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) $<
 
+select.cmdline.c select.cmdline.h: select.ggo
+	gengetopt --string-parser \
+		--set-package=select \
+		--no-handle-help \
+		--no-handle-error \
+		--no-handle-version \
+		--arg-struct-name=select_args_info \
+		--file-name=$(subst .ggo,,$<).cmdline \
+		--func-name $(subst .ggo,,$<)_cmdline_parser < $<
+
+select.cmdline.o: select.cmdline.c select.cmdline.h
+	$(CC) -c $(CPPFLAGS) $<
+
 clean:
 	rm -f *.o adu
diff --git a/adu.c b/adu.c
index db7a564..42d1b19 100644
--- a/adu.c
+++ b/adu.c
@@ -550,8 +550,10 @@ int main(int argc, char **argv)
 	ret = -E_SYNTAX;
 	if (conf.select_given)
 		ret = com_select();
-	else
+	else if (conf.create_given)
 		ret = com_create();
+	else
+		ret = com_interactive();
 	if (ret < 0)
 		goto out;
 out:
diff --git a/adu.ggo b/adu.ggo
index a46de25..38986af 100644
--- a/adu.ggo
+++ b/adu.ggo
@@ -3,7 +3,6 @@
 # Licensed under the GPL v2. For licencing details see COPYING.
 
 package "adu"
-version "0.0.2"
 purpose "advanced disk usage
 
 adu creates a database containing disk usage statistics of a given
@@ -107,6 +106,14 @@ details="
 	that directory.
 "
 
+groupoption "interactive" I
+#~~~~~~~~~~~~~~~~~~~~~
+"activate interactive mode"
+group="mode"
+details="
+	In this mode, adu reads commands from stdin.
+"
+
 groupoption "select" S
 #~~~~~~~~~~~~~~~~~~~~~
 "query a database previously created with --create"
@@ -158,7 +165,6 @@ details="
 	users. Decreasing the value causes adu to use slightly less memory.
 "
 
-
 ##############################
 section "Options for --select"
 ##############################
diff --git a/adu.h b/adu.h
index debada6..f8ef9c2 100644
--- a/adu.h
+++ b/adu.h
@@ -195,3 +195,4 @@ int com_select(void);
 
 /* create.h */
 int com_create(void);
+int com_interactive(void);
diff --git a/interactive.c b/interactive.c
new file mode 100644
index 0000000..686a89f
--- /dev/null
+++ b/interactive.c
@@ -0,0 +1,107 @@
+#include "adu.h"
+#include "string.h"
+#include "error.h"
+#include "cmdline.h"
+#include "select.cmdline.h"
+
+struct select_args_info select_conf;
+
+struct interactive_command {
+	const char *name;
+	int (*handler)(char *);
+};
+
+#define INTERACTIVE_COMMANDS \
+	INTERACTIVE_COMMAND(dump) \
+	INTERACTIVE_COMMAND(set) \
+	INTERACTIVE_COMMAND(def) \
+
+#define INTERACTIVE_COMMAND(name) \
+	static int icom_ ## name (char *line);
+
+INTERACTIVE_COMMANDS
+
+#undef INTERACTIVE_COMMAND
+
+#define INTERACTIVE_COMMAND(_name) \
+	{ \
+	.name = #_name, \
+	.handler = icom_ ## _name \
+	},
+
+struct interactive_command icmds[] = {
+	INTERACTIVE_COMMANDS
+	{.name  = NULL}
+};
+
+static int read_input_line(char *line, size_t size)
+{
+	return fgets(line, size, stdin)? 1 : -1;
+}
+
+static int icom_def(__a_unused char *line)
+{
+	select_cmdline_parser_init(&select_conf);
+	return 1;
+}
+
+static int icom_set(char *line)
+{
+	struct select_cmdline_parser_params params = {
+		.override = 1,
+		.initialize = 0,
+		.check_required = 1,
+		.check_ambiguity = 0,
+		.print_errors = 1
+	};
+	return select_cmdline_parser_string_ext(line, &select_conf, "select",
+		&params)?
+		-E_SYNTAX : 1;
+}
+
+static int icom_dump(__a_unused char *line)
+{
+	ERROR_LOG("dump: %s\n", select_conf.format_arg);
+	select_cmdline_parser_dump(stdout, &select_conf);
+	return 1;
+}
+
+static int exec_interactive_command(char *line)
+{
+	const char const *delim = "\t\n ";
+	int i;
+	char *cmd = adu_strdup(line + strspn(line, delim));
+	char *p = cmd + strcspn(cmd, delim);
+	int ret = -E_SYNTAX;
+
+	*p = '\0';
+	p++;
+	for (i = 0; icmds[i].name; i++) {
+		ERROR_LOG("name: %s, cmd: %s.\n", icmds[i].name, cmd);
+		if (strcmp(icmds[i].name, cmd))
+			continue;
+		ERROR_LOG("exec cmd: %s, args: %s\n", cmd, p);
+		ret = icmds[i].handler(p);
+		break;
+	}
+	free(cmd);
+	return ret;
+}
+
+int com_interactive(void)
+{
+	char line[255];
+	int ret = 1;
+
+	while (read_input_line(line, sizeof(line)) >= 0) {
+		size_t len = strlen(line);
+		if (!len)
+			continue;
+		if (line[len - 1] == '\n')
+			line[len - 1] = '\0';
+		ret = exec_interactive_command(line);
+		if (ret < 0)
+			printf("%s\n", adu_strerror(-ret));
+	}
+	return ret;
+}
diff --git a/select.ggo b/select.ggo
new file mode 100644
index 0000000..10c760e
--- /dev/null
+++ b/select.ggo
@@ -0,0 +1,72 @@
+
+option "uid" u
+#~~~~~~~~~~~~~
+"user id(s) to take into account"
+string typestr="uid_spec"
+optional
+multiple
+details="
+	An uid specifier may be a single number, or a range of uids.
+	Example:
+
+	--uid 42    # only consider uid 42
+	--uid 42-   # only consider uids greater or equal than 42
+	--uid 23-42 # only consider uids between 23 and 42, inclusively.
+
+	This option may be given multiple times. An uid is taken into
+	account if it satisfies at least one --uid option.
+"
+
+option "limit" L
+#~~~~~~~~~~~~~~~
+"Limit output"
+int  typestr="num"
+default="-1"
+optional
+details="
+	Only print num lines of output. If negative (the default),
+	print all lines.
+"
+
+option "no-headers" -
+#~~~~~~~~~~~~~~~~~~~~
+"supress descriptions for listings/tables"
+flag off
+details="
+	This is mostly useful to feed the output of adu to scripts.
+"
+
+option "sort" s
+#~~~~~~~~~~~~~~~
+"how to sort the output"
+enum typestr="<key>"
+values="sizes","files","unsorted"
+default="sizes"
+optional
+details="
+	Sort by file size, file count or unsorted.
+"
+
+option "format" f
+#~~~~~~~~~~~~~~~~~
+"how to format the output"
+string typestr="<format>"
+optional
+details="
+	%(basedir) 	-- the path given to --base-dir during create
+	%(dir)		-- the name of the directory
+	%(dir_size)	-- the size of the sum of all regular files in this directory
+	%(num_files)	-- the number of regular files in this directory
+	%%		-- interpolates to %
+	%xx		-- interpolates to the character with hex code xx
+"
+
+option "output" o
+#~~~~~~~~~~~~~~~~
+"file to write output to"
+string typestr="<path>"
+optional
+default="-"
+details="
+	If empty, or not given, use stdout.
+"
-- 
2.39.5