~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

Viewing changes to mysys/default.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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 "m_string.h"
 
38
#include "m_ctype.h"
 
39
#include <my_dir.h>
 
40
 
 
41
const char *my_defaults_file=0;
 
42
const char *my_defaults_group_suffix=0;
 
43
char *my_defaults_extra_file=0;
 
44
 
 
45
/* Which directories are searched for options (and in which order) */
 
46
 
 
47
#define MAX_DEFAULT_DIRS 6
 
48
const char *default_directories[MAX_DEFAULT_DIRS + 1];
 
49
 
 
50
static const char *f_extensions[]= { ".cnf", 0 };
 
51
#define NEWLINE "\n"
 
52
 
 
53
static int handle_default_option(void *in_ctx, const char *group_name,
 
54
                                 const char *option);
 
55
 
 
56
/*
 
57
   This structure defines the context that we pass to callback
 
58
   function 'handle_default_option' used in search_default_file
 
59
   to process each option. This context is used if search_default_file
 
60
   was called from load_defaults.
 
61
*/
 
62
 
 
63
struct handle_option_ctx
 
64
{
 
65
   MEM_ROOT *alloc;
 
66
   DYNAMIC_ARRAY *args;
 
67
   TYPELIB *group;
 
68
};
 
69
 
 
70
static int search_default_file(Process_option_func func, void *func_ctx,
 
71
                               const char *dir, const char *config_file);
 
72
static int search_default_file_with_ext(Process_option_func func,
 
73
                                        void *func_ctx,
 
74
                                        const char *dir, const char *ext,
 
75
                                        const char *config_file, int recursion_level);
 
76
 
 
77
 
 
78
 
 
79
/**
 
80
  Create the list of default directories.
 
81
 
 
82
  @details
 
83
  On all systems, if a directory is already in the list, it will be moved
 
84
  to the end of the list.  This avoids reading defaults files multiple times,
 
85
  while ensuring the correct precedence.
 
86
 
 
87
  @return void
 
88
*/
 
89
 
 
90
static void (*init_default_directories)();
 
91
 
 
92
 
 
93
static char *remove_end_comment(char *ptr);
 
94
 
 
95
 
 
96
/*
 
97
  Process config files in default directories.
 
98
 
 
99
  SYNOPSIS
 
100
  my_search_option_files()
 
101
  conf_file                   Basename for configuration file to search for.
 
102
                              If this is a path, then only this file is read.
 
103
  argc                        Pointer to argc of original program
 
104
  argv                        Pointer to argv of original program
 
105
  args_used                   Pointer to variable for storing the number of
 
106
                              arguments used.
 
107
  func                        Pointer to the function to process options
 
108
  func_ctx                    It's context. Usually it is the structure to
 
109
                              store additional options.
 
110
  DESCRIPTION
 
111
    Process the default options from argc & argv
 
112
    Read through each found config file looks and calls 'func' to process
 
113
    each option.
 
114
 
 
115
  NOTES
 
116
    --defaults-group-suffix is only processed if we are called from
 
117
    load_defaults().
 
118
 
 
119
 
 
120
  RETURN
 
121
    0  ok
 
122
    1  given cinf_file doesn't exist
 
123
 
 
124
    The global variable 'my_defaults_group_suffix' is updated with value for
 
125
    --defaults_group_suffix
 
126
*/
 
127
 
 
128
int my_search_option_files(const char *conf_file, int *argc, char ***argv,
 
129
                           uint *args_used, Process_option_func func,
 
130
                           void *func_ctx)
 
131
{
 
132
  const char **dirs, *forced_default_file, *forced_extra_defaults;
 
133
  int error= 0;
 
134
  DBUG_ENTER("my_search_option_files");
 
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
    uint i;
 
160
    const char **extra_groups;
 
161
    const uint 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
      uint len;
 
174
      extra_groups[i]= group->type_names[i]; /** copy group */
 
175
      
 
176
      len= strlen(extra_groups[i]);
 
177
      if (!(ptr= 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, NullS, 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
  DBUG_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= alloc_root(ctx->alloc, strlen(option) + 1)))
 
277
      return 1;
 
278
    if (insert_dynamic(ctx->args, (uchar*) &tmp))
 
279
      return 1;
 
280
    strmov(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
  my_bool found_print_defaults= 0;
 
376
  uint args_used= 0;
 
377
  int error= 0;
 
378
  MEM_ROOT alloc;
 
379
  char *ptr,**res;
 
380
  struct handle_option_ctx ctx;
 
381
  DBUG_ENTER("load_defaults");
 
382
 
 
383
  init_default_directories();
 
384
  init_alloc_root(&alloc,512,0);
 
385
  /*
 
386
    Check if the user doesn't want any default option processing
 
387
    --no-defaults is always the first option
 
388
  */
 
389
  if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
 
390
  {
 
391
    /* remove the --no-defaults argument and return only the other arguments */
 
392
    uint i;
 
393
    if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
 
394
                                 (*argc + 1)*sizeof(char*))))
 
