]> granicus.if.org Git - postgresql/blob - src/backend/utils/misc/guc-file.l
autovacuum setting false -> off, for consistency
[postgresql] / src / backend / utils / misc / guc-file.l
1 /* -*-pgsql-c-*- */
2 /*
3  * Scanner for the configuration file
4  *
5  * Copyright (c) 2000-2005, PostgreSQL Global Development Group
6  *
7  * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.31 2005/07/08 18:41:40 tgl Exp $
8  */
9
10 %{
11
12 #include "postgres.h"
13
14 #include <unistd.h>
15 #include <ctype.h>
16
17 #include "miscadmin.h"
18 #include "storage/fd.h"
19 #include "utils/guc.h"
20
21 /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
22 #undef fprintf
23 #define fprintf(file, fmt, msg)  ereport(ERROR, (errmsg_internal("%s", msg)))
24
25 static unsigned ConfigFileLineno;
26
27 enum {
28         GUC_ID = 1,
29         GUC_STRING = 2,
30         GUC_INTEGER = 3,
31         GUC_REAL = 4,
32         GUC_EQUALS = 5,
33         GUC_UNQUOTED_STRING = 6,
34         GUC_QUALIFIED_ID = 7,
35         GUC_EOL = 99,
36         GUC_ERROR = 100
37 };
38
39 /* prototype, so compiler is happy with our high warnings setting */
40 int GUC_yylex(void);
41 static char *GUC_scanstr(char *);
42 %}
43
44 %option 8bit
45 %option never-interactive
46 %option nodefault
47 %option nounput
48 %option noyywrap
49
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
69 %%
70
71 \n              ConfigFileLineno++; return GUC_EOL;
72 [ \t\r]+        /* eat whitespace */
73 #.*             /* eat comment (.* matches anything until newline) */
74
75 {ID}            return GUC_ID;
76 {QUALIFIED_ID}  return GUC_QUALIFIED_ID;
77 {STRING}        return GUC_STRING;
78 {UNQUOTED_STRING} return GUC_UNQUOTED_STRING;
79 {INTEGER}       return GUC_INTEGER;
80 {REAL}          return GUC_REAL;
81 =               return GUC_EQUALS;
82
83 .               return GUC_ERROR;
84
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 /*
97  * Free a list of name/value pairs, including the names and the values
98  */
99 static void
100 free_name_value_list(struct name_value_pair * list)
101 {
102         struct name_value_pair *item;
103
104         item = list;
105         while (item)
106         {
107                 struct name_value_pair *save;
108
109                 save = item->next;
110                 pfree(item->name);
111                 pfree(item->value);
112                 pfree(item);
113                 item = save;
114         }
115 }
116
117
118 /*
119  * Official function to read and process the configuration file. The
120  * parameter indicates in what context the file is being read --- either
121  * postmaster startup (including standalone-backend startup) or SIGHUP.
122  * All options mentioned in the configuration file are set to new values.
123  * If an error occurs, no values will be changed.
124  */
125 void
126 ProcessConfigFile(GucContext context)
127 {
128         int                     elevel;
129         int                     token, parse_state;
130         char       *opt_name, *opt_value;
131         struct name_value_pair *item, *head, *tail;
132         FILE       *fp;
133
134         Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
135
136         if (context == PGC_SIGHUP)
137         {
138                 /*
139                  * To avoid cluttering the log, only the postmaster bleats loudly
140                  * about problems with the config file.
141                  */
142                 elevel = IsUnderPostmaster ? DEBUG2 : LOG;
143         }
144         else
145                 elevel = ERROR;
146
147     fp = AllocateFile(ConfigFileName, "r");
148     if (!fp)
149     {
150                 ereport(elevel,
151                                 (errcode_for_file_access(),
152                                  errmsg("could not open configuration file \"%s\": %m",
153                                                 ConfigFileName)));
154                 return;
155     }
156
157         /*
158          * Parse
159          */
160         yyin = fp;
161     parse_state = 0;
162         head = tail = NULL;
163         opt_name = opt_value = NULL;
164         ConfigFileLineno = 1;
165
166     while ((token = yylex()))
167         {
168         switch(parse_state)
169         {
170             case 0: /* no previous input */
171                 if (token == GUC_EOL) /* empty line */
172                     continue;
173                 if (token != GUC_ID && token != GUC_QUALIFIED_ID)
174                     goto parse_error;
175                 opt_name = pstrdup(yytext);
176                 parse_state = 1;
177                 break;
178
179             case 1: /* found name */
180                 /* ignore equals sign */
181                 if (token == GUC_EQUALS)
182                     token = yylex();
183
184                 if (token != GUC_ID && token != GUC_STRING && 
185                                         token != GUC_INTEGER && 
186                                         token != GUC_REAL && 
187                                         token != GUC_UNQUOTED_STRING)
188                     goto parse_error;
189                 opt_value = pstrdup(yytext);
190                                 if (token == GUC_STRING)
191                                 {
192                                         /* remove the beginning and ending quote/apostrophe */
193                                         /* first: shift the whole thing down one character */
194                                         memmove(opt_value, opt_value+1, strlen(opt_value)-1);
195                                         /* second: null out the 2 characters we shifted */
196                                         opt_value[strlen(opt_value)-2] = '\0';
197                                         /* do the escape thing.  pfree()'s the pstrdup above */
198                                         opt_value = GUC_scanstr(opt_value);
199                                 }
200                 parse_state = 2;
201                 break;
202
203             case 2: /* now we'd like an end of line */
204                                 if (token != GUC_EOL)
205                                         goto parse_error;
206
207                                 if (strcmp(opt_name, "custom_variable_classes") == 0)
208                                 {
209                                         /*
210                                          * This variable must be processed first as it controls
211                                          * the validity of other variables; so apply immediately.
212                                          */
213                                         if (!set_config_option(opt_name, opt_value, context,
214                                                                                    PGC_S_FILE, false, true))
215                                         {
216                                                 pfree(opt_name);
217                                                 pfree(opt_value);
218                                                 FreeFile(fp);
219                                                 goto cleanup_exit;
220                                         }
221                                         pfree(opt_name);
222                                         pfree(opt_value);
223                                 }
224                                 else
225                                 {
226                                         /* append to list */
227                                         item = palloc(sizeof *item);
228                                         item->name = opt_name;
229                                         item->value = opt_value;
230                                         item->next = NULL;
231                                         if (!head)
232                                                 head = item;
233                                         else
234                                                 tail->next = item;
235                                         tail = item;
236                                 }
237
238                 parse_state = 0;
239                 break;
240         }
241         }
242
243         FreeFile(fp);
244
245         /*
246          * Check if all options are valid
247          */
248     for(item = head; item; item=item->next)
249         {
250                 if (!set_config_option(item->name, item->value, context,
251                                                            PGC_S_FILE, false, false))
252                         goto cleanup_exit;
253         }
254
255     /* If we got here all the options parsed okay, so apply them. */
256         for(item = head; item; item=item->next)
257         {
258                 set_config_option(item->name, item->value, context,
259                                                   PGC_S_FILE, false, true);
260         }
261
262  cleanup_exit:
263         free_name_value_list(head);
264         return;
265
266  parse_error:
267         FreeFile(fp);
268         free_name_value_list(head);
269         if (token == GUC_EOL)
270                 ereport(elevel,
271                                 (errcode(ERRCODE_SYNTAX_ERROR),
272                                  errmsg("syntax error in file \"%s\" line %u, near end of line",
273                                                 ConfigFileName, ConfigFileLineno - 1)));
274         else
275                 ereport(elevel,
276                                 (errcode(ERRCODE_SYNTAX_ERROR),
277                                  errmsg("syntax error in file \"%s\" line %u, near token \"%s\"", 
278                                                 ConfigFileName, ConfigFileLineno, yytext)));
279 }
280
281
282
283 /* ----------------
284  *              scanstr
285  *
286  * if the string passed in has escaped codes, map the escape codes to actual
287  * chars
288  *
289  * the string returned is palloc'd and should eventually be pfree'd by the
290  * caller; also we assume we should pfree the input string.
291  * ----------------
292  */
293
294 static char *
295 GUC_scanstr(char *s)
296 {
297         char       *newStr;
298         int                     len,
299                                 i,
300                                 j;
301
302         if (s == NULL || s[0] == '\0')
303         {
304                 if (s != NULL)
305                         pfree(s);
306                 return pstrdup("");
307         }
308         len = strlen(s);
309
310         newStr = palloc(len + 1);       /* string cannot get longer */
311
312         for (i = 0, j = 0; i < len; i++)
313         {
314                 if (s[i] == '\\')
315                 {
316                         i++;
317                         switch (s[i])
318                         {
319                                 case 'b':
320                                         newStr[j] = '\b';
321                                         break;
322                                 case 'f':
323                                         newStr[j] = '\f';
324                                         break;
325                                 case 'n':
326                                         newStr[j] = '\n';
327                                         break;
328                                 case 'r':
329                                         newStr[j] = '\r';
330                                         break;
331                                 case 't':
332                                         newStr[j] = '\t';
333                                         break;
334                                 case '0':
335                                 case '1':
336                                 case '2':
337                                 case '3':
338                                 case '4':
339                                 case '5':
340                                 case '6':
341                                 case '7':
342                                         {
343                                                 int                     k;
344                                                 long            octVal = 0;
345
346                                                 for (k = 0;
347                                                          s[i + k] >= '0' && s[i + k] <= '7' && k < 3;
348                                                          k++)
349                                                         octVal = (octVal << 3) + (s[i + k] - '0');
350                                                 i += k - 1;
351                                                 newStr[j] = ((char) octVal);
352                                         }
353                                         break;
354                                 default:
355                                         newStr[j] = s[i];
356                                         break;
357                                 }
358                         }                                       /* switch */
359                 else
360                         newStr[j] = s[i];
361                 j++;
362         }
363         newStr[j] = '\0';
364         pfree(s);
365         return newStr;
366 }