pr "#include \"full-write.h\"\n";
pr "#include \"xstrtol.h\"\n";
pr "#include \"fish.h\"\n";
+ pr "#include \"options.h\"\n";
+ pr "#include \"cmds_gperf.h\"\n";
pr "\n";
pr "/* Valid suffixes allowed for numbers. See Gnulib xstrtol function. */\n";
pr "static const char *xstrtol_suffixes = \"0kKMGTPEZY\";\n";
pr "\n";
- (* list_commands function, which implements guestfish -h *)
- pr "void list_commands (void)\n";
- pr "{\n";
- pr " printf (\" %%-16s %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
- pr " list_builtin_commands ();\n";
List.iter (
- fun (name, _, _, flags, _, shortdesc, _) ->
- let name = replace_char name '_' '-' in
- pr " printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
- name shortdesc
- ) all_functions_and_fish_commands_sorted;
- pr " printf (\" %%s\\n\",";
- pr " _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
- pr "}\n";
- pr "\n";
+ fun (name, _, _, _, _, _, _) ->
+ pr "static int run_%s (const char *cmd, size_t argc, char *argv[]);\n"
+ name
+ ) all_functions;
- (* display_command function, which implements guestfish -h cmd *)
- pr "int display_command (const char *cmd)\n";
- pr "{\n";
+ pr "\n";
+ (* List of command_entry structs. *)
List.iter (
fun (name, _, _, flags, _, shortdesc, longdesc) ->
let name2 = replace_char name '_' '-' in
(String.concat " or " (List.map (fun s -> "'" ^ s ^ "'") aliases))
else "" in
- pr " if (";
- pr "STRCASEEQ (cmd, \"%s\")" name;
- if name <> name2 then
- pr " || STRCASEEQ (cmd, \"%s\")" name2;
- List.iter (
- fun alias ->
- pr " || STRCASEEQ (cmd, \"%s\")" alias
- ) aliases;
- pr ") {\n";
- pr " pod2text (\"%s\", _(\"%s\"), %S);\n"
- name2 shortdesc
- ("=head1 DESCRIPTION\n\n" ^
- longdesc ^ describe_alias);
- pr " return 0;\n";
- pr " }\n";
- pr " else\n"
+ let pod =
+ sprintf "%s - %s\n\n=head1 DESCRIPTION\n\n%s\n\n%s"
+ name2 shortdesc longdesc describe_alias in
+ let text =
+ String.concat "\n" (pod2text ~trim:false ~discard:false "NAME" pod)
+ ^ "\n" in
+
+ pr "struct command_entry %s_cmd_entry = {\n" name;
+ pr " .name = \"%s\",\n" name2;
+ pr " .help = \"%s\",\n" (c_quote text);
+ pr " .run = run_%s\n" name;
+ pr "};\n";
+ pr "\n";
) fish_commands;
List.iter (
let name2 = replace_char name '_' '-' in
let aliases =
filter_map (function FishAlias n -> Some n | _ -> None) flags in
+
let longdesc = replace_str longdesc "C<guestfs_" "C<" in
let synopsis =
match args with
(String.concat " or " (List.map (fun s -> "'" ^ s ^ "'") aliases))
else "" in
- pr " if (";
- pr "STRCASEEQ (cmd, \"%s\")" name;
- if name <> name2 then
- pr " || STRCASEEQ (cmd, \"%s\")" name2;
- List.iter (
- fun alias ->
- pr " || STRCASEEQ (cmd, \"%s\")" alias
- ) aliases;
- pr ") {\n";
- pr " pod2text (\"%s\", _(\"%s\"), %S);\n"
- name2 shortdesc
- ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
- "=head1 DESCRIPTION\n\n" ^
- longdesc ^ warnings ^ describe_alias);
- pr " return 0;\n";
- pr " }\n";
- pr " else\n"
+ let pod =
+ sprintf "%s - %s\n\n=head1 SYNOPSIS\n\n %s\n\n=head1 DESCRIPTION\n\n%s%s%s"
+ name2 shortdesc synopsis longdesc warnings describe_alias in
+ let text =
+ String.concat "\n" (pod2text ~trim:false ~discard:false "NAME" pod)
+ ^ "\n" in
+
+ pr "struct command_entry %s_cmd_entry = {\n" name;
+ pr " .name = \"%s\",\n" name2;
+ pr " .help = \"%s\",\n" (c_quote text);
+ pr " .run = run_%s\n" name;
+ pr "};\n";
+ pr "\n";
) all_functions;
+ (* list_commands function, which implements guestfish -h *)
+ pr "void list_commands (void)\n";
+ pr "{\n";
+ pr " printf (\" %%-16s %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
+ pr " list_builtin_commands ();\n";
+ List.iter (
+ fun (name, _, _, flags, _, shortdesc, _) ->
+ let name = replace_char name '_' '-' in
+ pr " printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
+ name shortdesc
+ ) all_functions_and_fish_commands_sorted;
+ pr " printf (\" %%s\\n\",";
+ pr " _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
+ pr "}\n";
+ pr "\n";
+
+ (* display_command function, which implements guestfish -h cmd *)
+ pr "int display_command (const char *cmd)\n";
+ pr "{\n";
+ pr " const struct command_table *ct;\n";
+ pr "\n";
+ pr " ct = lookup_fish_command (cmd, strlen (cmd));\n";
+ pr " if (ct) {\n";
+ pr " fputs (ct->entry->help, stdout);\n";
+ pr " return 0;\n";
+ pr " }\n";
+ pr " else\n";
pr " return display_builtin_command (cmd);\n";
pr "}\n";
pr "\n";
(* run_<action> actions *)
List.iter (
fun (name, (ret, args, optargs as style), _, flags, _, _, _) ->
- pr "static int run_%s (const char *cmd, size_t argc, char *argv[])\n" name;
+ pr "static int\n";
+ pr "run_%s (const char *cmd, size_t argc, char *argv[])\n" name;
pr "{\n";
(match ret with
| RErr
| Bool n -> pr " int %s;\n" n
| Int n -> pr " int %s;\n" n
| Int64 n -> pr " int64_t %s;\n" n
+ | Pointer _ -> assert false
) args;
if optargs <> [] then (
parse_integer "argv[i++]" "xstrtoll" "long long" "int" range name
| Int64 name ->
parse_integer "argv[i++]" "xstrtoll" "long long" "int64_t" None name
+ | Pointer _ -> assert false
) args;
(* Optional arguments are prefixed with <argname>:<value> and
pr " for (; i < argc; ++i) {\n";
pr " uint64_t this_mask;\n";
pr " const char *this_arg;\n";
+ pr "\n";
+ pr " ";
List.iter (
fun argt ->
let n = name_of_argt argt in
let uc_n = String.uppercase n in
let len = String.length n in
- pr " if (STRPREFIX (argv[i], \"%s:\")) {\n" n;
+ pr "if (STRPREFIX (argv[i], \"%s:\")) {\n" n;
(match argt with
| Bool n ->
pr " optargs_s.%s = is_true (&argv[i][%d]) ? 1 : 0;\n"
"The Int type in the generator is a signed 31 bit int." in
Some (min, max, comment) in
let expr = sprintf "&argv[i][%d]" (len+1) in
- parse_integer expr "xstrtoll" "long long" "int" range name
+ parse_integer expr "xstrtoll" "long long" "int" range
+ (sprintf "optargs_s.%s" n)
| Int64 n ->
let expr = sprintf "&argv[i][%d]" (len+1) in
- parse_integer expr "xstrtoll" "long long" "int64_t" None name
+ parse_integer expr "xstrtoll" "long long" "int64_t" None
+ (sprintf "optargs_s.%s" n)
| String n ->
pr " optargs_s.%s = &argv[i][%d];\n" n (len+1);
| _ -> assert false
pr " this_mask = GUESTFS_%s_%s_BITMASK;\n" uc_name uc_n;
pr " this_arg = \"%s\";\n" n;
pr " }\n";
+ pr " else ";
) optargs;
+ pr "{\n";
+ pr " fprintf (stderr, _(\"%%s: unknown optional argument \\\"%%s\\\"\\n\"),\n";
+ pr " cmd, argv[i]);\n";
+ pr " return -1;\n";
+ pr " }\n";
+ pr "\n";
pr " if (optargs_s.bitmask & this_mask) {\n";
- pr " fprintf (stderr, _(\"%%s: optional argument %%s given twice\\n\"),\n";
+ pr " fprintf (stderr, _(\"%%s: optional argument \\\"%%s\\\" given twice\\n\"),\n";
pr " cmd, this_arg);\n";
pr " return -1;\n";
pr " }\n";
pr " free_file_in (%s);\n" name
| StringList name | DeviceList name ->
pr " free_strings (%s);\n" name
+ | Pointer _ -> assert false
) args;
(* Any output flags? *)
) all_functions;
(* run_action function *)
- pr "int run_action (const char *cmd, size_t argc, char *argv[])\n";
+ pr "int\n";
+ pr "run_action (const char *cmd, size_t argc, char *argv[])\n";
pr "{\n";
+ pr " const struct command_table *ct;\n";
+ pr "\n";
+ pr " ct = lookup_fish_command (cmd, strlen (cmd));\n";
+ pr " if (ct)\n";
+ pr " return ct->entry->run (cmd, argc, argv);\n";
+ pr " else {\n";
+ pr " fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
+ pr " if (command_num == 1)\n";
+ pr " extended_help_message ();\n";
+ pr " return -1;\n";
+ pr " }\n";
+ pr "}\n"
+
+(* gperf code to do fast lookups of commands. *)
+and generate_fish_cmds_gperf () =
+ generate_header CStyle GPLv2plus;
+
+ let all_functions_sorted =
+ List.filter (
+ fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
+ ) all_functions_sorted in
+
+ let all_functions_and_fish_commands_sorted =
+ List.sort action_compare (all_functions_sorted @ fish_commands) in
+
+ pr "\
+%%language=ANSI-C
+%%define lookup-function-name lookup_fish_command
+%%ignore-case
+%%readonly-tables
+%%null-strings
+
+%%{
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include \"cmds_gperf.h\"
+
+";
+
+ List.iter (
+ fun (name, _, _, _, _, _, _) ->
+ pr "extern struct command_entry %s_cmd_entry;\n" name
+ ) all_functions_and_fish_commands_sorted;
+
+ pr "\
+%%}
+
+struct command_table;
+
+%%%%
+";
List.iter (
fun (name, _, _, flags, _, _, _) ->
let name2 = replace_char name '_' '-' in
let aliases =
filter_map (function FishAlias n -> Some n | _ -> None) flags in
- pr " if (";
- pr "STRCASEEQ (cmd, \"%s\")" name;
+
+ (* The basic command. *)
+ pr "%s, &%s_cmd_entry\n" name name;
+
+ (* Command with dashes instead of underscores. *)
if name <> name2 then
- pr " || STRCASEEQ (cmd, \"%s\")" name2;
+ pr "%s, &%s_cmd_entry\n" name2 name;
+
+ (* Aliases for the command. *)
List.iter (
fun alias ->
- pr " || STRCASEEQ (cmd, \"%s\")" alias;
+ pr "%s, &%s_cmd_entry\n" alias name;
) aliases;
- pr ")\n";
- pr " return run_%s (cmd, argc, argv);\n" name;
- pr " else\n";
- ) all_functions_and_fish_commands_sorted;
-
- pr " {\n";
- pr " fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
- pr " if (command_num == 1)\n";
- pr " extended_help_message ();\n";
- pr " return -1;\n";
- pr " }\n";
- pr " return 0;\n";
- pr "}\n";
- pr "\n"
+ ) all_functions_and_fish_commands_sorted
(* Readline completion for guestfish. *)
and generate_fish_completion () =
| FileIn n | FileOut n -> pr " (%s|-)" n
| BufferIn n -> pr " %s" n
| Key _ -> () (* keys are entered at a prompt *)
+ | Pointer _ -> assert false
) args;
List.iter (
function
generate_header CStyle GPLv2plus;
pr "\
+#include <stdio.h>
+
#include \"fish.h\"
#include \"prepopts.h\"