~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/internal/default.cc

  • Committer: Olaf van der Spek
  • Date: 2011-07-04 19:11:47 UTC
  • mto: This revision was merged to the branch mainline in revision 2367.
  • Revision ID: olafvdspek@gmail.com-20110704191147-s99ojek811zi1fzj
RemoveĀ unusedĀ Name_resolution_context::error_reporter

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2003 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
 
 
16
 
/****************************************************************************
17
 
 Add all options from files named "group".cnf from the default_directories
18
 
 before the command line arguments.
19
 
 On Windows defaults will also search in the Windows directory for a file
20
 
 called 'group'.ini
21
 
 As long as the program uses the last argument for conflicting
22
 
 options one only have to add a call to "load_defaults" to enable
23
 
 use of default values.
24
 
 pre- and end 'blank space' are removed from options and values. The
25
 
 following escape sequences are recognized in values:  \b \t \n \r \\
26
 
 
27
 
 The following arguments are handled automaticly;  If used, they must be
28
 
 first argument on the command line!
29
 
 --no-defaults  ; no options are read.
30
 
 --defaults-file=full-path-to-default-file      ; Only this file will be read.
31
 
 --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
32
 
 --defaults-group-suffix  ; Also read groups with concat(group, suffix)
33
 
 --print-defaults         ; Print the modified command line and exit
34
 
****************************************************************************/
35
 
 
36
 
#include "config.h"
37
 
 
38
 
#include "drizzled/internal/my_sys.h"
39
 
#include "drizzled/internal/m_string.h"
40
 
#include "drizzled/charset_info.h"
41
 
#include "drizzled/typelib.h"
42
 
#include <drizzled/configmake.h>
43
 
#include <drizzled/gettext.h>
44
 
 
45
 
#include "drizzled/cached_directory.h"
46
 
 
47
 
#ifdef HAVE_SYS_STAT_H
48
 
# include <sys/stat.h>
49
 
#endif
50
 
 
51
 
#include <cstdio>
52
 
#include <algorithm>
53
 
 
54
 
using namespace std;
55
 
 
56
 
namespace drizzled
57
 
