~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/default.cc

Fix merge issues with 1.0 CC fix.

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
 
#include <drizzled/configmake.h>
41
 
 
42
 
#include <stdio.h>
43
 
 
44
 
const char *my_defaults_file=0;
45
 
const char *my_defaults_group_suffix=0;
46
 
char *my_defaults_extra_file=0;
47
 
 
48
 
/* Which directories are searched for options (and in which order) */
49
 
 
50
 
#define MAX_DEFAULT_DIRS 6
51
 
const char *default_directories[MAX_DEFAULT_DIRS + 1];
52
 
 
53
 
static const char *f_extensions[]= { ".cnf", 0 };
54
 
 
55
 
int handle_default_option(void *in_ctx, const char *group_name,
56
 
                          const char *option);
57
 
 
58
 
/*
59
 
   This structure defines the context that we pass to callback
60
 
   function 'handle_default_option' used in search_default_file
61
 
   to process each option. This context is used if search_default_file
62
 
   was called from load_defaults.
63
 
*/
64
 
 
65
 
struct handle_option_ctx
66
 
{
67
 
   MEM_ROOT *alloc;
68
 
   DYNAMIC_ARRAY *args;
69
 
   TYPELIB *group;
70
 
};
71
 
 
72
 
static int search_default_file(Process_option_func func, void *func_ctx,
73
 
                               const char *dir, const char *config_file);
74
 
static int search_default_file_with_ext(Process_option_func func,
75
 
                                        void *func_ctx,
76
 
                                        const char *dir, const char *ext,
77
 
                                        const char *config_file, int recursion_level);
78
 
 
79
 
 
80
 
 
81
 
/**
82
 
  Create the list of default directories.
83
 
 
84
 
  @details
85
 
  On all systems, if a directory is already in the list, it will be moved
86
 
  to the end of the list.  This avoids reading defaults files multiple times,
87
 
  while ensuring the correct precedence.
88
 
 
89
 
  @return void
90
 
*/
91
 
 
92
 
static void init_default_directories(void);
93
 
 
94
 
 
95
 
static char *remove_end_comment(char *ptr);
96
 
 
97
 
 
98
 
/*
99
 
  Process config files in default directories.
100
 
 
101
 
  SYNOPSIS
102
 
  my_search_option_files()
103
 
  conf_file                   Basename for configuration file to search for.
104
 
                              If this is a path, then only this file is read.
105
 
  argc                        Pointer to argc of original program
106
 
  argv                        Pointer to argv of original program
107
 
  args_used                   Pointer to variable for storing the number of
108
 
                              arguments used.
109
 
  func                        Pointer to the function to process options
110
 
  func_ctx                    It's context. Usually it is the structure to
111
 
                              store additional options.
112
 
  DESCRIPTION
113
 
    Process the default options from argc & argv
114
 
    Read through each found config file looks and calls 'func' to process
115
 
    each option.
116
 
 
117
 
  NOTES
118
 
    --defaults-group-suffix is only processed if we are called from
119
 
    load_defaults().
120
 
 
121
 
 
122
 
  RETURN
123
 
    0  ok
124
 
    1  given cinf_file doesn't exist
125
 
 
126
 
    The global variable 'my_defaults_group_suffix' is updated with value for
127
 
    --defaults_group_suffix
128
 
*/
129
 
 
130
 
int my_search_option_files(const char *conf_file, int *argc, char ***argv,
131
 
                           uint32_t *args_used, Process_option_func func,
132
 
                           void *func_ctx)
133
 
{
134
 
  const char **dirs, *forced_default_file, *forced_extra_defaults;
135
 
  int error= 0;
136
 
 
137
 
  /* Check if we want to force the use a specific default file */
138
 
  *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
139
 
                                    (char **) &forced_default_file,
140
 
                                    (char **) &forced_extra_defaults,
141
 
                                    (char **) &my_defaults_group_suffix);
142
 
 
143
 
  if (! my_defaults_group_suffix)
144
 
    my_defaults_group_suffix= getenv("DRIZZLE_GROUP_SUFFIX");
