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
This commit is contained in:
Daniel Stenberg 2024-08-03 20:24:12 +02:00
parent 9b1e4b4632
commit 9a0cf56471
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
22 changed files with 794 additions and 344 deletions

View File

@ -148,7 +148,6 @@
18. Command line tool 18. Command line tool
18.1 sync 18.1 sync
18.2 glob posts 18.2 glob posts
18.3 -h option
18.4 --proxycommand 18.4 --proxycommand
18.5 UTF-8 filenames in Content-Disposition 18.5 UTF-8 filenames in Content-Disposition
18.6 Option to make -Z merge lined based outputs on stdout 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'. Globbing support for -d and -F, as in 'curl -d "name=foo[0-9]" URL'.
This is easily scripted though. 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 18.4 --proxycommand
Allow the user to make curl run a command and use its stdio to make requests Allow the user to make curl run a command and use its stdio to make requests

View 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. retain their values and meaning even after --next.
The following options are global: `%GLOBALS`. The following options are global: `%GLOBALS`.
# ALL OPTIONS

View File

@ -2,7 +2,7 @@
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl SPDX-License-Identifier: curl
Long: help Long: help
Arg: <category> Arg: <subject>
Short: h Short: h
Help: Get help for commands Help: Get help for commands
Category: important curl Category: important curl
@ -12,15 +12,28 @@ See-also:
- verbose - verbose
Example: Example:
- --help all - --help all
- --help --insecure
- --help -f
--- ---
# `--help` # `--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 If no argument is provided, curl displays the most important command line
arguments. 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.

View File