{
58
 
namespace internal
59
 
{
60
 
 
61
 
const char *my_defaults_file=0;
62
 
const char *my_defaults_group_suffix=0;
63
 
char *my_defaults_extra_file=0;
64
 
 
65
 
/* Which directories are searched for options (and in which order) */
66
 
 
67
 
#define MAX_DEFAULT_DIRS 6
68
 
const char *default_directories[MAX_DEFAULT_DIRS + 1];
69
 
 
70
 
static const char *f_extensions[]= { ".cnf", 0 };
71
 
 
72
 
int handle_default_option(void *in_ctx, const char *group_name,
73
 
                          const char *option);
74
 
 
75
 
/*
76
 
   This structure defines the context that we pass to callback
77
 
   function 'handle_default_option' used in search_default_file
78
 
   to process each option. This context is used if search_default_file
79
 
   was called from load_defaults.
80
 
*/
81
 
 
82
 
struct handle_option_ctx
83
 
{
84
 
   memory::Root *alloc;
85
 
   DYNAMIC_ARRAY *args;
86
 
   TYPELIB *group;
87
 
};
88
 
 
89
 
static int search_default_file(Process_option_func func, void *func_ctx,
90
 
                               const char *dir, const char *config_file);
91
 
static int search_default_file_with_ext(Process_option_func func,
92
 
                                        void *func_ctx,
93
 
                                        const char *dir, const char *ext,
94
 
                                        const char *config_file, int recursion_level);
95
 
 
96
 
 
97
 
 
98
 
/**
99
 
  Create the list of default directories.
100
 
 
101
 
  @details
102
 
  On all systems, if a directory is already in the list, it will be moved
103
 
  to the end of the list.  This avoids reading defaults files multiple times,
104
 
  while ensuring the correct precedence.
105
 
 
106
 
  @return void
107
 
*/
108
 
 
109
 
static void init_default_directories(void);
110
 
 
111
 
 
112
 
static char *remove_end_comment(char *ptr);
113
 
 
114
 
 
115
 
/*
116
 
  Process config files in default directories.
117
 
 
118
 
  SYNOPSIS
119
 
  my_search_option_files()
120
 
  conf_file                   Basename for configuration file to search for.
121
 
                              If this is a path, then only this file is read.
122
 
  argc                        Pointer to argc of original program
123
 
  argv                        Pointer to argv of original program
124
 
  args_used                   Pointer to variable for storing the number of
125
 
                              arguments used.
126
 
  func                        Pointer to the function to process options
127
 
  func_ctx                    It's context. Usually it is the structure to
128
 
                              store additional options.
129
 
  DESCRIPTION
130
 
    Process the default options from argc & argv
131
 
    Read through each found config file looks and calls 'func' to process
132
 
    each option.
133
 
 
134
 
  NOTES
135
 
    --defaults-group-suffix is only processed if we are called from
136
 
    load_defaults().
137
 
 
138
 
 
139
 
  RETURN
140
 
    0  ok
141
 
    1  given cinf_file doesn't exist
142
 
 
143
 
    The global variable 'my_defaults_group_suffix' is updated with value for
144
 
    --defaults_group_suffix
145
 
*/
146
 
 
147
 
int my_search_option_files(const char *conf_file, int *argc, char ***argv,
148
 
                           uint32_t *args_used, Process_option_func func,
149
 
                           void *func_ctx)
150
 
{
151
 
  const char **dirs, *forced_default_file, *forced_extra_defaults;
152
 
  int error= 0;
153
 
 
154
 
  /* Check if we want to force the use a specific default file */
155
 
  *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
156
 
                                    (char **) &forced_default_file,
157
 
                                    (char **) &forced_extra_defaults,
158
 
                                    (char **) &my_defaults_group_suffix);
159
 
 
160
 
  if (! my_defaults_group_suffix)
161
 
    my_defaults_group_suffix= getenv("DRIZZLE_GROUP_SUFFIX");
162
 
 
163
 
  if (forced_extra_defaults)
164
 
    my_defaults_extra_file= (char *) forced_extra_defaults;
165
 
 
166
 
  if (forced_default_file)
167
 
    my_defaults_file= forced_default_file;
168
 
 
169
 
  /*
170
 
    We can only handle 'defaults-group-suffix' if we are called from
171
 
    load_defaults() as otherwise we can't know the type of 'func_ctx'
172
 
  */
173
 
 
174
 
  if (my_defaults_group_suffix && (func == handle_default_option))
175
 
  {
176
 
    /* Handle --defaults-group-suffix= */
177
 
    uint32_t i;
178
 
    const char **extra_groups;
179
 
    const size_t instance_len= strlen(my_defaults_group_suffix);
180
 
    struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
181
 
    char *ptr;
182
 
    TYPELIB *group= ctx->group;
183
 
 
184
 
    if (!(extra_groups=
185
 
          (const char**)ctx->alloc->alloc_root(
186
 
                                   (2*group->count+1)*sizeof(char*))))
187
 
      goto err;
188
 
 
189
 
    for (i= 0; i < group->count; i++)
190
 
    {
191
 
      size_t len;
192
 
      extra_groups[i]= group->type_names[i]; /** copy group */
193
 
 
194
 
      len= strlen(extra_groups[i]);
195
 
      if (!(ptr= (char *)ctx->alloc->alloc_root( len+instance_len+1)))
196
 
        goto err;
197
 
 
198
 
      extra_groups[i+group->count]= ptr;
199
 
 
200
 
      /** Construct new group */
201
 
      memcpy(ptr, extra_groups[i], len);
202
 
      memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
203
 
    }
204
 
 
205
 
    group->count*= 2;
206
 
    group->type_names= extra_groups;
207
 
    group->type_names[group->count]= 0;
208
 
  }
209
 
 
210
 
  if (forced_default_file)
211
 
  {
212
 
    if ((error= search_default_file_with_ext(func, func_ctx, "", "",
213
 
                                             forced_default_file, 0)) < 0)
214
 
      goto err;
215
 
    if (error > 0)
216
 
    {
217
 
      fprintf(stderr, "Could not open required defaults file: %s\n",
218
 
              forced_default_file);
219
 
      goto err;
220
 
    }
221
 
  }
222
 
  else if (dirname_length(conf_file))
223
 
  {
224
 
    if ((error= search_default_file(func, func_ctx, NULL, conf_file)) < 0)
225
 
      goto err;
226
 
  }
227
 
  else
228
 
  {
229
 
    for (dirs= default_directories ; *dirs; dirs++)
230
 
    {
231
 
      if (**dirs)
232
 
      {
233
 
        if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
234
 
          goto err;
235
 
      }
236
 
      else if (my_defaults_extra_file)
237
 
      {
238
 
        if ((error= search_default_file_with_ext(func, func_ctx, "", "",
239
 
                                                my_defaults_extra_file, 0)) < 0)
240
 
          goto err;                             /* Fatal error */
241
 
        if (error > 0)
242
 
        {
243
 
          fprintf(stderr, "Could not open required defaults file: %s\n",
244
 
                  my_defaults_extra_file);
245
 
          goto err;
246
 
        }
247
 
      }
248
 
    }
249
 
  }
250
 
 
251
 
  return(error);
252
 
 
253
 
err:
254
 
  fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
255
 
  exit(1);
256
 
}
257
 
 
258
 
 
259
 
/*
260
 
  The option handler for load_defaults.
261
 
 
262
 
  SYNOPSIS
263
 
    handle_deault_option()
264
 
    in_ctx                  Handler context. In this case it is a
265
 
                            handle_option_ctx structure.
266
 
    group_name              The name of the group the option belongs to.
267
 
    option                  The very option to be processed. It is already
268
 
                            prepared to be used in argv (has -- prefix). If it
269
 
                            is NULL, we are handling a new group (section).
270
 
 
271
 
  DESCRIPTION
272
 
    This handler checks whether a group is one of the listed and adds an option
273
 
    to the array if yes. Some other handler can record, for instance, all
274
 
    groups and their options, not knowing in advance the names and amount of
275
 
    groups.
276
 
 
277
 
  RETURN
278
 
    0 - ok
279
 
    1 - error occured
280
 
*/
281
 
 
282
 
int handle_default_option(void *in_ctx, const char *group_name,
283
 
                          const char *option)
284
 
{
285
 
  char *tmp;
286
 
  struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
287
 
 
288
 
  if (!option)
289
 
    return 0;
290
 
 
291
 
  if (ctx->group->find_type(const_cast<char*>(group_name), 3))
292
 
  {
293
 
    if (!(tmp= (char *)ctx->alloc->alloc_root(strlen(option) + 1)))
294
 
      return 1;
295
 
    if (insert_dynamic(ctx->args, (unsigned char*) &tmp))
296
 
      return 1;
297
 
    strcpy(tmp, option);
298
 
  }
299
 
 
300
 
  return 0;
301
 
}
302
 
 
303
 
 
304
 
/*
305
 
  Gets options from the command line
306
 
 
307
 
  SYNOPSIS
308
 
    get_defaults_options()
309
 
    argc                        Pointer to argc of original program
310
 
    argv                        Pointer to argv of original program
311
 
    defaults                    --defaults-file option
312
 
    extra_defaults              --defaults-extra-file option
313
 
 
314
 
  RETURN
315
 
    # Number of arguments used from *argv
316
 
      defaults and extra_defaults will be set to option of the appropriate
317
 
      items of argv array, or to NULL if there are no such options
318
 
*/
319
 
 
320
 
int get_defaults_options(int argc, char **argv,
321
 
                         char **defaults,
322
 
                         char **extra_defaults,
323
 
                         char **group_suffix)
324
 
{
325
 
  int org_argc= argc, prev_argc= 0;
326
 
  *defaults= *extra_defaults= *group_suffix= 0;
327
 
 
328
 
  const std::string DEFAULTS_FILE("--defaults-file=");
329
 
  const std::string DEFAULTS_EXTRA_FILE("--defaults-extra-file=");
330
 
  const std::string DEFAULTS_GROUP_SUFFIX("--defaults-group-suffix=");
331
 
 
332
 
  while (argc >= 2 && argc != prev_argc)
333
 
  {
334
 
    /* Skip program name or previously handled argument */
335
 
    argv++;
336
 
    prev_argc= argc;                            /* To check if we found */
337
 
    if (!*defaults && (strncmp(*argv,
338
 
                               DEFAULTS_FILE.c_str(),
339
 
                               DEFAULTS_FILE.size()) == 0))
340
 
    {
341
 
      *defaults= *argv + DEFAULTS_FILE.size();
342
 
       argc--;
343
 
       continue;
344
 
    }
345
 
    if (!*extra_defaults && (strncmp(*argv, 
346
 
                                     DEFAULTS_EXTRA_FILE.c_str(),
347
 
                                     DEFAULTS_EXTRA_FILE.size()) == 0))
348
 
    {
349
 
      *extra_defaults= *argv + DEFAULTS_EXTRA_FILE.size();
350
 
      argc--;
351
 
      continue;
352
 
    }
353
 
    if (!*group_suffix && (strncmp(*argv, 
354
 
                                   DEFAULTS_GROUP_SUFFIX.c_str(),
355
 
                                   DEFAULTS_GROUP_SUFFIX.size()) == 0))
356
 
 
357
 
    {
358
 
      *group_suffix= *argv + DEFAULTS_GROUP_SUFFIX.size();
359
 
      argc--;
360
 
      continue;
361
 
    }
362
 
  }
363
 
  return org_argc - argc;
364
 
}
365
 
 
366
 
 
367
 
/*
368
 
  Read options from configurations files
369
 
 
370
 
  SYNOPSIS
371
 
    load_defaults()
372
 
    conf_file                   Basename for configuration file to search for.
373
 
                                If this is a path, then only this file is read.
374
 
    groups                      Which [group] entrys to read.
375
 
                                Points to an null terminated array of pointers
376
 
    argc                        Pointer to argc of original program
377
 
    argv                        Pointer to argv of original program
378
 
 
379
 
  IMPLEMENTATION
380
 
 
381
 
   Read options from configuration files and put them BEFORE the arguments
382
 
   that are already in argc and argv.  This way the calling program can
383
 
   easily command line options override options in configuration files
384
 
 
385
 
   NOTES
386
 
    In case of fatal error, the function will print a warning and do
387
 
    exit(1)
388
 
 
389
 
    To free used memory one should call free_defaults() with the argument
390
 
    that was put in *argv
391
 
 
392
 
   RETURN
393
 
     0  ok
394
 
     1  The given conf_file didn't exists
395
 
*/
396
 
 
397
 
 
398
 
int load_defaults(const char *conf_file, const char **groups,
399
 
                  int *argc, char ***argv)
400
 
{
401
 
  DYNAMIC_ARRAY args;
402
 
  TYPELIB group;
403
 
  uint32_t args_used= 0;
404
 
  int error= 0;
405
 
  memory::Root alloc(512);
406
 
  char *ptr,**res;
407
 
  struct handle_option_ctx ctx;
408
 
 
409
 
  init_default_directories();
410
 
  /*
411
 
    Check if the user doesn't want any default option processing
412
 
    --no-defaults is always the first option
413
 
  */
414
 
  if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
415
 
  {
416
 
    /* remove the --no-defaults argument and return only the other arguments */
417
 
    uint32_t i;
418
 
    if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (*argc + 1)*sizeof(char*))))