395
      goto err;
 
396
    res= (char**) (ptr+sizeof(alloc));
 
397
    res[0]= **argv;                             /* Copy program name */
 
398
    for (i=2 ; i < (uint) *argc ; i++)
 
399
      res[i-1]=argv[0][i];
 
400
    res[i-1]=0;                                 /* End pointer */
 
401
    (*argc)--;
 
402
    *argv=res;
 
403
    *(MEM_ROOT*) ptr= alloc;                    /* Save alloc root for free */
 
404
    DBUG_RETURN(0);
 
405
  }
 
406
 
 
407
  group.count=0;
 
408
  group.name= "defaults";
 
409
  group.type_names= groups;
 
410
 
 
411
  for (; *groups ; groups++)
 
412
    group.count++;
 
413
 
 
414
  if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
 
415
    goto err;
 
416
 
 
417
  ctx.alloc= &alloc;
 
418
  ctx.args= &args;
 
419
  ctx.group= &group;
 
420
 
 
421
  error= my_search_option_files(conf_file, argc, argv, &args_used,
 
422
                                handle_default_option, (void *) &ctx);
 
423
  /*
 
424
    Here error contains <> 0 only if we have a fully specified conf_file
 
425
    or a forced default file
 
426
  */
 
427
  if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
 
428
                               (args.elements + *argc +1) *sizeof(char*))))
 
429
    goto err;
 
430
  res= (char**) (ptr+sizeof(alloc));
 
431
 
 
432
  /* copy name + found arguments + command line arguments to new array */
 
433
  res[0]= argv[0][0];  /* Name MUST be set, even by embedded library */
 
434
  memcpy((uchar*) (res+1), args.buffer, args.elements*sizeof(char*));
 
435
  /* Skip --defaults-xxx options */
 
436
  (*argc)-= args_used;
 
437
  (*argv)+= args_used;
 
438
 
 
439
  /*
 
440
    Check if we wan't to see the new argument list
 
441
    This options must always be the last of the default options
 
442
  */
 
443
  if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
 
444
  {
 
445
    found_print_defaults=1;
 
446
    --*argc; ++*argv;                           /* skip argument */
 
447
  }
 
448
 
 
449
  if (*argc)
 
450
    memcpy((uchar*) (res+1+args.elements), (char*) ((*argv)+1),
 
451
           (*argc-1)*sizeof(char*));
 
452
  res[args.elements+ *argc]=0;                  /* last null */
 
453
 
 
454
  (*argc)+=args.elements;
 
455
  *argv= (char**) res;
 
456
  *(MEM_ROOT*) ptr= alloc;                      /* Save alloc root for free */
 
457
  delete_dynamic(&args);
 
458
  if (found_print_defaults)
 
459
  {
 
460
    int i;
 
461
    printf("%s would have been started with the following arguments:\n",
 
462
           **argv);
 
463
    for (i=1 ; i < *argc ; i++)
 
464
      printf("%s ", (*argv)[i]);
 
465
    puts("");
 
466
    exit(0);
 
467
  }
 
468
  DBUG_RETURN(error);
 
469
 
 
470
 err:
 
471
  fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
 
472
  exit(1);
 
473
  return 0;                                     /* Keep compiler happy */
 
474
}
 
475
 
 
476
 
 
477
void free_defaults(char **argv)
 
478
{
 
479
  MEM_ROOT ptr;
 
480
  memcpy_fixed((char*) &ptr,(char *) argv - sizeof(ptr), sizeof(ptr));
 
481
  free_root(&ptr,MYF(0));
 
482
}
 
483
 
 
484
 
 
485
static int search_default_file(Process_option_func opt_handler,
 
486
                               void *handler_ctx,
 
487
                               const char *dir,
 
488
                               const char *config_file)
 