145
 
 
146
 
  if (forced_extra_defaults)
147
 
    my_defaults_extra_file= (char *) forced_extra_defaults;
148
 
 
149
 
  if (forced_default_file)
150
 
    my_defaults_file= forced_default_file;
151
 
 
152
 
  /*
153
 
    We can only handle 'defaults-group-suffix' if we are called from
154
 
    load_defaults() as otherwise we can't know the type of 'func_ctx'
155
 
  */
156
 
 
157
 
  if (my_defaults_group_suffix && (func == handle_default_option))
158
 
  {
159
 
    /* Handle --defaults-group-suffix= */
160
 
    uint32_t i;
161
 
    const char **extra_groups;
162
 
    const uint32_t instance_len= strlen(my_defaults_group_suffix);
163
 
    struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
164
 
    char *ptr;
165
 
    TYPELIB *group= ctx->group;
166
 
 
167
 
    if (!(extra_groups=
168
 
          (const char**)alloc_root(ctx->alloc,
169
 
                                   (2*group->count+1)*sizeof(char*))))
170
 
      goto err;
171
 
 
172
 
    for (i= 0; i < group->count; i++)
173
 
    {
174
 
      uint32_t len;
175
 
      extra_groups[i]= group->type_names[i]; /** copy group */
176
 
 
177
 
      len= strlen(extra_groups[i]);
178
 
      if (!(ptr= (char *)alloc_root(ctx->alloc, len+instance_len+1)))
179
 
        goto err;
180
 
 
181
 
      extra_groups[i+group->count]= ptr;
182
 
 
183
 
      /** Construct new group */
184
 
      memcpy(ptr, extra_groups[i], len);
185
 
      memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
186
 
    }
187
 
 
188
 
    group->count*= 2;
189
 
    group->type_names= extra_groups;
190
 
    group->type_names[group->count]= 0;
191
 
  }
192
 
 
193
 
  if (forced_default_file)
194
 
  {
195
 
    if ((error= search_default_file_with_ext(func, func_ctx, "", "",
196
 
                                             forced_default_file, 0)) < 0)
197
 
      goto err;
198
 
    if (error > 0)
199
 
    {
200
 
      fprintf(stderr, "Could not open required defaults file: %s\n",
201
 
              forced_default_file);
202
 
      goto err;
203
 
    }
204
 
  }
205
 
  else if (dirname_length(conf_file))
206
 
  {
207
 
    if ((error= search_default_file(func, func_ctx, NULL, conf_file)) < 0)
208
 
      goto err;
209
 
  }
210
 
  else
211
 
  {
212
 
    for (dirs= default_directories ; *dirs; dirs++)
213
 
    {
214
 
      if (**dirs)
215
 
      {
216
 
        if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
217
 
          goto err;
218
 
      }
219
 
      else if (my_defaults_extra_file)
220
 
      {
221
 
        if ((error= search_default_file_with_ext(func, func_ctx, "", "",
222
 
                                                my_defaults_extra_file, 0)) < 0)
223
 
          goto err;                             /* Fatal error */
224
 
        if (error > 0)
225
 
        {
226
 
          fprintf(stderr, "Could not open required defaults file: %s\n",
227
 
                  my_defaults_extra_file);
228
 
          goto err;
229
 
        }
230
 
      }
231
 
    }
232
 
  }
233
 
 
234
 
  return(error);
235
 
 
236
 
err:
237
 
  fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
238
 
  exit(1);
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
 
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
 
    strcpy(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
 
}
472
 
 
473
 
 
474
 
void free_defaults(char **argv)
475
 
{
476
 
  MEM_ROOT ptr;
477
 
  memcpy(&ptr, (char*) argv - sizeof(ptr), sizeof(ptr));
478
 
  free_root(&ptr,MYF(0));
479
 
}
480
 
 
481
 
 
482
 
static int search_default_file(Process_option_func opt_handler,
483
 
                               void *handler_ctx,
484
 
                               const char *dir,
485
 
                               const char *config_file)