419
 
      goto err;
420
 
    res= (char**) (ptr+sizeof(alloc));
421
 
    memset(res,0,(*argc + 1));
422
 
    res[0]= **argv;                             /* Copy program name */
423
 
    for (i=2 ; i < (uint32_t) *argc ; i++)
424
 
      res[i-1]=argv[0][i];
425
 
    res[i-1]=0;                                 /* End pointer */
426
 
    (*argc)--;
427
 
    *argv=res;
428
 
    *(memory::Root*) ptr= alloc;                        /* Save alloc root for free */
429
 
    return(0);
430
 
  }
431
 
 
432
 
  group.count=0;
433
 
  group.name= "defaults";
434
 
  group.type_names= groups;
435
 
 
436
 
  for (; *groups ; groups++)
437
 
    group.count++;
438
 
 
439
 
  if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
440
 
    goto err;
441
 
 
442
 
  ctx.alloc= &alloc;
443
 
  ctx.args= &args;
444
 
  ctx.group= &group;
445
 
 
446
 
  error= my_search_option_files(conf_file, argc, argv, &args_used,
447
 
                                handle_default_option, (void *) &ctx);
448
 
  /*
449
 
    Here error contains <> 0 only if we have a fully specified conf_file
450
 
    or a forced default file
451
 
  */
