diff options
Diffstat (limited to 'src/tool_parsecfg.c')
-rw-r--r-- | src/tool_parsecfg.c | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/src/tool_parsecfg.c b/src/tool_parsecfg.c new file mode 100644 index 000000000..b60d31830 --- /dev/null +++ b/src/tool_parsecfg.c @@ -0,0 +1,308 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, 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 http://curl.haxx.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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_getparam.h" +#include "tool_helpers.h" +#include "tool_homedir.h" +#include "tool_msgs.h" +#include "tool_parsecfg.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#define CURLRC DOT_CHAR "curlrc" +#define ISSEP(x) (((x) == '=') || ((x) == ':')) + +static const char *unslashquote(const char *line, char *param); +static char *my_get_line(FILE *fp); + +/* return 0 on everything-is-fine, and non-zero otherwise */ +int parseconfig(const char *filename, + struct Configurable *config) +{ + int res; + FILE *file; + char filebuffer[512]; + bool usedarg; + char *home; + int rc = 0; + + if(!filename || !*filename) { + /* NULL or no file name attempts to load .curlrc from the homedir! */ + +#ifndef __AMIGA__ + 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); + +#ifdef WIN32 + /* Check if the file exists - if not, try CURLRC in the same + * directory as our executable + */ + file = fopen(filebuffer, "r"); + if(file != NULL) { + fclose(file); + filename = filebuffer; + } + else { + /* Get the filename of our executable. GetModuleFileName is + * already declared via inclusions done in setup header file. + * We assume that we are using the ASCII version here. + */ + int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer)); + if(n > 0 && n < (int)sizeof(filebuffer)) { + /* We got a valid filename - get the directory part */ + char *lastdirchar = strrchr(filebuffer, '\\'); + if(lastdirchar) { + size_t remaining; + *lastdirchar = 0; + /* If we have enough space, build the RC filename */ + remaining = sizeof(filebuffer) - strlen(filebuffer); + if(strlen(CURLRC) < remaining - 1) { + snprintf(lastdirchar, remaining, + "%s%s", DIR_CHAR, CURLRC); + /* Don't bother checking if it exists - we do + * that later + */ + filename = filebuffer; + } + } + } + } +#else /* WIN32 */ + filename = filebuffer; +#endif /* WIN32 */ + } + Curl_safefree(home); /* we've used it, now free it */ + } + +# else /* __AMIGA__ */ + /* On AmigaOS all the config files are into env: + */ + filename = "ENV:" CURLRC; + +#endif + } + + if(strcmp(filename,"-")) + file = fopen(filename, "r"); + else + file = stdin; + + if(file) { + char *line; + char *aline; + char *option; + char *param; + int lineno = 0; + bool alloced_param; + + while(NULL != (aline = my_get_line(file))) { + lineno++; + line = aline; + alloced_param=FALSE; + + /* line with # in the first non-blank column is a comment! */ + while(*line && ISSPACE(*line)) + line++; + + switch(*line) { + case '#': + case '/': + case '\r': + case '\n': + case '*': + case '\0': + Curl_safefree(aline); + continue; + } + + /* the option keywords starts here */ + option = line; + while(*line && !ISSPACE(*line) && !ISSEP(*line)) + line++; + /* ... and has ended here */ + + if(*line) + *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(*line && (ISSPACE(*line) || ISSEP(*line))) + line++; + + /* the parameter starts here (unless quoted) */ + if(*line == '\"') { + /* quoted parameter, do the quote dance */ + line++; + param = malloc(strlen(line) + 1); /* parameter */ + if(!param) { + /* out of memory */ + Curl_safefree(aline); + rc = 1; + break; + } + alloced_param = TRUE; + (void)unslashquote(line, param); + } + else { + param = line; /* parameter starts here */ + while(*line && !ISSPACE(*line)) + line++; + *line = '\0'; /* zero terminate */ + } + + if(param && !*param) { + /* do this so getparameter can check for required parameters. + Otherwise it always thinks there's a parameter. */ + if(alloced_param) + Curl_safefree(param); + param = NULL; + } + +#ifdef DEBUG_CONFIG + fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)")); +#endif + res = getparameter(option, param, &usedarg, config); + + if(param && *param && !usedarg) + /* we passed in a parameter that wasn't used! */ + res = PARAM_GOT_EXTRA_PARAMETER; + + if(res != PARAM_OK) { + /* the help request isn't really an error */ + if(!strcmp(filename, "-")) { + filename = (char *)"<stdin>"; + } + if(PARAM_HELP_REQUESTED != res) { + const char *reason = param2text(res); + warnf(config, "%s:%d: warning: '%s' %s\n", + filename, lineno, option, reason); + } + } + + if(alloced_param) + Curl_safefree(param); + + Curl_safefree(aline); + } + if(file != stdin) + fclose(file); + } + else + rc = 1; /* couldn't open the file */ + + return rc; +} + +/* + * Copies the string from line to the buffer at param, unquoting + * backslash-quoted characters and NUL-terminating the output string. + * Stops at the first non-backslash-quoted double quote character or the + * end of the input string. param must be at least as long as the input + * string. Returns the pointer after the last handled input character. + */ +static const char *unslashquote(const char *line, char *param) +{ + while(*line && (*line != '\"')) { + if(*line == '\\') { + char out; + line++; + + /* default is to output the letter after the backslash */ + 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; + } + *param++ = out; + line++; + } + else + *param++ = *line++; + } + *param = '\0'; /* always zero terminate */ + return line; +} + +/* + * Reads a line from the given file, ensuring is NUL terminated. + * The pointer must be freed by the caller. + * NULL is returned on an out of memory condition. + */ +static char *my_get_line(FILE *fp) +{ + char buf[4096]; + char *nl = NULL; + char *retval = NULL; + + do { + if(NULL == fgets(buf, sizeof(buf), fp)) + break; + if(!retval) { + retval = strdup(buf); + if(!retval) + return NULL; + } + else { + char *ptr; + ptr = realloc(retval, strlen(retval) + strlen(buf) + 1); + if(!ptr) { + Curl_safefree(retval); + return NULL; + } + retval = ptr; + strcat(retval, buf); + } + nl = strchr(retval, '\n'); + } while(!nl); + + if(nl) + *nl = '\0'; + + return retval; +} + |