486
 
{
487
 
  char **ext;
488
 
  const char *empty_list[]= { "", 0 };
489
 
  bool have_ext= fn_ext(config_file)[0] != 0;
490
 
  const char **exts_to_use= have_ext ? empty_list : f_extensions;
491
 
 
492
 
  for (ext= (char**) exts_to_use; *ext; ext++)
493
 
  {
494
 
    int error;
495
 
    if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
496
 
                                             dir, *ext,
497
 
                                             config_file, 0)) < 0)
498
 
      return error;
499
 
  }
500
 
  return 0;
501
 
}
502
 
 
503
 
 
504
 
/*
505
 
  Skip over keyword and get argument after keyword
506
 
 
507
 
  SYNOPSIS
508
 
   get_argument()
509
 
   keyword              Include directive keyword
510
 
   kwlen                Length of keyword
511
 
   ptr                  Pointer to the keword in the line under process
512
 
   line                 line number
513
 
 
514
 
  RETURN
515
 
   0    error
516
 
   #    Returns pointer to the argument after the keyword.
517
 
*/
518
 
 
519
 
static char *get_argument(const char *keyword, size_t kwlen,
520
 
                          char *ptr, char *name, uint32_t line)
521
 
{
522
 
  char *end;
523
 
 
524
 
  /* Skip over "include / includedir keyword" and following whitespace */
525
 
 
526
 
  for (ptr+= kwlen - 1;
527
 
       my_isspace(&my_charset_utf8_general_ci, ptr[0]);
528
 
       ptr++)
529
 
  {}
530
 
 
531
 
  /*
532
 
    Trim trailing whitespace from directory name
533
 
    The -1 below is for the newline added by fgets()
534
 
    Note that my_isspace() is true for \r and \n
535
 
  */
536
 
  for (end= ptr + strlen(ptr) - 1;
537
 
       my_isspace(&my_charset_utf8_general_ci, *(end - 1));
538
 
       end--)
539
 
  {}
540
 
  end[0]= 0;                                    /* Cut off end space */
541
 
 
542
 
  /* Print error msg if there is nothing after !include* directive */
543
 
  if (end <= ptr)
544
 
  {
545
 
    fprintf(stderr,
546
 
            "error: Wrong '!%s' directive in config file: %s at line %d\n",
547
 
            keyword, name, line);
548
 
    return 0;
549
 
  }
550
 
  return ptr;
551
 
}
552
 
 
553
 
 
554
 
/*
555
 
  Open a configuration file (if exists) and read given options from it
556
 
 
557
 
  SYNOPSIS
558
 
    search_default_file_with_ext()
559
 
    opt_handler                 Option handler function. It is used to process
560
 
                                every separate option.
561
 
    handler_ctx                 Pointer to the structure to store actual
562
 
                                parameters of the function.
563
 
    dir                         directory to read
564
 
    ext                         Extension for configuration file
565
 
    config_file                 Name of configuration file
566
 
    group                       groups to read
567
 
    recursion_level             the level of recursion, got while processing
568
 
                                "!include" or "!includedir"
569
 
 
570
 
  RETURN
571
 
    0   Success
572
 
    -1  Fatal error, abort
573
 
     1  File not found (Warning)
574
 
*/
575
 
 
576
 
static int search_default_file_with_ext(Process_option_func opt_handler,
577
 
                                        void *handler_ctx,
578
 
                                        const char *dir,
579
 
                                        const char *ext,
580
 
                                        const char *config_file,
581
 
                                        int recursion_level)
582
 