489
{
 
490
  char **ext;
 
491
  const char *empty_list[]= { "", 0 };
 
492
  my_bool have_ext= fn_ext(config_file)[0] != 0;
 
493
  const char **exts_to_use= have_ext ? empty_list : f_extensions;
 
494
 
 
495
  for (ext= (char**) exts_to_use; *ext; ext++)
 
496
  {
 
497
    int error;
 
498
    if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
 
499
                                             dir, *ext,
 
500
                                             config_file, 0)) < 0)
 
501
      return error;
 
502
  }
 
503
  return 0;
 
504
}
 
505
 
 
506
 
 
507
/*
 
508
  Skip over keyword and get argument after keyword
 
509
 
 
510
  SYNOPSIS
 
511
   get_argument()
 
512
   keyword              Include directive keyword
 
513
   kwlen                Length of keyword
 
514
   ptr                  Pointer to the keword in the line under process
 
515
   line                 line number
 
516
 
 
517
  RETURN
 
518
   0    error
 
519
   #    Returns pointer to the argument after the keyword.
 
520
*/
 
521
 
 
522
static char *get_argument(const char *keyword, size_t kwlen,
 
523
                          char *ptr, char *name, uint line)
 
524
{
 
525
  char *end;
 
526
 
 
527
  /* Skip over "include / includedir keyword" and following whitespace */
 
528
 
 
529
  for (ptr+= kwlen - 1;
 
530
       my_isspace(&my_charset_latin1, ptr[0]);
 
531
       ptr++)
 
532
  {}
 
533
 
 
534
  /*
 
535
    Trim trailing whitespace from directory name
 
536
    The -1 below is for the newline added by fgets()
 
537
    Note that my_isspace() is true for \r and \n
 
538
  */
 
539
  for (end= ptr + strlen(ptr) - 1;
 
540
       my_isspace(&my_charset_latin1, *(end - 1));
 
541
       end--)
 
542
  {}
 
543
  end[0]= 0;                                    /* Cut off end space */
 
544
 
 
545
  /* Print error msg if there is nothing after !include* directive */
 
546
  if (end <= ptr)
 
547
  {
 
548
    fprintf(stderr,
 
549
            "error: Wrong '!%s' directive in config file: %s at line %d\n",
 
550
            keyword, name, line);
 
551
    return 0;
 
552
  }
 
553
  return ptr;
 
554
}
 
555
 
 
556
 
 
557
/*
 
558
  Open a configuration file (if exists) and read given options from it
 
559
 
 
560
  SYNOPSIS
 
561
    search_default_file_with_ext()
 
562
    opt_handler                 Option handler function. It is used to process
 
563
                                every separate option.
 
564
    handler_ctx                 Pointer to the structure to store actual 
 
565
                                parameters of the function.
 
566
    dir                         directory to read
 
567
    ext                         Extension for configuration file
 
568
    config_file                 Name of configuration file
 
569
    group                       groups to read
 
570
    recursion_level             the level of recursion, got while processing
 
571
                                "!include" or "!includedir"
 
572
 
 
573
  RETURN
 
574
    0   Success
 
575
    -1  Fatal error, abort
 
576
     1  File not found (Warning)
 
577
*/
 
578
 
 
579
static int search_default_file_with_ext(Process_option_func opt_handler,
 
580
                                        void *handler_ctx,
 
581
                                        const char *dir,
 
582
                                        const char *ext,
 
583
                                        const char *config_file,
 
584
                                        int recursion_level)
 
585
{
 
586
  char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
 
587
  char *value, option[4096], tmp[FN_REFLEN];
 
588
  static const char includedir_keyword[]= "includedir";
 
589
  static const char include_keyword[]= "include";
 
590
  const int max_recursion_level= 10;
 
591
  FILE *fp;
 
592
  uint line=0;
 
593
  my_bool found_group=0;
 
594
  uint i;
 
595
  MY_DIR *search_dir;
 
596
  FILEINFO *search_file;
 
597
 
 
598
  if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
 
599
    return 0;                                   /* Ignore wrong paths */
 
600
  if (dir)
 
601
  {
 
602
    end=convert_dirname(name, dir, NullS);
 
603
    if (dir[0] == FN_HOMELIB)           /* Add . to filenames in home */
 
604
      *end++='.';
 
605
    strxmov(end,config_file,ext,NullS);
 
606
  }
 
607
  else
 
608
  {
 
609
    strmov(name,config_file);
 
610
  }
 
611
  fn_format(name,name,"","",4);
 
612
  {
 
613
    MY_STAT stat_info;
 
614
    if (!my_stat(name,&stat_info,MYF(0)))
 
615
      return 1;
 
616
    /*
 
617
      Ignore world-writable regular files.
 
618
      This is mainly done to protect us to not read a file created by
 
619
      the mysqld server, but the check is still valid in most context. 
 
620
    */
 
621
    if ((stat_info.st_mode & S_IWOTH) &&
 
622
        (stat_info.st_mode & S_IFMT) == S_IFREG)
 
623
    {
 
624
      fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
 
625
              name);
 
626
      return 0;
 
627
    }
 
628
  }
 
