Convert para_client to lopsub.
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 10 Apr 2016 20:29:29 +0000 (22:29 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 26 Mar 2017 09:02:28 +0000 (11:02 +0200)
This replaces the gengetopt command line parser for para_client by a
lopsub suite and links para_client against the lopsub library. The ggo
file for para_client was the last user of m4/gengetopt/complete.m4,
so this file can be removed.

The tricky part is create_merged_lpr(), which replaces
make_client_argv(). It is called from the i9e line handler and from
the completers. The new function merges the original parse result
with the arguments given at the command line to produce the parse
result stored in the client task structure.

The completers no longer duplicate the possible options each server
subcommand because the header file generated by lopsubgen exposes
an array of string literals which is suitable as the opts argument
of i9e_complete_option().

Makefile.real
audiod.c
client.c
client.h
client_common.c
configure.ac
error.h
m4/gengetopt/client.m4 [deleted file]
m4/gengetopt/complete.m4 [deleted file]
m4/lls/client.suite.m4 [new file with mode: 0644]
m4/lls/include/config-file.m4 [new file with mode: 0644]

index 2d381ad328a2cc777e9e49b8c7e03f1f05760c30..ee60363ec79235788a3bb16846e57e1febafc433 100644 (file)
@@ -43,14 +43,15 @@ all_objs := $(sort $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \
        $(audiod_objs) $(audioc_objs) $(fade_objs) $(server_objs) \
        $(write_objs) $(afh_objs) $(play_objs))
 deps := $(addprefix $(dep_dir)/, $(filter-out %.cmdline.d, $(all_objs:.o=.d)))
        $(audiod_objs) $(audioc_objs) $(fade_objs) $(server_objs) \
        $(write_objs) $(afh_objs) $(play_objs))
 deps := $(addprefix $(dep_dir)/, $(filter-out %.cmdline.d, $(all_objs:.o=.d)))
-converted_executables := audioc
+converted_executables := audioc client
 unconverted_executables := $(filter-out $(converted_executables), $(executables))
 
 audioc_objs += audioc.lsg.o
 unconverted_executables := $(filter-out $(converted_executables), $(executables))
 
 audioc_objs += audioc.lsg.o
-audiod_objs += audiod_cmd.lsg.o recv_cmd.lsg.o
+audiod_objs += audiod_cmd.lsg.o recv_cmd.lsg.o client.lsg.o
 server_objs += server_cmd.lsg.o
 play_objs += play_cmd.lsg.o recv_cmd.lsg.o
 recv_objs += recv_cmd.lsg.o
 server_objs += server_cmd.lsg.o
 play_objs += play_cmd.lsg.o recv_cmd.lsg.o
 recv_objs += recv_cmd.lsg.o
+client_objs += client.lsg.o
 
 m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(unconverted_executables)))
 m4_lls_deps := audiod_cmd server_cmd play_cmd recv_cmd $(converted_executables)
 
 m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(unconverted_executables)))
 m4_lls_deps := audiod_cmd server_cmd play_cmd recv_cmd $(converted_executables)
@@ -303,6 +304,7 @@ para_fade \
 
 para_audioc \
 para_audiod \
 
 para_audioc \
 para_audiod \
+para_client \
 para_play \
 para_recv \
 para_server \
 para_play \
 para_recv \
 para_server \
index 181d6ab12e6370a4e0df6b661ce20132d6036e78..56ab0c9a0c86608a8b78909f40794b62ac99bcbf 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -18,6 +18,7 @@
 #include <lopsub.h>
 
 #include "recv_cmd.lsg.h"
 #include <lopsub.h>
 
 #include "recv_cmd.lsg.h"
+#include "client.lsg.h"
 #include "para.h"
 #include "error.h"
 #include "crypt.h"
 #include "para.h"
 #include "error.h"
 #include "crypt.h"
@@ -29,7 +30,6 @@
 #include "recv.h"
 #include "filter.h"
 #include "grab_client.h"
 #include "recv.h"
 #include "filter.h"
 #include "grab_client.h"
-#include "client.cmdline.h"
 #include "client.h"
 #include "audiod.h"
 #include "net.h"
 #include "client.h"
 #include "audiod.h"
 #include "net.h"
index 219cf2d8c1078a0e04e0ce00dd89420dd44264f4..68d8a7efed285891653adfd5d68faaae06d41c1a 100644 (file)
--- a/client.c
+++ b/client.c
@@ -8,12 +8,13 @@
 
 #include <regex.h>
 #include <signal.h>
 
 #include <regex.h>
 #include <signal.h>
+#include <lopsub.h>
 
 
+#include "client.lsg.h"
 #include "para.h"
 #include "list.h"
 #include "sched.h"
 #include "crypt.h"
 #include "para.h"
 #include "list.h"
 #include "sched.h"
 #include "crypt.h"