{
583
 
  char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
584
 
  char *value, option[4096], tmp[FN_REFLEN];
585
 
  static const char includedir_keyword[]= "includedir";
586
 
  static const char include_keyword[]= "include";
587
 
  const int max_recursion_level= 10;
588
 
  FILE *fp;
589
 
  uint32_t line=0;
590
 
  bool found_group=0;
591
 
  uint32_t i;
592
 
  MY_DIR *search_dir;
593
 
  FILEINFO *search_file;
594
 
 
595
 
  if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
596
 
    return 0;                                   /* Ignore wrong paths */
597
 
  if (dir)
598
 
  {
599
 
    end=convert_dirname(name, dir, NULL);
600
 
    if (dir[0] == FN_HOMELIB)           /* Add . to filenames in home */
601
 
      *end++='.';
602
 
    sprintf(end,"%s%s",config_file,ext);
603
 
  }
604
 
  else
605
 
  {
606
 
    strcpy(name,config_file);
607
 
  }
608
 
  fn_format(name,name,"","",4);
609
 
  {
610
 
    struct stat stat_info;
611
 
    if (stat(name,&stat_info))
612
 
      return 1;
613
 
    /*
614
 
      Ignore world-writable regular files.
615
 
      This is mainly done to protect us to not read a file created by
616
 
      the mysqld server, but the check is still valid in most context.
617
 
    */
618
 
    if ((stat_info.st_mode & S_IWOTH) &&
619
 
        (stat_info.st_mode & S_IFMT) == S_IFREG)
620
 
    {
621
 
      fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
622
 
              name);
623
 
      return 0;
624
 
    }
625
 
  }
626
 
  if (!(fp= my_fopen(name, O_RDONLY, MYF(0))))
627
 
    return 1;                                   /* Ignore wrong files */
628
 
 
629
 
  while (fgets(buff, sizeof(buff) - 1, fp))
630
 
  {
631
 
    line++;
632
 
    /* Ignore comment and empty lines */
633
 
    for (ptr= buff; my_isspace(&my_charset_utf8_general_ci, *ptr); ptr++)
634
 
    {}
635
 
 
636
 
    if (*ptr == '#' || *ptr == ';' || !*ptr)
637
 
      continue;
638
 
 
639
 
    /* Configuration File Directives */
640
 
    if ((*ptr == '!'))
641
 
    {
642
 
      if (recursion_level >= max_recursion_level)
643
 
      {
644
 
        for (end= ptr + strlen(ptr) - 1;
645
 
             my_isspace(&my_charset_utf8_general_ci, *(end - 1));
646
 
             end--)
647
 
        {}
648
 
        end[0]= 0;
649
 
        fprintf(stderr,
650
 
                "Warning: skipping '%s' directive as maximum include"
651
 
                "recursion level was reached in file %s at line %d\n",
652
 
                ptr, name, line);
653
 
        continue;
654
 
      }
655
 
 
656
 
      /* skip over `!' and following whitespace */
657
 
      for (++ptr; my_isspace(&my_charset_utf8_general_ci, ptr[0]); ptr++)
658
 
      {}
659
 
 
660
 
      if ((!strncmp(ptr, includedir_keyword,
661
 
                    sizeof(includedir_keyword) - 1)) &&
662
 
          my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(includedir_keyword) - 1]))
663
 
      {
664
 
        if (!(ptr= get_argument(includedir_keyword,
665
 
                                sizeof(includedir_keyword),
666
 
                                ptr, name, line)))
667
 
          goto err;
668
 
 
669
 
        if (!(search_dir= my_dir(ptr, MYF(MY_WME))))
670
 
          goto err;
671
 
 
672
 
        for (i= 0; i < (uint) search_dir->number_off_files; i++)
673
 
        {
674
 
          search_file= search_dir->dir_entry + i;
675
 
          ext= fn_ext(search_file->name);
676
 
 
677
 
          /* check extension */
678
 
          for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
679
 
          {
680
 
            if (!strcmp(ext, *tmp_ext))
681
 
              break;
682
 
          }
683
 
 
684
 
          if (*tmp_ext)
685
 
          {
686
 
            fn_format(tmp, search_file->name, ptr, "",
687
 
                      MY_UNPACK_FILENAME | MY_SAFE_PATH);
688
 
 
689
 
            search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp,
690
 
                                         recursion_level + 1);
691
 
          }
692
 
        }
693
 
 
694
 
        my_dirend(search_dir);
695
 
      }
696
 
      else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
697
 
               my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(include_keyword)-1]))
