mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-31 21:18:26 +03:00
1535 lines
35 KiB
C
1535 lines
35 KiB
C
#include <asm/types.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/wait.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdarg.h>
|
|
#include <limits.h>
|
|
#include <unistd.h>
|
|
#include <syslog.h>
|
|
#include <sched.h>
|
|
#include <dirent.h>
|
|
#include <ctype.h>
|
|
#include <getopt.h>
|
|
|
|
|
|
/* needed to include args.h */
|
|
#define ARG_COUNTABLE 0x00000001
|
|
#define ARG_GROUPABLE 0x00000002
|
|
struct cmd_context;
|
|
struct arg_values;
|
|
int yes_no_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int activation_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int cachemode_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int discards_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int mirrorlog_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int size_kb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int int_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int major_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int minor_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int string_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int tag_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int permission_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int units_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int segtype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int alloc_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int locktype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int readahead_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
|
int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
|
|
|
|
struct opt_name {
|
|
const char *enum_name;
|
|
int enum_val;
|
|
const char short_opt;
|
|
char _padding[7];
|
|
const char *long_opt;
|
|
|
|
/* NULL if option takes no arg */
|
|
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
|
|
|
|
uint32_t unused1;
|
|
uint32_t unused2;
|
|
};
|
|
|
|
/* enum for opt names */
|
|
enum {
|
|
#define arg(a, b, c, d, e, f) a ,
|
|
#include "args.h"
|
|
#undef arg
|
|
};
|
|
|
|
static struct opt_name opt_names[ARG_COUNT + 1] = {
|
|
#define arg(a, b, c, d, e, f) { # a, a, b, "", "--" c, d, e, f},
|
|
#include "args.h"
|
|
#undef arg
|
|
};
|
|
|
|
#include "command.h"
|
|
|
|
#define MAX_CMD_NAMES 128
|
|
struct cmd_name {
|
|
const char *name;
|
|
};
|
|
|
|
static struct cmd_name cmd_names[MAX_CMD_NAMES] = {
|
|
#define xx(a, b...) { # a } ,
|
|
#include "commands.h"
|
|
#undef xx
|
|
};
|
|
|
|
#define MAX_LINE 1024
|
|
#define MAX_LINE_ARGC 256
|
|
|
|
#define REQUIRED 1
|
|
#define OPTIONAL 0
|
|
|
|
struct oo_line {
|
|
char *name;
|
|
char *line;
|
|
};
|
|
|
|
#define MAX_CMDS 256
|
|
int cmd_count;
|
|
struct command cmd_array[MAX_CMDS];
|
|
|
|
#define MAX_OO_LINES 256
|
|
int oo_line_count;
|
|
struct oo_line oo_lines[MAX_OO_LINES];
|
|
|
|
|
|
static void add_optional_opt_line(struct command *cmd, int argc, char *argv[]);
|
|
|
|
|
|
static int opt_str_to_num(char *str)
|
|
{
|
|
char long_name[32];
|
|
char *p;
|
|
int i;
|
|
|
|
/*
|
|
* --foo_long means there are two args entries
|
|
* for --foo, one with a short option and one
|
|
* without, and we want the one without the
|
|
* short option.
|
|
*/
|
|
if (strstr(str, "_long")) {
|
|
strcpy(long_name, str);
|
|
p = strstr(long_name, "_long");
|
|
*p = '\0';
|
|
|
|
for (i = 0; i < ARG_COUNT; i++) {
|
|
if (!opt_names[i].long_opt)
|
|
continue;
|
|
/* skip anything with a short opt */
|
|
if (opt_names[i].short_opt)
|
|
continue;
|
|
if (!strcmp(opt_names[i].long_opt, long_name))
|
|
return opt_names[i].enum_val;
|
|
}
|
|
|
|
printf("Unknown opt str: %s %s\n", str, long_name);
|
|
exit(1);
|
|
}
|
|
|
|
for (i = 0; i < ARG_COUNT; i++) {
|
|
if (!opt_names[i].long_opt)
|
|
continue;
|
|
/* These are only selected using --foo_long */
|
|
if (strstr(opt_names[i].enum_name, "_long_ARG"))
|
|
continue;
|
|
if (!strcmp(opt_names[i].long_opt, str))
|
|
return opt_names[i].enum_val;
|
|
}
|
|
|
|
printf("Unknown opt str: \"%s\"\n", str);
|
|
exit(1);
|
|
}
|
|
|
|
static int lv_str_to_num(char *str)
|
|
{
|
|
char name[32] = { 0 };
|
|
char *new;
|
|
int i;
|
|
|
|
/* compare the lv name before the _new suffix */
|
|
|
|
strncpy(name, str, 31);
|
|
if ((new = strstr(name, "_new")))
|
|
*new = '\0';
|
|
|
|
if (!strcmp(name, "LV"))
|
|
return 0;
|
|
|
|
for (i = 1; i < ARG_DEF_LVS; i++) {
|
|
if (!arg_def_lvs[i].name)
|
|
break;
|
|
|
|
if (!strcmp(name, arg_def_lvs[i].name))
|
|
return arg_def_lvs[i].flag;
|
|
}
|
|
|
|
printf("Unknown LV type: \"%s\" \"%s\"\n", name, str);
|
|
exit(1);
|
|
}
|
|
|
|
static int type_str_to_num(char *str)
|
|
{
|
|
char name[32] = { 0 };
|
|
char *new;
|
|
int i;
|
|
|
|
/* compare the name before the _new suffix */
|
|
|
|
strncpy(name, str, 31);
|
|
if ((new = strstr(name, "_new")))
|
|
*new = '\0';
|
|
|
|
for (i = 0; i < ARG_DEF_TYPES; i++) {
|
|
if (!arg_def_types[i].name)
|
|
break;
|
|
if (!strncmp(name, arg_def_types[i].name, strlen(arg_def_types[i].name)))
|
|
return arg_def_types[i].flag;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* modifies buf, replacing the sep characters with \0
|
|
* argv pointers point to positions in buf
|
|
*/
|
|
|
|
static char *split_line(char *buf, int *argc, char **argv, char sep)
|
|
{
|
|
char *p = buf, *rp = NULL;
|
|
int i;
|
|
|
|
argv[0] = p;
|
|
|
|
for (i = 1; i < MAX_LINE_ARGC; i++) {
|
|
p = strchr(buf, sep);
|
|
if (!p)
|
|
break;
|
|
*p = '\0';
|
|
|
|
argv[i] = p + 1;
|
|
buf = p + 1;
|
|
}
|
|
*argc = i;
|
|
|
|
/* we ended by hitting \0, return the point following that */
|
|
if (!rp)
|
|
rp = strchr(buf, '\0') + 1;
|
|
|
|
return rp;
|
|
}
|
|
|
|
static const char *is_command_name(char *str)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_CMD_NAMES; i++) {
|
|
if (!cmd_names[i].name)
|
|
break;
|
|
if (!strcmp(cmd_names[i].name, str))
|
|
return cmd_names[i].name;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int is_opt_name(char *str)
|
|
{
|
|
if (!strncmp(str, "--", 2))
|
|
return 1;
|
|
|
|
if ((str[0] == '-') && (str[1] != '-')) {
|
|
printf("Options must be specified in long form: %s\n", str);
|
|
exit(1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* "Select" as a pos name means that the position
|
|
* can be empty if the --select option is used.
|
|
*/
|
|
|
|
static int is_pos_name(char *str)
|
|
{
|
|
if (!strncmp(str, "VG", 2))
|
|
return 1;
|
|
if (!strncmp(str, "LV", 2))
|
|
return 1;
|
|
if (!strncmp(str, "PV", 2))
|
|
return 1;
|
|
if (!strncmp(str, "Tag", 3))
|
|
return 1;
|
|
if (!strncmp(str, "String", 6))
|
|
return 1;
|
|
if (!strncmp(str, "Select", 6))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int is_oo_definition(char *str)
|
|
{
|
|
if (!strncmp(str, "OO_", 3))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int is_oo_line(char *str)
|
|
{
|
|
if (!strncmp(str, "OO:", 3))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int is_op_line(char *str)
|
|
{
|
|
if (!strncmp(str, "OP:", 3))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int is_desc_line(char *str)
|
|
{
|
|
if (!strncmp(str, "DESC:", 5))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* parse str for anything that can appear in a position,
|
|
* like VG, VG|LV, VG|LV_linear|LV_striped, etc
|
|
*/
|
|
|
|
static void set_pos_def(struct command *cmd, char *str, struct arg_def *def)
|
|
{
|
|
char *argv[MAX_LINE_ARGC];
|
|
int argc;
|
|
char *name;
|
|
int type_num;
|
|
int i;
|
|
|
|
split_line(str, &argc, argv, '|');
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
name = argv[i];
|
|
|
|
type_num = type_str_to_num(name);
|
|
|
|
if (!type_num) {
|
|
printf("Unknown pos arg: %s\n", name);
|
|
exit(1);
|
|
}
|
|
|
|
def->types |= type_num;
|
|
|
|
if ((type_num == ARG_DEF_TYPE_NAME_LV) && strstr(name, "_"))
|
|
def->lv_types |= lv_str_to_num(name);
|
|
|
|
if (strstr(name, "_new"))
|
|
def->flags |= ARG_DEF_FLAG_NEW;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* parse str for anything that can follow --option
|
|
*/
|
|
|
|
static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
|
|
{
|
|
char *argv[MAX_LINE_ARGC];
|
|
int argc;
|
|
char *name;
|
|
int type_num;
|
|
int i, j;
|
|
|
|
split_line(str, &argc, argv, '|');
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
name = argv[i];
|
|
|
|
type_num = type_str_to_num(name);
|
|
|
|
if (!type_num) {
|
|
/* a literal number or string */
|
|
|
|
if (isdigit(name[0]))
|
|
type_num = ARG_DEF_TYPE_NUM_CONST;
|
|
|
|
else if (isalpha(name[0]))
|
|
type_num = ARG_DEF_TYPE_STR_CONST;
|
|
|
|
else {
|
|
printf("Unknown opt arg: %s\n", name);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
|
|
switch (type_num) {
|
|
case ARG_DEF_TYPE_NONE:
|
|
break;
|
|
|
|
case ARG_DEF_TYPE_BOOL:
|
|
case ARG_DEF_TYPE_NUM_ANY:
|
|
case ARG_DEF_TYPE_STR_ANY:
|
|
case ARG_DEF_TYPE_NAME_ANY:
|
|
case ARG_DEF_TYPE_NAME_PV:
|
|
case ARG_DEF_TYPE_NAME_VG:
|
|
case ARG_DEF_TYPE_TAG:
|
|
def->types |= type_num;
|
|
break;
|
|
|
|
case ARG_DEF_TYPE_NUM_CONST:
|
|
def->types |= type_num;
|
|
def->num = (uint64_t)atoi(name);
|
|
break;
|
|
|
|
case ARG_DEF_TYPE_STR_CONST:
|
|
if (def->types & ARG_DEF_TYPE_STR_CONST) {
|
|
def->types &= ~ARG_DEF_TYPE_STR_CONST;
|
|
def->types |= ARG_DEF_TYPE_STR_SET;
|
|
def->str_set[0] = def->str;
|
|
def->str = NULL;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_STR_SET) {
|
|
for (j = 0; j < MAX_STR_SET; j++) {
|
|
if (def->str_set[j])
|
|
continue;
|
|
def->str_set[j] = strdup(name);
|
|
break;
|
|
}
|
|
} else {
|
|
def->types |= type_num;
|
|
def->str = strdup(name);
|
|
}
|
|
break;
|
|
|
|
case ARG_DEF_TYPE_NAME_LV:
|
|
def->types |= type_num;
|
|
if (strstr(name, "_"))
|
|
def->lv_types |= lv_str_to_num(name);
|
|
break;
|
|
}
|
|
|
|
if ((type_num == ARG_DEF_TYPE_NAME_VG) ||
|
|
(type_num == ARG_DEF_TYPE_NAME_LV) ||
|
|
(type_num == ARG_DEF_TYPE_NAME_PV)) {
|
|
if (strstr(name, "_new"))
|
|
def->flags |= ARG_DEF_FLAG_NEW;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* OO_FOO: --opt1 ...
|
|
*
|
|
* oo->name = "OO_FOO";
|
|
* oo->line = "--opt1 ...";
|
|
*/
|
|
|
|
static void add_oo_definition_line(const char *name, const char *line)
|
|
{
|
|
struct oo_line *oo;
|
|
char *colon;
|
|
char *start;
|
|
|
|
oo = &oo_lines[oo_line_count++];
|
|
oo->name = strdup(name);
|
|
|
|
if ((colon = strstr(oo->name, ":")))
|
|
*colon = '\0';
|
|
else {
|
|
printf("invalid OO definition\n");
|
|
exit(1);
|
|
}
|
|
|
|
start = strstr(line, ":") + 2;
|
|
oo->line = strdup(start);
|
|
}
|
|
|
|
/* when OO_FOO: continues on multiple lines */
|
|
|
|
static void append_oo_definition_line(const char *new_line)
|
|
{
|
|
struct oo_line *oo;
|
|
char *old_line;
|
|
char *line;
|
|
int len;
|
|
|
|
oo = &oo_lines[oo_line_count-1];
|
|
|
|
old_line = oo->line;
|
|
|
|
/* +2 = 1 space between old and new + 1 terminating \0 */
|
|
len = strlen(old_line) + strlen(new_line) + 2;
|
|
line = malloc(len);
|
|
memset(line, 0, len);
|
|
|
|
strcat(line, old_line);
|
|
strcat(line, " ");
|
|
strcat(line, new_line);
|
|
|
|
free(oo->line);
|
|
oo->line = line;
|
|
}
|
|
|
|
char *get_oo_line(char *str)
|
|
{
|
|
char *name;
|
|
char *end;
|
|
char str2[64];
|
|
int i;
|
|
|
|
strcpy(str2, str);
|
|
if ((end = strstr(str2, ":")))
|
|
*end = '\0';
|
|
if ((end = strstr(str2, ",")))
|
|
*end = '\0';
|
|
|
|
for (i = 0; i < oo_line_count; i++) {
|
|
name = oo_lines[i].name;
|
|
if (!strcmp(name, str2))
|
|
return oo_lines[i].line;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* add optional_opt_args entries when OO_FOO appears on OO: line */
|
|
|
|
static void include_optional_opt_args(struct command *cmd, char *str)
|
|
{
|
|
char *oo_line;
|
|
char *line;
|
|
char *line_argv[MAX_LINE_ARGC];
|
|
int line_argc;
|
|
|
|
if (!(oo_line = get_oo_line(str))) {
|
|
printf("No OO line found for %s\n", str);
|
|
exit(1);
|
|
}
|
|
|
|
if (!(line = strdup(oo_line)))
|
|
exit(1);
|
|
|
|
split_line(line, &line_argc, line_argv, ' ');
|
|
add_optional_opt_line(cmd, line_argc, line_argv);
|
|
free(line);
|
|
}
|
|
|
|
static void add_opt_arg(struct command *cmd, char *str, int *takes_arg, int required)
|
|
{
|
|
char *comma;
|
|
int opt;
|
|
|
|
/* opt_arg.opt set here */
|
|
/* opt_arg.def will be set in update_prev_opt_arg() if needed */
|
|
|
|
if ((comma = strstr(str, ",")))
|
|
*comma = '\0';
|
|
|
|
/*
|
|
* Work around nasty hack where --uuid is used for both uuid_ARG
|
|
* and uuidstr_ARG. The input uses --uuidstr, where an actual
|
|
* command uses --uuid string.
|
|
*/
|
|
if (!strcmp(str, "--uuidstr")) {
|
|
opt = uuidstr_ARG;
|
|
goto skip;
|
|
}
|
|
|
|
opt = opt_str_to_num(str);
|
|
skip:
|
|
if (required)
|
|
cmd->required_opt_args[cmd->ro_count++].opt = opt;
|
|
else
|
|
cmd->optional_opt_args[cmd->oo_count++].opt = opt;
|
|
|
|
*takes_arg = opt_names[opt].fn ? 1 : 0;
|
|
}
|
|
|
|
static void update_prev_opt_arg(struct command *cmd, char *str, int required)
|
|
{
|
|
struct arg_def def = { 0 };
|
|
char *comma;
|
|
|
|
if (str[0] == '-') {
|
|
printf("Option %s must be followed by an arg.\n", str);
|
|
exit(1);
|
|
}
|
|
|
|
/* opt_arg.def set here */
|
|
/* opt_arg.opt was previously set in add_opt_arg() when --foo was read */
|
|
|
|
if ((comma = strstr(str, ",")))
|
|
*comma = '\0';
|
|
|
|
set_opt_def(cmd, str, &def);
|
|
|
|
if (required)
|
|
cmd->required_opt_args[cmd->ro_count-1].def = def;
|
|
else
|
|
cmd->optional_opt_args[cmd->oo_count-1].def = def;
|
|
}
|
|
|
|
static void add_pos_arg(struct command *cmd, char *str, int required)
|
|
{
|
|
struct arg_def def = { 0 };
|
|
|
|
/* pos_arg.pos and pos_arg.def are set here */
|
|
|
|
set_pos_def(cmd, str, &def);
|
|
|
|
if (required) {
|
|
cmd->required_pos_args[cmd->rp_count].pos = cmd->pos_count++;
|
|
cmd->required_pos_args[cmd->rp_count].def = def;
|
|
cmd->rp_count++;
|
|
} else {
|
|
cmd->optional_pos_args[cmd->op_count].pos = cmd->pos_count++;;
|
|
cmd->optional_pos_args[cmd->op_count].def = def;
|
|
cmd->op_count++;
|
|
}
|
|
}
|
|
|
|
/* process something that follows a pos arg, which is not a new pos arg */
|
|
|
|
static void update_prev_pos_arg(struct command *cmd, char *str, int required)
|
|
{
|
|
struct arg_def *def;
|
|
|
|
/* a previous pos_arg.def is modified here */
|
|
|
|
if (required)
|
|
def = &cmd->required_pos_args[cmd->rp_count-1].def;
|
|
else
|
|
def = &cmd->optional_pos_args[cmd->op_count-1].def;
|
|
|
|
if (!strcmp(str, "..."))
|
|
def->flags |= ARG_DEF_FLAG_MAY_REPEAT;
|
|
else {
|
|
printf("Unknown pos arg: %s\n", str);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* process what follows OO:, which are optional opt args */
|
|
|
|
static void add_optional_opt_line(struct command *cmd, int argc, char *argv[])
|
|
{
|
|
int takes_arg;
|
|
int i;
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
if (!i && !strncmp(argv[i], "OO:", 3))
|
|
continue;
|
|
if (is_opt_name(argv[i]))
|
|
add_opt_arg(cmd, argv[i], &takes_arg, OPTIONAL);
|
|
else if (!strncmp(argv[i], "OO_", 3))
|
|
include_optional_opt_args(cmd, argv[i]);
|
|
else if (takes_arg)
|
|
update_prev_opt_arg(cmd, argv[i], OPTIONAL);
|
|
else
|
|
printf("Can't parse argc %d argv %s prev %s\n",
|
|
i, argv[i], argv[i-1]);
|
|
}
|
|
}
|
|
|
|
/* process what follows OP:, which are optional pos args */
|
|
|
|
static void add_optional_pos_line(struct command *cmd, int argc, char *argv[])
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
if (!i && !strncmp(argv[i], "OP:", 3))
|
|
continue;
|
|
if (is_pos_name(argv[i]))
|
|
add_pos_arg(cmd, argv[i], OPTIONAL);
|
|
else
|
|
update_prev_pos_arg(cmd, argv[i], OPTIONAL);
|
|
}
|
|
}
|
|
|
|
/* add required opt args from OO_FOO definition */
|
|
|
|
static void add_required_opt_line(struct command *cmd, int argc, char *argv[])
|
|
{
|
|
int takes_arg;
|
|
int i;
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
if (is_opt_name(argv[i]))
|
|
add_opt_arg(cmd, argv[i], &takes_arg, REQUIRED);
|
|
else if (takes_arg)
|
|
update_prev_opt_arg(cmd, argv[i], REQUIRED);
|
|
else
|
|
printf("Can't parse argc %d argv %s prev %s\n",
|
|
i, argv[i], argv[i-1]);
|
|
}
|
|
}
|
|
|
|
/* add to required_opt_args when OO_FOO appears on required line */
|
|
|
|
static void include_required_opt_args(struct command *cmd, char *str)
|
|
{
|
|
char *oo_line;
|
|
char *line;
|
|
char *line_argv[MAX_LINE_ARGC];
|
|
int line_argc;
|
|
|
|
if (!(oo_line = get_oo_line(str))) {
|
|
printf("No OO line found for %s\n", str);
|
|
exit(1);
|
|
}
|
|
|
|
if (!(line = strdup(oo_line)))
|
|
exit(1);
|
|
|
|
split_line(line, &line_argc, line_argv, ' ');
|
|
add_required_opt_line(cmd, line_argc, line_argv);
|
|
free(line);
|
|
}
|
|
|
|
/* process what follows command_name, which are required opt/pos args */
|
|
|
|
static void add_required_line(struct command *cmd, int argc, char *argv[])
|
|
{
|
|
int i;
|
|
int takes_arg;
|
|
int prev_was_opt = 0, prev_was_pos = 0;
|
|
|
|
/* argv[0] is command name */
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
if (is_opt_name(argv[i])) {
|
|
add_opt_arg(cmd, argv[i], &takes_arg, REQUIRED);
|
|
prev_was_opt = 1;
|
|
prev_was_pos = 0;
|
|
} else if (prev_was_opt && takes_arg) {
|
|
update_prev_opt_arg(cmd, argv[i], REQUIRED);
|
|
prev_was_opt = 0;
|
|
prev_was_pos = 0;
|
|
} else if (is_pos_name(argv[i])) {
|
|
add_pos_arg(cmd, argv[i], REQUIRED);
|
|
prev_was_opt = 0;
|
|
prev_was_pos = 1;
|
|
} else if (!strncmp(argv[i], "OO_", 3)) {
|
|
cmd->cmd_flags |= CMD_FLAG_ONE_REQUIRED_OPT;
|
|
include_required_opt_args(cmd, argv[i]);
|
|
} else if (prev_was_pos) {
|
|
update_prev_pos_arg(cmd, argv[i], REQUIRED);
|
|
} else
|
|
printf("Can't parse argc %d argv %s prev %s\n",
|
|
i, argv[i], argv[i-1]);
|
|
|
|
}
|
|
}
|
|
|
|
static void print_def(struct arg_def *def)
|
|
{
|
|
int sep = 0;
|
|
int i;
|
|
|
|
if (def->types & ARG_DEF_TYPE_BOOL) {
|
|
if (sep) printf("|");
|
|
printf("Bool");
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_NUM_ANY) {
|
|
if (sep) printf("|");
|
|
printf("Number");
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_STR_ANY) {
|
|
if (sep) printf("|");
|
|
printf("String");
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_NAME_ANY) {
|
|
if (sep) printf("|");
|
|
printf("Name");
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_NAME_PV) {
|
|
if (sep) printf("|");
|
|
printf("PV");
|
|
if (def->flags & ARG_DEF_FLAG_NEW)
|
|
printf("_new");
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_NAME_VG) {
|
|
if (sep) printf("|");
|
|
printf("VG");
|
|
if (def->flags & ARG_DEF_FLAG_NEW)
|
|
printf("_new");
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_NAME_LV) {
|
|
if (!def->lv_types) {
|
|
if (sep) printf("|");
|
|
printf("LV");
|
|
sep = 1;
|
|
} else {
|
|
for (i = 0; i < ARG_DEF_LVS; i++) {
|
|
if (def->lv_types & arg_def_lvs[i].flag) {
|
|
if (sep) printf("|");
|
|
printf("%s", arg_def_lvs[i].name);
|
|
sep = 1;
|
|
}
|
|
}
|
|
}
|
|
if (def->flags & ARG_DEF_FLAG_NEW)
|
|
printf("_new");
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_TAG) {
|
|
if (sep) printf("|");
|
|
printf("Tag");
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_SELECT) {
|
|
if (sep) printf("|");
|
|
printf("Select");
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_STR_CONST) {
|
|
if (sep) printf("|");
|
|
printf("%s", def->str);
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_NUM_CONST) {
|
|
if (sep) printf("|");
|
|
printf("%llu", def->num);
|
|
sep = 1;
|
|
}
|
|
|
|
if (def->types & ARG_DEF_TYPE_STR_SET) {
|
|
for (i = 0; i < MAX_STR_SET; i++) {
|
|
if (def->str_set[i]) {
|
|
if (sep) printf("|");
|
|
printf("%s", def->str_set[i]);
|
|
sep = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (def->flags & ARG_DEF_FLAG_MAY_REPEAT)
|
|
printf(" ...");
|
|
}
|
|
|
|
void print_data_expanded(void)
|
|
{
|
|
struct command *cmd;
|
|
int i, ro, rp, oo, op;
|
|
|
|
for (i = 0; i < cmd_count; i++) {
|
|
cmd = &cmd_array[i];
|
|
printf("%s", cmd->name);
|
|
|
|
if (cmd->ro_count) {
|
|
for (ro = 0; ro < cmd->ro_count; ro++) {
|
|
printf(" %s", opt_names[cmd->required_opt_args[ro].opt].long_opt);
|
|
if (cmd->required_opt_args[ro].def.types) {
|
|
printf(" ");
|
|
print_def(&cmd->required_opt_args[ro].def);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cmd->rp_count) {
|
|
for (rp = 0; rp < cmd->rp_count; rp++) {
|
|
if (cmd->required_pos_args[rp].def.types) {
|
|
printf(" ");
|
|
print_def(&cmd->required_pos_args[rp].def);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cmd->oo_count) {
|
|
printf("\n");
|
|
printf("OO:");
|
|
for (oo = 0; oo < cmd->oo_count; oo++) {
|
|
if (oo)
|
|
printf(",");
|
|
printf(" %s", opt_names[cmd->optional_opt_args[oo].opt].long_opt);
|
|
if (cmd->optional_opt_args[oo].def.types) {
|
|
printf(" ");
|
|
print_def(&cmd->optional_opt_args[oo].def);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cmd->op_count) {
|
|
printf("\n");
|
|
printf("OP:");
|
|
for (op = 0; op < cmd->op_count; op++) {
|
|
if (cmd->optional_pos_args[op].def.types) {
|
|
printf(" ");
|
|
print_def(&cmd->optional_pos_args[op].def);
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("\n\n");
|
|
}
|
|
}
|
|
|
|
static const char *opt_to_enum_str(int opt)
|
|
{
|
|
return opt_names[opt].enum_name;
|
|
}
|
|
|
|
static char *type_num_to_flags(int types)
|
|
{
|
|
static char buf[128];
|
|
int or = 0;
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
if (types & ARG_DEF_TYPE_BOOL) {
|
|
strcat(buf, "ARG_DEF_TYPE_BOOL");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_NUM_ANY) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_NUM_ANY");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_STR_ANY) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_STR_ANY");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_NUM_CONST) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_NUM_CONST");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_STR_CONST) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_STR_CONST");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_STR_SET) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_STR_SET");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_NAME_ANY) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_NAME_ANY");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_NAME_PV) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_NAME_PV");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_NAME_VG) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_NAME_VG");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_NAME_LV) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_NAME_LV");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_TAG) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_TAG");
|
|
or = 1;
|
|
}
|
|
|
|
if (types & ARG_DEF_TYPE_SELECT) {
|
|
if (or) strcat(buf, "|");
|
|
strcat(buf, "ARG_DEF_TYPE_SELECT");
|
|
or = 1;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
static char *lv_num_to_flags(int lv_types)
|
|
{
|
|
static char buf_lv_types[128];
|
|
int or = 0;
|
|
|
|
memset(buf_lv_types, 0, sizeof(buf_lv_types));
|
|
|
|
if (lv_types & ARG_DEF_LV_LINEAR) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_LINEAR");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_STRIPED) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_STRIPED");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_SNAPSHOT) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_SNAPSHOT");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_MIRROR) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_MIRROR");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_RAID) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_RAID");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_RAID0) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_RAID0");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_RAID1) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_RAID1");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_RAID4) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_RAID4");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_RAID5) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_RAID5");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_RAID6) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_RAID6");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_RAID10) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_RAID10");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_THIN) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_THIN");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_THINPOOL) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_THINPOOL");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_CACHE) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_CACHE");
|
|
or = 1;
|
|
}
|
|
|
|
if (lv_types & ARG_DEF_LV_CACHEPOOL) {
|
|
if (or) strcat(buf_lv_types, "|");
|
|
strcat(buf_lv_types, "ARG_DEF_LV_CACHEPOOL");
|
|
or = 1;
|
|
}
|
|
|
|
return buf_lv_types;
|
|
}
|
|
|
|
static char *flags_to_str(int flags)
|
|
{
|
|
static char buf_flags[32];
|
|
|
|
memset(buf_flags, 0, sizeof(buf_flags));
|
|
|
|
if (flags & ARG_DEF_FLAG_MAY_REPEAT)
|
|
strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT");
|
|
if (flags & ARG_DEF_FLAG_NEW)
|
|
strcat(buf_flags, "ARG_DEF_FLAG_NEW");
|
|
|
|
return buf_flags;
|
|
}
|
|
|
|
void print_define_command_count(void)
|
|
{
|
|
printf("#define COMMAND_COUNT %d\n", cmd_count);
|
|
}
|
|
|
|
void print_usage(struct command *cmd)
|
|
{
|
|
int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
|
|
int i, ro, rp, oo, op;
|
|
|
|
printf("\"%s", cmd->name);
|
|
|
|
if (cmd->ro_count) {
|
|
if (onereq)
|
|
printf(" (");
|
|
for (ro = 0; ro < cmd->ro_count; ro++) {
|
|
if (ro && onereq)
|
|
printf(",");
|
|
printf(" %s", opt_names[cmd->required_opt_args[ro].opt].long_opt);
|
|
|
|
if (cmd->required_opt_args[ro].def.types) {
|
|
printf(" ");
|
|
print_def(&cmd->required_opt_args[ro].def);
|
|
}
|
|
}
|
|
if (onereq)
|
|
printf(" )");
|
|
}
|
|
|
|
if (cmd->rp_count) {
|
|
for (rp = 0; rp < cmd->rp_count; rp++) {
|
|
if (cmd->required_pos_args[rp].def.types) {
|
|
printf(" ");
|
|
print_def(&cmd->required_pos_args[rp].def);
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("\"");
|
|
|
|
if (!cmd->oo_count)
|
|
goto op_count;
|
|
|
|
printf("\n");
|
|
printf("\"[");
|
|
|
|
if (cmd->oo_count) {
|
|
for (oo = 0; oo < cmd->oo_count; oo++) {
|
|
if (oo)
|
|
printf(",");
|
|
printf(" %s", opt_names[cmd->optional_opt_args[oo].opt].long_opt);
|
|
if (cmd->optional_opt_args[oo].def.types) {
|
|
printf(" ");
|
|
print_def(&cmd->optional_opt_args[oo].def);
|
|
}
|
|
}
|
|
}
|
|
|
|
printf(" ]\"");
|
|
|
|
op_count:
|
|
if (!cmd->op_count)
|
|
goto done;
|
|
|
|
printf("\n");
|
|
printf("\"[");
|
|
|
|
if (cmd->op_count) {
|
|
for (op = 0; op < cmd->op_count; op++) {
|
|
if (cmd->optional_pos_args[op].def.types) {
|
|
printf(" ");
|
|
print_def(&cmd->optional_pos_args[op].def);
|
|
}
|
|
}
|
|
}
|
|
|
|
printf(" ]\"");
|
|
|
|
done:
|
|
printf(";\n");
|
|
}
|
|
|
|
void print_command_count(void)
|
|
{
|
|
printf("#define COMMAND_COUNT %d\n", cmd_count);
|
|
}
|
|
|
|
void print_command_structs(void)
|
|
{
|
|
struct command *cmd;
|
|
int i, j, ro, rp, oo, op;
|
|
|
|
for (i = 0; i < cmd_count; i++) {
|
|
cmd = &cmd_array[i];
|
|
|
|
printf("commands[%d].name = \"%s\";\n", i, cmd->name);
|
|
printf("commands[%d].fn = %s;\n", i, cmd->name);
|
|
printf("commands[%d].desc = \"%s\";\n", i, cmd->desc ?: "");
|
|
printf("commands[%d].usage = ", i);
|
|
print_usage(cmd);
|
|
|
|
if (cmd->ro_count) {
|
|
for (ro = 0; ro < cmd->ro_count; ro++) {
|
|
printf("commands[%d].required_opt_args[%d].opt = %s;\n",
|
|
i, ro, opt_to_enum_str(cmd->required_opt_args[ro].opt));
|
|
|
|
if (!cmd->required_opt_args[ro].def.types)
|
|
continue;
|
|
|
|
printf("commands[%d].required_opt_args[%d].def.types = %s;\n",
|
|
i, ro, type_num_to_flags(cmd->required_opt_args[ro].def.types));
|
|
|
|
if (cmd->required_opt_args[ro].def.lv_types)
|
|
printf("commands[%d].required_opt_args[%d].def.lv_types = %s;\n",
|
|
i, ro, lv_num_to_flags(cmd->required_opt_args[ro].def.lv_types));
|
|
if (cmd->required_opt_args[ro].def.types & ARG_DEF_TYPE_NUM_CONST)
|
|
printf("commands[%d].required_opt_args[%d].def.num = %d;\n",
|
|
i, ro, cmd->required_opt_args[ro].def.num);
|
|
if (cmd->required_opt_args[ro].def.flags)
|
|
printf("commands[%d].required_opt_args[%d].def.flags = %s;\n",
|
|
i, ro, flags_to_str(cmd->required_opt_args[ro].def.flags));
|
|
if (cmd->required_opt_args[ro].def.types & ARG_DEF_TYPE_STR_CONST)
|
|
printf("commands[%d].required_opt_args[%d].def.str = \"%s\";\n",
|
|
i, ro, cmd->required_opt_args[ro].def.str ?: "NULL");
|
|
if (cmd->required_opt_args[ro].def.types & ARG_DEF_TYPE_STR_SET) {
|
|
for (j = 0; j < MAX_STR_SET; j++) {
|
|
if (cmd->required_opt_args[ro].def.str_set[j])
|
|
printf("commands[%d].required_opt_args[%d].def.str_set[%d] = %s;\n",
|
|
i, ro, j, cmd->required_opt_args[ro].def.str_set[j] ?: "NULL");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cmd->rp_count) {
|
|
for (rp = 0; rp < cmd->rp_count; rp++) {
|
|
printf("commands[%d].required_pos_args[%d].pos = %d;\n",
|
|
i, rp, cmd->required_pos_args[rp].pos);
|
|
|
|
if (!cmd->required_pos_args[rp].def.types)
|
|
continue;
|
|
|
|
printf("commands[%d].required_pos_args[%d].def.types = %s;\n",
|
|
i, rp, type_num_to_flags(cmd->required_pos_args[rp].def.types));
|
|
|
|
if (cmd->required_pos_args[rp].def.lv_types)
|
|
printf("commands[%d].required_pos_args[%d].def.lv_types = %s;\n",
|
|
i, rp, lv_num_to_flags(cmd->required_pos_args[rp].def.lv_types));
|
|
if (cmd->required_pos_args[rp].def.types & ARG_DEF_TYPE_NUM_CONST)
|
|
printf("commands[%d].required_pos_args[%d].def.num = %d;\n",
|
|
i, rp, cmd->required_pos_args[rp].def.num);
|
|
if (cmd->required_pos_args[rp].def.flags)
|
|
printf("commands[%d].required_pos_args[%d].def.flags = %s;\n",
|
|
i, rp, flags_to_str(cmd->required_pos_args[rp].def.flags));
|
|
if (cmd->required_pos_args[rp].def.types & ARG_DEF_TYPE_STR_CONST)
|
|
printf("commands[%d].required_pos_args[%d].def.str = \"%s\";\n",
|
|
i, rp, cmd->required_pos_args[rp].def.str ?: "NULL");
|
|
if (cmd->required_pos_args[rp].def.types & ARG_DEF_TYPE_STR_SET) {
|
|
for (j = 0; j < MAX_STR_SET; j++) {
|
|
if (cmd->required_pos_args[rp].def.str_set[j])
|
|
printf("commands[%d].required_pos_args[%d].def.str_set[%d] = \"%s\";\n",
|
|
i, rp, j, cmd->required_pos_args[rp].def.str_set[j] ?: "NULL");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cmd->oo_count) {
|
|
for (oo = 0; oo < cmd->oo_count; oo++) {
|
|
printf("commands[%d].optional_opt_args[%d].opt = %s;\n",
|
|
i, oo, opt_to_enum_str(cmd->optional_opt_args[oo].opt));
|
|
|
|
if (!cmd->optional_opt_args[oo].def.types)
|
|
continue;
|
|
|
|
printf("commands[%d].optional_opt_args[%d].def.types = %s;\n",
|
|
i, oo, type_num_to_flags(cmd->optional_opt_args[oo].def.types));
|
|
|
|
if (cmd->optional_opt_args[oo].def.lv_types)
|
|
printf("commands[%d].optional_opt_args[%d].def.lv_types = %s;\n",
|
|
i, oo, lv_num_to_flags(cmd->optional_opt_args[oo].def.lv_types));
|
|
if (cmd->optional_opt_args[oo].def.types & ARG_DEF_TYPE_NUM_CONST)
|
|
printf("commands[%d].optional_opt_args[%d].def.num = %d;\n",
|
|
i, oo, cmd->optional_opt_args[oo].def.num);
|
|
if (cmd->optional_opt_args[oo].def.flags)
|
|
printf("commands[%d].optional_opt_args[%d].def.flags = %s;\n",
|
|
i, oo, flags_to_str(cmd->optional_opt_args[oo].def.flags));
|
|
if (cmd->optional_opt_args[oo].def.types & ARG_DEF_TYPE_STR_CONST)
|
|
printf("commands[%d].optional_opt_args[%d].def.str = \"%s\";\n",
|
|
i, oo, cmd->optional_opt_args[oo].def.str ?: "NULL");
|
|
if (cmd->optional_opt_args[oo].def.types & ARG_DEF_TYPE_STR_SET) {
|
|
for (j = 0; j < MAX_STR_SET; j++) {
|
|
if (cmd->optional_opt_args[oo].def.str_set[j])
|
|
printf("commands[%d].optional_opt_args[%d].def.str_set[%d] = \"%s\";\n",
|
|
i, oo, j, cmd->optional_opt_args[oo].def.str_set[j] ?: "NULL");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cmd->op_count) {
|
|
for (op = 0; op < cmd->op_count; op++) {
|
|
printf("commands[%d].optional_pos_args[%d].pos = %d;\n",
|
|
i, op, cmd->optional_pos_args[op].pos);
|
|
|
|
if (!cmd->optional_pos_args[op].def.types)
|
|
continue;
|
|
|
|
printf("commands[%d].optional_pos_args[%d].def.types = %s;\n",
|
|
i, op, type_num_to_flags(cmd->optional_pos_args[op].def.types));
|
|
|
|
if (cmd->optional_pos_args[op].def.lv_types)
|
|
printf("commands[%d].optional_pos_args[%d].def.lv_types = %s;\n",
|
|
i, op, lv_num_to_flags(cmd->optional_pos_args[op].def.lv_types));
|
|
if (cmd->optional_pos_args[op].def.types & ARG_DEF_TYPE_NUM_CONST)
|
|
printf("commands[%d].optional_pos_args[%d].def.num = %d;\n",
|
|
i, op, cmd->optional_pos_args[op].def.num);
|
|
if (cmd->optional_pos_args[op].def.flags)
|
|
printf("commands[%d].optional_pos_args[%d].def.flags = %s;\n",
|
|
i, op, flags_to_str(cmd->optional_pos_args[op].def.flags));
|
|
if (cmd->optional_pos_args[op].def.types & ARG_DEF_TYPE_STR_CONST)
|
|
printf("commands[%d].optional_pos_args[%d].def.str = \"%s\";\n",
|
|
i, op, cmd->optional_pos_args[op].def.str ?: "NULL");
|
|
if (cmd->optional_pos_args[op].def.types & ARG_DEF_TYPE_STR_SET) {
|
|
for (j = 0; j < MAX_STR_SET; j++) {
|
|
if (cmd->optional_pos_args[op].def.str_set[j])
|
|
printf("commands[%d].optional_pos_args[%d].def.str_set[%d] = \"%s\";\n",
|
|
i, op, j, cmd->optional_pos_args[op].def.str_set[j] ?: "NULL");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
void print_command_list(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_CMD_NAMES; i++) {
|
|
if (!cmd_names[i].name) {
|
|
printf("found %d command names\n", i);
|
|
break;
|
|
}
|
|
printf("%s\n", cmd_names[i].name);
|
|
}
|
|
}
|
|
|
|
void print_option_list(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARG_COUNT; i++)
|
|
printf("%d %s %s %c\n",
|
|
opt_names[i].enum_val, opt_names[i].enum_name,
|
|
opt_names[i].long_opt, opt_names[i].short_opt ?: ' ');
|
|
}
|
|
|
|
static void print_help(int argc, char *argv[])
|
|
{
|
|
printf("%s --output struct|count|expand <filename>\n", argv[0]);
|
|
printf("\n");
|
|
printf("struct: print C structures for command definitions.\n");
|
|
printf("expand: print expanded input format.\n");
|
|
printf("count: print #define COMMAND_COUNT <Number>\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char *outputformat = NULL;
|
|
char *inputfile = NULL;
|
|
FILE *file;
|
|
struct command *cmd;
|
|
char line[MAX_LINE];
|
|
char line_orig[MAX_LINE];
|
|
const char *name;
|
|
char *line_argv[MAX_LINE_ARGC];
|
|
char *n;
|
|
int line_argc;
|
|
int prev_was_oo_def = 0;
|
|
int prev_was_oo = 0;
|
|
int prev_was_op = 0;
|
|
|
|
if (argc < 2) {
|
|
print_help(argc, argv);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
static struct option long_options[] = {
|
|
{"help", no_argument, 0, 'h' },
|
|
{"output", required_argument, 0, 'o' },
|
|
{0, 0, 0, 0 }
|
|
};
|
|
|
|
while (1) {
|
|
int c;
|
|
int option_index = 0;
|
|
|
|
c = getopt_long(argc, argv, "ho:",
|
|
long_options, &option_index);
|
|
if (c == -1)
|
|
break;
|
|
|
|
switch (c) {
|
|
case '0':
|
|
break;
|
|
case 'h':
|
|
print_help(argc, argv);
|
|
exit(EXIT_SUCCESS);
|
|
case 'o':
|
|
outputformat = strdup(optarg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (optind < argc)
|
|
inputfile = argv[optind];
|
|
else {
|
|
printf("Missing filename.\n");
|
|
return 0;
|
|
}
|
|
|
|
if (!(file = fopen(inputfile, "r"))) {
|
|
printf("Cannot open %s\n", argv[1]);
|
|
return -1;
|
|
}
|
|
|
|
while (fgets(line, MAX_LINE, file)) {
|
|
if (line[0] == '#')
|
|
continue;
|
|
if (line[0] == '\n')
|
|
continue;
|
|
|
|
if ((n = strchr(line, '\n')))
|
|
*n = '\0';
|
|
|
|
memcpy(line_orig, line, sizeof(line));
|
|
split_line(line, &line_argc, line_argv, ' ');
|
|
|
|
if (!line_argc)
|
|
continue;
|
|
|
|
/* command ... */
|
|
if ((name = is_command_name(line_argv[0]))) {
|
|
if (cmd_count >= MAX_CMDS) {
|
|
printf("MAX_CMDS too small\n");
|
|
return -1;
|
|
}
|
|
cmd = &cmd_array[cmd_count++];
|
|
cmd->name = name;
|
|
cmd->pos_count = 1;
|
|
add_required_line(cmd, line_argc, line_argv);
|
|
|
|
/* Every cmd gets the OO_ALL options */
|
|
include_optional_opt_args(cmd, "OO_ALL:");
|
|
continue;
|
|
}
|
|
|
|
if (is_desc_line(line_argv[0])) {
|
|
char *desc = strdup(strstr(line_orig, ":") + 2);
|
|
if (cmd->desc) {
|
|
cmd->desc = realloc((char *)cmd->desc, strlen(cmd->desc) + strlen(desc) + 2);
|
|
strcat((char *)cmd->desc, "\n");
|
|
strcat((char *)cmd->desc, desc);
|
|
free(desc);
|
|
} else
|
|
cmd->desc = desc;
|
|
continue;
|
|
}
|
|
|
|
/* OO_FOO: ... */
|
|
if (is_oo_definition(line_argv[0])) {
|
|
add_oo_definition_line(line_argv[0], line_orig);
|
|
prev_was_oo_def = 1;
|
|
prev_was_oo = 0;
|
|
prev_was_op = 0;
|
|
continue;
|
|
}
|
|
|
|
/* OO: ... */
|
|
if (is_oo_line(line_argv[0])) {
|
|
add_optional_opt_line(cmd, line_argc, line_argv);
|
|
prev_was_oo_def = 0;
|
|
prev_was_oo = 1;
|
|
prev_was_op = 0;
|
|
continue;
|
|
}
|
|
|
|
/* OP: ... */
|
|
if (is_op_line(line_argv[0])) {
|
|
add_optional_pos_line(cmd, line_argc, line_argv);
|
|
prev_was_oo_def = 0;
|
|
prev_was_oo = 0;
|
|
prev_was_op = 1;
|
|
continue;
|
|
}
|
|
|
|
/* handle OO_FOO:, OO:, OP: continuing on multiple lines */
|
|
|
|
if (prev_was_oo_def) {
|
|
append_oo_definition_line(line_orig);
|
|
continue;
|
|
}
|
|
|
|
if (prev_was_oo) {
|
|
add_optional_opt_line(cmd, line_argc, line_argv);
|
|
continue;
|
|
}
|
|
|
|
if (prev_was_op) {
|
|
add_optional_pos_line(cmd, line_argc, line_argv);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
fclose(file);
|
|
|
|
if (!outputformat)
|
|
print_data_expanded();
|
|
else if (!strcmp(outputformat, "struct"))
|
|
print_command_structs();
|
|
else if (!strcmp(outputformat, "count"))
|
|
print_command_count();
|
|
else if (!strcmp(outputformat, "expand"))
|
|
print_data_expanded();
|
|
else
|
|
print_help(argc, argv);
|
|
}
|
|
|