@ -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") { if($ARGV[0] eq "-c") {
$c=1; $c=1;
shift @ARGV; shift @ARGV;
@ -53,6 +46,8 @@ print <<HEAD
*/ */
#ifdef USE_MANUAL #ifdef USE_MANUAL
#include "tool_hugehelp.h" #include "tool_hugehelp.h"
#include "tool_help.h"
HEAD HEAD
; ;
if($c) { if($c) {
@ -111,23 +106,25 @@ static void zfree_func(voidpf opaque, voidpf ptr)
(void) opaque; (void) opaque;
free(ptr); free(ptr);
} }
#define HEADERLEN 10
/* Decompress and send to stdout a gzip-compressed buffer */ /* Decompress and send to stdout a gzip-compressed buffer */
void hugehelp(void) void hugehelp(void)
{ {
unsigned char *buf; unsigned char *buf;
int status, headerlen; int status;
z_stream z; z_stream z;
/* Make sure no gzip options are set */ /* Make sure no gzip options are set */
if(hugehelpgz[3] & 0xfe) if(hugehelpgz[3] & 0xfe)
return; return;
headerlen = 10;
memset(&z, 0, sizeof(z_stream)); memset(&z, 0, sizeof(z_stream));
z.zalloc = (alloc_func)zalloc_func; z.zalloc = (alloc_func)zalloc_func;
z.zfree = (free_func)zfree_func; z.zfree = (free_func)zfree_func;
z.avail_in = (unsigned int)(sizeof(hugehelpgz) - headerlen); z.avail_in = (unsigned int)(sizeof(hugehelpgz) - HEADERLEN);
z.next_in = (unsigned char *)hugehelpgz + headerlen; z.next_in = (unsigned char *)hugehelpgz + HEADERLEN;
if(inflateInit2(&z, -MAX_WBITS) != Z_OK) if(inflateInit2(&z, -MAX_WBITS) != Z_OK)
return; return;
@ -144,7 +141,49 @@ void hugehelp(void)
break; break;
} }
else 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); free(buf);
} }
@ -188,6 +227,21 @@ void hugehelp(void)
while(curlman[i]) while(curlman[i])
puts(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 ENDLINE
; ;

View File

@ -71,306 +71,16 @@ static ParameterError getstr(char **str, const char *val, bool allowblank)
return PARAM_OK; 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' */ /* this array MUST be alphasorted based on the 'lname' */
static const struct LongShort aliases[]= { static const struct LongShort aliases[]= {
{"abstract-unix-socket", ARG_FILE, ' ', C_ABSTRACT_UNIX_SOCKET}, {"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}, {"alt-svc", ARG_STRG, ' ', C_ALT_SVC},
{"anyauth", ARG_BOOL, ' ', C_ANYAUTH}, {"anyauth", ARG_BOOL, ' ', C_ANYAUTH},
{"append", ARG_BOOL, 'a', C_APPEND}, {"append", ARG_BOOL, 'a', C_APPEND},
{"aws-sigv4", ARG_STRG, ' ', C_AWS_SIGV4}, {"aws-sigv4", ARG_STRG, ' ', C_AWS_SIGV4},
{"basic", ARG_BOOL, ' ', C_BASIC}, {"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}, {"ca-native", ARG_BOOL, ' ', C_CA_NATIVE},
{"cacert", ARG_FILE, ' ', C_CACERT}, {"cacert", ARG_FILE, ' ', C_CACERT},
{"capath", ARG_FILE, ' ', C_CAPATH}, {"capath", ARG_FILE, ' ', C_CAPATH},
@ -378,7 +88,7 @@ static const struct LongShort aliases[]= {
{"cert-status", ARG_BOOL, ' ', C_CERT_STATUS}, {"cert-status", ARG_BOOL, ' ', C_CERT_STATUS},
{"cert-type", ARG_STRG, ' ', C_CERT_TYPE}, {"cert-type", ARG_STRG, ' ', C_CERT_TYPE},
{"ciphers", ARG_STRG, ' ', C_CIPHERS}, {"ciphers", ARG_STRG, ' ', C_CIPHERS},
{"clobber", ARG_BOOL, ' ', C_CLOBBER}, {"clobber", ARG_BOOL|ARG_NO, ' ', C_CLOBBER},
{"compressed", ARG_BOOL, ' ', C_COMPRESSED}, {"compressed", ARG_BOOL, ' ', C_COMPRESSED},
{"compressed-ssh", ARG_BOOL, ' ', C_COMPRESSED_SSH}, {"compressed-ssh", ARG_BOOL, ' ', C_COMPRESSED_SSH},
{"config", ARG_FILE, 'K', C_CONFIG}, {"config", ARG_FILE, 'K', C_CONFIG},
@ -468,7 +178,7 @@ static const struct LongShort aliases[]= {
{"ipv6", ARG_NONE, '6', C_IPV6}, {"ipv6", ARG_NONE, '6', C_IPV6},
{"json", ARG_STRG, ' ', C_JSON}, {"json", ARG_STRG, ' ', C_JSON},
{"junk-session-cookies", ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES}, {"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-cnt", ARG_STRG, ' ', C_KEEPALIVE_CNT},
{"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME}, {"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME},
{"key", ARG_FILE, ' ', C_KEY}, {"key", ARG_FILE, ' ', C_KEY},
@ -498,7 +208,7 @@ static const struct LongShort aliases[]= {
{"netrc-optional", ARG_BOOL, ' ', C_NETRC_OPTIONAL}, {"netrc-optional", ARG_BOOL, ' ', C_NETRC_OPTIONAL},
{"next", ARG_NONE, ':', C_NEXT}, {"next", ARG_NONE, ':', C_NEXT},
{"noproxy", ARG_STRG, ' ', C_NOPROXY}, {"noproxy", ARG_STRG, ' ', C_NOPROXY},
{"npn", ARG_BOOL, ' ', C_NPN}, {"npn", ARG_BOOL|ARG_NO, ' ', C_NPN},
{"ntlm", ARG_BOOL, ' ', C_NTLM}, {"ntlm", ARG_BOOL, ' ', C_NTLM},
{"ntlm-wb", ARG_BOOL, ' ', C_NTLM_WB}, {"ntlm-wb", ARG_BOOL, ' ', C_NTLM_WB},
{"oauth2-bearer", ARG_STRG, ' ', C_OAUTH2_BEARER}, {"oauth2-bearer", ARG_STRG, ' ', C_OAUTH2_BEARER},
@ -515,7 +225,7 @@ static const struct LongShort aliases[]= {
{"post303", ARG_BOOL, ' ', C_POST303}, {"post303", ARG_BOOL, ' ', C_POST303},
{"preproxy", ARG_STRG, ' ', C_PREPROXY}, {"preproxy", ARG_STRG, ' ', C_PREPROXY},
{"progress-bar", ARG_BOOL, '#', C_PROGRESS_BAR}, {"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", ARG_STRG, ' ', C_PROTO},
{"proto-default", ARG_STRG, ' ', C_PROTO_DEFAULT}, {"proto-default", ARG_STRG, ' ', C_PROTO_DEFAULT},
{"proto-redir", ARG_STRG, ' ', C_PROTO_REDIR}, {"proto-redir", ARG_STRG, ' ', C_PROTO_REDIR},
@ -573,7 +283,7 @@ static const struct LongShort aliases[]= {
{"sasl-authzid", ARG_STRG, ' ', C_SASL_AUTHZID}, {"sasl-authzid", ARG_STRG, ' ', C_SASL_AUTHZID},
{"sasl-ir", ARG_BOOL, ' ', C_SASL_IR}, {"sasl-ir", ARG_BOOL, ' ', C_SASL_IR},
{"service-name", ARG_STRG, ' ', C_SERVICE_NAME}, {"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-error", ARG_BOOL, 'S', C_SHOW_ERROR},
{"show-headers", ARG_BOOL, 'i', C_SHOW_HEADERS}, {"show-headers", ARG_BOOL, 'i', C_SHOW_HEADERS},
{"silent", ARG_BOOL, 's', C_SILENT}, {"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); 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 const struct LongShort *singles[128 - ' ']; /* ASCII => pointer */
static bool singles_done = FALSE; static bool singles_done = FALSE;
@ -1295,6 +1005,15 @@ static ParameterError set_rate(struct GlobalConfig *global,
return err; 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 */ ParameterError getparameter(const char *flag, /* f or -long-flag */
char *nextarg, /* NULL if unset */ 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; const char *word = ('-' == flag[0]) ? flag + 2 : flag;
bool noflagged = FALSE; bool noflagged = FALSE;
bool expand = FALSE; bool expand = FALSE;
struct LongShort key;
if(!strncmp(word, "no-", 3)) { if(!strncmp(word, "no-", 3)) {
/* disable this option but ignore the "no-" part when looking for it */ /* 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; word += 7;
expand = TRUE; expand = TRUE;
} }
key.lname = word;
a = bsearch(&key, aliases, sizeof(aliases)/sizeof(aliases[0]), a = findlongopt(word);
sizeof(aliases[0]), findarg);
if(a) { if(a) {
longopt = TRUE; longopt = TRUE;
} }
@ -1360,7 +1076,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
err = PARAM_OPTION_UNKNOWN; err = PARAM_OPTION_UNKNOWN;
goto error; goto error;
} }
if(noflagged && (a->desc != ARG_BOOL)) { if(noflagged && (ARGTYPE(a->desc) != ARG_BOOL)) {
/* --no- prefixed an option that is not boolean! */ /* --no- prefixed an option that is not boolean! */
err = PARAM_NO_NOT_BOOLEAN; err = PARAM_NO_NOT_BOOLEAN;
goto error; goto error;
@ -1369,8 +1085,8 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
struct curlx_dynbuf nbuf; struct curlx_dynbuf nbuf;
bool replaced; bool replaced;
if((a->desc != ARG_STRG) && if((ARGTYPE(a->desc) != ARG_STRG) &&
(a->desc != ARG_FILE)) { (ARGTYPE(a->desc) != ARG_FILE)) {
/* --expand on an option that is not a string or a filename */ /* --expand on an option that is not a string or a filename */
err = PARAM_EXPAND_ERROR; err = PARAM_EXPAND_ERROR;
goto error; goto error;
@ -1397,15 +1113,15 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
cmdline_t cmd; cmdline_t cmd;
if(!longopt && !a) { if(!longopt && !a) {
a = single(*parse); a = findshortopt(*parse);
if(!a) { if(!a) {
err = PARAM_OPTION_UNKNOWN; err = PARAM_OPTION_UNKNOWN;
break; break;
} }
} }
letter = a->letter; letter = a->letter;
cmd = a->cmd; cmd = (cmdline_t)a->cmd;
if(a->desc >= ARG_STRG) { if(ARGTYPE(a->desc) >= ARG_STRG) {
/* this option requires an extra parameter */ /* this option requires an extra parameter */
if(!longopt && parse[1]) { if(!longopt && parse[1]) {
nextarg = (char *)&parse[1]; /* this is the actual extra parameter */ 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 */ *usedarg = TRUE; /* mark it as used */
} }
if((a->desc == ARG_FILE) && if((ARGTYPE(a->desc) == ARG_FILE) &&
(nextarg[0] == '-') && nextarg[1]) { (nextarg[0] == '-') && nextarg[1]) {
/* if the filename looks like a command line option */ /* if the filename looks like a command line option */
warnf(global, "The filename argument '%s' looks like a flag.", warnf(global, "The filename argument '%s' looks like a flag.",
@ -1434,7 +1150,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
nextarg); nextarg);
} }
} }
else if((a->desc == ARG_NONE) && !toggle) { else if((ARGTYPE(a->desc) == ARG_NONE) && !toggle) {
err = PARAM_NO_PREFIX; err = PARAM_NO_PREFIX;
break; break;
} }

View File

@ -25,6 +25,301 @@
***************************************************************************/ ***************************************************************************/
#include "tool_setup.h" #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 { typedef enum {
PARAM_OK = 0, PARAM_OK = 0,
PARAM_OPTION_AMBIGUOUS, PARAM_OPTION_AMBIGUOUS,
@ -57,6 +352,9 @@ typedef enum {
struct GlobalConfig; struct GlobalConfig;
struct OperationConfig; struct OperationConfig;
const struct LongShort *findlongopt(const char *opt);
const struct LongShort *findshortopt(char letter);
ParameterError getparameter(const char *flag, char *nextarg, ParameterError getparameter(const char *flag, char *nextarg,
argv_item_t cleararg, argv_item_t cleararg,
bool *usedarg, bool *usedarg,

View File

@ -31,6 +31,8 @@
#include "tool_util.h" #include "tool_util.h"
#include "tool_version.h" #include "tool_version.h"
#include "tool_cb_prg.h" #include "tool_cb_prg.h"
#include "tool_hugehelp.h"
#include "tool_getparam.h"
#include "terminal.h" #include "terminal.h"
#include "memdebug.h" /* keep this as LAST include */ #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) void tool_help(char *category)
{ {
unsigned int cols = get_terminal_columns(); unsigned int cols = get_terminal_columns();
puts("Usage: curl [options...] <url>");
/* If no category was provided */ /* If no category was provided */
if(!category) { if(!category) {
const char *category_note = "\nThis is not the full help; this " const char *category_note = "\nThis is not the full help; this "
"menu is split into categories.\nUse \"--help category\" to get " "menu is split into categories.\nUse \"--help category\" to get "
"an overview of all categories, which are:"; "an overview of all categories, which are:";
const char *category_note2 = "For all options use the manual" const char *category_note2 =
" or \"--help all\"."; "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); print_category(CURLHELP_IMPORTANT, cols);
puts(category_note); puts(category_note);
get_categories_list(cols); get_categories_list(cols);
@ -184,6 +252,48 @@ void tool_help(char *category)
/* Lets handle the string "category" differently to not print an errormsg */ /* Lets handle the string "category" differently to not print an errormsg */
else if(curl_strequal(category, "category")) else if(curl_strequal(category, "category"))
get_categories(); 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 */ /* Otherwise print category and handle the case if the cat was not found */
else if(get_category_content(category, cols)) { else if(get_category_content(category, cols)) {
puts("Unknown category provided, here is a list of all categories:\n"); puts("Unknown category provided, here is a list of all categories:\n");

View File

@ -28,6 +28,24 @@
void tool_help(char *category); void tool_help(char *category);
void tool_list_engines(void); void tool_list_engines(void);
void tool_version_info(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 { struct helptxt {
const char *opt; const char *opt;

View File

@ -27,5 +27,12 @@
void hugehelp(void) 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();
} }

View File

@ -25,6 +25,8 @@
***************************************************************************/ ***************************************************************************/
#include "tool_setup.h" #include "tool_setup.h"
void showhelp(const char *trigger, const char *arg, const char *endarg);
#ifdef USE_MANUAL #ifdef USE_MANUAL
void hugehelp(void); void hugehelp(void);
#else #else

View File

@ -266,7 +266,7 @@ const struct helptxt helptext[] = {
{"-H, --header <header/@file>", {"-H, --header <header/@file>",
"Pass custom header(s) to server", "Pass custom header(s) to server",
CURLHELP_HTTP | CURLHELP_IMAP | CURLHELP_SMTP}, CURLHELP_HTTP | CURLHELP_IMAP | CURLHELP_SMTP},
{"-h, --help <category>", {"-h, --help <subject>",
"Get help for commands", "Get help for commands",
CURLHELP_IMPORTANT | CURLHELP_CURL}, CURLHELP_IMPORTANT | CURLHELP_CURL},
{" --hostpubmd5 <md5>", {" --hostpubmd5 <md5>",

View File

@ -50,6 +50,7 @@ TESTSCRIPTS = \
test1486.pl \ test1486.pl \
test1488.pl \ test1488.pl \
test1544.pl \ test1544.pl \
test1707.pl \
test971.pl test971.pl
EXTRA_DIST = \ EXTRA_DIST = \

View File

@ -221,7 +221,8 @@ test1670 test1671 \
\ \
test1680 test1681 test1682 test1683 \ test1680 test1681 test1682 test1683 \
\ \
test1700 test1701 test1702 test1703 test1704 test1705 test1706 \ test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \
test1708 test1709 test1710 \
\ \
test1800 test1801 \ test1800 test1801 \
\ \

View File

@ -13,6 +13,9 @@
# #
# Client-side # Client-side
<client> <client>
<features>
manual
</features>
<server> <server>
none none
</server> </server>
@ -34,7 +37,7 @@ curl important --help
Usage: curl [options...] <url> Usage: curl [options...] <url>
-d, --data <data> HTTP POST data -d, --data <data> HTTP POST data
-f, --fail Fail fast with no output on HTTP errors -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, --output <file> Write to file instead of stdout
-O, --remote-name Write output to file named as remote file -O, --remote-name Write output to file named as remote file
-i, --show-headers Show response headers in output -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, auth, connection, curl, deprecated, dns, file, ftp, global, http, imap, ldap,
output, pop3, post, proxy, scp, sftp, smtp, ssh, telnet, tftp, timeout, tls, output, pop3, post, proxy, scp, sftp, smtp, ssh, telnet, tftp, timeout, tls,
upload, verbose. 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> </stdout>
</verify> </verify>
</testcase> </testcase>

View File

@ -31,7 +31,6 @@ curl invalid category --help
0 0
</errorcode> </errorcode>
<stdout mode="text"> <stdout mode="text">
Usage: curl [options...] <url>
Unknown category provided, here is a list of all categories: Unknown category provided, here is a list of all categories:
auth Authentication methods auth Authentication methods

View File

@ -35,7 +35,6 @@ curl file category --help
0 0
</errorcode> </errorcode>
<stdout mode="text"> <stdout mode="text">
Usage: curl [options...] <url>
file: FILE protocol file: FILE protocol
--create-file-mode <mode> File mode for created files --create-file-mode <mode> File mode for created files
-I, --head Show document info only -I, --head Show document info only

View File

@ -35,7 +35,6 @@ curl file category --help with lower/upper mix
0 0
</errorcode> </errorcode>
<stdout mode="text"> <stdout mode="text">
Usage: curl [options...] <url>
file: FILE protocol file: FILE protocol
--create-file-mode <mode> File mode for created files --create-file-mode <mode> File mode for created files
-I, --head Show document info only -I, --head Show document info only

27
tests/data/test1707 Normal file
View File

@ -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>

27
tests/data/test1708 Normal file
View File

@ -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>

32
tests/data/test1709 Normal file
View File

@ -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>

27
tests/data/test1710 Normal file
View File

@ -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>

121
tests/test1707.pl Executable file
View File

@ -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;