nis-util
1.0.D108
|
00001 // 00002 // nis-util - NIS Administration Utilities 00003 // Copyright (C) 2012 Peter Miller 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation; either version 2 of the License, or (at 00008 // your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 // General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License along 00016 // with this program. If not, see <http://www.gnu.org/licenses/>. 00017 // 00018 00019 #include <lib/ac/string.h> 00020 #include <libexplain/output.h> 00021 00022 #include <lib/configuration.h> 00023 #include <lib/configuration/item/boolean.h> 00024 #include <lib/configuration/item/integer.h> 00025 #include <lib/configuration/item/string.h> 00026 #include <lib/input/remove_hash_comments.h> 00027 #include <lib/rcstring/accumulator.h> 00028 00029 00030 rcstring 00031 configuration::canonical_name(const rcstring &name) 00032 { 00033 rcstring_accumulator acc; 00034 const char *cp = name.c_str(); 00035 while (!isalnum((unsigned char)*cp)) 00036 ++cp; 00037 bool insert_one_hyphen = false; 00038 for (;;) 00039 { 00040 unsigned char c = *cp++; 00041 if (!c) 00042 { 00043 if (acc.empty()) 00044 return "empty"; 00045 return acc.mkstr(); 00046 } 00047 if (isalnum(c)) 00048 { 00049 if (insert_one_hyphen) 00050 acc.push_back('-'); 00051 acc.push_back(c); 00052 insert_one_hyphen = false; 00053 } 00054 else 00055 insert_one_hyphen = true; 00056 } 00057 } 00058 00059 00060 void 00061 configuration::parse(level_t level, const input::pointer &ip0) 00062 { 00063 input::pointer ip = input_remove_hash_comments::create(ip0); 00064 int number_of_errors = 0; 00065 rcstring section_name = SECTION_GLOBAL; 00066 for (;;) 00067 { 00068 source_location locn; 00069 rcstring line; 00070 if (!ip->read_one_line(locn, line)) 00071 break; 00072 line = line.trim(); 00073 00074 // blank lines 00075 if (line.empty()) 00076 continue; 00077 00078 // section headers 00079 if (line.front() == '[' && line.back() == ']') 00080 { 00081 section_name = line.substr(1, line.size() - 2).trim(); 00082 00083 // make sure we like the section name 00084 { 00085 rcstring suggest = canonical_name(section_name); 00086 if (suggest != section_name) 00087 { 00088 explain_output_error 00089 ( 00090 "%s: section name %s not valid, " 00091 "did you mean %s instead?", 00092 locn.get_both().c_str(), 00093 section_name.quote_c().c_str(), 00094 suggest.quote_c().c_str() 00095 ); 00096 ++number_of_errors; 00097 section_name = suggest; 00098 } 00099 } 00100 00101 // the global section is actually nameless 00102 if (section_name == "global" || section_name == "default") 00103 section_name = SECTION_GLOBAL; 00104 continue; 00105 } 00106 00107 // name = value 00108 { 00109 const char *cp = line.c_str(); 00110 const char *eq = strchr(cp, '='); 00111 if (eq) 00112 { 00113 rcstring name = rcstring(cp, eq - cp).trim(); 00114 ++eq; 00115 const char *end = cp + line.size(); 00116 rcstring value = rcstring(eq, end - eq).trim(); 00117 00118 // make sure we like the item name 00119 { 00120 rcstring suggest = canonical_name(name); 00121 if (suggest != name) 00122 { 00123 explain_output_error 00124 ( 00125 "%s: item name %s not valid, " 00126 "did you mean %s instead?", 00127 locn.get_both().c_str(), 00128 name.quote_c().c_str(), 00129 suggest.quote_c().c_str() 00130 ); 00131 ++number_of_errors; 00132 name = suggest; 00133 } 00134 } 00135 00136 // 00137 // Create a type-specific item. This avoids repeatedly 00138 // turning strings into long or bool for corresponding 00139 // usage. 00140 // 00141 configuration_item::pointer item = 00142 configuration_item_boolean::create_if_candidate 00143 ( 00144 locn, 00145 level, 00146 name, 00147 value 00148 ); 00149 if (!item) 00150 { 00151 item = 00152 configuration_item_integer::create_if_candidate 00153 ( 00154 locn, 00155 level, 00156 name, 00157 value 00158 ); 00159 } 00160 if (!item) 00161 { 00162 item = 00163 configuration_item_string::create 00164 ( 00165 locn, 00166 level, 00167 name, 00168 value 00169 ); 00170 set(section_name, item); 00171 } 00172 set(section_name, item); 00173 continue; 00174 } 00175 } 00176 00177 // looks like garbage 00178 explain_output_error("%s: malformed line", locn.get_both().c_str()); 00179 ++number_of_errors; 00180 } 00181 if (number_of_errors > 0) 00182 { 00183 explain_output_error_and_die 00184 ( 00185 "%s: found %d fatal error%s", 00186 ip->get_source_location().get_file_name().c_str(), 00187 number_of_errors, 00188 (number_of_errors == 1 ? "" : "s") 00189 ); 00190 } 00191 } 00192 00193 00194 // vim: set ts=8 sw=4 et :