629
  if (!(fp= my_fopen(name, O_RDONLY, MYF(0))))
 
630
    return 1;                                   /* Ignore wrong files */
 
631
 
 
632
  while (fgets(buff, sizeof(buff) - 1, fp))
 
633
  {
 
634
    line++;
 
635
    /* Ignore comment and empty lines */
 
636
    for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++)
 
637
    {}
 
638
 
 
639
    if (*ptr == '#' || *ptr == ';' || !*ptr)
 
640
      continue;
 
641
 
 
642
    /* Configuration File Directives */
 
643
    if ((*ptr == '!'))
 
644
    {
 
645
      if (recursion_level >= max_recursion_level)
 
646
      {
 
647
        for (end= ptr + strlen(ptr) - 1; 
 
648
             my_isspace(&my_charset_latin1, *(end - 1));
 
649
             end--)
 
650
        {}
 
651
        end[0]= 0;
 
652
        fprintf(stderr,
 
653
                "Warning: skipping '%s' directive as maximum include"
 
654
                "recursion level was reached in file %s at line %d\n",
 
655
                ptr, name, line);
 
656
        continue;
 
657
      }
 
658
 
 
659
      /* skip over `!' and following whitespace */
 
660
      for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++)
 
661
      {}
 
662
 
 
663
      if ((!strncmp(ptr, includedir_keyword,
 
664
                    sizeof(includedir_keyword) - 1)) &&
 
665
          my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1]))
 
666
      {
 
667
        if (!(ptr= get_argument(includedir_keyword,
 
668
                                sizeof(includedir_keyword),
 
669
                                ptr, name, line)))
 
670
          goto err;
 
671
 
 
672
        if (!(search_dir= my_dir(ptr, MYF(MY_WME))))
 
673
          goto err;
 
674
 
 
675
        for (i= 0; i < (uint) search_dir->number_off_files; i++)
 
676
        {
 
677
          search_file= search_dir->dir_entry + i;
 
678
          ext= fn_ext(search_file->name);
 
679
 
 
680
          /* check extension */
 
681
          for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
 
682
          {
 
683
            if (!strcmp(ext, *tmp_ext))
 
684
              break;
 
685
          }
 
686
 
 
687
          if (*tmp_ext)
 
688
          {
 
689
            fn_format(tmp, search_file->name, ptr, "",
 
690
                      MY_UNPACK_FILENAME | MY_SAFE_PATH);
 
691
 
 
692
            search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp,
 
693
                                         recursion_level + 1);
 
694
          }
 
695
        }
 
696
 
 
697
        my_dirend(search_dir);
 
698
      }
 
699
      else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
 
700
               my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1]))
 
701
      {
 
702
        if (!(ptr= get_argument(include_keyword,
 
703
                                sizeof(include_keyword), ptr,
 
704
                                name, line)))
 
705
          goto err;
 
706
 
 
707
        search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
 
708
                                     recursion_level + 1);
 
709
      }
 
710
 
 
711
      continue;
 
712
    }
 
713
 
 
714
    if (*ptr == '[')                            /* Group name */
 
