/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2011, Daniel Stenberg, , 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 #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 *)""; } 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; }