452
 
  if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (args.elements + *argc +1) *sizeof(char*))))
453
 
    goto err;
454
 
  res= (char**) (ptr+sizeof(alloc));
455
 
 
456
 
  /* copy name + found arguments + command line arguments to new array */
457
 
  res[0]= argv[0][0];  /* Name MUST be set, even by embedded library */
458
 
  memcpy(res+1, args.buffer, args.elements*sizeof(char*));
459
 
  /* Skip --defaults-xxx options */
460
 
  (*argc)-= args_used;
461
 
  (*argv)+= args_used;
462
 
 
463
 
  /*
464
 
    Check if we wan't to see the new argument list
465
 
    This options must always be the last of the default options
466
 
  */
467
 
  if (*argc)
468
 
    memcpy(res+1+args.elements, *argv + 1, (*argc-1)*sizeof(char*));
469
 
  res[args.elements+ *argc]=0;                  /* last null */
470
 
 
471
 
  (*argc)+=int(args.elements);
472
 
  *argv= static_cast<char**>(res);
473
 
  *(memory::Root*) ptr= alloc;                  /* Save alloc root for free */
474
 
  delete_dynamic(&args);
475
 
 
476
 
  return(error);
477
 
 
478
 
 err:
479
 
  fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
480
 
  exit(1);
481
 
}
482
 
 
483
 
 
484
 
void free_defaults(char **argv)
485
 
{
486
 
  memory::Root ptr;
487
 
  memcpy(&ptr, (char*) argv - sizeof(ptr), sizeof(ptr));
488
 
  ptr.free_root(MYF(0));
489
 
}
490
 
 
491
 
 
492
 
