The attached patch is a revised version of the patch I sent in before:

http://archives.postgresql.org/pgsql-patches/2005-12/msg00018.php

The old version did not apply to current CVS anymore and the new one
now also works with flex 2.5.4.

The patch works as proposed by Tom Lane in:

http://archives.postgresql.org/pgsql-patches/2004-06/msg00030.php
(see lower part)


Joachim

diff -cr cvs/pgsql/doc/src/sgml/config.sgml 
cvs.build/pgsql/doc/src/sgml/config.sgml
*** cvs/pgsql/doc/src/sgml/config.sgml  2006-01-12 08:08:54.000000000 +0100
--- cvs.build/pgsql/doc/src/sgml/config.sgml    2006-01-20 14:23:39.000000000 
+0100
***************
*** 71,76 ****
--- 71,78 ----
  <programlisting>
  postmaster -c log_connections=yes -c log_destination='syslog'
  </programlisting>
+     (The special option <varname>include</varname> however can not be 
specified
+     on the command line).
      Command-line options override any conflicting settings in
      <filename>postgresql.conf</filename>.  Note that this means you won't
      be able to change the value on-the-fly by editing
***************
*** 224,229 ****
--- 226,248 ----
         </para>
        </listitem>
       </varlistentry>
+ 
+      <varlistentry id="guc-include" xreflabel="include">
+       <term><varname>include</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>include</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies another configuration file that is read in by the starting
+         <application>postgres</> process. You can use this option multiple
+         times and you can also read in configuration files recursively.
+         This option can not be specified on the command line and can not be 
set
+         nor inspected with the <xref linkend="SQL-SET" 
endterm="SQL-SET-title">
+         or <xref linkend="SQL-SHOW" endterm="SQL-SHOW-title"> commands.
+        </para>
+       </listitem>
+      </varlistentry>
       </variablelist>
  
       <para>
***************
*** 260,268 ****
       </para>
  
       <para>
!       When setting any of these options, a relative path will be interpreted
        with respect to the directory in which the <command>postmaster</command>
!       is started.
       </para>
     </sect1>
  
--- 279,290 ----
       </para>
  
       <para>
!       When setting any of these options except for the
!       <varname>include</varname> option, a relative path will be interpreted
        with respect to the directory in which the <command>postmaster</command>
!       is started. For the <varname>include</varname> option, a relative path
!       will always be relative to the path of the file that contained the
!       <varname>include</varname> option.
       </para>
     </sect1>
  
diff -cr cvs/pgsql/src/backend/utils/misc/guc-file.l 
cvs.build/pgsql/src/backend/utils/misc/guc-file.l
*** cvs/pgsql/src/backend/utils/misc/guc-file.l 2006-01-02 20:55:25.000000000 
+0100
--- cvs.build/pgsql/src/backend/utils/misc/guc-file.l   2006-01-20 
13:53:27.000000000 +0100
***************
*** 22,27 ****
--- 22,35 ----
  #undef fprintf
  #define fprintf(file, fmt, msg)  ereport(ERROR, (errmsg_internal("%s", msg)))
  
+ /* include configuration files to a maximal recursion depth of 10 */
+ #define MAX_INCLUDE_FILE_DEPTH  10
+ 
+ /* we have to manually handle buffer stack management (newer versions of flex
+  * >= 2.5.31 can handle this via calls to push/pop buffer functions) */
+ static YY_BUFFER_STATE GUC_include_stack[MAX_INCLUDE_FILE_DEPTH];
+ static int GUC_include_stack_counter = 0;
+ 
  static unsigned ConfigFileLineno;
  
  enum {
***************
*** 115,164 ****
  }
  
  
! /*
!  * Official function to read and process the configuration file. The
!  * parameter indicates in what context the file is being read --- either
!  * postmaster startup (including standalone-backend startup) or SIGHUP.
!  * All options mentioned in the configuration file are set to new values.
!  * If an error occurs, no values will be changed.
   */
! void
! ProcessConfigFile(GucContext context)
  {
!       int                     elevel;
!       int                     token;
!       char       *opt_name, *opt_value;
!       struct name_value_pair *item, *head, *tail;
!       FILE       *fp;
! 
!       Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
  
!       if (context == PGC_SIGHUP)
        {
!               /*
!                * To avoid cluttering the log, only the postmaster bleats 
loudly
!                * about problems with the config file.
!                */
!               elevel = IsUnderPostmaster ? DEBUG2 : LOG;
        }
        else
!               elevel = ERROR;
  
!       fp = AllocateFile(ConfigFileName, "r");
        if (!fp)
        {
                ereport(elevel,
                                (errcode_for_file_access(),
                                 errmsg("could not open configuration file 
\"%s\": %m",
!                                               ConfigFileName)));
!               return;
        }
  
!       /*
!        * Parse
!        */
!       yyrestart(fp);
!       head = tail = NULL;
        opt_name = opt_value = NULL;
        ConfigFileLineno = 1;
  
--- 123,220 ----
  }
  
  