698
 
      {
699
 
        if (!(ptr= get_argument(include_keyword,
700
 
                                sizeof(include_keyword), ptr,
701
 
                                name, line)))
702
 
          goto err;
703
 
 
704
 
        search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
705
 
                                     recursion_level + 1);
706
 
      }
707
 
 
708
 
      continue;
709
 
    }
710
 
 
711
 
    if (*ptr == '[')                            /* Group name */
712
 
    {
713
 
      found_group=1;
714
 
      if (!(end=(char *) strchr(++ptr,']')))
715
 
      {
716
 
        fprintf(stderr,
717
 
                "error: Wrong group definition in config file: %s at line %d\n",
718
 
                name,line);
719
 
        goto err;
720
 
      }
721
 
      /* Remove end space */
722
 
      for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) ; end--) ;
723
 
      end[0]=0;
724
 
 
725
 
      strncpy(curr_gr, ptr, cmin((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
726
 
      curr_gr[cmin((size_t)(end-ptr)+1, sizeof(curr_gr)-1)] = '\0';
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
 
      strncpy(strcpy(option,"--")+2,ptr,strlen(ptr)+1);
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= strncpy(strcpy(option,"--")+2,ptr,(size_t) (end-ptr));
775
 
      ptr+= strlen(ptr);
776
 
      *ptr++= '=';
777
 
 
778
 
      for ( ; value != value_end; value++)
779
 
      {
780
 
        if (*value == '\\' && value != value_end-1)
781
 
        {
782
 
          switch(*++value) {
783
 
          case 'n':
784
 
            *ptr++='\n';
785
 
            break;
786
 
          case 't':
787
 
            *ptr++= '\t';
788
 
            break;
789
 
          case 'r':
790
 
            *ptr++ = '\r';
791
 
            break;
792
 
          case 'b':
793
 
            *ptr++ = '\b';
794
 
            break;
795
 
          case 's':
796
 
            *ptr++= ' ';                        /* space */
797
 
            break;
798
 
          case '\"':
799
 
            *ptr++= '\"';
800
 
            break;
801
 
          case '\'':
802
 
            *ptr++= '\'';
803
 
            break;
804
 
          case '\\':
805
 
            *ptr++= '\\';
806
 
            break;
807
 
          default:                              /* Unknown; Keep '\' */
808
 
            *ptr++= '\\';
809
 
            *ptr++= *value;
810
 
            break;
811
 
          }
812
 
        }
813
 
        else
814
 
          *ptr++= *value;
815
 
      }
816
 
      *ptr=0;
817
 
      if (opt_handler(handler_ctx, curr_gr, option))
818
 
        goto err;
819
 
    }
820
 
  }
821
 
  my_fclose(fp,MYF(0));
822
 
  return(0);
823
 
 
824
 
 err:
825
 
  my_fclose(fp,MYF(0));
826
 
  return -1;                                    /* Fatal error */
827
 
}
828
 
 
829
 
 
830
 
static char *remove_end_comment(char *ptr)
831
 
{
832
 
  char quote= 0;        /* we are inside quote marks */
833
 
  char escape= 0;       /* symbol is protected by escape chagacter */
834
 
 
835
 
  for (; *ptr; ptr++)
836
 
  {
837
 
    if ((*ptr == '\'' || *ptr == '\"') && !escape)
838
 
    {
839
 
      if (!quote)
840
 
        quote= *ptr;
841
 
      else if (quote == *ptr)
842
 
        quote= 0;
843
 
    }
844
 
    /* We are not inside a string */
845
 
    if (!quote && *ptr == '#')
846
 
    {
847
 
      *ptr= 0;
848
 
      return ptr;
849
 
    }
850
 
    escape= (quote && *ptr == '\\' && !escape);
851
 
  }
852
 
  return ptr;
853
 
}
854
 
 
855
 
void my_print_default_files(const char *conf_file)
856
 