static int search_default_file(Process_option_func opt_handler,
493
 
                               void *handler_ctx,
494
 
                               const char *dir,
495
 
                               const char *config_file)
496
 
{
497
 
  char **ext;
498
 
  const char *empty_list[]= { "", 0 };
499
 
  bool have_ext= fn_ext(config_file)[0] != 0;
500
 
  const char **exts_to_use= have_ext ? empty_list : f_extensions;
501
 
 
502
 
  for (ext= (char**) exts_to_use; *ext; ext++)
503
 
  {
504
 
    int error;
505
 
    if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
506
 
                                             dir, *ext,
507
 
                                             config_file, 0)) < 0)
508
 
      return error;
509
 
  }
510
 
  return 0;
511
 
}
512
 
 
513
 
 
514
 
/*
515
 
  Skip over keyword and get argument after keyword
516
 
 
517
 
  SYNOPSIS
518
 
   get_argument()
519
 
   keyword              Include directive keyword
520
 
   kwlen                Length of keyword
521
 
   ptr                  Pointer to the keword in the line under process
522
 
   line                 line number
523
 
 
524
 
  RETURN
525
 
   0    error
526
 
   #    Returns pointer to the argument after the keyword.
527
 
*/
528
 
 
529
 
static char *get_argument(const char *keyword, size_t kwlen,
530
 
                          char *ptr, char *name, uint32_t line)
531
 
{
532
 
  char *end;
533
 
 
534
 
  /* Skip over "include / includedir keyword" and following whitespace */
535
 
 
536
 
  for (ptr+= kwlen - 1;
537
 
       my_isspace(&my_charset_utf8_general_ci, ptr[0]);
538
 
       ptr++)
539
 
  {}
540
 
 
541
 
  /*
542
 
    Trim trailing whitespace from directory name
543
 
    The -1 below is for the newline added by fgets()
544
 
    Note that my_isspace() is true for \r and \n
545
 
  */
546
 
  for (end= ptr + strlen(ptr) - 1;
547
 
       my_isspace(&my_charset_utf8_general_ci, *(end - 1));
548
 
       end--)
549
 
  {}
550
 
  end[0]= 0;                                    /* Cut off end space */
551
 
 
552
 
  /* Print error msg if there is nothing after !include* directive */
553
 
  if (end <= ptr)
554
 
  {
555
 
    fprintf(stderr,
556
 
            "error: Wrong '!%s' directive in config file: %s at line %d\n",
557
 
            keyword, name, line);
558
 
    return 0;
559
 
  }
560
 
  return ptr;
561
 
}
562
 
 
563
 
 
564
 
/*
565
 
  Open a configuration file (if exists) and read given options from it
566
 
 
567
 
  SYNOPSIS
568
 
    search_default_file_with_ext()
569
 
    opt_handler                 Option handler function. It is used to process
570
 
                                every separate option.
571
 
    handler_ctx                 Pointer to the structure to store actual
572
 
                                parameters of the function.
573
 
    dir                         directory to read
574
 
    ext                         Extension for configuration file
575
 
    config_file                 Name of configuration file
576
 
    group                       groups to read
577
 
    recursion_level             the level of recursion, got while processing
578
 
                                "!include" or "!includedir"
579
 
 
580
 
  RETURN
581
 
    0   Success
582
 
    -1  Fatal error, abort
583
 
     1  File not found (Warning)
584
 
*/
585
 
 
586
 
static int search_default_file_with_ext(Process_option_func opt_handler,
587
 
                                        void *handler_ctx,
588
 
                                        const char *dir,
589
 
                                        const char *ext,
590
 
                                        const char *config_file,
591
 
                                        int recursion_level)
592
 
{
593
 
  char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
594
 
  char *value, option[4096], tmp[FN_REFLEN];
595
 
  static const char includedir_keyword[]= "includedir";
596
 
  static const char include_keyword[]= "include";
597
 
  const int max_recursion_level= 10;
598
 
  FILE *fp;
599
 
  uint32_t line=0;
600
 
  bool found_group=0;
601
 
 
602
 
  if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
603
 
    return 0;                                   /* Ignore wrong paths */
604
 
  if (dir)
605
 
  {
606
 
    end=convert_dirname(name, dir, NULL);
607
 
    if (dir[0] == FN_HOMELIB)           /* Add . to filenames in home */
608
 
      *end++='.';
609
 
    sprintf(end,"%s%s",config_file,ext);
610
 
  }
611
 
  else
612
 
  {
613
 
    strcpy(name,config_file);
614
 
  }
615
 
  fn_format(name,name,"","",4);
616
 
  {
617
 
    struct stat stat_info;
618
 
    if (stat(name,&stat_info))
619
 
      return 1;
620
 
    /*
621
 
      Ignore world-writable regular files.
622
 
      This is mainly done to protect us to not read a file created by
623
 
      the mysqld server, but the check is still valid in most context.
624
 
    */
625
 
    if ((stat_info.st_mode & S_IWOTH) &&
626
 
        (stat_info.st_mode & S_IFMT) == S_IFREG)
627
 
    {
628
 
      fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
629
 
              name);
630
 
      return 0;
631
 
    }
632
 
  }
