diff mbox

[v5,2/2] Use help sub-sections to create sub-help options

Message ID 1442253680-8657-3-git-send-email-lvivier@redhat.com
State New
Headers show

Commit Message

Laurent Vivier Sept. 14, 2015, 6:01 p.m. UTC
As '-help' output is 400 lines long it is not easy
to find information, but generally we know from
which area we want the information.

As sections already exist in the help description,
add some options to only display the wanted section.

'-help' now can take an optional parameter of the
form -help[=LIST], which is a comma separated list
of sections to display:

    all       display all help sections
    help      display help options
    standard  display standard options
    block     display block options
    usb       display usb options
    display   display display options
    machine   display machine options
    network   display network options
    character display character options
    url       display url options
    bt        display bt options
    tpm       display tpm options
    kernel    display kernel options
    expert    display expert options
    object    display object options

'-help' without option displays only help options.

Example:

    $ x86_64-softmmu/qemu-system-x86_64 -help=kernel,usb
    QEMU emulator version 2.4.50, Copyright (c) 2003-2008 Fabrice Bellard
    usage: qemu-system-x86_64 [options] [disk_image]

    'disk_image' is a raw hard disk image for IDE hard disk 0

    Linux/Multiboot boot specific:
    -kernel bzImage use 'bzImage' as kernel image
    -append cmdline use 'cmdline' as kernel command line
    -initrd file    use 'file' as initial ram disk
    -dtb    file    use 'file' as device tree image

    USB options:
    -usb            enable the USB driver (will be the default soon)
    -usbdevice name add the host or guest USB device 'name'

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
 qemu-options.hx | 124 ++++++++++++++++++++++++++++++++++++++++---
 vl.c            | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 274 insertions(+), 10 deletions(-)

Comments

Laurent Vivier Sept. 24, 2015, 4:14 p.m. UTC | #1
ping ?