{
857
 
  const char *empty_list[]= { "", 0 };
858
 
  bool have_ext= fn_ext(conf_file)[0] != 0;
859
 
  const char **exts_to_use= have_ext ? empty_list : f_extensions;
860
 
  char name[FN_REFLEN], **ext;
861
 
  const char **dirs;
862
 
 
863
 
  init_default_directories();
864
 
  puts("\nDefault options are read from the following files in the given order:");
865
 
 
866
 
  if (dirname_length(conf_file))
867
 
    fputs(conf_file,stdout);
868
 
  else
869
 
  {
870
 
    for (dirs=default_directories ; *dirs; dirs++)
871
 
    {
872
 
      for (ext= (char**) exts_to_use; *ext; ext++)
873
 
      {
874
 
        const char *pos;
875
 
        char *end;
876
 
        if (**dirs)
877
 
          pos= *dirs;
878
 
        else if (my_defaults_extra_file)
879
 
          pos= my_defaults_extra_file;
880
 
        else
881
 
          continue;
882
 
        end= convert_dirname(name, pos, NULL);
883
 
        if (name[0] == FN_HOMELIB)      /* Add . to filenames in home */
884
 
          *end++='.';
885
 
  sprintf(end,"%s%s ",conf_file, *ext);
886
 
        fputs(name,stdout);
887
 
      }
888
 
    }
889
 
  }
890
 
  puts("");
891
 
}
892
 
 
893
 
void print_defaults(const char *conf_file, const char **groups)
894
 
{
895
 
  const char **groups_save= groups;
896
 
  my_print_default_files(conf_file);
897
 
 
898
 
  fputs("The following groups are read:",stdout);
899
 
  for ( ; *groups ; groups++)
900
 
  {
901
 
    fputc(' ',stdout);
902
 
    fputs(*groups,stdout);
903
 
  }
904
 
 
905
 
  if (my_defaults_group_suffix)
906
 
  {
907
 
    groups= groups_save;
908
 
    for ( ; *groups ; groups++)
909
 
    {
910
 
      fputc(' ',stdout);
911
 
      fputs(*groups,stdout);
912
 
      fputs(my_defaults_group_suffix,stdout);
913
 
    }
914
 
  }
915
 
  puts("\nThe following options may be given as the first argument:\n\
916
 
--print-defaults        Print the program argument list and exit\n\
917
 
--no-defaults           Don't read default options from any options file\n\
918
 
--defaults-file=#       Only read default options from the given file #\n\
919
 
--defaults-extra-file=# Read this file after the global files are read");
920
 
}
921
 
 
922
 
/*
923
 
  This extra complexity is to avoid declaring 'rc' if it won't be
924
 
  used.
925
 
*/
926
 
#define ADD_DIRECTORY(DIR)  (void) array_append_string_unique((DIR), default_directories, \
927
 
                             array_elements(default_directories))
928
 
 
929
 
#define ADD_COMMON_DIRECTORIES() \
930
 
  do { \
931
 
    const char *env; \
932
 
    if ((env= getenv("DRIZZLE_HOME"))) \
933
 
      ADD_DIRECTORY(env); \
934
 
    /* Placeholder for --defaults-extra-file=<path> */ \
935
 
    ADD_DIRECTORY(""); \
936
 
  } while (0)
937
 
 
938
 
 
939
 
/**
940
 
  Initialize default directories for Unix
941
 
 
942
 
  @details
943
 
    1. /etc/
944
 
    2. /etc/drizzle/
945
 
    3. --sysconfdir=<path> (compile-time option)
946
 
    4. getenv("DRIZZLE_HOME")
947
 
    5. --defaults-extra-file=<path> (run-time option)
948
 
    6. "~/"
949
 
*/
950
 
 
951
 
static void init_default_directories(void)
952
 
{
953
 
  memset(default_directories, 0, sizeof(default_directories));
954
 
  ADD_DIRECTORY("/etc/");
955
 
  ADD_DIRECTORY("/etc/drizzle/");
956
 
  ADD_DIRECTORY(SYSCONFDIR);
957
 
  ADD_COMMON_DIRECTORIES();
958
 
  ADD_DIRECTORY("~/");
959
 
}