+ ) functions;
+
+ (* Dispatch function. *)
+ pr "void dispatch_incoming_message (XDR *xdr_in)\n";
+ pr "{\n";
+ pr " switch (proc_nr) {\n";
+
+ List.iter (
+ fun (name, style, _, _, _, _) ->
+ pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
+ pr " %s_stub (xdr_in);\n" name;
+ pr " break;\n"
+ ) functions;
+
+ pr " default:\n";
+ pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
+ pr " }\n";
+ pr "}\n"
+
+(* Generate a lot of different functions for guestfish. *)
+and generate_fish_cmds () =
+ generate_header CStyle GPLv2;
+
+ pr "#include <stdio.h>\n";
+ pr "#include <stdlib.h>\n";
+ pr "#include <string.h>\n";
+ pr "\n";
+ pr "#include \"fish.h\"\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, _, _, _, shortdesc, _) ->
+ pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
+ name shortdesc
+ ) functions;
+ pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
+ pr "}\n";
+ pr "\n";
+
+ (* display_command function, which implements guestfish -h cmd *)
+ pr "void display_command (const char *cmd)\n";
+ pr "{\n";
+ List.iter (
+ fun (name, style, _, flags, shortdesc, longdesc) ->
+ let synopsis =
+ match snd style with
+ | P0 -> name
+ | args ->
+ sprintf "%s <%s>"
+ name (
+ String.concat "> <" (
+ map_args (function
+ | String n -> n) args
+ )
+ ) in
+
+ let warnings =
+ if List.mem ProtocolLimitWarning flags then
+ "\n\nBecause of the message protocol, there is a transfer limit
+of somewhere between 2MB and 4MB. To transfer large files you should use
+FTP."
+ else "" in
+
+ pr " if (strcasecmp (cmd, \"%s\") == 0)\n" name;
+ pr " pod2text (\"%s - %s\", %S);\n"
+ name shortdesc
+ (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings);
+ pr " else\n"
+ ) functions;
+ pr " display_builtin_command (cmd);\n";
+ pr "}\n";
+ pr "\n";
+
+ (* run_<action> actions *)
+ List.iter (
+ fun (name, style, _, _, _, _) ->
+ pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
+ pr "{\n";
+ (match fst style with
+ | Err -> pr " int r;\n"
+ | RString _ -> pr " char *r;\n"
+ | RStringList _ -> pr " char **r;\n"
+ );
+ iter_args (
+ function
+ | String name -> pr " const char *%s;\n" name
+ ) (snd style);
+
+ (* Check and convert parameters. *)
+ let argc_expected = nr_args (snd style) in
+ pr " if (argc != %d) {\n" argc_expected;
+ pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
+ argc_expected;
+ pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
+ pr " return -1;\n";
+ pr " }\n";
+ iteri_args (
+ fun i ->
+ function
+ | String name -> pr " %s = argv[%d];\n" name i
+ ) (snd style);
+
+ (* Call C API function. *)
+ pr " r = guestfs_%s " name;
+ generate_call_args ~handle:"g" style;
+ pr ";\n";
+
+ (* Check return value for errors and display command results. *)
+ (match fst style with
+ | Err -> pr " return r;\n"
+ | RString _ ->
+ pr " if (r == NULL) return -1;\n";
+ pr " printf (\"%%s\", r);\n";
+ pr " free (r);\n";
+ pr " return 0;\n"
+ | RStringList _ ->
+ pr " if (r == NULL) return -1;\n";
+ pr " print_strings (r);\n";
+ pr " free_strings (r);\n";
+ pr " return 0;\n"
+ );
+ pr "}\n";
+ pr "\n"
+ ) functions;
+
+ (* run_action function *)
+ pr "int run_action (const char *cmd, int argc, char *argv[])\n";
+ pr "{\n";
+ List.iter (
+ fun (name, _, _, _, _, _) ->
+ pr " if (strcasecmp (cmd, \"%s\") == 0)\n" name;
+ pr " return run_%s (cmd, argc, argv);\n" name;
+ pr " else\n";
+ ) functions;
+ pr " {\n";
+ pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
+ pr " return -1;\n";
+ pr " }\n";
+ pr " return 0;\n";
+ pr "}\n";
+ pr "\n"