00001 /* Copyright (C) 2000-2003 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 /**************************************************************************** 00018 Add all options from files named "group".cnf from the default_directories 00019 before the command line arguments. 00020 On Windows defaults will also search in the Windows directory for a file 00021 called 'group'.ini 00022 As long as the program uses the last argument for conflicting 00023 options one only have to add a call to "load_defaults" to enable 00024 use of default values. 00025 pre- and end 'blank space' are removed from options and values. The 00026 following escape sequences are recognized in values: \b \t \n \r \\ 00027 00028 The following arguments are handled automaticly; If used, they must be 00029 first argument on the command line! 00030 --no-defaults ; no options are read. 00031 --defaults-file=full-path-to-default-file ; Only this file will be read. 00032 --defaults-extra-file=full-path-to-default-file ; Read this file before ~/ 00033 --defaults-group-suffix ; Also read groups with concat(group, suffix) 00034 --print-defaults ; Print the modified command line and exit 00035 ****************************************************************************/ 00036 00037 #include "mysys_priv.h" 00038 #include "m_string.h" 00039 #include "m_ctype.h" 00040 #include <my_dir.h> 00041 #ifdef __WIN__ 00042 #include <winbase.h> 00043 #endif 00044 00045 const char *defaults_file=0; 00046 const char *defaults_group_suffix=0; 00047 char *defaults_extra_file=0; 00048 00049 /* Which directories are searched for options (and in which order) */ 00050 00051 #define MAX_DEFAULT_DIRS 7 00052 const char *default_directories[MAX_DEFAULT_DIRS + 1]; 00053 00054 #ifdef __WIN__ 00055 static const char *f_extensions[]= { ".ini", ".cnf", 0 }; 00056 #define NEWLINE "\r\n" 00057 static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN], 00058 config_dir[FN_REFLEN]; 00059 #else 00060 static const char *f_extensions[]= { ".cnf", 0 }; 00061 #define NEWLINE "\n" 00062 #endif 00063 00064 static int handle_default_option(void *in_ctx, const char *group_name, 00065 const char *option); 00066 00067 /* 00068 This structure defines the context that we pass to callback 00069 function 'handle_default_option' used in search_default_file 00070 to process each option. This context is used if search_default_file 00071 was called from load_defaults. 00072 */ 00073 00074 struct handle_option_ctx 00075 { 00076 MEM_ROOT *alloc; 00077 DYNAMIC_ARRAY *args; 00078 TYPELIB *group; 00079 }; 00080 00081 static int search_default_file(Process_option_func func, void *func_ctx, 00082 const char *dir, const char *config_file); 00083 static int search_default_file_with_ext(Process_option_func func, 00084 void *func_ctx, 00085 const char *dir, const char *ext, 00086 const char *config_file, int recursion_level); 00087 static void init_default_directories(); 00088 00089 static char *remove_end_comment(char *ptr); 00090 00091 00092 /* 00093 Process config files in default directories. 00094 00095 SYNOPSIS 00096 my_search_option_files() 00097 conf_file Basename for configuration file to search for. 00098 If this is a path, then only this file is read. 00099 argc Pointer to argc of original program 00100 argv Pointer to argv of original program 00101 args_used Pointer to variable for storing the number of 00102 arguments used. 00103 func Pointer to the function to process options 00104 func_ctx It's context. Usually it is the structure to 00105 store additional options. 00106 DESCRIPTION 00107 Process the default options from argc & argv 00108 Read through each found config file looks and calls 'func' to process 00109 each option. 00110 00111 NOTES 00112 --defaults-group-suffix is only processed if we are called from 00113 load_defaults(). 00114 00115 00116 RETURN 00117 0 ok 00118 1 given cinf_file doesn't exist 00119 00120 The global variable 'defaults_group_suffix' is updated with value for 00121 --defaults_group_suffix 00122 */ 00123 00124 int my_search_option_files(const char *conf_file, int *argc, char ***argv, 00125 uint *args_used, Process_option_func func, 00126 void *func_ctx) 00127 { 00128 const char **dirs, *forced_default_file, *forced_extra_defaults; 00129 int error= 0; 00130 DBUG_ENTER("my_search_option_files"); 00131 00132 /* Check if we want to force the use a specific default file */ 00133 *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used, 00134 (char **) &forced_default_file, 00135 (char **) &forced_extra_defaults, 00136 (char **) &defaults_group_suffix); 00137 00138 if (! defaults_group_suffix) 00139 defaults_group_suffix= getenv(STRINGIFY_ARG(DEFAULT_GROUP_SUFFIX_ENV)); 00140 00141 if (forced_extra_defaults) 00142 defaults_extra_file= (char *) forced_extra_defaults; 00143 00144 if (forced_default_file) 00145 defaults_file= forced_default_file; 00146 00147 /* 00148 We can only handle 'defaults-group-suffix' if we are called from 00149 load_defaults() as otherwise we can't know the type of 'func_ctx' 00150 */ 00151 00152 if (defaults_group_suffix && func == handle_default_option) 00153 { 00154 /* Handle --defaults-group-suffix= */ 00155 uint i; 00156 const char **extra_groups; 00157 const uint instance_len= strlen(defaults_group_suffix); 00158 struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx; 00159 char *ptr; 00160 TYPELIB *group= ctx->group; 00161 00162 if (!(extra_groups= 00163 (const char**)alloc_root(ctx->alloc, 00164 (2*group->count+1)*sizeof(char*)))) 00165 goto err; 00166 00167 for (i= 0; i < group->count; i++) 00168 { 00169 uint len; 00170 extra_groups[i]= group->type_names[i]; 00172 len= strlen(extra_groups[i]); 00173 if (!(ptr= alloc_root(ctx->alloc, len+instance_len+1))) 00174 goto err; 00175 00176 extra_groups[i+group->count]= ptr; 00177 00179 memcpy(ptr, extra_groups[i], len); 00180 memcpy(ptr+len, defaults_group_suffix, instance_len+1); 00181 } 00182 00183 group->count*= 2; 00184 group->type_names= extra_groups; 00185 group->type_names[group->count]= 0; 00186 } 00187 00188 if (forced_default_file) 00189 { 00190 if ((error= search_default_file_with_ext(func, func_ctx, "", "", 00191 forced_default_file, 0)) < 0) 00192 goto err; 00193 if (error > 0) 00194 { 00195 fprintf(stderr, "Could not open required defaults file: %s\n", 00196 forced_default_file); 00197 goto err; 00198 } 00199 } 00200 else if (dirname_length(conf_file)) 00201 { 00202 if ((error= search_default_file(func, func_ctx, NullS, conf_file)) < 0) 00203 goto err; 00204 } 00205 else 00206 { 00207 for (dirs= default_directories ; *dirs; dirs++) 00208 { 00209 if (**dirs) 00210 { 00211 if (search_default_file(func, func_ctx, *dirs, conf_file) < 0) 00212 goto err; 00213 } 00214 else if (defaults_extra_file) 00215 { 00216 if ((error= search_default_file_with_ext(func, func_ctx, "", "", 00217 defaults_extra_file, 0)) < 0) 00218 goto err; /* Fatal error */ 00219 if (error > 0) 00220 { 00221 fprintf(stderr, "Could not open required defaults file: %s\n", 00222 defaults_extra_file); 00223 goto err; 00224 } 00225 } 00226 } 00227 } 00228 00229 DBUG_RETURN(error); 00230 00231 err: 00232 fprintf(stderr,"Fatal error in defaults handling. Program aborted\n"); 00233 exit(1); 00234 return 0; /* Keep compiler happy */ 00235 } 00236 00237 00238 /* 00239 The option handler for load_defaults. 00240 00241 SYNOPSIS 00242 handle_deault_option() 00243 in_ctx Handler context. In this case it is a 00244 handle_option_ctx structure. 00245 group_name The name of the group the option belongs to. 00246 option The very option to be processed. It is already 00247 prepared to be used in argv (has -- prefix). If it 00248 is NULL, we are handling a new group (section). 00249 00250 DESCRIPTION 00251 This handler checks whether a group is one of the listed and adds an option 00252 to the array if yes. Some other handler can record, for instance, all 00253 groups and their options, not knowing in advance the names and amount of 00254 groups. 00255 00256 RETURN 00257 0 - ok 00258 1 - error occured 00259 */ 00260 00261 static int handle_default_option(void *in_ctx, const char *group_name, 00262 const char *option) 00263 { 00264 char *tmp; 00265 struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx; 00266 00267 if (!option) 00268 return 0; 00269 00270 if (find_type((char *)group_name, ctx->group, 3)) 00271 { 00272 if (!(tmp= alloc_root(ctx->alloc, (uint) strlen(option) + 1))) 00273 return 1; 00274 if (insert_dynamic(ctx->args, (gptr) &tmp)) 00275 return 1; 00276 strmov(tmp, option); 00277 } 00278 00279 return 0; 00280 } 00281 00282 00283 /* 00284 Gets options from the command line 00285 00286 SYNOPSIS 00287 get_defaults_options() 00288 argc Pointer to argc of original program 00289 argv Pointer to argv of original program 00290 defaults --defaults-file option 00291 extra_defaults --defaults-extra-file option 00292 00293 RETURN 00294 # Number of arguments used from *argv 00295 defaults and extra_defaults will be set to option of the appropriate 00296 items of argv array, or to NULL if there are no such options 00297 */ 00298 00299 int get_defaults_options(int argc, char **argv, 00300 char **defaults, 00301 char **extra_defaults, 00302 char **group_suffix) 00303 { 00304 int org_argc= argc, prev_argc= 0; 00305 *defaults= *extra_defaults= *group_suffix= 0; 00306 00307 while (argc >= 2 && argc != prev_argc) 00308 { 00309 /* Skip program name or previously handled argument */ 00310 argv++; 00311 prev_argc= argc; /* To check if we found */ 00312 if (!*defaults && is_prefix(*argv,"--defaults-file=")) 00313 { 00314 *defaults= *argv + sizeof("--defaults-file=")-1; 00315 argc--; 00316 continue; 00317 } 00318 if (!*extra_defaults && is_prefix(*argv,"--defaults-extra-file=")) 00319 { 00320 *extra_defaults= *argv + sizeof("--defaults-extra-file=")-1; 00321 argc--; 00322 continue; 00323 } 00324 if (!*group_suffix && is_prefix(*argv, "--defaults-group-suffix=")) 00325 { 00326 *group_suffix= *argv + sizeof("--defaults-group-suffix=")-1; 00327 argc--; 00328 continue; 00329 } 00330 } 00331 return org_argc - argc; 00332 } 00333 00334 00335 /* 00336 Read options from configurations files 00337 00338 SYNOPSIS 00339 load_defaults() 00340 conf_file Basename for configuration file to search for. 00341 If this is a path, then only this file is read. 00342 groups Which [group] entrys to read. 00343 Points to an null terminated array of pointers 00344 argc Pointer to argc of original program 00345 argv Pointer to argv of original program 00346 00347 IMPLEMENTATION 00348 00349 Read options from configuration files and put them BEFORE the arguments 00350 that are already in argc and argv. This way the calling program can 00351 easily command line options override options in configuration files 00352 00353 NOTES 00354 In case of fatal error, the function will print a warning and do 00355 exit(1) 00356 00357 To free used memory one should call free_defaults() with the argument 00358 that was put in *argv 00359 00360 RETURN 00361 0 ok 00362 1 The given conf_file didn't exists 00363 */ 00364 00365 00366 int load_defaults(const char *conf_file, const char **groups, 00367 int *argc, char ***argv) 00368 { 00369 DYNAMIC_ARRAY args; 00370 TYPELIB group; 00371 my_bool found_print_defaults= 0; 00372 uint args_used= 0; 00373 int error= 0; 00374 MEM_ROOT alloc; 00375 char *ptr,**res; 00376 struct handle_option_ctx ctx; 00377 DBUG_ENTER("load_defaults"); 00378 00379 init_default_directories(); 00380 init_alloc_root(&alloc,512,0); 00381 /* 00382 Check if the user doesn't want any default option processing 00383 --no-defaults is always the first option 00384 */ 00385 if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults")) 00386 { 00387 /* remove the --no-defaults argument and return only the other arguments */ 00388 uint i; 00389 if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+ 00390 (*argc + 1)*sizeof(char*)))) 00391 goto err; 00392 res= (char**) (ptr+sizeof(alloc)); 00393 res[0]= **argv; /* Copy program name */ 00394 for (i=2 ; i < (uint) *argc ; i++) 00395 res[i-1]=argv[0][i]; 00396 res[i-1]=0; /* End pointer */ 00397 (*argc)--; 00398 *argv=res; 00399 *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */ 00400 DBUG_RETURN(0); 00401 } 00402 00403 group.count=0; 00404 group.name= "defaults"; 00405 group.type_names= groups; 00406 00407 for (; *groups ; groups++) 00408 group.count++; 00409 00410 if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32)) 00411 goto err; 00412 00413 ctx.alloc= &alloc; 00414 ctx.args= &args; 00415 ctx.group= &group; 00416 00417 error= my_search_option_files(conf_file, argc, argv, &args_used, 00418 handle_default_option, (void *) &ctx); 00419 /* 00420 Here error contains <> 0 only if we have a fully specified conf_file 00421 or a forced default file 00422 */ 00423 if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+ 00424 (args.elements + *argc +1) *sizeof(char*)))) 00425 goto err; 00426 res= (char**) (ptr+sizeof(alloc)); 00427 00428 /* copy name + found arguments + command line arguments to new array */ 00429 res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */ 00430 memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*)); 00431 /* Skip --defaults-xxx options */ 00432 (*argc)-= args_used; 00433 (*argv)+= args_used; 00434 00435 /* 00436 Check if we wan't to see the new argument list 00437 This options must always be the last of the default options 00438 */ 00439 if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults")) 00440 { 00441 found_print_defaults=1; 00442 --*argc; ++*argv; /* skip argument */ 00443 } 00444 00445 if (*argc) 00446 memcpy((gptr) (res+1+args.elements), (char*) ((*argv)+1), 00447 (*argc-1)*sizeof(char*)); 00448 res[args.elements+ *argc]=0; /* last null */ 00449 00450 (*argc)+=args.elements; 00451 *argv= (char**) res; 00452 *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */ 00453 delete_dynamic(&args); 00454 if (found_print_defaults) 00455 { 00456 int i; 00457 printf("%s would have been started with the following arguments:\n", 00458 **argv); 00459 for (i=1 ; i < *argc ; i++) 00460 printf("%s ", (*argv)[i]); 00461 puts(""); 00462 exit(0); 00463 } 00464 DBUG_RETURN(error); 00465 00466 err: 00467 fprintf(stderr,"Fatal error in defaults handling. Program aborted\n"); 00468 exit(1); 00469 return 0; /* Keep compiler happy */ 00470 } 00471 00472 00473 void free_defaults(char **argv) 00474 { 00475 MEM_ROOT ptr; 00476 memcpy_fixed((char*) &ptr,(char *) argv - sizeof(ptr), sizeof(ptr)); 00477 free_root(&ptr,MYF(0)); 00478 } 00479 00480 00481 static int search_default_file(Process_option_func opt_handler, 00482 void *handler_ctx, 00483 const char *dir, 00484 const char *config_file) 00485 { 00486 char **ext; 00487 const char *empty_list[]= { "", 0 }; 00488 my_bool have_ext= fn_ext(config_file)[0] != 0; 00489 const char **exts_to_use= have_ext ? empty_list : f_extensions; 00490 00491 for (ext= (char**) exts_to_use; *ext; *ext++) 00492 { 00493 int error; 00494 if ((error= search_default_file_with_ext(opt_handler, handler_ctx, 00495 dir, *ext, 00496 config_file, 0)) < 0) 00497 return error; 00498 } 00499 return 0; 00500 } 00501 00502 00503 /* 00504 Skip over keyword and get argument after keyword 00505 00506 SYNOPSIS 00507 get_argument() 00508 keyword Include directive keyword 00509 kwlen Length of keyword 00510 ptr Pointer to the keword in the line under process 00511 line line number 00512 00513 RETURN 00514 0 error 00515 # Returns pointer to the argument after the keyword. 00516 */ 00517 00518 static char *get_argument(const char *keyword, uint kwlen, 00519 char *ptr, char *name, uint line) 00520 { 00521 char *end; 00522 00523 /* Skip over "include / includedir keyword" and following whitespace */ 00524 00525 for (ptr+= kwlen - 1; 00526 my_isspace(&my_charset_latin1, ptr[0]); 00527 ptr++) 00528 {} 00529 00530 /* 00531 Trim trailing whitespace from directory name 00532 The -1 below is for the newline added by fgets() 00533 Note that my_isspace() is true for \r and \n 00534 */ 00535 for (end= ptr + strlen(ptr) - 1; 00536 my_isspace(&my_charset_latin1, *(end - 1)); 00537 end--) 00538 {} 00539 end[0]= 0; /* Cut off end space */ 00540 00541 /* Print error msg if there is nothing after !include* directive */ 00542 if (end <= ptr) 00543 { 00544 fprintf(stderr, 00545 "error: Wrong '!%s' directive in config file: %s at line %d\n", 00546 keyword, name, line); 00547 return 0; 00548 } 00549 return ptr; 00550 } 00551 00552 00553 /* 00554 Open a configuration file (if exists) and read given options from it 00555 00556 SYNOPSIS 00557 search_default_file_with_ext() 00558 opt_handler Option handler function. It is used to process 00559 every separate option. 00560 handler_ctx Pointer to the structure to store actual 00561 parameters of the function. 00562 dir directory to read 00563 ext Extension for configuration file 00564 config_file Name of configuration file 00565 group groups to read 00566 recursion_level the level of recursion, got while processing 00567 "!include" or "!includedir" 00568 00569 RETURN 00570 0 Success 00571 -1 Fatal error, abort 00572 1 File not found (Warning) 00573 */ 00574 00575 static int search_default_file_with_ext(Process_option_func opt_handler, 00576 void *handler_ctx, 00577 const char *dir, 00578 const char *ext, 00579 const char *config_file, 00580 int recursion_level) 00581 { 00582 char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext; 00583 char *value, option[4096], tmp[FN_REFLEN]; 00584 static const char includedir_keyword[]= "includedir"; 00585 static const char include_keyword[]= "include"; 00586 const int max_recursion_level= 10; 00587 FILE *fp; 00588 uint line=0; 00589 my_bool found_group=0; 00590 uint i; 00591 MY_DIR *search_dir; 00592 FILEINFO *search_file; 00593 00594 if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3) 00595 return 0; /* Ignore wrong paths */ 00596 if (dir) 00597 { 00598 end=convert_dirname(name, dir, NullS); 00599 if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */ 00600 *end++='.'; 00601 strxmov(end,config_file,ext,NullS); 00602 } 00603 else 00604 { 00605 strmov(name,config_file); 00606 } 00607 fn_format(name,name,"","",4); 00608 #if !defined(__WIN__) && !defined(__NETWARE__) 00609 { 00610 MY_STAT stat_info; 00611 if (!my_stat(name,&stat_info,MYF(0))) 00612 return 1; 00613 /* 00614 Ignore world-writable regular files. 00615 This is mainly done to protect us to not read a file created by 00616 the mysqld server, but the check is still valid in most context. 00617 */ 00618 if ((stat_info.st_mode & S_IWOTH) && 00619 (stat_info.st_mode & S_IFMT) == S_IFREG) 00620 { 00621 fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n", 00622 name); 00623 return 0; 00624 } 00625 } 00626 #endif 00627 if (!(fp= my_fopen(name, O_RDONLY, MYF(0)))) 00628 return 1; /* Ignore wrong files */ 00629 00630 while (fgets(buff, sizeof(buff) - 1, fp)) 00631 { 00632 line++; 00633 /* Ignore comment and empty lines */ 00634 for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++) 00635 {} 00636 00637 if (*ptr == '#' || *ptr == ';' || !*ptr) 00638 continue; 00639 00640 /* Configuration File Directives */ 00641 if ((*ptr == '!')) 00642 { 00643 if (recursion_level >= max_recursion_level) 00644 { 00645 for (end= ptr + strlen(ptr) - 1; 00646 my_isspace(&my_charset_latin1, *(end - 1)); 00647 end--) 00648 {} 00649 end[0]= 0; 00650 fprintf(stderr, 00651 "Warning: skipping '%s' directive as maximum include" 00652 "recursion level was reached in file %s at line %d\n", 00653 ptr, name, line); 00654 continue; 00655 } 00656 00657 /* skip over `!' and following whitespace */ 00658 for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++) 00659 {} 00660 00661 if ((!strncmp(ptr, includedir_keyword, 00662 sizeof(includedir_keyword) - 1)) && 00663 my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) 00664 { 00665 if (!(ptr= get_argument(includedir_keyword, 00666 sizeof(includedir_keyword), 00667 ptr, name, line))) 00668 goto err; 00669 00670 if (!(search_dir= my_dir(ptr, MYF(MY_WME)))) 00671 goto err; 00672 00673 for (i= 0; i < (uint) search_dir->number_off_files; i++) 00674 { 00675 search_file= search_dir->dir_entry + i; 00676 ext= fn_ext(search_file->name); 00677 00678 /* check extension */ 00679 for (tmp_ext= (char**) f_extensions; *tmp_ext; *tmp_ext++) 00680 { 00681 if (!strcmp(ext, *tmp_ext)) 00682 break; 00683 } 00684 00685 if (*tmp_ext) 00686 { 00687 fn_format(tmp, search_file->name, ptr, "", 00688 MY_UNPACK_FILENAME | MY_SAFE_PATH); 00689 00690 search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp, 00691 recursion_level + 1); 00692 } 00693 } 00694 00695 my_dirend(search_dir); 00696 } 00697 else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) && 00698 my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1])) 00699 { 00700 if (!(ptr= get_argument(include_keyword, 00701 sizeof(include_keyword), ptr, 00702 name, line))) 00703 goto err; 00704 00705 search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr, 00706 recursion_level + 1); 00707 } 00708 00709 continue; 00710 } 00711 00712 if (*ptr == '[') /* Group name */ 00713 { 00714 found_group=1; 00715 if (!(end=(char *) strchr(++ptr,']'))) 00716 { 00717 fprintf(stderr, 00718 "error: Wrong group definition in config file: %s at line %d\n", 00719 name,line); 00720 goto err; 00721 } 00722 for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;/* Remove end space */ 00723 end[0]=0; 00724 00725 strnmov(curr_gr, ptr, min((uint) (end-ptr)+1, 4096)); 00726 00727 /* signal that a new group is found */ 00728 opt_handler(handler_ctx, curr_gr, NULL); 00729 00730 continue; 00731 } 00732 if (!found_group) 00733 { 00734 fprintf(stderr, 00735 "error: Found option without preceding group in config file: %s at line: %d\n", 00736 name,line); 00737 goto err; 00738 } 00739 00740 00741 end= remove_end_comment(ptr); 00742 if ((value= strchr(ptr, '='))) 00743 end= value; /* Option without argument */ 00744 for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ; 00745 if (!value) 00746 { 00747 strmake(strmov(option,"--"),ptr,(uint) (end-ptr)); 00748 if (opt_handler(handler_ctx, curr_gr, option)) 00749 goto err; 00750 } 00751 else 00752 { 00753 /* Remove pre- and end space */ 00754 char *value_end; 00755 for (value++ ; my_isspace(&my_charset_latin1,*value); value++) ; 00756 value_end=strend(value); 00757 /* 00758 We don't have to test for value_end >= value as we know there is 00759 an '=' before 00760 */ 00761 for ( ; my_isspace(&my_charset_latin1,value_end[-1]) ; value_end--) ; 00762 if (value_end < value) /* Empty string */ 00763 value_end=value; 00764 00765 /* remove quotes around argument */ 00766 if ((*value == '\"' || *value == '\'') && /* First char is quote */ 00767 (value + 1 < value_end ) && /* String is longer than 1 */ 00768 *value == value_end[-1] ) /* First char is equal to last char */ 00769 { 00770 value++; 00771 value_end--; 00772 } 00773 ptr=strnmov(strmov(option,"--"),ptr,(uint) (end-ptr)); 00774 *ptr++= '='; 00775 00776 for ( ; value != value_end; value++) 00777 { 00778 if (*value == '\\' && value != value_end-1) 00779 { 00780 switch(*++value) { 00781 case 'n': 00782 *ptr++='\n'; 00783 break; 00784 case 't': 00785 *ptr++= '\t'; 00786 break; 00787 case 'r': 00788 *ptr++ = '\r'; 00789 break; 00790 case 'b': 00791 *ptr++ = '\b'; 00792 break; 00793 case 's': 00794 *ptr++= ' '; /* space */ 00795 break; 00796 case '\"': 00797 *ptr++= '\"'; 00798 break; 00799 case '\'': 00800 *ptr++= '\''; 00801 break; 00802 case '\\': 00803 *ptr++= '\\'; 00804 break; 00805 default: /* Unknown; Keep '\' */ 00806 *ptr++= '\\'; 00807 *ptr++= *value; 00808 break; 00809 } 00810 } 00811 else 00812 *ptr++= *value; 00813 } 00814 *ptr=0; 00815 if (opt_handler(handler_ctx, curr_gr, option)) 00816 goto err; 00817 } 00818 } 00819 my_fclose(fp,MYF(0)); 00820 return(0); 00821 00822 err: 00823 my_fclose(fp,MYF(0)); 00824 return -1; /* Fatal error */ 00825 } 00826 00827 00828 static char *remove_end_comment(char *ptr) 00829 { 00830 char quote= 0; /* we are inside quote marks */ 00831 char escape= 0; /* symbol is protected by escape chagacter */ 00832 00833 for (; *ptr; ptr++) 00834 { 00835 if ((*ptr == '\'' || *ptr == '\"') && !escape) 00836 { 00837 if (!quote) 00838 quote= *ptr; 00839 else if (quote == *ptr) 00840 quote= 0; 00841 } 00842 /* We are not inside a string */ 00843 if (!quote && *ptr == '#') 00844 { 00845 *ptr= 0; 00846 return ptr; 00847 } 00848 escape= (quote && *ptr == '\\' && !escape); 00849 } 00850 return ptr; 00851 } 00852 00853 #include <help_start.h> 00854 00855 void my_print_default_files(const char *conf_file) 00856 { 00857 const char *empty_list[]= { "", 0 }; 00858 my_bool have_ext= fn_ext(conf_file)[0] != 0; 00859 const char **exts_to_use= have_ext ? empty_list : f_extensions; 00860 char name[FN_REFLEN], **ext; 00861 const char **dirs; 00862 00863 init_default_directories(); 00864 puts("\nDefault options are read from the following files in the given order:"); 00865 00866 if (dirname_length(conf_file)) 00867 fputs(conf_file,stdout); 00868 else 00869 { 00870 for (dirs=default_directories ; *dirs; dirs++) 00871 { 00872 for (ext= (char**) exts_to_use; *ext; *ext++) 00873 { 00874 const char *pos; 00875 char *end; 00876 if (**dirs) 00877 pos= *dirs; 00878 else if (defaults_extra_file) 00879 pos= defaults_extra_file; 00880 else 00881 continue; 00882 end= convert_dirname(name, pos, NullS); 00883 if (name[0] == FN_HOMELIB) /* Add . to filenames in home */ 00884 *end++='.'; 00885 strxmov(end, conf_file, *ext, " ", NullS); 00886 fputs(name,stdout); 00887 } 00888 } 00889 puts(""); 00890 } 00891 } 00892 00893 void print_defaults(const char *conf_file, const char **groups) 00894 { 00895 const char **groups_save= groups; 00896 my_print_default_files(conf_file); 00897 00898 fputs("The following groups are read:",stdout); 00899 for ( ; *groups ; groups++) 00900 { 00901 fputc(' ',stdout); 00902 fputs(*groups,stdout); 00903 } 00904 00905 if (defaults_group_suffix) 00906 { 00907 groups= groups_save; 00908 for ( ; *groups ; groups++) 00909 { 00910 fputc(' ',stdout); 00911 fputs(*groups,stdout); 00912 fputs(defaults_group_suffix,stdout); 00913 } 00914 } 00915 puts("\nThe following options may be given as the first argument:\n\ 00916 --print-defaults Print the program argument list and exit\n\ 00917 --no-defaults Don't read default options from any options file\n\ 00918 --defaults-file=# Only read default options from the given file #\n\ 00919 --defaults-extra-file=# Read this file after the global files are read"); 00920 } 00921 00922 #include <help_end.h> 00923 00924 00925 #ifdef __WIN__ 00926 /* 00927 This wrapper for GetSystemWindowsDirectory() will dynamically bind to the 00928 function if it is available, emulate it on NT4 Terminal Server by stripping 00929 the \SYSTEM32 from the end of the results of GetSystemDirectory(), or just 00930 return GetSystemDirectory(). 00931 */ 00932 00933 typedef UINT (WINAPI *GET_SYSTEM_WINDOWS_DIRECTORY)(LPSTR, UINT); 00934 00935 static uint my_get_system_windows_directory(char *buffer, uint size) 00936 { 00937 uint count; 00938 GET_SYSTEM_WINDOWS_DIRECTORY 00939 func_ptr= (GET_SYSTEM_WINDOWS_DIRECTORY) 00940 GetProcAddress(GetModuleHandle("kernel32.dll"), 00941 "GetSystemWindowsDirectoryA"); 00942 00943 if (func_ptr) 00944 return func_ptr(buffer, size); 00945 00946 /* 00947 Windows NT 4.0 Terminal Server Edition: 00948 To retrieve the shared Windows directory, call GetSystemDirectory and 00949 trim the "System32" element from the end of the returned path. 00950 */ 00951 count= GetSystemDirectory(buffer, size); 00952 if (count > 8 && stricmp(buffer+(count-8), "\\System32") == 0) 00953 { 00954 count-= 8; 00955 buffer[count] = '\0'; 00956 } 00957 return count; 00958 } 00959 #endif 00960 00961 00962 /* 00963 Create the list of default directories. 00964 00965 On Microsoft Windows, this is: 00966 1. C:/ 00967 2. GetWindowsDirectory() 00968 3. GetSystemWindowsDirectory() 00969 4. getenv(DEFAULT_HOME_ENV) 00970 5. Directory above where the executable is located 00971 6. "" 00972 7. --sysconfdir=<path> 00973 00974 On Novell NetWare, this is: 00975 1. sys:/etc/ 00976 2. getenv(DEFAULT_HOME_ENV) 00977 3. "" 00978 4. --sysconfdir=<path> 00979 00980 On OS/2, this is: 00981 1. getenv(ETC) 00982 2. /etc/ 00983 3. getenv(DEFAULT_HOME_ENV) 00984 4. "" 00985 5. "~/" 00986 6. --sysconfdir=<path> 00987 00988 Everywhere else, this is: 00989 1. /etc/ 00990 2. getenv(DEFAULT_HOME_ENV) 00991 3. "" 00992 4. "~/" 00993 5. --sysconfdir=<path> 00994 00995 */ 00996 00997 static void init_default_directories() 00998 { 00999 const char *env, **ptr= default_directories; 01000 01001 #ifdef __WIN__ 01002 *ptr++= "C:/"; 01003 01004 if (GetWindowsDirectory(system_dir,sizeof(system_dir))) 01005 *ptr++= (char*)&system_dir; 01006 if (my_get_system_windows_directory(shared_system_dir, 01007 sizeof(shared_system_dir)) && 01008 strcmp(system_dir, shared_system_dir)) 01009 *ptr++= (char *)&shared_system_dir; 01010 01011 #elif defined(__NETWARE__) 01012 *ptr++= "sys:/etc/"; 01013 #else 01014 *ptr++= "/etc/"; 01015 #endif 01016 if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) 01017 *ptr++= env; 01018 *ptr++= ""; /* Place for defaults_extra_file */ 01019 #if !defined(__WIN__) && !defined(__NETWARE__) 01020 *ptr++= "~/";; 01021 #elif defined(__WIN__) 01022 if (GetModuleFileName(NULL, config_dir, sizeof(config_dir))) 01023 { 01024 char *last= NULL, *end= strend(config_dir); 01025 /* 01026 Look for the second-to-last \ in the filename, but hang on 01027 to a pointer after the last \ in case we're in the root of 01028 a drive. 01029 */ 01030 for ( ; end > config_dir; end--) 01031 { 01032 if (*end == FN_LIBCHAR) 01033 { 01034 if (last) 01035 { 01036 if (end != config_dir) 01037 { 01038 /* Keep the last '\' as this works both with D:\ and a directory */ 01039 end[1]= 0; 01040 } 01041 else 01042 { 01043 /* No parent directory (strange). Use current dir + '\' */ 01044 last[1]= 0; 01045 } 01046 break; 01047 } 01048 last= end; 01049 } 01050 } 01051 *ptr++= (char *)&config_dir; 01052 } 01053 #endif 01054 #ifdef DEFAULT_SYSCONFDIR 01055 if (DEFAULT_SYSCONFDIR != "") 01056 *ptr++= DEFAULT_SYSCONFDIR; 01057 #endif 01058 *ptr= 0; /* end marker */ 01059 }
1.4.7

