]> git.tuebingen.mpg.de Git - paraslash.git/blob - lsu.c
Introduce lsu.{c,h}, implement help --long for para_server.
[paraslash.git] / lsu.c
1 /* Copyright (C) 2018 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file lsu.c Utilities related to the lopsub library. */
4
5 #include <lopsub.h>
6 #include <regex.h>
7
8 #include "para.h"
9 #include "error.h"
10 #include "string.h"
11
12 static int lsu_lopsub_error(int ret, char **errctx, char **result, unsigned *num_chars)
13 {
14         const char *se = para_strerror(-ret);
15         unsigned n;
16
17         if (*errctx)
18                 n = xasprintf(result, "%s: %s\n", *errctx, se);
19         else
20                 n = xasprintf(result, "lopsub error: %s\n", se);
21         free(*errctx);
22         *errctx = NULL;
23         if (num_chars)
24                 *num_chars = n;
25         return ret;
26 }
27
28 static void lsu_get_subcommand_summary(bool long_summary,
29                 const struct lls_suite *suite,
30                 const char *(*aux_info_cb)(unsigned cmd_num, bool verbose),
31                 char **result, unsigned *num_chars)
32 {
33         int i;
34         const struct lls_command *cmd;
35         const char *name, *aux_info = NULL;
36         struct para_buffer pb = {.max_size = 0 /* unlimited */};
37
38         para_printf(&pb, "Available subcommands:\n");
39         if (long_summary) {
40                 int maxname = 0, max_aux_info = 0;
41                 for (i = 1; (cmd = lls_cmd(i, suite)); i++) {
42                         maxname = PARA_MAX(maxname,
43                                 (int)strlen(lls_command_name(cmd)));
44                         if (aux_info_cb) {
45                                 aux_info = aux_info_cb(i, false);
46                                 if (!aux_info)
47                                         continue;
48                                 max_aux_info = PARA_MAX(max_aux_info,
49                                         (int)strlen(aux_info));
50                         }
51                 }
52                 for (i = 1; (cmd = lls_cmd(i, suite)); i++) {
53                         if (aux_info_cb)
54                                 aux_info = aux_info_cb(i, false);
55                         para_printf(&pb, "%-*s %-*s %s\n", maxname,
56                                 lls_command_name(cmd), max_aux_info, aux_info?
57                                 aux_info : "", lls_purpose(cmd));
58                 }
59         } else {
60                 unsigned n = 8;
61                 para_printf(&pb, "\t");
62                 for (i = 1; (cmd = lls_cmd(i, suite)); i++) {
63                         name = lls_command_name(cmd);
64                         if (i > 1)
65                                 n += para_printf(&pb, ", ");
66                         if (n > 70) {
67                                 para_printf(&pb, "\n\t");
68                                 n = 8;
69                         }
70                         n += para_printf(&pb, "%s", name);
71                 }
72                 para_printf(&pb, "\n");
73         }
74         *result = pb.buf;
75         if (num_chars)
76                 *num_chars = pb.offset;
77 }
78
79 /**
80  * A generic implementation of the help subcommand.
81  *
82  * This function returns the help text for the given subcommand, or the list of
83  * all subcommands if no non-option argument is given. The function is generic
84  * in that it works for arbitrary lopsub suites.
85  *
86  * \param long_help Applies to both command list and command help.
87  * \param suite The supercommand, if any, is omitted.
88  * \param lpr Used to determine whether a non-option argument is given.
89  * \param aux_info_cb Optional callback, may return NULL, static memory.
90  * \param result Must be freed by the caller.
91  * \param num_chars Initialized to the length of the returned string, optional.
92  *
93  * If the optional aux_info_cb function pointer is not NULL, the callback
94  * function must return the string representation of the aux_info structure of
95  * the given command, or NULL to indicate that this command has no aux info
96  * structure.
97  *
98  * The function fails if lpr has more than one non-option argument, or if there
99  * is exactly one non-option argument, but this argument is not the name of a
100  * subcommand in the given lopsub suite.
101  *
102  * \return Standard. In the failure case a suitable error message is returned
103  * via the result pointer and num_chars is set accordingly.
104  */
105 int lsu_com_help(bool long_help, const struct lls_parse_result *lpr,
106                 const struct lls_suite *suite,
107                 const char *(*aux_info_cb)(unsigned cmd_num, bool verbose),
108                 char **result, unsigned *num_chars)
109 {
110         int ret;
111         unsigned n;
112         char *errctx, *tmp;
113         const char *arg, *aux_info = NULL;
114         const struct lls_command *cmd;
115
116         ret = lls(lls_check_arg_count(lpr, 0, 1, &errctx));
117         if (ret < 0)
118                 return lsu_lopsub_error(ret, &errctx, result, num_chars);
119         if (lls_num_inputs(lpr) == 0) {
120                 lsu_get_subcommand_summary(long_help, suite,
121                         aux_info_cb, result, num_chars);
122                 return 0;
123         }
124         arg = lls_input(0, lpr);
125         ret = lls(lls_lookup_subcmd(arg, suite, &errctx));
126         if (ret < 0)
127                 return lsu_lopsub_error(ret, &errctx, result, num_chars);
128         cmd = lls_cmd(ret, suite);
129         tmp = long_help? lls_long_help(cmd) : lls_short_help(cmd);
130         if (aux_info_cb)
131                 aux_info = aux_info_cb(ret, true);
132         n = xasprintf(result, "%s%s%s", tmp, aux_info? aux_info : "",
133                 aux_info? "\n" : "");
134         free(tmp);
135         if (num_chars)
136                 *num_chars = n;
137         return 1;
138 }