tool_paramhlp.c \
tool_parsecfg.c \
tool_progress.c \
+ tool_stderr.c \
tool_strdup.c \
tool_setopt.c \
tool_sleep.c \
tool_setopt.h \
tool_setup.h \
tool_sleep.h \
+ tool_stderr.h \
tool_strdup.h \
tool_urlglob.h \
tool_util.h \
{
struct OperationConfig *operation = userdata;
struct GlobalConfig *config = operation->global;
- FILE *output = config->errors;
+ FILE *output = stderr;
const char *text;
struct timeval tv;
char timebuf[20];
config->trace_stream = stdout;
else if(!strcmp("%", config->trace_dump))
/* Ok, this is somewhat hackish but we do it undocumented for now */
- config->trace_stream = config->errors; /* aka stderr */
+ config->trace_stream = stderr;
else {
config->trace_stream = fopen(config->trace_dump, FOPEN_WRITETEXT);
config->trace_fopened = TRUE;
else if(bar->width > MAX_BARLENGTH)
bar->width = MAX_BARLENGTH;
- bar->out = config->global->errors;
+ bar->out = stderr;
bar->tick = 150;
bar->barmove = 1;
}
bool silent; /* don't show messages, --silent given */
bool noprogress; /* don't show progress bar */
bool isatty; /* Updated internally if output is a tty */
- FILE *errors; /* Error stream, defaults to stderr */
- bool errors_fopened; /* Whether error stream isn't stderr */
char *trace_dump; /* file to dump the network trace to */
FILE *trace_stream;
bool trace_fopened;
if(hdrlen) {
hdrbuf[hdrlen] = '\0';
if(slist_append(pheaders, hdrbuf)) {
- fprintf(config->global->errors,
- "Out of memory for field headers!\n");
+ fprintf(stderr, "Out of memory for field headers!\n");
return -1;
}
hdrlen = 0;
switch(c) {
case EOF:
if(ferror(fp)) {
- fprintf(config->global->errors,
- "Header file %s read error: %s\n", filename, strerror(errno));
+ fprintf(stderr, "Header file %s read error: %s\n", filename,
+ strerror(errno));
return -1;
}
return 0; /* Done. */
sep = *p;
*endpos = '\0';
if(slist_append(&headers, hdr)) {
- fprintf(config->global->errors, "Out of memory for field header!\n");
+ fprintf(stderr, "Out of memory for field header!\n");
curl_slist_free_all(headers);
return -1;
}
#include "tool_parsecfg.h"
#include "tool_main.h"
#include "dynbuf.h"
+#include "tool_stderr.h"
#include "memdebug.h" /* keep this as LAST include */
break;
case 'v': /* --stderr */
- if(strcmp(nextarg, "-")) {
- FILE *newfile = fopen(nextarg, FOPEN_WRITETEXT);
- if(!newfile)
- warnf(global, "Failed to open %s!\n", nextarg);
- else {
- if(global->errors_fopened)
- fclose(global->errors);
- global->errors = newfile;
- global->errors_fopened = TRUE;
- }
- }
- else
- global->errors = stdout;
+ tool_set_stderr_file(nextarg);
break;
case 'w': /* --interface */
/* interface */
const char *reason = param2text(result);
if(orig_opt && strcmp(":", orig_opt))
- helpf(global->errors, "option %s: %s\n", orig_opt, reason);
+ helpf(stderr, "option %s: %s\n", orig_opt, reason);
else
- helpf(global->errors, "%s\n", reason);
+ helpf(stderr, "%s\n", reason);
}
curlx_unicodefree(orig_opt);
#include "tool_vms.h"
#include "tool_main.h"
#include "tool_libinfo.h"
+#include "tool_stderr.h"
/*
* This is low-level hard-hacking memory leak tracking and similar. Using
/* Initialise the global config */
config->showerror = FALSE; /* show errors when silent */
- config->errors = stderr; /* Default errors to stderr */
config->styled_output = TRUE; /* enable detection */
config->parallel_max = PARALLEL_DEFAULT;
{
Curl_safefree(config->trace_dump);
- if(config->errors_fopened && config->errors)
- fclose(config->errors);
- config->errors = NULL;
-
if(config->trace_fopened && config->trace_stream)
fclose(config->trace_stream);
config->trace_stream = NULL;
struct GlobalConfig global;
memset(&global, 0, sizeof(global));
+ tool_init_stderr();
+
#ifdef WIN32
/* Undocumented diagnostic option to list the full paths of all loaded
modules. This is purposely pre-init. */
ptr = print_buffer;
while(len > 0) {
- fputs(prefix, config->errors);
+ fputs(prefix, stderr);
if(len > width) {
size_t cut = width-1;
max text width then! */
cut = width-1;
- (void)fwrite(ptr, cut + 1, 1, config->errors);
- fputs("\n", config->errors);
+ (void)fwrite(ptr, cut + 1, 1, stderr);
+ fputs("\n", stderr);
ptr += cut + 1; /* skip the space too */
len -= cut + 1;
}
else {
- fputs(ptr, config->errors);
+ fputs(ptr, stderr);
len = 0;
}
}
if((per->infd == -1) || fstat(per->infd, &fileinfo))
#endif
{
- helpf(global->errors, "Can't open '%s'!\n", per->uploadfile);
+ helpf(stderr, "Can't open '%s'!\n", per->uploadfile);
if(per->infd != -1) {
close(per->infd);
per->infd = STDIN_FILENO;
if(!config->synthetic_error && result &&
(!global->silent || global->showerror)) {
const char *msg = per->errorbuffer;
- fprintf(global->errors, "curl: (%d) %s\n", result,
+ fprintf(stderr, "curl: (%d) %s\n", result,
(msg && msg[0]) ? msg : curl_easy_strerror(result));
if(result == CURLE_PEER_FAILED_VERIFICATION)
- fputs(CURL_CA_CERT_ERRORMSG, global->errors);
+ fputs(CURL_CA_CERT_ERRORMSG, stderr);
}
else if(config->failwithbody) {
/* if HTTP response >= 400, return error */
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
if(code >= 400) {
if(!global->silent || global->showerror)
- fprintf(global->errors,
+ fprintf(stderr,
"curl: (%d) The requested URL returned error: %ld\n",
CURLE_HTTP_RETURNED_ERROR, code);
result = CURLE_HTTP_RETURNED_ERROR;
/* something went wrong in the writing process */
result = CURLE_WRITE_ERROR;
if(!global->silent || global->showerror)
- fprintf(global->errors, "curl: (%d) Failed writing body\n", result);
+ fprintf(stderr, "curl: (%d) Failed writing body\n", result);
}
}
/* We have written data to an output file, we truncate file
*/
if(!global->silent)
- fprintf(global->errors, "Throwing away %"
- CURL_FORMAT_CURL_OFF_T " bytes\n",
+ fprintf(stderr, "Throwing away %" CURL_FORMAT_CURL_OFF_T " bytes\n",
outs->bytes);
fflush(outs->stream);
/* truncate file at the position where we started appending */
/* when truncate fails, we can't just append as then we'll
create something strange, bail out */
if(!global->silent || global->showerror)
- fprintf(global->errors,
- "curl: (23) Failed to truncate file\n");
+ fprintf(stderr, "curl: (23) Failed to truncate file\n");
return CURLE_WRITE_ERROR;
}
/* now seek to the end of the file, the position where we
#endif
if(rc) {
if(!global->silent || global->showerror)
- fprintf(global->errors,
- "curl: (23) Failed seeking to end of file\n");
+ fprintf(stderr, "curl: (23) Failed seeking to end of file\n");
return CURLE_WRITE_ERROR;
}
outs->bytes = 0; /* clear for next round */
/* something went wrong in the writing process */
result = CURLE_WRITE_ERROR;
if(!global->silent || global->showerror)
- fprintf(global->errors, "curl: (%d) Failed writing body\n", result);
+ fprintf(stderr, "curl: (%d) Failed writing body\n", result);
}
if(result && config->rm_partial) {
notef(global, "Removing output file: %s\n", outs->filename);
/* Unless explicitly shut off */
result = glob_url(&inglob, infiles, &state->infilenum,
(!global->silent || global->showerror)?
- global->errors:NULL);
+ stderr:NULL);
if(result)
break;
config->state.inglob = inglob;
expressions and return total number of URLs in pattern set */
result = glob_url(&state->urls, urlnode->url, &state->urlnum,
(!global->silent || global->showerror)?
- global->errors:NULL);
+ stderr:NULL);
if(result)
break;
urlnum = state->urlnum;
file output call */
if(config->create_dirs) {
- result = create_dir_hierarchy(per->outfile, global->errors);
+ result = create_dir_hierarchy(per->outfile, stderr);
/* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
if(result)
break;
}
}
- if(!global->errors)
- global->errors = stderr;
-
if((!per->outfile || !strcmp(per->outfile, "-")) &&
!config->use_ascii) {
/* We get the output to stdout and we have not got the ASCII/text
my_setopt(curl, CURLOPT_TIMEVALUE_LARGE, config->condtime);
my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
customrequest_helper(config, config->httpreq, config->customrequest);
- my_setopt(curl, CURLOPT_STDERR, global->errors);
+ my_setopt(curl, CURLOPT_STDERR, stderr);
/* three new ones in libcurl 7.3: */
my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
/* Check we have a url */
if(!config->url_list || !config->url_list->url) {
- helpf(global->errors, "(%d) no URL specified!\n",
- CURLE_FAILED_INIT);
+ helpf(stderr, "(%d) no URL specified!\n", CURLE_FAILED_INIT);
return CURLE_FAILED_INIT;
}
if(!config->capath) {
curl_free(env);
curl_easy_cleanup(curltls);
- helpf(global->errors, "out of memory\n");
+ helpf(stderr, "out of memory\n");
return CURLE_OUT_OF_MEMORY;
}
capath_from_env = true;
/* If we had no arguments then make sure a url was specified in .curlrc */
if((argc < 2) && (!global->first->url_list)) {
- helpf(global->errors, NULL);
+ helpf(stderr, NULL);
result = CURLE_FAILED_INIT;
}
}
header = TRUE;
fputs("DL% UL% Dled Uled Xfers Live "
"Total Current Left Speed\n",
- global->errors);
+ stderr);
}
if(final || (diff > 500)) {
char time_left[10];
}
time2str(time_spent, spent);
- fprintf(global->errors,
+ fprintf(stderr,
"\r"
"%-3s " /* percent downloaded */
"%-3s " /* percent uploaded */
#include "curl_setup.h" /* from the lib directory */
+extern FILE *tool_stderr;
+
+#if !defined(CURL_DO_NOT_OVERRIDE_STDERR) && !defined(UNITTESTS)
+#ifdef stderr
+#undef stderr
+#endif
+#define stderr tool_stderr
+#endif
+
/*
* curl tool certainly uses libcurl's external interface.
*/
--- /dev/null
+/***************************************************************************
+ * _ _ ____ _
+ * 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
+ *
+ ***************************************************************************/
+
+/* In this file, stdio.h's stderr macro is not overridden. */
+#define CURL_DO_NOT_OVERRIDE_STDERR
+
+#include "tool_setup.h"
+
+#include "tool_stderr.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* In other tool files stderr is defined as tool_stderr by tool_setup.h */
+FILE *tool_stderr;
+
+void tool_init_stderr(void)
+{
+ tool_stderr = stderr;
+}
+
+void tool_set_stderr_file(char *filename)
+{
+ FILE *fp;
+
+ if(!filename)
+ return;
+
+ if(!strcmp(filename, "-")) {
+ tool_stderr = stdout;
+ return;
+ }
+
+ /* precheck that filename is accessible to lessen the chance that the
+ subsequent freopen will fail. */
+ fp = fopen(filename, FOPEN_WRITETEXT);
+ if(!fp) {
+ fprintf(tool_stderr, "Warning: Failed to open %s!\n", filename);
+ return;
+ }
+ fclose(fp);
+
+ /* freopen the actual stderr (stdio.h stderr) instead of tool_stderr since
+ the latter may be set to stdout. */
+ fp = freopen(filename, FOPEN_WRITETEXT, stderr);
+ if(!fp) {
+ /* stderr may have been closed by freopen. there is nothing to be done. */
+ DEBUGASSERT(0);
+ return;
+ }
+ tool_stderr = stderr;
+}
--- /dev/null
+#ifndef HEADER_CURL_TOOL_STDERR_H
+#define HEADER_CURL_TOOL_STDERR_H
+/***************************************************************************
+ * _ _ ____ _
+ * 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
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+void tool_init_stderr(void);
+void tool_set_stderr_file(char *filename);
+
+#endif /* HEADER_CURL_TOOL_STDERR_H */
stream = stdout;
break;
case VAR_STDERR:
- stream = config->global->errors;
+ stream = stderr;
break;
case VAR_JSON:
ourWriteOutJSON(stream, variables, per, per_result);