~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/default.cc

  • Committer: Daniel Nichter
  • Date: 2011-10-23 16:01:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2448.
  • Revision ID: daniel@percona.com-20111023160137-7ac3blgz8z4tf8za
Add Administration Getting Started and Logging.  Capitalize SQL clause keywords.

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