633
 
  if (!(fp= fopen(name, "r")))
634
 
    return 1;                                   /* Ignore wrong files */
635
 
 
636
 
  memset(buff,0,sizeof(buff));
637
 
  while (fgets(buff, sizeof(buff) - 1, fp))
638
 
  {
639
 
    line++;
640
 
    /* Ignore comment and empty lines */
641
 
    for (ptr= buff; my_isspace(&my_charset_utf8_general_ci, *ptr); ptr++)
642
 
    {}
643
 
 
644
 
    if (*ptr == '#' || *ptr == ';' || !*ptr)
645
 
      continue;
646
 
 
647
 
    /* Configuration File Directives */
648
 
    if ((*ptr == '!'))
649
 
    {
650
 
      if (recursion_level >= max_recursion_level)
651
 
      {
652
 
        for (end= ptr + strlen(ptr) - 1;
653
 
             my_isspace(&my_charset_utf8_general_ci, *(end - 1));
654
 
             end--)
655
 
        {}
656
 
        end[0]= 0;
657
 
        fprintf(stderr,
658
 
                "Warning: skipping '%s' directive as maximum include"
659
 
                "recursion level was reached in file %s at line %d\n",
660
 
                ptr, name, line);
661
 
        continue;
662
 
      }
663
 
 
664
 
      /* skip over `!' and following whitespace */
665
 
      for (++ptr; my_isspace(&my_charset_utf8_general_ci, ptr[0]); ptr++)
666
 
      {}
667
 
 
668
 
      if ((!strncmp(ptr, includedir_keyword,
669
 
                    sizeof(includedir_keyword) - 1)) &&
670
 
          my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(includedir_keyword) - 1]))
671
 
      {
672
 
        if (!(ptr= get_argument(includedir_keyword,
673
 
                                sizeof(includedir_keyword),
674
 
                                ptr, name, line)))
675
 
          goto err;
676
 
 
677
 
        CachedDirectory dir_cache(ptr);
678
 
 
679
 
        if (dir_cache.fail())
680
 
        {
681
 
          /**
682
 
           * @todo
683
 
           * Since clients still use this code, we use fprintf here.
684
 
           * This fprintf needs to be turned into errmsg_printf
685
 
           * as soon as the client programs no longer use mysys
686
 
           * and can use the pluggable error message system.
687
 
           */
688
 
          fprintf(stderr, _("error: could not open directory: %s\n"), ptr);
689
 
          goto err;
690
 
        }
691
 
 
692
 
        CachedDirectory::Entries files= dir_cache.getEntries();
693
 
        CachedDirectory::Entries::iterator file_iter= files.begin();
694
 
 
695
 
        while (file_iter != files.end())
696
 
        {
697
 
          CachedDirectory::Entry *entry= *file_iter;
698
 
          ext= fn_ext(entry->filename.c_str());
699
 
 
700
 
          /* check extension */
701
 
          for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
702
 
          {
703
 
            if (!strcmp(ext, *tmp_ext))
704
 
            {
705
 
              fn_format(tmp, entry->filename.c_str(), ptr, "",
706
 
                        MY_UNPACK_FILENAME | MY_SAFE_PATH);
707
 
 
708
 
              search_default_file_with_ext(opt_handler, handler_ctx, "", "",
709
 
                                           tmp, recursion_level + 1);
710
 
            }
711
 
          }
712
 
 
713
 
          ++file_iter;
714
 
        }
715
 
      }
716
 
      else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
717
 
               my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(include_keyword)-1]))
718
 
      {
719
 
        if (!(ptr= get_argument(include_keyword,
720
 
                                sizeof(include_keyword), ptr,
721
 
                                name, line)))
722
 
          goto err;
723
 
 
724
 
        search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
725
 
                                     recursion_level + 1);
726
 
      }
727
 
 
728
 
      continue;
729
 
    }
730
 
 
731
 
    if (*ptr == '[')                            /* Group name */
