Script file parsing using getline()
IonBlade

[EDIT]

- Problem solved!

[/EDIT]

I'm loading default fonts into my game using a script file called fonts.res (really just a text file). At startup, the program parses this file and creates all the fonts it finds in there. Here is how my fonts.res file looks:

1; This is a script file used for loading fonts.
2; All lines beginning with semi-colons are comments.
3; Syntax:
4;
5; FontName (as referred to in code)
6; FontDataPath (path to any font data format supported by alfont)
7; Size (size that the renderer prints this font)
8 
9; Default 14 pt arial font
10arial_14
11data/resources/arial.ttf
1214
13 
14; Larger arial
15arial_18
16data/resources/arial.ttf
1718

And here is the current code that parses this file:

1gameresult CGameRenderer::LoadResFiles()
2{
3 //load font resources
4 std::ifstream file( FONT_RESOURCE_FILE );
5 
6 if ( !file.is_open() )
7 {
8 conwarning( "Font resource file '%s' not loaded!", FONT_RESOURCE_FILE );
9 return GAME_FILENOTFOUND;
10 }
11 
12 bool foundName = false;
13 bool foundPath = false;
14 bool foundSize = false;
15 std::string bufstr, curPath, curSize;
16 
17 Font_t tempFont;
18 tempFont.name = "";
19 tempFont.size = 12;
20 
21 int num_loaded = 0;
22 int dbglines = 0;
23 
24 while ( !file.eof() )
25 {
26 std::getline( file, bufstr );
27 dbglines++;
28 
29 /* TODO: Make a correct COMMENT_STRINGS macro somewhere containing
30 standard C comment syntax (ie. // and /* etc). Really what I need
31 to do is make a unified script parser with key/value pairs that all
32 systems use, but this is good enough right here for the time being. */
33
34 if ( bufstr.length() && (bufstr[0] != ';') )
35 {
36 // find a name
37 if ( !foundName )
38 {
39 conmsg("Found name: %s", (char*)bufstr.c_str());
40 tempFont.name = bufstr;
41 foundName = true;
42 }
43 else if ( !foundPath )
44 {
45 conmsg("Found path: %s", (char*)bufstr.c_str());
46 curPath = bufstr;
47 foundPath = true;
48 }
49 else if ( !foundSize )
50 {
51 conmsg("Found size: %s", (char*)bufstr.c_str());
52 tempFont.size = atoi( bufstr.c_str() );
53 foundSize = true;
54 }
55 else
56 {
57 //got one, load font and reset everything
58 conmsg("Loading font!");
59 if ( LoadFont( (char*)curPath.c_str(), (char*)tempFont.name.c_str(), tempFont.size ) )
60 num_loaded++;
61 
62 foundName = false;
63 foundPath = false;
64 foundSize = false;
65 curPath = "";
66 curSize = "";
67 tempFont.name = "";
68 tempFont.size = 12;
69 }
70 }
71 }
72 
73 file.close();
74 
75 conmsg( "Loaded %i font%s from script file", num_loaded, num_fonts == 1 ? "" : "s" );
76 conmsg( "%i lines read", dbglines );
77 
78 return num_loaded;
79}

This works nicely for the first font, but the second (or anything past it) is botched because it seems to be skipping a line and giving wrong values.

The output in my game's console looks like:

Found name: arial_14
Found path: data/resources/arial.ttf
Found size: 14
Loading font!
Found name: data/resources/arial.ttf
Found path: 18
Loaded 1 font from script file

As you can see, for the second entry, it is reading path into name, size into path, and then reaching eof.

My brain is a little tired right now and I can't figure out how to prevent getline from going past the first line I'm trying to read :P

nonnus29

Are you REALLY sure that's the source that's generating that output? I think we're missing a few things there.... like the actual parsing.

;)

IonBlade

Maybe "parsing" isn't the right word then :P

All it's doing is going line by line, excluding whitespace/return/semicolon and reading in Name, Path, and Size in that order. When all 3 have been found, it uses the LoadFont( path, name, size ) function, resets itself to looking for a name, and goes again until eof.

The "output" i'm showing you is just some debug printing for me to see what exactly it is filling Name, Path, and Size with.

[EDIT]

I solved it :)

I had to change

std::getline( file, bufstr );

To

if ( !( foundName && foundPath && foundSize) )
     std::getline( file, bufstr );

To prevent an extra line from being read if all values had been found already. This ended up only partially fixing it, where all values would be found, but the last font would never reach its loading function because EOF had been reached and the loop wouldn't run again - so I added another check past EOF to make sure the last entry is loaded if all values were found.

Thread #593751. Printed from Allegro.cc