]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
curl: --help [option] displays documentation for given cmdline option
authorDaniel Stenberg <daniel@haxx.se>
Sat, 3 Aug 2024 18:24:12 +0000 (20:24 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 4 Aug 2024 14:06:17 +0000 (16:06 +0200)
Since the documentation text blob might be gzipped, it needs to search
for what to output in a streaming manner. It then first searches for
"\nALL OPTIONS".

Then, it looks for the start to display at "\n    -[option]" and stops
again at "\n    -". Except for the last option in the man page, which
ends at "\nFILES" - the subtitle for the section following all options
in the manpage.

Test 1707 to 1710 verify

Closes #13997

22 files changed:
docs/TODO
docs/cmdline-opts/_OPTIONS.md
docs/cmdline-opts/help.md
src/mkhelp.pl
src/tool_getparam.c
src/tool_getparam.h
src/tool_help.c
src/tool_help.h
src/tool_hugehelp.c.cvs
src/tool_hugehelp.h
src/tool_listhelp.c
tests/Makefile.am
tests/data/Makefile.am
tests/data/test1461
tests/data/test1462
tests/data/test1463
tests/data/test1464
tests/data/test1707 [new file with mode: 0644]
tests/data/test1708 [new file with mode: 0644]
tests/data/test1709 [new file with mode: 0644]
tests/data/test1710 [new file with mode: 0644]
tests/test1707.pl [new file with mode: 0755]

index 914b9a312d8a41d405c9f556faa4b33a994ace6e..f10becd71435080f1b82083ede1abdc5baa1f4d7 100644 (file)
--- a/docs/TODO
+++ b/docs/TODO
  18. Command line tool
  18.1 sync
  18.2 glob posts
- 18.3 -h option
  18.4 --proxycommand
  18.5 UTF-8 filenames in Content-Disposition
  18.6 Option to make -Z merge lined based outputs on stdout
  Globbing support for -d and -F, as in 'curl -d "name=foo[0-9]" URL'.
  This is easily scripted though.
 
-18.3 -h option
-
- Support "curl -h --insecure" etc to output the manpage section for the
- --insecure command line option in the terminal. Should be possible to work
- with either long or short versions of command line options.
-
 18.4 --proxycommand
 
  Allow the user to make curl run a command and use its stdio to make requests
index 106298e7457ab18d172e4ffe48def829ed446e3a..ef208ade0f48c86df9e7546996da2587b2b3a286 100644 (file)
@@ -24,3 +24,5 @@ clean option state, except for the options that are global. Global options
 retain their values and meaning even after --next.
 
 The following options are global: `%GLOBALS`.
+
+# ALL OPTIONS
index 7477a1e40749a8abfb2c3757bac3e76a0dd77173..122c55cd4341a2fecb2135897e24924592e0bf0e 100644 (file)
@@ -2,7 +2,7 @@
 c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
 SPDX-License-Identifier: curl
 Long: help
-Arg: <category>
+Arg: <subject>
 Short: h
 Help: Get help for commands
 Category: important curl
@@ -12,15 +12,28 @@ See-also:
   - verbose
 Example:
   - --help all
+  - --help --insecure
+  - --help -f
 ---
 
 # `--help`
 
-Usage help. List all curl command line options within the given **category**.
+Usage help. Provide help for the subject given as an optional argument.
 
 If no argument is provided, curl displays the most important command line
 arguments.
 
-For category **all**, curl displays help for all options.
+The argument can either be a **category** or a **command line option**. When a
+category is provided, curl shows all command line options within the given
+category. Specify category `all` to list all available options.
 
-If **category** is specified, curl displays all available help categories.
+If `category` is specified, curl displays all available help categories.
+
+If the provided subject is instead an existing command line option, specified
+either in its short form with a single dash and a single letter, or in the
+long form with two dashes and a longer name, curl displays a help text for
+that option in the terminal.
+
+The help output is extensive for some options.
+
+If the provided command line option is not known, curl says so.
index 96c2b4192b32a5bfc5da3c53d8351c6d3e06d948..77130a4ce3c356755142f4ef41321662f499b1a1 100755 (executable)
 #
 ###########################################################################
 
-# Yeah, I know, probably 1000 other persons already wrote a script like
-# this, but I'll tell ya:
-
-# THEY DON'T FIT ME :-)
-
-# Get readme file as parameter:
-
 if($ARGV[0] eq "-c") {
     $c=1;
     shift @ARGV;
@@ -53,6 +46,8 @@ print <<HEAD
  */
 #ifdef USE_MANUAL
 #include "tool_hugehelp.h"
+#include "tool_help.h"
+
 HEAD
     ;
 if($c) {
@@ -111,23 +106,25 @@ static void zfree_func(voidpf opaque, voidpf ptr)
   (void) opaque;
   free(ptr);
 }
+
+#define HEADERLEN 10
+
 /* Decompress and send to stdout a gzip-compressed buffer */
 void hugehelp(void)
 {
   unsigned char *buf;
-  int status, headerlen;
+  int status;
   z_stream z;
 
   /* Make sure no gzip options are set */
   if(hugehelpgz[3] & 0xfe)
     return;
 
-  headerlen = 10;
   memset(&z, 0, sizeof(z_stream));
   z.zalloc = (alloc_func)zalloc_func;
   z.zfree = (free_func)zfree_func;
-  z.avail_in = (unsigned int)(sizeof(hugehelpgz) - headerlen);
-  z.next_in = (unsigned char *)hugehelpgz + headerlen;
+  z.avail_in = (unsigned int)(sizeof(hugehelpgz) - HEADERLEN);
+  z.next_in = (unsigned char *)hugehelpgz + HEADERLEN;
 
   if(inflateInit2(&z, -MAX_WBITS) != Z_OK)
     return;
@@ -144,7 +141,49 @@ void hugehelp(void)
           break;
       }
       else
-        break;    /* Error */
+        break;    /* error */
+    }
+    free(buf);
+  }
+  inflateEnd(&z);
+}
+/* Show the help text for the 'arg' curl argument on stdout */
+void showhelp(const char *trigger, const char *arg, const char *endarg)
+{
+  unsigned char *buf;
+  int status;
+  z_stream z;
+  struct scan_ctx ctx;
+  inithelpscan(&ctx, trigger, arg, endarg);
+
+  /* Make sure no gzip options are set */
+  if(hugehelpgz[3] & 0xfe)
+    return;
+
+  memset(&z, 0, sizeof(z_stream));
+  z.zalloc = (alloc_func)zalloc_func;
+  z.zfree = (free_func)zfree_func;
+  z.avail_in = (unsigned int)(sizeof(hugehelpgz) - HEADERLEN);
+  z.next_in = (unsigned char *)hugehelpgz + HEADERLEN;
+
+  if(inflateInit2(&z, -MAX_WBITS) != Z_OK)
+    return;
+
+  buf = malloc(BUF_SIZE);
+  if(buf) {
+    while(1) {
+      z.avail_out = BUF_SIZE;
+      z.next_out = buf;
+      status = inflate(&z, Z_SYNC_FLUSH);
+      if(status == Z_OK || status == Z_STREAM_END) {
+        size_t len = BUF_SIZE - z.avail_out;
+        if(!helpscan(buf, len, &ctx))
+          break;
+        if(status == Z_STREAM_END)
+          break;
+      }
+      else
+        break;    /* error */
     }
     free(buf);
   }
@@ -188,6 +227,21 @@ void hugehelp(void)
   while(curlman[i])
     puts(curlman[i++]);
 }