732
 
    {
733
 
      found_group=1;
734
 
      if (!(end=(char *) strchr(++ptr,']')))
735
 
      {
736
 
        fprintf(stderr,
737
 
                "error: Wrong group definition in config file: %s at line %d\n",
738
 
                name,line);
739
 
        goto err;
740
 
      }
741
 
      /* Remove end space */
742
 
      for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) ; end--) ;
743
 
      end[0]=0;
744
 
 
745
 
      strncpy(curr_gr, ptr, min((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
746
 
      curr_gr[min((size_t)(end-ptr)+1, sizeof(curr_gr)-1)] = '\0';
747
 
 
748
 
      /* signal that a new group is found */
749
 
      opt_handler(handler_ctx, curr_gr, NULL);
750
 
 
751
 
      continue;
752
 
    }
753
 
    if (!found_group)
754
 
    {
755
 
      fprintf(stderr,
756
 
              "error: Found option without preceding group in config file: %s at line: %d\n",
757
 
              name,line);
758
 
      goto err;
759
 
    }
760
 
 
761
 
 
762
 
    end= remove_end_comment(ptr);
763
 
    if ((value= strchr(ptr, '=')))
764
 
      end= value;                               /* Option without argument */
765
 
    for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) || end[-1]== '\n'; end--) ;
766
 
    if (!value)
767
 
    {
768
 
      strncpy(strcpy(option,"--")+2,ptr,strlen(ptr)+1);
769
 
      if (opt_handler(handler_ctx, curr_gr, option))
770
 
        goto err;
771
 
    }
772
 
    else
773
 
    {
774
 
      /* Remove pre- and end space */
775
 
      char *value_end;
776
 
      for (value++ ; my_isspace(&my_charset_utf8_general_ci,*value); value++) ;
777
 
      value_end= strchr(value, '\0');
778
 
      /*
779
 
       We don't have to test for value_end >= value as we know there is
780
 
       an '=' before
781
 
      */
782
 
      for ( ; my_isspace(&my_charset_utf8_general_ci,value_end[-1]) ; value_end--) ;
783
 
      if (value_end < value)                    /* Empty string */
784
 
        value_end=value;
785
 
 
786
 
      /* remove quotes around argument */
787
 
      if ((*value == '\"' || *value == '\'') && /* First char is quote */
788
 
          (value + 1 < value_end ) && /* String is longer than 1 */
789
 
          *value == value_end[-1] ) /* First char is equal to last char */
790
 
      {
791
 
        value++;
792
 
        value_end--;
793
 
      }
794
 
      
795
 
      memset(option,0,2+(size_t)(end-ptr)+1);
796
 
      ptr= strncpy(strcpy(option,"--")+2,ptr,(size_t) (end-ptr));
797
 
      ptr[end-ptr]= '\0';
798
 
      ptr+= strlen(ptr);
799
 
      *ptr++= '=';
800
 
 
801
 
      for ( ; value != value_end; value++)
802
 
      {
803
 
        if (*value == '\\' && value != value_end-1)
804
 
        {
805
 
          switch(*++value) {
806
 
          case 'n':
807
 
            *ptr++='\n';
808
 
            break;
809
 
          case 't':
810
 
            *ptr++= '\t';
811
 
            break;
812
 
          case 'r':
813
 
            *ptr++ = '\r';
814
 
            break;
815
 
          case 'b':
816
 
            *ptr++ = '\b';
817
 
            break;
818
 
          case 's':
819
 
            *ptr++= ' ';                        /* space */
820
 
            break;
821
 
          case '\"':
822
 
            *ptr++= '\"';
823
 
            break;
824
 
          case '\'':
825
 
            *ptr++= '\'';
826
 
            break;
827
 
          case '\\':
828
 
            *ptr++= '\\';
829
 
            break;
830
 
          default:                              /* Unknown; Keep '\' */
831
 
            *ptr++= '\\';
832
 
            *ptr++= *value;
833
 
            break;
834
 
          }
835
 
        }
836
 
        else
837
 
          *ptr++= *value;
838
 
      }
839
 
      *ptr=0;
840
 
      if (opt_handler(handler_ctx, curr_gr, option))
841
 
        goto err;
842
 
    }
843
 
  }
844
 
  fclose(fp);
845
 
  return(0);
846
 
 
847
 
 err:
848
 
  fclose(fp);
849
 
 
850
 
  return -1;                                    /* Fatal error */
851
 
}
852
 
 
853
 
 
854
 
static char *remove_end_comment(char *ptr)
855
 