! /* Function that calls itself recursively for each configuration file that 
gets
!  * included via the "include = 'file.conf'" directive.
!  * The first time it gets called by ProcessConfigFile() 
!  * See below for notes on the parameters ConfigFileName and BasePath.
!  *
!  * The function returns
!  *    0  if OK
!  *   -1  on error
   */
! static int
! ParseConfigFile(char* ConfigFileName,
!                               char* BasePath,
!                               int depth,
!                               GucContext context, int elevel,
!                               struct name_value_pair **head_p,
!                               struct name_value_pair **tail_p)
  {
!       struct name_value_pair *item;
!       YY_BUFFER_STATE                 lex_buffer;
!       int                                             token;
!       int                                             LocalConfigFileLineno;
!       char                               *opt_name;
!       char                               *opt_value;
!       char                               *ConfigFileNameCopy;
!       char                               *NewBasePath;
!       char                               *p;
!       FILE                               *fp;
! 
!       /* when the function gets called for the first time by 
ProcessConfigFile,
!        * we get a BasePath == NULL but the ConfigFileName is absolute in every
!        * case (because the filename the user specified is transformed by
!        * make_absolute_path()). If we encounter another include = '...' in the
!        * configuration file however we can be sure that BasePath has been set 
to
!        * the path of the including file. */
  
!       if (!is_absolute_path(ConfigFileName))
        {
!               /* If the path is not absolute, make it absolute by prepending 
the
!                * BasePath */
!               int length;
!               Assert(BasePath != NULL);
!               length = strlen(BasePath)
!                          + 1
!                          + strlen(ConfigFileName)
!                          + 1;
!               ConfigFileNameCopy = (char*) palloc(length);
!               strcpy(ConfigFileNameCopy, BasePath);
!               strcat(ConfigFileNameCopy, "/");
!               strcat(ConfigFileNameCopy, ConfigFileName);
        }
        else
!               ConfigFileNameCopy = pstrdup(ConfigFileName);
! 
!       /* Calculate the new base path, i.e. the path where the new config file 
is
!        * in. We have an absolute path to the configuration file we're reading
!        * already (it might be /usr/local/etc/../etc/include.conf however but 
it
!        * doesn't matter).
!        * What we do is basically just copying over the whole and then 
stripping
!        * off everything behind the last slash. */
! 
!       NewBasePath = pstrdup(ConfigFileNameCopy);
!       p = NewBasePath + strlen(NewBasePath);
!       while (*p != '/' && p > NewBasePath)
!               *p-- = '\0';
! 
!       /* strip off the slash as well */
!       if (*p == '/')
!               *p = '\0';
  
!       if (depth > MAX_INCLUDE_FILE_DEPTH)
!       {
!               ereport(elevel,
!                               (errcode_for_file_access(),
!                                errmsg("could not open configuration file 
\"%s\": "
!                                               "maximal inclusion depth 
reached",
!                                               ConfigFileNameCopy)));
!               return -1;
!       }
! 
!       fp = AllocateFile(ConfigFileNameCopy, "r");
        if (!fp)
        {
                ereport(elevel,
                                (errcode_for_file_access(),
                                 errmsg("could not open configuration file 
\"%s\": %m",
!                                               ConfigFileNameCopy)));
!               return -1;
        }
  
!       lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
!       yy_switch_to_buffer(lex_buffer);
! 
        opt_name = opt_value = NULL;
        ConfigFileLineno = 1;
  
***************
*** 207,218 ****
                        {
                                pfree(opt_name);
                                pfree(opt_value);
                                FreeFile(fp);
!                               goto cleanup_exit;
                        }
                        pfree(opt_name);
                        pfree(opt_value);
                }
                else
                {
                        /* append to list */
--- 263,299 ----
                        {
                                pfree(opt_name);
                                pfree(opt_value);
+                               pfree(NewBasePath);
+                               pfree(ConfigFileNameCopy);
                                FreeFile(fp);
!                               free_name_value_list(*head_p);
!                               return 0;
                        }
                        pfree(opt_name);
                        pfree(opt_value);
                }
