diff options
Diffstat (limited to 'tools/create-commands.c')
-rw-r--r-- | tools/create-commands.c | 2855 |
1 files changed, 2855 insertions, 0 deletions
diff --git a/tools/create-commands.c b/tools/create-commands.c new file mode 100644 index 000000000..480f76f83 --- /dev/null +++ b/tools/create-commands.c @@ -0,0 +1,2855 @@ +#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 vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } +int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } +int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } +int polloperation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } +int writemostly_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } +int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } +int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } +int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } +int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } + +/* also see arg_props in tools.h and args.h */ +struct opt_name { + const char *name; /* "foo_ARG" */ + int opt_enum; /* foo_ARG */ + const char short_opt; /* -f */ + char _padding[7]; + const char *long_opt; /* --foo */ + int val_enum; /* xyz_VAL when --foo takes a val like "--foo xyz" */ + uint32_t unused1; + uint32_t unused2; +}; + +/* also see val_props in tools.h and vals.h */ +struct val_name { + const char *enum_name; /* "foo_VAL" */ + int val_enum; /* foo_VAL */ + int (*fn) (struct cmd_context *cmd, struct arg_values *av); /* foo_arg() */ + const char *name; /* FooVal */ + const char *usage; +}; + +/* also see lv_props in tools.h and lv_props.h */ +struct lvp_name { + const char *enum_name; /* "is_foo_LVP" */ + int lvp_enum; /* is_foo_LVP */ + const char *name; /* "lv_is_foo" */ +}; + +/* also see lv_types in tools.h and lv_types.h */ +struct lvt_name { + const char *enum_name; /* "foo_LVT" */ + int lvt_enum; /* foo_LVT */ + const char *name; /* "foo" */ +}; + +/* create foo_VAL enums for option and position values */ + +enum { +#define val(a, b, c, d) a , +#include "vals.h" +#undef val +}; + +/* create foo_ARG enums for --option's */ + +enum { +#define arg(a, b, c, d, e, f) a , +#include "args.h" +#undef arg +}; + +/* create foo_LVP enums for LV properties */ + +enum { +#define lvp(a, b, c) a, +#include "lv_props.h" +#undef lvp +}; + +/* create foo_LVT enums for LV types */ + +enum { +#define lvt(a, b, c) a, +#include "lv_types.h" +#undef lvt +}; + +/* create table of value names, e.g. String, and corresponding enum from vals.h */ + +static struct val_name val_names[VAL_COUNT + 1] = { +#define val(a, b, c, d) { # a, a, b, c, d }, +#include "vals.h" +#undef val +}; + +/* create table of option names, e.g. --foo, and corresponding enum from args.h */ + +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 +}; + +/* create table of lv property names, e.g. lv_is_foo, and corresponding enum from lv_props.h */ + +static struct lvp_name lvp_names[LVP_COUNT + 1] = { +#define lvp(a, b, c) { # a, a, b }, +#include "lv_props.h" +#undef lvp +}; + +/* create table of lv type names, e.g. linear and corresponding enum from lv_types.h */ + +static struct lvt_name lvt_names[LVT_COUNT + 1] = { +#define lvt(a, b, c) { # a, a, b }, +#include "lv_types.h" +#undef lvt +}; + +#include "command.h" + +#define MAX_CMD_NAMES 128 +struct cmd_name { + const char *name; + const char *desc; + int common_options[ARG_COUNT + 1]; + int all_options[ARG_COUNT + 1]; + int variants; + int variant_has_ro; + int variant_has_rp; + int variant_has_oo; + int variant_has_op; +}; + +/* create table of command names, e.g. vgcreate */ + +static struct cmd_name cmd_names[MAX_CMD_NAMES] = { +#define xx(a, b, c) { # a , b } , +#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]; + +struct command lvm_all; /* for printing common options for all lvm commands */ + +#define MAX_OO_LINES 256 +int oo_line_count; +struct oo_line oo_lines[MAX_OO_LINES]; + +static int include_man_secondary = 1; +static int include_man_primary = 1; +static char *man_command_name = NULL; + +static void add_optional_opt_line(struct command *cmd, int argc, char *argv[]); + +/* + * 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; +} + +/* convert value string, e.g. Number, to foo_VAL enum */ + +static int val_str_to_num(char *str) +{ + char name[32] = { 0 }; + char *new; + int i; + + /* compare the name before any suffix like _new or _<lvtype> */ + + strncpy(name, str, 31); + if ((new = strstr(name, "_"))) + *new = '\0'; + + for (i = 0; i < VAL_COUNT; i++) { + if (!val_names[i].name) + break; + if (!strncmp(name, val_names[i].name, strlen(val_names[i].name))) + return val_names[i].val_enum; + } + + return 0; +} + +/* convert "--option" to foo_ARG enum */ + +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].opt_enum; + } + + 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].name, "_long_ARG")) + continue; + if (!strcmp(opt_names[i].long_opt, str)) + return opt_names[i].opt_enum; + } + + printf("Unknown opt str: \"%s\"\n", str); + exit(1); +} + +static char *val_bits_to_str(uint64_t val_bits) +{ + static char buf[1024]; + int i; + int or = 0; + + memset(buf, 0, sizeof(buf)); + + for (i = 0; i < VAL_COUNT; i++) { + if (val_bits & val_enum_to_bit(i)) { + if (or) strcat(buf, " | "); + strcat(buf, "val_enum_to_bit("); + strcat(buf, val_names[i].enum_name); + strcat(buf, ")"); + or = 1; + } + } + + return buf; +} + +/* + * When bits for foo_LVP and bar_LVP are both set in bits, print: + * lvp_enum_to_bit(foo_LVP) | lvp_enum_to_bit(bar_LVP) + */ + +static char *lvp_bits_to_str(uint64_t bits) +{ + static char lvp_buf[1024]; + int i; + int or = 0; + + memset(lvp_buf, 0, sizeof(lvp_buf)); + + for (i = 0; i < LVP_COUNT; i++) { + if (bits & lvp_enum_to_bit(i)) { + if (or) strcat(lvp_buf, " | "); + strcat(lvp_buf, "lvp_enum_to_bit("); + strcat(lvp_buf, lvp_names[i].enum_name); + strcat(lvp_buf, ")"); + or = 1; + } + } + + return lvp_buf; +} + +/* + * When bits for foo_LVT and bar_LVT are both set in bits, print: + * lvt_enum_to_bit(foo_LVT) | lvt_enum_to_bit(bar_LVT) + */ + +static char *lvt_bits_to_str(uint64_t bits) +{ + static char lvt_buf[1024]; + int i; + int or = 0; + + memset(lvt_buf, 0, sizeof(lvt_buf)); + + for (i = 1; i < LVT_COUNT; i++) { + if (bits & lvt_enum_to_bit(i)) { + if (or) strcat(lvt_buf, " | "); + strcat(lvt_buf, "lvt_enum_to_bit("); + strcat(lvt_buf, lvt_names[i].enum_name); + strcat(lvt_buf, ")"); + or = 1; + } + } + + return lvt_buf; +} + +/* "lv_is_prop" to is_prop_LVP */ + +static int lvp_name_to_enum(char *str) +{ + int i; + + for (i = 1; i < LVP_COUNT; i++) { + if (!strcmp(str, lvp_names[i].name)) + return lvp_names[i].lvp_enum; + } + printf("unknown lv property %s\n", str); + exit(1); +} + +/* type_LVT to "type" */ + +static const char *lvt_enum_to_name(int lvt_enum) +{ + return lvt_names[lvt_enum].name; +} + +/* "type" to type_LVT */ + +static int lvt_name_to_enum(char *str) +{ + int i; + + for (i = 1; i < LVT_COUNT; i++) { + if (!strcmp(str, lvt_names[i].name)) + return lvt_names[i].lvt_enum; + } + printf("unknown lv type %s\n", str); + exit(1); +} + +/* LV_<type> to <type>_LVT */ + +int lv_to_enum(char *name) +{ + return lvt_name_to_enum(name + 3); +} + +/* + * LV_<type1>_<type2> to lvt_bits + * + * type1 to lvt_enum + * lvt_bits |= lvt_enum_to_bit(lvt_enum) + * type2 to lvt_enum + * lvt_bits |= lvt_enum_to_bit(lvt_enum) + */ + +uint64_t lv_to_bits(char *name) +{ + char buf[64]; + char *argv[MAX_LINE_ARGC]; + uint64_t lvt_bits = 0; + int lvt_enum; + int argc; + int i; + + strcpy(buf, name); + + split_line(buf, &argc, argv, '_'); + + /* 0 is "LV" */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "new")) + continue; + lvt_enum = lvt_name_to_enum(argv[i]); + lvt_bits |= lvt_enum_to_bit(lvt_enum); + } + + return lvt_bits; +} + +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 const char *cmd_name_desc(const char *name) +{ + int i; + + for (i = 0; i < MAX_CMD_NAMES; i++) { + if (!cmd_names[i].name) + break; + if (!strcmp(cmd_names[i].name, name)) + return cmd_names[i].desc; + } + return NULL; +} + +static struct cmd_name *find_command_name(const 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]; + } + 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) && strstr(str, ":")) + 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; +} + +static int is_flags_line(char *str) +{ + if (!strncmp(str, "FLAGS:", 6)) + return 1; + return 0; +} + +static int is_rule_line(char *str) +{ + if (!strncmp(str, "RULE:", 5)) + return 1; + return 0; +} + +static int is_id_line(char *str) +{ + if (!strncmp(str, "ID:", 3)) + 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 val_enum; + int i; + + split_line(str, &argc, argv, '|'); + + for (i = 0; i < argc; i++) { + name = argv[i]; + + val_enum = val_str_to_num(name); + + if (!val_enum) { + printf("Unknown pos arg: %s\n", name); + exit(1); + } + + def->val_bits |= val_enum_to_bit(val_enum); + + if ((val_enum == lv_VAL) && strstr(name, "_")) + def->lvt_bits = lv_to_bits(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 val_enum; + int i, j; + + split_line(str, &argc, argv, '|'); + + for (i = 0; i < argc; i++) { + name = argv[i]; + + val_enum = val_str_to_num(name); + + if (!val_enum) { + /* a literal number or string */ + + if (isdigit(name[0])) + val_enum = constnum_VAL; + + else if (isalpha(name[0])) + val_enum = conststr_VAL; + + else { + printf("Unknown opt arg: %s\n", name); + exit(0); + } + } + + + def->val_bits |= val_enum_to_bit(val_enum); + + if (val_enum == constnum_VAL) + def->num = (uint64_t)atoi(name); + + if (val_enum == conststr_VAL) + def->str = strdup(name); + + if (val_enum == lv_VAL) { + if (strstr(name, "_")) + def->lvt_bits = lv_to_bits(name); + } + + if ((val_enum == vg_VAL) || (val_enum == lv_VAL) || (val_enum == pv_VAL)) { + 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].val_enum ? 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 usage) +{ + int val_enum; + int lvt_enum; + int sep = 0; + int i; + + for (val_enum = 0; val_enum < VAL_COUNT; val_enum++) { + if (def->val_bits & val_enum_to_bit(val_enum)) { + + if (val_enum == conststr_VAL) + printf("%s", def->str); + + else if (val_enum == constnum_VAL) + printf("%llu", (unsigned long long)def->num); + + else { + if (sep) printf("|"); + + if (!usage || !val_names[val_enum].usage) + printf("%s", val_names[val_enum].name); + else + printf("%s", val_names[val_enum].usage); + + sep = 1; + } + + if (val_enum == lv_VAL && def->lvt_bits) { + for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) { + if (lvt_bit_is_set(def->lvt_bits, lvt_enum)) + printf("_%s", lvt_enum_to_name(lvt_enum)); + } + } + + if ((val_enum == pv_VAL) || (val_enum == vg_VAL) || (val_enum == lv_VAL)) { + if (def->flags & ARG_DEF_FLAG_NEW) + printf("_new"); + } + } + } + + if (def->flags & ARG_DEF_FLAG_MAY_REPEAT) + printf(" ..."); +} + +void print_expanded(void) +{ + struct command *cmd; + int onereq; + int i, ro, rp, oo, op; + + for (i = 0; i < cmd_count; i++) { + cmd = &cmd_array[i]; + printf("%s", cmd->name); + + onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0; + + 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.val_bits) { + printf(" "); + print_def(&cmd->required_opt_args[ro].def, 0); + } + } + if (onereq) + printf(" )"); + } + + if (cmd->rp_count) { + for (rp = 0; rp < cmd->rp_count; rp++) { + if (cmd->required_pos_args[rp].def.val_bits) { + printf(" "); + print_def(&cmd->required_pos_args[rp].def, 0); + } + } + } + + 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.val_bits) { + printf(" "); + print_def(&cmd->optional_opt_args[oo].def, 0); + } + } + } + + if (cmd->op_count) { + printf("\n"); + printf("OP:"); + for (op = 0; op < cmd->op_count; op++) { + if (cmd->optional_pos_args[op].def.val_bits) { + printf(" "); + print_def(&cmd->optional_pos_args[op].def, 0); + } + } + } + + printf("\n\n"); + } +} + +static int opt_arg_matches(struct opt_arg *oa1, struct opt_arg *oa2) +{ + if (oa1->opt != oa2->opt) + return 0; + + /* FIXME: some cases may need more specific val_bits checks */ + if (oa1->def.val_bits != oa2->def.val_bits) + return 0; + + if (oa1->def.str && oa2->def.str && strcmp(oa1->def.str, oa2->def.str)) + return 0; + + if (oa1->def.num != oa2->def.num) + return 0; + + /* + * Do NOT compare lv_types because we are checking if two + * command lines are ambiguous before the LV type is known. + */ + + return 1; +} + +static int pos_arg_matches(struct pos_arg *pa1, struct pos_arg *pa2) +{ + if (pa1->pos != pa2->pos) + return 0; + + /* FIXME: some cases may need more specific val_bits checks */ + if (pa1->def.val_bits != pa2->def.val_bits) + return 0; + + if (pa1->def.str && pa2->def.str && strcmp(pa1->def.str, pa2->def.str)) + return 0; + + if (pa1->def.num != pa2->def.num) + return 0; + + /* + * Do NOT compare lv_types because we are checking if two + * command lines are ambiguous before the LV type is known. + */ + + return 1; +} + +static const char *opt_to_enum_str(int opt) +{ + return opt_names[opt].name; +} + +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) { + if (buf_flags[0]) + strcat(buf_flags, " | "); + strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT"); + } + if (flags & ARG_DEF_FLAG_NEW) { + if (buf_flags[0]) + strcat(buf_flags, " | "); + strcat(buf_flags, "ARG_DEF_FLAG_NEW"); + } + + return buf_flags; +} + +static void add_flags(struct command *cmd, char *line) +{ + if (strstr(line, "SECONDARY_SYNTAX")) + cmd->cmd_flags |= CMD_FLAG_SECONDARY_SYNTAX; +} + +static void add_rule(struct command *cmd, char *line) +{ + struct cmd_rule *rule; + char *line_argv[MAX_LINE_ARGC]; + char *arg; + int line_argc; + int i, lvt_enum, lvp_enum; + int check = 0; + + if (cmd->rule_count == CMD_MAX_RULES) { + printf("too many rules for cmd\n"); + exit(1); + } + + rule = &cmd->rules[cmd->rule_count++]; + + split_line(line, &line_argc, line_argv, ' '); + + for (i = 0; i < line_argc; i++) { + arg = line_argv[i]; + + if (!strcmp(arg, "not")) { + rule->rule = RULE_INVALID; + check = 1; + } + + else if (!strcmp(arg, "and")) { + rule->rule = RULE_REQUIRE; + check = 1; + } + + else if (!strncmp(arg, "all", 3)) { + /* opt/lvt_bits/lvp_bits all remain 0 to mean all */ + continue; + } + + else if (!strncmp(arg, "--", 2)) { + if (check) + rule->check_opt = opt_str_to_num(arg); + else + rule->opt = opt_str_to_num(arg); + } + + else if (!strncmp(arg, "LV_", 3)) { + lvt_enum = lv_to_enum(arg); + + if (check) + rule->check_lvt_bits |= lvt_enum_to_bit(lvt_enum); + else + rule->lvt_bits |= lvt_enum_to_bit(lvt_enum); + } + + else if (!strncmp(arg, "lv_is_", 6)) { + lvp_enum = lvp_name_to_enum(arg); + + if (check) + rule->check_lvp_bits |= lvp_enum_to_bit(lvp_enum); + else + rule->lvp_bits |= lvp_enum_to_bit(lvp_enum); + } + } +} + +static char *rule_to_define_str(int rule_type) +{ + switch (rule_type) { + case RULE_INVALID: + return "RULE_INVALID"; + case RULE_REQUIRE: + return "RULE_REQUIRE"; + } +} + +static char *cmd_flags_to_str(uint32_t flags) +{ + static char buf_cmd_flags[32]; + + memset(buf_cmd_flags, 0, sizeof(buf_cmd_flags)); + + if (flags & CMD_FLAG_SECONDARY_SYNTAX) { + if (buf_cmd_flags[0]) + strcat(buf_cmd_flags, " | "); + strcat(buf_cmd_flags, "CMD_FLAG_SECONDARY_SYNTAX"); + } + if (flags & CMD_FLAG_ONE_REQUIRED_OPT) { + if (buf_cmd_flags[0]) + strcat(buf_cmd_flags, " | "); + strcat(buf_cmd_flags, "CMD_FLAG_ONE_REQUIRED_OPT"); + } + + return buf_cmd_flags; +} + +void print_command_count(void) +{ + struct command *cmd; + int i, j; + + printf("/* Do not edit. This file is generated by scripts/create-commands */\n"); + printf("/* using command definitions from scripts/command-lines.in */\n"); + printf("#define COMMAND_COUNT %d\n", cmd_count); + + printf("enum {\n"); + printf("\tno_CMD,\n"); /* enum value 0 is not used */ + + for (i = 0; i < cmd_count; i++) { + cmd = &cmd_array[i]; + + if (!cmd->command_line_id) { + printf("Missing ID: at %d\n", i); + exit(1); + } + + for (j = 0; j < i; j++) { + if (!strcmp(cmd->command_line_id, cmd_array[j].command_line_id)) + goto next; + } + + printf("\t%s_CMD,\n", cmd->command_line_id); + next: + ; + } + printf("\tCOMMAND_ID_COUNT,\n"); + printf("};\n"); +} + +static int is_lvm_all_opt(int opt) +{ + int oo; + + for (oo = 0; oo < lvm_all.oo_count; oo++) { + if (lvm_all.optional_opt_args[oo].opt == opt) + return 1; + } + return 0; +} + +static void factor_common_options(void) +{ + int cn, opt_enum, ci, oo, ro, found; + struct command *cmd; + + for (cn = 0; cn < MAX_CMD_NAMES; cn++) { + if (!cmd_names[cn].name) + break; + + for (ci = 0; ci < cmd_count; ci++) { + cmd = &cmd_array[ci]; + + if (strcmp(cmd->name, cmd_names[cn].name)) + continue; + + cmd_names[cn].variants++; + } + + for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { + + for (ci = 0; ci < cmd_count; ci++) { + cmd = &cmd_array[ci]; + + if (strcmp(cmd->name, cmd_names[cn].name)) + continue; + + if (cmd->ro_count) + cmd_names[cn].variant_has_ro = 1; + if (cmd->rp_count) + cmd_names[cn].variant_has_rp = 1; + if (cmd->oo_count) + cmd_names[cn].variant_has_oo = 1; + if (cmd->op_count) + cmd_names[cn].variant_has_op = 1; + + for (ro = 0; ro < cmd->ro_count; ro++) { + cmd_names[cn].all_options[cmd->required_opt_args[ro].opt] = 1; + + if ((cmd->required_opt_args[ro].opt == size_ARG) && !strncmp(cmd->name, "lv", 2)) + cmd_names[cn].all_options[extents_ARG] = 1; + } + for (oo = 0; oo < cmd->oo_count; oo++) + cmd_names[cn].all_options[cmd->optional_opt_args[oo].opt] = 1; + + found = 0; + + for (oo = 0; oo < cmd->oo_count; oo++) { + if (cmd->optional_opt_args[oo].opt == opt_enum) { + found = 1; + break; + } + } + + if (!found) + goto next_opt; + } + + /* all commands starting with this name use this option */ + cmd_names[cn].common_options[opt_enum] = 1; + next_opt: + ; + } + } + + /* + for (cn = 0; cn < MAX_CMD_NAMES; cn++) { + if (!cmd_names[cn].name) + break; + + printf("%s (%d)\n", cmd_names[cn].name, cmd_names[cn].variants); + for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { + if (cmd_names[cn].common_options[opt_enum]) + printf(" %s\n", opt_names[opt_enum].long_opt); + } + } + */ +} + +void print_usage_common(struct command *cmd) +{ + struct cmd_name *cname; + int i, sep, ro, rp, oo, op, opt_enum; + + if (!(cname = find_command_name(cmd->name))) + return; + + sep = 0; + + /* + * when there's more than one variant, options that + * are common to all commands with a common name. + */ + + if (cname->variants < 2) + goto all; + + for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { + if (!cname->common_options[opt_enum]) + continue; + + if (is_lvm_all_opt(opt_enum)) + continue; + + if (!sep) { + printf("\n"); + printf("\" ["); + } else { + printf(","); + } + + for (oo = 0; oo < cmd->oo_count; oo++) { + if (cmd->optional_opt_args[oo].opt != opt_enum) + continue; + + printf(" %s", opt_names[opt_enum].long_opt); + if (cmd->optional_opt_args[oo].def.val_bits) { + printf(" "); + print_def(&cmd->optional_opt_args[oo].def, 1); + } + sep = 1; + break; + } + } + + all: + /* options that are common to all lvm commands */ + + for (oo = 0; oo < lvm_all.oo_count; oo++) { + opt_enum = lvm_all.optional_opt_args[oo].opt; + + if (!sep) { + printf("\n"); + printf("\" ["); + } else { + printf(","); + } + + printf(" %s", opt_names[opt_enum].long_opt); + if (lvm_all.optional_opt_args[oo].def.val_bits) { + printf(" "); + print_def(&lvm_all.optional_opt_args[oo].def, 1); + } + sep = 1; + } + + printf(" ]\""); + printf(";\n"); +} + +void print_usage(struct command *cmd) +{ + struct cmd_name *cname; + int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0; + int i, sep, ro, rp, oo, op, opt_enum; + + if (!(cname = find_command_name(cmd->name))) + return; + + 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.val_bits) { + printf(" "); + print_def(&cmd->required_opt_args[ro].def, 1); + } + } + if (onereq) + printf(" )"); + } + + if (cmd->rp_count) { + for (rp = 0; rp < cmd->rp_count; rp++) { + if (cmd->required_pos_args[rp].def.val_bits) { + printf(" "); + print_def(&cmd->required_pos_args[rp].def, 1); + } + } + } + + printf("\""); + + oo_count: + if (!cmd->oo_count) + goto op_count; + + sep = 0; + + if (cmd->oo_count) { + printf("\n"); + printf("\" ["); + + for (oo = 0; oo < cmd->oo_count; oo++) { + opt_enum = cmd->optional_opt_args[oo].opt; + + /* + * Skip common opts which are in the usage_common string. + * The common opts are those in lvm_all and in + * cname->common_options. + */ + + if (is_lvm_all_opt(opt_enum)) + continue; + + if ((cname->variants > 1) && cname->common_options[opt_enum]) + continue; + + if (sep) + printf(","); + + printf(" %s", opt_names[opt_enum].long_opt); + if (cmd->optional_opt_args[oo].def.val_bits) { + printf(" "); + print_def(&cmd->optional_opt_args[oo].def, 1); + } + sep = 1; + } + + if (sep) + printf(","); + printf(" COMMON_OPTIONS"); + 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.val_bits) { + printf(" "); + print_def(&cmd->optional_pos_args[op].def, 1); + } + } + } + + printf(" ]\""); + + done: + printf(";\n"); +} + +static void print_val_man(const char *str) +{ + char *line; + char *line_argv[MAX_LINE_ARGC]; + int line_argc; + int i; + + if (!strcmp(str, "Number") || + !strcmp(str, "String") || + !strncmp(str, "VG", 2) || + !strncmp(str, "LV", 2) || + !strncmp(str, "PV", 2) || + !strcmp(str, "Tag")) { + printf("\\fI%s\\fP", str); + return; + } + + if (strstr(str, "Number[") || strstr(str, "]Number")) { + for (i = 0; i < strlen(str); i++) { + if (str[i] == 'N') + printf("\\fI"); + if (str[i] == 'r') { + printf("%c", str[i]); + printf("\\fP"); + continue; + } + printf("%c", str[i]); + } + return; + } + + if (strstr(str, "|")) { + int len = strlen(str); + line = strdup(str); + split_line(line, &line_argc, line_argv, '|'); + for (i = 0; i < line_argc; i++) { + if (i) { + printf("|"); + + /* this is a hack to add a line break for + a long string of opt values */ + if ((len > 40) && (i >= (line_argc / 2) + 1)) { + printf("\n"); + printf(" "); + len = 0; + } + } + if (strstr(line_argv[i], "Number")) + printf("\\fI%s\\fP", line_argv[i]); + else + printf("\\fB%s\\fP", line_argv[i]); + } + return; + } + + printf("\\fB%s\\fP", str); +} + +static void print_def_man(struct arg_def *def, int usage) +{ + int val_enum; + int lvt_enum; + int sep = 0; + int i; + + for (val_enum = 0; val_enum < VAL_COUNT; val_enum++) { + if (def->val_bits & val_enum_to_bit(val_enum)) { + + if (val_enum == conststr_VAL) { + printf("\\fB"); + printf("%s", def->str); + printf("\\fP"); + } + + else if (val_enum == constnum_VAL) { + printf("\\fB"); + printf("%llu", (unsigned long long)def->num); + printf("\\fP"); + } + + else { + if (sep) printf("|"); + + if (!usage || !val_names[val_enum].usage) { + printf("\\fI"); + printf("%s", val_names[val_enum].name); + printf("\\fP"); + } else { + print_val_man(val_names[val_enum].usage); + } + + sep = 1; + } + + if (val_enum == lv_VAL && def->lvt_bits) { + printf("\\fI"); + for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) { + if (lvt_bit_is_set(def->lvt_bits, lvt_enum)) + printf("_%s", lvt_enum_to_name(lvt_enum)); + } + printf("\\fP"); + } + + if ((val_enum == pv_VAL) || (val_enum == vg_VAL) || (val_enum == lv_VAL)) { + if (def->flags & ARG_DEF_FLAG_NEW) { + printf("\\fI"); + printf("_new"); + printf("\\fP"); + } + } + } + } + + if (def->flags & ARG_DEF_FLAG_MAY_REPEAT) + printf(" ..."); +} + +static char *man_long_opt_name(const char *cmdname, int opt_enum) +{ + static char long_opt_name[64]; + + memset(&long_opt_name, 0, sizeof(long_opt_name)); + + switch (opt_enum) { + case syncaction_ARG: + strncpy(long_opt_name, "--[raid]syncaction", 63); + break; + case writemostly_ARG: + strncpy(long_opt_name, "--[raid]writemostly", 63); + break; + case minrecoveryrate_ARG: + strncpy(long_opt_name, "--[raid]minrecoveryrate", 63); + break; + case maxrecoveryrate_ARG: + strncpy(long_opt_name, "--[raid]maxrecoveryrate", 63); + break; + case writebehind_ARG: + strncpy(long_opt_name, "--[raid]writebehind", 63); + break; + case vgmetadatacopies_ARG: + if (!strncmp(cmdname, "vg", 2)) + strncpy(long_opt_name, "--[vg]metadatacopies", 63); + else + strncpy(long_opt_name, "--vgmetadatacopies", 63); + break; + case pvmetadatacopies_ARG: + if (!strncmp(cmdname, "pv", 2)) + strncpy(long_opt_name, "--[pv]metadatacopies", 63); + else + strncpy(long_opt_name, "--pvmetadatacopies", 63); + break; + default: + strncpy(long_opt_name, opt_names[opt_enum].long_opt, 63); + break; + } + + return long_opt_name; +} + +void print_man_usage(struct command *cmd) +{ + struct cmd_name *cname; + int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0; + int i, sep, ro, rp, oo, op, opt_enum; + + if (!(cname = find_command_name(cmd->name))) + return; + + printf("\\fB%s\\fP", cmd->name); + + if (!onereq) + goto ro_normal; + + /* + * one required option in a set, print as: + * ( -a|--a, + * -b|--b, + * --c, + * --d ) + * + * First loop through ro prints those with short opts, + * and the second loop prints those without short opts. + */ + + if (cmd->ro_count) { + printf("\n"); + printf(".RS 4\n"); + printf("("); + + sep = 0; + + /* print required options with a short opt */ + for (ro = 0; ro < cmd->ro_count; ro++) { + opt_enum = cmd->required_opt_args[ro].opt; + + if (!opt_names[opt_enum].short_opt) + continue; + + if (sep) { + printf(","); + printf("\n.br\n"); + printf(" "); + } + + if (opt_names[opt_enum].short_opt) { + printf(" \\fB-%c\\fP|\\fB%s\\fP", + opt_names[opt_enum].short_opt, + man_long_opt_name(cmd->name, opt_enum)); + } else { + printf(" "); + printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum)); + } + + if (cmd->required_opt_args[ro].def.val_bits) { + printf(" "); + print_def_man(&cmd->required_opt_args[ro].def, 1); + } + + sep = 1; + } + + /* print required options without a short opt */ + for (ro = 0; ro < cmd->ro_count; ro++) { + opt_enum = cmd->required_opt_args[ro].opt; + + if (opt_names[opt_enum].short_opt) + continue; + + if (sep) { + printf(","); + printf("\n.br\n"); + printf(" "); + } + + printf(" "); + printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum)); + + if (cmd->required_opt_args[ro].def.val_bits) { + printf(" "); + print_def_man(&cmd->required_opt_args[ro].def, 1); + } + + sep = 1; + } + + printf(" )\n"); + printf(".RE\n"); + } + + /* print required position args on a new line after the onereq set */ + if (cmd->rp_count) { + printf(".RS 4\n"); + for (rp = 0; rp < cmd->rp_count; rp++) { + if (cmd->required_pos_args[rp].def.val_bits) { + printf(" "); + print_def_man(&cmd->required_pos_args[rp].def, 1); + } + } + + printf("\n"); + printf(".RE\n"); + } else { + /* printf("\n"); */ + } + + printf(".br\n"); + goto oo_count; + + ro_normal: + + /* + * all are required options, print as: + * -a|--aaa <val> -b|--bbb <val> + */ + + if (cmd->ro_count) { + for (ro = 0; ro < cmd->ro_count; ro++) { + opt_enum = cmd->required_opt_args[ro].opt; + + if (opt_names[opt_enum].short_opt) { + printf(" \\fB-%c\\fP|\\fB%s\\fP", + opt_names[opt_enum].short_opt, + man_long_opt_name(cmd->name, opt_enum)); + } else { + printf(" \\fB%s\\fP", opt_names[cmd->required_opt_args[ro].opt].long_opt); + } + + if (cmd->required_opt_args[ro].def.val_bits) { + printf(" "); + print_def_man(&cmd->required_opt_args[ro].def, 1); + } + } + } + + /* print required position args on the same line as the required options */ + if (cmd->rp_count) { + for (rp = 0; rp < cmd->rp_count; rp++) { + if (cmd->required_pos_args[rp].def.val_bits) { + printf(" "); + print_def_man(&cmd->required_pos_args[rp].def, 1); + } + } + + printf("\n"); + } else { + printf("\n"); + } + + printf(".br\n"); + + oo_count: + if (!cmd->oo_count) + goto op_count; + + sep = 0; + + if (cmd->oo_count) { + printf(".RS 4\n"); + printf("["); + + /* print optional options with short opts */ + + for (oo = 0; oo < cmd->oo_count; oo++) { + opt_enum = cmd->optional_opt_args[oo].opt; + + if (!opt_names[opt_enum].short_opt) + continue; + + /* + * Skip common opts which are in the usage_common string. + * The common opts are those in lvm_all and in + * cname->common_options. + */ + + if (is_lvm_all_opt(opt_enum)) + continue; + + if ((cname->variants > 1) && cname->common_options[opt_enum]) + continue; + + if (sep) { + printf(","); + printf("\n.br\n"); + printf(" "); + } + + printf(" \\fB-%c\\fP|\\fB%s\\fP", + opt_names[opt_enum].short_opt, + man_long_opt_name(cmd->name, opt_enum)); + + if (cmd->optional_opt_args[oo].def.val_bits) { + printf(" "); + print_def_man(&cmd->optional_opt_args[oo].def, 1); + } + sep = 1; + } + + /* print optional options without short opts */ + + for (oo = 0; oo < cmd->oo_count; oo++) { + opt_enum = cmd->optional_opt_args[oo].opt; + + if (opt_names[opt_enum].short_opt) + continue; + + /* + * Skip common opts which are in the usage_common string. + * The common opts are those in lvm_all and in + * cname->common_options. + */ + + if (is_lvm_all_opt(opt_enum)) + continue; + + if ((cname->variants > 1) && cname->common_options[opt_enum]) + continue; + + if (sep) { + printf(","); + printf("\n.br\n"); + printf(" "); + } + + /* space alignment without short opt */ + printf(" "); + + printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum)); + + if (cmd->optional_opt_args[oo].def.val_bits) { + printf(" "); + print_def_man(&cmd->optional_opt_args[oo].def, 1); + } + sep = 1; + } + + if (sep) { + printf(","); + printf("\n.br\n"); + printf(" "); + /* space alignment without short opt */ + printf(" "); + } + printf(" COMMON_OPTIONS"); + printf(" ]\n"); + printf(".RE\n"); + printf(".br\n"); + } + + op_count: + if (!cmd->op_count) + goto done; + + printf(".RS 4\n"); + printf("["); + + if (cmd->op_count) { + for (op = 0; op < cmd->op_count; op++) { + if (cmd->optional_pos_args[op].def.val_bits) { + printf(" "); + print_def_man(&cmd->optional_pos_args[op].def, 1); + } + } + } + + printf(" ]\n"); + printf(".RE\n"); + + done: + printf("\n"); +} + +void print_man_usage_common(struct command *cmd) +{ + struct cmd_name *cname; + int i, sep, ro, rp, oo, op, opt_enum; + + if (!(cname = find_command_name(cmd->name))) + return; + + sep = 0; + + printf(".RS 4\n"); + printf("["); + + /* + * when there's more than one variant, options that + * are common to all commands with a common name. + */ + + if (cname->variants < 2) + goto all; + + /* print those with short opts */ + for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { + if (!cname->common_options[opt_enum]) + continue; + + if (!opt_names[opt_enum].short_opt) + continue; + + if (is_lvm_all_opt(opt_enum)) + continue; + + if (sep) { + printf(","); + printf("\n.br\n"); + printf(" "); + } + + for (oo = 0; oo < cmd->oo_count; oo++) { + if (cmd->optional_opt_args[oo].opt != opt_enum) + continue; + + printf(" \\fB-%c\\fP|\\fB%s\\fP", + opt_names[opt_enum].short_opt, + man_long_opt_name(cmd->name, opt_enum)); + + if (cmd->optional_opt_args[oo].def.val_bits) { + printf(" "); + print_def_man(&cmd->optional_opt_args[oo].def, 1); + } + sep = 1; + break; + } + + } + + /* print those without short opts */ + for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { + if (!cname->common_options[opt_enum]) + continue; + + if (opt_names[opt_enum].short_opt) + continue; + + if (is_lvm_all_opt(opt_enum)) + continue; + + if (sep) { + printf(","); + printf("\n.br\n"); + printf(" "); + } + + for (oo = 0; oo < cmd->oo_count; oo++) { + if (cmd->optional_opt_args[oo].opt != opt_enum) + continue; + + /* space alignment without short opt */ + printf(" "); + + printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum)); + + if (cmd->optional_opt_args[oo].def.val_bits) { + printf(" "); + print_def_man(&cmd->optional_opt_args[oo].def, 1); + } + sep = 1; + break; + } + } + all: + /* options that are common to all lvm commands */ + + /* those with short opts */ + for (oo = 0; oo < lvm_all.oo_count; oo++) { + opt_enum = lvm_all.optional_opt_args[oo].opt; + + if (!opt_names[opt_enum].short_opt) + continue; + + if (sep) { + printf(","); + printf("\n.br\n"); + printf(" "); + } + + printf(" \\fB-%c\\fP|\\fB%s\\fP", + opt_names[opt_enum].short_opt, + man_long_opt_name(cmd->name, opt_enum)); + + if (lvm_all.optional_opt_args[oo].def.val_bits) { + printf(" "); + print_def(&lvm_all.optional_opt_args[oo].def, 1); + } + sep = 1; + } + + /* those without short opts */ + for (oo = 0; oo < lvm_all.oo_count; oo++) { + opt_enum = lvm_all.optional_opt_args[oo].opt; + + if (opt_names[opt_enum].short_opt) + continue; + + if (sep) { + printf(","); + printf("\n.br\n"); + printf(" "); + } + + /* space alignment without short opt */ + printf(" "); + + printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum)); + + if (lvm_all.optional_opt_args[oo].def.val_bits) { + printf(" "); + print_def(&lvm_all.optional_opt_args[oo].def, 1); + } + sep = 1; + } + printf(" ]\n"); +} + +void print_man_all_options(struct cmd_name *cname) +{ + int opt_enum, val_enum; + int sep = 0; + + /* print those with short opts */ + for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { + if (!cname->all_options[opt_enum]) + continue; + + if (!opt_names[opt_enum].short_opt) + continue; + + if (sep) + printf("\n.br\n"); + + printf(" \\fB-%c\\fP|\\fB%s\\fP", + opt_names[opt_enum].short_opt, + man_long_opt_name(cname->name, opt_enum)); + + val_enum = opt_names[opt_enum].val_enum; + + if (!val_names[val_enum].fn) { + /* takes no arg */ + } else if (!val_names[val_enum].usage) { + printf(" "); + printf("\\fI"); + printf("%s", val_names[val_enum].name); + printf("\\fP"); + } else { + printf(" "); + print_val_man(val_names[val_enum].usage); + } + + sep = 1; + } + + /* print those without short opts */ + for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { + if (!cname->all_options[opt_enum]) + continue; + + if (opt_names[opt_enum].short_opt) + continue; + + if (sep) + printf("\n.br\n"); + + /* space alignment without short opt */ + printf(" "); + + printf(" \\fB%s\\fP", man_long_opt_name(cname->name, opt_enum)); + + val_enum = opt_names[opt_enum].val_enum; + + if (!val_names[val_enum].fn) { + /* takes no arg */ + } else if (!val_names[val_enum].usage) { + printf(" "); + printf("\\fI"); + printf("%s", val_names[val_enum].name); + printf("\\fP"); + } else { + printf(" "); + print_val_man(val_names[val_enum].usage); + } + + sep = 1; + } +} + +#define DESC_LINE 256 + +void print_desc_man(const char *desc) +{ + char buf[DESC_LINE] = {0}; + int di = 0; + int bi = 0; + + for (di = 0; di < strlen(desc); di++) { + if (desc[di] == '\0') + break; + if (desc[di] == '\n') + continue; + + if (!strncmp(&desc[di], "DESC:", 5)) { + if (bi) { + printf("%s\n", buf); + printf(".br\n"); + memset(buf, 0, sizeof(buf)); + bi = 0; + } + di += 5; + continue; + } + + if (!bi && desc[di] == ' ') + continue; + + buf[bi++] = desc[di]; + + if (bi == (DESC_LINE - 1)) + break; + } + + if (bi) { + printf("%s\n", buf); + printf(".br\n"); + } +} + +static char *upper_command_name(char *str) +{ + static char str_upper[32]; + int i = 0; + + while (*str) { + str_upper[i++] = toupper(*str); + str++; + } + str_upper[i] = '\0'; + return str_upper; +} + +void print_man_command(void) +{ + struct cmd_name *cname; + struct command *cmd, *prev_cmd = NULL; + const char *desc; + int i, j, ro, rp, oo, op; + + include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON"); + + printf(".TH %s 8 \"LVM TOOLS #VERSION#\" \"Sistina Software UK\"\n", + man_command_name ? upper_command_name(man_command_name) : "LVM_COMMANDS"); + + for (i = 0; i < cmd_count; i++) { + + cmd = &cmd_array[i]; + + if (prev_cmd && strcmp(prev_cmd->name, cmd->name)) { + printf("Common options:\n"); + printf(".\n"); + print_man_usage_common(prev_cmd); + prev_cmd = NULL; + } + + if ((cmd->cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && !include_man_secondary) + continue; + + if (!(cmd->cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && !include_man_primary) + continue; + + if (man_command_name && strcmp(man_command_name, cmd->name)) + continue; + + if (!prev_cmd || strcmp(prev_cmd->name, cmd->name)) { + printf(".SH NAME\n"); + printf(".\n"); + if ((desc = cmd_name_desc(cmd->name))) + printf("%s \\- %s\n", cmd->name, desc); + else + printf("%s\n", cmd->name); + printf(".br\n"); + printf(".P\n"); + printf(".\n"); + printf(".SH SYNOPSIS\n"); + printf(".br\n"); + printf(".P\n"); + printf(".\n"); + prev_cmd = cmd; + + if (!(cname = find_command_name(cmd->name))) + return; + + if (cname->variant_has_ro && cname->variant_has_rp) + printf("\\fB%s\\fP \\fIrequired_option_args\\fP \\fIrequired_position_args\\fP\n", cmd->name); + else if (cname->variant_has_ro && !cname->variant_has_rp) + printf("\\fB%s\\fP \\fIrequired_option_args\\fP\n", cmd->name); + else if (!cname->variant_has_ro && cname->variant_has_rp) + printf("\\fB%s\\fP \\fIrequired_position_args\\fP\n", cmd->name); + else if (!cname->variant_has_ro && !cname->variant_has_rp) + printf("\\fB%s\\fP\n", cmd->name); + + printf(".br\n"); + + if (cname->variant_has_oo) { + printf(" [ \\fIoptional_option_args\\fP ]\n"); + printf(".br\n"); + } + + if (cname->variant_has_op) { + printf(" [ \\fIoptional_position_args\\fP ]\n"); + printf(".br\n"); + } + + printf(".P\n"); + printf("\n"); + + /* listing them all when there's only 1 or 2 is just repetative */ + if (cname->variants > 2) { + printf(".P\n"); + print_man_all_options(cname); + printf("\n"); + printf(".P\n"); + printf("\n"); + } + + printf(".SH USAGE\n"); + printf(".br\n"); + printf(".P\n"); + printf(".\n"); + } + + if (cmd->desc) { + print_desc_man(cmd->desc); + printf(".P\n"); + } + + print_man_usage(cmd); + + if (i == (cmd_count - 1)) { + printf("Common options:\n"); + printf(".\n"); + print_man_usage_common(cmd); + } + + printf("\n"); + continue; + } +} + +void print_command_struct(int only_usage) +{ + struct command *cmd; + int i, j, ro, rp, oo, op, ru; + + include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON"); + + printf("/* Do not edit. This file is generated by scripts/create-commands */\n"); + printf("/* using command definitions from scripts/command-lines.in */\n"); + printf("\n"); + + for (i = 0; i < cmd_count; i++) { + cmd = &cmd_array[i]; + + if (only_usage) { + print_usage(cmd); + print_usage_common(cmd); + printf("\n"); + continue; + } + + printf("commands[%d].name = \"%s\";\n", i, cmd->name); + printf("commands[%d].command_line_id = \"%s\";\n", i, cmd->command_line_id); + printf("commands[%d].command_line_enum = %s_CMD;\n", i, cmd->command_line_id); + printf("commands[%d].fn = %s;\n", i, cmd->name); + printf("commands[%d].ro_count = %d;\n", i, cmd->ro_count); + printf("commands[%d].rp_count = %d;\n", i, cmd->rp_count); + printf("commands[%d].oo_count = %d;\n", i, cmd->oo_count); + printf("commands[%d].op_count = %d;\n", i, cmd->op_count); + printf("commands[%d].rule_count = %d;\n", i, cmd->rule_count); + + if (cmd->cmd_flags) + printf("commands[%d].cmd_flags = %s;\n", i, cmd_flags_to_str(cmd->cmd_flags)); + else + printf("commands[%d].cmd_flags = 0;\n", i, cmd_flags_to_str(cmd->cmd_flags)); + + printf("commands[%d].desc = \"%s\";\n", i, cmd->desc ?: ""); + printf("commands[%d].usage = ", i); + print_usage(cmd); + + if (cmd->oo_count) { + printf("commands[%d].usage_common = ", i); + print_usage_common(cmd); + } else { + printf("commands[%d].usage_common = \"NULL\";\n", i); + } + + 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.val_bits) + continue; + + printf("commands[%d].required_opt_args[%d].def.val_bits = %s;\n", + i, ro, val_bits_to_str(cmd->required_opt_args[ro].def.val_bits)); + + if (cmd->required_opt_args[ro].def.lvt_bits) + printf("commands[%d].required_opt_args[%d].def.lvt_bits = %s;\n", + i, ro, lvt_bits_to_str(cmd->required_opt_args[ro].def.lvt_bits)); + + 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 (val_bit_is_set(cmd->required_opt_args[ro].def.val_bits, constnum_VAL)) + printf("commands[%d].required_opt_args[%d].def.num = %d;\n", + i, ro, cmd->required_opt_args[ro].def.num); + + if (val_bit_is_set(cmd->required_opt_args[ro].def.val_bits, conststr_VAL)) + printf("commands[%d].required_opt_args[%d].def.str = \"%s\";\n", + i, ro, cmd->required_opt_args[ro].def.str ?: "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.val_bits) + continue; + + printf("commands[%d].required_pos_args[%d].def.val_bits = %s;\n", + i, rp, val_bits_to_str(cmd->required_pos_args[rp].def.val_bits)); + + if (cmd->required_pos_args[rp].def.lvt_bits) + printf("commands[%d].required_pos_args[%d].def.lvt_bits = %s;\n", + i, rp, lvt_bits_to_str(cmd->required_pos_args[rp].def.lvt_bits)); + + 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 (val_bit_is_set(cmd->required_pos_args[rp].def.val_bits, constnum_VAL)) + printf("commands[%d].required_pos_args[%d].def.num = %d;\n", + i, rp, cmd->required_pos_args[rp].def.num); + + if (val_bit_is_set(cmd->required_pos_args[rp].def.val_bits, conststr_VAL)) + printf("commands[%d].required_pos_args[%d].def.str = \"%s\";\n", + i, rp, cmd->required_pos_args[rp].def.str ?: "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.val_bits) + continue; + + printf("commands[%d].optional_opt_args[%d].def.val_bits = %s;\n", + i, oo, val_bits_to_str(cmd->optional_opt_args[oo].def.val_bits)); + + if (cmd->optional_opt_args[oo].def.lvt_bits) + printf("commands[%d].optional_opt_args[%d].def.lvt_bits = %s;\n", + i, oo, lvt_bits_to_str(cmd->optional_opt_args[oo].def.lvt_bits)); + + 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 (val_bit_is_set(cmd->optional_opt_args[oo].def.val_bits, constnum_VAL)) + printf("commands[%d].optional_opt_args[%d].def.num = %d;\n", + i, oo, cmd->optional_opt_args[oo].def.num); + + if (val_bit_is_set(cmd->optional_opt_args[oo].def.val_bits, conststr_VAL)) + printf("commands[%d].optional_opt_args[%d].def.str = \"%s\";\n", + i, oo, cmd->optional_opt_args[oo].def.str ?: "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.val_bits) + continue; + + printf("commands[%d].optional_pos_args[%d].def.val_bits = %s;\n", + i, op, val_bits_to_str(cmd->optional_pos_args[op].def.val_bits)); + + if (cmd->optional_pos_args[op].def.lvt_bits) + printf("commands[%d].optional_pos_args[%d].def.lvt_bits = %s;\n", + i, op, lvt_bits_to_str(cmd->optional_pos_args[op].def.lvt_bits)); + + 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 (val_bit_is_set(cmd->optional_pos_args[op].def.val_bits, constnum_VAL)) + printf("commands[%d].optional_pos_args[%d].def.num = %d;\n", + i, op, cmd->optional_pos_args[op].def.num); + + if (val_bit_is_set(cmd->optional_pos_args[op].def.val_bits, conststr_VAL)) + printf("commands[%d].optional_pos_args[%d].def.str = \"%s\";\n", + i, op, cmd->optional_pos_args[op].def.str ?: "NULL"); + } + } + + if (cmd->rule_count) { + for (ru = 0; ru < cmd->rule_count; ru++) { + printf("commands[%d].rules[%d].opt = %s;\n", i, ru, + cmd->rules[ru].opt ? opt_to_enum_str(cmd->rules[ru].opt) : "0"); + + printf("commands[%d].rules[%d].lvt_bits = %s;\n", i, ru, + cmd->rules[ru].lvt_bits ? lvt_bits_to_str(cmd->rules[ru].lvt_bits) : "0"); + + printf("commands[%d].rules[%d].lvp_bits = %s;\n", i, ru, + cmd->rules[ru].lvp_bits ? lvp_bits_to_str(cmd->rules[ru].lvp_bits) : "0"); + + printf("commands[%d].rules[%d].rule = %s;\n", i, ru, + rule_to_define_str(cmd->rules[ru].rule)); + + printf("commands[%d].rules[%d].check_opt = %s;\n", i, ru, + cmd->rules[ru].check_opt ? opt_to_enum_str(cmd->rules[ru].check_opt) : "0"); + + printf("commands[%d].rules[%d].check_lvt_bits = %s;\n", i, ru, + cmd->rules[ru].check_lvt_bits ? lvt_bits_to_str(cmd->rules[ru].check_lvt_bits) : "0"); + + printf("commands[%d].rules[%d].check_lvp_bits = %s;\n", i, ru, + cmd->rules[ru].check_lvp_bits ? lvp_bits_to_str(cmd->rules[ru].check_lvp_bits) : "0"); + } + } + + printf("\n"); + } +} + +struct cmd_pair { + int i, j; +}; + +static void print_ambiguous(void) +{ + struct command *cmd, *dup; + struct cmd_pair dups[64] = { 0 }; + int found = 0; + int i, j, f, ro, rp; + + for (i = 0; i < cmd_count; i++) { + cmd = &cmd_array[i]; + + for (j = 0; j < cmd_count; j++) { + dup = &cmd_array[j]; + + if (i == j) + continue; + if (strcmp(cmd->name, dup->name)) + continue; + if (cmd->ro_count != dup->ro_count) + continue; + if (cmd->rp_count != dup->rp_count) + continue; + + for (ro = 0; ro < cmd->ro_count; ro++) { + if (!opt_arg_matches(&cmd->required_opt_args[ro], + &dup->required_opt_args[ro])) + goto next; + } + + for (rp = 0; rp < cmd->rp_count; rp++) { + if (!pos_arg_matches(&cmd->required_pos_args[rp], + &dup->required_pos_args[rp])) + goto next; + } + + for (f = 0; f < found; f++) { + if ((dups[f].i == j) && (dups[f].j == i)) + goto next; + } + + printf("Ambiguous commands %d and %d:\n", i, j); + print_usage(cmd); + print_usage(dup); + printf("\n"); + + dups[found].i = i; + dups[found].j = j; + found++; +next: + ; + } + } +} + +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 (%d)\n", + opt_names[i].opt_enum, opt_names[i].name, + opt_names[i].long_opt, opt_names[i].short_opt ?: ' ', + opt_names[i].short_opt ? opt_names[i].short_opt : 0); +} + +static void print_help(int argc, char *argv[]) +{ + printf("%s --output struct|count|usage|expanded <filename>\n", argv[0]); + printf("\n"); + printf("struct: print C structures for command-lines.h\n"); + printf("count: print defines and enums for command-lines-count.h\n"); + printf("ambiguous: print commands differing only by LV types\n"); + printf("usage: print usage format.\n"); + printf("expanded: print expanded input format.\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); + } + + if (!strcmp(argv[1], "debug")) { + print_command_list(); + print_option_list(); + return 0; + } + + static struct option long_options[] = { + {"help", no_argument, 0, 'h' }, + {"output", required_argument, 0, 'o' }, + {"man-primary", required_argument, 0, 'p' }, + {"man-secondary", required_argument, 0, 's' }, + {"man-command", required_argument, 0, 'c' }, + {0, 0, 0, 0 } + }; + + while (1) { + int c; + int option_index = 0; + + c = getopt_long(argc, argv, "ho:p:s:c:", + 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; + case 'p': + include_man_primary = atoi(optarg); + break; + case 's': + include_man_secondary = atoi(optarg); + break; + case 'c': + man_command_name = 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 (line[0] == '-' && line[1] == '-' && line[2] == '-') + 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(line_orig); + if (cmd->desc) { + int newlen = strlen(cmd->desc) + strlen(desc) + 2; + char *newdesc = malloc(newlen); + memset(newdesc, 0, newlen); + snprintf(newdesc, newlen, "%s %s", cmd->desc, desc); + cmd->desc = newdesc; + free(desc); + } else + cmd->desc = desc; + continue; + } + + if (is_flags_line(line_argv[0])) { + add_flags(cmd, line_orig); + continue; + } + + if (is_rule_line(line_argv[0])) { + add_rule(cmd, line_orig); + continue; + } + + if (is_id_line(line_argv[0])) { + cmd->command_line_id = strdup(line_argv[1]); + 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); + + factor_common_options(); + + if (!outputformat) + print_command_struct(1); + else if (!strcmp(outputformat, "struct")) { + print_command_struct(0); + print_ambiguous(); + } + else if (!strcmp(outputformat, "count")) + print_command_count(); + else if (!strcmp(outputformat, "usage")) + print_command_struct(1); + else if (!strcmp(outputformat, "expanded")) + print_expanded(); + else if (!strcmp(outputformat, "ambiguous")) + print_ambiguous(); + else if (!strcmp(outputformat, "man")) + print_man_command(); + else + print_help(argc, argv); + + return 0; +} + |