Made on Kubuntu
00001 // Copyright (C) 2009-2010 Ferdinand Majerech 00002 // This file is part of MiniINI 00003 // For conditions of distribution and use, see copyright notice in LICENSE.txt 00004 00005 #ifndef INISECTIONUTIL_H_INCLUDED 00006 #define INISECTIONUTIL_H_INCLUDED 00007 00008 #include <cstring> 00009 #include <cerrno> 00010 #include <cstdlib> 00011 #include <cassert> 00012 00013 #include "typedefs.h" 00014 #include "globals.h" 00015 #include "log.h" 00016 #include "linetoken.h" 00017 #include "inisection.h" 00018 #include "util.h" 00019 #include "parse.h" 00020 00021 using namespace miniini_private; 00022 00023 ui INISection::temptagscap = 0; 00024 c * * INISection::temptags = NULL; 00025 ui INISection::tagcap = 0; 00026 c * INISection::tagbuf = NULL; 00027 00030 #define FOR_4(instr) \ 00031 {\ 00032 instr;\ 00033 instr;\ 00034 instr;\ 00035 instr;\ 00036 } 00037 00038 00039 inline LineToken INISection::TagName(const c * & currentcharref, ui & tagsize) 00040 { 00041 //ptr to the current character 00042 const c * currentchar = currentcharref; 00043 //current character 00044 register c ch; 00045 for(;;) 00046 { 00047 //reallocate header buffer if not enough space to add new chars 00048 //need 4 chars for unrolled part of the loop, 3 for trailing zeroes 00049 //since tag and value are stored in the same buffer separated by a zero 00050 //and the last tag is followed by two zeroes 00051 if(tagcap < tagsize + 7) 00052 { 00053 MINIINI_REALLOCATE(tagbuf, tagcap, tagsize, c); 00054 } 00055 //unrolled part of the loop (process 4 chars) 00056 FOR_4 00057 ( 00058 { 00059 ch = *currentchar; 00060 switch(ch) 00061 { 00062 case ' ': 00063 case '\t': 00064 { 00065 //ignore spaces 00066 break; 00067 } 00068 //CR, LF 00069 case 10: 00070 case 13: 00071 { 00072 currentcharref = NextLine(currentchar); 00073 return LT_NAME; 00074 break; 00075 } 00076 //header start found. 00077 case '[': 00078 { 00079 currentcharref = currentchar; 00080 return LT_HEADER; 00081 break; 00082 } 00083 case '\0': 00084 { 00085 currentcharref = currentchar; 00086 return LT_NAME; 00087 break; 00088 } 00089 default: 00090 { 00091 //value found, if tag name is not empty, start reading val 00092 if(ch == namevalsep) 00093 { 00094 if(tagsize) 00095 { 00096 //adding trailing zero to the tag name 00097 tagbuf[tagsize] = 0; 00098 ++tagsize; 00099 currentcharref = currentchar + 1; 00100 return LT_VAL; 00101 } 00102 else 00103 { 00104 MINIINI_WARNING("Empty tag name."); 00105 currentcharref = NextLine(currentchar); 00106 return LT_NAME; 00107 } 00108 } 00109 if(ch == comment) 00110 { 00111 currentcharref = NextLine(currentchar); 00112 return LT_NAME; 00113 } 00114 //add new char to tag name. 00115 tagbuf[tagsize] = ch; 00116 ++tagsize; 00117 break; 00118 } 00119 } 00120 ++currentchar; 00121 } 00122 ) 00123 } 00124 } 00125 00126 #undef FOR_4 00127 00128 inline ui INISection::TagValue(const c * & currentcharref, ui tagsize) 00129 { 00130 //ptr to the current character 00131 const c * currentchar = currentcharref; 00132 //current character 00133 register c ch; 00134 //reading characters of value 00135 for(; ; ++currentchar) 00136 { 00137 ch = *currentchar; 00138 switch(ch) 00139 { 00140 case ' ': 00141 case '\t': 00142 { 00143 //ignore spaces 00144 break; 00145 } 00146 //CR, LF 00147 case 10: 00148 case 13: 00149 { 00150 currentcharref = NextLine(currentchar); 00151 return tagsize; 00152 break; 00153 } 00154 case '\0': 00155 { 00156 currentcharref = currentchar; 00157 return tagsize; 00158 break; 00159 } 00160 case ',': 00161 { 00162 //need 2 more chars for trailing 0s 00163 if(tagcap < tagsize + 3) 00164 { 00165 MINIINI_REALLOCATE(tagbuf, tagcap, tagsize, c); 00166 } 00167 //add new char to value 00168 tagbuf[tagsize] = '\0'; 00169 ++tagsize; 00170 break; 00171 } 00172 default: 00173 { 00174 if(ch == comment) 00175 { 00176 currentcharref = NextLine(currentchar); 00177 return tagsize; 00178 } 00179 //need 2 more chars for trailing 0s 00180 if(tagcap < tagsize + 3) 00181 { 00182 MINIINI_REALLOCATE(tagbuf, tagcap, tagsize, c); 00183 } 00184 //add new char to value 00185 tagbuf[tagsize] = ch; 00186 ++tagsize; 00187 } 00188 } 00189 } 00190 } 00191 00192 inline bool INISection::Header(const c * & currentcharref) 00193 { 00194 //ptr to the current character 00195 const c * currentchar = currentcharref; 00196 //current character 00197 register c ch; 00198 //Name doesn't skip [ so we skip it here 00199 ++currentchar; 00200 //searching for first newline 00201 for(; ; ++currentchar) 00202 { 00203 ch = *currentchar; 00204 switch(ch) 00205 { 00206 //CR, LF 00207 case 10: 00208 case 13: 00209 { 00210 //not a header 00211 currentcharref = NextLine(currentchar); 00212 return false; 00213 break; 00214 } 00215 case ']': 00216 { 00217 //if empty, ignore 00218 return static_cast<bool>(currentchar - currentcharref); 00219 break; 00220 } 00221 case '\0': 00222 { 00223 //not a header 00224 currentcharref = currentchar; 00225 return false; 00226 break; 00227 } 00228 default: 00229 { 00230 if(ch == comment) 00231 { 00232 currentcharref = NextLine(currentchar); 00233 return false; 00234 } 00235 break; 00236 } 00237 } 00238 } 00239 } 00240 00241 inline ui INISection::ParseInts(const c * * strings, int * out, const ui numstrings) 00242 { 00243 MINIINI_ASSERT(strings, "NULL pointer was passed as strings buffer to" 00244 "INISection::ParseInts()"); 00245 MINIINI_ASSERT(out, "NULL pointer was passed as output buffer to" 00246 "INISection::ParseInts()"); 00247 //Ptr to current string in strings 00248 const c * const * str = strings; 00249 //When string reaches this, we've iterated over all the strings 00250 const c * const * maxstr = strings + numstrings; 00251 //Number of actual valid ints written to out 00252 unsigned elems = 0; 00253 //Currently parsed int 00254 s32 tempelem; 00255 //Status of current conversion 00256 ConversionStatus status; 00257 //Iterating through strings read by ReadStrings and converting them to ints 00258 for(; str < maxstr; ++str) 00259 { 00260 status = ParseInt(*str, tempelem); 00261 if(status == CONV_ERR_TYPE) 00262 { 00263 MINIINI_ERROR("Non-integer value in an array or multi value tag " 00264 "where integer is expected. Terminating array / multi " 00265 "value reading. Value: %s", *str); 00266 break; 00267 } 00268 #ifdef MINIINI_DEBUG 00269 else if(status == CONV_WAR_OVERFLOW) 00270 { 00271 MINIINI_WARNING("Integer value in an array or multi value tag out of " 00272 "range." 00273 "Value: %s", *str); 00274 } 00275 else if(status == CONV_WAR_REDUNANT) 00276 { 00277 MINIINI_WARNING("Redunant characters in a tag where integer is " 00278 "expected. Reading integer. Value: %s", *str); 00279 } 00280 #endif 00281 out[elems] = static_cast<int>(tempelem); 00282 ++elems; 00283 } 00284 return elems; 00285 } 00286 00287 inline ui INISection::ParseFloats(const c * * strings, float * out, const ui numstrings) 00288 { 00289 MINIINI_ASSERT(strings, "NULL pointer was passed as strings buffer to" 00290 "INISection::ParseFloats()"); 00291 MINIINI_ASSERT(out, "NULL pointer was passed as output buffer to" 00292 "INISection::ParseFloats()"); 00293 //Ptr to current string in strings 00294 const c * const * string = strings; 00295 //When string reaches this, we've iterated over all the strings 00296 const c * const * const maxstring = strings + numstrings; 00297 //Number of actual valid floats written to out 00298 unsigned elems = 0; 00299 //Currently parsed float 00300 f tempelem; 00301 //Status of current conversion 00302 ConversionStatus status; 00303 //Iterating through strings read by ReadStrings and converting them to floats 00304 for(; string < maxstring; ++string) 00305 { 00306 status = ParseFloat(*string, tempelem); 00307 if(status == CONV_ERR_TYPE) 00308 { 00309 MINIINI_ERROR("Non-float value in an array or multi value tag where " 00310 "float is expected. Terminating array reading. " 00311 "Value: %s", *string); 00312 break; 00313 } 00314 #ifdef MINIINI_DEBUG 00315 else if(status == CONV_WAR_OVERFLOW) 00316 { 00317 MINIINI_WARNING("Float value in an array or multi value tag out of " 00318 "range. Value: %s", *string); 00319 } 00320 else if(status == CONV_WAR_REDUNANT) 00321 { 00322 MINIINI_WARNING("Redunant characters in a tag where float is " 00323 "expected. Reading float. Value: %s", *string); 00324 } 00325 #endif 00326 out[elems] = tempelem; 00327 ++elems; 00328 00329 } 00330 return elems; 00331 } 00332 00333 inline ui INISection::ParseBools(const c * * strings, bool * out, const ui numstrings) 00334 { 00335 MINIINI_ASSERT(strings, "NULL pointer was passed as strings buffer to" 00336 "INISection::ParseBools()"); 00337 MINIINI_ASSERT(out, "NULL pointer was passed as output buffer to" 00338 "INISection::ParseBools()"); 00339 //Ptr to current string in strings 00340 const c * const * string = strings; 00341 //When string reaches this, we've iterated over all the strings 00342 const c * const * const maxstring = strings + numstrings; 00343 //Number of actual valid bools written to out 00344 unsigned elems = 0; 00345 //Iterating through strings read by ReadStrings and converting them to bools 00346 for(; string < maxstring; ++string, ++elems) 00347 { 00348 switch(*string[0]) 00349 { 00350 case 't': 00351 case 'T': 00352 case 'y': 00353 case 'Y': 00354 case '1': 00355 out[elems] = true; 00356 break; 00357 case 'f': 00358 case 'F': 00359 case 'n': 00360 case 'N': 00361 case '0': 00362 out[elems] = false; 00363 break; 00364 default: 00365 MINIINI_ERROR("Non-bool value in a tag where bool is expected." 00366 "Value: %s", *string); 00367 goto BREAK_FOR; 00368 } 00369 } 00370 BREAK_FOR:; 00371 return elems; 00372 } 00373 #endif