+               else if (strcmp(opt_name, "include") == 0)
+               {
+                       LocalConfigFileLineno = ConfigFileLineno;
+                       GUC_include_stack[GUC_include_stack_counter++] = 
lex_buffer;
+                       if (ParseConfigFile(opt_value,
+                                                               NewBasePath,
+                                                               depth + 1,
+                                                               context, elevel,
+                                                               head_p, tail_p) 
!= 0)
+                       {
+                               yy_delete_buffer(lex_buffer);
+                               pfree(NewBasePath);
+                               pfree(ConfigFileNameCopy);
+                               FreeFile(fp);
+                               return -1;
+                       }
+                       
yy_delete_buffer(GUC_include_stack[GUC_include_stack_counter]);
+                       GUC_include_stack_counter--;
+                       lex_buffer = 
GUC_include_stack[GUC_include_stack_counter];
+                       yy_switch_to_buffer(lex_buffer);
+                       ConfigFileLineno = LocalConfigFileLineno;
+               }
                else
                {
                        /* append to list */
***************
*** 220,230 ****
                        item->name = opt_name;
                        item->value = opt_value;
                        item->next = NULL;
!                       if (!head)
!                               head = item;
                        else
!                               tail->next = item;
!                       tail = item;
                }
  
                /* break out of loop if read EOF, else loop for next line */
--- 301,311 ----
                        item->name = opt_name;
                        item->value = opt_value;
                        item->next = NULL;
!                       if (!(*head_p))
!                               *head_p = item;
                        else
!                               (*tail_p)->next = item;
!                       (*tail_p) = item;
                }
  
                /* break out of loop if read EOF, else loop for next line */
***************
*** 232,273 ****
                        break;
        }
  
        FreeFile(fp);
  
!       /*
!        * Check if all options are valid
!        */
!       for(item = head; item; item=item->next)
!       {
!               if (!set_config_option(item->name, item->value, context,
!                                                          PGC_S_FILE, false, 
false))
!                       goto cleanup_exit;
!       }
! 
!       /* If we got here all the options parsed okay, so apply them. */
!       for(item = head; item; item=item->next)
!       {
!               set_config_option(item->name, item->value, context,
!                                                 PGC_S_FILE, false, true);
!       }
! 
!  cleanup_exit:
!       free_name_value_list(head);
!       return;
  
   parse_error:
        FreeFile(fp);
!       free_name_value_list(head);
        if (token == GUC_EOL || token == 0)
                ereport(elevel,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("syntax error in file \"%s\" line %u, 
near end of line",
!                                               ConfigFileName, 
ConfigFileLineno - 1)));
        else
                ereport(elevel,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("syntax error in file \"%s\" line %u, 
near token \"%s\"", 
!                                               ConfigFileName, 
ConfigFileLineno, yytext)));
  }
  
  
--- 313,397 ----
                        break;
        }
  
+       pfree(NewBasePath);
+       pfree(ConfigFileNameCopy);
        FreeFile(fp);
  
!       return 0;
  
   parse_error:
        FreeFile(fp);
!       free_name_value_list(*head_p);
        if (token == GUC_EOL || token == 0)
                ereport(elevel,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("syntax error in file \"%s\" line %u, 
near end of line",
!                                               ConfigFileNameCopy, 
ConfigFileLineno - 1)));
        else
                ereport(elevel,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("syntax error in file \"%s\" line %u, 
near token \"%s\"", 
!                                               ConfigFileNameCopy, 
ConfigFileLineno, yytext)));
! 
!       yy_delete_buffer(lex_buffer);
!       pfree(NewBasePath);
!       pfree(ConfigFileNameCopy);
!       return -1;
! }
! 
! /*
!  * Official function to read and process the configuration file. The
!  * parameter indicates in what context the file is being read --- either
!  * postmaster startup (including standalone-backend startup) or SIGHUP.
!  * All options mentioned in the configuration file are set to new values.
!  * If an error occurs, no values will be changed.
!  */
! void
! ProcessConfigFile(GucContext context)
! {
!       int                     elevel;
!       struct          name_value_pair *item, *head, *tail;
! 
!       Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
! 
!       if (context == PGC_SIGHUP)
!       {
!               /*
!                * To avoid cluttering the log, only the postmaster bleats 
loudly
!                * about problems with the config file.
!                */
!               elevel = IsUnderPostmaster ? DEBUG2 : LOG;
!       }
!       else
!               elevel = ERROR;
! 
!       /*
!        * Parse
!        */
!       head = tail = NULL;
!       if (ParseConfigFile(ConfigFileName, NULL, 0, context,
!                                               elevel, &head, &tail) == 0)
!       {
!               /*
!                * Check if all options are valid
!                */
!               for(item = head; item; item=item->next)
!               {
!                       if (!set_config_option(item->name, item->value, context,
!                                                                  PGC_S_FILE, 
false, false))
!                       {
!                               free_name_value_list(head);
!                               return;
!                       }
!               }
! 
!               /* If we got here all the options parsed okay, so apply them. */
!               for(item = head; item; item=item->next)
!               {
!                       set_config_option(item->name, item->value, context,
!                                                         PGC_S_FILE, false, 
true);
!               }
!       }
  }
  
  
---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

Reply via email to