Browse Source

curl: make --help adapt to the terminal width

Instead of assuming and working with 80 colums, try figuring out what
width is actually used.

Ref: #13141

Closes #13171
Daniel Stenberg 1 month ago
parent
commit
2efc111ea4
3 changed files with 49 additions and 37 deletions
  1. 31 18
      src/tool_cb_prg.c
  2. 4 0
      src/tool_cb_prg.h
  3. 14 19
      src/tool_help.c

+ 31 - 18
src/tool_cb_prg.c

@@ -229,28 +229,25 @@ int tool_progress_cb(void *clientp,
   return 0;
 }
 
-void progressbarinit(struct ProgressData *bar,
-                     struct OperationConfig *config)
-{
-  char *colp;
-  memset(bar, 0, sizeof(struct ProgressData));
-
-  /* pass the resume from value through to the progress function so it can
-   * display progress towards total file not just the part that's left. */
-  if(config->use_resume)
-    bar->initial_size = config->resume_from;
+/*
+ * get_terminal_columns() returns the number of columns in the current
+ * terminal. It will return 79 on failure. Also, the number can be very big.
+ */
 
-  colp = curlx_getenv("COLUMNS");
+unsigned int get_terminal_columns(void)
+{
+  unsigned int width = 0;
+  char *colp = curlx_getenv("COLUMNS");
   if(colp) {
     char *endptr;
     long num = strtol(colp, &endptr, 10);
     if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) &&
        (num < 10000))
-      bar->width = (int)num;
+      width = (unsigned int)num;
     curl_free(colp);
   }
 
-  if(!bar->width) {
+  if(!width) {
     int cols = 0;
 
 #ifdef TIOCGSIZE
@@ -277,14 +274,30 @@ void progressbarinit(struct ProgressData *bar,
       }
     }
 #endif /* TIOCGSIZE */
-    if(cols > 20)
-      bar->width = cols;
+    if(cols < 10000)
+      width = cols;
   }
+  if(!width)
+    width = 79;
+  return width; /* 79 for unknown, might also be very small or very big */
+}
+
+void progressbarinit(struct ProgressData *bar,
+                     struct OperationConfig *config)
+{
+  int cols;
+  memset(bar, 0, sizeof(struct ProgressData));
+
+  /* pass the resume from value through to the progress function so it can
+   * display progress towards total file not just the part that's left. */
+  if(config->use_resume)
+    bar->initial_size = config->resume_from;
 
-  if(!bar->width)
-    bar->width = 79;
-  else if(bar->width > MAX_BARLENGTH)
+  cols = get_terminal_columns();
+  if(cols > MAX_BARLENGTH)
     bar->width = MAX_BARLENGTH;
+  else if(cols > 20)
+    bar->width = cols;
 
   bar->out = tool_stderr;
   bar->tick = 150;

+ 4 - 0
src/tool_cb_prg.h

@@ -40,9 +40,13 @@ struct ProgressData {
   int barmove;
 };
 
+struct OperationConfig;
+
 void progressbarinit(struct ProgressData *bar,
                      struct OperationConfig *config);
 
+unsigned int get_terminal_columns(void);
+
 /*
 ** callback for CURLOPT_PROGRESSFUNCTION
 */

+ 14 - 19
src/tool_help.c

@@ -30,6 +30,7 @@
 #include "tool_libinfo.h"
 #include "tool_util.h"
 #include "tool_version.h"
+#include "tool_cb_prg.h"
 
 #include "memdebug.h" /* keep this as LAST include */
 
@@ -73,13 +74,7 @@ static const struct category_descriptors categories[] = {
   {NULL, NULL, CURLHELP_HIDDEN}
 };
 
-#ifdef _WIN32
-#define BORDER 78
-#else
-#define BORDER 79
-#endif
-
-static void print_category(curlhelp_t category)
+static void print_category(curlhelp_t category, unsigned int cols)
 {
   unsigned int i;
   size_t longopt = 5;
@@ -96,17 +91,16 @@ static void print_category(curlhelp_t category)
     if(len > longdesc)
       longdesc = len;
   }
-  if(longopt + longdesc >= BORDER) {
-    longdesc -= 3;
-    longopt = BORDER -1 - longdesc;
-  }
+  if(longopt + longdesc > cols)
+    longopt = cols - longdesc;
+
   for(i = 0; helptext[i].opt; ++i)
     if(helptext[i].categories & category) {
       int opt = (int)longopt;
       size_t desclen = strlen(helptext[i].desc);
-      if(opt + desclen >= (BORDER -1)) {
-        if(desclen < (BORDER -1))
-          opt = (BORDER -2) - (int)desclen;
+      if(opt + desclen >= (cols - 2)) {
+        if(desclen < (cols - 2))
+          opt = (cols - 3) - (int)desclen;
         else
           opt = 0;
       }
@@ -115,13 +109,13 @@ static void print_category(curlhelp_t category)
 }
 
 /* Prints category if found. If not, it returns 1 */
-static int get_category_content(const char *category)
+static int get_category_content(const char *category, unsigned int cols)
 {
   unsigned int i;
   for(i = 0; categories[i].opt; ++i)
     if(curl_strequal(categories[i].opt, category)) {
       printf("%s: %s\n", categories[i].opt, categories[i].desc);
-      print_category(categories[i].category);
+      print_category(categories[i].category, cols);
       return 0;
     }
   return 1;
@@ -138,6 +132,7 @@ static void get_categories(void)
 
 void tool_help(char *category)
 {
+  unsigned int cols = get_terminal_columns();
   puts("Usage: curl [options...] <url>");
   /* If no category was provided */
   if(!category) {
@@ -145,18 +140,18 @@ void tool_help(char *category)
       "menu is stripped into categories.\nUse \"--help category\" to get "
       "an overview of all categories.\nFor all options use the manual"
       " or \"--help all\".";
-    print_category(CURLHELP_IMPORTANT);
+    print_category(CURLHELP_IMPORTANT, cols);
     puts(category_note);
   }
   /* Lets print everything if "all" was provided */
   else if(curl_strequal(category, "all"))
     /* Print everything except hidden */
-    print_category(~(CURLHELP_HIDDEN));
+    print_category(~(CURLHELP_HIDDEN), cols);
   /* Lets handle the string "category" differently to not print an errormsg */
   else if(curl_strequal(category, "category"))
     get_categories();
   /* Otherwise print category and handle the case if the cat was not found */
-  else if(get_category_content(category)) {
+  else if(get_category_content(category, cols)) {
     puts("Invalid category provided, here is a list of all categories:\n");
     get_categories();
   }