static void help_completer(struct i9e_completion_info *ci,
struct i9e_completion_result *result)
{
+ char *opts[] = {LSG_SERVER_CMD_HELP_OPTS, NULL};
+
+ if (ci->word[0] == '-') {
+ i9e_complete_option(opts, ci, result);
+ return;
+ }
result->matches = i9e_complete_commands(ci->word, completers);
}
#include "server.lsg.h"
#include "para.h"
#include "error.h"
+#include "lsu.h"
#include "crypt.h"
#include "sideband.h"
#include "command.h"
}
EXPORT_SERVER_CMD_HANDLER(stat);
-/* fixed-length, human readable permission string */
-const char *server_cmd_perms_str(unsigned int perms)
+const char *aux_info_cb(unsigned cmd_num, bool verbose)
{
- static char result[5];
+ static char result[80];
+ unsigned perms = server_command_perms[cmd_num];
- result[0] = perms & AFS_READ? 'a' : '-';
- result[1] = perms & AFS_WRITE? 'A' : '-';
- result[2] = perms & VSS_READ? 'v' : '-';
- result[3] = perms & VSS_WRITE? 'V' : '-';
- result[4] = '\0';
- return result;
-}
-
-static int send_list_of_commands(struct command_context *cc)
-{
- int i;
- const struct lls_command *cmd;
- char *msg = para_strdup("");
-
- for (i = 1; (cmd = lls_cmd(i, server_cmd_suite)); i++) {
- const char *perms = server_cmd_perms_str(server_command_perms[i]);
- char *tmp = make_message("%s%s\t%s\t%s\n", msg,
- lls_command_name(cmd), perms, lls_purpose(cmd));
- free(msg);
- msg = tmp;
+ if (verbose) {
+ /* permissions: VSS_READ | VSS_WRITE */
+ sprintf(result, "permissions: %s",
+ server_command_perms_txt[cmd_num]);
+ } else {
+ result[0] = perms & AFS_READ? 'a' : '-';
+ result[1] = perms & AFS_WRITE? 'A' : '-';
+ result[2] = perms & VSS_READ? 'v' : '-';
+ result[3] = perms & VSS_WRITE? 'V' : '-';
+ result[4] = '\0';
}
- return send_sb(&cc->scc, msg, strlen(msg), SBD_OUTPUT, false);
+ return result;
}
static int com_help(struct command_context *cc, struct lls_parse_result *lpr)
{
- const char *perms;
- char *long_help, *buf, *errctx;
+ char *buf;
int ret;
- const struct lls_command *cmd;
+ unsigned n;
+ bool long_help = SERVER_CMD_OPT_GIVEN(HELP, LONG, lpr);
- ret = lls(lls_check_arg_count(lpr, 0, 1, &errctx));
- if (ret < 0) {
- send_errctx(cc, errctx);
- return ret;
- }
- if (lls_num_inputs(lpr) == 0)
- return send_list_of_commands(cc);
- /* argument given for help */
- ret = lls(lls_lookup_subcmd(lls_input(0, lpr), server_cmd_suite,
- &errctx));
- if (ret < 0) {
- send_errctx(cc, errctx);
- return ret;
- }
- cmd = lls_cmd(ret, server_cmd_suite);
- perms = server_command_perms_txt[ret];
- long_help = lls_long_help(cmd);
- assert(long_help);
- ret = xasprintf(&buf, "%spermissions: %s\n", long_help, perms);
- free(long_help);
- return send_sb(&cc->scc, buf, ret, SBD_OUTPUT, false);
+ lsu_com_help(long_help, lpr, server_cmd_suite, aux_info_cb, &buf, &n);
+ ret = send_sb(&cc->scc, buf, n, SBD_OUTPUT, false);
+ return ret;
}
EXPORT_SERVER_CMD_HANDLER(help);
wma_common
sideband
version
+ lsu
"
if test "$CRYPTOLIB" = openssl; then
server_errlist_objs="$server_errlist_objs crypt"
--- /dev/null
+/* Copyright (C) 2018 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
+
+/** \file lsu.c Utilities related to the lopsub library. */
+
+#include <lopsub.h>
+#include <regex.h>
+
+#include "para.h"
+#include "error.h"
+#include "string.h"
+
+static int lsu_lopsub_error(int ret, char **errctx, char **result, unsigned *num_chars)
+{
+ const char *se = para_strerror(-ret);
+ unsigned n;
+
+ if (*errctx)
+ n = xasprintf(result, "%s: %s\n", *errctx, se);
+ else
+ n = xasprintf(result, "lopsub error: %s\n", se);
+ free(*errctx);
+ *errctx = NULL;
+ if (num_chars)
+ *num_chars = n;
+ return ret;
+}
+
+static void lsu_get_subcommand_summary(bool long_summary,
+ const struct lls_suite *suite,
+ const char *(*aux_info_cb)(unsigned cmd_num, bool verbose),
+ char **result, unsigned *num_chars)
+{
+ int i;
+ const struct lls_command *cmd;
+ const char *name, *aux_info = NULL;
+ struct para_buffer pb = {.max_size = 0 /* unlimited */};
+
+ para_printf(&pb, "Available subcommands:\n");
+ if (long_summary) {
+ int maxname = 0, max_aux_info = 0;
+ for (i = 1; (cmd = lls_cmd(i, suite)); i++) {
+ maxname = PARA_MAX(maxname,
+ (int)strlen(lls_command_name(cmd)));
+ if (aux_info_cb) {
+ aux_info = aux_info_cb(i, false);
+ if (!aux_info)
+ continue;
+ max_aux_info = PARA_MAX(max_aux_info,
+ (int)strlen(aux_info));
+ }
+ }
+ for (i = 1; (cmd = lls_cmd(i, suite)); i++) {
+ if (aux_info_cb)
+ aux_info = aux_info_cb(i, false);
+ para_printf(&pb, "%-*s %-*s %s\n", maxname,
+ lls_command_name(cmd), max_aux_info, aux_info?
+ aux_info : "", lls_purpose(cmd));
+ }
+ } else {
+ unsigned n = 8;
+ para_printf(&pb, "\t");
+ for (i = 1; (cmd = lls_cmd(i, suite)); i++) {
+ name = lls_command_name(cmd);
+ if (i > 1)
+ n += para_printf(&pb, ", ");
+ if (n > 70) {
+ para_printf(&pb, "\n\t");
+ n = 8;
+ }
+ n += para_printf(&pb, "%s", name);
+ }
+ para_printf(&pb, "\n");
+ }
+ *result = pb.buf;
+ if (num_chars)
+ *num_chars = pb.offset;
+}
+
+/**
+ * A generic implementation of the help subcommand.
+ *
+ * This function returns the help text for the given subcommand, or the list of
+ * all subcommands if no non-option argument is given. The function is generic
+ * in that it works for arbitrary lopsub suites.
+ *
+ * \param long_help Applies to both command list and command help.
+ * \param suite The supercommand, if any, is omitted.
+ * \param lpr Used to determine whether a non-option argument is given.
+ * \param aux_info_cb Optional callback, may return NULL, static memory.
+ * \param result Must be freed by the caller.
+ * \param num_chars Initialized to the length of the returned string, optional.
+ *
+ * If the optional aux_info_cb function pointer is not NULL, the callback
+ * function must return the string representation of the aux_info structure of
+ * the given command, or NULL to indicate that this command has no aux info
+ * structure.
+ *
+ * The function fails if lpr has more than one non-option argument, or if there
+ * is exactly one non-option argument, but this argument is not the name of a
+ * subcommand in the given lopsub suite.
+ *
+ * \return Standard. In the failure case a suitable error message is returned
+ * via the result pointer and num_chars is set accordingly.
+ */
+int lsu_com_help(bool long_help, const struct lls_parse_result *lpr,
+ const struct lls_suite *suite,
+ const char *(*aux_info_cb)(unsigned cmd_num, bool verbose),
+ char **result, unsigned *num_chars)
+{
+ int ret;
+ unsigned n;
+ char *errctx, *tmp;
+ const char *arg, *aux_info = NULL;
+ const struct lls_command *cmd;
+
+ ret = lls(lls_check_arg_count(lpr, 0, 1, &errctx));
+ if (ret < 0)
+ return lsu_lopsub_error(ret, &errctx, result, num_chars);
+ if (lls_num_inputs(lpr) == 0) {
+ lsu_get_subcommand_summary(long_help, suite,
+ aux_info_cb, result, num_chars);
+ return 0;
+ }
+ arg = lls_input(0, lpr);
+ ret = lls(lls_lookup_subcmd(arg, suite, &errctx));
+ if (ret < 0)
+ return lsu_lopsub_error(ret, &errctx, result, num_chars);
+ cmd = lls_cmd(ret, suite);
+ tmp = long_help? lls_long_help(cmd) : lls_short_help(cmd);
+ if (aux_info_cb)
+ aux_info = aux_info_cb(ret, true);
+ n = xasprintf(result, "%s%s%s", tmp, aux_info? aux_info : "",
+ aux_info? "\n" : "");
+ free(tmp);
+ if (num_chars)
+ *num_chars = n;
+ return 1;
+}
--- /dev/null
+/* Copyright (C) 2018 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
+
+/** \file lsu.h Lopsub Utilities, enums and public functions. */
+int lsu_com_help(bool long_help, const struct lls_parse_result *lpr,
+ const struct lls_suite *suite,
+ const char *(*aux_info_cb)(unsigned cmd_num, bool verbose),
+ char **result, unsigned *num_chars);
--- /dev/null
+[option long]
+ short_opt = l
+ summary = show the long help text
+[help]
+ If no non-option argument is supplied to the help subcommand and --long
+ is not given, only the names of all subcommands are shown. With --long
+ the purpose of each command is printed as well.
+
+ If the name of a subcommand is supplied and --long is given, the help
+ text for the given subcommand contains the synopsis, the purpose and
+ the description of the specified command, followed by the option list
+ including summary and help text of each option. Without --long the
+ description of the command and the option help are omitted.
+[/help]
+
non-opts-name = [command]
aux_info = NO_PERMISSION_REQUIRED
[description]
- Without any arguments, help prints a list of available commands. When
- called with a command name as first argument, it prints the description
- of this command.
+ When executed without any arguments, the available server commands
+ are listed. Otherwise, if the first argument is the name of a server
+ command, the description of this command is shown.
[/description]
+ m4_include(`long-help.m4')
[subcommand hup]
purpose = reload config file, log file and user list
declare -a commands=() cmdline=() required_objects=() good=() bad=()
i=0
commands[$i]="help"
-cmdline[$i]="help"
-good[$i]='help ----'
+cmdline[$i]="help -l"
+good[$i]='help \{1,\}----'
let i++
commands[$i]="init"