-#include "client.cmdline.h"
 #include "string.h"
 #include "stdin.h"
 #include "stdout.h"
 #include "string.h"
 #include "stdin.h"
 #include "stdout.h"
@@ -77,17 +78,52 @@ out:
        return 0;
 }
 
        return 0;
 }
 
-static int make_client_argv(const char *line)
+/* Called from the line handler and the completers. This overwrites ct->lpr. */
+static int create_merged_lpr(const char *line)
 {
 {
-       int ret;
+       const struct lls_command *cmd = CLIENT_CMD_PTR;
+       int argc, ret;
+       char *cmdline, **argv, *errctx;
+       struct lls_parse_result *argv_lpr;
+       static struct lls_parse_result *orig_lpr;
 
 
-       free_argv(ct->conf.inputs);
-       ret = create_argv(line, " ", &ct->conf.inputs);
-       if (ret >= 0)
-               ct->conf.inputs_num = ret;
+       if (!orig_lpr)
+               orig_lpr = ct->lpr;
+       ct->lpr = NULL;
+       cmdline = make_message("-- %s", line);
+       ret = create_shifted_argv(cmdline, " ", &argv);
+       free(cmdline);
+       if (ret < 0)
+               return ret;
+       argc = ret;
+       if (argc == 2) { /* no words (only blanks in line) */
+               free_argv(argv);
+               return 0;
+       }
+       argv[0] = para_strdup("--");
+       /*
+        * The original lpr for the interactive session has no non-option
+        * arguments. We create a fresh lpr from the words in "line" and merge
+        * it with the orignal lpr.
+        */
+       ret = lls(lls_parse(argc, argv, cmd, &argv_lpr, &errctx));
+       free_argv(argv);
+       if (ret < 0)
+               goto fail;
+       ret = lls(lls_merge(orig_lpr, argv_lpr, cmd, &ct->lpr, &errctx));
+       lls_free_parse_result(argv_lpr, cmd);
+       if (ret < 0)
+               goto fail;
+       return 1;
+fail:
+       if (errctx)
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+       free(errctx);
+       assert(ret < 0);
        return ret;
 }
 
        return ret;
 }
 
+/* called from completers */
 static int execute_client_command(const char *cmd, char **result)
 {
        int ret;
 static int execute_client_command(const char *cmd, char **result)
 {
        int ret;
@@ -96,9 +132,11 @@ static int execute_client_command(const char *cmd, char **result)
                .result_buf = para_strdup(""),
                .result_size = 1,
        };
                .result_buf = para_strdup(""),
                .result_size = 1,
        };
+       struct lls_parse_result *old_lpr = ct->lpr;
+
        *result = NULL;
        *result = NULL;
-       ret = make_client_argv(cmd);
-       if (ret < 0)
+       ret = create_merged_lpr(cmd);
+       if (ret <= 0)
                goto out;
        exec_task.btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = "exec_collect"));
                goto out;
        exec_task.btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = "exec_collect"));
@@ -113,6 +151,8 @@ static int execute_client_command(const char *cmd, char **result)
                goto out;
        schedule(&command_sched);
        sched_shutdown(&command_sched);
                goto out;
        schedule(&command_sched);
        sched_shutdown(&command_sched);
+       lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR);
+       ct->lpr = old_lpr;
        *result = exec_task.result_buf;
        btr_remove_node(&exec_task.btrn);
        ret = 1;
        *result = exec_task.result_buf;
        btr_remove_node(&exec_task.btrn);
        ret = 1;
@@ -173,7 +213,7 @@ static void complete_lsblob(const char *blob_type,
                struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
                struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {"-i", "-l", "-r", NULL};
+       char *opts[] = {LSG_SERVER_CMD_LSIMG_OPTS, NULL};
 
        if (ci->word[0] == '-')
                return i9e_complete_option(opts, ci, cr);
 
        if (ci->word[0] == '-')
                return i9e_complete_option(opts, ci, cr);
@@ -217,18 +257,17 @@ static void help_completer(struct i9e_completion_info *ci,
        result->matches = i9e_complete_commands(ci->word, completers);
 }
 
        result->matches = i9e_complete_commands(ci->word, completers);
 }
 
-static void version_completer(struct i9e_completion_info *ci,
+static void stat_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {"-v", NULL};
+       char *opts[] = {LSG_SERVER_CMD_STAT_OPTS, NULL};
        i9e_complete_option(opts, ci, cr);
 }
 
        i9e_complete_option(opts, ci, cr);
 }
 
-static void stat_completer(struct i9e_completion_info *ci,
+static void version_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {"-n=", "-p", NULL};
-       //PARA_CRIT_LOG("word: %s\n", ci->word);
+       char *opts[] = {LSG_SERVER_CMD_VERSION_OPTS, NULL};
        i9e_complete_option(opts, ci, cr);
 }
 
        i9e_complete_option(opts, ci, cr);
 }
 
