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 #include <cstring> 00006 #include <cerrno> 00007 #include <cstdlib> 00008 #include <cassert> 00009 #include <climits> 00010 00011 #include "typedefs.h" 00012 #include "globals.h" 00013 #include "log.h" 00014 #include "linetoken.h" 00015 #include "inisection.h" 00016 #include "util.h" 00017 00018 using namespace miniini_private; 00019 00020 ui INISection::temptagscap = 0; 00021 c * * INISection::temptags = NULL; 00022 ui INISection::tagcap = 0; 00023 c * INISection::tagbuf = NULL; 00024 00027 #define FOR_4(instr) \ 00028 {\ 00029 instr;\ 00030 instr;\ 00031 instr;\ 00032 instr;\ 00033 } 00034 00035 00036 inline LineToken INISection::TagName(const c * & currentcharref, ui & tagsize) 00037 { 00038 //ptr to the current character 00039 const c * currentchar = currentcharref; 00040 //current character 00041 register c ch; 00042 for(;;) 00043 { 00044 //reallocate header buffer if not enough space to add new chars 00045 //need 4 chars for unrolled part of the loop, 3 for trailing zeroes 00046 //since tag and value are stored in the same buffer separated by a zero 00047 //and the last tag is followed by two zeroes 00048 if(tagcap < tagsize + 7) 00049 { 00050 REALLOCATE(tagbuf, tagcap, tagsize, c); 00051 } 00052 //unrolled part of the loop (process 4 chars) 00053 FOR_4 00054 ( 00055 { 00056 ch = *currentchar; 00057 switch(ch) 00058 { 00059 case ' ': 00060 case '\t': 00061 { 00062 //ignore spaces 00063 break; 00064 } 00065 //CR, LF 00066 case 10: 00067 case 13: 00068 { 00069 currentcharref = NextLine(currentchar); 00070 return LT_NAME; 00071 break; 00072 } 00073 //header start found. 00074 case '[': 00075 { 00076 currentcharref = currentchar; 00077 return LT_HEADER; 00078 break; 00079 } 00080 case '\0': 00081 { 00082 currentcharref = currentchar; 00083 return LT_NAME; 00084 break; 00085 } 00086 default: 00087 { 00088 //value found, if tag name is not empty, start reading val 00089 if(ch == namevalsep) 00090 { 00091 if(tagsize) 00092 { 00093 //adding trailing zero to the tag name 00094 tagbuf[tagsize] = 0; 00095 ++tagsize; 00096 currentcharref = currentchar + 1; 00097 return LT_VAL; 00098 } 00099 else 00100 { 00101 WARNING("Empty tag name."); 00102 currentcharref = NextLine(currentchar); 00103 return LT_NAME; 00104 } 00105 } 00106 if(ch == comment) 00107 { 00108 currentcharref = NextLine(currentchar); 00109 return LT_NAME; 00110 } 00111 //add new char to tag name. 00112 tagbuf[tagsize] = ch; 00113 ++tagsize; 00114 break; 00115 } 00116 } 00117 ++currentchar; 00118 } 00119 ) 00120 } 00121 } 00122 00123 inline ui INISection::TagValue(const c * & currentcharref, ui tagsize) 00124 { 00125 //ptr to the current character 00126 const c * currentchar = currentcharref; 00127 //current character 00128 register c ch; 00129 //reading characters of value 00130 for(; ; ++currentchar) 00131 { 00132 ch = *currentchar; 00133 switch(ch) 00134 { 00135 case ' ': 00136 case '\t': 00137 { 00138 //ignore spaces 00139 break; 00140 } 00141 //CR, LF 00142 case 10: 00143 case 13: 00144 { 00145 currentcharref = NextLine(currentchar); 00146 return tagsize; 00147 break; 00148 } 00149 case '\0': 00150 { 00151 currentcharref = currentchar; 00152 return tagsize; 00153 break; 00154 } 00155 case ',': 00156 { 00157 //need 2 more chars for trailing 0s 00158 if(tagcap < tagsize + 3) 00159 { 00160 REALLOCATE(tagbuf, tagcap, tagsize, c); 00161 } 00162 //add new char to value 00163 tagbuf[tagsize] = '\0'; 00164 ++tagsize; 00165 break; 00166 } 00167 default: 00168 { 00169 if(ch == comment) 00170 { 00171 currentcharref = NextLine(currentchar); 00172 return tagsize; 00173 } 00174 //need 2 more chars for trailing 0s 00175 if(tagcap < tagsize + 3) 00176 { 00177 REALLOCATE(tagbuf, tagcap, tagsize, c); 00178 } 00179 //add new char to value 00180 tagbuf[tagsize] = ch; 00181 ++tagsize; 00182 } 00183 } 00184 } 00185 } 00186 00187 inline bool INISection::Header(const c * & currentcharref) 00188 { 00189 //ptr to the current character 00190 const c * currentchar = currentcharref; 00191 //current character 00192 register c ch; 00193 //Name doesn't skip [ so we skip it here 00194 ++currentchar; 00195 //searching for first newline 00196 for(; ; ++currentchar) 00197 { 00198 ch = *currentchar; 00199 switch(ch) 00200 { 00201 //CR, LF 00202 case 10: 00203 case 13: 00204 { 00205 //not a header 00206 currentcharref = NextLine(currentchar); 00207 return false; 00208 break; 00209 } 00210 case ']': 00211 { 00212 //if empty, ignore 00213 return static_cast<bool>(currentchar - currentcharref); 00214 break; 00215 } 00216 case '\0': 00217 { 00218 //not a header 00219 currentcharref = currentchar; 00220 return false; 00221 break; 00222 } 00223 default: 00224 { 00225 if(ch == comment) 00226 { 00227 currentcharref = NextLine(currentchar); 00228 return false; 00229 } 00230 break; 00231 } 00232 } 00233 } 00234 } 00235 00236 void INISection::Init(const c * const sectionname, const c * * const currentcharptr, 00237 Allocator * const alloc) 00238 { 00239 assert(sectionname); 00240 assert(alloc); 00241 assert(currentcharptr); 00242 assert(*currentcharptr); 00243 assert(temptags); 00244 assert(tagbuf); 00245 //Copying allocator ptr 00246 Alloc = alloc; 00247 //Copying name of the section 00248 const ui namelen = strlen(sectionname) + 1; 00249 assert(namelen > 1); 00250 Name = Alloc->NewSpace(namelen); 00251 memcpy(Name, sectionname, namelen); 00252 //ptr to the current character in buffer 00253 const c * currentchar = *currentcharptr; 00254 //Iterating through lines in the buffer 00255 while(*currentchar != '\0') 00256 { 00257 //size of tag name (if any) read 00258 ui namesize = 0; 00259 //goes to start of next line if nothing found, 00260 //if value found, stops right after name=value separator, 00261 //if header found, stays at beginning of line 00262 LineToken token = TagName(currentchar, namesize); 00263 //value found (this line is a name=value pair) 00264 if(token == LT_VAL) 00265 { 00266 //size of name and value 00267 ui tagsize = TagValue(currentchar, namesize); 00268 //value is empty 00269 if(namesize == tagsize) 00270 { 00271 WARNING("Empty value in a tag (no characters after name=value " 00272 "separator. Ignoring. Section: %s", Name); 00273 continue; 00274 } 00275 //adding trailing zero to the tag value 00276 tagbuf[tagsize] = tagbuf[tagsize + 1] = 0; 00277 tagsize += 2; 00278 //if needed, reallocate the temp tags buffer 00279 if(Length >= temptagscap) 00280 { 00281 REALLOCATE(temptags, temptagscap, Length, c *); 00282 } 00283 //Add new tag to temp tags buffer. 00284 c * newtag = Alloc->NewSpace(tagsize); 00285 memcpy(newtag, tagbuf, tagsize * sizeof(c)); 00286 Insert(temptags, Length, newtag); 00287 ++Length; 00288 } 00289 //header found 00290 else if(token == LT_HEADER) 00291 { 00292 //if this line is a header, we're finished loading the section 00293 if(Header(currentchar)) 00294 { 00295 break; 00296 } 00297 //else Header() leaves currentchar at the start of next line 00298 } 00299 } 00300 //Updating line token ptr of the caller 00301 *currentcharptr = currentchar; 00302 //There are no tags in the section 00303 if(!Length) 00304 { 00305 WARNING("Empty section. Section: %s", Name); 00306 } 00307 //Copy temp lines buffer to Lines 00308 Tags = new c * [Length]; 00309 memcpy(Tags, temptags, Length * sizeof(c *)); 00310 } 00311 00312 INISection::~INISection() 00313 { 00314 //There is no need to tell allocator to delete data here, 00315 //since this is only called on INIFile destruction and that's 00316 //when Allocator gets destroyed and deletes the data anyway. 00317 //However, if/when section deletion is implemented, there 00318 //will need to be a separate dtor to handle that case. 00319 if(Tags) 00320 { 00321 delete [] Tags; 00322 } 00323 } 00324 00325 inline bool INISection::ReadString(const char * const name, const char * & out) const 00326 { 00327 assert(name); 00328 i pos = BinarySearch(Tags, Length, name); 00329 if(pos >= 0) 00330 { 00331 out = Tags [pos] + strlen(Tags[pos]) + 1; 00332 return true; 00333 } 00334 return false; 00335 } 00336 00337 bool INISection::ReadInt(const char * const name, int & out) const 00338 { 00339 assert(name); 00340 //Points to char where strtol finished processing. Used to check for errors 00341 c * tail; 00342 errno = 0; 00343 const c * valstr; 00344 //Requested tag does not exist 00345 if(!ReadString(name, valstr)) 00346 { 00347 return false; 00348 } 00349 const long tempout = strtol(valstr, &tail, 0); 00350 const c tailc = tail[0]; 00351 if(tailc == valstr[0]) 00352 { 00353 ERROR("Non-integer value in a tag where integer is expected." 00354 "Section: %s Tag: %s Value: %s", Name, name, valstr); 00355 return false; 00356 } 00357 if(errno) 00358 { 00359 //this is an error because in my tests strtol returned -1 on overflow. 00360 ERROR("Integer value out of range." 00361 "Section: %s Tag: %s Value: %s", Name, name, valstr); 00362 return false; 00363 } 00364 #ifdef INI_DEBUG 00365 if(tailc) 00366 { 00367 WARNING("Redunant characters in a tag where integer is " 00368 "expected. Reading integer." 00369 "Section: %s Tag: %s Value: %s", Name, name, valstr); 00370 } 00371 #endif 00372 out = static_cast<int>(tempout); 00373 return true; 00374 } 00375 00376 bool INISection::ReadFloat(const char * const name, float & out) const 00377 { 00378 assert(name); 00379 //Points to char where strtof finished processing. Used to check for errors 00380 c * tail; 00381 errno = 0; 00382 const c * valstr; 00383 //Requested tag does not exist 00384 if(!ReadString(name, valstr)) 00385 { 00386 return false; 00387 } 00388 const float tempout = strtof(valstr, &tail); 00389 const c tailc = tail[0]; 00390 if(tailc == valstr[0]) 00391 { 00392 ERROR("Non-float value in a tag where float is expected." 00393 "Section: %s Tag: %s Value: %s", Name, name, valstr); 00394 return false; 00395 } 00396 if(errno) 00397 { 00398 ERROR("Float value out of range." 00399 "Section: %s Tag: %s Value: %s", Name, name, valstr); 00400 return false; 00401 } 00402 #ifdef INI_DEBUG 00403 if(tailc) 00404 { 00405 WARNING("Redunant characters in a tag where float is " 00406 "expected. Reading float." 00407 "Section: %s Tag: %s Value: %s", Name, name, valstr); 00408 } 00409 #endif 00410 out = tempout; 00411 return true; 00412 } 00413 00414 bool INISection::ReadBool( const char * const name, bool & out) const 00415 { 00416 assert(name); 00417 const c * valstr; 00418 //Requested tag does not exist 00419 if(!ReadString(name, valstr)) 00420 { 00421 return false; 00422 } 00423 //Parsing bool using the first character only 00424 switch(valstr[0]) 00425 { 00426 case 't': 00427 case 'T': 00428 case 'y': 00429 case 'Y': 00430 case '1': 00431 out = true; 00432 return true; 00433 case 'f': 00434 case 'F': 00435 case 'n': 00436 case 'N': 00437 case '0': 00438 out = false; 00439 return true; 00440 default: 00441 return false; 00442 } 00443 return false; 00444 } 00445 00446 inline ui INISection::ParseInts(const c * * strings, int * out, const ui numstrings) 00447 { 00448 //Ptr to current string in strings 00449 const c * const * str = strings; 00450 //When string reaches this, we've iterated over all the strings 00451 const c * const * maxstr = strings + numstrings; 00452 //Number of actual valid ints written to out 00453 unsigned elems = 0; 00454 //Points to char where strtol finished processing. Used to check for errors 00455 c * tail; 00456 //Iterating through strings read by ReadStrings and converting them to ints 00457 for(; str < maxstr; ++str) 00458 { 00459 errno = 0; 00460 const long tempelem = strtol(*str, &tail, 0); 00461 const c tailc = tail[0]; 00462 if(tailc == *str[0]) 00463 { 00464 ERROR("Non-integer value in an array or multi value tag where " 00465 "integer is expected. Terminating array / multi value" 00466 "reading. Value: %s", *str); 00467 break; 00468 } 00469 if(errno) 00470 { 00471 //this is an error because in some of my tests strtol returned -1 on overflow. 00472 ERROR("Integer value in an array or multi value tag out of range." 00473 "Terminating array / multi value reading. Value: %s", *str); 00474 break; 00475 } 00476 #ifdef INI_DEBUG 00477 if(tailc) 00478 { 00479 WARNING("Redunant characters in a tag where integer is expected. " 00480 "Reading integer. Value: %s", *str); 00481 } 00482 #endif 00483 out[elems] = static_cast<int>(tempelem); 00484 ++elems; 00485 } 00486 return elems; 00487 } 00488 00489 inline ui INISection::ParseFloats(const c * * strings, float * out, const ui numstrings) 00490 { 00491 //Ptr to current string in strings 00492 const c * const * string = strings; 00493 //When string reaches this, we've iterated over all the strings 00494 const c * const * const maxstring = strings + numstrings; 00495 //Number of actual valid floats written to out 00496 unsigned elems = 0; 00497 //Points to char where strtof finished processing. Used to check for errors 00498 c * tail; 00499 //Iterating through strings read by ReadStrings and converting them to floats 00500 for(; string < maxstring; ++string) 00501 { 00502 errno = 0; 00503 const f tempelem = strtof(*string, &tail); 00504 const c tailc = tail[0]; 00505 if(tailc == *string[0]) 00506 { 00507 ERROR("Non-float value in an array tag where float is expected. " 00508 "Terminating array reading. Value: %s", *string); 00509 break; 00510 } 00511 if(errno) 00512 { 00513 ERROR("Float value in an array tag out of range. Terminating array " 00514 "reading. Value: %s", *string); 00515 break; 00516 } 00517 #ifdef INI_DEBUG 00518 if(tailc) 00519 { 00520 WARNING("Redunant characters in a tag where float is expected. " 00521 "Reading float. Value: %s", *string); 00522 } 00523 #endif 00524 out[elems] = tempelem; 00525 ++elems; 00526 } 00527 return elems; 00528 } 00529 00530 inline ui INISection::ParseBools(const c * * strings, bool * out, const ui numstrings) 00531 { 00532 //Ptr to current string in strings 00533 const c * const * string = strings; 00534 //When string reaches this, we've iterated over all the strings 00535 const c * const * const maxstring = strings + numstrings; 00536 //Number of actual valid bools written to out 00537 unsigned elems = 0; 00538 //Iterating through strings read by ReadStrings and converting them to bools 00539 for(; string < maxstring; ++string, ++elems) 00540 { 00541 switch(*string[0]) 00542 { 00543 case 't': 00544 case 'T': 00545 case 'y': 00546 case 'Y': 00547 case '1': 00548 out[elems] = true; 00549 break; 00550 case 'f': 00551 case 'F': 00552 case 'n': 00553 case 'N': 00554 case '0': 00555 out[elems] = false; 00556 break; 00557 default: 00558 goto BREAK_FOR; 00559 } 00560 } 00561 BREAK_FOR:; 00562 return elems; 00563 } 00564 00565 unsigned INISection::MultiValSize(const char * const name) const 00566 { 00567 assert(name); 00568 //ptr to current position in tag 00569 const c * tag; 00570 //Number of elements in the tag 00571 ui elems = 0; 00572 i pos = BinarySearch(Tags, Length, name); 00573 if(pos >= 0) 00574 { 00575 //get to the start of the first value 00576 tag = Tags[pos]; 00577 while(*tag != '\0') 00578 { 00579 ++tag; 00580 } 00581 ++tag; 00582 //now we're at the first char of value 00583 while(*tag != '\0') 00584 { 00585 ++elems; 00586 while(*tag != '\0') 00587 { 00588 ++tag; 00589 } 00590 ++tag; 00591 //now we're at the char after the trailing zero of previous value 00592 } 00593 return static_cast<unsigned>(elems); 00594 } 00595 return 0; 00596 } 00597 00598 unsigned INISection::ReadMultiString(const char * const name, const char * * out, 00599 const unsigned cap) const 00600 { 00601 assert(name); 00602 assert(out); 00603 //ptr to current position in tag 00604 const c * tag; 00605 //Number of elements in the tag 00606 ui elems = 0; 00607 i pos = BinarySearch(Tags, Length, name); 00608 //tag exists 00609 if(pos >= 0) 00610 { 00611 //get to the start of the first value 00612 tag = Tags[pos]; 00613 while(*tag != '\0') 00614 { 00615 ++tag; 00616 } 00617 ++tag; 00618 //now we're at the first char of value 00619 while(*tag != '\0') 00620 { 00621 //out of capacity, don't read any more values 00622 if(elems == cap) 00623 { 00624 WARNING("Multi value tag element out of capacity." 00625 "Section: %s Tag name: %s Capacity: %d", Name, name, cap); 00626 break; 00627 } 00628 //add element 00629 out[elems] = tag; 00630 ++elems; 00631 //get to the zero after the current value 00632 while(*tag != '\0') 00633 { 00634 ++tag; 00635 } 00636 //go to the next character. if it's 0, we're at the end of the tag, 00637 //otherwise, there is another value. 00638 ++tag; 00639 //now we're at the char after the trailing zero of previous value 00640 } 00641 return static_cast<unsigned>(elems); 00642 } 00643 return 0; 00644 00645 } 00646 00647 unsigned INISection::ReadMultiInt(const char * const name, int * out, 00648 const unsigned cap) const 00649 { 00650 assert(name); 00651 assert(out); 00652 //Array of value strings to be converted to ints 00653 const c * * const valstrs = new const c * [cap]; 00654 //Number of strings read by ReadStrings to valstrs 00655 const ui tempelems = ReadMultiString(name, valstrs, cap); 00656 ui output = ParseInts(valstrs, out, tempelems); 00657 delete [] valstrs; 00658 return static_cast<unsigned>(output); 00659 } 00660 00661 unsigned INISection::ReadMultiFloat(const char * const name, float * out, 00662 const unsigned cap) const 00663 { 00664 assert(name); 00665 assert(out); 00666 //Array of value strings to be converted to floats 00667 const c * * const valstrs = new const c * [cap]; 00668 //Number of strings read by ReadStrings to valstrs 00669 const ui tempelems = ReadMultiString(name, valstrs, cap); 00670 ui output = ParseFloats(valstrs, out, tempelems); 00671 delete [] valstrs; 00672 return static_cast<unsigned>(output); 00673 } 00674 00675 unsigned INISection::ReadMultiBool(const char * const name, bool * out, 00676 const unsigned cap) const 00677 { 00678 assert(name); 00679 assert(out); 00680 //Array of value strings to be converted to floats 00681 const c * * const valstrs = new const c * [cap]; 00682 //Number of strings read by ReadStrings to valstrs 00683 const ui tempelems = ReadMultiString(name, valstrs, cap); 00684 ui output = ParseBools(valstrs, out, tempelems); 00685 delete [] valstrs; 00686 return static_cast<unsigned>(output); 00687 } 00688 00689 #ifndef INI_NO_STL 00690 unsigned INISection::ReadMultiString(const std::string & name, 00691 std::vector<std::string> & out) const 00692 { 00693 const char * cname = name.c_str(); 00694 unsigned numelems = MultiValSize(cname); 00695 //Read data to this array first 00696 const char * * tempstrs = new const char * [numelems]; 00697 numelems = ReadMultiString(cname, tempstrs, numelems); 00698 out.reserve(numelems); 00699 //Move data to output vector 00700 for(ui str = 0; str < numelems; ++str) 00701 { 00702 out.push_back(std::string(tempstrs[str])); 00703 } 00704 delete [] tempstrs; 00705 return numelems; 00706 } 00707 00708 unsigned INISection::ReadMultiInt(const std::string & name, 00709 std::vector<int> & out) const 00710 { 00711 const char * cname = name.c_str(); 00712 unsigned numelems = MultiValSize(cname); 00713 //Read data to this array first 00714 int * tempints = new int [numelems]; 00715 numelems = ReadMultiInt(cname, tempints, numelems); 00716 out.reserve(numelems); 00717 //Move data to output vector 00718 for(ui in = 0; in < numelems; ++in) 00719 { 00720 out.push_back(tempints[in]); 00721 } 00722 delete [] tempints; 00723 return numelems; 00724 } 00725 00726 unsigned INISection::ReadMultiFloat(const std::string & name, 00727 std::vector<float> & out) const 00728 { 00729 const char * cname = name.c_str(); 00730 unsigned numelems = MultiValSize(cname); 00731 //Read data to this array first 00732 float * tempfloats = new float [numelems]; 00733 numelems = ReadMultiFloat(cname, tempfloats, numelems); 00734 out.reserve(numelems); 00735 //Move data to output vector 00736 for(ui fl = 0; fl < numelems; ++fl) 00737 { 00738 out.push_back(tempfloats[fl]); 00739 } 00740 delete [] tempfloats; 00741 return numelems; 00742 } 00743 00744 unsigned INISection::ReadMultiBool(const std::string & name, 00745 std::vector<bool> & out) const 00746 { 00747 const char * cname = name.c_str(); 00748 unsigned numelems = MultiValSize(cname); 00749 //Read data to this array first 00750 bool * tempbools = new bool [numelems]; 00751 numelems = ReadMultiBool(cname, tempbools, numelems); 00752 out.reserve(numelems); 00753 //Move data to output vector 00754 for(ui bo = 0; bo < numelems; ++bo) 00755 { 00756 out.push_back(tempbools[bo]); 00757 } 00758 delete [] tempbools; 00759 return numelems; 00760 } 00761 #endif 00762 00763 unsigned INISection::ArraySize(const char * const name) const 00764 { 00765 assert(name); 00766 ui namelen = strlen(name); 00767 //ptr to current tag 00768 const c * tag; 00769 //Points to char where strtol finished processing. Used to check for errors 00770 c * tail; 00771 //Index of current array element 00772 ui elemidx; 00773 ui indicescap = 32; 00774 ui indicessize = 0; 00775 //Stores indices of found elements 00776 ui * indices = new ui [indicescap]; 00777 for(ui idx = 0; idx < Length; ++idx) 00778 { 00779 tag = Tags[idx]; 00780 //if tag name starts by name 00781 if(!strncmp(name, tag, namelen)) 00782 { 00783 errno = 0; 00784 elemidx = strtol(tag + namelen, &tail, 0); 00785 //Note: If tag contains no integer, elemidx will be set to 0 which 00786 //will never be read. 00787 //Redunant chars after int - probably a different tag name or error 00788 if(tail[0]) 00789 { 00790 WARNING("Redunant characters after integer in tag name. " 00791 "Ignoring. Section: %s Tag name: %s", Name, tag); 00792 continue; 00793 } 00794 #ifdef INI_DEBUG 00795 //Huge (out of range) integer in tag name- 00796 //Probably a different tag name or error 00797 if(errno == ERANGE) 00798 { 00799 WARNING("Integer in tag name out of range. Ignoring. " 00800 "Section: %s Tag name: %s", Name, tag); 00801 continue; 00802 } 00803 #endif 00804 //elemidx can be 0 if tag contains no integer 00805 if(elemidx) 00806 { 00807 //Reallocating indices if out of space 00808 if(indicessize >= indicescap) 00809 { 00810 REALLOCATE(indices, indicescap, indicessize, ui); 00811 } 00812 //Correct index, counting this array element 00813 indices[indicessize] = elemidx - 1; 00814 ++indicessize; 00815 } 00816 } 00817 } 00818 ui elems = 0; 00819 bool finished = false; 00820 //Count number of consecutive indices 00821 while(!finished) 00822 { 00823 finished = true; 00824 for(ui idx = 0; idx < indicessize; ++idx) 00825 { 00826 if(indices[idx] == elems) 00827 { 00828 ++elems; 00829 finished = false; 00830 } 00831 } 00832 } 00833 return static_cast<unsigned>(elems); 00834 } 00835 00836 unsigned INISection::ReadStrings(const char * const name, const char * * out, 00837 const unsigned cap) const 00838 { 00839 assert(name); 00840 assert(out); 00841 ui namelen = strlen(name); 00842 //we fill out with zeroes, so we can search for null ptr to determine how 00843 //many elements we've read 00844 memset(out, 0, sizeof(const char *) * cap); 00845 //ptr to current tag 00846 const c * tag; 00847 //Points to char where strtol finished processing. Used to check for errors 00848 c * tail; 00849 //Index of current array element 00850 ui elemidx; 00851 for(ui idx = 0; idx < Length; ++idx) 00852 { 00853 tag = Tags[idx]; 00854 //if tag name starts by name 00855 if(!strncmp(name, tag, namelen)) 00856 { 00857 errno = 0; 00858 elemidx = strtol(tag + namelen, &tail, 0); 00859 //Note: If tag contains no integer, elemidx will be set to 0 which 00860 //will never be read. 00861 //Redunant chars after int - probably a different tag name or error 00862 if(tail[0]) 00863 { 00864 WARNING("Redunant characters after integer in tag name. " 00865 "Ignoring. Section: %s Tag name: %s", Name, tag); 00866 continue; 00867 } 00868 #ifdef INI_DEBUG 00869 //Huge (out of range) integer in tag name- 00870 //Probably a different tag name or error 00871 if(errno == ERANGE) 00872 { 00873 WARNING("Integer in tag name out of range. Ignoring. " 00874 "Section: %s Tag name: %s", Name, tag); 00875 continue; 00876 } 00877 #endif 00878 //Out of capacity 00879 if(elemidx > cap) 00880 { 00881 WARNING("Array element out of capacity." 00882 "Section: %s Tag name: %s Capacity: %d", Name, tag, cap); 00883 continue; 00884 } 00885 //elemidx can be 0 if tag contains no integer 00886 if(elemidx) 00887 { 00888 //Correct index at the end of name, reading array element 00889 out[elemidx - 1] = (tag) + strlen(tag) + 1; 00890 } 00891 } 00892 } 00893 //return number of valid elements read 00894 //(if, say, elem 19 is missing, only elems 0-18 are valid) 00895 for(unsigned elem = 0; elem < cap; ++elem) 00896 { 00897 if(!out[elem]) 00898 { 00899 return elem; 00900 } 00901 } 00902 return cap; 00903 } 00904 00905 unsigned INISection::ReadInts(const char * const name, int * out, 00906 const unsigned cap) const 00907 { 00908 assert(name); 00909 assert(out); 00910 //Array of value strings to be converted to ints 00911 const c * * const valstrs = new const c * [cap]; 00912 //Number of strings read by ReadStrings to valstrs 00913 const ui tempelems = ReadStrings(name, valstrs, cap); 00914 ui output = ParseInts(valstrs, out, tempelems); 00915 delete [] valstrs; 00916 return static_cast<unsigned>(output); 00917 } 00918 00919 unsigned INISection::ReadFloats(const char * const name, float * out, 00920 const unsigned cap) const 00921 { 00922 assert(name); 00923 assert(out); 00924 //Array of value strings to be converted to floats 00925 const c * * const valstrs = new const c * [cap]; 00926 //Number of strings read by ReadStrings to valstrs 00927 const ui tempelems = ReadStrings(name, valstrs, cap); 00928 ui output = ParseFloats(valstrs, out, tempelems); 00929 delete [] valstrs; 00930 return static_cast<unsigned>(output); 00931 } 00932 00933 unsigned INISection::ReadBools(const char * const name, bool * out, 00934 const unsigned cap) const 00935 { 00936 assert(name); 00937 assert(out); 00938 //Array of value strings to be converted to bools 00939 const c * * const valstrs = new const c * [cap]; 00940 //Number of strings read by ReadStrings to valstrs 00941 const ui tempelems = ReadStrings(name, valstrs, cap); 00942 ui output = ParseBools(valstrs, out, tempelems); 00943 delete [] valstrs; 00944 return static_cast<unsigned>(output); 00945 } 00946 00947 #ifndef INI_NO_STL 00948 unsigned INISection::ReadStrings(const std::string & name, 00949 std::vector<std::string> & out) const 00950 { 00951 const char * cname = name.c_str(); 00952 unsigned numelems = ArraySize(cname); 00953 //Read data to this array first 00954 const char * * tempstrs = new const char * [numelems]; 00955 numelems = ReadStrings(cname, tempstrs, numelems); 00956 out.reserve(numelems); 00957 //Move data to output vector 00958 for(ui str = 0; str < numelems; ++str) 00959 { 00960 out.push_back(std::string(tempstrs[str])); 00961 } 00962 delete [] tempstrs; 00963 return numelems; 00964 } 00965 00966 unsigned INISection::ReadInts(const std::string & name, 00967 std::vector<int> & out) const 00968 { 00969 const char * cname = name.c_str(); 00970 unsigned numelems = ArraySize(cname); 00971 //Read data to this array first 00972 int * tempints = new int [numelems]; 00973 numelems = ReadInts(cname, tempints, numelems); 00974 out.reserve(numelems); 00975 //Move data to output vector 00976 for(ui in = 0; in < numelems; ++in) 00977 { 00978 out.push_back(tempints[in]); 00979 } 00980 delete [] tempints; 00981 return numelems; 00982 } 00983 00984 unsigned INISection::ReadFloats(const std::string & name, 00985 std::vector<float> & out) const 00986 { 00987 const char * cname = name.c_str(); 00988 unsigned numelems = ArraySize(cname); 00989 //Read data to this array first 00990 float * tempfloats = new float [numelems]; 00991 numelems = ReadFloats(cname, tempfloats, numelems); 00992 out.reserve(numelems); 00993 //Move data to output vector 00994 for(ui fl = 0; fl < numelems; ++fl) 00995 { 00996 out.push_back(tempfloats[fl]); 00997 } 00998 delete [] tempfloats; 00999 return numelems; 01000 } 01001 01002 unsigned INISection::ReadBools(const std::string & name, 01003 std::vector<bool> & out) const 01004 { 01005 const char * cname = name.c_str(); 01006 unsigned numelems = ArraySize(cname); 01007 //Read data to this array first 01008 bool * tempbools = new bool [numelems]; 01009 numelems = ReadBools(cname, tempbools, numelems); 01010 out.reserve(numelems); 01011 //Move data to output vector 01012 for(ui bo = 0; bo < numelems; ++bo) 01013 { 01014 out.push_back(tempbools[bo]); 01015 } 01016 delete [] tempbools; 01017 return numelems; 01018 } 01019 #endif