715
    {
 
716
      found_group=1;
 
717
      if (!(end=(char *) strchr(++ptr,']')))
 
718
      {
 
719
        fprintf(stderr,
 
720
                "error: Wrong group definition in config file: %s at line %d\n",
 
721
                name,line);
 
722
        goto err;
 
723
      }
 
724
      /* Remove end space */
 
725
      for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
 
726
      end[0]=0;
 
727
 
 
728
      strmake(curr_gr, ptr, min((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
 
729
 
 
730
      /* signal that a new group is found */
 
731
      opt_handler(handler_ctx, curr_gr, NULL);
 
732
 
 
733
      continue;
 
734
    }
 
735
    if (!found_group)
 
736
    {
 
737
      fprintf(stderr,
 
738
              "error: Found option without preceding group in config file: %s at line: %d\n",
 
739
              name,line);
 
740
      goto err;
 
741
    }
 
742
    
 
743
   
 
744
    end= remove_end_comment(ptr);
 
745
    if ((value= strchr(ptr, '=')))
 
746
      end= value;                               /* Option without argument */
 
747
    for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
 
748
    if (!value)
 
749
    {
 
750
      strmake(strmov(option,"--"),ptr, (size_t) (end-ptr));
 
751
      if (opt_handler(handler_ctx, curr_gr, option))
 
752
        goto err;
 
753
    }
 
754
    else
 
755
    {
 
756
      /* Remove pre- and end space */
 
757
      char *value_end;
 
758
      for (value++ ; my_isspace(&my_charset_latin1,*value); value++) ;
 
759
      value_end=strend(value);
 
760
      /*
 
761
        We don't have to test for value_end >= value as we know there is
 
762
        an '=' before
 
763
      */
 
764
      for ( ; my_isspace(&my_charset_latin1,value_end[-1]) ; value_end--) ;
 
765
      if (value_end < value)                    /* Empty string */
 
766
        value_end=value;
 
767
 
 
768
      /* remove quotes around argument */
 
769
      if ((*value == '\"' || *value == '\'') && /* First char is quote */
 
770
          (value + 1 < value_end ) && /* String is longer than 1 */
 
771
          *value == value_end[-1] ) /* First char is equal to last char */
 
772
      {
 
773
        value++;
 
774
        value_end--;
 
775
      }
 
776
      ptr=strnmov(strmov(option,"--"),ptr,(size_t) (end-ptr));
 
777
      *ptr++= '=';
 
778
 
 
779
      for ( ; value != value_end; value++)
 
780
      {
 
781
        if (*value == '\\' && value != value_end-1)
 
782
        {
 
783
          switch(*++value) {
 
784
          case 'n':
 
785
            *ptr++='\n';
 
786
            break;
 
787
          case 't':
 
788
            *ptr++= '\t';
 
789
            break;
 
790
          case 'r':
 
791
            *ptr++ = '\r';
 
792
            break;
 
793
          case 'b':
 
794
            *ptr++ = '\b';
 
795
            break;
 
796
          case 's':
 
797
            *ptr++= ' ';                        /* space */
 
798
            break;
 
799
          case '\"':
 
800
            *ptr++= '\"';
 
801
            break;
 
802
          case '\'':
 
803
            *ptr++= '\'';
 
804
            break;
 
805
          case '\\':
 
806
            *ptr++= '\\';
 
807
            break;
 
808
          default:                              /* Unknown; Keep '\' */
 
809
            *ptr++= '\\';
 
810
            *ptr++= *value;
 
811
            break;
 
812
          }
 
813
        }
 
814
        else
 
815
          *ptr++= *value;
 
816
      }
 
817
      *ptr=0;
 
818
      if (opt_handler(handler_ctx, curr_gr, option))
 
819
        goto err;
 
820
    }
 
821
  }
 
822
  my_fclose(fp,MYF(0));
 
823
  return(0);
 
824
 
 
825
 err:
 
826
  my_fclose(fp,MYF(0));
 
827
  return -1;                                    /* Fatal error */
 
828
}
 
829
 
 
830
 
 
831
static char *remove_end_comment(char *ptr)
 
832
{
 
833
  char quote= 0;        /* we are inside quote marks */
 
834
  char escape= 0;       /* symbol is protected by escape chagacter */
 
835
 
 
836
  for (; *ptr; ptr++)
 
837
  {
 
838
    if ((*ptr == '\'' || *ptr == '\"') && !escape)
 
839
    {
 
840
      if (!quote)
 
841
        quote= *ptr;
 
842
      else if (quote == *ptr)
 
843
        quote= 0;
 
844
    }
 
845
    /* We are not inside a string */
 
846
    if (!quote && *ptr == '#')
 
847
    {
 
848
      *ptr= 0;
 
849
      return ptr;
 
850
    }
 
851
    escape= (quote && *ptr == '\\' && !escape);
 
852
  }
 
853
  return ptr;
 
854
}
 
855
 
 
856
#include <help_start.h>
 
857
 
 
858
void my_print_default_files(const char *conf_file)
 
859
{
 
860
  const char *empty_list[]= { "", 0 };
 
861
  my_bool have_ext= fn_ext(conf_file)[0] != 0;
 
862
  const char **exts_to_use= have_ext ? empty_list : f_extensions;
 
863
  char name[FN_REFLEN], **ext;
 
864
  const char **dirs;
 
865
 
 
866
  init_default_directories();
 
867
  puts("\nDefault options are read from the following files in the given order:");
 
868
 
 
869
  if (dirname_length(conf_file))
 
870
    fputs(conf_file,stdout);
 
871
  else
 
872
  {
 
873
    for (dirs=default_directories ; *dirs; dirs++)
 
874
    {
 
875
      for (ext= (char**) exts_to_use; *ext; ext++)
 
876
      {
 
877
        const char *pos;
 
878
        char *end;
 
879
        if (**dirs)
 
880
          pos= *dirs;
 
881
        else if (my_defaults_extra_file)
 
882
          pos= my_defaults_extra_file;
 
883
        else
 
884
          continue;
 
885
        end= convert_dirname(name, pos, NullS);
 
886
        if (name[0] == FN_HOMELIB)      /* Add . to filenames in home */
 
887
          *end++='.';
 
888
        strxmov(end, conf_file, *ext, " ", NullS);
 
889
        fputs(name,stdout);
 
890
      }
 
891
    }
 
892
  }
 
893
  puts("");
 
894
}
 
895
 
 
896
void print_defaults(const char *conf_file, const char **groups)
 
897
{
 
898
  const char **groups_save= groups;
 
899
  my_print_default_files(conf_file);
 
900
 
 
901
  fputs("The following groups are read:",stdout);
 
902
  for ( ; *groups ; groups++)
 
903
  {
 
904
    fputc(' ',stdout);
 
905
    fputs(*groups,stdout);
 
906
  }
 
907
 
 
908
  if (my_defaults_group_suffix)
 
909
  {
 
910
    groups= groups_save;
 
911
    for ( ; *groups ; groups++)
 
912
    {
 
913
      fputc(' ',stdout);
 
914
      fputs(*groups,stdout);
 
915
      fputs(my_defaults_group_suffix,stdout);
 
916
    }
 
917
  }
 
918
  puts("\nThe following options may be given as the first argument:\n\
 
919
--print-defaults        Print the program argument list and exit\n\
 
920
--no-defaults           Don't read default options from any options file\n\
 
921
--defaults-file=#       Only read default options from the given file #\n\
 
922
--defaults-extra-file=# Read this file after the global files are read");
 
923
}
 
924
 
 
925
#include <help_end.h>
 
926
 
 
927
 
 
928
/*
 
929
  This extra complexity is to avoid declaring 'rc' if it won't be
 
930
  used.
 
931
*/
 
932
#define ADD_DIRECTORY_INTERNAL(DIR) \
 
933
  array_append_string_unique((DIR), default_directories, \
 
934
                             array_elements(default_directories))
 
935
#ifdef DBUG_OFF
 
936
#  define ADD_DIRECTORY(DIR)  (void) ADD_DIRECTORY_INTERNAL(DIR)
 
937
#else
 
938
#define ADD_DIRECTORY(DIR) \
 
939
  do { \
 
940
    my_bool rc= ADD_DIRECTORY_INTERNAL(DIR); \
 
941
    DBUG_ASSERT(rc == FALSE);                   /* Success */ \
 
942
  } while (0)
 
943
#endif
 
944
 
 
945
 
 
946
#define ADD_COMMON_DIRECTORIES() \
 
947
  do { \
 
948
    char *env; \
 
949
    if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) \
 
950
      ADD_DIRECTORY(env); \
 
951
    /* Placeholder for --defaults-extra-file=<path> */ \
 
952
    ADD_DIRECTORY(""); \
 
953
  } while (0)
 
954
 
 
955
 
 
956
/**
 
957
  Initialize default directories for Unix
 
958
 
 
959
  @details
 
960
    1. /etc/
 
961
    2. /etc/mysql/
 
962
    3. --sysconfdir=<path> (compile-time option)
 
963
    4. getenv(DEFAULT_HOME_ENV)
 
964
    5. --defaults-extra-file=<path> (run-time option)
 
965
    6. "~/"
 
966
*/
 
967
 
 
968
static void init_default_directories_unix()
 
969
{
 
970
  bzero((char *) default_directories, sizeof(default_directories));
 
971
  ADD_DIRECTORY("/etc/");
 
972
  ADD_DIRECTORY("/etc/mysql/");
 
973
#ifdef DEFAULT_SYSCONFDIR
 
974
  if (DEFAULT_SYSCONFDIR != "")
 
975
    ADD_DIRECTORY(DEFAULT_SYSCONFDIR);
 
976
#endif
 
977
  ADD_COMMON_DIRECTORIES();
 
978
  ADD_DIRECTORY("~/");
 
979
}
 
980
 
 
981
static void (*init_default_directories)()= init_default_directories_unix;