tool_parsecfg.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 #include "tool_setup.h"
23 
24 #define ENABLE_CURLX_PRINTF
25 /* use our own printf() functions */
26 #include "curlx.h"
27 
28 #include "tool_cfgable.h"
29 #include "tool_getparam.h"
30 #include "tool_helpers.h"
31 #include "tool_homedir.h"
32 #include "tool_msgs.h"
33 #include "tool_parsecfg.h"
34 
35 #include "memdebug.h" /* keep this as LAST include */
36 
37 #define CURLRC DOT_CHAR "curlrc"
38 
39 /* only acknowledge colon or equals as separators if the option was not
40  specified with an initial dash! */
41 #define ISSEP(x,dash) (!dash && (((x) == '=') || ((x) == ':')))
42 
43 static const char *unslashquote(const char *line, char *param);
44 static char *my_get_line(FILE *fp);
45 
46 /* return 0 on everything-is-fine, and non-zero otherwise */
47 int parseconfig(const char *filename, struct GlobalConfig *global)
48 {
49  int res;
50  FILE *file;
51  char filebuffer[512];
52  bool usedarg = FALSE;
53  char *home;
54  int rc = 0;
55  struct OperationConfig *operation = global->first;
56 
57  if(!filename || !*filename) {
58  /* NULL or no file name attempts to load .curlrc from the homedir! */
59 
60 #ifndef __AMIGA__
61  filename = CURLRC; /* sensible default */
62  home = homedir(); /* portable homedir finder */
63  if(home) {
64  if(strlen(home) < (sizeof(filebuffer) - strlen(CURLRC))) {
65  snprintf(filebuffer, sizeof(filebuffer),
66  "%s%s%s", home, DIR_CHAR, CURLRC);
67 
68 #ifdef WIN32
69  /* Check if the file exists - if not, try CURLRC in the same
70  * directory as our executable
71  */
72  file = fopen(filebuffer, FOPEN_READTEXT);
73  if(file != NULL) {
74  fclose(file);
75  filename = filebuffer;
76  }
77  else {
78  /* Get the filename of our executable. GetModuleFileName is
79  * already declared via inclusions done in setup header file.
80  * We assume that we are using the ASCII version here.
81  */
82  int n = GetModuleFileNameA(0, filebuffer, sizeof(filebuffer));
83  if(n > 0 && n < (int)sizeof(filebuffer)) {
84  /* We got a valid filename - get the directory part */
85  char *lastdirchar = strrchr(filebuffer, '\\');
86  if(lastdirchar) {
87  size_t remaining;
88  *lastdirchar = 0;
89  /* If we have enough space, build the RC filename */
90  remaining = sizeof(filebuffer) - strlen(filebuffer);
91  if(strlen(CURLRC) < remaining - 1) {
92  snprintf(lastdirchar, remaining,
93  "%s%s", DIR_CHAR, CURLRC);
94  /* Don't bother checking if it exists - we do
95  * that later
96  */
97  filename = filebuffer;
98  }
99  }
100  }
101  }
102 #else /* WIN32 */
103  filename = filebuffer;
104 #endif /* WIN32 */
105  }
106  Curl_safefree(home); /* we've used it, now free it */
107  }
108 
109 # else /* __AMIGA__ */
110  /* On AmigaOS all the config files are into env:
111  */
112  filename = "ENV:" CURLRC;
113 
114 #endif
115  }
116 
117  if(strcmp(filename, "-"))
118  file = fopen(filename, FOPEN_READTEXT);
119  else
120  file = stdin;
121 
122  if(file) {
123  char *line;
124  char *aline;
125  char *option;
126  char *param;
127  int lineno = 0;
128  bool alloced_param;
129  bool dashed_option;
130 
131  while(NULL != (aline = my_get_line(file))) {
132  lineno++;
133  line = aline;
134  alloced_param = FALSE;
135 
136  /* line with # in the first non-blank column is a comment! */
137  while(*line && ISSPACE(*line))
138  line++;
139 
140  switch(*line) {
141  case '#':
142  case '/':
143  case '\r':
144  case '\n':
145  case '*':
146  case '\0':
147  Curl_safefree(aline);
148  continue;
149  }
150 
151  /* the option keywords starts here */
152  option = line;
153 
154  /* the option starts with a dash? */
155  dashed_option = option[0]=='-'?TRUE:FALSE;
156 
157  while(*line && !ISSPACE(*line) && !ISSEP(*line, dashed_option))
158  line++;
159  /* ... and has ended here */
160 
161  if(*line)
162  *line++ = '\0'; /* zero terminate, we have a local copy of the data */
163 
164 #ifdef DEBUG_CONFIG
165  fprintf(stderr, "GOT: %s\n", option);
166 #endif
167 
168  /* pass spaces and separator(s) */
169  while(*line && (ISSPACE(*line) || ISSEP(*line, dashed_option)))
170  line++;
171 
172  /* the parameter starts here (unless quoted) */
173  if(*line == '\"') {
174  /* quoted parameter, do the quote dance */
175  line++;
176  param = malloc(strlen(line) + 1); /* parameter */
177  if(!param) {
178  /* out of memory */
179  Curl_safefree(aline);
180  rc = 1;
181  break;
182  }
183  alloced_param = TRUE;
184  (void)unslashquote(line, param);
185  }
186  else {
187  param = line; /* parameter starts here */
188  while(*line && !ISSPACE(*line))
189  line++;
190 
191  if(*line) {
192  *line = '\0'; /* zero terminate */
193 
194  /* to detect mistakes better, see if there's data following */
195  line++;
196  /* pass all spaces */
197  while(*line && ISSPACE(*line))
198  line++;
199 
200  switch(*line) {
201  case '\0':
202  case '\r':
203  case '\n':
204  case '#': /* comment */
205  break;
206  default:
207  warnf(operation->global, "%s:%d: warning: '%s' uses unquoted "
208  "white space in the line that may cause side-effects!\n",
209  filename, lineno, option);
210  }
211  }
212  if(!*param)
213  /* do this so getparameter can check for required parameters.
214  Otherwise it always thinks there's a parameter. */
215  param = NULL;
216  }
217 
218 #ifdef DEBUG_CONFIG
219  fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
220 #endif
221  res = getparameter(option, param, &usedarg, global, operation);
222 
223  if(!res && param && *param && !usedarg)
224  /* we passed in a parameter that wasn't used! */
226 
227  if(res == PARAM_NEXT_OPERATION) {
228  if(operation->url_list && operation->url_list->url) {
229  /* Allocate the next config */
230  operation->next = malloc(sizeof(struct OperationConfig));
231  if(operation->next) {
232  /* Initialise the newly created config */
233  config_init(operation->next);
234 
235  /* Copy the easy handle */
236  operation->next->easy = global->easy;
237 
238  /* Set the global config pointer */
239  operation->next->global = global;
240 
241  /* Update the last operation pointer */
242  global->last = operation->next;
243 
244  /* Move onto the new config */
245  operation->next->prev = operation;
246  operation = operation->next;
247  }
248  else
249  res = PARAM_NO_MEM;
250  }
251  }
252 
253  if(res != PARAM_OK && res != PARAM_NEXT_OPERATION) {
254  /* the help request isn't really an error */
255  if(!strcmp(filename, "-")) {
256  filename = "<stdin>";
257  }
258  if(res != PARAM_HELP_REQUESTED &&
259  res != PARAM_MANUAL_REQUESTED &&
261  res != PARAM_ENGINES_REQUESTED) {
262  const char *reason = param2text(res);
263  warnf(operation->global, "%s:%d: warning: '%s' %s\n",
264  filename, lineno, option, reason);
265  }
266  }
267 
268  if(alloced_param)
269  Curl_safefree(param);
270 
271  Curl_safefree(aline);
272  }
273  if(file != stdin)
274  fclose(file);
275  }
276  else
277  rc = 1; /* couldn't open the file */
278 
279  return rc;
280 }
281 
282 /*
283  * Copies the string from line to the buffer at param, unquoting
284  * backslash-quoted characters and NUL-terminating the output string.
285  * Stops at the first non-backslash-quoted double quote character or the
286  * end of the input string. param must be at least as long as the input
287  * string. Returns the pointer after the last handled input character.
288  */
289 static const char *unslashquote(const char *line, char *param)
290 {
291  while(*line && (*line != '\"')) {
292  if(*line == '\\') {
293  char out;
294  line++;
295 
296  /* default is to output the letter after the backslash */
297  switch(out = *line) {
298  case '\0':
299  continue; /* this'll break out of the loop */
300  case 't':
301  out = '\t';
302  break;
303  case 'n':
304  out = '\n';
305  break;
306  case 'r':
307  out = '\r';
308  break;
309  case 'v':
310  out = '\v';
311  break;
312  }
313  *param++ = out;
314  line++;
315  }
316  else
317  *param++ = *line++;
318  }
319  *param = '\0'; /* always zero terminate */
320  return line;
321 }
322 
323 /*
324  * Reads a line from the given file, ensuring is NUL terminated.
325  * The pointer must be freed by the caller.
326  * NULL is returned on an out of memory condition.
327  */
328 static char *my_get_line(FILE *fp)
329 {
330  char buf[4096];
331  char *nl = NULL;
332  char *line = NULL;
333 
334  do {
335  if(NULL == fgets(buf, sizeof(buf), fp))
336  break;
337  if(!line) {
338  line = strdup(buf);
339  if(!line)
340  return NULL;
341  }
342  else {
343  char *ptr;
344  size_t linelen = strlen(line);
345  ptr = realloc(line, linelen + strlen(buf) + 1);
346  if(!ptr) {
347  Curl_safefree(line);
348  return NULL;
349  }
350  line = ptr;
351  strcpy(&line[linelen], buf);
352  }
353  nl = strchr(line, '\n');
354  } while(!nl);
355 
356  if(nl)
357  *nl = '\0';
358 
359  return line;
360 }
361 
static const char * unslashquote(const char *line, char *param)
bool param(const std::string &param_name, T &param_val, const T &default_val)
struct OperationConfig * prev
Definition: tool_cfgable.h:252
#define strdup(ptr)
Definition: curl_memory.h:122
UNITTEST_START char * ptr
Definition: unit1330.c:38
struct OperationConfig * last
Definition: tool_cfgable.h:276
static int res
#define realloc(ptr, size)
Definition: curl_memory.h:128
struct GlobalConfig * global
Definition: tool_cfgable.h:251
#define malloc(size)
Definition: curl_memory.h:124
#define FOPEN_READTEXT
Definition: curl_setup.h:732
#define FALSE
UNITTEST_START int rc
Definition: unit1301.c:31
#define CURLRC
Definition: tool_parsecfg.c:37
static char * my_get_line(FILE *fp)
#define ISSEP(x, dash)
Definition: tool_parsecfg.c:41
struct OperationConfig * next
Definition: tool_cfgable.h:253
#define Curl_safefree(ptr)
Definition: memdebug.h:170
#define ISSPACE(x)
struct getout * url_list
Definition: tool_cfgable.h:113
int parseconfig(const char *filename, struct GlobalConfig *global)
Definition: tool_parsecfg.c:47
const char * param2text(int res)
Definition: tool_helpers.c:41
char * url
Definition: tool_sdecls.h:105
char * homedir(void)
Definition: tool_homedir.c:63
char buf[3]
Definition: unit1398.c:32
#define fprintf
Definition: curl_printf.h:41
#define snprintf
Definition: curl_printf.h:42
#define TRUE
#define DIR_CHAR
Definition: curl_setup.h:465
void warnf(struct GlobalConfig *config, const char *fmt,...)
Definition: tool_msgs.c:95
void config_init(struct OperationConfig *config)
Definition: tool_cfgable.c:29
ParameterError getparameter(const char *flag, char *nextarg, bool *usedarg, struct GlobalConfig *global, struct OperationConfig *config)
struct OperationConfig * first
Definition: tool_cfgable.h:274


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16