|
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: 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: 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 Agui GUI API -> https://github.com/jmasterx/Agui |
Arthur Kalliokoski
Second in Command
February 2005
|
Sledgehammers to swat mosquitoes... 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]. Agui GUI API -> https://github.com/jmasterx/Agui |
Arthur Kalliokoski
Second in Command
February 2005
|
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 . Thanks Agui GUI API -> https://github.com/jmasterx/Agui |
Luiji99
Member #12,254
September 2010
|
Arthur Kalliokoski said: 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. Agui GUI API -> https://github.com/jmasterx/Agui |
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. |
|