[cli] Automatically break lines after 79 characters in help output.
authorMatthias Bolte <matthias.bolte@googlemail.com>
Sat, 18 Apr 2009 17:55:57 +0000 (19:55 +0200)
committerMatthias Bolte <matthias.bolte@googlemail.com>
Sat, 18 Apr 2009 17:55:57 +0000 (19:55 +0200)
Signed-off-by: Matthias Bolte <matthias.bolte@googlemail.com>

cli/help.c

index 40bd4af..0efb2ec 100644 (file)
@@ -18,7 +18,9 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  */
 
+#include <stdarg.h>
 #include <stdio.h>
+#include <string.h>
 
 #include <libvscmisc/assert.h>
 #include <libvscmisc/error.h>
@@ -28,6 +30,8 @@
 #include "command.h"
 #include "option.h"
 
+#define _LENGTH_LIMIT 79
+
 extern char *_vsc_cli_name;
 extern char *_vsc_cli_help;
 extern const struct VscCliOptionInfo *_vsc_cli_option_infos;
@@ -35,6 +39,90 @@ extern const struct VscCliCommandInfo **_vsc_cli_command_infos;
 extern int _vsc_cli_output_coloring;
 extern int _vsc_cli_interactive;
 
+static int /* total */
+_limited_print_words (const char* indent, int total, const char *string)
+{
+       const char* ptr;
+       const char* start;
+
+       VSC__ASSERT (string != NULL);
+
+       ptr = string;
+       start = string;
+
+       while (*ptr != '\0') {
+               if (*ptr == ' ') {
+                       ++ptr;
+
+                       if (total + (ptr - start) > _LENGTH_LIMIT) {
+                               printf ("\n");
+                               printf ("%s", indent);
+
+                               total = strlen (indent);
+                       }
+
+                       while (start < ptr) {
+                               putc (*start++, stdout);
+                               ++total;
+                       }
+               } else {
+                       ++ptr;
+               }
+       }
+
+       if (total + (ptr - start) > _LENGTH_LIMIT) {
+               printf ("\n");
+               printf ("%s", indent);
+
+               total = strlen (indent);
+       }
+
+       while (start < ptr) {
+               putc (*start++, stdout);
+               ++total;
+       }
+
+       return total;
+}
+
+static int /* total */
+_limited_printf (const char* indent, int total, const char *format, ...)
+{
+       va_list args;
+       int single;
+
+       VSC__ASSERT (indent != NULL);
+       VSC__ASSERT (format != NULL);
+
+       va_start (args, format);
+
+       single = vsnprintf (NULL, 0, format, args);
+
+       va_end (args);
+
+       if (single < 0) {
+               goto cleanup;
+       }
+
+       if (total + single > _LENGTH_LIMIT) {
+               printf ("\n");
+               printf ("%s", indent);
+
+               total = strlen (indent) + single;
+       } else {
+               total += single;
+       }
+
+       va_start (args, format);
+
+       vprintf (format, args);
+
+cleanup:
+       va_end (args);
+
+       return total;
+}
+
 static void
 _help (struct VscError *error, const struct VscCliCommandInfo *command_info,
        const struct VscCliOption *option_list, void *user_data);