@@ -265,7 +304,7 @@ static void sender_completer(struct i9e_completion_info *ci,
 static void add_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
 static void add_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {"-a", "-l", "-f", "-v", "--", NULL};
+       char *opts[] = {LSG_SERVER_CMD_ADD_OPTS, NULL};
 
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
 
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
@@ -275,11 +314,7 @@ static void add_completer(struct i9e_completion_info *ci,
 static void ls_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
 static void ls_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {
-               "--", "-l", "-l=s", "-l=l", "-l=v", "-l=p", "-l=m", "-l=c",
-               "-p", "-a", "-r", "-d", "-s=p", "-s=l", "-s=s", "-s=n", "-s=f",
-               "-s=c", "-s=i", "-s=y", "-s=b", "-s=d", "-s=a", "-F", "-b", NULL
-       };
+       char *opts[] = {LSG_SERVER_CMD_LS_OPTS, NULL};
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
        cr->filename_completion_desired = true;
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
        cr->filename_completion_desired = true;
@@ -322,7 +357,7 @@ out:
 static void lsatt_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
 static void lsatt_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {"-i", "-l", "-r", NULL};
+       char *opts[] = {LSG_SERVER_CMD_LSATT_OPTS, NULL};
        i9e_complete_option(opts, ci, cr);
 }
 
        i9e_complete_option(opts, ci, cr);
 }
 
@@ -341,14 +376,14 @@ static void rmatt_completer(struct i9e_completion_info *ci,
 static void check_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
 static void check_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {"-a", "-m", "-p", NULL};
+       char *opts[] = {LSG_SERVER_CMD_CHECK_OPTS, NULL};
        i9e_complete_option(opts, ci, cr);
 }
 
 static void rm_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
        i9e_complete_option(opts, ci, cr);
 }
 
 static void rm_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {"-v", "-f", "-p", NULL};
