~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/utils/misc/guc-file.l

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

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