@@ -59,8 +147,10 @@ _help (struct VscError *error,
        const struct VscCliOption *option_list,
        void *user_data VSC__ATTR__UNUSED)
 {
-       int i;
+       int i, total, length;
        const char *command_name;
+       const char *syntax;
+       char indent[256];
        const struct VscCliCommandInfo *command_info_;
        const struct VscCliOptionInfo *option_info;
 
@@ -78,35 +168,80 @@ _help (struct VscError *error,
                        return;
                }
 
+               /*
+                * NAME
+                */
                printf (_vsc_cli_output_coloring ? "\033[1mNAME\033[0m\n"
                                                 : "NAME\n");
-               printf ("       %s - %s\n", command_info_->name, command_info_->help);
+
+               length = strlen (command_info_->name) + 10;
+
+               if (length > 256) {
+                       length = 256;
+               }
+
+               for (int i = 0; i < length; i++) {
+                       indent[i] = ' ';
+               }
+
+               indent[length] = '\0';
+               total = _limited_printf ("", 0, "       %s - ", command_info_->name);
+
+               _limited_print_words (indent, total, command_info_->help);
+               printf ("\n");
                printf ("\n");
 
+               /*
+                * SYNOPSIS
+                */
                printf (_vsc_cli_output_coloring ? "\033[1mSYNOPSIS\033[0m\n"
                                                 : "SYNOPSIS\n");
-               printf ("       %s", command_info_->name);
+
+               total = _limited_printf ("", 0, "       %s", command_info_->name);
+               length = strlen (command_info_->name) + 7;
+
+               if (length > 256) {
+                       length = 256;
+               }
+
+               for (int i = 0; i < length; i++) {
+                       indent[i] = ' ';
+               }
+
+               indent[length] = '\0';
 
                for (i = 0; command_info_->option_infos[i].long_name != NULL; ++i) {
                        option_info = &command_info_->option_infos[i];
+                       syntax = _vsc_cli_option_syntax (option_info, TRUE);
 
                        if (option_info->required) {
-                               printf (" %s", _vsc_cli_option_syntax (option_info, TRUE));
+                               total = _limited_printf (indent, total, " %s", syntax);
                        } else {
-                               printf (" [%s]", _vsc_cli_option_syntax (option_info, TRUE));
+                               total = _limited_printf (indent, total, " [%s]", syntax);
                        }
                }
 
                printf ("\n");
 
+               /*
+                * DESCRIPTION
+                */
                if (command_info_->description != NULL &&
                    *command_info_->description != '\0') {
                        printf ("\n");
                        printf (_vsc_cli_output_coloring ? "\033[1mDESCRIPTION\033[0m\n"
                                                         : "DESCRIPTION\n");
-                       printf ("       %s\n", command_info_->description);
+
+                       total = _limited_print_words ("", 0, "       ");
+                       total = _limited_print_words ("       ", total,
+                                                     command_info_->description);
+
+                       printf ("\n");
                }
 
+               /*
+                * OPTIONS
+                */
                if (command_info_->option_infos[0].long_name != NULL) {
                        printf ("\n");
                        printf (_vsc_cli_output_coloring ? "\033[1mOPTIONS\033[0m\n"
@@ -115,10 +250,14 @@ _help (struct VscError *error,
                        for (i = 0; command_info_->option_infos[i].long_name != NULL; ++i) {
                                option_info = &command_info_->option_infos[i];
 
-                               printf ("       %s\n"
-                                       "              %s\n",
-                                       _vsc_cli_option_syntax (option_info, FALSE),
-                                       option_info->help);
+                               printf ("       %s\n",
+                                       _vsc_cli_option_syntax (option_info, FALSE));
+
+                               total = _limited_print_words ("", 0, "              ");
+                               total = _limited_print_words ("              ", total,
+                                                             option_info->help);
+
+                               printf ("\n");
 
                                if (command_info_->option_infos[i + 1].long_name != NULL) {
                                        printf ("\n");
@@ -127,26 +266,66 @@ _help (struct VscError *error,
                }
        } else {
                if (! _vsc_cli_interactive) {
+                       /*
+                        * NAME
+                        */
                        printf (_vsc_cli_output_coloring ? "\033[1mNAME\033[0m\n" : "NAME\n");
-                       printf ("       %s - %s\n", _vsc_cli_name, _vsc_cli_help);
+
+                       length = strlen (_vsc_cli_name) + 10;
+
+                       if (length > 256) {
+                               length = 256;
+                       }
+
+                       for (int i = 0; i < length; i++) {
+                               indent[i] = ' ';
+                       }
+
+                       indent[length] = '\0';
+                       total = _limited_printf ("", 0, "       %s - ", _vsc_cli_name);
+
+                       _limited_print_words (indent, total, _vsc_cli_help);
+                       printf ("\n");
                        printf ("\n");
 
+                       /*
+                        * SYNOPSIS
+                        */
                        printf (_vsc_cli_output_coloring ? "\033[1mSYNOPSIS\033[0m\n"
                                                         : "SYNOPSIS\n");
-                       printf ("       %s", _vsc_cli_name);
+
+                       total = _limited_printf ("", 0, "       %s", _vsc_cli_name);
 
                        for (i = 0; _vsc_cli_option_infos[i].long_name != NULL; ++i) {
                                option_info = &_vsc_cli_option_infos[i];
+                               syntax = _vsc_cli_option_syntax (option_info, TRUE);
 
                                if (option_info->required) {
-                                       printf (" %s", _vsc_cli_option_syntax (option_info, TRUE));
+                                       total = _limited_printf ("      ", total, " %s", syntax);
                                } else {
-                                       printf (" [%s]", _vsc_cli_option_syntax (option_info, TRUE));
+                                       total = _limited_printf ("      ", total, " [%s]", syntax);
                                }
                        }
 
-                       printf (" [<command>[, <command>]...]\n");
+                       length = strlen (_vsc_cli_name) + 7;
 
+                       if (length > 256) {
+                               length = 256;
+                       }
+
+                       for (int i = 0; i < length; i++) {
+                               indent[i] = ' ';
+                       }
+
+                       indent[length] = '\0';
+
+                       _limited_printf (indent, total, " [<command>[, <command>]...]");
+
+                       printf ("\n");
+
+                       /*
+                        * OPTIONS
+                        */
                        if (_vsc_cli_option_infos[0].long_name != NULL) {
                                printf ("\n");
                                printf (_vsc_cli_output_coloring ? "\033[1mOPTIONS\033[0m\n"
@@ -167,6 +346,9 @@ _help (struct VscError *error,
                        }
                }
 
+               /*
+                * COMMANDS
+                */
                if (_vsc_cli_command_infos[0]->name != NULL) {
                        if (! _vsc_cli_interactive) {
                                printf ("\n");
@@ -176,8 +358,12 @@ _help (struct VscError *error,
                                                         : "COMMANDS\n");
 
                        for (i = 0; _vsc_cli_command_infos[i] != NULL; ++i) {
-                               printf ("       %-20s  %s\n", _vsc_cli_command_infos[i]->name,
-                                       _vsc_cli_command_infos[i]->help);
+                               total = _limited_printf ("", 0, "       %-15s  ",
+                                                        _vsc_cli_command_infos[i]->name);
+
+                               _limited_print_words ("                        ", total,
+                                                     _vsc_cli_command_infos[i]->help);
+                               printf ("\n");
                        }
                }
        }