1 /* 2 * Copyright (C) 2007 Tommi Maekitalo 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * As a special exception, you may use this file as part of a free 10 * software library without restriction. Specifically, if other files 11 * instantiate templates or use macros or inline functions from this 12 * file, or you compile this file and link it with other files to 13 * produce an executable, this file does not by itself cause the 14 * resulting executable to be covered by the GNU General Public 15 * License. This exception does not however invalidate any other 16 * reasons why the executable file might be covered by the GNU Library 17 * General Public License. 18 * 19 * This library is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 * Lesser General Public License for more details. 23 * 24 * You should have received a copy of the GNU Lesser General Public 25 * License along with this library; if not, write to the Free Software 26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27 */ 28 29 #include <cxxtools/iniparser.h> 30 #include <cxxtools/log.h> 31 #include <cctype> 32 #include <iostream> 33 #include <stdexcept> 34 35 log_define("cxxtools.iniparser") 36 37 namespace cxxtools 38 { onSection(const std::string & section)39 bool IniParser::Event::onSection(const std::string& section) 40 { 41 return false; 42 } 43 onKey(const std::string & key)44 bool IniParser::Event::onKey(const std::string& key) 45 { 46 return false; 47 } 48 onValue(const std::string & key)49 bool IniParser::Event::onValue(const std::string& key) 50 { 51 return false; 52 } 53 onComment(const std::string & comment)54 bool IniParser::Event::onComment(const std::string& comment) 55 { 56 return false; 57 } 58 onError()59 bool IniParser::Event::onError() 60 { 61 throw std::runtime_error("parse error in ini-file"); 62 return true; 63 } 64 parse(std::istream & in)65 void IniParser::parse(std::istream& in) 66 { 67 char ch; 68 while (in.get(ch) && !parse(ch)) 69 ; 70 end(); 71 } 72 parse(char ch)73 bool IniParser::parse(char ch) 74 { 75 bool ret = false; 76 switch (state) 77 { 78 case state_0: 79 if (ch == '[') 80 state = state_section; 81 else if (std::isalnum(ch)) 82 { 83 data = ch; 84 state = state_key; 85 } 86 else if (ch == '#' || ch == ';') 87 { 88 state = state_comment; 89 } 90 else if (std::isspace(ch)) 91 ; 92 else 93 { 94 log_debug("onError"); 95 ret = event.onError(); 96 } 97 break; 98 99 case state_section: 100 if (ch == ']') 101 { 102 log_debug("onSection(" << data << ')'); 103 ret = event.onSection(data); 104 data.clear(); 105 state = state_0; 106 } 107 else 108 data += ch; 109 break; 110 111 case state_key: 112 if (ch == '=') 113 { 114 log_debug("onKey(" << data << ')'); 115 ret = event.onKey(data); 116 state = state_value0; 117 } 118 else if (std::isspace(ch)) 119 { 120 log_debug("onKey(" << data << ')'); 121 ret = event.onKey(data); 122 state = state_key_sp; 123 } 124 else 125 data += ch; 126 break; 127 128 case state_key_sp: 129 if (ch == '=') 130 state = state_value0; 131 else if (!std::isspace(ch)) 132 { 133 log_debug("onError"); 134 ret = event.onError(); 135 } 136 break; 137 138 case state_value0: 139 if (ch == '\n') 140 { 141 log_debug("onValue(\"\")"); 142 ret = event.onValue(std::string()); 143 state = state_0; 144 } 145 else if (!std::isspace(ch)) 146 { 147 data = ch; 148 state = state_value; 149 } 150 break; 151 152 case state_value: 153 if (ch == '\n') 154 { 155 log_debug("onValue(" << data << ')'); 156 ret = event.onValue(data); 157 data.clear(); 158 state = state_0; 159 } 160 else 161 data += ch; 162 break; 163 164 case state_comment: 165 if (ch == '\n') 166 state = state_0; 167 break; 168 } 169 170 return ret; 171 } 172 end()173 void IniParser::end() 174 { 175 switch (state) 176 { 177 case state_0: 178 case state_comment: 179 break; 180 181 case state_section: 182 case state_key: 183 case state_key_sp: 184 log_debug("onError"); 185 event.onError(); 186 break; 187 188 case state_value0: 189 log_debug("onValue(\"\")"); 190 event.onValue(std::string()); 191 break; 192 193 case state_value: 194 log_debug("onValue" << data << ')'); 195 event.onValue(data); 196 break; 197 } 198 } 199 200 } 201