Drizzled Public API Documentation

default.cc

00001 /* Copyright (C) 2000-2003 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 /****************************************************************************
00017  Add all options from files named "group".cnf from the default_directories
00018  before the command line arguments.
00019  On Windows defaults will also search in the Windows directory for a file
00020  called 'group'.ini
00021  As long as the program uses the last argument for conflicting
00022  options one only have to add a call to "load_defaults" to enable
00023  use of default values.
00024  pre- and end 'blank space' are removed from options and values. The
00025  following escape sequences are recognized in values:  \b \t \n \r \\
00026 
00027  The following arguments are handled automaticly;  If used, they must be
00028  first argument on the command line!
00029  --no-defaults  ; no options are read.
00030  --defaults-file=full-path-to-default-file  ; Only this file will be read.
00031  --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
00032  --defaults-group-suffix  ; Also read groups with concat(group, suffix)
00033  --print-defaults   ; Print the modified command line and exit
00034 ****************************************************************************/
00035 
00036 #include <config.h>
00037 
00038 #include <drizzled/internal/my_sys.h>
00039 #include <drizzled/internal/m_string.h>
00040 #include <drizzled/charset_info.h>
00041 #include <drizzled/typelib.h>
00042 #include <drizzled/configmake.h>
00043 #include <drizzled/gettext.h>
00044 #include <drizzled/dynamic_array.h>
00045 #include <drizzled/cached_directory.h>
00046 
00047 #ifdef HAVE_SYS_STAT_H
00048 # include <sys/stat.h>
00049 #endif
00050 
00051 #include <cstdio>
00052 #include <algorithm>
00053 
00054 using namespace std;
00055 
00056 namespace drizzled
00057 {
00058 namespace internal
00059 {
00060 
00061 const char *my_defaults_file=0;
00062 const char *my_defaults_group_suffix=0;
00063 char *my_defaults_extra_file=0;
00064 
00065 /* Which directories are searched for options (and in which order) */
00066 
00067 #define MAX_DEFAULT_DIRS 6
00068 const char *default_directories[MAX_DEFAULT_DIRS + 1];
00069 
00070 static const char *f_extensions[]= { ".cnf", 0 };
00071 
00072 int handle_default_option(void *in_ctx, const char *group_name,
00073                           const char *option);
00074 
00075 /*
00076    This structure defines the context that we pass to callback
00077    function 'handle_default_option' used in search_default_file
00078    to process each option. This context is used if search_default_file
00079    was called from load_defaults.
00080 */
00081 
00082 struct handle_option_ctx
00083 {
00084    memory::Root *alloc;
00085    DYNAMIC_ARRAY *args;
00086    TYPELIB *group;
00087 };
00088 
00089 static int search_default_file(Process_option_func func, void *func_ctx,
00090              const char *dir, const char *config_file);
00091 static int search_default_file_with_ext(Process_option_func func,
00092                                         void *func_ctx,
00093           const char *dir, const char *ext,
00094           const char *config_file, int recursion_level);
00095 
00096 
00097 
00109 static void init_default_directories(void);
00110 
00111 
00112 static char *remove_end_comment(char *ptr);
00113 
00114 
00115 /*
00116   Process config files in default directories.
00117 
00118   SYNOPSIS
00119   my_search_option_files()
00120   conf_file                   Basename for configuration file to search for.
00121                               If this is a path, then only this file is read.
00122   argc                        Pointer to argc of original program
00123   argv                        Pointer to argv of original program
00124   args_used                   Pointer to variable for storing the number of
00125                               arguments used.
00126   func                        Pointer to the function to process options
00127   func_ctx                    It's context. Usually it is the structure to
00128                               store additional options.
00129   DESCRIPTION
00130     Process the default options from argc & argv
00131     Read through each found config file looks and calls 'func' to process
00132     each option.
00133 
00134   NOTES
00135     --defaults-group-suffix is only processed if we are called from
00136     load_defaults().
00137 
00138 
00139   RETURN
00140     0  ok
00141     1  given cinf_file doesn't exist
00142 
00143     The global variable 'my_defaults_group_suffix' is updated with value for
00144     --defaults_group_suffix
00145 */
00146 
00147 int my_search_option_files(const char *conf_file, int *argc, char ***argv,
00148                            uint32_t *args_used, Process_option_func func,
00149                            void *func_ctx)
00150 {
00151   const char **dirs, *forced_default_file, *forced_extra_defaults;
00152   int error= 0;
00153 
00154   /* Check if we want to force the use a specific default file */
00155   *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
00156                                     (char **) &forced_default_file,
00157                                     (char **) &forced_extra_defaults,
00158                                     (char **) &my_defaults_group_suffix);
00159 
00160   if (! my_defaults_group_suffix)
00161     my_defaults_group_suffix= getenv("DRIZZLE_GROUP_SUFFIX");
00162 
00163   if (forced_extra_defaults)
00164     my_defaults_extra_file= (char *) forced_extra_defaults;
00165 
00166   if (forced_default_file)
00167     my_defaults_file= forced_default_file;
00168 
00169   /*
00170     We can only handle 'defaults-group-suffix' if we are called from
00171     load_defaults() as otherwise we can't know the type of 'func_ctx'
00172   */
00173 
00174   if (my_defaults_group_suffix && (func == handle_default_option))
00175   {
00176     /* Handle --defaults-group-suffix= */
00177     uint32_t i;
00178     const char **extra_groups;
00179     const size_t instance_len= strlen(my_defaults_group_suffix);
00180     struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
00181     char *ptr;
00182     TYPELIB *group= ctx->group;
00183 
00184     if (!(extra_groups=
00185     (const char**)ctx->alloc->alloc_root(
00186                                    (2*group->count+1)*sizeof(char*))))
00187       goto err;
00188 
00189     for (i= 0; i < group->count; i++)
00190     {
00191       size_t len;
00192       extra_groups[i]= group->type_names[i]; 
00194       len= strlen(extra_groups[i]);
00195       if (!(ptr= (char *)ctx->alloc->alloc_root( len+instance_len+1)))
00196   goto err;
00197 
00198       extra_groups[i+group->count]= ptr;
00199 
00201       memcpy(ptr, extra_groups[i], len);
00202       memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
00203     }
00204 
00205     group->count*= 2;
00206     group->type_names= extra_groups;
00207     group->type_names[group->count]= 0;
00208   }
00209 
00210   if (forced_default_file)
00211   {
00212     if ((error= search_default_file_with_ext(func, func_ctx, "", "",
00213                                              forced_default_file, 0)) < 0)
00214       goto err;
00215     if (error > 0)
00216     {
00217       fprintf(stderr, "Could not open required defaults file: %s\n",
00218               forced_default_file);
00219       goto err;
00220     }
00221   }
00222   else if (dirname_length(conf_file))
00223   {
00224     if ((error= search_default_file(func, func_ctx, NULL, conf_file)) < 0)
00225       goto err;
00226   }
00227   else
00228   {
00229     for (dirs= default_directories ; *dirs; dirs++)
00230     {
00231       if (**dirs)
00232       {
00233   if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
00234     goto err;
00235       }
00236       else if (my_defaults_extra_file)
00237       {
00238         if ((error= search_default_file_with_ext(func, func_ctx, "", "",
00239                                                 my_defaults_extra_file, 0)) < 0)
00240     goto err;       /* Fatal error */
00241         if (error > 0)
00242         {
00243           fprintf(stderr, "Could not open required defaults file: %s\n",
00244                   my_defaults_extra_file);
00245           goto err;
00246         }
00247       }
00248     }
00249   }
00250 
00251   return(error);
00252 
00253 err:
00254   fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
00255   exit(1);
00256 }
00257 
00258 
00259 /*
00260   The option handler for load_defaults.
00261 
00262   SYNOPSIS
00263     handle_deault_option()
00264     in_ctx                  Handler context. In this case it is a
00265                             handle_option_ctx structure.
00266     group_name              The name of the group the option belongs to.
00267     option                  The very option to be processed. It is already
00268                             prepared to be used in argv (has -- prefix). If it
00269                             is NULL, we are handling a new group (section).
00270 
00271   DESCRIPTION
00272     This handler checks whether a group is one of the listed and adds an option
00273     to the array if yes. Some other handler can record, for instance, all
00274     groups and their options, not knowing in advance the names and amount of
00275     groups.
00276 
00277   RETURN
00278     0 - ok
00279     1 - error occured
00280 */
00281 
00282 int handle_default_option(void *in_ctx, const char *group_name,
00283                           const char *option)
00284 {
00285   char *tmp;
00286   struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
00287 
00288   if (!option)
00289     return 0;
00290 
00291   if (ctx->group->find_type(const_cast<char*>(group_name), 3))
00292   {
00293     if (!(tmp= (char *)ctx->alloc->alloc_root(strlen(option) + 1)))
00294       return 1;
00295     ctx->args->push_back(&tmp);
00296     strcpy(tmp, option);
00297   }
00298 
00299   return 0;
00300 }
00301 
00302 
00303 /*
00304   Gets options from the command line
00305 
00306   SYNOPSIS
00307     get_defaults_options()
00308     argc      Pointer to argc of original program
00309     argv      Pointer to argv of original program
00310     defaults                    --defaults-file option
00311     extra_defaults              --defaults-extra-file option
00312 
00313   RETURN
00314     # Number of arguments used from *argv
00315       defaults and extra_defaults will be set to option of the appropriate
00316       items of argv array, or to NULL if there are no such options
00317 */
00318 
00319 int get_defaults_options(int argc, char **argv,
00320                          char **defaults,
00321                          char **extra_defaults,
00322                          char **group_suffix)
00323 {
00324   int org_argc= argc, prev_argc= 0;
00325   *defaults= *extra_defaults= *group_suffix= 0;
00326 
00327   const std::string DEFAULTS_FILE("--defaults-file=");
00328   const std::string DEFAULTS_EXTRA_FILE("--defaults-extra-file=");
00329   const std::string DEFAULTS_GROUP_SUFFIX("--defaults-group-suffix=");
00330 
00331   while (argc >= 2 && argc != prev_argc)
00332   {
00333     /* Skip program name or previously handled argument */
00334     argv++;
00335     prev_argc= argc;                            /* To check if we found */
00336     if (!*defaults && (strncmp(*argv,
00337                                DEFAULTS_FILE.c_str(),
00338                                DEFAULTS_FILE.size()) == 0))
00339     {
00340       *defaults= *argv + DEFAULTS_FILE.size();
00341        argc--;
00342        continue;
00343     }
00344     if (!*extra_defaults && (strncmp(*argv, 
00345                                      DEFAULTS_EXTRA_FILE.c_str(),
00346                                      DEFAULTS_EXTRA_FILE.size()) == 0))
00347     {
00348       *extra_defaults= *argv + DEFAULTS_EXTRA_FILE.size();
00349       argc--;
00350       continue;
00351     }
00352     if (!*group_suffix && (strncmp(*argv, 
00353                                    DEFAULTS_GROUP_SUFFIX.c_str(),
00354                                    DEFAULTS_GROUP_SUFFIX.size()) == 0))
00355 
00356     {
00357       *group_suffix= *argv + DEFAULTS_GROUP_SUFFIX.size();
00358       argc--;
00359       continue;
00360     }
00361   }
00362   return org_argc - argc;
00363 }
00364 
00365 
00366 /*
00367   Read options from configurations files
00368 
00369   SYNOPSIS
00370     load_defaults()
00371     conf_file     Basename for configuration file to search for.
00372             If this is a path, then only this file is read.
00373     groups      Which [group] entrys to read.
00374         Points to an null terminated array of pointers
00375     argc      Pointer to argc of original program
00376     argv      Pointer to argv of original program
00377 
00378   IMPLEMENTATION
00379 
00380    Read options from configuration files and put them BEFORE the arguments
00381    that are already in argc and argv.  This way the calling program can
00382    easily command line options override options in configuration files
00383 
00384    NOTES
00385     In case of fatal error, the function will print a warning and do
00386     exit(1)
00387 
00388     To free used memory one should call free_defaults() with the argument
00389     that was put in *argv
00390 
00391    RETURN
00392      0  ok
00393      1  The given conf_file didn't exists
00394 */
00395 
00396 
00397 int load_defaults(const char *conf_file, const char **groups,
00398                   int *argc, char ***argv)
00399 {
00400   DYNAMIC_ARRAY args;
00401   TYPELIB group;
00402   uint32_t args_used= 0;
00403   int error= 0;
00404   memory::Root alloc(512);
00405   char *ptr,**res;
00406   struct handle_option_ctx ctx;
00407 
00408   init_default_directories();
00409   /*
00410     Check if the user doesn't want any default option processing
00411     --no-defaults is always the first option
00412   */
00413   if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
00414   {
00415     /* remove the --no-defaults argument and return only the other arguments */
00416     uint32_t i;
00417     if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (*argc + 1)*sizeof(char*))))
00418       goto err;
00419     res= (char**) (ptr+sizeof(alloc));
00420     memset(res,0,(*argc + 1));
00421     res[0]= **argv;       /* Copy program name */
00422     for (i=2 ; i < (uint32_t) *argc ; i++)
00423       res[i-1]=argv[0][i];
00424     res[i-1]=0;         /* End pointer */
00425     (*argc)--;
00426     *argv=res;
00427     *(memory::Root*) ptr= alloc;      /* Save alloc root for free */
00428     return(0);
00429   }
00430 
00431   group.count=0;
00432   group.name= "defaults";
00433   group.type_names= groups;
00434 
00435   for (; *groups ; groups++)
00436     group.count++;
00437 
00438   if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
00439     goto err;
00440 
00441   ctx.alloc= &alloc;
00442   ctx.args= &args;
00443   ctx.group= &group;
00444 
00445   error= my_search_option_files(conf_file, argc, argv, &args_used,
00446                                 handle_default_option, (void *) &ctx);
00447   /*
00448     Here error contains <> 0 only if we have a fully specified conf_file
00449     or a forced default file
00450   */
00451   if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (args.size() + *argc +1) *sizeof(char*))))
00452     goto err;
00453   res= (char**) (ptr+sizeof(alloc));
00454 
00455   /* copy name + found arguments + command line arguments to new array */
00456   res[0]= argv[0][0];  /* Name MUST be set, even by embedded library */
00457   memcpy(res+1, args.buffer, args.size()*sizeof(char*));
00458   /* Skip --defaults-xxx options */
00459   (*argc)-= args_used;
00460   (*argv)+= args_used;
00461 
00462   /*
00463     Check if we wan't to see the new argument list
00464     This options must always be the last of the default options
00465   */
00466   if (*argc)
00467     memcpy(res+1+args.size(), *argv + 1, (*argc-1)*sizeof(char*));
00468   res[args.size()+ *argc]=0;      /* last null */
00469 
00470   (*argc)+=int(args.size());
00471   *argv= static_cast<char**>(res);
00472   *(memory::Root*) ptr= alloc;      /* Save alloc root for free */
00473   delete_dynamic(&args);
00474 
00475   return(error);
00476 
00477  err:
00478   fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
00479   exit(1);
00480 }
00481 
00482 
00483 void free_defaults(char **argv)
00484 {
00485   memory::Root ptr;
00486   memcpy(&ptr, (char*) argv - sizeof(ptr), sizeof(ptr));
00487   ptr.free_root(MYF(0));
00488 }
00489 
00490 
00491 static int search_default_file(Process_option_func opt_handler,
00492                                void *handler_ctx,
00493              const char *dir,
00494              const char *config_file)
00495 {
00496   char **ext;
00497   const char *empty_list[]= { "", 0 };
00498   bool have_ext= fn_ext(config_file)[0] != 0;
00499   const char **exts_to_use= have_ext ? empty_list : f_extensions;
00500 
00501   for (ext= (char**) exts_to_use; *ext; ext++)
00502   {
00503     int error;
00504     if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
00505                                              dir, *ext,
00506                config_file, 0)) < 0)
00507       return error;
00508   }
00509   return 0;
00510 }
00511 
00512 
00513 /*
00514   Skip over keyword and get argument after keyword
00515 
00516   SYNOPSIS
00517    get_argument()
00518    keyword    Include directive keyword
00519    kwlen    Length of keyword
00520    ptr      Pointer to the keword in the line under process
00521    line     line number
00522 
00523   RETURN
00524    0  error
00525    #  Returns pointer to the argument after the keyword.
00526 */
00527 
00528 static char *get_argument(const char *keyword, size_t kwlen,
00529                           char *ptr, char *name, uint32_t line)
00530 {
00531   char *end;
00532 
00533   /* Skip over "include / includedir keyword" and following whitespace */
00534 
00535   for (ptr+= kwlen - 1;
00536        my_isspace(&my_charset_utf8_general_ci, ptr[0]);
00537        ptr++)
00538   {}
00539 
00540   /*
00541     Trim trailing whitespace from directory name
00542     The -1 below is for the newline added by fgets()
00543     Note that my_isspace() is true for \r and \n
00544   */
00545   for (end= ptr + strlen(ptr) - 1;
00546        my_isspace(&my_charset_utf8_general_ci, *(end - 1));
00547        end--)
00548   {}
00549   end[0]= 0;                                    /* Cut off end space */
00550 
00551   /* Print error msg if there is nothing after !include* directive */
00552   if (end <= ptr)
00553   {
00554     fprintf(stderr,
00555       "error: Wrong '!%s' directive in config file: %s at line %d\n",
00556       keyword, name, line);
00557     return 0;
00558   }
00559   return ptr;
00560 }
00561 
00562 
00563 /*
00564   Open a configuration file (if exists) and read given options from it
00565 
00566   SYNOPSIS
00567     search_default_file_with_ext()
00568     opt_handler                 Option handler function. It is used to process
00569                                 every separate option.
00570     handler_ctx                 Pointer to the structure to store actual
00571                                 parameters of the function.
00572     dir       directory to read
00573     ext       Extension for configuration file
00574     config_file                 Name of configuration file
00575     group     groups to read
00576     recursion_level             the level of recursion, got while processing
00577                                 "!include" or "!includedir"
00578 
00579   RETURN
00580     0   Success
00581     -1  Fatal error, abort
00582      1  File not found (Warning)
00583 */
00584 
00585 static int search_default_file_with_ext(Process_option_func opt_handler,
00586                                         void *handler_ctx,
00587                                         const char *dir,
00588                                         const char *ext,
00589                                         const char *config_file,
00590                                         int recursion_level)
00591 {
00592   char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
00593   char *value, option[4096], tmp[FN_REFLEN];
00594   static const char includedir_keyword[]= "includedir";
00595   static const char include_keyword[]= "include";
00596   const int max_recursion_level= 10;
00597   FILE *fp;
00598   uint32_t line=0;
00599   bool found_group=0;
00600 
00601   if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
00602     return 0;         /* Ignore wrong paths */
00603   if (dir)
00604   {
00605     end=convert_dirname(name, dir, NULL);
00606     if (dir[0] == FN_HOMELIB)   /* Add . to filenames in home */
00607       *end++='.';
00608     sprintf(end,"%s%s",config_file,ext);
00609   }
00610   else
00611   {
00612     strcpy(name,config_file);
00613   }
00614   fn_format(name,name,"","",4);
00615   {
00616     struct stat stat_info;
00617     if (stat(name,&stat_info))
00618       return 1;
00619     /*
00620       Ignore world-writable regular files.
00621       This is mainly done to protect us to not read a file created by
00622       the mysqld server, but the check is still valid in most context.
00623     */
00624     if ((stat_info.st_mode & S_IWOTH) &&
00625   (stat_info.st_mode & S_IFMT) == S_IFREG)
00626     {
00627       fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
00628               name);
00629       return 0;
00630     }
00631   }
00632   if (!(fp= fopen(name, "r")))
00633     return 1;         /* Ignore wrong files */
00634 
00635   memset(buff,0,sizeof(buff));
00636   while (fgets(buff, sizeof(buff) - 1, fp))
00637   {
00638     line++;
00639     /* Ignore comment and empty lines */
00640     for (ptr= buff; my_isspace(&my_charset_utf8_general_ci, *ptr); ptr++)
00641     {}
00642 
00643     if (*ptr == '#' || *ptr == ';' || !*ptr)
00644       continue;
00645 
00646     /* Configuration File Directives */
00647     if ((*ptr == '!'))
00648     {
00649       if (recursion_level >= max_recursion_level)
00650       {
00651         for (end= ptr + strlen(ptr) - 1;
00652              my_isspace(&my_charset_utf8_general_ci, *(end - 1));
00653              end--)
00654         {}
00655         end[0]= 0;
00656         fprintf(stderr,
00657                 "Warning: skipping '%s' directive as maximum include"
00658                 "recursion level was reached in file %s at line %d\n",
00659                 ptr, name, line);
00660         continue;
00661       }
00662 
00663       /* skip over `!' and following whitespace */
00664       for (++ptr; my_isspace(&my_charset_utf8_general_ci, ptr[0]); ptr++)
00665       {}
00666 
00667       if ((!strncmp(ptr, includedir_keyword,
00668                     sizeof(includedir_keyword) - 1)) &&
00669           my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(includedir_keyword) - 1]))
00670       {
00671   if (!(ptr= get_argument(includedir_keyword,
00672                                 sizeof(includedir_keyword),
00673                                 ptr, name, line)))
00674     goto err;
00675 
00676         CachedDirectory dir_cache(ptr);
00677 
00678         if (dir_cache.fail())
00679         {
00687           fprintf(stderr, _("error: could not open directory: %s\n"), ptr);
00688           goto err;
00689         }
00690 
00691         CachedDirectory::Entries files= dir_cache.getEntries();
00692         CachedDirectory::Entries::iterator file_iter= files.begin();
00693 
00694         while (file_iter != files.end())
00695         {
00696           CachedDirectory::Entry *entry= *file_iter;
00697           ext= fn_ext(entry->filename.c_str());
00698 
00699           /* check extension */
00700           for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
00701           {
00702             if (!strcmp(ext, *tmp_ext))
00703             {
00704               fn_format(tmp, entry->filename.c_str(), ptr, "",
00705                         MY_UNPACK_FILENAME | MY_SAFE_PATH);
00706 
00707               search_default_file_with_ext(opt_handler, handler_ctx, "", "",
00708                                            tmp, recursion_level + 1);
00709             }
00710           }
00711 
00712           ++file_iter;
00713         }
00714       }
00715       else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
00716                my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(include_keyword)-1]))
00717       {
00718   if (!(ptr= get_argument(include_keyword,
00719                                 sizeof(include_keyword), ptr,
00720                                 name, line)))
00721     goto err;
00722 
00723         search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
00724                                      recursion_level + 1);
00725       }
00726 
00727       continue;
00728     }
00729 
00730     if (*ptr == '[')        /* Group name */
00731     {
00732       found_group=1;
00733       if (!(end=(char *) strchr(++ptr,']')))
00734       {
00735   fprintf(stderr,
00736     "error: Wrong group definition in config file: %s at line %d\n",
00737     name,line);
00738   goto err;
00739       }
00740       /* Remove end space */
00741       for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) ; end--) ;
00742       end[0]=0;
00743 
00744       strncpy(curr_gr, ptr, min((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
00745       curr_gr[min((size_t)(end-ptr)+1, sizeof(curr_gr)-1)] = '\0';
00746 
00747       /* signal that a new group is found */
00748       opt_handler(handler_ctx, curr_gr, NULL);
00749 
00750       continue;
00751     }
00752     if (!found_group)
00753     {
00754       fprintf(stderr,
00755         "error: Found option without preceding group in config file: %s at line: %d\n",
00756         name,line);
00757       goto err;
00758     }
00759 
00760 
00761     end= remove_end_comment(ptr);
00762     if ((value= strchr(ptr, '=')))
00763       end= value;       /* Option without argument */
00764     for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) || end[-1]== '\n'; end--) ;
00765     if (!value)
00766     {
00767       strncpy(strcpy(option,"--")+2,ptr,strlen(ptr)+1);
00768       if (opt_handler(handler_ctx, curr_gr, option))
00769         goto err;
00770     }
00771     else
00772     {
00773       /* Remove pre- and end space */
00774       char *value_end;
00775       for (value++ ; my_isspace(&my_charset_utf8_general_ci,*value); value++) ;
00776       value_end= strchr(value, '\0');
00777       /*
00778        We don't have to test for value_end >= value as we know there is
00779        an '=' before
00780       */
00781       for ( ; my_isspace(&my_charset_utf8_general_ci,value_end[-1]) ; value_end--) ;
00782       if (value_end < value)      /* Empty string */
00783         value_end=value;
00784 
00785       /* remove quotes around argument */
00786       if ((*value == '\"' || *value == '\'') && /* First char is quote */
00787           (value + 1 < value_end ) && /* String is longer than 1 */
00788           *value == value_end[-1] ) /* First char is equal to last char */
00789       {
00790         value++;
00791         value_end--;
00792       }
00793       
00794       memset(option,0,2+(size_t)(end-ptr)+1);
00795       ptr= strncpy(strcpy(option,"--")+2,ptr,(size_t) (end-ptr));
00796       ptr[end-ptr]= '\0';
00797       ptr+= strlen(ptr);
00798       *ptr++= '=';
00799 
00800       for ( ; value != value_end; value++)
00801       {
00802   if (*value == '\\' && value != value_end-1)
00803   {
00804     switch(*++value) {
00805     case 'n':
00806       *ptr++='\n';
00807       break;
00808     case 't':
00809       *ptr++= '\t';
00810       break;
00811     case 'r':
00812       *ptr++ = '\r';
00813       break;
00814     case 'b':
00815       *ptr++ = '\b';
00816       break;
00817     case 's':
00818       *ptr++= ' ';      /* space */
00819       break;
00820     case '\"':
00821       *ptr++= '\"';
00822       break;
00823     case '\'':
00824       *ptr++= '\'';
00825       break;
00826     case '\\':
00827       *ptr++= '\\';
00828       break;
00829     default:        /* Unknown; Keep '\' */
00830       *ptr++= '\\';
00831       *ptr++= *value;
00832       break;
00833     }
00834   }
00835   else
00836     *ptr++= *value;
00837       }
00838       *ptr=0;
00839       if (opt_handler(handler_ctx, curr_gr, option))
00840         goto err;
00841     }
00842   }
00843   fclose(fp);
00844   return(0);
00845 
00846  err:
00847   fclose(fp);
00848 
00849   return -1;          /* Fatal error */
00850 }
00851 
00852 
00853 static char *remove_end_comment(char *ptr)
00854 {
00855   char quote= 0;  /* we are inside quote marks */
00856   char escape= 0; /* symbol is protected by escape chagacter */
00857 
00858   for (; *ptr; ptr++)
00859   {
00860     if ((*ptr == '\'' || *ptr == '\"') && !escape)
00861     {
00862       if (!quote)
00863   quote= *ptr;
00864       else if (quote == *ptr)
00865   quote= 0;
00866     }
00867     /* We are not inside a string */
00868     if (!quote && *ptr == '#')
00869     {
00870       *ptr= 0;
00871       return ptr;
00872     }
00873     escape= (quote && *ptr == '\\' && !escape);
00874   }
00875   return ptr;
00876 }
00877 
00878 void my_print_default_files(const char *conf_file)
00879 {
00880   const char *empty_list[]= { "", 0 };
00881   bool have_ext= fn_ext(conf_file)[0] != 0;
00882   const char **exts_to_use= have_ext ? empty_list : f_extensions;
00883   char name[FN_REFLEN], **ext;
00884   const char **dirs;
00885 
00886   init_default_directories();
00887   puts("\nDefault options are read from the following files in the given order:");
00888 
00889   if (dirname_length(conf_file))
00890     fputs(conf_file,stdout);
00891   else
00892   {
00893     for (dirs=default_directories ; *dirs; dirs++)
00894     {
00895       for (ext= (char**) exts_to_use; *ext; ext++)
00896       {
00897   const char *pos;
00898   char *end;
00899   if (**dirs)
00900     pos= *dirs;
00901   else if (my_defaults_extra_file)
00902     pos= my_defaults_extra_file;
00903   else
00904     continue;
00905   end= convert_dirname(name, pos, NULL);
00906   if (name[0] == FN_HOMELIB)  /* Add . to filenames in home */
00907     *end++='.';
00908   sprintf(end,"%s%s ",conf_file, *ext);
00909   fputs(name,stdout);
00910       }
00911     }
00912   }
00913   puts("");
00914 }
00915 
00916 void print_defaults(const char *conf_file, const char **groups)
00917 {
00918   const char **groups_save= groups;
00919   my_print_default_files(conf_file);
00920 
00921   fputs("The following groups are read:",stdout);
00922   for ( ; *groups ; groups++)
00923   {
00924     fputc(' ',stdout);
00925     fputs(*groups,stdout);
00926   }
00927 
00928   if (my_defaults_group_suffix)
00929   {
00930     groups= groups_save;
00931     for ( ; *groups ; groups++)
00932     {
00933       fputc(' ',stdout);
00934       fputs(*groups,stdout);
00935       fputs(my_defaults_group_suffix,stdout);
00936     }
00937   }
00938   puts("\nThe following options may be given as the first argument:\n\
00939   --no-defaults   Don't read default options from any options file\n\
00940   --defaults-file=# Only read default options from the given file #\n\
00941   --defaults-extra-file=# Read this file after the global files are read");
00942 }
00943 
00944 /*
00945   This extra complexity is to avoid declaring 'rc' if it won't be
00946   used.
00947 */
00948 static void add_directory(const char* dir)
00949 {
00950   array_append_string_unique(dir, default_directories, array_elements(default_directories));
00951 }
00952 
00953 static void add_common_directories()
00954 {
00955   const char *env= getenv("DRIZZLE_HOME"); 
00956   if (env) 
00957     add_directory(env); 
00958   // Placeholder for --defaults-extra-file=<path>
00959   add_directory(""); 
00960 }
00961 
00974 static void init_default_directories(void)
00975 {
00976   memset(default_directories, 0, sizeof(default_directories));
00977   add_directory("/etc/");
00978   add_directory("/etc/drizzle/");
00979   add_directory(SYSCONFDIR);
00980   add_common_directories();
00981   add_directory("~/");
00982 }
00983 
00984 } /* namespace internal */
00985 } /* namespace drizzled */