+       char *opts[] = {LSG_SERVER_CMD_RM_OPTS, NULL};
 
        if (ci->word[0] == '-') {
                i9e_complete_option(opts, ci, cr);
 
        if (ci->word[0] == '-') {
                i9e_complete_option(opts, ci, cr);
@@ -360,7 +395,7 @@ static void rm_completer(struct i9e_completion_info *ci,
 static void touch_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
 static void touch_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {"-n=", "-l=", "-y=", "-i=", "-a=", "-v", "-p", NULL};
+       char *opts[] = {LSG_SERVER_CMD_TOUCH_OPTS, NULL};
 
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
 
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
@@ -370,7 +405,7 @@ static void touch_completer(struct i9e_completion_info *ci,
 static void cpsi_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
 static void cpsi_completer(struct i9e_completion_info *ci,
                struct i9e_completion_result *cr)
 {
-       char *opts[] = {"-a", "-y", "-i", "-l", "-n", "-v", NULL};
+       char *opts[] = {LSG_SERVER_CMD_CPSI_OPTS, NULL};
 
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
 
        if (ci->word[0] == '-')
                i9e_complete_option(opts, ci, cr);
@@ -446,9 +481,13 @@ DEFINE_BLOB_COMPLETER(mv, pl)
 static int client_i9e_line_handler(char *line)
 {
        int ret;
 static int client_i9e_line_handler(char *line)
 {
        int ret;
+       static bool first = true;
 
 
-       PARA_DEBUG_LOG("line: %s\n", line);
-       ret = make_client_argv(line);
+       if (first)
+               first = false;
+       else
+               lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR);
+       ret = create_merged_lpr(line);
        if (ret <= 0)
                return ret;
        ret = client_connect(ct, &sched, NULL, NULL);
        if (ret <= 0)
                return ret;
        ret = client_connect(ct, &sched, NULL, NULL);
@@ -462,7 +501,7 @@ I9E_DUMMY_COMPLETER(SUPERCOMMAND_UNAVAILABLE);
 static struct i9e_completer completers[] = {
 #define LSG_SERVER_CMD_CMD(_name) {.name = #_name, \
        .completer = _name ## _completer}
 static struct i9e_completer completers[] = {
 #define LSG_SERVER_CMD_CMD(_name) {.name = #_name, \
        .completer = _name ## _completer}
-       LSG_SERVER_CMD_COMMANDS
+       LSG_SERVER_CMD_SUBCOMMANDS
 #undef LSG_SERVER_CMD_CMD
        {.name = NULL}
 };
 #undef LSG_SERVER_CMD_CMD
        {.name = NULL}
 };
@@ -470,7 +509,6 @@ static struct i9e_completer completers[] = {
 __noreturn static void interactive_session(void)
 {
        int ret;
 __noreturn static void interactive_session(void)
 {
        int ret;
-       char *history_file;
        struct sigaction act;
        struct i9e_client_info ici = {
                .fds = {0, 1, 2},
        struct sigaction act;
        struct i9e_client_info ici = {
                .fds = {0, 1, 2},
@@ -481,16 +519,15 @@ __noreturn static void interactive_session(void)
        };
 
        PARA_NOTICE_LOG("\n%s\n", version_text("client"));
        };
 
        PARA_NOTICE_LOG("\n%s\n", version_text("client"));
-       if (ct->conf.history_file_given)
-               history_file = para_strdup(ct->conf.history_file_arg);
+       if (CLIENT_OPT_GIVEN(HISTORY_FILE, ct->lpr))
+               ici.history_file = para_strdup(CLIENT_OPT_STRING_VAL(
+                       HISTORY_FILE, ct->lpr));
        else {
                char *home = para_homedir();
        else {
                char *home = para_homedir();
-               history_file = make_message("%s/.paraslash/client.history",
+               ici.history_file = make_message("%s/.paraslash/client.history",
                        home);
                free(home);
        }
                        home);
                free(home);
        }
-       ici.history_file = history_file;
-
        act.sa_handler = i9e_signal_dispatch;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        act.sa_handler = i9e_signal_dispatch;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
@@ -514,7 +551,9 @@ out:
 
 __noreturn static void print_completions(void)
 {
 
 __noreturn static void print_completions(void)
 {
-       int ret = i9e_print_completions(completers);
+       int ret;
+
+       ret = i9e_print_completions(completers);
        exit(ret <= 0? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
        exit(ret <= 0? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
@@ -589,7 +628,7 @@ int main(int argc, char *argv[])
        ret = client_parse_config(argc, argv, &ct, &client_loglevel);
        if (ret < 0)
                goto out;
        ret = client_parse_config(argc, argv, &ct, &client_loglevel);
        if (ret < 0)
                goto out;
-       if (ct->conf.complete_given)
+       if (CLIENT_OPT_GIVEN(COMPLETE, ct->lpr))
                print_completions();
        if (ret == 0)
                interactive_session(); /* does not return */
                print_completions();
        if (ret == 0)
                interactive_session(); /* does not return */
index 2f257221510b1cb0b0848eb615d1dfb894f0cc81..87cfc618d64825684d0d607a07cf4605d4476ae2 100644 (file)
--- a/client.h
+++ b/client.h
@@ -38,8 +38,8 @@ struct client_task {
        struct btr_node *btrn[2];
        /** The hash value of the decrypted challenge. */
        unsigned char *challenge_hash;
        struct btr_node *btrn[2];
        /** The hash value of the decrypted challenge. */
        unsigned char *challenge_hash;
-       /** The configuration (including the command). */
-       struct client_args_info conf;
+       /** The parsed command line (including the command). */
+       struct lls_parse_result *lpr;
        /** The config file for client options. */
        char *config_file;
        /** The RSA private key. */
        /** The config file for client options. */
        char *config_file;
        /** The RSA private key. */
@@ -52,6 +52,16 @@ struct client_task {
        char **features;
 };
 
        char **features;
 };
 
+#define CLIENT_CMD_PTR (lls_cmd(0, client_suite))
+#define CLIENT_OPT_RESULT(_name, _lpr) \
+       (lls_opt_result(LSG_CLIENT_PARA_CLIENT_OPT_ ## _name, _lpr))
+#define CLIENT_OPT_GIVEN(_name, _lpr) \
+       (lls_opt_given(CLIENT_OPT_RESULT(_name, _lpr)))
+#define CLIENT_OPT_UINT32_VAL(_name, _lpr) \
+       (lls_uint32_val(0, CLIENT_OPT_RESULT(_name, _lpr)))
+#define CLIENT_OPT_STRING_VAL(_name, _lpr) \
+       (lls_string_val(0, CLIENT_OPT_RESULT(_name, _lpr)))
+
 void client_close(struct client_task *ct);
 int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr,
                int *loglevel);
 void client_close(struct client_task *ct);
 int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr,
                int *loglevel);
index eea7510fd0589e86fb4058dd7f4361f3c79901aa..c22312c883d06d261eee97bcf9c8432d4f284e7c 100644 (file)
@@ -13,7 +13,9 @@
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
+#include <lopsub.h>
 
 
+#include "client.lsg.h"
 #include "para.h"
 #include "error.h"
 #include "list.h"
 #include "para.h"
 #include "error.h"
 #include "list.h"
 #include "fd.h"
 #include "sideband.h"
 #include "string.h"
 #include "fd.h"
 #include "sideband.h"
 #include "string.h"
-#include "client.cmdline.h"
 #include "client.h"
 #include "buffer_tree.h"
 #include "version.h"
 #include "client.h"
 #include "buffer_tree.h"
 #include "version.h"
-#include "ggo.h"
 
 /** The size of the receiving buffer. */
 #define CLIENT_BUFSIZE 4000
 
 /** The size of the receiving buffer. */
 #define CLIENT_BUFSIZE 4000
@@ -46,7 +46,7 @@ void client_close(struct client_task *ct)
        free(ct->user);
        free(ct->config_file);
        free(ct->key_file);
        free(ct->user);
        free(ct->config_file);
        free(ct->key_file);
-       client_cmdline_parser_free(&ct->conf);
+       lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR);
        free(ct->challenge_hash);
        sb_free(ct->sbc[0]);
        sb_free(ct->sbc[1]);
        free(ct->challenge_hash);
        sb_free(ct->sbc[0]);
        sb_free(ct->sbc[1]);
@@ -251,16 +251,18 @@ static int send_sb_command(struct client_task *ct)
        int i;
        char *command, *p;
        size_t len = 0;
        int i;
        char *command, *p;
        size_t len = 0;
+       unsigned num_inputs = lls_num_inputs(ct->lpr);
 
        if (ct->sbc[1])
                return send_sb(ct, 0, NULL, 0, 0, false);
 
 
        if (ct->sbc[1])
                return send_sb(ct, 0, NULL, 0, 0, false);
 
-       for (i = 0; i < ct->conf.inputs_num; i++)
-               len += strlen(ct->conf.inputs[i]) + 1;
+       for (i = 0; i < num_inputs; i++)
+               len += strlen(lls_input(i, ct->lpr)) + 1;
        p = command = para_malloc(len);
        p = command = para_malloc(len);
-       for (i = 0; i < ct->conf.inputs_num; i++) {
-               strcpy(p, ct->conf.inputs[i]);
-               p += strlen(ct->conf.inputs[i]) + 1;
+       for (i = 0; i < num_inputs; i++) {
+               const char *str = lls_input(i, ct->lpr);
+               strcpy(p, str);
+               p += strlen(str) + 1;
        }
        PARA_DEBUG_LOG("--> %s\n", command);
        return send_sb(ct, 0, command, len, SBD_COMMAND, false);
        }
        PARA_DEBUG_LOG("--> %s\n", command);
        return send_sb(ct, 0, command, len, SBD_COMMAND, false);
@@ -467,12 +469,12 @@ int client_connect(struct client_task *ct, struct sched *s,
                struct btr_node *parent, struct btr_node *child)
 {
        int ret;
                struct btr_node *parent, struct btr_node *child)
 {
        int ret;
+       const char *host = CLIENT_OPT_STRING_VAL(HOSTNAME, ct->lpr);
+       uint32_t port = CLIENT_OPT_UINT32_VAL(SERVER_PORT, ct->lpr);
 
 
-       PARA_NOTICE_LOG("connecting %s:%d\n", ct->conf.hostname_arg,
-               ct->conf.server_port_arg);
+       PARA_NOTICE_LOG("connecting %s:%u\n", host, port);
        ct->scc.fd = -1;
        ct->scc.fd = -1;
-       ret = para_connect_simple(IPPROTO_TCP, ct->conf.hostname_arg,
-                                              ct->conf.server_port_arg);
+       ret = para_connect_simple(IPPROTO_TCP, host, port);
        if (ret < 0)
                return ret;
        ct->scc.fd = ret;
        if (ret < 0)
                return ret;
        ct->scc.fd = ret;
@@ -498,13 +500,19 @@ err_out:
        return ret;
 }
 
        return ret;
 }
 
-__noreturn static void print_help_and_die(struct client_task *ct)
+static void handle_help_flag(struct lls_parse_result *lpr)
 {
 {
-       struct ggo_help h = DEFINE_GGO_HELP(client);
-       bool d = ct->conf.detailed_help_given;
+       char *help;
 
 
-       ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
-       exit(0);
+       if (CLIENT_OPT_GIVEN(DETAILED_HELP, lpr))
+               help = lls_long_help(CLIENT_CMD_PTR);
+       else if (CLIENT_OPT_GIVEN(HELP, lpr))
+               help = lls_short_help(CLIENT_CMD_PTR);
+       else
+               return;
+       printf("%s\n", help);
+       free(help);
+       exit(EXIT_SUCCESS);
 }
 
 /**
 }
 
 /**
@@ -528,65 +536,90 @@ __noreturn static void print_help_and_die(struct client_task *ct)
 int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr,
                int *loglevel)
 {
 int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr,
                int *loglevel)
 {
-       char *home = para_homedir();
-       int ret;
-       struct client_task *ct = para_calloc(sizeof(struct client_task));
-
-       *ct_ptr = ct;
-       ct->scc.fd = -1;
-       ret = -E_CLIENT_SYNTAX;
-       if (client_cmdline_parser(argc, argv, &ct->conf))
-               goto out;
-       version_handle_flag("client", ct->conf.version_given);
-       if (ct->conf.help_given || ct->conf.detailed_help_given)
-               print_help_and_die(ct);
-
-       ct->config_file = ct->conf.config_file_given?
-               para_strdup(ct->conf.config_file_arg) :
-               make_message("%s/.paraslash/client.conf", home);
-       ret = file_exists(ct->config_file);
-       if (!ret && ct->conf.config_file_given) {
-               ret = -E_NO_CONFIG;
+       const struct lls_command *cmd = CLIENT_CMD_PTR;
+       void *map;
+       size_t sz;
+       struct lls_parse_result *lpr;
+       int ret, ll;
+       struct client_task *ct;
+       char *cf = NULL, *kf = NULL, *user, *errctx, *home = para_homedir();
+
+       ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx));
+       if (ret < 0)
                goto out;
                goto out;
-       }
-       if (ret) {
-               struct client_cmdline_parser_params params = {
-                       .override = 0,
-                       .initialize = 0,
-                       .check_required = 0,
-                       .check_ambiguity = 0,
-                       .print_errors = 0
-               };
-               ret = -E_BAD_CONFIG;
-               if (client_cmdline_parser_config_file(ct->config_file,
-                       &ct->conf, &params))
+       ll = CLIENT_OPT_UINT32_VAL(LOGLEVEL, lpr);
+       version_handle_flag("client", CLIENT_OPT_GIVEN(VERSION, lpr));
+       handle_help_flag(lpr);
+
+       if (CLIENT_OPT_GIVEN(CONFIG_FILE, lpr))
+               cf = para_strdup(CLIENT_OPT_STRING_VAL(CONFIG_FILE, lpr));
+       else
+               cf = make_message("%s/.paraslash/client.conf", home);
+       ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
+       if (ret < 0) {
+               if (ret != -E_EMPTY && ret != -ERRNO_TO_PARA_ERROR(ENOENT))
+                       goto out;
+               if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) &&
+                               CLIENT_OPT_GIVEN(CONFIG_FILE, lpr))
                        goto out;
                        goto out;
+       } else {
+               int cf_argc;
+               char **cf_argv;
+               struct lls_parse_result *cf_lpr, *merged_lpr;
+               ret = lls(lls_convert_config(map, sz, NULL, &cf_argv, &errctx));
+               para_munmap(map, sz);
+               if (ret < 0)
+                       goto out;
+               cf_argc = ret;
+               ret = lls(lls_parse(cf_argc, cf_argv, cmd, &cf_lpr, &errctx));
+               lls_free_argv(cf_argv);
+               if (ret < 0)
+                       goto out;
+               ret = lls(lls_merge(lpr, cf_lpr, cmd, &merged_lpr,
+                       &errctx));
+               lls_free_parse_result(cf_lpr, cmd);
+               if (ret < 0)
+                       goto out;
+               lls_free_parse_result(lpr, cmd);
+               lpr = merged_lpr;
        }
        }
-       ct->user = ct->conf.user_given?
-               para_strdup(ct->conf.user_arg) : para_logname();
+       /* success */
+       user = CLIENT_OPT_GIVEN(USER, lpr)?
+               para_strdup(CLIENT_OPT_STRING_VAL(USER, lpr)) : para_logname();
 
 
-       if (ct->conf.key_file_given)
-               ct->key_file = para_strdup(ct->conf.key_file_arg);
+       if (CLIENT_OPT_GIVEN(KEY_FILE, lpr))
+               kf = para_strdup(CLIENT_OPT_STRING_VAL(KEY_FILE, lpr));
        else {
        else {
-               ct->key_file = make_message("%s/.paraslash/key.%s",
-                       home, ct->user);
-               if (!file_exists(ct->key_file)) {
-                       free(ct->key_file);
-                       ct->key_file = make_message("%s/.ssh/id_rsa", home);
+               kf = make_message("%s/.paraslash/key.%s", home, user);
+               if (!file_exists(kf)) {
+                       free(kf);
+                       kf = make_message("%s/.ssh/id_rsa", home);
                }
        }
                }
        }
-
+       PARA_INFO_LOG("user: %s\n", user);
+       PARA_INFO_LOG("config file: %s\n", cf);
+       PARA_INFO_LOG("key file: %s\n", kf);
+       PARA_INFO_LOG("loglevel: %d\n", ll);
+       ct = para_calloc(sizeof(*ct));
+       ct->scc.fd = -1;
+       ct->lpr = lpr;
+       ct->key_file = kf;
+       ct->config_file = cf;
+       ct->user = user;
+       *ct_ptr = ct;
        if (loglevel)
        if (loglevel)
-               *loglevel = get_loglevel_by_name(ct->conf.loglevel_arg);
-       PARA_INFO_LOG("loglevel: %s\n", ct->conf.loglevel_arg);
-       PARA_INFO_LOG("config_file: %s\n", ct->config_file);
-       PARA_INFO_LOG("key_file: %s\n", ct->key_file);
-       ret = ct->conf.inputs_num;
+               *loglevel = ll;
+       ret = lls_num_inputs(lpr);
 out:
        free(home);
        if (ret < 0) {
 out:
        free(home);
        if (ret < 0) {
+               if (errctx)
+                       PARA_ERROR_LOG("%s\n", errctx);
+               free(errctx);
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
-               client_close(ct);
+               lls_free_parse_result(lpr, cmd);
+               free(cf);
+               free(kf);
                *ct_ptr = NULL;
        }
        return ret;
                *ct_ptr = NULL;
        }
        return ret;
index d5e52839f8998ab89db35b9f657be627d0a6fc0a..a22c5f1a96fa5d31e68007ea76f390913ae439f1 100644 (file)
@@ -472,7 +472,6 @@ fi
 if test -n "$CRYPTOLIB"; then
        build_client="yes"
        executables="$executables client"
 if test -n "$CRYPTOLIB"; then
        build_client="yes"
        executables="$executables client"
-       client_cmdline_objs="client"
        client_errlist_objs="
                client
                net
        client_errlist_objs="
                client
                net
@@ -488,7 +487,6 @@ if test -n "$CRYPTOLIB"; then
                crypt_common
                base64
                version
                crypt_common
                base64
                version
-               ggo
        "
        if test "$CRYPTOLIB" = openssl; then
                client_errlist_objs="$client_errlist_objs crypt"
        "
        if test "$CRYPTOLIB" = openssl; then
                client_errlist_objs="$client_errlist_objs crypt"
@@ -498,8 +496,8 @@ if test -n "$CRYPTOLIB"; then
        if test $HAVE_READLINE = yes; then
                client_errlist_objs="$client_errlist_objs interactive"
        fi
        if test $HAVE_READLINE = yes; then
                client_errlist_objs="$client_errlist_objs interactive"
        fi
-       client_objs="add_cmdline($client_cmdline_objs) $client_errlist_objs"
-       AC_SUBST(client_objs, add_dot_o($client_objs))
+       client_objs="$client_errlist_objs"
+       AC_SUBST(client_objs, add_dot_o($client_errlist_objs))
 else
        build_client="no"
 fi
 else
        build_client="no"
 fi
@@ -512,7 +510,6 @@ if test -n "$CRYPTOLIB"; then
                audiod
                compress_filter
                file_write
                audiod
                compress_filter
                file_write
-               client
                amp_filter
                prebuffer_filter
                sync_filter
                amp_filter
                prebuffer_filter
                sync_filter
diff --git a/error.h b/error.h
index d10ac76abcaa669abb381b07325040338b85c100..404bdf426d8f6fa69e7804381589c25ac262be98 100644 (file)
--- a/error.h
+++ b/error.h
@@ -56,7 +56,6 @@
        PARA_ERROR(BAD_BAND, "invalid or unexpected band designator"), \
        PARA_ERROR(BAD_CHANNEL_COUNT, "channel count not supported"), \
        PARA_ERROR(BAD_CHANNEL, "invalid channel"), \
        PARA_ERROR(BAD_BAND, "invalid or unexpected band designator"), \
        PARA_ERROR(BAD_CHANNEL_COUNT, "channel count not supported"), \
        PARA_ERROR(BAD_CHANNEL, "invalid channel"), \
-       PARA_ERROR(BAD_CONFIG, "syntax error in config file"), \
        PARA_ERROR(BAD_CT, "invalid chunk table or bad FEC configuration"), \
        PARA_ERROR(BAD_FEATURE, "invalid feature request"), \
        PARA_ERROR(BAD_FEC_HEADER, "invalid fec header"), \
        PARA_ERROR(BAD_CT, "invalid chunk table or bad FEC configuration"), \
        PARA_ERROR(BAD_FEATURE, "invalid feature request"), \
        PARA_ERROR(BAD_FEC_HEADER, "invalid fec header"), \
        PARA_ERROR(NO_AFHI, "audio format handler info required"), \
        PARA_ERROR(NO_ATTRIBUTES, "no attributes defined yet"), \
        PARA_ERROR(NO_AUDIO_FILE, "no audio file"), \
        PARA_ERROR(NO_AFHI, "audio format handler info required"), \
        PARA_ERROR(NO_ATTRIBUTES, "no attributes defined yet"), \
        PARA_ERROR(NO_AUDIO_FILE, "no audio file"), \
-       PARA_ERROR(NO_CONFIG, "config file not found"), \
        PARA_ERROR(NOFD, "did not receive open fd from afs"), \
        PARA_ERROR(NO_FILTERS, "at least one filter must be given"), \
        PARA_ERROR(NO_MATCH, "no matches"), \
        PARA_ERROR(NOFD, "did not receive open fd from afs"), \
        PARA_ERROR(NO_FILTERS, "at least one filter must be given"), \
        PARA_ERROR(NO_MATCH, "no matches"), \
diff --git a/m4/gengetopt/client.m4 b/m4/gengetopt/client.m4
deleted file mode 100644 (file)
index a5a27a0..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-args "--unamed-opts=command --no-handle-error --conf-parser --no-handle-version --no-handle-help"
-
-purpose "Communicate with para_server through the paraslash control port"
-
-include(header.m4)
-define(CURRENT_PROGRAM,para_client)
-define(DEFAULT_CONFIG_FILE,~/.paraslash/client.conf)
-define(DEFAULT_HISTORY_FILE,~/.paraslash/client.history)
-<qu>
-option "hostname" i
-#~~~~~~~~~~~~~~~~~~
-"ip or host to connect"
-string typestr = "host"
-default = "localhost"
-optional
-
-option "user" u
-#~~~~~~~~~~~~~~
-"paraslash username"
-string typestr = "username"
-default = "<current user>"
-optional
-
-option "server-port" p
-#~~~~~~~~~~~~~~~~~~~~~
-"port to connect"
-int typestr = "port"
-default = "2990"
-optional
-
-option "key-file" k
-#~~~~~~~~~~~~~~~~~~
-"path to private key"
-string typestr = "filename"
-optional
-details = "
-       If not given, the following files are tried, in order:
-       $HOME/.paraslash/key.$LOGNAME, $HOME/.ssh/id_rsa. It is a fatal
-       error if the key file can not be opened, or is world-readable.
-"
-</qu>
-
-include(loglevel.m4)
-include(config_file.m4)
-include(history_file.m4)
-include(complete.m4)
diff --git a/m4/gengetopt/complete.m4 b/m4/gengetopt/complete.m4
deleted file mode 100644 (file)
index 14e737c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<qu>
-option "complete" -
-#~~~~~~~~~~~~~~~~~~
-"print possible command line completions"
-       flag off
-       details = "
-       If this flag is given, </qu>CURRENT_PROGRAM<qu> reads the environment
-       variables COMP_LINE and COMP_POINT to obtain the current command line
-       and the cursor position respectively, prints possible completions
-       to stdout and exits.
-"
-</qu>
diff --git a/m4/lls/client.suite.m4 b/m4/lls/client.suite.m4
new file mode 100644 (file)
index 0000000..30230c4
--- /dev/null
@@ -0,0 +1,63 @@
+m4_define(PROGRAM, para_client)
+m4_define(DEFAULT_HISTORY_FILE, ~/.paraslash/client.history)
+m4_define(DEFAULT_CONFIG_FILE,~/.paraslash/client.conf)
+[suite client]
+version-string = GIT_VERSION()
+[supercommand para_client]
+       purpose = Communicate with para_server through the paraslash control port
+       non-opts-name = [command [options]]
+       [description]
+               para_client is the program used to connect to a running instance of
+               para_server. If a command is provided, this command is sent to the
+               server and any output received from the server is echoed to stdout. If
+               no command is given, para_client enters interactive mode.
+       [/description]
+       m4_include(common-option-section.m4)
+       m4_include(help.m4)
+       m4_include(detailed-help.m4)
+       m4_include(version.m4)
+       m4_include(loglevel.m4)
+       m4_include(config-file.m4)
+       m4_include(history-file.m4)
+       m4_include(per-command-options-section.m4)
+       [option hostname]
+               short_opt = i
+               summary = IP address or name of the host where para_server is running
+               typestr = host
+               arg_info = required_arg
+               arg_type = string
+               default_val = localhost
+               [help]
+                       Both IPv4 and IPv6 addresses are supported.
+               [/help]
+       [option user]
+               short_opt = u
+               summary = the paraslash username to authenticate as
+               arg_info = required_arg
+               arg_type = string
+               typestr = name
+               [help]
+                       If this is not given, the current username is assumed.
+               [/help]
+       [option server-port]
+               short_opt = p
+               summary = the port on the remote host to connect
+               arg_info = required_arg
+               arg_type = uint32
+               typestr = portnumber
+               default_val = 2990
+               [help]
+                       If this is not given, the current username is assumed.
+               [/help]
+       [option key-file]
+               short_opt = k
+               summary = path to private key
+               arg_info = required_arg
+               arg_type = string
+               typestr = filename
+               [help]
+                       If not given, the following files are tried, in order:
+                       $HOME/.paraslash/key.$LOGNAME, $HOME/.ssh/id_rsa. It is a fatal error
+                       if the key file can not be opened, or is world-readable.
+               [/help]
+       m4_include(complete.m4)
diff --git a/m4/lls/include/config-file.m4 b/m4/lls/include/config-file.m4
new file mode 100644 (file)
index 0000000..a5de133
--- /dev/null
@@ -0,0 +1,14 @@
+[option config-file]
+       short_opt = c
+       summary = path to alternative config file
+       arg_info = required_arg
+       arg_type = string
+       typestr = filename
+       [help]
+               default: DEFAULT_CONFIG_FILE()
+
+               PROGRAM() reads its config file right after parsing the options that
+               were given at the command line. If an option is given both at the
+               command line and in the config file, the value that was specified at
+               the command line takes precedence.
+       [/help]