From: Daniel Stenberg Date: Sat, 3 Aug 2024 18:24:12 +0000 (+0200) Subject: curl: --help [option] displays documentation for given cmdline option X-Git-Tag: curl-8_10_0~402 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9a0cf56471c1a;p=thirdparty%2Fcurl.git curl: --help [option] displays documentation for given cmdline option 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 --- diff --git a/docs/TODO b/docs/TODO index 914b9a312d..f10becd714 100644 --- a/docs/TODO +++ b/docs/TODO @@ -148,7 +148,6 @@ 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 @@ -1037,12 +1036,6 @@ 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 diff --git a/docs/cmdline-opts/_OPTIONS.md b/docs/cmdline-opts/_OPTIONS.md index 106298e745..ef208ade0f 100644 --- a/docs/cmdline-opts/_OPTIONS.md +++ b/docs/cmdline-opts/_OPTIONS.md @@ -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 diff --git a/docs/cmdline-opts/help.md b/docs/cmdline-opts/help.md index 7477a1e407..122c55cd43 100644 --- a/docs/cmdline-opts/help.md +++ b/docs/cmdline-opts/help.md @@ -2,7 +2,7 @@ c: Copyright (C) Daniel Stenberg, , et al. SPDX-License-Identifier: curl Long: help -Arg: +Arg: 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. diff --git a/src/mkhelp.pl b/src/mkhelp.pl index 96c2b4192b..77130a4ce3 100755 --- a/src/mkhelp.pl +++ b/src/mkhelp.pl @@ -23,13 +23,6 @@ # ########################################################################### -# 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 <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; } diff --git a/src/tool_getparam.h b/src/tool_getparam.h index 8abf5787e9..c36d1d66f2 100644 --- a/src/tool_getparam.h +++ b/src/tool_getparam.h @@ -25,6 +25,301 @@ ***************************************************************************/ #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, diff --git a/src/tool_help.c b/src/tool_help.c index c570cb96c8..f7ecb72199 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -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...] "); /* 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...] "); 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"); diff --git a/src/tool_help.h b/src/tool_help.h index 299da1db8c..0a334464d2 100644 --- a/src/tool_help.h +++ b/src/tool_help.h @@ -28,6 +28,24 @@ 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; diff --git a/src/tool_hugehelp.c.cvs b/src/tool_hugehelp.c.cvs index 06b132fbcb..8757cfc684 100644 --- a/src/tool_hugehelp.c.cvs +++ b/src/tool_hugehelp.c.cvs @@ -27,5 +27,12 @@ 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(); } diff --git a/src/tool_hugehelp.h b/src/tool_hugehelp.h index ce9af0c545..f00f88702b 100644 --- a/src/tool_hugehelp.h +++ b/src/tool_hugehelp.h @@ -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 diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c index d87beae6d2..4a33c7db7c 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -266,7 +266,7 @@ const struct helptxt helptext[] = { {"-H, --header
", "Pass custom header(s) to server", CURLHELP_HTTP | CURLHELP_IMAP | CURLHELP_SMTP}, - {"-h, --help ", + {"-h, --help ", "Get help for commands", CURLHELP_IMPORTANT | CURLHELP_CURL}, {" --hostpubmd5 ", diff --git a/tests/Makefile.am b/tests/Makefile.am index 54b9af66a8..c81cfbe2c0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -50,6 +50,7 @@ TESTSCRIPTS = \ test1486.pl \ test1488.pl \ test1544.pl \ + test1707.pl \ test971.pl EXTRA_DIST = \ diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 9c1ca69eff..39041bec7f 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -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 \ \ diff --git a/tests/data/test1461 b/tests/data/test1461 index b1544ff5b3..f1c481ec65 100644 --- a/tests/data/test1461 +++ b/tests/data/test1461 @@ -13,6 +13,9 @@ # # Client-side + +manual + none @@ -34,7 +37,7 @@ curl important --help Usage: curl [options...] -d, --data HTTP POST data -f, --fail Fail fast with no output on HTTP errors - -h, --help Get help for commands + -h, --help Get help for commands -o, --output 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 diff --git a/tests/data/test1462 b/tests/data/test1462 index 572b1dd4b8..a3cc46e31d 100644 --- a/tests/data/test1462 +++ b/tests/data/test1462 @@ -31,7 +31,6 @@ curl invalid category --help 0 -Usage: curl [options...] Unknown category provided, here is a list of all categories: auth Authentication methods diff --git a/tests/data/test1463 b/tests/data/test1463 index a916cb4dfa..9fd527f787 100644 --- a/tests/data/test1463 +++ b/tests/data/test1463 @@ -35,7 +35,6 @@ curl file category --help 0 -Usage: curl [options...] file: FILE protocol --create-file-mode File mode for created files -I, --head Show document info only diff --git a/tests/data/test1464 b/tests/data/test1464 index ccdb56d1a3..59f58dfc5a 100644 --- a/tests/data/test1464 +++ b/tests/data/test1464 @@ -35,7 +35,6 @@ curl file category --help with lower/upper mix 0 -Usage: curl [options...] file: FILE protocol --create-file-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 index 0000000000..f187490681 --- /dev/null +++ b/tests/data/test1707 @@ -0,0 +1,27 @@ + + + +curl + + + +# +# Client-side + + +manual + + +none + + + +Verify curl -h --insecure + + + +%SRCDIR/test1707.pl %CURL --insecure %LOGDIR/help%TESTNUMBER ../docs/cmdline-opts/curl.txt + + + + diff --git a/tests/data/test1708 b/tests/data/test1708 new file mode 100644 index 0000000000..ab59e71fa4 --- /dev/null +++ b/tests/data/test1708 @@ -0,0 +1,27 @@ + + + +curl + + + +# +# Client-side + + +manual + + +none + + + +Verify curl -h -F + + + +%SRCDIR/test1707.pl %CURL -F %LOGDIR/help%TESTNUMBER ../docs/cmdline-opts/curl.txt + + + + diff --git a/tests/data/test1709 b/tests/data/test1709 new file mode 100644 index 0000000000..8482ba49ad --- /dev/null +++ b/tests/data/test1709 @@ -0,0 +1,32 @@ + + + +curl + + + +# +# Client-side + + +manual + + +none + + + +Verify curl -h --badone + + + +-h --badone + + + + + +Incorrect option name to show help for, see curl -h + + + diff --git a/tests/data/test1710 b/tests/data/test1710 new file mode 100644 index 0000000000..7356355e41 --- /dev/null +++ b/tests/data/test1710 @@ -0,0 +1,27 @@ + + + +curl + + + +# +# Client-side + + +manual + + +none + + + +Verify curl -h --no-clobber + + + +%SRCDIR/test1707.pl %CURL --no-clobber %LOGDIR/help%TESTNUMBER ../docs/cmdline-opts/curl.txt + + + + diff --git a/tests/test1707.pl b/tests/test1707.pl new file mode 100755 index 0000000000..65f9019efe --- /dev/null +++ b/tests/test1707.pl @@ -0,0 +1,121 @@ +#!/usr/bin/env perl +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Daniel Stenberg, , 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, ; +close(O); + +# figure out the short+long option combo using -h all*/ +open(C, "$curl -h all|"); +if($shortopt) { + while() { + if(/^ +$opt, ([^ ]*)/) { + $longopt = $1; + last; + } + } +} +else { + while() { + 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() { + 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;