]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - lsu.c
Introduce lsu.{c,h}, implement help --long for para_server.
[paraslash.git] / lsu.c
diff --git a/lsu.c b/lsu.c
new file mode 100644 (file)
index 0000000..de6f2cb
--- /dev/null
+++ b/lsu.c
@@ -0,0 +1,138 @@
+/* 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;
+}