default.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:20k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000-2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /****************************************************************************
  14.  Add all options from files named "group".cnf from the default_directories
  15.  before the command line arguments.
  16.  On Windows defaults will also search in the Windows directory for a file
  17.  called 'group'.ini
  18.  As long as the program uses the last argument for conflicting
  19.  options one only have to add a call to "load_defaults" to enable
  20.  use of default values.
  21.  pre- and end 'blank space' are removed from options and values. The
  22.  following escape sequences are recognized in values:  b t n r \
  23.  The following arguments are handled automaticly;  If used, they must be
  24.  first argument on the command line!
  25.  --no-defaults ; no options are read.
  26.  --defaults-file=full-path-to-default-file ; Only this file will be read.
  27.  --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
  28.  --print-defaults ; Print the modified command line and exit
  29. ****************************************************************************/
  30. #include "mysys_priv.h"
  31. #include "m_string.h"
  32. #include "m_ctype.h"
  33. #include <my_dir.h>
  34. char *defaults_extra_file=0;
  35. /* Which directories are searched for options (and in which order) */
  36. const char *default_directories[]= {
  37. #ifdef __WIN__
  38. "C:/",
  39. #elif defined(__NETWARE__)
  40. "sys:/etc/",
  41. #else
  42. "/etc/",
  43. #endif
  44. #ifdef DATADIR
  45. DATADIR,
  46. #endif
  47. "", /* Place for defaults_extra_dir */
  48. #if !defined(__WIN__) && !defined(__NETWARE__)
  49. "~/",
  50. #endif
  51. NullS,
  52. };
  53. #ifdef __WIN__
  54. static const char *f_extensions[]= { ".ini", ".cnf", 0 };
  55. #else
  56. static const char *f_extensions[]= { ".cnf", 0 };
  57. #endif
  58. static int search_default_file(DYNAMIC_ARRAY *args,MEM_ROOT *alloc,
  59.        const char *dir, const char *config_file,
  60.        TYPELIB *group);
  61. static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
  62. const char *dir, const char *ext,
  63. const char *config_file,
  64. TYPELIB *group, int recursion_level);
  65. static char *remove_end_comment(char *ptr);
  66. /*
  67.   Gets --defaults-file and --defaults-extra-file options from command line.
  68.   SYNOPSIS
  69.     get_defaults_files()
  70.     argc Pointer to argc of original program
  71.     argv Pointer to argv of original program
  72.     defaults                    --defaults-file option
  73.     extra_defaults              --defaults-extra-file option
  74.   RETURN
  75.     defaults and extra_defaults will be set to appropriate items
  76.     of argv array, or to NULL if there are no such options
  77. */
  78. void get_defaults_files(int argc, char **argv,
  79.                         char **defaults, char **extra_defaults)
  80. {
  81.   *defaults=0;
  82.   *extra_defaults=0;
  83.   if (argc >= 2)
  84.   {
  85.     if (is_prefix(argv[1],"--defaults-file="))
  86.       *defaults= argv[1];
  87.     else if (is_prefix(argv[1],"--defaults-extra-file="))
  88.       *extra_defaults= argv[1];
  89.   }
  90. }
  91. /*
  92.   Read options from configurations files
  93.   SYNOPSIS
  94.     load_defaults()
  95.     conf_file Basename for configuration file to search for.
  96.      If this is a path, then only this file is read.
  97.     groups Which [group] entrys to read.
  98. Points to an null terminated array of pointers
  99.     argc Pointer to argc of original program
  100.     argv Pointer to argv of original program
  101.   IMPLEMENTATION
  102.    Read options from configuration files and put them BEFORE the arguments
  103.    that are already in argc and argv.  This way the calling program can
  104.    easily command line options override options in configuration files
  105.    NOTES
  106.     In case of fatal error, the function will print a warning and do
  107.     exit(1)
  108.  
  109.     To free used memory one should call free_defaults() with the argument
  110.     that was put in *argv
  111.    RETURN
  112.      0 ok
  113.      1 The given conf_file didn't exists
  114.      2 The given conf_file was not a normal readable file
  115. */
  116. int load_defaults(const char *conf_file, const char **groups,
  117.                   int *argc, char ***argv)
  118. {
  119.   DYNAMIC_ARRAY args;
  120.   const char **dirs, *forced_default_file, *forced_extra_defaults;
  121.   TYPELIB group;
  122.   my_bool found_print_defaults=0;
  123.   uint args_used=0;
  124.   int error= 0;
  125.   MEM_ROOT alloc;
  126.   char *ptr, **res;
  127.   DBUG_ENTER("load_defaults");
  128.   init_alloc_root(&alloc,512,0);
  129.   if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
  130.   {
  131.     /* remove the --no-defaults argument and return only the other arguments */
  132.     uint i;
  133.     if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
  134.  (*argc + 1)*sizeof(char*))))
  135.       goto err;
  136.     res= (char**) (ptr+sizeof(alloc));
  137.     res[0]= **argv; /* Copy program name */
  138.     for (i=2 ; i < (uint) *argc ; i++)
  139.       res[i-1]=argv[0][i];
  140.     res[i-1]=0; /* End pointer */
  141.     (*argc)--;
  142.     *argv=res;
  143.     *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
  144.     DBUG_RETURN(0);
  145.   }
  146.   get_defaults_files(*argc, *argv,
  147.                       (char **)&forced_default_file,
  148.                       (char **)&forced_extra_defaults);
  149.   if (forced_default_file)
  150.     forced_default_file= strchr(forced_default_file,'=')+1;
  151.   if (forced_extra_defaults)
  152.     defaults_extra_file= strchr(forced_extra_defaults,'=')+1;
  153.   args_used+= (forced_default_file ? 1 : 0) + (forced_extra_defaults ? 1 : 0);
  154.   group.count=0;
  155.   group.name= "defaults";
  156.   group.type_names= groups;
  157.   for (; *groups ; groups++)
  158.     group.count++;
  159.   if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
  160.     goto err;
  161.   if (forced_default_file)
  162.   {
  163.     if ((error= search_default_file_with_ext(&args, &alloc, "", "",
  164.      forced_default_file,
  165.      &group, 0)) < 0)
  166.       goto err;
  167.     if (error > 0)
  168.     {
  169.       fprintf(stderr, "Could not open required defaults file: %sn",
  170.               forced_default_file);
  171.       goto err;
  172.     }
  173.   }
  174.   else if (dirname_length(conf_file))
  175.   {
  176.     if ((error= search_default_file(&args, &alloc, NullS, conf_file,
  177.     &group)) < 0)
  178.       goto err;
  179.   }
  180.   else
  181.   {
  182. #ifdef __WIN__
  183.     char system_dir[FN_REFLEN];
  184.     GetWindowsDirectory(system_dir,sizeof(system_dir));
  185.     if ((search_default_file(&args, &alloc, system_dir, conf_file, &group)))
  186.       goto err;
  187. #endif
  188. #if defined(__EMX__) || defined(OS2)
  189.     {
  190.       const char *etc;
  191.       if ((etc= getenv("ETC")) &&
  192.   (search_default_file(&args, &alloc, etc, conf_file, 
  193.        &group)) < 0)
  194.       goto err;
  195.     }
  196. #endif
  197.     for (dirs=default_directories ; *dirs; dirs++)
  198.     {
  199.       if (**dirs)
  200.       {
  201. if (search_default_file(&args, &alloc, *dirs, conf_file,
  202. &group) < 0)
  203.   goto err;
  204.       }
  205.       else if (defaults_extra_file)
  206.       {
  207. if (search_default_file(&args, &alloc, NullS, defaults_extra_file,
  208. &group) < 0)
  209.   goto err; /* Fatal error */
  210.       }
  211.     }
  212.   }
  213.   /*
  214.     Here error contains <> 0 only if we have a fully specified conf_file
  215.     or a forced default file
  216.   */
  217.   if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
  218.        (args.elements + *argc +1) *sizeof(char*))))
  219.     goto err;
  220.   res= (char**) (ptr+sizeof(alloc));
  221.   /* copy name + found arguments + command line arguments to new array */
  222.   res[0]= argv[0][0];  /* Name MUST be set, even by embedded library */
  223.   memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*));
  224.   /* Skip --defaults-file and --defaults-extra-file */
  225.   (*argc)-= args_used;
  226.   (*argv)+= args_used;
  227.   /* Check if we wan't to see the new argument list */
  228.   if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
  229.   {
  230.     found_print_defaults=1;
  231.     --*argc; ++*argv; /* skip argument */
  232.   }
  233.   if (*argc)
  234.     memcpy((gptr) (res+1+args.elements), (char*) ((*argv)+1),
  235.    (*argc-1)*sizeof(char*));
  236.   res[args.elements+ *argc]=0; /* last null */
  237.   (*argc)+=args.elements;
  238.   *argv= (char**) res;
  239.   *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
  240.   delete_dynamic(&args);
  241.   if (found_print_defaults)
  242.   {
  243.     int i;
  244.     printf("%s would have been started with the following arguments:n",
  245.    **argv);
  246.     for (i=1 ; i < *argc ; i++)
  247.       printf("%s ", (*argv)[i]);
  248.     puts("");
  249.     exit(0);
  250.   }
  251.   DBUG_RETURN(error);
  252.  err:
  253.   fprintf(stderr,"Fatal error in defaults handling. Program abortedn");
  254.   exit(1);
  255.   return 0; /* Keep compiler happy */
  256. }
  257. void free_defaults(char **argv)
  258. {
  259.   MEM_ROOT ptr;
  260.   memcpy_fixed((char*) &ptr,(char *) argv - sizeof(ptr), sizeof(ptr));
  261.   free_root(&ptr,MYF(0));
  262. }
  263. static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
  264.        const char *dir,
  265.        const char *config_file, TYPELIB *group)
  266. {
  267.   char **ext;
  268.   for (ext= (char**) f_extensions; *ext; *ext++)
  269.   {
  270.     int error;
  271.     if ((error= search_default_file_with_ext(args, alloc, dir, *ext,
  272.      config_file, group, 0)) < 0)
  273.       return error;
  274.   }
  275.   return 0;
  276. }
  277. /*
  278.   Skip over keyword and get argument after keyword
  279.   SYNOPSIS
  280.    get_argument()
  281.    keyword Include directive keyword
  282.    kwlen Length of keyword
  283.    ptr Pointer to the keword in the line under process
  284.    line line number
  285.   RETURN
  286.    0 error
  287.    # Returns pointer to the argument after the keyword.
  288. */
  289. static char *get_argument(const char *keyword, uint kwlen,
  290.                           char *ptr, char *name, uint line)
  291. {
  292.   char *end;
  293.   /* Skip over "include / includedir keyword" and following whitespace */
  294.   for (ptr+= kwlen - 1;
  295.        my_isspace(&my_charset_latin1, ptr[0]);
  296.        ptr++)
  297.   {}
  298.   /*
  299.     Trim trailing whitespace from directory name
  300.     The -1 below is for the newline added by fgets()
  301.     Note that my_isspace() is true for r and n
  302.   */
  303.   for (end= ptr + strlen(ptr) - 1;
  304.        my_isspace(&my_charset_latin1, *(end - 1));
  305.        end--)
  306.   {}
  307.   end[0]= 0;                                    /* Cut off end space */
  308.   /* Print error msg if there is nothing after !include* directive */
  309.   if (end <= ptr)
  310.   {
  311.     fprintf(stderr,
  312.     "error: Wrong '!%s' directive in config file: %s at line %dn",
  313.     keyword, name, line);
  314.     return 0;
  315.   }
  316.   return ptr;
  317. }
  318. /*
  319.   Open a configuration file (if exists) and read given options from it
  320.   SYNOPSIS
  321.     search_default_file_with_ext()
  322.     args Store pointer to found options here
  323.     alloc Allocate strings in this object
  324.     dir directory to read
  325.     ext Extension for configuration file
  326.     config_file                 Name of configuration file
  327.     group groups to read
  328.     recursion_level             the level of recursion, got while processing
  329.                                 "!include" or "!includedir"
  330.   RETURN
  331.     0   Success
  332.     -1 Fatal error, abort
  333.      1 File not found (Warning)
  334.      2  File is not a regular file (Warning)
  335. */
  336. static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
  337. const char *dir, const char *ext,
  338. const char *config_file,
  339. TYPELIB *group, int recursion_level)
  340. {
  341.   char name[FN_REFLEN + 10], buff[4096], *ptr, *end, *value, *tmp, **tmp_ext;
  342.   static const char includedir_keyword[]= "includedir";
  343.   static const char include_keyword[]= "include";
  344.   const int max_recursion_level= 10;
  345.   FILE *fp;
  346.   uint line= 0;
  347.   my_bool read_values= 0, found_group= 0;
  348.   uint i;
  349.   MY_DIR *search_dir;
  350.   FILEINFO *search_file;
  351.   if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
  352.     return 0; /* Ignore wrong paths */
  353.   if (dir)
  354.   {
  355.     end=convert_dirname(name, dir, NullS);
  356.     if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
  357.       *end++='.';
  358.     strxmov(end,config_file,ext,NullS);
  359.   }
  360.   else
  361.   {
  362.     strmov(name,config_file);
  363.   }
  364.   fn_format(name,name,"","",4);
  365. #if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
  366.   {
  367.     MY_STAT stat_info;
  368.     if (!my_stat(name,&stat_info,MYF(0)))
  369.       return 1;
  370.     /*
  371.       Ignore world-writable regular files.
  372.       This is mainly done to protect us to not read a file created by
  373.       the mysqld server, but the check is still valid in most context. 
  374.     */
  375.     if ((stat_info.st_mode & S_IWOTH) &&
  376. (stat_info.st_mode & S_IFMT) == S_IFREG)
  377.     {
  378.       fprintf(stderr, "warning: World-writable config file %s is ignoredn",
  379.               name);
  380.       return 0;
  381.     }
  382.   }
  383. #endif
  384.   if (!(fp= my_fopen(fn_format(name, name, "", "", 4), O_RDONLY, MYF(0))))
  385.     return 0; /* Ignore wrong files */
  386.   while (fgets(buff, sizeof(buff) - 1, fp))
  387.   {
  388.     line++;
  389.     /* Ignore comment and empty lines */
  390.     for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++)
  391.     {}
  392.     if (*ptr == '#' || *ptr == ';' || !*ptr)
  393.       continue;
  394.     /* Configuration File Directives */
  395.     if ((*ptr == '!'))
  396.     {
  397.       if (recursion_level >= max_recursion_level)
  398.       {
  399.         for (end= ptr + strlen(ptr) - 1; 
  400.              my_isspace(&my_charset_latin1, *(end - 1));
  401.              end--)
  402.         {}
  403.         end[0]= 0;
  404.         fprintf(stderr,
  405.                 "Warning: skipping '%s' directive as maximum include"
  406.                 "recursion level was reached in file %s at line %dn",
  407.                 ptr, name, line);
  408.         continue;
  409.       }
  410.       /* skip over `!' and following whitespace */
  411.       for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++)
  412.       {}
  413.       if ((!strncmp(ptr, includedir_keyword,
  414.                     sizeof(includedir_keyword) - 1)) &&
  415.           my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1]))
  416.       {
  417. if (!(ptr= get_argument(includedir_keyword,
  418.                                 sizeof(includedir_keyword),
  419.                                 ptr, name, line)))
  420.   goto err;
  421.         if (!(search_dir= my_dir(ptr, MYF(MY_WME))))
  422.           goto err;
  423.         for (i= 0; i < (uint) search_dir->number_off_files; i++)
  424.         {
  425.           search_file= search_dir->dir_entry + i;
  426.           ext= fn_ext(search_file->name);
  427.           /* check extension */
  428.           for (tmp_ext= (char**) f_extensions; *tmp_ext; *tmp_ext++)
  429.           {
  430.             if (!strcmp(ext, *tmp_ext))
  431.               break;
  432.           }
  433.           if (*tmp_ext)
  434.           {
  435.             if (!(tmp= alloc_root(alloc, 2 + strlen(search_file->name)
  436.                                           + strlen(ptr))))
  437.               goto err;
  438.             fn_format(tmp, search_file->name, ptr, "",
  439.                       MY_UNPACK_FILENAME | MY_SAFE_PATH);
  440.             search_default_file_with_ext(args, alloc, "", "", tmp, group,
  441.                                          recursion_level + 1);
  442.           }
  443.         }
  444.         my_dirend(search_dir);
  445.       }
  446.       else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
  447.                my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1]))
  448.       {
  449. if (!(ptr= get_argument(include_keyword,
  450.                                 sizeof(include_keyword), ptr,
  451.                                 name, line)))
  452.   goto err;
  453.         search_default_file_with_ext(args, alloc, "", "", ptr, group,
  454.                                      recursion_level + 1);
  455.       }
  456.       continue;
  457.     }
  458.     if (*ptr == '[') /* Group name */
  459.     {
  460.       found_group=1;
  461.       if (!(end=(char *) strchr(++ptr,']')))
  462.       {
  463. fprintf(stderr,
  464. "error: Wrong group definition in config file: %s at line %dn",
  465. name,line);
  466. goto err;
  467.       }
  468.       for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;/* Remove end space */
  469.       end[0]=0;
  470.       read_values=find_type(ptr,group,3) > 0;
  471.       continue;
  472.     }
  473.     if (!found_group)
  474.     {
  475.       fprintf(stderr,
  476.       "error: Found option without preceding group in config file: %s at line: %dn",
  477.       name,line);
  478.       goto err;
  479.     }
  480.     if (!read_values)
  481.       continue;
  482.     end= remove_end_comment(ptr);
  483.     if ((value= strchr(ptr, '=')))
  484.       end= value; /* Option without argument */
  485.     for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
  486.     if (!value)
  487.     {
  488.       if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3)))
  489. goto err;
  490.       strmake(strmov(tmp,"--"),ptr,(uint) (end-ptr));
  491.       if (insert_dynamic(args,(gptr) &tmp))
  492. goto err;
  493.     }
  494.     else
  495.     {
  496.       /* Remove pre- and end space */
  497.       char *value_end;
  498.       for (value++ ; my_isspace(&my_charset_latin1,*value); value++) ;
  499.       value_end=strend(value);
  500.       /*
  501. We don't have to test for value_end >= value as we know there is
  502. an '=' before
  503.       */
  504.       for ( ; my_isspace(&my_charset_latin1,value_end[-1]) ; value_end--) ;
  505.       if (value_end < value) /* Empty string */
  506. value_end=value;
  507.       /* remove quotes around argument */
  508.       if ((*value == '"' || *value == ''') && *value == value_end[-1])
  509.       {
  510. value++;
  511. value_end--;
  512.       }
  513.       if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3 +
  514.    (uint) (value_end-value)+1)))
  515. goto err;
  516.       if (insert_dynamic(args,(gptr) &tmp))
  517. goto err;
  518.       ptr=strnmov(strmov(tmp,"--"),ptr,(uint) (end-ptr));
  519.       *ptr++= '=';
  520.       for ( ; value != value_end; value++)
  521.       {
  522. if (*value == '\' && value != value_end-1)
  523. {
  524.   switch(*++value) {
  525.   case 'n':
  526.     *ptr++='n';
  527.     break;
  528.   case 't':
  529.     *ptr++= 't';
  530.     break;
  531.   case 'r':
  532.     *ptr++ = 'r';
  533.     break;
  534.   case 'b':
  535.     *ptr++ = 'b';
  536.     break;
  537.   case 's':
  538.     *ptr++= ' '; /* space */
  539.     break;
  540.   case '"':
  541.     *ptr++= '"';
  542.     break;
  543.   case ''':
  544.     *ptr++= ''';
  545.     break;
  546.   case '\':
  547.     *ptr++= '\';
  548.     break;
  549.   default: /* Unknown; Keep '' */
  550.     *ptr++= '\';
  551.     *ptr++= *value;
  552.     break;
  553.   }
  554. }
  555. else
  556.   *ptr++= *value;
  557.       }
  558.       *ptr=0;
  559.     }
  560.   }
  561.   my_fclose(fp,MYF(0));
  562.   return(0);
  563.  err:
  564.   my_fclose(fp,MYF(0));
  565.   return -1; /* Fatal error */
  566. }
  567. static char *remove_end_comment(char *ptr)
  568. {
  569.   char quote= 0; /* we are inside quote marks */
  570.   char escape= 0; /* symbol is protected by escape chagacter */
  571.   for (; *ptr; ptr++)
  572.   {
  573.     if ((*ptr == ''' || *ptr == '"') && !escape)
  574.     {
  575.       if (!quote)
  576. quote= *ptr;
  577.       else if (quote == *ptr)
  578. quote= 0;
  579.     }
  580.     /* We are not inside a string */
  581.     if (!quote && *ptr == '#')
  582.     {
  583.       *ptr= 0;
  584.       return ptr;
  585.     }
  586.     escape= (quote && *ptr == '\' && !escape);
  587.   }
  588.   return ptr;
  589. }
  590. #include <help_start.h>
  591. void print_defaults(const char *conf_file, const char **groups)
  592. {
  593. #ifdef __WIN__
  594.   my_bool have_ext= fn_ext(conf_file)[0] != 0;
  595. #endif
  596.   char name[FN_REFLEN], **ext;
  597.   const char **dirs;
  598.   puts("nDefault options are read from the following files in the given order:");
  599.   if (dirname_length(conf_file))
  600.     fputs(conf_file,stdout);
  601.   else
  602.   {
  603. #ifdef __WIN__
  604.     GetWindowsDirectory(name,sizeof(name));
  605.     if (!have_ext)
  606.     {
  607.       for (ext= (char**) f_extensions; *ext; *ext++)
  608.         printf("%s\%s%s ", name, conf_file, *ext);
  609.     }
  610.     else
  611.         printf("%s\%s ", name, conf_file);
  612. #endif
  613. #if defined(__EMX__) || defined(OS2)
  614.     {
  615.       const char *etc;
  616.       if ((etc= getenv("ETC")))
  617.       {
  618. for (ext= (char**) f_extensions; *ext; *ext++)
  619.   printf("%s\%s%s ", etc, conf_file, *ext);
  620.       }
  621.     }
  622. #endif
  623.     for (dirs=default_directories ; *dirs; dirs++)
  624.     {
  625.       for (ext= (char**) f_extensions; *ext; *ext++)
  626.       {
  627. const char *pos;
  628. char *end;
  629. if (**dirs)
  630.   pos= *dirs;
  631. else if (defaults_extra_file)
  632.   pos= defaults_extra_file;
  633. else
  634.   continue;
  635. end= convert_dirname(name, pos, NullS);
  636. if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
  637.   *end++='.';
  638. strxmov(end, conf_file, *ext, " ", NullS);
  639. fputs(name,stdout);
  640.       }
  641.     }
  642.     puts("");
  643.   }
  644.   fputs("The following groups are read:",stdout);
  645.   for ( ; *groups ; groups++)
  646.   {
  647.     fputc(' ',stdout);
  648.     fputs(*groups,stdout);
  649.   }
  650.   puts("nThe following options may be given as the first argument:n
  651. --print-defaults Print the program argument list and exitn
  652. --no-defaults Don't read default options from any options filen
  653. --defaults-file=# Only read default options from the given file #n
  654. --defaults-extra-file=# Read this file after the global files are read");
  655. }
  656. #include <help_end.h>