{
856
 
  char quote= 0;        /* we are inside quote marks */
857
 
  char escape= 0;       /* symbol is protected by escape chagacter */
858
 
 
859
 
  for (; *ptr; ptr++)
860
 
  {
861
 
    if ((*ptr == '\'' || *ptr == '\"') && !escape)
862
 
    {
863
 
      if (!quote)
864
 
        quote= *ptr;
865
 
      else if (quote == *ptr)
866
 
        quote= 0;
867
 
    }
868
 
    /* We are not inside a string */
869
 
    if (!quote && *ptr == '#')
870
 
    {
871
 
      *ptr= 0;
872
 
      return ptr;
873
 
    }
874
 
    escape= (quote && *ptr == '\\' && !escape);
875
 
  }
876
 
  return ptr;
877
 
}
878
 
 
879
 
void my_print_default_files(const char *conf_file)
880
 
{
881
 
  const char *empty_list[]= { "", 0 };
882
 
  bool have_ext= fn_ext(conf_file)[0] != 0;
883
 
  const char **exts_to_use= have_ext ? empty_list : f_extensions;
884
 
  char name[FN_REFLEN], **ext;
885
 
  const char **dirs;
886
 
 
887
 
  init_default_directories();
888
 
  puts("\nDefault options are read from the following files in the given order:");
889
 
 
890
 
  if (dirname_length(conf_file))
891
 
    fputs(conf_file,stdout);
892
 
  else
893
 
  {
894
 
    for (dirs=default_directories ; *dirs; dirs++)
895
 
    {
896
 
      for (ext= (char**) exts_to_use; *ext; ext++)
897
 
      {
898
 
        const char *pos;
899
 
        char *end;
900
 
        if (**dirs)
901
 
          pos= *dirs;
902
 
        else if (my_defaults_extra_file)
903
 
          pos= my_defaults_extra_file;
904
 
        else
905
 
          continue;
906
 
        end= convert_dirname(name, pos, NULL);
907
 
        if (name[0] == FN_HOMELIB)      /* Add . to filenames in home */
908
 
          *end++='.';
909
 
  sprintf(end,"%s%s ",conf_file, *ext);
910
 
        fputs(name,stdout);
911
 
      }
912
 
    }
913
 
  }
914
 
  puts("");
915
 
}
916
 
 
917
 
void print_defaults(const char *conf_file, const char **groups)
918
 
{
919
 
  const char **groups_save= groups;
920
 
  my_print_default_files(conf_file);
921
 
 
922
 
  fputs("The following groups are read:",stdout);
923
 
  for ( ; *groups ; groups++)
924
 
  {
925
 
    fputc(' ',stdout);
926
 
    fputs(*groups,stdout);
927
 
  }
928
 
 
929
 
  if (my_defaults_group_suffix)
930
 
  {
931
 
    groups= groups_save;
932
 
    for ( ; *groups ; groups++)
933
 
    {
934
 
      fputc(' ',stdout);
935
 
      fputs(*groups,stdout);
936
 
      fputs(my_defaults_group_suffix,stdout);
937
 
    }
938
 
  }
939
 
  puts("\nThe following options may be given as the first argument:\n\
940
 
  --no-defaults         Don't read default options from any options file\n\
941
 
  --defaults-file=#     Only read default options from the given file #\n\
942
 
  --defaults-extra-file=# Read this file after the global files are read");
943
 
}
944
 
 
945
 
/*
946
 
  This extra complexity is to avoid declaring 'rc' if it won't be
947
 
  used.
948
 
*/
949
 
static void add_directory(const char* dir)
950
 
{
951
 
  array_append_string_unique(dir, default_directories, array_elements(default_directories));
952
 
}
953
 
 
954
 
static void add_common_directories()
955
 
{
956
 
  const char *env= getenv("DRIZZLE_HOME"); 
957
 
  if (env) 
958
 
    add_directory(env); 
959
 
  // Placeholder for --defaults-extra-file=<path>
960
 
  add_directory(""); 
961
 
}
962
 
 
963
 
/**
964
 
  Initialize default directories for Unix
965
 
 
966
 
  @details
967
 
    1. /etc/
968
 
    2. /etc/drizzle/
969
 
    3. --sysconfdir=<path> (compile-time option)
970
 
    4. getenv("DRIZZLE_HOME")
971
 
    5. --defaults-extra-file=<path> (run-time option)
972
 
    6. "~/"
973
 
*/
974
 
 
975
 
static void init_default_directories(void)
976
 
{
977
 
  memset(default_directories, 0, sizeof(default_directories));
978
 
  add_directory("/etc/");
979
 
  add_directory("/etc/drizzle/");
980
 
  add_directory(SYSCONFDIR);
981
 
  add_common_directories();
982
 
  add_directory("~/");
983
 
}
984
 
 
985
 
} /* namespace internal */
986
 
} /* namespace drizzled */