MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
config_parser.c
1 #include <assert.h>
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <strings.h>
6 #include <string.h>
7 #include <ctype.h>
8 
9 #ifndef bool
10 #define bool char
11 #define false 0
12 #define true 1
13 #endif
14 
15 #include <memcached/config_parser.h>
16 #include <memcached/util.h>
17 
18 static int read_config_file(const char *fname, struct config_item items[],
19  FILE *error);
20 
32 static int trim_copy(char *dest, size_t size, const char *src,
33  const char **end, char stop) {
34  while (isspace(*src)) {
35  ++src;
36  }
37  size_t n = 0;
38  bool escape = false;
39  int ret = 0;
40 
41  /* Find the last non-escaped non-space character */
42  const char *lastchar = src + strlen(src) - 1;
43  while (lastchar > src && isspace(*lastchar)) {
44  lastchar--;
45  }
46  if (lastchar < src || *lastchar == '\\') {
47  lastchar++;
48  }
49  assert(lastchar >= src);
50 
51  do {
52  if ((*dest = *src) == '\\') {
53  escape = true;
54  } else {
55  escape = false;
56  ++dest;
57  }
58  ++n;
59  ++src;
60 
61  } while (!(n == size || src > lastchar || ((*src == stop) && !escape) || *src == '\0'));
62  *end = src;
63 
64  if (n == size) {
65  --dest;
66  ret = -1;
67  }
68  *dest = '\0';
69 
70  return ret;
71 }
72 
73 
74 int parse_config(const char *str, struct config_item *items, FILE *error) {
75  int ret = 0;
76  const char *ptr = str;
77 
78  while (*ptr != '\0') {
79  while (isspace(*ptr)) {
80  ++ptr;
81  }
82  if (*ptr == '\0') {
83  /* end of parameters */
84  return 0;
85  }
86 
87  const char *end;
88  char key[80];
89  if (trim_copy(key, sizeof(key), ptr, &end, '=') == -1) {
90  if (error != NULL) {
91  fprintf(error, "ERROR: Invalid key, starting at: <%s>\n", ptr);
92  }
93  return -1;
94  }
95 
96  ptr = end + 1;
97  char value[1024];
98  if (trim_copy(value, sizeof(value), ptr, &end, ';') == -1) {
99  if (error != NULL) {
100  fprintf(error, "ERROR: Invalid value, starting at: <%s>\n", ptr);
101  }
102  return -1;
103  }
104  if (*end == ';') {
105  ptr = end + 1;
106  } else {
107  ptr = end;
108  }
109 
110  int ii = 0;
111  while (items[ii].key != NULL) {
112  if (strcmp(key, items[ii].key) == 0) {
113  if (items[ii].found) {
114  if (error != NULL) {
115  fprintf(error, "WARNING: Found duplicate entry for \"%s\"\n",
116  items[ii].key);
117  }
118  }
119 
120  switch (items[ii].datatype) {
121  case DT_SIZE:
122  {
123  char *sfx = "kmgt";
124  int multiplier = 1;
125  int m = 1;
126  for (char *p = sfx; *p != '\0'; ++p) {
127  m *= 1024;
128  char *ptr = strchr(value, *p);
129  if (ptr == NULL) {
130  ptr = strchr(value, toupper(*p));
131  }
132  if (ptr != NULL) {
133  multiplier = m;
134  *ptr = '\0';
135  break;
136  }
137  }
138 
139  uint64_t val;
140  if (safe_strtoull(value, &val)) {
141  *items[ii].value.dt_size = (size_t)(val * multiplier);
142  items[ii].found = true;
143  } else {
144  ret = -1;
145  }
146  }
147  break;
148  case DT_FLOAT:
149  {
150  float val;
151  if (safe_strtof(value, &val)) {
152  *items[ii].value.dt_float = val;
153  items[ii].found = true;
154  } else {
155  ret = -1;
156  }
157  }
158  break;
159  case DT_STRING:
160  *items[ii].value.dt_string = strdup(value);
161  items[ii].found = true;
162  break;
163  case DT_BOOL:
164  if (strcasecmp(value, "true") == 0 || strcasecmp(value, "on") == 0) {
165  *items[ii].value.dt_bool = true;
166  items[ii].found = true;
167  } else if (strcasecmp(value, "false") == 0 || strcasecmp(value, "off") == 0) {
168  *items[ii].value.dt_bool = false;
169  items[ii].found = true;
170  } else {
171  ret = -1;
172  }
173  break;
174  case DT_CONFIGFILE:
175  {
176  int r = read_config_file(value, items, error);
177  if (r != 0) {
178  ret = r;
179  }
180  }
181  break;
182  default:
183  /* You need to fix your code!!! */
184  abort();
185  }
186  if (ret == -1) {
187  if (error != NULL) {
188  fprintf(error, "Invalid entry, Key: <%s> Value: <%s>\n",
189  key, value);
190  }
191  return ret;
192  }
193  break;
194  }
195  ++ii;
196  }
197 
198  if (items[ii].key == NULL) {
199  if (error != NULL) {
200  fprintf(error, "Unsupported key: <%s>\n", key);
201  }
202  ret = 1;
203  }
204  }
205  return ret;
206 }
207 
208 static int read_config_file(const char *fname, struct config_item items[],
209  FILE *error) {
210  FILE *fp = fopen(fname, "r");
211  if (fp == NULL) {
212  if (error != NULL) {
213  fprintf(error, "Failed to open file: %s\n", fname);
214  }
215  return -1;
216  }
217 
218  int ret = 0;
219  char line[1024];
220  while (fgets(line, sizeof(line), fp) != NULL && ret != -1L) {
221  if (line[0] == '#') {
222  /* Ignore comment line */
223  continue;
224  }
225 
226  int r = parse_config(line, items, error);
227  if (r != 0) {
228  ret = r;
229  }
230  }
231 
232  (void)fclose(fp);
233 
234  return ret;
235 }