Add rudimentary interactive support.
authorAndre Noll <maan@systemlinux.org>
Fri, 20 Jun 2008 08:40:13 +0000 (10:40 +0200)
committerAndre Noll <maan@systemlinux.org>
Fri, 20 Jun 2008 08:40:13 +0000 (10:40 +0200)
This needs much more work..

.gitignore
Makefile
adu.c
adu.ggo
adu.h
interactive.c [new file with mode: 0644]
select.ggo [new file with mode: 0644]

index 743f60e..617d85d 100644 (file)
@@ -1,7 +1,7 @@
 *.[oa]
 foo*
 bar*
-cmdline.[ch]
+*cmdline.[ch]
 GPATH
 GRTAGS
 GSYMS
index 5e425da..2429a67 100644 (file)
--- 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 (file)
--- 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 (file)
--- 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 (file)
--- 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 (file)
index 0000000..686a89f
--- /dev/null
@@ -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 (file)
index 0000000..10c760e
--- /dev/null
@@ -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.
+"