~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
53.2.19 by Monty Taylor
Fixed prototypes. Cleaned define a little bit.
90
static void (*init_default_directories)(void);
1 by brian
clean slate
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;
146 by Brian Aker
my_bool cleanup.
375
  bool found_print_defaults= 0;
1 by brian
clean slate
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 };
146 by Brian Aker
my_bool cleanup.
492
  bool have_ext= fn_ext(config_file)[0] != 0;
1 by brian
clean slate
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;
146 by Brian Aker
my_bool cleanup.
593
  bool found_group=0;
1 by brian
clean slate
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
  {
15 by brian
Fix for stat, NETWARE removal
613
    struct stat stat_info;
614
    if (stat(name,&stat_info))
1 by brian
clean slate
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 };
146 by Brian Aker
my_bool cleanup.
861
  bool have_ext= fn_ext(conf_file)[0] != 0;
1 by brian
clean slate
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 { \
146 by Brian Aker
my_bool cleanup.
940
    bool rc= ADD_DIRECTORY_INTERNAL(DIR); \
1 by brian
clean slate
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
53.2.19 by Monty Taylor
Fixed prototypes. Cleaned define a little bit.
968
static void init_default_directories_unix(void)
1 by brian
clean slate
969
{
970
  bzero((char *) default_directories, sizeof(default_directories));
971
  ADD_DIRECTORY("/etc/");
972
  ADD_DIRECTORY("/etc/mysql/");
53.2.19 by Monty Taylor
Fixed prototypes. Cleaned define a little bit.
973
#if defined(DEFAULT_SYSCONFDIR)
1 by brian
clean slate
974
    ADD_DIRECTORY(DEFAULT_SYSCONFDIR);
975
#endif
976
  ADD_COMMON_DIRECTORIES();
977
  ADD_DIRECTORY("~/");
978
}
979
53.2.19 by Monty Taylor
Fixed prototypes. Cleaned define a little bit.
980
static void (*init_default_directories)(void)= init_default_directories_unix;