1 /* Scanner for slon config file */
2 
3 %{
4 #include <sys/stat.h>
5 #include <errno.h>
6 #include <ctype.h>
7 #include <pthread.h>
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/types.h>
13 
14 #ifndef WIN32
15 #include <unistd.h>
16 #endif
17 
18 #include "slon.h"
19 
20 
21 #define CONFIG_FILENAME "./slon.conf"
22 
23 static unsigned ConfigFileLineno;
24 
25 enum {
26         SLON_ID = 1,
27         SLON_STRING = 2,
28         SLON_INTEGER = 3,
29         SLON_REAL = 4,
30         SLON_EQUALS = 5,
31         SLON_UNQUOTED_STRING = 6,
32         SLON_QUALIFIED_ID = 7,
33 	SLON_ESCAPED_STRING = 8,
34         SLON_EOL = 99,
35         SLON_FERROR = 100
36 };
37 
38 #define YY_USER_INIT (ConfigFileLineno = 1)
39 
40 /* prototype, so compiler is happy with our high warnings setting */
41 int SLON_yylex(void);
42 char *SLON_scanstr(char *);
43 %}
44 
45 %option 8bit
46 %option never-interactive
47 %option nodefault
48 %option nounput
49 %option noyywrap
50 
51 SIGN            ("-"|"+")
52 DIGIT           [0-9]
53 HEXDIGIT        [0-9a-fA-F]
54 
55 INTEGER         {SIGN}?({DIGIT}+|0x{HEXDIGIT}+)
56 
57 EXPONENT        [Ee]{SIGN}?{DIGIT}+
58 REAL            {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
59 
60 LETTER          [A-Za-z_\200-\377]
61 LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
62 
63 ID              {LETTER}{LETTER_OR_DIGIT}*
64 QUALIFIED_ID    {ID}"."{ID}
65 
66 UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
67 STRING          \'([^'\n]|\\.)*\'
68 ESCAPED_STRING  \"([^"\n]|\\.)*\"
69 %%
70 
71 \n              ConfigFileLineno++; return SLON_EOL;
72 [ \t\r]+        /* eat whitespace */
73 #.*             /* eat comment */
74 
75 {ID}            return SLON_ID;
76 {QUALIFIED_ID}  return SLON_QUALIFIED_ID;
77 {STRING}        return SLON_STRING;
78 {UNQUOTED_STRING} return SLON_UNQUOTED_STRING;
79 {ESCAPED_STRING}  return SLON_ESCAPED_STRING;
80 {INTEGER}       return SLON_INTEGER;
81 {REAL}          return SLON_REAL;
82 =               return SLON_EQUALS;
83 
84 .               return SLON_FERROR;
85 
86 %%
87 
88 struct name_value_pair
89 {
90         char       *name;
91         char       *value;
92         struct name_value_pair *next;
93 };
94 
95 /*
96  * Free a list of name/value pairs, including the names and the values
97  */
98 static void
99 free_name_value_list(struct name_value_pair * list)
100 {
101         struct name_value_pair *item;
102 
103         item = list;
104         while (item)
105         {
106                 struct name_value_pair *save;
107 
108                 save = item->next;
109                 free(item->name);
110                 free(item->value);
111                 free(item);
112                 item = save;
113         }
114 }
115 
116 void ProcessConfigFile(const char *filename)
117 {
118 	int token, parse_state;
119 	char *opt_name, *opt_value;
120 	int elevel;
121 	struct name_value_pair *item, *head, *tail;
122 	FILE * fp;
123 
124 	elevel = SLON_ERROR;
125 
126 	/*
127 	 * Open the conf file
128 	 */
129 	if (filename == NULL)
130 	{
131 		fp = fopen(CONFIG_FILENAME, "r");
132 	}
133 	else
134 	{
135 		fp = fopen(filename, "r");
136 	}
137 	if (!fp)
138 	{
139 		/* File not found is fine */
140 		if (errno != ENOENT)
141 		{
142 			slon_log(elevel,"could not open configuration file \"%s\"\n", filename);
143 
144 		}
145 		return;
146 	}
147 
148 	/* Ok we have the file, lets parse it */
149 
150 	yyin = fp;
151 	parse_state = 0;
152 	head = NULL;
153 	tail = head;
154 	opt_name = NULL;
155 	opt_value = opt_name;
156 
157 	while ( (token = yylex()) )
158 	{
159 		switch(parse_state)
160 		{
161 			case 0:
162 				if (token == SLON_EOL) /* empty line */
163 				{
164 					continue;
165 				}
166 				if (token != SLON_ID && token != SLON_QUALIFIED_ID)
167 				{
168 					goto parse_error;
169 				}
170 				opt_name = strdup(yytext);
171 				parse_state = 1;
172 				break;
173 			case 1:
174 				/* ignore equals sign */
175 				if (token == SLON_EQUALS)
176 				{
177 					token =  yylex();
178 				}
179 				if (token != SLON_ID && token != SLON_STRING && token != SLON_INTEGER && token != SLON_REAL && token != SLON_UNQUOTED_STRING && token != SLON_ESCAPED_STRING)
180 				{
181 					goto parse_error;
182 				}
183 				opt_value = strdup(yytext);
184 				if (token == SLON_STRING || token == SLON_ESCAPED_STRING)
185 				{
186 					memmove(opt_value,opt_value+1,strlen(opt_value)-1);
187 					opt_value[strlen(opt_value)-2]='\0';
188 					opt_value=SLON_scanstr(opt_value);
189 				}
190 				parse_state = 2;
191 				break;
192 			case 2:	/* OEL ? */
193 				if (token != SLON_EOL)
194 				{
195 					 goto parse_error;
196 				}
197 				item = malloc(sizeof *item);
198 				item->name = opt_name;
199 				item->value = opt_value;
200 
201 				if (strcmp(opt_name, "custom_variable_classes") == 0)
202 				{
203 					item->next = head;
204 					head = item;
205 					if (!tail)
206 					{
207 						tail = item;
208 					}
209 				}
210 				else
211 				{
212 					/* append to list */
213 					item->next = NULL;
214 					if (!head)
215 					{
216 						head = item;
217 					}
218 					else
219 					{
220 						tail->next = item;
221 					}
222 					tail = item;
223 				}
224 				parse_state = 0;
225 				break;
226 		}
227 	}
228 	/*
229 	 * If we encountered an EOF after we've already
230 	 * reached parse_state of 2, we already have a complete
231 	 * configuration line, it's just terminated with EOF
232 	 * instead of EOL. Store that config option.
233 	 */
234 	if(parse_state == 2)
235 	{
236 		item = malloc(sizeof *item);
237 		item->name = opt_name;
238 		item->value = opt_value;
239 		if (strcmp(opt_name, "custom_variable_classes") == 0)
240 		{
241 			item->next = head;
242 			head = item;
243 			if (!tail)
244 			{
245 				tail = item;
246 			}
247 		}
248 		else
249 		{
250 			/* append to list */
251 			item->next = NULL;
252 			if (!head)
253 			{
254 				head = item;
255 			}
256 			else
257 			{
258 				tail->next = item;
259 			}
260 			tail = item;
261 		}
262 		parse_state = 0;
263 	}
264 
265 	fclose(fp);
266 
267 	for(item = head; item; item=item->next)
268 	{
269 		set_config_option(item->name, item->value);
270 	}
271 
272 	cleanup_exit:
273 		free_name_value_list(head);
274 		return;
275 
276 	parse_error:
277 		fclose(fp);
278 		free_name_value_list(head);
279 		if (token == SLON_EOL)
280 		{
281 			slon_log(elevel, "syntax error in file \"%s\" line %u, near end of line\n", filename, ConfigFileLineno - 1);
282 		}
283 
284 		else
285 		{
286 			slon_log(elevel, "syntax error in file \"%s\" line %u, near end of line\n", filename, ConfigFileLineno - 1);
287 		}
288 }
289 
290 
291 
292 
293 
294 
295 
296 char *SLON_scanstr(char *s)
297 {
298         char       *newStr;
299         int                     len,
300                                 i,
301                                 j;
302 
303         if (s == NULL || s[0] == '\0')
304         {
305                 if (s != NULL)
306                         free(s);
307                 return strdup("");
308         }
309         len = strlen(s);
310 
311         newStr = malloc(len + 1);       /* string cannot get longer */
312         if (newStr == NULL)
313 		slon_log(SLON_FATAL, "out of memory\n");
314 
315         for (i = 0, j = 0; i < len; i++)
316         {
317                 if (s[i] == '\\')
318                 {
319                         i++;
320                         switch (s[i])
321                         {
322                                 case 'b':
323                                         newStr[j] = '\b';
324                                         break;
325                                 case 'f':
326                                         newStr[j] = '\f';
327                                         break;
328                                 case 'n':
329                                         newStr[j] = '\n';
330                                         break;
331                                 case 'r':
332                                         newStr[j] = '\r';
333                                         break;
334                                 case 't':
335                                         newStr[j] = '\t';
336                                         break;
337                                 case '0':
338                                 case '1':
339                                 case '2':
340                                 case '3':
341                                 case '4':
342                                 case '5':
343                                 case '6':
344                                 case '7':
345                                         {
346                                                 int                     k;
347                                                 long            octVal = 0;
348 
349                                                 for (k = 0;
350                                                          s[i + k] >= '0' && s[i
351 + k] <= '7' && k < 3;
352                                                          k++)
353                                                         octVal = (octVal << 3) +
354  (s[i + k] - '0');
355                                                 i += k - 1;
356                                                 newStr[j] = ((char) octVal);
357                                         }
358                                         break;
359                                 default:
360                                         newStr[j] = s[i];
361                                         break;
362                                 }
363                         }                                       /* switch */
364                 else
365                         newStr[j] = s[i];
366                 j++;
367         }
368         newStr[j] = '\0';
369         free(s);
370         return newStr;
371 }
372 
373 /*
374  * Local Variables:
375  *  tab-width: 4
376  *  c-indent-level: 4
377  *  c-basic-offset: 4
378  * End:
379  */
380