+
+/* Show the help text for the 'arg' curl argument on stdout */
+void showhelp(const char *trigger, const char *arg, const char *endarg)
+{
+  int i = 0;
+  struct scan_ctx ctx;
+  inithelpscan(&ctx, trigger, arg, endarg);
+  while(curlman[i]) {
+    size_t len = strlen(curlman[i]);
+    if(!helpscan((unsigned char *)curlman[i], len, &ctx) ||
+       !helpscan((unsigned char *)"\\n", 1, &ctx))
+      break;
+    i++;
+  }
+}
 ENDLINE
     ;
 
index 523450230307a42bae9ed76db164050b450a5210..0c2f08faf45d54586cee1b39bf9a7dfc4ba44218 100644 (file)
@@ -71,306 +71,16 @@ static ParameterError getstr(char **str, const char *val, bool allowblank)
   return PARAM_OK;
 }
 
-/* one enum for every command line option. The name is the verbatim long
-   option name, but in uppercase with periods and minuses replaced with
-   underscores using a "C_" prefix. */
-typedef enum {
-  C_ABSTRACT_UNIX_SOCKET,
-  C_ALPN,
-  C_ALT_SVC,
-  C_ANYAUTH,
-  C_APPEND,
-  C_AWS_SIGV4,
-  C_BASIC,
-  C_BUFFER,
-  C_CA_NATIVE,
-  C_CACERT,
-  C_CAPATH,
-  C_CERT,
-  C_CERT_STATUS,
-  C_CERT_TYPE,
-  C_CIPHERS,
-  C_CLOBBER,
-  C_COMPRESSED,
-  C_COMPRESSED_SSH,
-  C_CONFIG,
-  C_CONNECT_TIMEOUT,
-  C_CONNECT_TO,
-  C_CONTINUE_AT,
-  C_COOKIE,
-  C_COOKIE_JAR,
-  C_CREATE_DIRS,
-  C_CREATE_FILE_MODE,
-  C_CRLF,
-  C_CRLFILE,
-  C_CURVES,
-  C_DATA,
-  C_DATA_ASCII,
-  C_DATA_BINARY,
-  C_DATA_RAW,
-  C_DATA_URLENCODE,
-  C_DELEGATION,
-  C_DIGEST,
-  C_DISABLE,
-  C_DISABLE_EPRT,
-  C_DISABLE_EPSV,
-  C_DISALLOW_USERNAME_IN_URL,
-  C_DNS_INTERFACE,
-  C_DNS_IPV4_ADDR,
-  C_DNS_IPV6_ADDR,
-  C_DNS_SERVERS,
-  C_DOH_CERT_STATUS,
-  C_DOH_INSECURE,
-  C_DOH_URL,
-  C_DUMP_CA_EMBED,
-  C_DUMP_HEADER,
-  C_ECH,
-  C_EGD_FILE,
-  C_ENGINE,
-  C_EPRT,
-  C_EPSV,
-  C_ETAG_COMPARE,
-  C_ETAG_SAVE,
-  C_EXPECT100_TIMEOUT,
-  C_FAIL,
-  C_FAIL_EARLY,
-  C_FAIL_WITH_BODY,
-  C_FALSE_START,
-  C_FORM,
-  C_FORM_ESCAPE,
-  C_FORM_STRING,
-  C_FTP_ACCOUNT,
-  C_FTP_ALTERNATIVE_TO_USER,
-  C_FTP_CREATE_DIRS,
-  C_FTP_METHOD,
-  C_FTP_PASV,
-  C_FTP_PORT,
-  C_FTP_PRET,
-  C_FTP_SKIP_PASV_IP,
-  C_FTP_SSL,
-  C_FTP_SSL_CCC,
-  C_FTP_SSL_CCC_MODE,
-  C_FTP_SSL_CONTROL,
-  C_FTP_SSL_REQD,
-  C_GET,
-  C_GLOBOFF,
-  C_HAPPY_EYEBALLS_TIMEOUT_MS,
-  C_HAPROXY_CLIENTIP,
-  C_HAPROXY_PROTOCOL,
-  C_HEAD,
-  C_HEADER,
-  C_HELP,
-  C_HOSTPUBMD5,
-  C_HOSTPUBSHA256,
-  C_HSTS,
-  C_HTTP0_9,
-  C_HTTP1_0,
-  C_HTTP1_1,
-  C_HTTP2,
-  C_HTTP2_PRIOR_KNOWLEDGE,
-  C_HTTP3,
-  C_HTTP3_ONLY,
-  C_IGNORE_CONTENT_LENGTH,
-  C_INCLUDE,
-  C_INSECURE,
-  C_INTERFACE,
-  C_IPFS_GATEWAY,
-  C_IPV4,
-  C_IPV6,
-  C_JSON,
-  C_JUNK_SESSION_COOKIES,
-  C_KEEPALIVE,
-  C_KEEPALIVE_CNT,
-  C_KEEPALIVE_TIME,
-  C_KEY,
-  C_KEY_TYPE,
-  C_KRB,
-  C_KRB4,
-  C_LIBCURL,
-  C_LIMIT_RATE,
-  C_LIST_ONLY,
-  C_LOCAL_PORT,
-  C_LOCATION,
-  C_LOCATION_TRUSTED,
-  C_LOGIN_OPTIONS,
-  C_MAIL_AUTH,
-  C_MAIL_FROM,
-  C_MAIL_RCPT,
-  C_MAIL_RCPT_ALLOWFAILS,
-  C_MANUAL,
-  C_MAX_FILESIZE,
-  C_MAX_REDIRS,
-  C_MAX_TIME,
-  C_METALINK,
-  C_MPTCP,
-  C_NEGOTIATE,
-  C_NETRC,
-  C_NETRC_FILE,
-  C_NETRC_OPTIONAL,
-  C_NEXT,
-  C_NOPROXY,
-  C_NPN,
-  C_NTLM,
-  C_NTLM_WB,
-  C_OAUTH2_BEARER,
-  C_OUTPUT,
-  C_OUTPUT_DIR,
-  C_PARALLEL,
-  C_PARALLEL_IMMEDIATE,
-  C_PARALLEL_MAX,
-  C_PASS,
-  C_PATH_AS_IS,
-  C_PINNEDPUBKEY,
-  C_POST301,
-  C_POST302,
-  C_POST303,
-  C_PREPROXY,
-  C_PROGRESS_BAR,
-  C_PROGRESS_METER,
-  C_PROTO,
-  C_PROTO_DEFAULT,
-  C_PROTO_REDIR,
-  C_PROXY,
-  C_PROXY_ANYAUTH,
-  C_PROXY_BASIC,
-  C_PROXY_CA_NATIVE,
-  C_PROXY_CACERT,
-  C_PROXY_CAPATH,
-  C_PROXY_CERT,
-  C_PROXY_CERT_TYPE,
-  C_PROXY_CIPHERS,
-  C_PROXY_CRLFILE,
-  C_PROXY_DIGEST,
-  C_PROXY_HEADER,
-  C_PROXY_HTTP2,
-  C_PROXY_INSECURE,
-  C_PROXY_KEY,
-  C_PROXY_KEY_TYPE,
-  C_PROXY_NEGOTIATE,
-  C_PROXY_NTLM,
-  C_PROXY_PASS,
-  C_PROXY_PINNEDPUBKEY,
-  C_PROXY_SERVICE_NAME,
-  C_PROXY_SSL_ALLOW_BEAST,
-  C_PROXY_SSL_AUTO_CLIENT_CERT,
-  C_PROXY_TLS13_CIPHERS,
-  C_PROXY_TLSAUTHTYPE,
-  C_PROXY_TLSPASSWORD,
-  C_PROXY_TLSUSER,
-  C_PROXY_TLSV1,
-  C_PROXY_USER,
-  C_PROXY1_0,
-  C_PROXYTUNNEL,
-  C_PUBKEY,
-  C_QUOTE,
-  C_RANDOM_FILE,
-  C_RANGE,
-  C_RATE,
-  C_RAW,
-  C_REFERER,
-  C_REMOTE_HEADER_NAME,
-  C_REMOTE_NAME,
-  C_REMOTE_NAME_ALL,
-  C_REMOTE_TIME,
-  C_REMOVE_ON_ERROR,
-  C_REQUEST,
-  C_REQUEST_TARGET,
-  C_RESOLVE,
-  C_RETRY,
-  C_RETRY_ALL_ERRORS,
-  C_RETRY_CONNREFUSED,
-  C_RETRY_DELAY,
-  C_RETRY_MAX_TIME,
-  C_SASL_AUTHZID,
-  C_SASL_IR,
-  C_SERVICE_NAME,
-  C_SESSIONID,
-  C_SHOW_ERROR,
-  C_SHOW_HEADERS,
-  C_SILENT,
-  C_SOCKS4,
-  C_SOCKS4A,
-  C_SOCKS5,
-  C_SOCKS5_BASIC,
-  C_SOCKS5_GSSAPI,
-  C_SOCKS5_GSSAPI_NEC,
-  C_SOCKS5_GSSAPI_SERVICE,
-  C_SOCKS5_HOSTNAME,
-  C_SPEED_LIMIT,
-  C_SPEED_TIME,
-  C_SSL,
-  C_SSL_ALLOW_BEAST,
-  C_SSL_AUTO_CLIENT_CERT,
-  C_SSL_NO_REVOKE,
-  C_SSL_REQD,
-  C_SSL_REVOKE_BEST_EFFORT,
-  C_SSLV2,
-  C_SSLV3,
-  C_STDERR,
-  C_STYLED_OUTPUT,
-  C_SUPPRESS_CONNECT_HEADERS,
-  C_TCP_FASTOPEN,
-  C_TCP_NODELAY,
-  C_TELNET_OPTION,
-  C_TEST_EVENT,
-  C_TFTP_BLKSIZE,
-  C_TFTP_NO_OPTIONS,
-  C_TIME_COND,
-  C_TLS_MAX,
-  C_TLS13_CIPHERS,
-  C_TLSAUTHTYPE,
-  C_TLSPASSWORD,
-  C_TLSUSER,
-  C_TLSV1,
-  C_TLSV1_0,
-  C_TLSV1_1,
-  C_TLSV1_2,
-  C_TLSV1_3,
-  C_TR_ENCODING,
-  C_TRACE,
-  C_TRACE_ASCII,
-  C_TRACE_CONFIG,
-  C_TRACE_IDS,
-  C_TRACE_TIME,
-  C_IP_TOS,
-  C_UNIX_SOCKET,
-  C_UPLOAD_FILE,
-  C_URL,
-  C_URL_QUERY,
-  C_USE_ASCII,
-  C_USER,
-  C_USER_AGENT,
-  C_VARIABLE,
-  C_VERBOSE,
-  C_VERSION,
-  C_VLAN_PRIORITY,
-  C_WDEBUG,
-  C_WRITE_OUT,
-  C_XATTR
-} cmdline_t;
-
-struct LongShort {
-  const char *lname;  /* long name option */
-  enum {
-    ARG_NONE, /* stand-alone but not a boolean */
-    ARG_BOOL, /* accepts a --no-[name] prefix */
-    ARG_STRG, /* requires an argument */
-    ARG_FILE  /* requires an argument, usually a filename */
-  } desc;
-  char letter;  /* short name option or ' ' */
-  cmdline_t cmd;
-};
-
 /* this array MUST be alphasorted based on the 'lname' */
 static const struct LongShort aliases[]= {
   {"abstract-unix-socket",       ARG_FILE, ' ', C_ABSTRACT_UNIX_SOCKET},
-  {"alpn",                       ARG_BOOL, ' ', C_ALPN},
+  {"alpn",                       ARG_BOOL|ARG_NO, ' ', C_ALPN},
   {"alt-svc",                    ARG_STRG, ' ', C_ALT_SVC},
   {"anyauth",                    ARG_BOOL, ' ', C_ANYAUTH},
   {"append",                     ARG_BOOL, 'a', C_APPEND},
   {"aws-sigv4",                  ARG_STRG, ' ', C_AWS_SIGV4},
   {"basic",                      ARG_BOOL, ' ', C_BASIC},
-  {"buffer",                     ARG_BOOL, 'N', C_BUFFER},
+  {"buffer",                     ARG_BOOL|ARG_NO, 'N', C_BUFFER},
   {"ca-native",                  ARG_BOOL, ' ', C_CA_NATIVE},
   {"cacert",                     ARG_FILE, ' ', C_CACERT},
   {"capath",                     ARG_FILE, ' ', C_CAPATH},
@@ -378,7 +88,7 @@ static const struct LongShort aliases[]= {
   {"cert-status",                ARG_BOOL, ' ', C_CERT_STATUS},
   {"cert-type",                  ARG_STRG, ' ', C_CERT_TYPE},
   {"ciphers",                    ARG_STRG, ' ', C_CIPHERS},
-  {"clobber",                    ARG_BOOL, ' ', C_CLOBBER},
+  {"clobber",                    ARG_BOOL|ARG_NO, ' ', C_CLOBBER},
   {"compressed",                 ARG_BOOL, ' ', C_COMPRESSED},
   {"compressed-ssh",             ARG_BOOL, ' ', C_COMPRESSED_SSH},
   {"config",                     ARG_FILE, 'K', C_CONFIG},
@@ -468,7 +178,7 @@ static const struct LongShort aliases[]= {
   {"ipv6",                       ARG_NONE, '6', C_IPV6},
   {"json",                       ARG_STRG, ' ', C_JSON},
   {"junk-session-cookies",       ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES},
-  {"keepalive",                  ARG_BOOL, ' ', C_KEEPALIVE},
+  {"keepalive",                  ARG_BOOL|ARG_NO, ' ', C_KEEPALIVE},
   {"keepalive-cnt",              ARG_STRG, ' ', C_KEEPALIVE_CNT},
   {"keepalive-time",             ARG_STRG, ' ', C_KEEPALIVE_TIME},
   {"key",                        ARG_FILE, ' ', C_KEY},
@@ -498,7 +208,7 @@ static const struct LongShort aliases[]= {
   {"netrc-optional",             ARG_BOOL, ' ', C_NETRC_OPTIONAL},
   {"next",                       ARG_NONE, ':', C_NEXT},
   {"noproxy",                    ARG_STRG, ' ', C_NOPROXY},
-  {"npn",                        ARG_BOOL, ' ', C_NPN},
+  {"npn",                        ARG_BOOL|ARG_NO, ' ', C_NPN},
   {"ntlm",                       ARG_BOOL, ' ', C_NTLM},
   {"ntlm-wb",                    ARG_BOOL, ' ', C_NTLM_WB},
   {"oauth2-bearer",              ARG_STRG, ' ', C_OAUTH2_BEARER},
@@ -515,7 +225,7 @@ static const struct LongShort aliases[]= {
   {"post303",                    ARG_BOOL, ' ', C_POST303},
   {"preproxy",                   ARG_STRG, ' ', C_PREPROXY},
   {"progress-bar",               ARG_BOOL, '#', C_PROGRESS_BAR},
-  {"progress-meter",             ARG_BOOL, ' ', C_PROGRESS_METER},
+  {"progress-meter",             ARG_BOOL|ARG_NO, ' ', C_PROGRESS_METER},
   {"proto",                      ARG_STRG, ' ', C_PROTO},
   {"proto-default",              ARG_STRG, ' ', C_PROTO_DEFAULT},
   {"proto-redir",                ARG_STRG, ' ', C_PROTO_REDIR},
@@ -573,7 +283,7 @@ static const struct LongShort aliases[]= {
   {"sasl-authzid",               ARG_STRG, ' ', C_SASL_AUTHZID},
   {"sasl-ir",                    ARG_BOOL, ' ', C_SASL_IR},
   {"service-name",               ARG_STRG, ' ', C_SERVICE_NAME},
-  {"sessionid",                  ARG_BOOL, ' ', C_SESSIONID},
+  {"sessionid",                  ARG_BOOL|ARG_NO, ' ', C_SESSIONID},
   {"show-error",                 ARG_BOOL, 'S', C_SHOW_ERROR},
   {"show-headers",               ARG_BOOL, 'i', C_SHOW_HEADERS},
   {"silent",                     ARG_BOOL, 's', C_SILENT},
@@ -1029,7 +739,7 @@ static int findarg(const void *a, const void *b)
   return strcmp(aa->lname, bb->lname);
 }
 
-static const struct LongShort *single(char letter)
+const struct LongShort *findshortopt(char letter)
 {
   static const struct LongShort *singles[128 - ' ']; /* ASCII => pointer */
   static bool singles_done = FALSE;
@@ -1295,6 +1005,15 @@ static ParameterError set_rate(struct GlobalConfig *global,
   return err;
 }
 
+const struct LongShort *findlongopt(const char *opt)
+{
+  struct LongShort key;
+  key.lname = opt;
+
+  return bsearch(&key, aliases, sizeof(aliases)/sizeof(aliases[0]),
+                 sizeof(aliases[0]), findarg);
+}
+
 
 ParameterError getparameter(const char *flag, /* f or -long-flag */
                             char *nextarg,    /* NULL if unset */
@@ -1336,7 +1055,6 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
     const char *word = ('-' == flag[0]) ? flag + 2 : flag;
     bool noflagged = FALSE;
     bool expand = FALSE;
-    struct LongShort key;
 
     if(!strncmp(word, "no-", 3)) {
       /* disable this option but ignore the "no-" part when looking for it */
@@ -1349,10 +1067,8 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
       word += 7;
       expand = TRUE;
     }
-    key.lname = word;
 
-    a = bsearch(&key, aliases, sizeof(aliases)/sizeof(aliases[0]),
-                sizeof(aliases[0]), findarg);
+    a = findlongopt(word);
     if(a) {
       longopt = TRUE;
     }
@@ -1360,7 +1076,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
       err = PARAM_OPTION_UNKNOWN;
       goto error;
     }
-    if(noflagged && (a->desc != ARG_BOOL)) {
+    if(noflagged && (ARGTYPE(a->desc) != ARG_BOOL)) {
       /* --no- prefixed an option that is not boolean! */
       err = PARAM_NO_NOT_BOOLEAN;
       goto error;
@@ -1369,8 +1085,8 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
       struct curlx_dynbuf nbuf;
       bool replaced;
 
-      if((a->desc != ARG_STRG) &&
-         (a->desc != ARG_FILE)) {
+      if((ARGTYPE(a->desc) != ARG_STRG) &&
+         (ARGTYPE(a->desc) != ARG_FILE)) {
         /* --expand on an option that is not a string or a filename */
         err = PARAM_EXPAND_ERROR;
         goto error;
@@ -1397,15 +1113,15 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
     cmdline_t cmd;
 
     if(!longopt && !a) {
-      a = single(*parse);
+      a = findshortopt(*parse);
       if(!a) {
         err = PARAM_OPTION_UNKNOWN;
         break;
       }
     }
     letter = a->letter;
-    cmd = a->cmd;
-    if(a->desc >= ARG_STRG) {
+    cmd = (cmdline_t)a->cmd;
+    if(ARGTYPE(a->desc) >= ARG_STRG) {
       /* this option requires an extra parameter */
       if(!longopt && parse[1]) {
         nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
@@ -1422,7 +1138,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
         *usedarg = TRUE; /* mark it as used */
       }
 
-      if((a->desc == ARG_FILE) &&
+      if((ARGTYPE(a->desc) == ARG_FILE) &&
          (nextarg[0] == '-') && nextarg[1]) {
         /* if the filename looks like a command line option */
         warnf(global, "The filename argument '%s' looks like a flag.",
@@ -1434,7 +1150,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
               nextarg);
       }
     }
-    else if((a->desc == ARG_NONE) && !toggle) {
+    else if((ARGTYPE(a->desc) == ARG_NONE) && !toggle) {
       err = PARAM_NO_PREFIX;
       break;
     }
index 8abf5787e9db0b49f47f04505ac5c5e16ffa621b..c36d1d66f2ec3d4dfa5f74a7daebb69e04641e9e 100644 (file)
  ***************************************************************************/
 #include "tool_setup.h"
 
+/* one enum for every command line option. The name is the verbatim long
+   option name, but in uppercase with periods and minuses replaced with
+   underscores using a "C_" prefix. */
+typedef enum {
+  C_ABSTRACT_UNIX_SOCKET,
+  C_ALPN,
+  C_ALT_SVC,
+  C_ANYAUTH,
+  C_APPEND,
+  C_AWS_SIGV4,
+  C_BASIC,
+  C_BUFFER,
+  C_CA_NATIVE,
+  C_CACERT,
+  C_CAPATH,
+  C_CERT,
+  C_CERT_STATUS,
+  C_CERT_TYPE,
+  C_CIPHERS,
+  C_CLOBBER,
+  C_COMPRESSED,
+  C_COMPRESSED_SSH,
+  C_CONFIG,
+  C_CONNECT_TIMEOUT,
+  C_CONNECT_TO,
+  C_CONTINUE_AT,
+  C_COOKIE,
+  C_COOKIE_JAR,
+  C_CREATE_DIRS,
+  C_CREATE_FILE_MODE,
+  C_CRLF,
+  C_CRLFILE,
+  C_CURVES,
+  C_DATA,
+  C_DATA_ASCII,
+  C_DATA_BINARY,
+  C_DATA_RAW,
+  C_DATA_URLENCODE,
+  C_DELEGATION,
+  C_DIGEST,
+  C_DISABLE,
+  C_DISABLE_EPRT,
+  C_DISABLE_EPSV,
+  C_DISALLOW_USERNAME_IN_URL,
+  C_DNS_INTERFACE,
+  C_DNS_IPV4_ADDR,
+  C_DNS_IPV6_ADDR,
+  C_DNS_SERVERS,
+  C_DOH_CERT_STATUS,
+  C_DOH_INSECURE,
+  C_DOH_URL,
+  C_DUMP_CA_EMBED,
+  C_DUMP_HEADER,
+  C_ECH,
+  C_EGD_FILE,
+  C_ENGINE,
+  C_EPRT,
+  C_EPSV,
+  C_ETAG_COMPARE,
+  C_ETAG_SAVE,
+  C_EXPECT100_TIMEOUT,
+  C_FAIL,
+  C_FAIL_EARLY,
+  C_FAIL_WITH_BODY,
+  C_FALSE_START,
+  C_FORM,
+  C_FORM_ESCAPE,
+  C_FORM_STRING,
+  C_FTP_ACCOUNT,
+  C_FTP_ALTERNATIVE_TO_USER,
+  C_FTP_CREATE_DIRS,
+  C_FTP_METHOD,
+  C_FTP_PASV,
+  C_FTP_PORT,
+  C_FTP_PRET,
+  C_FTP_SKIP_PASV_IP,
+  C_FTP_SSL,
+  C_FTP_SSL_CCC,
+  C_FTP_SSL_CCC_MODE,
+  C_FTP_SSL_CONTROL,
+  C_FTP_SSL_REQD,
+  C_GET,
+  C_GLOBOFF,
+  C_HAPPY_EYEBALLS_TIMEOUT_MS,
+  C_HAPROXY_CLIENTIP,
+  C_HAPROXY_PROTOCOL,
+  C_HEAD,
+  C_HEADER,
+  C_HELP,
+  C_HOSTPUBMD5,
+  C_HOSTPUBSHA256,
+  C_HSTS,
+  C_HTTP0_9,
+  C_HTTP1_0,
+  C_HTTP1_1,
+  C_HTTP2,
+  C_HTTP2_PRIOR_KNOWLEDGE,
+  C_HTTP3,
+  C_HTTP3_ONLY,
+  C_IGNORE_CONTENT_LENGTH,
+  C_INCLUDE,
+  C_INSECURE,
+  C_INTERFACE,
+  C_IPFS_GATEWAY,
+  C_IPV4,
+  C_IPV6,
+  C_JSON,
+  C_JUNK_SESSION_COOKIES,
+  C_KEEPALIVE,
+  C_KEEPALIVE_CNT,
+  C_KEEPALIVE_TIME,
+  C_KEY,
+  C_KEY_TYPE,
+  C_KRB,
+  C_KRB4,
+  C_LIBCURL,
+  C_LIMIT_RATE,
+  C_LIST_ONLY,
+  C_LOCAL_PORT,
+  C_LOCATION,
+  C_LOCATION_TRUSTED,
+  C_LOGIN_OPTIONS,
+  C_MAIL_AUTH,
+  C_MAIL_FROM,
+  C_MAIL_RCPT,
+  C_MAIL_RCPT_ALLOWFAILS,
+  C_MANUAL,
+  C_MAX_FILESIZE,
+  C_MAX_REDIRS,
+  C_MAX_TIME,
+  C_METALINK,
+  C_MPTCP,
+  C_NEGOTIATE,
+  C_NETRC,
+  C_NETRC_FILE,
+  C_NETRC_OPTIONAL,
+  C_NEXT,
+  C_NOPROXY,
+  C_NPN,
+  C_NTLM,
+  C_NTLM_WB,
+  C_OAUTH2_BEARER,
+  C_OUTPUT,
+  C_OUTPUT_DIR,
+  C_PARALLEL,
+  C_PARALLEL_IMMEDIATE,
+  C_PARALLEL_MAX,
+  C_PASS,
+  C_PATH_AS_IS,
+  C_PINNEDPUBKEY,
+  C_POST301,
+  C_POST302,
+  C_POST303,
+  C_PREPROXY,
+  C_PROGRESS_BAR,
+  C_PROGRESS_METER,
+  C_PROTO,
+  C_PROTO_DEFAULT,
+  C_PROTO_REDIR,
+  C_PROXY,
+  C_PROXY_ANYAUTH,
+  C_PROXY_BASIC,
+  C_PROXY_CA_NATIVE,
+  C_PROXY_CACERT,
+  C_PROXY_CAPATH,
+  C_PROXY_CERT,
+  C_PROXY_CERT_TYPE,
+  C_PROXY_CIPHERS,
+  C_PROXY_CRLFILE,
+  C_PROXY_DIGEST,
+  C_PROXY_HEADER,
+  C_PROXY_HTTP2,
+  C_PROXY_INSECURE,
+  C_PROXY_KEY,
+  C_PROXY_KEY_TYPE,
+  C_PROXY_NEGOTIATE,
+  C_PROXY_NTLM,
+  C_PROXY_PASS,
+  C_PROXY_PINNEDPUBKEY,
+  C_PROXY_SERVICE_NAME,
+  C_PROXY_SSL_ALLOW_BEAST,
+  C_PROXY_SSL_AUTO_CLIENT_CERT,
+  C_PROXY_TLS13_CIPHERS,
+  C_PROXY_TLSAUTHTYPE,
+  C_PROXY_TLSPASSWORD,
+  C_PROXY_TLSUSER,
+  C_PROXY_TLSV1,
+  C_PROXY_USER,
+  C_PROXY1_0,
+  C_PROXYTUNNEL,
+  C_PUBKEY,
+  C_QUOTE,
+  C_RANDOM_FILE,
+  C_RANGE,
+  C_RATE,
+  C_RAW,
+  C_REFERER,
+  C_REMOTE_HEADER_NAME,
+  C_REMOTE_NAME,
+  C_REMOTE_NAME_ALL,
+  C_REMOTE_TIME,
+  C_REMOVE_ON_ERROR,
+  C_REQUEST,
+  C_REQUEST_TARGET,
+  C_RESOLVE,
+  C_RETRY,
+  C_RETRY_ALL_ERRORS,
+  C_RETRY_CONNREFUSED,
+  C_RETRY_DELAY,
+  C_RETRY_MAX_TIME,
+  C_SASL_AUTHZID,
+  C_SASL_IR,
+  C_SERVICE_NAME,
+  C_SESSIONID,
+  C_SHOW_ERROR,
+  C_SHOW_HEADERS,
+  C_SILENT,
+  C_SOCKS4,
+  C_SOCKS4A,
+  C_SOCKS5,
+  C_SOCKS5_BASIC,
+  C_SOCKS5_GSSAPI,
+  C_SOCKS5_GSSAPI_NEC,
+  C_SOCKS5_GSSAPI_SERVICE,
+  C_SOCKS5_HOSTNAME,
+  C_SPEED_LIMIT,
+  C_SPEED_TIME,
+  C_SSL,
+  C_SSL_ALLOW_BEAST,
+  C_SSL_AUTO_CLIENT_CERT,
+  C_SSL_NO_REVOKE,
+  C_SSL_REQD,
+  C_SSL_REVOKE_BEST_EFFORT,
+  C_SSLV2,
+  C_SSLV3,
+  C_STDERR,
+  C_STYLED_OUTPUT,
+  C_SUPPRESS_CONNECT_HEADERS,
+  C_TCP_FASTOPEN,
+  C_TCP_NODELAY,
+  C_TELNET_OPTION,
+  C_TEST_EVENT,
+  C_TFTP_BLKSIZE,
+  C_TFTP_NO_OPTIONS,
+  C_TIME_COND,
+  C_TLS_MAX,
+  C_TLS13_CIPHERS,
+  C_TLSAUTHTYPE,
+  C_TLSPASSWORD,
+  C_TLSUSER,
+  C_TLSV1,
+  C_TLSV1_0,
+  C_TLSV1_1,
+  C_TLSV1_2,
+  C_TLSV1_3,
+  C_TR_ENCODING,
+  C_TRACE,
+  C_TRACE_ASCII,
+  C_TRACE_CONFIG,
+  C_TRACE_IDS,
+  C_TRACE_TIME,
+  C_IP_TOS,
+  C_UNIX_SOCKET,
+  C_UPLOAD_FILE,
+  C_URL,
+  C_URL_QUERY,
+  C_USE_ASCII,
+  C_USER,
+  C_USER_AGENT,
+  C_VARIABLE,
+  C_VERBOSE,
+  C_VERSION,
+  C_VLAN_PRIORITY,
+  C_WDEBUG,
+  C_WRITE_OUT,
+  C_XATTR
+} cmdline_t;
+
+#define ARG_NONE 0 /* stand-alone but not a boolean */
+#define ARG_BOOL 1 /* accepts a --no-[name] prefix */
+#define ARG_STRG 2 /* requires an argument */
+#define ARG_FILE 3 /* requires an argument, usually a filename */
+
+#define ARG_TYPEMASK 0x03
+#define ARGTYPE(x) ((x) & ARG_TYPEMASK)
+
+#define ARG_NO 0x80 /* set if the option is documented as --no-* */
+
+struct LongShort {
+  const char *lname;  /* long name option */
+  unsigned char desc; /* type, see ARG_* */
+  char letter;  /* short name option or ' ' */
+  unsigned short cmd;
+};
+
 typedef enum {
   PARAM_OK = 0,
   PARAM_OPTION_AMBIGUOUS,
@@ -57,6 +352,9 @@ typedef enum {
 struct GlobalConfig;
 struct OperationConfig;
 
+const struct LongShort *findlongopt(const char *opt);
+const struct LongShort *findshortopt(char letter);
+
 ParameterError getparameter(const char *flag, char *nextarg,
                             argv_item_t cleararg,
                             bool *usedarg,
index c570cb96c8e96b030b19a264110cc44aa71342ee..f7ecb7219938a4b1d12e78ca3c0ddadf24cb3a71 100644 (file)
@@ -31,6 +31,8 @@
 #include "tool_util.h"
 #include "tool_version.h"
 #include "tool_cb_prg.h"
+#include "tool_hugehelp.h"
+#include "tool_getparam.h"
 #include "terminal.h"
 
 #include "memdebug.h" /* keep this as LAST include */
@@ -160,18 +162,84 @@ static void get_categories_list(unsigned int width)
   }
 }
 
+#ifdef USE_MANUAL
+
+void inithelpscan(struct scan_ctx *ctx,
+                  const char *trigger,
+                  const char *arg,
+                  const char *endarg)
+{
+  ctx->trigger = trigger;
+  ctx->tlen = strlen(trigger);
+  ctx->arg = arg;
+  ctx->flen = strlen(arg);
+  ctx->endarg = endarg;
+  ctx->elen = strlen(endarg);
+  DEBUGASSERT((ctx->elen < sizeof(ctx->rbuf)) ||
+              (ctx->flen < sizeof(ctx->rbuf)));
+  ctx->show = 0;
+  ctx->olen = 0;
+  memset(ctx->rbuf, 0, sizeof(ctx->rbuf));
+}
+
+bool helpscan(unsigned char *buf, size_t len, struct scan_ctx *ctx)
+{
+  size_t i;
+  for(i = 0; i < len; i++) {
+    if(!ctx->show) {
+      /* wait for the trigger */
+      memmove(&ctx->rbuf[0], &ctx->rbuf[1], ctx->tlen - 1);
+      ctx->rbuf[ctx->tlen - 1] = buf[i];
+      if(!memcmp(ctx->rbuf, ctx->trigger, ctx->tlen))
+        ctx->show++;
+      continue;
+    }
+    /* past the trigger */
+    if(ctx->show == 1) {
+      memmove(&ctx->rbuf[0], &ctx->rbuf[1], ctx->flen - 1);
+      ctx->rbuf[ctx->flen - 1] = buf[i];
+      if(!memcmp(ctx->rbuf, ctx->arg, ctx->flen)) {
+        /* match, now output until endarg */
+        fputs(&ctx->arg[1], stdout);
+        ctx->show++;
+      }
+      continue;
+    }
+    /* show until the end */
+    memmove(&ctx->rbuf[0], &ctx->rbuf[1], ctx->elen - 1);
+    ctx->rbuf[ctx->elen - 1] = buf[i];
+    if(!memcmp(ctx->rbuf, ctx->endarg, ctx->elen))
+      return FALSE;
+
+    if(buf[i] == '\n') {
+      DEBUGASSERT(ctx->olen < sizeof(ctx->obuf));
+      ctx->obuf[ctx->olen++] = 0;
+      ctx->olen = 0;
+      puts(ctx->obuf);
+    }
+    else
+      ctx->obuf[ctx->olen++] = buf[i];
+  }
+  return TRUE;
+}
+
+#endif
 
 void tool_help(char *category)
 {
   unsigned int cols = get_terminal_columns();
-  puts("Usage: curl [options...] <url>");
   /* If no category was provided */
   if(!category) {
     const char *category_note = "\nThis is not the full help; this "
       "menu is split into categories.\nUse \"--help category\" to get "
       "an overview of all categories, which are:";
-    const char *category_note2 = "For all options use the manual"
-      " or \"--help all\".";
+    const char *category_note2 =
+      "Use \"--help all\" to list all options"
+#ifdef USE_MANUAL
+      "\nUse \"--help [option]\" to view documentation for a given option"
+#endif
+      ;
+    puts("Usage: curl [options...] <url>");
     print_category(CURLHELP_IMPORTANT, cols);
     puts(category_note);
     get_categories_list(cols);
@@ -184,6 +252,48 @@ void tool_help(char *category)
   /* Lets handle the string "category" differently to not print an errormsg */
   else if(curl_strequal(category, "category"))
     get_categories();
+  else if(category[0] == '-') {
+#ifdef USE_MANUAL
+    /* command line option help */
+    const struct LongShort *a = NULL;
+    if(category[1] == '-') {
+      char *lookup = &category[2];
+      bool noflagged = FALSE;
+      if(!strncmp(lookup, "no-", 3)) {
+        lookup += 3;
+        noflagged = TRUE;
+      }
+      a = findlongopt(lookup);
+      if(noflagged && (ARGTYPE(a->desc) != ARG_BOOL))
+        /* a --no- prefix for a non-boolean is not specifying a proper
+           option */
+        a = NULL;
+    }
+    else if(!category[2])
+      a = findshortopt(category[1]);
+    if(!a) {
+      fprintf(tool_stderr, "Incorrect option name to show help for,"
+              " see curl -h\n");
+    }
+    else {
+      char cmdbuf[80];
+      if(a->letter != ' ')
+        msnprintf(cmdbuf, sizeof(cmdbuf), "\n    -%c, --", a->letter);
+      else if(a->desc & ARG_NO)
+        msnprintf(cmdbuf, sizeof(cmdbuf), "\n    --no-%s", a->lname);
+      else
+        msnprintf(cmdbuf, sizeof(cmdbuf), "\n    %s", category);
+      if(a->cmd == C_XATTR)
+        /* this is the last option, which then ends when FILES starts */
+        showhelp("\nALL OPTIONS\n", cmdbuf, "\nFILES");
+      else
+        showhelp("\nALL OPTIONS\n", cmdbuf, "\n    -");
+    }
+#else
+    fprintf(tool_stderr, "Cannot comply. "
+            "This curl was built without built-in manual\n");
+#endif
+  }
   /* Otherwise print category and handle the case if the cat was not found */
   else if(get_category_content(category, cols)) {
     puts("Unknown category provided, here is a list of all categories:\n");
index 299da1db8cea296d7932c9d0b228aeae4473cdd6..0a334464d2479074c56e58b03d21be78e605adca 100644 (file)
 void tool_help(char *category);
 void tool_list_engines(void);
 void tool_version_info(void);
+struct scan_ctx {
+  const char *trigger;
+  size_t tlen;
+  const char *arg;
+  size_t flen;
+  const char *endarg;
+  size_t elen;
+  size_t olen;
+  char rbuf[40];
+  char obuf[80];
+  unsigned char show; /* start as at 0.
+                         trigger match moves it to 1
+                         arg match moves it to 2
+                         endarg stops the search */
+};
+void inithelpscan(struct scan_ctx *ctx, const char *trigger,
+                  const char *arg, const char *endarg);
+bool helpscan(unsigned char *buf, size_t len, struct scan_ctx *ctx);
 
 struct helptxt {
   const char *opt;
index 06b132fbcb6be0f867930a655e50d8976547e942..8757cfc6845739ac53a43e30d88d1d91becb432f 100644 (file)
 
 void hugehelp(void)
 {
-  puts("This is a silly replacement for the actual file.");
+  puts("built-in manual was disabled at build-time");
+}
+
+void showhelp(const char *arg, const char *endarg)
+{
+  (void)arg;
+  (void)endarg;
+  hugehelp();
 }
index ce9af0c5456c3195f65099e73d1753e5103546bb..f00f88702b9725ad41f5b2ce20d06b20285d1792 100644 (file)
@@ -25,6 +25,8 @@
  ***************************************************************************/
 #include "tool_setup.h"
 
+void showhelp(const char *trigger, const char *arg, const char *endarg);
+
 #ifdef USE_MANUAL
 void hugehelp(void);
 #else
index d87beae6d259779bd7c5e886b61b45fd6956c0bf..4a33c7db7cba7bbc44df970a2a7b7bf786209219 100644 (file)
@@ -266,7 +266,7 @@ const struct helptxt helptext[] = {
   {"-H, --header <header/@file>",
    "Pass custom header(s) to server",
    CURLHELP_HTTP | CURLHELP_IMAP | CURLHELP_SMTP},
-  {"-h, --help <category>",
+  {"-h, --help <subject>",
    "Get help for commands",
    CURLHELP_IMPORTANT | CURLHELP_CURL},
   {"    --hostpubmd5 <md5>",
index 54b9af66a83c189e7fc27ddcaa48ab20db717bb5..c81cfbe2c0336e2542ff41766a516e45c82ba845 100644 (file)
@@ -50,6 +50,7 @@ TESTSCRIPTS = \
  test1486.pl  \
  test1488.pl  \
  test1544.pl  \
+ test1707.pl  \
  test971.pl
 
 EXTRA_DIST =        \
index 9c1ca69eff1cb094b9ff698447787e506a8404b9..39041bec7f3d2047022223a6d61e19ed11e5977a 100644 (file)
@@ -221,7 +221,8 @@ test1670 test1671 \
 \
 test1680 test1681 test1682 test1683 \
 \
-test1700 test1701 test1702 test1703 test1704 test1705 test1706 \
+test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \
+test1708 test1709 test1710 \
 \
 test1800 test1801 \
 \
index b1544ff5b346fd60ba2c2c187acc8c3f91065220..f1c481ec6586ecf35def0f5c1f1ebd0033b8690b 100644 (file)
@@ -13,6 +13,9 @@
 #
 # Client-side
 <client>
+<features>
+manual
+</features>
 <server>
 none
 </server>
@@ -34,7 +37,7 @@ curl important --help
 Usage: curl [options...] <url>
  -d, --data <data>           HTTP POST data
  -f, --fail                  Fail fast with no output on HTTP errors
- -h, --help <category>       Get help for commands
+ -h, --help <subject>        Get help for commands
  -o, --output <file>         Write to file instead of stdout
  -O, --remote-name           Write output to file named as remote file
  -i, --show-headers          Show response headers in output
@@ -50,7 +53,8 @@ Use "--help category" to get an overview of all categories, which are:
 auth, connection, curl, deprecated, dns, file, ftp, global, http, imap, ldap, 
 output, pop3, post, proxy, scp, sftp, smtp, ssh, telnet, tftp, timeout, tls, 
 upload, verbose.
-For all options use the manual or "--help all".
+Use "--help all" to list all options
+Use "--help [option]" to view documentation for a given option
 </stdout>
 </verify>
 </testcase>
index 572b1dd4b83be4e7e9dfde3442f1d949504ed479..a3cc46e31deee019873071e881eb9b15f2c5d408 100644 (file)
@@ -31,7 +31,6 @@ curl invalid category --help
 0
 </errorcode>
 <stdout mode="text">
-Usage: curl [options...] <url>
 Unknown category provided, here is a list of all categories:
 
  auth        Authentication methods
index a916cb4dfa7172681411d73ffe267bdb7082d2dc..9fd527f787b7a4d699fa3d373d6bf42e1a0dca0f 100644 (file)
@@ -35,7 +35,6 @@ curl file category --help
 0
 </errorcode>
 <stdout mode="text">
-Usage: curl [options...] <url>
 file: FILE protocol
      --create-file-mode <mode>  File mode for created files
  -I, --head                     Show document info only
index ccdb56d1a376ddcc3d232f79c778abf5936cf172..59f58dfc5acce20bbe4bc982eed65e7d71c831e6 100644 (file)
@@ -35,7 +35,6 @@ curl file category --help with lower/upper mix
 0
 </errorcode>
 <stdout mode="text">
-Usage: curl [options...] <url>
 file: FILE protocol
      --create-file-mode <mode>  File mode for created files
  -I, --head                     Show document info only
diff --git a/tests/data/test1707 b/tests/data/test1707
new file mode 100644 (file)
index 0000000..f187490
--- /dev/null
@@ -0,0 +1,27 @@
+<testcase>
+<info>
+<keywords>
+curl
+</keywords>
+</info>
+
+#
+# Client-side
+<client>
+<features>
+manual
+</features>
+<server>
+none
+</server>
+
+<name>
+Verify curl -h --insecure
+</name>
+
+<command type="perl">
+%SRCDIR/test1707.pl %CURL --insecure %LOGDIR/help%TESTNUMBER ../docs/cmdline-opts/curl.txt
+</command>
+</client>
+
+</testcase>
diff --git a/tests/data/test1708 b/tests/data/test1708
new file mode 100644 (file)
index 0000000..ab59e71
--- /dev/null
@@ -0,0 +1,27 @@
+<testcase>
+<info>
+<keywords>
+curl
+</keywords>
+</info>
+
+#
+# Client-side
+<client>
+<features>
+manual
+</features>
+<server>
+none
+</server>
+
+<name>
+Verify curl -h -F
+</name>
+
+<command type="perl">
+%SRCDIR/test1707.pl %CURL -F %LOGDIR/help%TESTNUMBER ../docs/cmdline-opts/curl.txt
+</command>
+</client>
+
+</testcase>
diff --git a/tests/data/test1709 b/tests/data/test1709
new file mode 100644 (file)
index 0000000..8482ba4
--- /dev/null
@@ -0,0 +1,32 @@
+<testcase>
+<info>
+<keywords>
+curl
+</keywords>
+</info>
+
+#
+# Client-side
+<client>
+<features>
+manual
+</features>
+<server>
+none
+</server>
+
+<name>
+Verify curl -h --badone
+</name>
+
+<command>
+-h --badone
+</command>
+</client>
+
+<verify>
+<stderr mode="text">
+Incorrect option name to show help for, see curl -h
+</stderr>
+</verify>
+</testcase>
diff --git a/tests/data/test1710 b/tests/data/test1710
new file mode 100644 (file)
index 0000000..7356355
--- /dev/null
@@ -0,0 +1,27 @@
+<testcase>
+<info>
+<keywords>
+curl
+</keywords>
+</info>
+
+#
+# Client-side
+<client>
+<features>
+manual
+</features>
+<server>
+none
+</server>
+
+<name>
+Verify curl -h --no-clobber
+</name>
+
+<command type="perl">
+%SRCDIR/test1707.pl %CURL --no-clobber %LOGDIR/help%TESTNUMBER ../docs/cmdline-opts/curl.txt
+</command>
+</client>
+
+</testcase>
diff --git a/tests/test1707.pl b/tests/test1707.pl
new file mode 100755 (executable)
index 0000000..65f9019
--- /dev/null
@@ -0,0 +1,121 @@
+#!/usr/bin/env perl
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+#
+# This script grew out of help from Przemyslaw Iskra and Balint Szilakszi
+# a late evening in the #curl IRC channel.
+#
+
+use strict;
+use warnings;
+
+my $curl = shift @ARGV;
+my $opt = shift @ARGV;
+my $output = shift @ARGV;
+my $txt = shift @ARGV;
+
+my $longopt;
+my $shortopt;
+if($opt =~ /^--/) {
+    $longopt = $opt;
+}
+else {
+    $shortopt = $opt;
+}
+
+# first run the help command
+system("$curl -h $opt > $output");
+my @curlout;
+open(O, "<$output");
+push @curlout, <O>;
+close(O);
+
+# figure out the short+long option combo using -h all*/
+open(C, "$curl -h all|");
+if($shortopt) {
+    while(<C>) {
+        if(/^ +$opt, ([^ ]*)/) {
+            $longopt = $1;
+            last;
+        }
+    }
+}
+else {
+    while(<C>) {
+        my $f  = $_;
+        if(/ $opt /) {
+            if($f =~ /^ *(-(.)), $longopt/) {
+                $shortopt = $1;
+            }
+            last;
+        }
+    }
+}
+close(C);
+
+my $fullopt;
+if($shortopt) {
+    $fullopt = "$shortopt, $longopt";
+}
+else {
+    $fullopt = $longopt;
+}
+
+open(R, "<$txt");
+my $show = 0;
+my @txtout;
+while(<R>) {
+    if(/^    $fullopt/) {
+        $show = 1;
+    }
+    elsif(/^    -/ && $show) {
+        last;
+    }
+    if($show) {
+        push @txtout, $_;
+    }
+}
+close(R);
+
+my $error;
+if(scalar(@curlout) != scalar(@txtout)) {
+    printf "curl -h $opt is %d lines, $txt says %d lines\n",
+        scalar(@curlout), scalar(@txtout);
+    $error++;
+}
+else {
+    # same size, compare line by line
+    for my $i (0 .. $#curlout) {
+        # trim CRLF from the data
+        $curlout[$i] =~ s/[\r\n]//g;
+        $txtout[$i] =~ s/[\r\n]//g;
+        if($curlout[$i] ne $txtout[$i]) {
+            printf "Line %d\n", $i;
+            printf "-h   : %s\n", $curlout[$i];
+            printf "file : %s\n", $txtout[$i];
+            $error++;
+        }
+    }
+}
+exit $error;