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 <cstdio> 00006 #include <cstring> 00007 00008 #ifndef INI_NO_STL 00009 #include <string> 00010 #endif 00011 00012 #include "typedefs.h" 00013 #include "globals.h" 00014 #include "log.h" 00015 #include "linetoken.h" 00016 #include "inisection.h" 00017 #include "inifile.h" 00018 #include "util.h" 00019 00020 using namespace miniini_private; 00021 00022 bool INIFile::OpenFile(const char * const fname) 00023 { 00024 assert(fname); 00025 assert(!IsValid()); 00026 //opening file 00027 FILE * const file = fopen( fname, "rb" ); 00028 if(file == NULL) 00029 { 00030 ERROR("Couldn't open file. Maybe it does not exist? File: %s", 00031 fname); 00032 return false; 00033 } 00034 //determining filesize 00035 i seek = fseek(file, 0, SEEK_END); 00036 if(seek != 0) 00037 { 00038 fclose(file); 00039 ERROR("Couldn't reach end of file. File: %s", fname); 00040 return false; 00041 } 00042 const i size = ftell(file); 00043 if(size == -1) 00044 { 00045 fclose(file); 00046 ERROR("Couldn't determine size of file. File: %s", fname); 00047 return false; 00048 } 00049 seek = fseek(file, 0, SEEK_SET); 00050 if(seek!=0) 00051 { 00052 fclose(file); 00053 ERROR("Couldn't reach start of file. File: %s", fname); 00054 return false; 00055 } 00056 //reading file to a buffer 00057 c * const buf = new c [size + 1]; 00058 const i readnum = fread(buf, size, 1, file); 00059 //if 0 blocks succesfully read 00060 if(readnum == 0) 00061 { 00062 fclose(file); 00063 delete [] buf; 00064 ERROR("Could open but could not read from file. File might be " 00065 "corrupted or you might not have sufficient rights to " 00066 "read from it. File: %s", fname); 00067 return false; 00068 } 00069 //adding trailing zero to the buffer 00070 buf[size] = 0; 00071 bool out = LoadBuffer(buf, static_cast<unsigned>(size + 1)); 00072 delete [] buf; 00073 fclose(file); 00074 return out; 00075 } 00076 00078 00086 static inline ui Header(const c * & currentcharref, c * & header, ui & headercap) 00087 { 00088 //ptr to the current character 00089 const c * currentchar = currentcharref; 00090 //current character 00091 register c ch; 00092 //size of header in characters 00093 ui headersize = 0; 00094 //searching for [ 00095 for(; ; ++currentchar) 00096 { 00097 ch = *currentchar; 00098 switch(ch) 00099 { 00100 case ' ': 00101 case '\t': 00102 { 00103 //ignore spaces 00104 break; 00105 } 00106 //CR, LF 00107 case 10: 00108 case 13: 00109 { 00110 currentcharref = NextLine(currentchar); 00111 return 0; 00112 break; 00113 } 00114 //header start found, we can start reading header 00115 case '[': 00116 { 00117 //move to next char 00118 ++currentchar; 00119 goto HEADER_START; 00120 } 00121 case '\0': 00122 { 00123 currentcharref = currentchar; 00124 return 0; 00125 break; 00126 } 00127 default: 00128 { 00129 //comment char 00130 if(ch == comment) 00131 { 00132 currentcharref = NextLine(currentchar); 00133 return 0; 00134 } 00135 break; 00136 } 00137 } 00138 } 00139 HEADER_START:; 00140 //searching for ] and reading header characters 00141 for(; ; ++currentchar) 00142 { 00143 ch = *currentchar; 00144 switch(ch) 00145 { 00146 case ' ': 00147 case '\t': 00148 { 00149 //ignore spaces 00150 break; 00151 } 00152 //CR, LF 00153 case 10: 00154 case 13: 00155 { 00156 currentcharref = NextLine(currentchar); 00157 return 0; 00158 break; 00159 } 00160 //header end found, we're finished reading 00161 case ']': 00162 { 00163 header[headersize] = 0; 00164 currentcharref = NextLine(currentchar); 00165 return headersize; 00166 break; 00167 } 00168 case '\0': 00169 { 00170 currentcharref = currentchar; 00171 return 0; 00172 break; 00173 } 00174 default: 00175 { 00176 if(ch == comment) 00177 { 00178 currentcharref = NextLine(currentchar); 00179 return 0; 00180 } 00181 //reallocate header buffer if not enough space to add new char 00182 //need 1 more char for trailing 0 00183 if(headercap < headersize + 2) 00184 { 00185 REALLOCATE(header, headercap, headersize, c); 00186 } 00187 //add new char to header 00188 header[headersize] = ch; 00189 ++headersize; 00190 break; 00191 } 00192 } 00193 } 00194 } 00195 00196 bool INIFile::LoadBuffer(const char * buf, unsigned size) 00197 { 00198 assert(buf); 00199 assert(!IsValid()); 00200 //Allocating memory for ini sections' strings in 16 blocks- 00201 //that results in a little speed overhead but potential memory 00202 //overhead of the allocator is decreased to a bit more than 00203 //1/16 of file size. 00204 Alloc = new Allocator(size, 16); 00205 //capacity of temporary buffer of pointers to sections 00206 ui tempsectionscap = 16; 00207 INISection::InitTempData(); 00208 //temporary buffer of pointers to sections 00209 INISection * * tempsections = new INISection * [tempsectionscap]; 00210 //ptr to the current character in buffer 00211 const c * currentchar = buf; 00212 //allocated capacity of headername 00213 ui headercap = 64; 00214 //buffer to load section header name to. 00215 c * headername = new c [headercap]; 00216 //number of chars in headername 00217 ui headersize; 00218 //Loading the default INI section 00219 INISection * newsection = new INISection(); 00220 newsection->Init("[DEFAULT]", ¤tchar, Alloc); 00221 Insert(tempsections, Length, newsection); 00222 ++Length; 00223 //Iterating through lines in buffer, reading sections found 00224 while(*currentchar != '\0') 00225 { 00226 //Header() leaves currentchar at start of next line 00227 headersize = Header(currentchar, headername, headercap); 00228 //header found 00229 if(headersize) 00230 { 00231 //if temp section ptrs buffer runs out of space, reallocate it 00232 if(Length + 1 > tempsectionscap) 00233 { 00234 REALLOCATE(tempsections, tempsectionscap, Length, INISection *); 00235 } 00236 //Try to load new section 00237 newsection = new INISection(); 00238 newsection->Init(headername, ¤tchar, Alloc); 00239 //Insert new section 00240 Insert(tempsections, Length, newsection); 00241 ++Length; 00242 } 00243 } 00244 delete [] headername; 00245 if(!Length) 00246 { 00247 WARNING("Empty INI file/buffer."); 00248 } 00249 //copy pointers from tempsections to Sections and delete tempsections 00250 Sections = new INISection * [Length]; 00251 memcpy(Sections, tempsections, Length * sizeof(INISection *)); 00252 delete [] tempsections; 00253 INISection::DestroyTempData(); 00254 //Remove any unused memory blocks from the allocator. 00255 Alloc->Trim(); 00256 return true; 00257 } 00258 00259 INIFile::~INIFile() 00260 { 00261 if(!(Sections && Alloc)) 00262 { 00263 return; 00264 } 00265 for(ui section = 0; section < Length; ++section) 00266 { 00267 delete Sections[section]; 00268 } 00269 delete [] Sections; 00270 delete Alloc; 00271 } 00272 00273 INISection * INIFile::GetSection(const char * const name) const 00274 { 00275 assert(IsValid()); 00276 assert(name); 00277 i sectionidx = BinarySearch(Sections, Length, name); 00278 if(sectionidx >= 0) 00279 { 00280 return Sections[sectionidx]; 00281 } 00282 ERROR("Missing requested section. Section: %s", name); 00283 return NULL; 00284 } 00285 00286 void INIFile::Benchmark(BenchmarkType type, bool stl) 00287 { 00288 INISection * section; 00289 for(ui s = 0; s < Length; ++s) 00290 { 00291 if(stl) 00292 { 00293 section = GetSection(Sections[s]->Name); 00294 } 00295 #ifndef INI_NO_STL 00296 else 00297 { 00298 section = GetSection(std::string(Sections[s]->Name)); 00299 } 00300 #endif 00301 switch(type) 00302 { 00303 case BT_STRING: 00304 section->BenchString(stl); 00305 break; 00306 case BT_INT: 00307 section->BenchInt(stl); 00308 break; 00309 case BT_FLOAT: 00310 section->BenchFloat(stl); 00311 break; 00312 case BT_BOOL: 00313 section->BenchBool(stl); 00314 break; 00315 case BT_MULTISTRING: 00316 section->BenchMultiString(stl); 00317 break; 00318 case BT_MULTIINT: 00319 section->BenchMultiInt(stl); 00320 break; 00321 case BT_MULTIFLOAT: 00322 section->BenchMultiFloat(stl); 00323 break; 00324 case BT_MULTIBOOL: 00325 section->BenchMultiBool(stl); 00326 break; 00327 case BT_STRINGS: 00328 section->BenchStrings(stl); 00329 break; 00330 case BT_INTS: 00331 section->BenchInts(stl); 00332 break; 00333 case BT_FLOATS: 00334 section->BenchFloats(stl); 00335 case BT_BOOLS: 00336 section->BenchBools(stl); 00337 break; 00338 default: 00339 ERROR("Unknown benchmark type"); 00340 break; 00341 } 00342 } 00343 }