On 14/09/2015 20:01, Laurent Vivier wrote:
> As '-help' output is 400 lines long it is not easy
> to find information, but generally we know from
> which area we want the information.
> 
> As sections already exist in the help description,
> add some options to only display the wanted section.
> 
> '-help' now can take an optional parameter of the
> form -help[=LIST], which is a comma separated list
> of sections to display:
> 
>     all       display all help sections
>     help      display help options
>     standard  display standard options
>     block     display block options
>     usb       display usb options
>     display   display display options
>     machine   display machine options
>     network   display network options
>     character display character options
>     url       display url options
>     bt        display bt options
>     tpm       display tpm options
>     kernel    display kernel options
>     expert    display expert options
>     object    display object options
> 
> '-help' without option displays only help options.
> 
> Example:
> 
>     $ x86_64-softmmu/qemu-system-x86_64 -help=kernel,usb
>     QEMU emulator version 2.4.50, Copyright (c) 2003-2008 Fabrice Bellard
>     usage: qemu-system-x86_64 [options] [disk_image]
> 
>     'disk_image' is a raw hard disk image for IDE hard disk 0
> 
>     Linux/Multiboot boot specific:
>     -kernel bzImage use 'bzImage' as kernel image
>     -append cmdline use 'cmdline' as kernel command line
>     -initrd file    use 'file' as initial ram disk
>     -dtb    file    use 'file' as device tree image
> 
>     USB options:
>     -usb            enable the USB driver (will be the default soon)
>     -usbdevice name add the host or guest USB device 'name'
> 
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> ---
>  qemu-options.hx | 124 ++++++++++++++++++++++++++++++++++++++++---
>  vl.c            | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 274 insertions(+), 10 deletions(-)
> 
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 166eae6..9216b02 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -6,17 +6,80 @@ HXCOMM construct option structures, enums and help message for specified
>  HXCOMM architectures.
>  HXCOMM HXCOMM can be used for comments, discarded from both texi and C
>  
> -DEFHEADING(Standard options:)
> +#if defined(QEMU_HELP_SELECT_HELP) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_HELP
> +DEFHEADING(Help/version options:)
>  STEXI
>  @table @option
>  ETEXI
>  
>  DEF("help", 0, QEMU_OPTION_h,
> -    "-h or -help     display this help and exit\n", QEMU_ARCH_ALL)
> -STEXI
> -@item -h
> +    "-h|-help[=section[,...]]\n"
> +    "                list help options.\n"
> +    "                You can provide the list of sections to display.\n"
> +    "                available sections are:\n"
> +    "                all,help,standard,block,usb,display,machine,network,\n"
> +    "                character,url,bt,tpm,kernel,expert,object\n" , QEMU_ARCH_ALL)
> +STEXI
> +@item -help [section][,...]
>  @findex -h
> -Display help and exit
> +list help options.
> +
> +You can provide the list of sections to display:
> +@table @option
> +@item all
> +display all sections
> +@item help
> +display help options
> +@item standard
> +display standard options
> +@item block
> +display block options
> +@item usb
> +display usb options
> +@item display
> +display display options
> +@item machine
> +display machine options
> +@item network
> +display network options
> +@item character
> +display character options
> +@item url
> +display url options
> +@item bt
> +display bt options
> +@item tpm
> +display tpm options
> +@item kernel
> +display kernel options
> +@item expert
> +display expert options
> +@item object
> +display object options
> +@end table
> +
> +'-help' without option displays help options.
> +
> +@example
> +Example:
> +    $ x86_64-softmmu/qemu-system-x86_64 -help=kernel,usb
> +    QEMU emulator version 2.4.50, Copyright (c) 2003-2008 Fabrice Bellard
> +    usage: qemu-system-x86_64 [options] [disk_image]
> +
> +    'disk_image' is a raw hard disk image for IDE hard disk 0
> +
> +    Linux/Multiboot boot specific:
> +    -kernel bzImage use 'bzImage' as kernel image
> +    -append cmdline use 'cmdline' as kernel command line
> +    -initrd file    use 'file' as initial ram disk
> +    -dtb    file    use 'file' as device tree image
> +
> +    USB options:
> +    -usb            enable the USB driver (will be the default soon)
> +    -usbdevice name add the host or guest USB device 'name'
> +@end example
> +
>  ETEXI
>  
>  DEF("version", 0, QEMU_OPTION_version,
> @@ -27,6 +90,19 @@ STEXI
>  Display version information and exit
>  ETEXI
>  
> +STEXI
> +@end table
> +ETEXI
> +DEFHEADING()
> +#endif
> +
> +#if defined(QEMU_HELP_SELECT_STANDARD) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_STANDARD
> +DEFHEADING(Standard options:)
> +STEXI
> +@table @option
> +ETEXI
> +
>  DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
>      "-machine [type=]name[,prop[=value][,...]]\n"
>      "                selects emulated machine ('-machine help' for list)\n"
> @@ -413,7 +489,10 @@ STEXI
>  @end table
>  ETEXI
>  DEFHEADING()
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_BLOCK) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_BLOCK
>  DEFHEADING(Block device options:)
>  STEXI
>  @table @option
> @@ -801,7 +880,10 @@ STEXI
>  @end table
>  ETEXI
>  DEFHEADING()
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_USB) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_USB
>  DEFHEADING(USB options:)
>  STEXI
>  @table @option
> @@ -865,7 +947,10 @@ STEXI
>  @end table
>  ETEXI
>  DEFHEADING()
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_DISPLAY) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_DISPLAY
>  DEFHEADING(Display options:)
>  STEXI
>  @table @option
> @@ -1332,7 +1417,10 @@ STEXI
>  @end table
>  ETEXI
>  ARCHHEADING(, QEMU_ARCH_I386)
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_MACHINE) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_MACHINE
>  ARCHHEADING(i386 target only:, QEMU_ARCH_I386)
>  STEXI
>  @table @option
> @@ -1444,7 +1532,10 @@ STEXI
>  @end table
>  ETEXI
>  DEFHEADING()
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_NETWORK) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_NETWORK
>  DEFHEADING(Network options:)
>  STEXI
>  @table @option
> @@ -1998,7 +2089,10 @@ STEXI
>  @end table
>  ETEXI
>  DEFHEADING()
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_CHARACTER) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_CHARACTER
>  DEFHEADING(Character device options:)
>  STEXI
>  
> @@ -2276,7 +2370,10 @@ STEXI
>  @end table
>  ETEXI
>  DEFHEADING()
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_URL) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_URL
>  DEFHEADING(Device URL Syntax:)
>  STEXI
>  
> @@ -2485,7 +2582,10 @@ ETEXI
>  STEXI
>  @end table
>  ETEXI
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_BT) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_BT
>  DEFHEADING(Bluetooth(R) options:)
>  STEXI
>  @table @option
> @@ -2560,7 +2660,10 @@ STEXI
>  @end table
>  ETEXI
>  DEFHEADING()
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_TPM) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_TPM
>  #ifdef CONFIG_TPM
>  DEFHEADING(TPM device options:)
>  
> @@ -2635,7 +2738,10 @@ ETEXI
>  DEFHEADING()
>  
>  #endif
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_KERNEL) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_KERNEL
>  DEFHEADING(Linux/Multiboot boot specific:)
>  STEXI
>  
> @@ -2691,7 +2797,10 @@ STEXI
>  @end table
>  ETEXI
>  DEFHEADING()
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_EXPERT) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_EXPERT
>  DEFHEADING(Debug/Expert options:)
>  STEXI
>  @table @option
> @@ -3521,7 +3630,10 @@ STEXI
>  Dump json-encoded vmstate information for current machine type to file
>  in @var{file}
>  ETEXI
> +#endif
>  
> +#if defined(QEMU_HELP_SELECT_OBJECT) || !defined(QEMU_HELP_SELECT)
> +#undef QEMU_HELP_SELECT_OBJECT
>  DEFHEADING(Generic object creation)
>  
>  DEF("object", HAS_ARG, QEMU_OPTION_object,
> @@ -3574,7 +3686,7 @@ to the RNG daemon.
>  @end table
>  
>  ETEXI
> -
> +#endif
>  
>  HXCOMM This is the last statement. Insert new options before this line!
>  STEXI
> diff --git a/vl.c b/vl.c
> index 586ce55..5d05dee 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -1916,15 +1916,167 @@ static void version(void)
>      printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
>  }
>  
> -static void help(int exitcode)
> +#define QEMU_HELP_SELECT
> +static void help_help(void)
>  {
> +#define QEMU_HELP_SELECT_HELP
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_standard(void)
> +{
> +#define QEMU_HELP_SELECT_STANDARD
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_block(void)
> +{
> +#define QEMU_HELP_SELECT_BLOCK
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_usb(void)
> +{
> +#define QEMU_HELP_SELECT_USB
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_display(void)
> +{
> +#define QEMU_HELP_SELECT_DISPLAY
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_machine(void)
> +{
> +#define QEMU_HELP_SELECT_MACHINE
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_network(void)
> +{
> +#define QEMU_HELP_SELECT_NETWORK
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_character(void)
> +{
> +#define QEMU_HELP_SELECT_CHARACTER
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_url(void)
> +{
> +#define QEMU_HELP_SELECT_URL
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_bt(void)
> +{
> +#define QEMU_HELP_SELECT_BT
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +#ifdef CONFIG_TPM
> +static void help_tpm(void)
> +{
> +#define QEMU_HELP_SELECT_TPM
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +#endif
> +static void help_kernel(void)
> +{
> +#define QEMU_HELP_SELECT_KERNEL
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_expert(void)
> +{
> +#define QEMU_HELP_SELECT_EXPERT
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +static void help_object(void)
> +{
> +#define QEMU_HELP_SELECT_OBJECT
> +#define QEMU_OPTIONS_GENERATE_HELP
> +#include "qemu-options-wrapper.h"
> +}
> +#undef QEMU_HELP_SELECT
> +
> +#define SUBHELP(n) { .name = #n, .handler = help_##n }
> +typedef struct {
> +    const char *name;
> +    void (*handler)(void);
> +} QEMUHelpOptions;
> +
> +static void help_all(void);
> +static QEMUHelpOptions help_handler[] = {
> +    SUBHELP(all), /* must be the first */
> +    SUBHELP(standard),
> +    SUBHELP(block),
> +    SUBHELP(usb),
> +    SUBHELP(display),
> +    SUBHELP(machine),
> +    SUBHELP(network),
> +    SUBHELP(character),
> +    SUBHELP(url),
> +    SUBHELP(bt),
> +#ifdef CONFIG_TPM
> +    SUBHELP(tpm),
> +#endif
> +    SUBHELP(kernel),
> +    SUBHELP(expert),
> +    SUBHELP(object),
> +    SUBHELP(help),
> +    { NULL, NULL }
> +};
> +
> +static void help_all(void)
> +{
> +    int i;
> +
> +    for (i = 1; help_handler[i].handler; i++) {
> +        help_handler[i].handler();
> +    }
> +}
> +
> +static void help(const char *optarg, int exitcode)
> +{
> +    const char *p, *e;
> +    size_t l;
> +    int i;
> +
>      version();
>      printf("usage: %s [options] [disk_image]\n\n"
>             "'disk_image' is a raw hard disk image for IDE hard disk 0\n\n",
>              error_get_progname());
>  
> -#define QEMU_OPTIONS_GENERATE_HELP
> -#include "qemu-options-wrapper.h"
> +    if (optarg == NULL) {
> +        help_help();
> +        exit(exitcode);
> +    }
> +
> +    p = optarg;
> +    while (*p) {
> +        e = strchr(p, ',');
> +        l = !e ? strlen(p) : (size_t) (e - p);
> +        for (i = 0; help_handler[i].handler; i++) {
> +            if (l != strlen(help_handler[i].name)) {
> +                continue;
> +            }
> +            if (strncmp(help_handler[i].name, p, l) == 0) {
> +                break;
> +            }
> +        }
> +        if (help_handler[i].handler) {
> +            help_handler[i].handler();
> +        } else {
> +            printf("Unknown help option \"%.*s\"\n", (int)l, p);
> +        }
> +        p += l + (e != NULL);
> +    }
>  
>      printf("\nDuring emulation, the following keys are useful:\n"
>             "ctrl-alt-f      toggle full screen\n"
> @@ -3330,7 +3482,7 @@ int main(int argc, char **argv, char **envp)
>                  select_soundhw (optarg);
>                  break;
>              case QEMU_OPTION_h:
> -                help(0);
> +                help(optarg, 0);
>                  break;
>              case QEMU_OPTION_version:
>                  version();
>
Michael S. Tsirkin Oct. 5, 2015, 9 p.m. UTC | #2
On Mon, Sep 14, 2015 at 08:01:20PM +0200, Laurent Vivier wrote:
> As '-help' output is 400 lines long it is not easy
> to find information, but generally we know from
> which area we want the information.

I agree - a bit more order is IMHO needed in the general
-help - I'm not sure this is the place to start.
E.g. it is not your fault that it lists e.g. a ton of random
stuff as Standard options but this becomes more of
a problem if you hide things behind sub-sections.

For example, how do I change the amount of memory?
Currently I do --help and search for memory.


This also diverges from the way one queries other help
(-device foo,help, -cpu help  etc).

How about we move detailed help into each option instead?
This will mean only 113 lines which is a lot, but
kind of reasonable.

-machine [type=]name[,prop[=value][,...]] select emulated machine ('-machine help' for help)
-cpu cpu        select CPU ('-cpu help' for list)
-smp [cpus=]n[,prop[=value][,...]] configure SMP ('-smp help' for help)
-numa node[,prop[=value][,...]] configure NUMA ('-numa help' for help)


Of course it's also true that often the help says
nothing useful at all.


> As sections already exist in the help description,
> add some options to only display the wanted section.
> 
> '-help' now can take an optional parameter of the
> form -help[=LIST], which is a comma separated list
> of sections to display:
> 
>     all       display all help sections
>     help      display help options
>     standard  display standard options

What does standard options mean?

>     block     display block options
>     usb       display usb options
>     display   display display options
>     machine   display machine options
>     network   display network options
>     character display character options

Character device options?

>     url       display url options

what are these?

>     bt        display bt options

bluetooth options?

>     tpm       display tpm options
>     kernel    display kernel options
>     expert    display expert options
>     object    display object options

what are these?

> 
> '-help' without option displays only help options.
> 
> Example:
> 
>     $ x86_64-softmmu/qemu-system-x86_64 -help=kernel,usb
>     QEMU emulator version 2.4.50, Copyright (c) 2003-2008 Fabrice Bellard
>     usage: qemu-system-x86_64 [options] [disk_image]
> 
>     'disk_image' is a raw hard disk image for IDE hard disk 0
> 
>     Linux/Multiboot boot specific:
>     -kernel bzImage use 'bzImage' as kernel image
>     -append cmdline use 'cmdline' as kernel command line
>     -initrd file    use 'file' as initial ram disk
>     -dtb    file    use 'file' as device tree image
> 
>     USB options:
>     -usb            enable the USB driver (will be the default soon)
>     -usbdevice name add the host or guest USB device 'name'
> 
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>

Maybe a good place to start is rewriting our man page.
We can then distill that to a minimum that makes sense
in -help.
diff mbox

Patch

diff --git a/qemu-options.hx b/qemu-options.hx
index 166eae6..9216b02 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -6,17 +6,80 @@  HXCOMM construct option structures, enums and help message for specified
 HXCOMM architectures.
 HXCOMM HXCOMM can be used for comments, discarded from both texi and C
 
-DEFHEADING(Standard options:)
+#if defined(QEMU_HELP_SELECT_HELP) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_HELP
+DEFHEADING(Help/version options:)
 STEXI
 @table @option
 ETEXI
 
 DEF("help", 0, QEMU_OPTION_h,
-    "-h or -help     display this help and exit\n", QEMU_ARCH_ALL)
-STEXI
-@item -h
+    "-h|-help[=section[,...]]\n"
+    "                list help options.\n"
+    "                You can provide the list of sections to display.\n"
+    "                available sections are:\n"
+    "                all,help,standard,block,usb,display,machine,network,\n"
+    "                character,url,bt,tpm,kernel,expert,object\n" , QEMU_ARCH_ALL)
+STEXI
+@item -help [section][,...]
 @findex -h
-Display help and exit
+list help options.
+
+You can provide the list of sections to display:
+@table @option
+@item all
+display all sections
+@item help
+display help options
+@item standard
+display standard options
+@item block
+display block options
+@item usb
+display usb options
+@item display
+display display options
+@item machine
+display machine options
+@item network
+display network options
+@item character
+display character options
+@item url
+display url options
+@item bt
+display bt options
+@item tpm
+display tpm options
+@item kernel
+display kernel options
+@item expert
+display expert options
+@item object
+display object options
+@end table
+
+'-help' without option displays help options.
+
+@example
+Example:
+    $ x86_64-softmmu/qemu-system-x86_64 -help=kernel,usb
+    QEMU emulator version 2.4.50, Copyright (c) 2003-2008 Fabrice Bellard
+    usage: qemu-system-x86_64 [options] [disk_image]
+
+    'disk_image' is a raw hard disk image for IDE hard disk 0
+
+    Linux/Multiboot boot specific:
+    -kernel bzImage use 'bzImage' as kernel image
+    -append cmdline use 'cmdline' as kernel command line
+    -initrd file    use 'file' as initial ram disk
+    -dtb    file    use 'file' as device tree image
+
+    USB options:
+    -usb            enable the USB driver (will be the default soon)
+    -usbdevice name add the host or guest USB device 'name'
+@end example
+
 ETEXI
 
 DEF("version", 0, QEMU_OPTION_version,
@@ -27,6 +90,19 @@  STEXI
 Display version information and exit
 ETEXI
 
+STEXI
+@end table
+ETEXI
+DEFHEADING()
+#endif
+
+#if defined(QEMU_HELP_SELECT_STANDARD) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_STANDARD
+DEFHEADING(Standard options:)
+STEXI
+@table @option
+ETEXI
+
 DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "-machine [type=]name[,prop[=value][,...]]\n"
     "                selects emulated machine ('-machine help' for list)\n"
@@ -413,7 +489,10 @@  STEXI
 @end table
 ETEXI
 DEFHEADING()
+#endif
 
+#if defined(QEMU_HELP_SELECT_BLOCK) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_BLOCK
 DEFHEADING(Block device options:)
 STEXI
 @table @option
@@ -801,7 +880,10 @@  STEXI
 @end table
 ETEXI
 DEFHEADING()
+#endif
 
+#if defined(QEMU_HELP_SELECT_USB) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_USB
 DEFHEADING(USB options:)
 STEXI
 @table @option
@@ -865,7 +947,10 @@  STEXI
 @end table
 ETEXI
 DEFHEADING()
+#endif
 
+#if defined(QEMU_HELP_SELECT_DISPLAY) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_DISPLAY
 DEFHEADING(Display options:)
 STEXI
 @table @option
@@ -1332,7 +1417,10 @@  STEXI
 @end table
 ETEXI
 ARCHHEADING(, QEMU_ARCH_I386)
+#endif
 
+#if defined(QEMU_HELP_SELECT_MACHINE) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_MACHINE
 ARCHHEADING(i386 target only:, QEMU_ARCH_I386)
 STEXI
 @table @option
@@ -1444,7 +1532,10 @@  STEXI
 @end table
 ETEXI
 DEFHEADING()
+#endif
 
+#if defined(QEMU_HELP_SELECT_NETWORK) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_NETWORK
 DEFHEADING(Network options:)
 STEXI
 @table @option
@@ -1998,7 +2089,10 @@  STEXI
 @end table
 ETEXI
 DEFHEADING()
+#endif
 
+#if defined(QEMU_HELP_SELECT_CHARACTER) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_CHARACTER
 DEFHEADING(Character device options:)
 STEXI
 
@@ -2276,7 +2370,10 @@  STEXI
 @end table
 ETEXI
 DEFHEADING()
+#endif
 
+#if defined(QEMU_HELP_SELECT_URL) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_URL
 DEFHEADING(Device URL Syntax:)
 STEXI
 
@@ -2485,7 +2582,10 @@  ETEXI
 STEXI
 @end table
 ETEXI
+#endif
 
+#if defined(QEMU_HELP_SELECT_BT) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_BT
 DEFHEADING(Bluetooth(R) options:)
 STEXI
 @table @option
@@ -2560,7 +2660,10 @@  STEXI
 @end table
 ETEXI
 DEFHEADING()
+#endif
 
+#if defined(QEMU_HELP_SELECT_TPM) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_TPM
 #ifdef CONFIG_TPM
 DEFHEADING(TPM device options:)
 
@@ -2635,7 +2738,10 @@  ETEXI
 DEFHEADING()
 
 #endif
+#endif
 
+#if defined(QEMU_HELP_SELECT_KERNEL) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_KERNEL
 DEFHEADING(Linux/Multiboot boot specific:)
 STEXI
 
@@ -2691,7 +2797,10 @@  STEXI
 @end table
 ETEXI
 DEFHEADING()
+#endif
 
+#if defined(QEMU_HELP_SELECT_EXPERT) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_EXPERT
 DEFHEADING(Debug/Expert options:)
 STEXI
 @table @option
@@ -3521,7 +3630,10 @@  STEXI
 Dump json-encoded vmstate information for current machine type to file
 in @var{file}
 ETEXI
+#endif
 
+#if defined(QEMU_HELP_SELECT_OBJECT) || !defined(QEMU_HELP_SELECT)
+#undef QEMU_HELP_SELECT_OBJECT
 DEFHEADING(Generic object creation)
 
 DEF("object", HAS_ARG, QEMU_OPTION_object,
@@ -3574,7 +3686,7 @@  to the RNG daemon.
 @end table
 
 ETEXI
-
+#endif
 
 HXCOMM This is the last statement. Insert new options before this line!
 STEXI
diff --git a/vl.c b/vl.c
index 586ce55..5d05dee 100644
--- a/vl.c
+++ b/vl.c
@@ -1916,15 +1916,167 @@  static void version(void)
     printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
 }
 
-static void help(int exitcode)
+#define QEMU_HELP_SELECT
+static void help_help(void)
 {
+#define QEMU_HELP_SELECT_HELP
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_standard(void)
+{
+#define QEMU_HELP_SELECT_STANDARD
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_block(void)
+{
+#define QEMU_HELP_SELECT_BLOCK
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_usb(void)
+{
+#define QEMU_HELP_SELECT_USB
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_display(void)
+{
+#define QEMU_HELP_SELECT_DISPLAY
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_machine(void)
+{
+#define QEMU_HELP_SELECT_MACHINE
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_network(void)
+{
+#define QEMU_HELP_SELECT_NETWORK
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_character(void)
+{
+#define QEMU_HELP_SELECT_CHARACTER
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_url(void)
+{
+#define QEMU_HELP_SELECT_URL
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_bt(void)
+{
+#define QEMU_HELP_SELECT_BT
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+#ifdef CONFIG_TPM
+static void help_tpm(void)
+{
+#define QEMU_HELP_SELECT_TPM
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+#endif
+static void help_kernel(void)
+{
+#define QEMU_HELP_SELECT_KERNEL
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_expert(void)
+{
+#define QEMU_HELP_SELECT_EXPERT
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+static void help_object(void)
+{
+#define QEMU_HELP_SELECT_OBJECT
+#define QEMU_OPTIONS_GENERATE_HELP
+#include "qemu-options-wrapper.h"
+}
+#undef QEMU_HELP_SELECT
+
+#define SUBHELP(n) { .name = #n, .handler = help_##n }
+typedef struct {
+    const char *name;
+    void (*handler)(void);
+} QEMUHelpOptions;
+
+static void help_all(void);
+static QEMUHelpOptions help_handler[] = {
+    SUBHELP(all), /* must be the first */
+    SUBHELP(standard),
+    SUBHELP(block),
+    SUBHELP(usb),
+    SUBHELP(display),
+    SUBHELP(machine),
+    SUBHELP(network),
+    SUBHELP(character),
+    SUBHELP(url),
+    SUBHELP(bt),
+#ifdef CONFIG_TPM
+    SUBHELP(tpm),
+#endif
+    SUBHELP(kernel),
+    SUBHELP(expert),
+    SUBHELP(object),
+    SUBHELP(help),
+    { NULL, NULL }
+};
+
+static void help_all(void)
+{
+    int i;
+
+    for (i = 1; help_handler[i].handler; i++) {
+        help_handler[i].handler();
+    }
+}
+
+static void help(const char *optarg, int exitcode)
+{
+    const char *p, *e;
+    size_t l;
+    int i;
+
     version();
     printf("usage: %s [options] [disk_image]\n\n"
            "'disk_image' is a raw hard disk image for IDE hard disk 0\n\n",
             error_get_progname());
 
-#define QEMU_OPTIONS_GENERATE_HELP
-#include "qemu-options-wrapper.h"
+    if (optarg == NULL) {
+        help_help();
+        exit(exitcode);
+    }
+
+    p = optarg;
+    while (*p) {
+        e = strchr(p, ',');
+        l = !e ? strlen(p) : (size_t) (e - p);
+        for (i = 0; help_handler[i].handler; i++) {
+            if (l != strlen(help_handler[i].name)) {
+                continue;
+            }
+            if (strncmp(help_handler[i].name, p, l) == 0) {
+                break;
+            }
+        }
+        if (help_handler[i].handler) {
+            help_handler[i].handler();
+        } else {
+            printf("Unknown help option \"%.*s\"\n", (int)l, p);
+        }
+        p += l + (e != NULL);
+    }
 
     printf("\nDuring emulation, the following keys are useful:\n"
            "ctrl-alt-f      toggle full screen\n"
@@ -3330,7 +3482,7 @@  int main(int argc, char **argv, char **envp)
                 select_soundhw (optarg);
                 break;
             case QEMU_OPTION_h:
-                help(0);
+                help(optarg, 0);
                 break;
             case QEMU_OPTION_version:
                 version();