Josh Renwald
Josh Renwald

Reputation: 1479

Newline character in Text Document?

I wrote a pretty simple function that reads in possible player names and stores them in a map for later use. Basically in the file, each line is a new possible player name, but for some reason it seems like all but the last name has some invisible new line character after it. My print out is showing it like this...

nameLine = Georgio

Name: Georgio
 0
nameLine = TestPlayer

Name: TestPlayer 0

Here is the actual code. I assume I need to be stripping something out but I am not sure what I need to be checking for.

bool PlayerManager::ParsePlayerNames()
{
    FileHandle_t file;
    file = filesystem->Open("names.txt", "r", "MOD");

    if(file)
    {
        int size = filesystem->Size(file);
        char *line = new char[size + 1];

        while(!filesystem->EndOfFile(file))
        {
            char *nameLine = filesystem->ReadLine(line, size, file);

            if(strcmp(nameLine, "") != 0)
            {
                Msg("nameLine = %s\n", nameLine);
                g_PlayerNames.insert(std::pair<char*, int>(nameLine, 0));
            }

            for(std::map<char*,int>::iterator it = g_PlayerNames.begin(); it != g_PlayerNames.end(); ++it)
            {
                Msg("Name: %s %d\n", it->first, it->second);
            }
        }

        return true;
    }

    Msg("[PlayerManager] Failed to find the Player Names File (names.txt)\n");
    filesystem->Close(file);
    return false;
}

Upvotes: 0

Views: 1005

Answers (3)

Nim
Nim

Reputation: 33645

You really need to consider using iostreams and std::string. The above code is SO much more simpler if you used the C++ constructs available to you.

Problems with your code:

  1. why do you allocate a buffer for a single line which is the size of the file?
  2. You don't clean up this buffer!
  3. How does ReadLine fill the line buffer?
  4. presumably nameLine points to the begining of the line buffer, if so, given in the std::map, the key is a pointer (char*) rather than a string as you were expecting, and the pointer is the same! If different (i.e. somehow you read a line and then move the pointer along for each name, then std::map will contain an entry per player, however you'll not be able to find an entry by player name as the comparison will be a pointer comparison rather than a string comparison as you are expecting!

I suggest that you look at implementing this using iostreams, here is some example code (without any testing)

ifstream fin("names.txt");
std::string line;
while (fin.good())
{
  std::getline(fin, line); // automatically drops the  new line character!
  if (!line.empty())
  {
    g_PlayerNames.insert(std::pair<std::string, int>(line, 0));
  }
} 
// now do what you need to
}

No need to do any manual memory management, and std::map is typed with std::string!

Upvotes: 2

Tony Delroy
Tony Delroy

Reputation: 106136

ReadLine clearly includes the newline in the data it returns. Simply check for and remove it:

char *nameLine = filesystem->ReadLine(line, size, file);

// remove any newline...
if (const char* p_nl = strchr(nameLine, '\n'))
    *p_nl = '\0';

(What this does is overwrite the newline character with a new NUL terminator, which effectively truncates the ASCIIZ string at that point.

Upvotes: 1

default
default

Reputation: 11635

Most likely the ReadLinefunction also reads the newline character. I suppose your file does not have a newline at the very last line, thus you do not get a newline for that name.

But until I know what filesystem, FileHandle_t, and Msg is, it is very hard to determine where the issue could be.

Upvotes: 0

Related Questions