Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » What's wrong with my readline function?

This thread is locked; no one can reply to it. rss feed Print
What's wrong with my readline function?
jmasterx
Member #11,410
October 2009

I used to use ifstream everywhere and used getline(ifs,line) to get a line of text. I'm trying to create a function that does the same thing. Instead of using streams I'm now creating my own File class which utilizes PhysFS.

Here is my class:

#SelectExpand
1#include "Game/Utility/File.hpp" 2namespace cge 3{ 4 File::File(void) 5 : m_file(NULL) 6 { 7 } 8 9 File::File( const std::string& fileName, const std::string& openMode /*= "r"*/ ) 10 : m_file(NULL) 11 { 12 open(fileName,openMode); 13 } 14 15 File::~File(void) 16 { 17 } 18 19 bool File::isOpen() const 20 { 21 return m_file != NULL; 22 } 23 24 bool File::open( const std::string& fileName, const std::string& openMode ) 25 { 26 m_file = al_fopen(fileName.c_str(),openMode.c_str()); 27 28 return m_file != NULL; 29 } 30 31 bool File::close() 32 { 33 if(isOpen()) 34 { 35 al_fclose(m_file); 36 m_file = NULL; 37 return true; 38 } 39 return false; 40 } 41 42 bool File::eof() const 43 { 44 if(!isOpen()) 45 { 46 return true; 47 } 48 else 49 { 50 return al_feof(m_file); 51 } 52 } 53 54 bool File::readLine( std::string& buff ) 55 { 56 buff = ""; 57 if(eof() || !isOpen()) 58 { 59 return false; 60 } 61 62 63 int c = 0; 64 while((c = al_fgetc(m_file)) != EOF && c != '\n') 65 { 66 buff += static_cast<char>(c); 67 } 68 69 return !eof(); 70 } 71}

It seems to almost work, but not quite, a few of my files and a few of my resources are not having lines read correctly from them. Is there something I'm not considering?

For example, I have code that reads backgrounds:

#SelectExpand
1 bool BackgroundManager::_loadBackgrounds( 2 const std::string& path, const std::string& bgFile ) 3 { 4 std::string fullPath = path + bgFile; 5 6 _cleanBackground(); 7 _cleanBackgrounds(); 8 m_backgrounds.clear(); 9 10 //open the file 11 File ifs( fullPath ); 12 13 //ensure it is open 14 if(!ifs.isOpen()) 15 { 16 return false; 17 } 18 std::string line; 19 20 //read each line 21 while( ifs.readLine(line) ) 22 { 23 24 if(line.length() == 0) 25 { 26 continue; 27 } 28 else if(line.length() >= 1 && line[0] == '#') 29 { 30 continue; 31 } 32 33 if(line.length() >= 1 && line[0] != '@') 34 { 35 continue; 36 } 37 38 //name, background, offsetX, offsetY, scale, thumbnail 39 std::string attrib[6]; 40 Sprite* bgThumbImg = NULL; 41 42 for(int i = 0; i < 6; ++i) 43 { 44 if(!ifs.readLine(line)) 45 return false; 46 47 int pos = -1; 48 for(size_t j = 0; j < line.length(); ++j) 49 { 50 if(line[j] == ':') 51 { 52 pos = j; 53 break; 54 } 55 } 56 57 //need 6 valid attributes 58 if(pos == -1) 59 { 60 return false; 61 } 62 63 //move to first character 64 pos+= 2; 65 if(pos < (int)line.length()) 66 { 67 attrib[i] = line.substr(pos); 68 } 69 } 70 71 if(attrib[5] != "") 72 { 73 bgThumbImg = new Sprite(attrib[5]); 74 } 75 76 float values[3] = { 0.0f,0.0f,0.0f }; 77 78 int j = 0; 79 for(int i = 2; i < 5; ++i, ++j) 80 { 81 std::stringstream ss; 82 ss << attrib[i]; 83 ss >> values[j]; 84 } 85 86 m_backgrounds.push_back(BackgroundData(bgThumbImg,path + attrib[1],values[0], 87 values[1],values[2],attrib[0])); 88 } 89 90 return true; 91 }

Sample Background file:

@default background
Name: Blue Marble Floor
Background: default.bg.png
OffsetX: 0.225
OffsetY: 0.225
Scale: 1.0
Thumbnail:

Although it seems like it loads all 6 parameters for the background, but the code never reaches the new Sprite call. Certain files load fully and some fail to read certain lines. I'm puzzled.

Thanks

Arthur Kalliokoski
Second in Command
February 2005
avatar

Sledgehammers to swat mosquitoes...

http://www.allegro.cc/manual/5/al_fgets

They all watch too much MSNBC... they get ideas.

jmasterx
Member #11,410
October 2009

I was aware of that but was hoping to have an arbitrarily long line, not something like char tmpBuff[4096].

Arthur Kalliokoski
Second in Command
February 2005
avatar

So if strlen() says your buffer is full, realloc() it to be larger and try again. Oh, wait, C++ can't do that, sorry.

They all watch too much MSNBC... they get ideas.

jmasterx
Member #11,410
October 2009

Changed return !eof(); to return true and that fixed it. And I didn't even need realloc :o . Thanks :)

Luiji99
Member #12,254
September 2010

So if strlen() says your buffer is full, realloc() it to be larger and try again. Oh, wait, C++ can't do that, sorry.

C++ can call both strlen and realloc in exactly the same way as C, but that method wouldn't work anyway.

Also, constantly appending individual characters to a C++ string will result in a number of realloc calls internally, so deciding on a maximum buffer size, running al_gets and then creating a string from that. Its less flexible, but its faster.

Programming should be fun. That's why I hate Java.

jmasterx
Member #11,410
October 2009

The way I get around that is by calling str.reserve(512) or something. This way it only reallocs if I have something really big. For me this way offers more flexibility than a fixed size.

Luiji99
Member #12,254
September 2010

True. It still has the overhead of constant function calls, but that would provide a nice balance between flexibility and speed.

Programming should be fun. That's why I hate Java.

Go to: