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

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 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. #include <ndb_global.h>
  14. #include "InitConfigFileParser.hpp"
  15. #include "Config.hpp"
  16. #include "MgmtErrorReporter.hpp"
  17. #include <NdbOut.hpp>
  18. #include "ConfigInfo.hpp"
  19. #include <m_string.h>
  20. const int MAX_LINE_LENGTH = 1024;  // Max length of line of text in config file
  21. static void trim(char *);
  22. static void require(bool v) { if(!v) abort();}
  23. //****************************************************************************
  24. //  Ctor / Dtor
  25. //****************************************************************************
  26. InitConfigFileParser::InitConfigFileParser(FILE * out)
  27. {
  28.   m_info = new ConfigInfo();
  29.   m_errstream = out ? out : stdout;
  30. }
  31. InitConfigFileParser::~InitConfigFileParser() {
  32.   delete m_info;
  33. }
  34. //****************************************************************************
  35. //  Read Config File
  36. //****************************************************************************
  37. InitConfigFileParser::Context::Context(const ConfigInfo * info, FILE * out)
  38.   :  m_userProperties(true), m_configValues(1000, 20) {
  39.   m_config = new Properties(true);
  40.   m_defaults = new Properties(true);
  41.   m_errstream = out;
  42. }
  43. InitConfigFileParser::Context::~Context(){
  44.   if(m_config != 0)
  45.     delete m_config;
  46.   if(m_defaults != 0)
  47.     delete m_defaults;
  48. }
  49. Config *
  50. InitConfigFileParser::parseConfig(const char * filename) {
  51.   FILE * file = fopen(filename, "r");
  52.   if(file == 0){
  53.     fprintf(m_errstream, "Error opening file: %sn", filename);
  54.     return 0;
  55.   }
  56.   
  57.   Config * ret = parseConfig(file);
  58.   fclose(file);
  59.   return ret;
  60. }
  61. Config *
  62. InitConfigFileParser::parseConfig(FILE * file) {
  63.   char line[MAX_LINE_LENGTH];
  64.   Context ctx(m_info, m_errstream); 
  65.   ctx.m_lineno = 0;
  66.   ctx.m_currentSection = 0;
  67.   /*************
  68.    * Open file *
  69.    *************/
  70.   if (file == NULL) {
  71.     return 0;
  72.   }
  73.   /***********************
  74.    * While lines to read *
  75.    ***********************/
  76.   while (fgets(line, MAX_LINE_LENGTH, file)) {
  77.     ctx.m_lineno++;
  78.     trim(line);
  79.     if (isEmptyLine(line)) // Skip if line is empty or comment
  80.       continue;   
  81.     // End with NULL instead of newline
  82.     if (line[strlen(line)-1] == 'n')
  83.       line[strlen(line)-1] = '';
  84.     
  85.     /********************************
  86.      * 1. Parse new default section *
  87.      ********************************/
  88.     if (char* section = parseDefaultSectionHeader(line)) {
  89.       if(!storeSection(ctx)){
  90. free(section);
  91. ctx.reportError("Could not store previous default section "
  92. "of configuration file.");
  93. return 0;
  94.       }
  95.       BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section); free(section);
  96.       ctx.type             = InitConfigFileParser::DefaultSection;
  97.       ctx.m_sectionLineno  = ctx.m_lineno;
  98.       ctx.m_currentSection = new Properties(true);
  99.       ctx.m_userDefaults   = NULL;
  100.       require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
  101.       require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
  102.       continue;
  103.     }
  104.     
  105.     /************************
  106.      * 2. Parse new section *
  107.      ************************/
  108.     if (char* section = parseSectionHeader(line)) {
  109.       if(!storeSection(ctx)){
  110. free(section);
  111. ctx.reportError("Could not store previous section "
  112. "of configuration file.");
  113. return 0;
  114.       }
  115.       BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section);
  116.       free(section);
  117.       ctx.type             = InitConfigFileParser::Section;
  118.       ctx.m_sectionLineno  = ctx.m_lineno;      
  119.       ctx.m_currentSection = new Properties(true);
  120.       ctx.m_userDefaults   = getSection(ctx.fname, ctx.m_defaults);
  121.       require((ctx.m_currentInfo    = m_info->getInfo(ctx.fname)) != 0);
  122.       require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
  123.       continue;
  124.     }
  125.     
  126.     /****************************
  127.      * 3. Parse name-value pair *
  128.      ****************************/
  129.     if (!parseNameValuePair(ctx, line)) {
  130.       ctx.reportError("Could not parse name-value pair in config file.");
  131.       return 0;
  132.     }
  133.   }
  134.   
  135.   if (ferror(file)){
  136.     ctx.reportError("Failure in reading");
  137.     return 0;
  138.   } 
  139.   if(!storeSection(ctx)) {
  140.     ctx.reportError("Could not store section of configuration file.");
  141.     return 0;
  142.   }
  143.   for(size_t i = 0; ConfigInfo::m_ConfigRules[i].m_configRule != 0; i++){
  144.     ctx.type             = InitConfigFileParser::Undefined;
  145.     ctx.m_currentSection = 0;
  146.     ctx.m_userDefaults   = 0;
  147.     ctx.m_currentInfo    = 0;
  148.     ctx.m_systemDefaults = 0;
  149.     
  150.     Vector<ConfigInfo::ConfigRuleSection> tmp;
  151.     if(!(* ConfigInfo::m_ConfigRules[i].m_configRule)(tmp, ctx,
  152.       ConfigInfo::m_ConfigRules[i].m_ruleData))
  153.       return 0;
  154.     for(size_t j = 0; j<tmp.size(); j++){
  155.       BaseString::snprintf(ctx.fname, sizeof(ctx.fname), tmp[j].m_sectionType.c_str());
  156.       ctx.type             = InitConfigFileParser::Section;
  157.       ctx.m_currentSection = tmp[j].m_sectionData;
  158.       ctx.m_userDefaults   = getSection(ctx.fname, ctx.m_defaults);
  159.       require((ctx.m_currentInfo    = m_info->getInfo(ctx.fname)) != 0);
  160.       require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
  161.       if(!storeSection(ctx))
  162. return 0;
  163.     }
  164.   }
  165.   Uint32 nConnections = 0;
  166.   Uint32 nComputers = 0;
  167.   Uint32 nNodes = 0;
  168.   Uint32 nExtConnections = 0;
  169.   const char * system = "?";
  170.   ctx.m_userProperties.get("NoOfConnections", &nConnections);
  171.   ctx.m_userProperties.get("NoOfComputers", &nComputers);
  172.   ctx.m_userProperties.get("NoOfNodes", &nNodes);
  173.   ctx.m_userProperties.get("ExtNoOfConnections", &nExtConnections);
  174.   ctx.m_userProperties.get("ExtSystem", &system);
  175.   ctx.m_config->put("NoOfConnections", nConnections);
  176.   ctx.m_config->put("NoOfComputers", nComputers);
  177.   ctx.m_config->put("NoOfNodes", nNodes);
  178.   char tmpLine[MAX_LINE_LENGTH];
  179.   BaseString::snprintf(tmpLine, MAX_LINE_LENGTH, "EXTERNAL SYSTEM_");
  180.   strncat(tmpLine, system, MAX_LINE_LENGTH);
  181.   strncat(tmpLine, ":NoOfConnections", MAX_LINE_LENGTH);
  182.   ctx.m_config->put(tmpLine, nExtConnections);
  183.   
  184.   Config * ret = new Config();
  185.   ret->m_configValues = (struct ndb_mgm_configuration*)ctx.m_configValues.getConfigValues();
  186.   ret->m_oldConfig = ctx.m_config; ctx.m_config = 0;
  187.   return ret;
  188. }
  189. //****************************************************************************
  190. //  Parse Name-Value Pair
  191. //****************************************************************************
  192. bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line)
  193. {
  194.   if (ctx.m_currentSection == NULL){
  195.     ctx.reportError("Value specified outside section");
  196.     return false;
  197.   }
  198.   // *************************************
  199.   //  Split string at first occurrence of 
  200.   //  '=' or ':'
  201.   // *************************************
  202.   Vector<BaseString> tmp_string_split;
  203.   if (BaseString(line).split(tmp_string_split,
  204.      "=:", 2) != 2)
  205.   {
  206.     ctx.reportError("Parse error");
  207.     return false;
  208.   }
  209.   // *************************************
  210.   //  Remove all after #
  211.   // *************************************
  212.   Vector<BaseString> tmp_string_split2;
  213.   tmp_string_split[1].split(tmp_string_split2,
  214.     "#", 2);
  215.   tmp_string_split[1]=tmp_string_split2[0];
  216.   // *************************************
  217.   // Remove leading and trailing chars
  218.   // *************************************
  219.   {
  220.     for (int i = 0; i < 2; i++)
  221.       tmp_string_split[i].trim("rn t"); 
  222.   }
  223.   // *************************************
  224.   // First in split is fname
  225.   // *************************************
  226.   const char *fname= tmp_string_split[0].c_str();
  227.   if (!ctx.m_currentInfo->contains(fname)) {
  228.     ctx.reportError("[%s] Unknown parameter: %s", ctx.fname, fname);
  229.     return false;
  230.   }
  231.   ConfigInfo::Status status = m_info->getStatus(ctx.m_currentInfo, fname);
  232.   if (status == ConfigInfo::CI_NOTIMPLEMENTED) {
  233.     ctx.reportWarning("[%s] %s not yet implemented", ctx.fname, fname);
  234.   }
  235.   if (status == ConfigInfo::CI_DEPRICATED) {
  236.     const char * desc = m_info->getDescription(ctx.m_currentInfo, fname);
  237.     if(desc){
  238.       ctx.reportWarning("[%s] %s is depricated, use %s instead", 
  239. ctx.fname, fname, desc);
  240.     } else {
  241.       ctx.reportWarning("[%s] %s is depricated", ctx.fname, fname);
  242.     } 
  243.   }
  244.   // ***********************
  245.   //  Store name-value pair
  246.   // ***********************
  247.   return storeNameValuePair(ctx, fname, tmp_string_split[1].c_str());
  248. }
  249. //****************************************************************************
  250. //  STORE NAME-VALUE pair in properties section 
  251. //****************************************************************************
  252. bool 
  253. InitConfigFileParser::storeNameValuePair(Context& ctx,
  254.  const char* fname, 
  255.  const char* value) {
  256.   
  257.   const char * pname = fname;
  258.   if (ctx.m_currentSection->contains(pname)) {
  259.     ctx.reportError("[%s] Parameter %s specified twice", ctx.fname, fname);
  260.     return false;
  261.   }
  262.   
  263.   // ***********************
  264.   //  Store name-value pair
  265.   // ***********************
  266.   const ConfigInfo::Type type = m_info->getType(ctx.m_currentInfo, fname);
  267.   switch(type){
  268.   case ConfigInfo::CI_BOOL: {
  269.     bool value_bool;
  270.     if (!convertStringToBool(value, value_bool)) {
  271.       ctx.reportError("Illegal boolean value for parameter %s", fname);
  272.       return false;
  273.     }
  274.     MGM_REQUIRE(ctx.m_currentSection->put(pname, value_bool));
  275.     break;
  276.   }
  277.   case ConfigInfo::CI_INT:
  278.   case ConfigInfo::CI_INT64:{
  279.     Uint64 value_int;
  280.     if (!convertStringToUint64(value, value_int)) {
  281.       ctx.reportError("Illegal integer value for parameter %s", fname);
  282.       return false;
  283.     }
  284.     if (!m_info->verify(ctx.m_currentInfo, fname, value_int)) {
  285.       ctx.reportError("Illegal value %s for parameter %s.n"
  286.       "Legal values are between %Lu and %Lu", value, fname,
  287.       m_info->getMin(ctx.m_currentInfo, fname), 
  288.       m_info->getMax(ctx.m_currentInfo, fname));
  289.       return false;
  290.     }
  291.     if(type == ConfigInfo::CI_INT){
  292.       MGM_REQUIRE(ctx.m_currentSection->put(pname, (Uint32)value_int));
  293.     } else {
  294.       MGM_REQUIRE(ctx.m_currentSection->put64(pname, value_int));
  295.     }
  296.     break;
  297.   }
  298.   case ConfigInfo::CI_STRING:
  299.     MGM_REQUIRE(ctx.m_currentSection->put(pname, value));
  300.     break;
  301.   case ConfigInfo::CI_SECTION:
  302.     abort();
  303.   }
  304.   return true;
  305. }
  306. //****************************************************************************
  307. //  Is Empty Line
  308. //****************************************************************************
  309. bool InitConfigFileParser::isEmptyLine(const char* line) const {
  310.   int i;
  311.   
  312.   // Check if it is a comment line
  313.   if (line[0] == '#') return true;               
  314.   // Check if it is a line with only spaces
  315.   for (i = 0; i < MAX_LINE_LENGTH && line[i] != 'n' && line[i] != ''; i++) {
  316.     if (line[i] != ' ' && line[i] != 't') return false;
  317.   }
  318.   return true;
  319. }
  320. //****************************************************************************
  321. //  Convert String to Int
  322. //****************************************************************************
  323. bool InitConfigFileParser::convertStringToUint64(const char* s, 
  324.  Uint64& val,
  325.  Uint32 log10base) {
  326.   if (s == NULL)
  327.     return false;
  328.   if (strlen(s) == 0) 
  329.     return false;
  330.   errno = 0;
  331.   char* p;
  332.   Int64 v = strtoll(s, &p, log10base);
  333.   if (errno != 0)
  334.     return false;
  335.   
  336.   long mul = 0;
  337.   if (p != &s[strlen(s)]){
  338.     char * tmp = strdup(p);
  339.     trim(tmp);
  340.     switch(tmp[0]){
  341.     case 'k':
  342.     case 'K':
  343.       mul = 10;
  344.       break;
  345.     case 'M':
  346.       mul = 20;
  347.       break;
  348.     case 'G':
  349.       mul = 30;
  350.       break;
  351.     default:
  352.       free(tmp);
  353.       return false;
  354.     }
  355.     free(tmp);
  356.   }
  357.   
  358.   val = (v << mul);
  359.   return true;
  360. }
  361. bool InitConfigFileParser::convertStringToBool(const char* s, bool& val) {
  362.   if (s == NULL) return false;
  363.   if (strlen(s) == 0) return false;
  364.   if (!strcmp(s, "Y") || !strcmp(s, "y") || 
  365.       !strcmp(s, "Yes") || !strcmp(s, "YES") || !strcmp(s, "yes") || 
  366.       !strcmp(s, "True") || !strcmp(s, "TRUE") || !strcmp(s, "true") ||
  367.       !strcmp(s, "1")) {
  368.     val = true;
  369.     return true;
  370.   }
  371.   if (!strcmp(s, "N") || !strcmp(s, "n") || 
  372.       !strcmp(s, "No") || !strcmp(s, "NO") || !strcmp(s, "no") || 
  373.       !strcmp(s, "False") || !strcmp(s, "FALSE") || !strcmp(s, "false") ||
  374.       !strcmp(s, "0")) {
  375.     val = false;
  376.     return true;
  377.   }
  378.   
  379.   return false;  // Failure to convert
  380. }
  381. //****************************************************************************
  382. //  Parse Section Header
  383. //****************************************************************************
  384. static void
  385. trim(char * str){
  386.   int len = strlen(str);
  387.   for(len--;
  388.       (str[len] == 'r' || str[len] == 'n' || 
  389.        str[len] == ' ' || str[len] == 't') && 
  390. len > 0; 
  391.       len--)
  392.     str[len] = 0;
  393.   
  394.   int pos = 0;
  395.   while(str[pos] == ' ' || str[pos] == 't')
  396.     pos++;
  397.   
  398.   if(str[pos] == '"' && str[len] == '"') {
  399.     pos++;
  400.     str[len] = 0;
  401.     len--;
  402.   }
  403.   
  404.   memmove(str, &str[pos], len - pos + 2);
  405. }
  406. char* 
  407. InitConfigFileParser::parseSectionHeader(const char* line) const {
  408.   char * tmp = strdup(line);
  409.   if(tmp[0] != '['){
  410.     free(tmp);
  411.     return NULL;
  412.   }
  413.   if(tmp[strlen(tmp)-1] != ']'){
  414.     free(tmp);
  415.     return NULL;
  416.   }
  417.   tmp[strlen(tmp)-1] = 0;
  418.   tmp[0] = ' ';
  419.   trim(tmp);
  420.   // Get the correct header name if an alias
  421.   {
  422.     const char *tmp_alias= m_info->getAlias(tmp);
  423.     if (tmp_alias) {
  424.       free(tmp);
  425.       tmp= strdup(tmp_alias);
  426.     }
  427.   }
  428.   // Lookup token among sections
  429.   if(!m_info->isSection(tmp)) {
  430.     free(tmp);
  431.     return NULL;
  432.   }
  433.   if(m_info->getInfo(tmp)) return tmp;
  434.   free(tmp);
  435.   return NULL;
  436. }
  437. //****************************************************************************
  438. //  Parse Default Section Header
  439. //****************************************************************************
  440. char* 
  441. InitConfigFileParser::parseDefaultSectionHeader(const char* line) const {
  442.   static char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH];
  443.   int no = sscanf(line, "[%120[A-Z_a-z] %120[A-Z_a-z]]", token1, token2);
  444.   // Not correct no of tokens 
  445.   if (no != 2) return NULL;
  446.   // Not correct keyword at end
  447.   if (!strcasecmp(token2, "DEFAULT") == 0) return NULL;
  448.   const char *token1_alias= m_info->getAlias(token1);
  449.   if (token1_alias == 0)
  450.     token1_alias= token1;
  451.   if(m_info->getInfo(token1_alias)){
  452.     return strdup(token1_alias);
  453.   }
  454.   
  455.   // Did not find section
  456.   return NULL;
  457. }
  458. const Properties *
  459. InitConfigFileParser::getSection(const char * name, const Properties * src){
  460.   const Properties * p;
  461.   if(src && src->get(name, &p))
  462.     return p;
  463.   return 0;
  464. }
  465. //****************************************************************************
  466. //  STORE section
  467. //****************************************************************************
  468. bool
  469. InitConfigFileParser::storeSection(Context& ctx){
  470.   if(ctx.m_currentSection == NULL)
  471.     return true;
  472.   for(int i = strlen(ctx.fname) - 1; i>=0; i--){
  473.     ctx.fname[i] = toupper(ctx.fname[i]);
  474.   }
  475.   BaseString::snprintf(ctx.pname, sizeof(ctx.pname), ctx.fname);
  476.   char buf[255];
  477.   if(ctx.type == InitConfigFileParser::Section)
  478.     BaseString::snprintf(buf, sizeof(buf), "%s", ctx.fname);
  479.   if(ctx.type == InitConfigFileParser::DefaultSection)
  480.     BaseString::snprintf(buf, sizeof(buf), "%s DEFAULT", ctx.fname);
  481.   BaseString::snprintf(ctx.fname, sizeof(ctx.fname), buf);
  482.   if(ctx.type == InitConfigFileParser::Section){
  483.     for(int i = 0; i<m_info->m_NoOfRules; i++){
  484.       const ConfigInfo::SectionRule & rule = m_info->m_SectionRules[i];
  485.       if(!strcmp(rule.m_section, "*") || !strcmp(rule.m_section, ctx.fname)){
  486. if(!(* rule.m_sectionRule)(ctx, rule.m_ruleData)){
  487.   return false;
  488. }
  489.       }
  490.     }
  491.   }
  492.   if(ctx.type == InitConfigFileParser::DefaultSection &&
  493.      !ctx.m_defaults->put(ctx.pname, ctx.m_currentSection))
  494.   {
  495.     ctx.reportError("Duplicate default section not allowed");
  496.     return false;
  497.   }
  498.   if(ctx.type == InitConfigFileParser::Section)
  499.     require(ctx.m_config->put(ctx.pname, ctx.m_currentSection));
  500.   delete ctx.m_currentSection; ctx.m_currentSection = NULL;
  501.   return true;
  502. }
  503. void
  504. InitConfigFileParser::Context::reportError(const char * fmt, ...){
  505.   va_list ap;
  506.   char buf[1000];
  507.   
  508.   va_start(ap, fmt);
  509.   if (fmt != 0)
  510.     BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
  511.   va_end(ap);
  512.   fprintf(m_errstream, "Error line %d: %sn",
  513.   m_lineno, buf);
  514.   //m_currentSection->print();
  515. }
  516. void
  517. InitConfigFileParser::Context::reportWarning(const char * fmt, ...){
  518.   va_list ap;
  519.   char buf[1000];
  520.   
  521.   va_start(ap, fmt);
  522.   if (fmt != 0)
  523.     BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
  524.   va_end(ap);
  525.   fprintf(m_errstream, "Warning line %d: %sn",
  526.   m_lineno, buf);
  527. }