2 * Copyright (C) 2009-2010 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 (* Please read generator/README first. *)
26 open Generator_docstrings
27 open Generator_optgroups
28 open Generator_actions
29 open Generator_structs
30 open Generator_prepopts
33 (* Generate a lot of different functions for guestfish. *)
34 let generate_fish_cmds () =
35 generate_header CStyle GPLv2plus;
39 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
41 let all_functions_sorted =
43 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
44 ) all_functions_sorted in
46 pr "#include <config.h>\n";
48 pr "#include <stdio.h>\n";
49 pr "#include <stdlib.h>\n";
50 pr "#include <string.h>\n";
51 pr "#include <inttypes.h>\n";
53 pr "#include <guestfs.h>\n";
54 pr "#include \"c-ctype.h\"\n";
55 pr "#include \"full-write.h\"\n";
56 pr "#include \"xstrtol.h\"\n";
57 pr "#include \"fish.h\"\n";
59 pr "/* Valid suffixes allowed for numbers. See Gnulib xstrtol function. */\n";
60 pr "static const char *xstrtol_suffixes = \"0kKMGTPEZY\";\n";
63 (* list_commands function, which implements guestfish -h *)
64 pr "void list_commands (void)\n";
66 pr " printf (\" %%-16s %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
67 pr " list_builtin_commands ();\n";
69 fun (name, _, _, flags, _, shortdesc, _) ->
70 let name = replace_char name '_' '-' in
71 pr " printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
73 ) all_functions_sorted;
74 pr " printf (\" %%s\\n\",";
75 pr " _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
79 (* display_command function, which implements guestfish -h cmd *)
80 pr "int display_command (const char *cmd)\n";
83 fun (name, style, _, flags, _, shortdesc, longdesc) ->
84 let name2 = replace_char name '_' '-' in
86 try find_map (function FishAlias n -> Some n | _ -> None) flags
87 with Not_found -> name in
88 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
93 let args = List.filter (function Key _ -> false | _ -> true) args in
95 name2 (String.concat " " (List.map name_of_argt args)) in
98 if List.exists (function Key _ -> true | _ -> false) (snd style) then
99 "\n\nThis command has one or more key or passphrase parameters.
100 Guestfish will prompt for these separately."
105 if List.mem ProtocolLimitWarning flags then
106 ("\n\n" ^ protocol_limit_warning)
109 (* For DangerWillRobinson commands, we should probably have
110 * guestfish prompt before allowing you to use them (especially
111 * in interactive mode). XXX
115 if List.mem DangerWillRobinson flags then
116 ("\n\n" ^ danger_will_robinson)
121 match deprecation_notice flags with
123 | Some txt -> "\n\n" ^ txt in
126 if name <> alias then
127 sprintf "\n\nYou can use '%s' as an alias for this command." alias
131 pr "STRCASEEQ (cmd, \"%s\")" name;
132 if name <> name2 then
133 pr " || STRCASEEQ (cmd, \"%s\")" name2;
134 if name <> alias then
135 pr " || STRCASEEQ (cmd, \"%s\")" alias;
137 pr " pod2text (\"%s\", _(\"%s\"), %S);\n"
139 ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
140 "=head1 DESCRIPTION\n\n" ^
141 longdesc ^ warnings ^ describe_alias);
146 pr " return display_builtin_command (cmd);\n";
150 let emit_print_list_function typ =
151 pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
154 pr " unsigned int i;\n";
156 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
157 pr " printf (\"[%%d] = {\\n\", i);\n";
158 pr " print_%s_indent (&%ss->val[i], \" \");\n" typ typ;
159 pr " printf (\"}\\n\");\n";
165 (* print_* functions *)
169 List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
171 pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
174 pr " unsigned int i;\n";
180 pr " printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
182 pr " printf (\"%%s%s: \", indent);\n" name;
183 pr " for (i = 0; i < 32; ++i)\n";
184 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
185 pr " printf (\"\\n\");\n"
187 pr " printf (\"%%s%s: \", indent);\n" name;
188 pr " for (i = 0; i < %s->%s_len; ++i)\n" typ name;
189 pr " if (c_isprint (%s->%s[i]))\n" typ name;
190 pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
192 pr " printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
193 pr " printf (\"\\n\");\n"
194 | name, (FUInt64|FBytes) ->
195 pr " printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
198 pr " printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
201 pr " printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
204 pr " printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
207 pr " printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
209 | name, FOptPercent ->
210 pr " if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
211 typ name name typ name;
212 pr " else printf (\"%%s%s: \\n\", indent);\n" name
218 (* Emit a print_TYPE_list function definition only if that function is used. *)
221 | typ, (RStructListOnly | RStructAndList) ->
222 (* generate the function for typ *)
223 emit_print_list_function typ
224 | typ, _ -> () (* empty *)
225 ) (rstructs_used_by all_functions);
227 (* Emit a print_TYPE function definition only if that function is used. *)
230 | typ, (RStructOnly | RStructAndList) ->
231 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
233 pr " print_%s_indent (%s, \"\");\n" typ typ;
236 | typ, _ -> () (* empty *)
237 ) (rstructs_used_by all_functions);
239 (* run_<action> actions *)
241 fun (name, style, _, flags, _, _, _) ->
242 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
244 (match fst style with
247 | RBool _ -> pr " int r;\n"
248 | RInt64 _ -> pr " int64_t r;\n"
249 | RConstString _ | RConstOptString _ -> pr " const char *r;\n"
250 | RString _ -> pr " char *r;\n"
251 | RStringList _ | RHashtable _ -> pr " char **r;\n"
252 | RStruct (_, typ) -> pr " struct guestfs_%s *r;\n" typ
253 | RStructList (_, typ) -> pr " struct guestfs_%s_list *r;\n" typ
256 pr " size_t size;\n";
262 | OptString n -> pr " const char *%s;\n" n
267 | Key n -> pr " char *%s;\n" n
269 pr " const char *%s;\n" n;
270 pr " size_t %s_size;\n" n
271 | StringList n | DeviceList n -> pr " char **%s;\n" n
272 | Bool n -> pr " int %s;\n" n
273 | Int n -> pr " int %s;\n" n
274 | Int64 n -> pr " int64_t %s;\n" n
277 (* Check and convert parameters. *)
280 List.filter (function Key _ -> false | _ -> true) (snd style) in
281 List.length args_no_keys in
282 pr " if (argc != %d) {\n" argc_expected;
283 pr " fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
285 pr " fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
289 let parse_integer fn fntyp rtyp range name =
291 pr " strtol_error xerr;\n";
294 pr " xerr = %s (argv[i++], NULL, 0, &r, xstrtol_suffixes);\n" fn;
295 pr " if (xerr != LONGINT_OK) {\n";
296 pr " fprintf (stderr,\n";
297 pr " _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
298 pr " cmd, \"%s\", \"%s\", xerr);\n" name fn;
303 | Some (min, max, comment) ->
304 pr " /* %s */\n" comment;
305 pr " if (r < %s || r > %s) {\n" min max;
306 pr " fprintf (stderr, _(\"%%s: %%s: integer out of range\\n\"), cmd, \"%s\");\n"
310 pr " /* The check above should ensure this assignment does not overflow. */\n";
312 pr " %s = r;\n" name;
316 if snd style <> [] then
317 pr " size_t i = 0;\n";
323 pr " %s = argv[i++];\n" name
325 | Dev_or_Path name ->
326 pr " %s = resolve_win_path (argv[i++]);\n" name;
327 pr " if (%s == NULL) return -1;\n" name
329 pr " %s = STRNEQ (argv[i], \"\") ? argv[i] : NULL;\n" name;
332 pr " %s = argv[i];\n" name;
333 pr " %s_size = strlen (argv[i]);\n" name;
336 pr " %s = file_in (argv[i++]);\n" name;
337 pr " if (%s == NULL) return -1;\n" name
339 pr " %s = file_out (argv[i++]);\n" name;
340 pr " if (%s == NULL) return -1;\n" name
341 | StringList name | DeviceList name ->
342 pr " %s = parse_string_list (argv[i++]);\n" name;
343 pr " if (%s == NULL) return -1;\n" name
345 pr " %s = read_key (\"%s\");\n" name name;
346 pr " if (%s == NULL) return -1;\n" name
348 pr " %s = is_true (argv[i++]) ? 1 : 0;\n" name
351 let min = "(-(2LL<<30))"
352 and max = "((2LL<<30)-1)"
354 "The Int type in the generator is a signed 31 bit int." in
355 Some (min, max, comment) in
356 parse_integer "xstrtoll" "long long" "int" range name
358 parse_integer "xstrtoll" "long long" "int64_t" None name
361 (* Call C API function. *)
362 pr " r = guestfs_%s " name;
363 generate_c_call_args ~handle:"g" style;
368 | Device _ | String _
369 | OptString _ | Bool _
372 | Pathname name | Dev_or_Path name | FileOut name
374 pr " free (%s);\n" name
376 pr " free_file_in (%s);\n" name
377 | StringList name | DeviceList name ->
378 pr " free_strings (%s);\n" name
381 (* Any output flags? *)
383 let flags = filter_map (
384 function FishOutput flag -> Some flag | _ -> None
390 failwithf "%s: more than one FishOutput flag is not allowed" name in
392 (* Check return value for errors and display command results. *)
393 (match fst style with
394 | RErr -> pr " return r;\n"
396 pr " if (r == -1) return -1;\n";
397 (match fish_output with
399 pr " printf (\"%%d\\n\", r);\n";
400 | Some FishOutputOctal ->
401 pr " printf (\"%%s%%o\\n\", r != 0 ? \"0\" : \"\", r);\n";
402 | Some FishOutputHexadecimal ->
403 pr " printf (\"%%s%%x\\n\", r != 0 ? \"0x\" : \"\", r);\n");
406 pr " if (r == -1) return -1;\n";
407 (match fish_output with
409 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
410 | Some FishOutputOctal ->
411 pr " printf (\"%%s%%\" PRIo64 \"\\n\", r != 0 ? \"0\" : \"\", r);\n";
412 | Some FishOutputHexadecimal ->
413 pr " printf (\"%%s%%\" PRIx64 \"\\n\", r != 0 ? \"0x\" : \"\", r);\n");
416 pr " if (r == -1) return -1;\n";
417 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
420 pr " if (r == NULL) return -1;\n";
421 pr " printf (\"%%s\\n\", r);\n";
423 | RConstOptString _ ->
424 pr " printf (\"%%s\\n\", r ? : \"(null)\");\n";
427 pr " if (r == NULL) return -1;\n";
428 pr " printf (\"%%s\\n\", r);\n";
432 pr " if (r == NULL) return -1;\n";
433 pr " print_strings (r);\n";
434 pr " free_strings (r);\n";
436 | RStruct (_, typ) ->
437 pr " if (r == NULL) return -1;\n";
438 pr " print_%s (r);\n" typ;
439 pr " guestfs_free_%s (r);\n" typ;
441 | RStructList (_, typ) ->
442 pr " if (r == NULL) return -1;\n";
443 pr " print_%s_list (r);\n" typ;
444 pr " guestfs_free_%s_list (r);\n" typ;
447 pr " if (r == NULL) return -1;\n";
448 pr " print_table (r);\n";
449 pr " free_strings (r);\n";
452 pr " if (r == NULL) return -1;\n";
453 pr " if (full_write (1, r, size) != size) {\n";
454 pr " perror (\"write\");\n";
465 (* run_action function *)
466 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
469 fun (name, _, _, flags, _, _, _) ->
470 let name2 = replace_char name '_' '-' in
472 try find_map (function FishAlias n -> Some n | _ -> None) flags
473 with Not_found -> name in
475 pr "STRCASEEQ (cmd, \"%s\")" name;
476 if name <> name2 then
477 pr " || STRCASEEQ (cmd, \"%s\")" name2;
478 if name <> alias then
479 pr " || STRCASEEQ (cmd, \"%s\")" alias;
481 pr " return run_%s (cmd, argc, argv);\n" name;
485 pr " fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
486 pr " if (command_num == 1)\n";
487 pr " extended_help_message ();\n";
494 (* Readline completion for guestfish. *)
495 and generate_fish_completion () =
496 generate_header CStyle GPLv2plus;
500 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
510 #ifdef HAVE_LIBREADLINE
511 #include <readline/readline.h>
516 #ifdef HAVE_LIBREADLINE
518 static const char *const commands[] = {
519 BUILTIN_COMMANDS_FOR_COMPLETION,
522 (* Get the commands, including the aliases. They don't need to be
523 * sorted - the generator() function just does a dumb linear search.
527 fun (name, _, _, flags, _, _, _) ->
528 let name2 = replace_char name '_' '-' in
530 try find_map (function FishAlias n -> Some n | _ -> None) flags
531 with Not_found -> name in
533 if name <> alias then [name2; alias] else [name2]
535 let commands = List.flatten commands in
537 List.iter (pr " \"%s\",\n") commands;
543 generator (const char *text, int state)
545 static size_t index, len;
553 rl_attempted_completion_over = 1;
555 while ((name = commands[index]) != NULL) {
557 if (STRCASEEQLEN (name, text, len))
558 return strdup (name);
564 #endif /* HAVE_LIBREADLINE */
566 #ifdef HAVE_RL_COMPLETION_MATCHES
567 #define RL_COMPLETION_MATCHES rl_completion_matches
569 #ifdef HAVE_COMPLETION_MATCHES
570 #define RL_COMPLETION_MATCHES completion_matches
572 #endif /* else just fail if we don't have either symbol */
575 do_completion (const char *text, int start, int end)
577 char **matches = NULL;
579 #ifdef HAVE_LIBREADLINE
580 rl_completion_append_character = ' ';
583 matches = RL_COMPLETION_MATCHES (text, generator);
584 else if (complete_dest_paths)
585 matches = RL_COMPLETION_MATCHES (text, complete_dest_paths_generator);
592 (* Generate the POD documentation for guestfish. *)
593 and generate_fish_actions_pod () =
594 let all_functions_sorted =
596 fun (_, _, _, flags, _, _, _) ->
597 not (List.mem NotInFish flags || List.mem NotInDocs flags)
598 ) all_functions_sorted in
600 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
603 fun (name, style, _, flags, _, _, longdesc) ->
605 Str.global_substitute rex (
608 try Str.matched_group 1 s
610 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
611 "C<" ^ replace_char sub '_' '-' ^ ">"
613 let name = replace_char name '_' '-' in
615 try find_map (function FishAlias n -> Some n | _ -> None) flags
616 with Not_found -> name in
619 if name <> alias then
626 | Pathname n | Device n | Dev_or_Path n | String n ->
628 | OptString n -> pr " %s" n
629 | StringList n | DeviceList n -> pr " '%s ...'" n
630 | Bool _ -> pr " true|false"
631 | Int n -> pr " %s" n
632 | Int64 n -> pr " %s" n
633 | FileIn n | FileOut n -> pr " (%s|-)" n
634 | BufferIn n -> pr " %s" n
635 | Key _ -> () (* keys are entered at a prompt *)
639 pr "%s\n\n" longdesc;
641 if List.exists (function FileIn _ | FileOut _ -> true
642 | _ -> false) (snd style) then
643 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
645 if List.exists (function Key _ -> true | _ -> false) (snd style) then
646 pr "This command has one or more key or passphrase parameters.
647 Guestfish will prompt for these separately.\n\n";
649 if List.mem ProtocolLimitWarning flags then
650 pr "%s\n\n" protocol_limit_warning;
652 if List.mem DangerWillRobinson flags then
653 pr "%s\n\n" danger_will_robinson;
655 match deprecation_notice flags with
657 | Some txt -> pr "%s\n\n" txt
658 ) all_functions_sorted
660 and generate_fish_prep_options_h () =
661 generate_header CStyle GPLv2plus;
663 pr "#ifndef PREPOPTS_H\n";
668 const char *name; /* eg. \"fs\" */
670 size_t nr_params; /* optional parameters */
671 struct prep_param *params;
673 const char *shortdesc; /* short description */
674 const char *longdesc; /* long description */
676 /* functions to implement it */
677 void (*prelaunch) (const char *filename, prep_data *);
678 void (*postlaunch) (const char *filename, prep_data *, const char *device);
682 const char *pname; /* parameter name */
683 const char *pdefault; /* parameter default */
684 const char *pdesc; /* parameter description */
687 extern const struct prep preps[];
690 " (List.length prepopts);
693 fun (name, shortdesc, args, longdesc) ->
695 extern void prep_prelaunch_%s (const char *filename, prep_data *data);
696 extern void prep_postlaunch_%s (const char *filename, prep_data *data, const char *device);
702 pr "#endif /* PREPOPTS_H */\n"
704 and generate_fish_prep_options_c () =
705 generate_header CStyle GPLv2plus;
709 #include \"prepopts.h\"
714 fun (name, shortdesc, args, longdesc) ->
715 pr "static struct prep_param %s_args[] = {\n" name;
717 fun (n, default, desc) ->
718 pr " { \"%s\", \"%s\", \"%s\" },\n" n default desc
724 pr "const struct prep preps[] = {\n";
726 fun (name, shortdesc, args, longdesc) ->
727 pr " { \"%s\", %d, %s_args,
730 prep_prelaunch_%s, prep_postlaunch_%s },
732 name (List.length args) name
733 (c_quote shortdesc) (c_quote longdesc)