Newer
Older
if(str2num(&config->low_speed_limit, nextarg))
return PARAM_BAD_NUMERIC;
if(!config->low_speed_time)
config->low_speed_time=30;
break;
case 'z': /* time condition coming up */
switch(*nextarg) {
case '+':
nextarg++;
default:
/* If-Modified-Since: (section 14.28 in RFC2068) */
config->timecond = CURL_TIMECOND_IFMODSINCE;
break;
case '-':
/* If-Unmodified-Since: (section 14.24 in RFC2068) */
config->timecond = CURL_TIMECOND_IFUNMODSINCE;
nextarg++;
break;
case '=':
/* Last-Modified: (section 14.29 in RFC2068) */
nextarg++;
break;
}
now=time(NULL);
config->condtime=curl_getdate(nextarg, &now);
/* now let's see if it is a file name to get the time from instead! */
struct stat statbuf;
if(-1 == stat(nextarg, &statbuf)) {
/* failed, remove time condition */
}
else {
/* pull the time out from the file */
config->condtime = statbuf.st_mtime;
}
}
break;
return PARAM_OPTION_UNKNOWN;
} while(!longopt && !singleopt && *++parse && !*usedarg);
return PARAM_OK;
static int parseconfig(const char *filename,
struct Configurable *config)
{
int res;
FILE *file;
char filebuffer[512];
char *home;
if(!filename || !*filename) {
/* NULL or no file name attempts to load .curlrc from the homedir! */
#define CURLRC DOT_CHAR "curlrc"
filename = CURLRC; /* sensible default */
home = homedir(); /* portable homedir finder */
if(home) {
if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) {
snprintf(filebuffer, sizeof(filebuffer),
"%s%s%s", home, DIR_CHAR, CURLRC);
filename = filebuffer;
}
free(home); /* we've used it, now free it */
}
}
if(strcmp(filename,"-"))
file = fopen(filename, "r");
else
file = stdin;
Daniel Stenberg
committed
if(file) {
Daniel Stenberg
committed
char *line;
char *aline;
char *option;
char *param;
int lineno=0;
bool alloced_param;
#define isseparator(x) (((x)=='=') || ((x) == ':'))
while (NULL != (aline = my_get_line(file))) {
lineno++;
line = aline;
alloced_param=FALSE;
Daniel Stenberg
committed
/* lines with # in the fist column is a comment! */
line++;
switch(*line) {
case '#':
case '/':
case '\r':
case '\n':
case '*':
case '\0':
Daniel Stenberg
committed
continue;
}
/* the option keywords starts here */
option = line;
while(*line && !isspace((int)*line) && !isseparator(*line))
line++;
/* ... and has ended here */
*line++=0; /* zero terminate, we have a local copy of the data */
#ifdef DEBUG_CONFIG
fprintf(stderr, "GOT: %s\n", option);
#endif
/* pass spaces and separator(s) */
while(isspace((int)*line) || isseparator(*line))
line++;
/* the parameter starts here (unless quoted) */
if(*line == '\"') {
char *ptr;
/* quoted parameter, do the qoute dance */
line++;
param=strdup(line); /* parameter */
alloced_param=TRUE;
ptr=param;
while(*line && (*line != '\"')) {
if(*line == '\\') {
line++;
/* default is to output the letter after the backslah */
switch(out = *line) {
case '\0':
continue; /* this'll break out of the loop */
case 't':
out='\t';
break;
case 'n':
out='\n';
break;
case 'r':
out='\r';
break;
case 'v':
out='\v';
break;
}
*ptr++=out;
line++;
}
else
*ptr++=*line++;
}
*ptr=0; /* always zero terminate */
else {
param=line; /* parameter starts here */
while(*line && !isspace((int)*line))
line++;
*line=0; /* zero terminate */
#ifdef DEBUG_CONFIG
fprintf(stderr, "PARAM: \"%s\"\n", param);
#endif
res = getparameter(option, param, &usedarg, config);
Daniel Stenberg
committed
if(*param && !usedarg)
/* we passed in a parameter that wasn't used! */
res = PARAM_GOT_EXTRA_PARAMETER;
Daniel Stenberg
committed
if(res != PARAM_OK) {
/* the help request isn't really an error */
if(!strcmp(filename, "-")) {
}
if(PARAM_HELP_REQUESTED != res) {
const char *reason = param2text(res);
fprintf(stderr, "%s:%d: warning: '%s' %s\n",
filename, lineno, option, reason);
Daniel Stenberg
committed
}
Daniel Stenberg
committed
}
if(alloced_param)
free(param);
free(aline);
return 0;
#ifdef HAVE_POLL
/* portable subsecond "sleep" */
poll((void *)0, 0, ms);
#else
/* systems without poll() need other solutions */
#ifdef WIN32
/* Windows offers a millisecond sleep */
Sleep(ms);
#else
/* Other systems must use select() for this */
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = ms * 1000;
select(0, NULL, NULL, NULL, &timeout);
#endif
#endif
struct OutStruct {
char *filename;
FILE *stream;
struct Configurable *config;
int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
Daniel Stenberg
committed
int rc;
if(out && !out->stream) {
/* open file for writing */
out->stream=fopen(out->filename, "wb");
if(!out->stream)
return -1; /* failure */
}
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
if(config->recvpersecond) {
/*
* We know when we received data the previous time. We know how much data
* we get now. Make sure that this is not faster than we are told to run.
* If we're faster, sleep a while *before* doing the fwrite() here.
*/
time_t timediff;
time_t now;
now = time(NULL);
timediff = now - config->lastrecvtime;
if( size*nmemb > config->recvpersecond*timediff) {
/* figure out how many milliseconds to rest */
go_sleep ( (size*nmemb)*1000/config->recvpersecond - timediff*1000 );
now = time(NULL);
}
config->lastrecvtime = now;
}
Daniel Stenberg
committed
rc = fwrite(buffer, size, nmemb, out->stream);
if(config->nobuffer)
/* disable output buffering */
fflush(out->stream);
return rc;
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
struct InStruct {
FILE *stream;
struct Configurable *config;
};
int my_fread(void *buffer, size_t size, size_t nmemb, void *userp)
{
struct InStruct *in=(struct InStruct *)userp;
struct Configurable *config = in->config;
if(config->sendpersecond) {
/*
* We know when we sent data the previous time. We know how much data
* we sent. Make sure that this was not faster than we are told to run.
* If we're faster, sleep a while *before* doing the fread() here.
* Also, make no larger fread() than should be sent this second!
*/
time_t timediff;
time_t now;
now = time(NULL);
timediff = now - config->lastsendtime;
if( config->lastsendsize > config->sendpersecond*timediff) {
/* figure out how many milliseconds to rest */
go_sleep ( config->lastsendsize*1000/config->sendpersecond -
timediff*1000 );
now = time(NULL);
}
config->lastsendtime = now;
if(size*nmemb > config->sendpersecond) {
/* lower the size to actually read */
nmemb = config->sendpersecond;
size = 1;
}
config->lastsendsize = size*nmemb;
}
return fread(buffer, size, nmemb, in->stream);
}
struct ProgressData {
Daniel Stenberg
committed
int calls;
double prev;
int width;
FILE *out; /* where to write everything to */
int initial_size;
};
int myprogress (void *clientp,
Daniel Stenberg
committed
double dltotal,
double dlnow,
double ultotal,
double ulnow)
{
/* The original progress-bar source code was written for curl by Lars Aas,
and this new edition inherites some of his concepts. */
char line[256];
char outline[256];
char format[40];
double frac;
double percent;
int barwidth;
int num;
int i;
struct ProgressData *bar = (struct ProgressData *)clientp;
double total = dltotal + ultotal + bar->initial_size;
double point = dlnow + ulnow + bar->initial_size; /* we've come this far */
Daniel Stenberg
committed
bar->calls++; /* simply count invokes */
if(0 == total) {
int prevblock = (int)bar->prev / 1024;
int thisblock = (int)point / 1024;
while ( thisblock > prevblock ) {
fprintf( bar->out, "#" );
prevblock++;
}
}
else {
frac = point / total;
percent = frac * 100.0f;
barwidth = bar->width - 7;
num = (int) (((double)barwidth) * frac);
i = 0;
for ( i = 0; i < num; i++ ) {
line[i] = '#';
}
line[i] = '\0';
sprintf( format, "%%-%ds %%5.1f%%%%", barwidth );
sprintf( outline, format, line, percent );
fprintf( bar->out, "\r%s", outline );
}
fflush(bar->out);
bar->prev = point;
return 0;
}
static
void progressbarinit(struct ProgressData *bar,
struct Configurable *config)
{
#ifdef __EMX__
/* 20000318 mgs */
int scr_size [2];
#endif
char *colp;
memset(bar, 0, sizeof(struct ProgressData));
/* pass this through to progress function so
* it can display progress towards total file
* not just the part that's left. (21-may-03, dbyron) */
if (config->use_resume)
bar->initial_size = config->resume_from;
/* TODO: get terminal width through ansi escapes or something similar.
try to update width when xterm is resized... - 19990617 larsa */
#ifndef __EMX__
/* 20000318 mgs
* OS/2 users most likely won't have this env var set, and besides that
* we're using our own way to determine screen width */
colp = curl_getenv("COLUMNS");
if (colp != NULL) {
bar->width = atoi(colp);
}
else
bar->width = 79;
#else
/* 20000318 mgs
* We use this emx library call to get the screen width, and subtract
* one from what we got in order to avoid a problem with the cursor
* advancing to the next line if we print a string that is as long as
* the screen is wide. */
_scrsize(scr_size);
bar->width = scr_size[0] - 1;
#endif
bar->out = config->errors;
}
Daniel Stenberg
committed
static
void dump(const char *text,
FILE *stream, unsigned char *ptr, size_t size,
bool nohex)
Daniel Stenberg
committed
{
size_t i;
size_t c;
unsigned int width=0x10;
if(nohex)
/* without the hex output, we can fit more on screen */
width = 0x40;
Daniel Stenberg
committed
fprintf(stream, "%s, %d bytes (0x%x)\n", text, size, size);
Daniel Stenberg
committed
Daniel Stenberg
committed
fprintf(stream, "%04x: ", i);
if(!nohex) {
/* hex not disabled, show it */
for(c = 0; c < width; c++)
if(i+c < size)
fprintf(stream, "%02x ", ptr[i+c]);
else
fputs(" ", stream);
}
for(c = 0; (c < width) && (i+c < size); c++) {
/* check for 0D0A; if found, skip past and start a new line of output */
if (nohex && (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
i+=(c+2-width);
break;
}
Daniel Stenberg
committed
fprintf(stream, "%c",
(ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:'.');
/* check again for 0D0A, to avoid an extra \n if it's at width */
if (nohex && (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
i+=(c+3-width);
break;
}
}
Daniel Stenberg
committed
fputc('\n', stream); /* newline */
}
Daniel Stenberg
committed
}
static
int my_trace(CURL *handle, curl_infotype type,
unsigned char *data, size_t size,
void *userp)
{
struct Configurable *config = (struct Configurable *)userp;
FILE *output=config->errors;
Daniel Stenberg
committed
(void)handle; /* prevent compiler warning */
if(!config->trace_stream) {
Daniel Stenberg
committed
/* open for append */
Daniel Stenberg
committed
if(curl_strequal("-", config->trace_dump))
config->trace_stream = stdout;
else {
config->trace_stream = fopen(config->trace_dump, "w");
config->trace_fopened = TRUE;
}
}
Daniel Stenberg
committed
if(config->trace_stream)
output = config->trace_stream;
switch (type) {
case CURLINFO_TEXT:
fprintf(output, "== Info: %s", data);
default: /* in case a new one is introduced to shock us */
return 0;
Daniel Stenberg
committed
case CURLINFO_HEADER_OUT:
Daniel Stenberg
committed
break;
case CURLINFO_DATA_OUT:
text = "=> Send data";
Daniel Stenberg
committed
break;
case CURLINFO_HEADER_IN:
Daniel Stenberg
committed
break;
case CURLINFO_DATA_IN:
Daniel Stenberg
committed
break;
}
dump(text, output, data, size, config->trace_ascii);
Daniel Stenberg
committed
return 0;
}
void free_config_fields(struct Configurable *config)
{
if(config->random_file)
free(config->random_file);
if(config->egd_file)
free(config->egd_file);
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
if(config->userpwd)
free(config->userpwd);
if(config->postfields)
free(config->postfields);
if(config->proxy)
free(config->proxy);
if(config->proxyuserpwd)
free(config->proxyuserpwd);
if(config->cookie)
free(config->cookie);
if(config->cookiefile)
free(config->cookiefile);
if(config->krb4level)
free(config->krb4level);
if(config->headerfile)
free(config->headerfile);
if(config->ftpport)
free(config->ftpport);
if(config->range)
free(config->range);
if(config->customrequest)
free(config->customrequest);
if(config->writeout)
free(config->writeout);
if(config->httppost)
curl_formfree(config->httppost);
if(config->cacert)
free(config->cacert);
if(config->capath)
free(config->capath);
if(config->cookiejar)
free(config->cookiejar);
curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
curl_slist_free_all(config->postquote); /* */
curl_slist_free_all(config->headers); /* */
}
Daniel Stenberg
committed
#if defined(WIN32) && !defined(__CYGWIN32__)
/* Function to find CACert bundle on a Win32 platform using SearchPath.
* (SearchPath is defined in windows.h, which is #included into libcurl)
* (Use the ASCII version instead of the unicode one!)
* The order of the directories it searches is:
* 1. application's directory
* 2. current working directory
* 3. Windows System directory (e.g. C:\windows\system32)
* 4. Windows Directory (e.g. C:\windows)
* 5. all directories along %PATH%
*/
static void FindWin32CACert(struct Configurable *config,
const char *bundle_file)
{
/* only check for cert file if "we" support SSL */
if(curlinfo->features & CURL_VERSION_SSL) {
Daniel Stenberg
committed
DWORD buflen;
char *ptr = NULL;
char *retval = (char *) malloc(sizeof (TCHAR) * (MAX_PATH + 1));
if (!retval)
return;
retval[0] = '\0';
buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr);
if (buflen > 0) {
GetStr(&config->cacert, retval);
}
free(retval);
}
}
#endif
static int
operate(struct Configurable *config, int argc, char *argv[])
char errorbuffer[CURL_ERROR_SIZE];
char useragent[128]; /* buah, we don't want a larger default user agent */
struct ProgressData progressbar;
struct getout *urlnode;
struct getout *nextnode;
Daniel Stenberg
committed
struct OutStruct heads;
Daniel Stenberg
committed
URLGlob *urls=NULL;
URLGlob *inglob=NULL;
int infilenum;
char *infiles; /* might a glob pattern */
char *uploadfile=NULL; /* a single file, never a glob */
FILE *infd;
bool infdfopen;
FILE *headerfilep = NULL;
char *urlbuffer=NULL;
long uploadfilesize; /* -1 means unknown */
Daniel Stenberg
committed
char *httpgetfields=NULL;
int res = 0;
int up; /* upload file counter within a single upload glob */
Daniel Stenberg
committed
char *env;
/* this sends all memory debug messages to a logfile named memdump */
env = curl_getenv("CURL_MEMDEBUG");
if(env) {
curl_memdebug("memdump");
}
env = curl_getenv("CURL_MEMLIMIT");
if(env) {
curl_memlimit(atoi(env));
curl_free(env);
}
/* we get libcurl info right away */
curlinfo = curl_version_info(CURLVERSION_NOW);
errorbuffer[0]=0; /* prevent junk from being output */
Daniel Stenberg
committed
main_init(); /* inits */
config->showerror=TRUE;
config->conf=CONF_DEFAULT;
Daniel Stenberg
committed
config->use_httpget=FALSE;
config->create_dirs=FALSE;
Daniel Stenberg
committed
(!curl_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
strchr(argv[1], 'q')) {
/*
* The first flag, that is not a verbose name, but a shortname
* and it includes the 'q' flag!
*/
;
}
else {
res = parseconfig(NULL, config);
}
/* Parse options */
for (i = 1; i < argc; i++) {
if(stillflags &&
('-' == argv[i][0])) {
char *nextarg;
bool passarg;
char *origopt=argv[i];
char *flag = argv[i];
Daniel Stenberg
committed
if(curl_strequal("--", argv[i]))
/* this indicates the end of the flags and thus enables the
following (URL) argument to start with -. */
stillflags=FALSE;
else {
nextarg= (i < argc - 1)? argv[i+1]: NULL;
res = getparameter(flag, nextarg, &passarg, config);
if(res) {
const char *reason = param2text(res);
if(res != PARAM_HELP_REQUESTED)
helpf("option %s: %s\n", origopt, reason);
return CURLE_FAILED_INIT;
}
if(passarg) /* we're supposed to skip this */
i++;
}
}
else {
bool used;
/* just add the URL please */
res = getparameter((char *)"--url", argv[i], &used, config);
if(!config->url_list || !config->url_list->url) {
clean_getout(config);
if(NULL == config->useragent) {
/* set non-zero default values: */
snprintf(useragent, sizeof(useragent),
CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
config->useragent= useragent;
Daniel Stenberg
committed
/* On WIN32 (non-cygwin), we can't set the path to curl-ca-bundle.crt
* at compile time. So we look here for the file in two ways:
* 1: look at the environment variable CURL_CA_BUNDLE for a path
* 2: if #1 isn't found, use the windows API function SearchPath()
* to find it along the app's path (includes app's dir and CWD)
*
* We support the environment variable thing for non-Windows platforms
* too. Just for the sake of it.
*/
if (!config->cacert &&
!config->capath &&
!config->insecure_ok) {
Daniel Stenberg
committed
env = curl_getenv("CURL_CA_BUNDLE");
if(env) {
GetStr(&config->cacert, env);
Daniel Stenberg
committed
}
#if defined(WIN32) && !defined(__CYGWIN32__)
else
FindWin32CACert(config, "curl-ca-bundle.crt");
Daniel Stenberg
committed
#endif
Daniel Stenberg
committed
Daniel Stenberg
committed
if (config->postfields) {
if (config->use_httpget) {
/* Use the postfields data for a http get */
httpgetfields = strdup(config->postfields);
free(config->postfields);
config->postfields = NULL;
if(SetHTTPrequest((config->conf&CONF_NOBODY?HTTPREQ_HEAD:HTTPREQ_GET),
&config->httpreq)) {
Daniel Stenberg
committed
free(httpgetfields);
return PARAM_BAD_USE;
}
}
else {
if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
return PARAM_BAD_USE;
}
}
/*
* Get a curl handle to use for all forthcoming curl transfers. Cleanup
* when all transfers are done.
if(!curl) {
clean_getout(config);
}
/* After this point, we should call curl_easy_cleanup() if we decide to bail
* out from this function! */
Daniel Stenberg
committed
Daniel Stenberg
committed
if(config->headerfile) {
/* open file for output: */
if(strcmp(config->headerfile,"-")) {
heads.filename = config->headerfile;
headerfilep=NULL;
}
else
headerfilep=stdout;
heads.stream = headerfilep;
heads.config = config;
}
while(urlnode && !res) {
char *dourl;
/* get the full URL (it might be NULL) */
dourl=urlnode->url;
url = dourl;
if(NULL == url) {
/* This node had no URL, skip it and continue to the next */
if(urlnode->outfile)
free(urlnode->outfile);
/* move on to the next URL */
nextnode=urlnode->next;
free(urlnode); /* free the node */
urlnode = nextnode;
continue; /* next please */
}
/* default output stream is stdout */
outs.stream = stdout;
outs.config = config;
Daniel Stenberg
committed
/* save outfile pattern before expansion */
outfiles = urlnode->outfile?strdup(urlnode->outfile):NULL;
infiles = urlnode->infile;
if(!config->globoff && infiles) {
/* Unless explicitly shut off */
res = glob_url(&inglob, infiles, &infilenum,
config->showerror?
(config->errors?config->errors:stderr):NULL);
if(res != CURLE_OK) {
clean_getout(config);
break;
}
Daniel Stenberg
committed
}
/* Here's the loop for uploading multiple files within the same
single globbed string. If no upload, we enter the loop once anyway. */
for(up = 0;
(!up && !infiles) ||
(uploadfile = inglob?
glob_next_url(inglob):
(!up?strdup(infiles):NULL));
up++) {
uploadfilesize=-1;
if(!config->globoff) {
/* Unless explicitly shut off, we expand '{...}' and '[...]'
expressions and return total number of URLs in pattern set */
res = glob_url(&urls, dourl, &urlnum,
config->showerror?
(config->errors?config->errors:stderr):NULL);
if(res != CURLE_OK) {
break;
}
}
else
urlnum = 1; /* without globbing, this is a single URL */
/* if multiple files extracted to stdout, insert separators! */
separator= ((!outfiles || curl_strequal(outfiles, "-")) && urlnum > 1);
/* Here's looping around each globbed URL */
for(i = 0;
(url = urls?glob_next_url(urls):(i?NULL:strdup(url)));
i++) {
char *outfile;
outfile = outfiles?strdup(outfiles):NULL;
if((urlnode->flags&GETOUT_USEREMOTE) ||
(outfile && !curl_strequal("-", outfile)) ) {
/*
* We have specified a file name to store the result in, or we have
* decided we want to use the remote file name.
*/
if(!outfile) {
/* Find and get the remote file name */
char * pc =strstr(url, "://");
if(pc)
pc+=3;
else
pc=url;
pc = strrchr(pc, '/');
if(pc) {
/* duplicate the string beyond the slash */
pc++;
outfile = *pc ? strdup(pc): NULL;
}
if(!outfile || !*outfile) {
helpf("Remote file name has no length!\n");
res = CURLE_WRITE_ERROR;
free(url);
break;
}
#if defined(__DJGPP__)
{
/* This is for DOS, and then we do some major replacing of
bad characters in the file name before using it */
char *file1=xmalloc(PATH_MAX);
strcpy(file1, msdosify(outfile));
strcpy(outfile, rename_if_dos_device_name(file1));
xfree(file1);
}
#endif /* __DJGPP__ */
}
else if(urls) {
/* fill '#1' ... '#9' terms from URL pattern */
char *storefile = outfile;
outfile = glob_match_url(storefile, urls);
free(storefile);
if(!outfile) {
/* bad globbing */
fprintf(stderr, "bad output glob!\n");
free(url);
res = CURLE_FAILED_INIT;
break;
}
}
/* Create the directory hierarchy, if not pre-existant to a multiple
file output call */
Daniel Stenberg
committed
if(config->create_dirs)
if (-1 == create_dir_hierarchy(outfile)) {
return CURLE_WRITE_ERROR;
}
Daniel Stenberg
committed
if(config->resume_from_current) {
/* We're told to continue from where we are now. Get the
size of the file as it is now and open it for append instead */
struct stat fileinfo;
/*VMS?? -- Danger, the filesize is only valid for stream files */
if(0 == stat(outfile, &fileinfo))
/* set offset to current file size: */
config->resume_from = fileinfo.st_size;
else
/* let offset be 0 */
config->resume_from = 0;
}
Daniel Stenberg
committed
if(config->resume_from) {
/* open file for output: */
outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
if (!outs.stream) {
helpf("Can't open '%s'!\n", outfile);
return CURLE_WRITE_ERROR;
}
}
else {
outs.filename = outfile;
outs.stream = NULL; /* open when needed */
infdfopen=FALSE;
if(uploadfile && !curl_strequal(uploadfile, "-")) {
/*
* We have specified a file to upload and it isn't "-".
*/
struct stat fileinfo;
/* If no file name part is given in the URL, we add this file name */
char *ptr=strstr(url, "://");
if(ptr)
ptr+=3;
else
ptr=url;
ptr = strrchr(ptr, '/');
if(!ptr || !strlen(++ptr)) {
/* The URL has no file name part, add the local file name. In order
to be able to do so, we have to create a new URL in another
buffer.*/
/* We only want the part of the local path that is on the right
side of the rightmost slash and backslash. */
char *filep = strrchr(uploadfile, '/');
char *file2 = strrchr(filep?filep:uploadfile, '\\');
if(file2)