sl: Add extended MANDOC generation
This commit is contained in:
177
lib/sl/sl.c
177
lib/sl/sl.c
@@ -36,6 +36,17 @@
|
||||
#include "sl_locl.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
static SL_cmd_info *
|
||||
find_cmd_info(SL_cmd_info *info, const char *name)
|
||||
{
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
for (; info->name != NULL; info++)
|
||||
if (strcmp(info->name, name) == 0)
|
||||
return info;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
mandoc_template(SL_cmd *cmds,
|
||||
const char *extra_string)
|
||||
@@ -108,6 +119,156 @@ mandoc_template(SL_cmd *cmds,
|
||||
printf(".\\\".Sh BUGS\n");
|
||||
}
|
||||
|
||||
static void
|
||||
mandoc_template_ext(SL_cmd *cmds,
|
||||
SL_cmd_info *info,
|
||||
const char *extra_string)
|
||||
{
|
||||
SL_cmd *c, *prev;
|
||||
SL_cmd_info *ci;
|
||||
char timestr[64], cmd[64];
|
||||
const char *p;
|
||||
time_t t;
|
||||
int i;
|
||||
|
||||
printf(".\\\" Things to fix:\n");
|
||||
printf(".\\\" * correct section, and operating system\n");
|
||||
printf(".\\\" * remove Op from mandatory flags\n");
|
||||
printf(".\\\" * use better macros for arguments (like .Pa for files)\n");
|
||||
printf(".\\\"\n");
|
||||
t = time(NULL);
|
||||
strftime(timestr, sizeof(timestr), "%b %d, %Y", localtime(&t));
|
||||
printf(".Dd %s\n", timestr);
|
||||
#ifdef HAVE_GETPROGNAME
|
||||
p = getprogname();
|
||||
#else
|
||||
p = "unknown-application";
|
||||
#endif
|
||||
strncpy(cmd, p, sizeof(cmd));
|
||||
cmd[sizeof(cmd)-1] = '\0';
|
||||
strupr(cmd);
|
||||
|
||||
printf(".Dt %s SECTION\n", cmd);
|
||||
printf(".Os OPERATING_SYSTEM\n");
|
||||
printf(".Sh NAME\n");
|
||||
printf(".Nm %s\n", p);
|
||||
printf(".Nd\n");
|
||||
printf("in search of a description\n");
|
||||
printf(".Sh SYNOPSIS\n");
|
||||
printf(".Nm\n");
|
||||
for(c = cmds; c->name; ++c) {
|
||||
if (c->func == NULL)
|
||||
continue;
|
||||
printf(".Nm\n");
|
||||
printf(".Ic %s\n", c->name);
|
||||
ci = find_cmd_info(info, c->name);
|
||||
if (ci && ci->args) {
|
||||
for (i = 0; i < ci->nargs; i++) {
|
||||
struct getargs *arg = &ci->args[i];
|
||||
if (arg->long_name == NULL)
|
||||
continue;
|
||||
/* Skip the implicit --help */
|
||||
if (strcmp(arg->long_name, "help") == 0)
|
||||
continue;
|
||||
if (arg->type == arg_flag || arg->type == arg_negative_flag) {
|
||||
if (arg->short_name)
|
||||
printf(".Op Fl %c | Fl \\-%s\n",
|
||||
arg->short_name, arg->long_name);
|
||||
else
|
||||
printf(".Op Fl \\-%s\n", arg->long_name);
|
||||
} else {
|
||||
if (arg->short_name)
|
||||
printf(".Op Fl %c Ar %s | Fl \\-%s Ns = Ns Ar %s\n",
|
||||
arg->short_name,
|
||||
arg->arg_help ? arg->arg_help : "value",
|
||||
arg->long_name,
|
||||
arg->arg_help ? arg->arg_help : "value");
|
||||
else
|
||||
printf(".Op Fl \\-%s Ns = Ns Ar %s\n",
|
||||
arg->long_name,
|
||||
arg->arg_help ? arg->arg_help : "value");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ci && ci->argument)
|
||||
printf(".Ar %s\n", ci->argument);
|
||||
}
|
||||
if (extra_string && *extra_string)
|
||||
printf (".Ar %s\n", extra_string);
|
||||
|
||||
printf(".Sh DESCRIPTION\n");
|
||||
printf("The following commands are supported:\n");
|
||||
printf(".Bl -tag -width Ds\n");
|
||||
prev = NULL;
|
||||
for(c = cmds; c->name; ++c) {
|
||||
if (c->func) {
|
||||
if (prev)
|
||||
printf ("\n%s\n", prev->help ? prev->help : "");
|
||||
|
||||
printf (".It Ic %s", c->name);
|
||||
prev = c;
|
||||
} else
|
||||
printf (" , Ic %s", c->name);
|
||||
}
|
||||
if (prev)
|
||||
printf ("\n%s\n", prev->help ? prev->help : "");
|
||||
|
||||
printf(".El\n");
|
||||
|
||||
/* Now output detailed option descriptions for each command */
|
||||
printf(".Sh COMMAND OPTIONS\n");
|
||||
for(c = cmds; c->name; ++c) {
|
||||
if (c->func == NULL)
|
||||
continue;
|
||||
ci = find_cmd_info(info, c->name);
|
||||
if (ci == NULL || ci->args == NULL || ci->nargs == 0)
|
||||
continue;
|
||||
|
||||
printf(".Ss %s\n", c->name);
|
||||
printf(".Bl -tag -width Ds -compact\n");
|
||||
for (i = 0; i < ci->nargs; i++) {
|
||||
struct getargs *arg = &ci->args[i];
|
||||
if (arg->long_name == NULL)
|
||||
continue;
|
||||
/* Skip the implicit --help */
|
||||
if (strcmp(arg->long_name, "help") == 0)
|
||||
continue;
|
||||
|
||||
if (arg->short_name) {
|
||||
if (arg->type == arg_flag || arg->type == arg_negative_flag)
|
||||
printf(".It Fl %c , Fl \\-%s\n",
|
||||
arg->short_name, arg->long_name);
|
||||
else
|
||||
printf(".It Fl %c Ar %s , Fl \\-%s Ns = Ns Ar %s\n",
|
||||
arg->short_name,
|
||||
arg->arg_help ? arg->arg_help : "value",
|
||||
arg->long_name,
|
||||
arg->arg_help ? arg->arg_help : "value");
|
||||
} else {
|
||||
if (arg->type == arg_flag || arg->type == arg_negative_flag)
|
||||
printf(".It Fl \\-%s\n", arg->long_name);
|
||||
else
|
||||
printf(".It Fl \\-%s Ns = Ns Ar %s\n",
|
||||
arg->long_name,
|
||||
arg->arg_help ? arg->arg_help : "value");
|
||||
}
|
||||
if (arg->help)
|
||||
printf("%s\n", arg->help);
|
||||
}
|
||||
printf(".El\n");
|
||||
}
|
||||
|
||||
printf(".\\\".Sh ENVIRONMENT\n");
|
||||
printf(".\\\".Sh FILES\n");
|
||||
printf(".\\\".Sh EXAMPLES\n");
|
||||
printf(".\\\".Sh DIAGNOSTICS\n");
|
||||
printf(".\\\".Sh SEE ALSO\n");
|
||||
printf(".\\\".Sh STANDARDS\n");
|
||||
printf(".\\\".Sh HISTORY\n");
|
||||
printf(".\\\".Sh AUTHORS\n");
|
||||
printf(".\\\".Sh BUGS\n");
|
||||
}
|
||||
|
||||
SL_cmd *
|
||||
sl_match (SL_cmd *cmds, char *cmd, int exactp)
|
||||
{
|
||||
@@ -131,12 +292,26 @@ sl_match (SL_cmd *cmds, char *cmd, int exactp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
sl_help_ext(SL_cmd *cmds, SL_cmd_info *info, int argc, char **argv)
|
||||
{
|
||||
if (getenv("SLMANDOC")) {
|
||||
if (info)
|
||||
mandoc_template_ext(cmds, info, NULL);
|
||||
else
|
||||
mandoc_template(cmds, NULL);
|
||||
return;
|
||||
}
|
||||
sl_slc_help(cmds, argc, argv);
|
||||
}
|
||||
|
||||
void
|
||||
sl_help (SL_cmd *cmds, int argc, char **argv)
|
||||
{
|
||||
SL_cmd *c, *prev_c;
|
||||
|
||||
if (getenv("SLMANDOC")) {
|
||||
if (getenv("SLMANDOC") &&
|
||||
strcmp(getenv("SLMANDOC"), "extended") == 0) {
|
||||
mandoc_template(cmds, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
13
lib/sl/sl.h
13
lib/sl/sl.h
@@ -49,6 +49,18 @@ struct sl_cmd {
|
||||
|
||||
typedef struct sl_cmd SL_cmd;
|
||||
|
||||
/*
|
||||
* Extended command info for mandoc generation.
|
||||
* Generated by slc alongside SL_cmd.
|
||||
*/
|
||||
struct sl_cmd_info {
|
||||
const char *name;
|
||||
const char *argument;
|
||||
struct getargs *args;
|
||||
int nargs;
|
||||
};
|
||||
typedef struct sl_cmd_info SL_cmd_info;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -61,6 +73,7 @@ int sl_make_argv(char*, int*, char***);
|
||||
void sl_apropos (SL_cmd *cmd, const char *topic);
|
||||
SL_cmd *sl_match (SL_cmd *cmds, char *cmd, int exactp);
|
||||
void sl_slc_help (SL_cmd *cmds, int argc, char **argv);
|
||||
void sl_help_ext (SL_cmd *cmds, SL_cmd_info *info, int argc, char **argv);
|
||||
void sl_did_you_mean(SL_cmd *cmds, const char *match);
|
||||
|
||||
|
||||
|
||||
@@ -42,4 +42,5 @@
|
||||
|
||||
#include <roken.h>
|
||||
|
||||
#include <getarg.h>
|
||||
#include <sl.h>
|
||||
|
||||
@@ -486,6 +486,58 @@ gen_options(struct assignment *opt1, const char *name)
|
||||
hprint(0, "};\n");
|
||||
}
|
||||
|
||||
static int
|
||||
count_options(struct assignment *as)
|
||||
{
|
||||
struct assignment *tmp;
|
||||
int nargs = 0;
|
||||
for(tmp = find(as, "option"); tmp != NULL; tmp = find_next(tmp, "option"))
|
||||
nargs++;
|
||||
return nargs + 1; /* +1 for help */
|
||||
}
|
||||
|
||||
static void
|
||||
gen_args_array(struct assignment *as, const char *n)
|
||||
{
|
||||
struct assignment *tmp;
|
||||
|
||||
cprint(0, "static struct getargs %s_args[] = {\n", n);
|
||||
for(tmp = find(as, "option");
|
||||
tmp != NULL;
|
||||
tmp = find_next(tmp, "option")) {
|
||||
struct assignment *type = find(tmp->u.assignment, "type");
|
||||
struct assignment *lopt = find(tmp->u.assignment, "long");
|
||||
struct assignment *sopt = find(tmp->u.assignment, "short");
|
||||
struct assignment *aarg = find(tmp->u.assignment, "argument");
|
||||
struct assignment *help = find(tmp->u.assignment, "help");
|
||||
struct type_handler *th;
|
||||
|
||||
cprint(1, "{ ");
|
||||
if(lopt)
|
||||
fprintf(cfile, "\"%s\", ", lopt->u.value);
|
||||
else
|
||||
fprintf(cfile, "NULL, ");
|
||||
if(sopt)
|
||||
fprintf(cfile, "'%c', ", *sopt->u.value);
|
||||
else
|
||||
fprintf(cfile, "0, ");
|
||||
th = find_handler(type);
|
||||
fprintf(cfile, "%s, ", th->getarg_type);
|
||||
fprintf(cfile, "NULL, ");
|
||||
if(help)
|
||||
fprintf(cfile, "\"%s\", ", help->u.value);
|
||||
else
|
||||
fprintf(cfile, "NULL, ");
|
||||
if(aarg)
|
||||
fprintf(cfile, "\"%s\"", aarg->u.value);
|
||||
else
|
||||
fprintf(cfile, "NULL");
|
||||
fprintf(cfile, " },\n");
|
||||
}
|
||||
cprint(1, "{ \"help\", 'h', arg_flag, NULL, NULL, NULL }\n");
|
||||
cprint(0, "};\n\n");
|
||||
}
|
||||
|
||||
static void
|
||||
gen_wrapper(struct assignment *as)
|
||||
{
|
||||
@@ -519,6 +571,9 @@ gen_wrapper(struct assignment *as)
|
||||
hprint(0, "int %s(void*, int, char **);\n", f);
|
||||
}
|
||||
|
||||
/* Generate the static args array */
|
||||
gen_args_array(as, n);
|
||||
|
||||
fprintf(cfile, "static int\n");
|
||||
fprintf(cfile, "%s_wrap(int argc, char **argv)\n", n);
|
||||
fprintf(cfile, "{\n");
|
||||
@@ -526,43 +581,7 @@ gen_wrapper(struct assignment *as)
|
||||
cprint(1, "struct %s_options opt;\n", n);
|
||||
cprint(1, "int ret;\n");
|
||||
cprint(1, "int optidx = 0;\n");
|
||||
cprint(1, "struct getargs args[] = {\n");
|
||||
for(tmp = find(as, "option");
|
||||
tmp != NULL;
|
||||
tmp = find_next(tmp, "option")) {
|
||||
struct assignment *type = find(tmp->u.assignment, "type");
|
||||
struct assignment *lopt = find(tmp->u.assignment, "long");
|
||||
struct assignment *sopt = find(tmp->u.assignment, "short");
|
||||
struct assignment *aarg = find(tmp->u.assignment, "argument");
|
||||
struct assignment *help = find(tmp->u.assignment, "help");
|
||||
|
||||
struct type_handler *th;
|
||||
|
||||
cprint(2, "{ ");
|
||||
if(lopt)
|
||||
fprintf(cfile, "\"%s\", ", lopt->u.value);
|
||||
else
|
||||
fprintf(cfile, "NULL, ");
|
||||
if(sopt)
|
||||
fprintf(cfile, "'%c', ", *sopt->u.value);
|
||||
else
|
||||
fprintf(cfile, "0, ");
|
||||
th = find_handler(type);
|
||||
fprintf(cfile, "%s, ", th->getarg_type);
|
||||
fprintf(cfile, "NULL, ");
|
||||
if(help)
|
||||
fprintf(cfile, "\"%s\", ", help->u.value);
|
||||
else
|
||||
fprintf(cfile, "NULL, ");
|
||||
if(aarg) {
|
||||
fprintf(cfile, "\"%s\"", aarg->u.value);
|
||||
narguments++;
|
||||
} else
|
||||
fprintf(cfile, "NULL");
|
||||
fprintf(cfile, " },\n");
|
||||
}
|
||||
cprint(2, "{ \"help\", 'h', arg_flag, NULL, NULL, NULL }\n");
|
||||
cprint(1, "};\n");
|
||||
cprint(1, "struct getargs *args = %s_args;\n", n);
|
||||
cprint(1, "int help_flag = 0;\n");
|
||||
|
||||
for(tmp = find(as, "option");
|
||||
@@ -695,6 +714,28 @@ gen_wrapper(struct assignment *as)
|
||||
char cname[PATH_MAX];
|
||||
char hname[PATH_MAX];
|
||||
|
||||
static void
|
||||
gen_command_info(struct assignment *as)
|
||||
{
|
||||
struct assignment *a, *arg;
|
||||
char *n;
|
||||
|
||||
a = find(as, "name");
|
||||
n = strdup(a->u.value);
|
||||
gen_name(n);
|
||||
arg = find(as, "argument");
|
||||
|
||||
cprint(1, "{ \"%s\", ", a->u.value);
|
||||
if (arg)
|
||||
fprintf(cfile, "\"%s\", ", arg->u.value);
|
||||
else
|
||||
fprintf(cfile, "NULL, ");
|
||||
fprintf(cfile, "%s_args, ", n);
|
||||
fprintf(cfile, "%d ", count_options(as));
|
||||
fprintf(cfile, "},\n");
|
||||
free(n);
|
||||
}
|
||||
|
||||
static void
|
||||
gen(struct assignment *as)
|
||||
{
|
||||
@@ -707,6 +748,7 @@ gen(struct assignment *as)
|
||||
|
||||
hprint(0, "#include <stdio.h>\n");
|
||||
hprint(0, "#include <sl.h>\n");
|
||||
hprint(0, "#include <getarg.h>\n");
|
||||
hprint(0, "\n");
|
||||
|
||||
|
||||
@@ -717,9 +759,17 @@ gen(struct assignment *as)
|
||||
for(a = as; a != NULL; a = a->next)
|
||||
gen_command(a->u.assignment);
|
||||
cprint(1, "{ NULL, NULL, NULL, NULL }\n");
|
||||
cprint(0, "};\n\n");
|
||||
|
||||
/* Generate the commands_info array for mandoc generation */
|
||||
cprint(0, "SL_cmd_info commands_info[] = {\n");
|
||||
for(a = as; a != NULL; a = a->next)
|
||||
gen_command_info(a->u.assignment);
|
||||
cprint(1, "{ NULL, NULL, NULL, 0 }\n");
|
||||
cprint(0, "};\n");
|
||||
|
||||
hprint(0, "extern SL_cmd commands[];\n");
|
||||
hprint(0, "extern SL_cmd_info commands_info[];\n");
|
||||
}
|
||||
|
||||
int version_flag;
|
||||
|
||||
Reference in New Issue
Block a user