mirror of
https://github.com/curl/curl.git
synced 2026-07-31 11:38:06 +03:00
Merge 1c3f0c194e into 1d7b8e6c29
This commit is contained in:
commit
a207cf33a8
10 changed files with 146 additions and 66 deletions
|
|
@ -57,6 +57,12 @@ when using this option to properly escape. If this option is used at the
|
|||
command prompt then the % cannot be escaped and unintended expansion is
|
||||
possible.
|
||||
|
||||
To format numerical output for better human readability, append the `:pretty`
|
||||
modifier to a numerical variable name (e.g., `--write-out '%{size_download:pretty}'`).
|
||||
This modifier applies standard SI metric suffixes (K, M, G, etc.) and
|
||||
constrains the output to a maximum width of 5 characters, including the
|
||||
suffix. This works only with numerical variables.
|
||||
|
||||
The variables available are:
|
||||
|
||||
## `certs`
|
||||
|
|
|
|||
|
|
@ -121,3 +121,36 @@ void customrequest_helper(HttpReq req, const char *method)
|
|||
"the way you want. Consider using -I/--head instead.");
|
||||
}
|
||||
}
|
||||
|
||||
char *max5data(curl_off_t bytes, char *max5, size_t mlen)
|
||||
{
|
||||
/* a signed 64-bit value is 8192 petabytes maximum */
|
||||
const char unit[] = {'k', 'M', 'G', 'T', 'P', 'E', 0};
|
||||
int k = 0;
|
||||
if(bytes < 100000) {
|
||||
curl_msnprintf(max5, mlen, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
|
||||
return max5;
|
||||
}
|
||||
|
||||
do {
|
||||
curl_off_t nbytes = bytes / 1024;
|
||||
if(nbytes < 100) {
|
||||
/* display with a decimal */
|
||||
curl_msnprintf(max5, mlen,
|
||||
"%2" CURL_FORMAT_CURL_OFF_T ".%" CURL_FORMAT_CURL_OFF_T
|
||||
"%c",
|
||||
bytes / 1024, (bytes % 1024) * 10 / 1024, unit[k]);
|
||||
break;
|
||||
}
|
||||
else if(nbytes < 10000) {
|
||||
/* no decimals */
|
||||
curl_msnprintf(max5, mlen, "%4" CURL_FORMAT_CURL_OFF_T "%c", nbytes,
|
||||
unit[k]);
|
||||
break;
|
||||
}
|
||||
bytes = nbytes;
|
||||
k++;
|
||||
DEBUGASSERT(unit[k]);
|
||||
} while(unit[k]);
|
||||
return max5;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,10 +23,20 @@
|
|||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_getparam.h"
|
||||
#include "tool_sdecls.h"
|
||||
#include "tool_setup.h"
|
||||
|
||||
const char *param2text(ParameterError error);
|
||||
int SetHTTPrequest(HttpReq req, HttpReq *store);
|
||||
void customrequest_helper(HttpReq req, const char *method);
|
||||
|
||||
/* The point of this function would be to return a string of the input data,
|
||||
but never longer than 5 columns (+ one zero byte).
|
||||
Add suffix k, M, G when suitable...
|
||||
|
||||
Unit test @1622
|
||||
*/
|
||||
char *max5data(curl_off_t bytes, char *max5, size_t mlen);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_HELPERS_H */
|
||||
|
|
|
|||
|
|
@ -26,44 +26,6 @@
|
|||
#include "tool_operate.h"
|
||||
#include "tool_progress.h"
|
||||
|
||||
/* The point of this function would be to return a string of the input data,
|
||||
but never longer than 5 columns (+ one zero byte).
|
||||
Add suffix k, M, G when suitable...
|
||||
|
||||
Unit test 1622
|
||||
*/
|
||||
UNITTEST char *max5data(curl_off_t bytes, char *max5, size_t mlen)
|
||||
{
|
||||
/* a signed 64-bit value is 8192 petabytes maximum */
|
||||
static const char unit[] = { 'k', 'M', 'G', 'T', 'P', 'E', 0 };
|
||||
int k = 0;
|
||||
if(bytes < 100000) {
|
||||
curl_msnprintf(max5, mlen, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
|
||||
return max5;
|
||||
}
|
||||
|
||||
do {
|
||||
curl_off_t nbytes = bytes / 1024;
|
||||
if(nbytes < 100) {
|
||||
/* display with a decimal */
|
||||
curl_msnprintf(max5, mlen, "%2" CURL_FORMAT_CURL_OFF_T ".%"
|
||||
CURL_FORMAT_CURL_OFF_T "%c", bytes / 1024,
|
||||
(bytes % 1024) * 10 / 1024, unit[k]);
|
||||
break;
|
||||
}
|
||||
else if(nbytes < 10000) {
|
||||
/* no decimals */
|
||||
curl_msnprintf(max5, mlen, "%4" CURL_FORMAT_CURL_OFF_T "%c", nbytes,
|
||||
unit[k]);
|
||||
break;
|
||||
}
|
||||
bytes = nbytes;
|
||||
k++;
|
||||
DEBUGASSERT(unit[k]);
|
||||
} while(unit[k]);
|
||||
return max5;
|
||||
}
|
||||
|
||||
int xferinfo_cb(void *clientp,
|
||||
curl_off_t dltotal,
|
||||
curl_off_t dlnow,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_helpers.h"
|
||||
|
||||
int xferinfo_cb(void *clientp,
|
||||
curl_off_t dltotal,
|
||||
|
|
@ -38,7 +39,6 @@ struct per_transfer;
|
|||
void progress_finalize(struct per_transfer *per);
|
||||
|
||||
#ifdef UNITTESTS
|
||||
UNITTEST char *max5data(curl_off_t bytes, char *max5, size_t mlen);
|
||||
UNITTEST void timebuf(char *r, size_t rlen, curl_off_t seconds);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -21,11 +21,17 @@
|
|||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
#include "curlx/dynbuf.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_helpers.h"
|
||||
#include "tool_writeout.h"
|
||||
#include "tool_writeout_json.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct httpmap {
|
||||
const char *str;
|
||||
|
|
@ -43,8 +49,7 @@ static const struct httpmap http_version[] = {
|
|||
|
||||
static int writeTime(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json)
|
||||
{
|
||||
bool use_json, const struct writeoutfilter *filter) {
|
||||
bool valid = FALSE;
|
||||
curl_off_t us = 0;
|
||||
|
||||
|
|
@ -69,6 +74,13 @@ static int writeTime(FILE *stream, const struct writeoutvar *wovar,
|
|||
|
||||
curl_mfprintf(stream, "%" CURL_FORMAT_CURL_OFF_T
|
||||
".%06" CURL_FORMAT_CURL_OFF_T, secs, us);
|
||||
switch(filter->id) {
|
||||
case FILTER_NONE:
|
||||
break;
|
||||
default:
|
||||
curl_mfprintf(stream, ":%s", filter->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(use_json)
|
||||
|
|
@ -79,8 +91,7 @@ static int writeTime(FILE *stream, const struct writeoutvar *wovar,
|
|||
}
|
||||
|
||||
static int urlpart(struct per_transfer *per, writeoutid vid,
|
||||
const char **contentp)
|
||||
{
|
||||
const char **contentp) {
|
||||
CURLU *uh = curl_url();
|
||||
int rc = 0;
|
||||
if(uh) {
|
||||
|
|
@ -171,8 +182,7 @@ static void certinfo(struct per_transfer *per)
|
|||
|
||||
static int writeString(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json)
|
||||
{
|
||||
bool use_json, const struct writeoutfilter *filter) {
|
||||
bool valid = FALSE;
|
||||
const char *strinfo = NULL;
|
||||
const char *freestr = NULL;
|
||||
|
|
@ -307,8 +317,16 @@ static int writeString(FILE *stream, const struct writeoutvar *wovar,
|
|||
curl_mfprintf(stream, "\"%s\":", wovar->name);
|
||||
jsonWriteString(stream, strinfo, FALSE);
|
||||
}
|
||||
else
|
||||
else {
|
||||
fputs(strinfo, stream);
|
||||
switch(filter->id) {
|
||||
case FILTER_NONE:
|
||||
break;
|
||||
default:
|
||||
curl_mfprintf(stream, ":%s", filter->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(use_json)
|
||||
|
|
@ -322,8 +340,7 @@ static int writeString(FILE *stream, const struct writeoutvar *wovar,
|
|||
|
||||
static int writeLong(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json)
|
||||
{
|
||||
bool use_json, const struct writeoutfilter *filter) {
|
||||
bool valid = FALSE;
|
||||
long longinfo = 0;
|
||||
|
||||
|
|
@ -364,8 +381,16 @@ static int writeLong(FILE *stream, const struct writeoutvar *wovar,
|
|||
else {
|
||||
if(wovar->id == VAR_HTTP_CODE || wovar->id == VAR_HTTP_CODE_PROXY)
|
||||
curl_mfprintf(stream, "%03ld", longinfo);
|
||||
else
|
||||
else {
|
||||
curl_mfprintf(stream, "%ld", longinfo);
|
||||
switch(filter->id) {
|
||||
case FILTER_NONE:
|
||||
break;
|
||||
default:
|
||||
curl_mfprintf(stream, ":%s", filter->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -378,10 +403,10 @@ static int writeLong(FILE *stream, const struct writeoutvar *wovar,
|
|||
|
||||
static int writeOffset(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json)
|
||||
{
|
||||
bool use_json, const struct writeoutfilter *filter) {
|
||||
bool valid = FALSE;
|
||||
curl_off_t offinfo = 0;
|
||||
char prettyOff[6];
|
||||
|
||||
(void)per;
|
||||
(void)per_result;
|
||||
|
|
@ -408,7 +433,18 @@ static int writeOffset(FILE *stream, const struct writeoutvar *wovar,
|
|||
if(use_json)
|
||||
curl_mfprintf(stream, "\"%s\":", wovar->name);
|
||||
|
||||
curl_mfprintf(stream, "%" CURL_FORMAT_CURL_OFF_T, offinfo);
|
||||
switch(filter->id) {
|
||||
case FILTER_NONE:
|
||||
|
||||
curl_mfprintf(stream, "%" CURL_FORMAT_CURL_OFF_T, offinfo);
|
||||
break;
|
||||
case FILTER_BYTES_PRETTY:
|
||||
fputs(max5data(offinfo, prettyOff, sizeof(prettyOff)), stream);
|
||||
break;
|
||||
default:
|
||||
curl_mfprintf(stream, "%" CURL_FORMAT_CURL_OFF_T ":%s", offinfo,
|
||||
filter->name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(use_json)
|
||||
|
|
@ -759,18 +795,39 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
|
|||
else {
|
||||
/* this is meant as a variable to output */
|
||||
const char *end;
|
||||
size_t vlen;
|
||||
const char *filter;
|
||||
size_t vlen, filen;
|
||||
if('{' == ptr[1]) {
|
||||
const struct writeoutvar *wv = NULL;
|
||||
struct writeoutvar find = { 0 };
|
||||
struct writeoutfilter cur_fil;
|
||||
struct writeoutvar find = {0};
|
||||
filter = strchr(ptr, ':');
|
||||
end = strchr(ptr, '}');
|
||||
ptr += 2; /* pass the % and the { */
|
||||
if(!end) {
|
||||
fputs("%{", stream);
|
||||
continue;
|
||||
}
|
||||
vlen = end - ptr;
|
||||
if(filter && filter < end) {
|
||||
vlen = filter - ptr;
|
||||
|
||||
filter += 1; /* remove the : */
|
||||
filen = end - filter;
|
||||
|
||||
if(strncmp("pretty}", filter, filen) == 0) {
|
||||
cur_fil.name = "pretty";
|
||||
cur_fil.id = FILTER_BYTES_PRETTY;
|
||||
}
|
||||
else {
|
||||
errorf("Unknown --write-out filter: %s", filter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
vlen = end - ptr;
|
||||
cur_fil.name = "none";
|
||||
cur_fil.id = FILTER_NONE;
|
||||
}
|
||||
curlx_dyn_reset(&name);
|
||||
if(!curlx_dyn_addn(&name, ptr, vlen)) {
|
||||
find.name = curlx_dyn_ptr(&name);
|
||||
|
|
@ -800,15 +857,15 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
|
|||
stream = tool_stderr;
|
||||
break;
|
||||
case VAR_JSON:
|
||||
ourWriteOutJSON(stream, variables,
|
||||
CURL_ARRAYSIZE(variables),
|
||||
per, per_result);
|
||||
ourWriteOutJSON(stream, variables, CURL_ARRAYSIZE(variables),
|
||||
per, per_result, &cur_fil);
|
||||
break;
|
||||
case VAR_HEADER_JSON:
|
||||
headerJSON(stream, per);
|
||||
break;
|
||||
default:
|
||||
(void)wv->writefunc(stream, wv, per, per_result, FALSE);
|
||||
(void)wv->writefunc(stream, wv, per, per_result, FALSE,
|
||||
&cur_fil);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,13 +105,23 @@ typedef enum {
|
|||
VAR_NUM_OF_VARS /* must be the last */
|
||||
} writeoutid;
|
||||
|
||||
typedef enum {
|
||||
FILTER_NONE,
|
||||
FILTER_BYTES_PRETTY
|
||||
} writeoutfilterid;
|
||||
|
||||
struct writeoutfilter {
|
||||
const char *name;
|
||||
writeoutfilterid id;
|
||||
};
|
||||
|
||||
struct writeoutvar {
|
||||
const char *name;
|
||||
writeoutid id;
|
||||
CURLINFO ci;
|
||||
int (*writefunc)(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json);
|
||||
bool use_json, const struct writeoutfilter *filter);
|
||||
};
|
||||
|
||||
void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_writeout_json.h"
|
||||
#include "tool_writeout.h"
|
||||
#include "tool_writeout_json.h"
|
||||
|
||||
#define MAX_JSON_STRING 100000
|
||||
|
||||
|
|
@ -95,8 +95,8 @@ void jsonWriteString(FILE *stream, const char *in, bool lowercase)
|
|||
}
|
||||
|
||||
void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],
|
||||
size_t nentries,
|
||||
struct per_transfer *per, CURLcode per_result)
|
||||
size_t nentries, struct per_transfer *per,
|
||||
CURLcode per_result, const struct writeoutfilter *filter)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
|
|
@ -104,7 +104,8 @@ void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],
|
|||
|
||||
for(i = 0; i < nentries; i++) {
|
||||
if(mappings[i].writefunc &&
|
||||
mappings[i].writefunc(stream, &mappings[i], per, per_result, TRUE))
|
||||
mappings[i].writefunc(stream, &mappings[i], per, per_result, TRUE,
|
||||
filter))
|
||||
fputs(",", stream);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@
|
|||
int jsonquoted(const char *in, size_t len, struct dynbuf *out, bool lowercase);
|
||||
|
||||
void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],
|
||||
size_t nentries,
|
||||
struct per_transfer *per, CURLcode per_result);
|
||||
size_t nentries, struct per_transfer *per,
|
||||
CURLcode per_result, const struct writeoutfilter *filter);
|
||||
void headerJSON(FILE *stream, struct per_transfer *per);
|
||||
void jsonWriteString(FILE *stream, const char *in, bool lowercase);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
***************************************************************************/
|
||||
#include "unitcheck.h"
|
||||
#include "tool_progress.h"
|
||||
#include "tool_helpers.h"
|
||||
|
||||
static CURLcode test_tool1622(const char *arg)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue