MoonKnight
MoonKnight

Reputation: 23831

`fgetpos` Not Returning the Correct Position

Update: To get around the problem below, I have done

if (ftell(m_pFile) != m_strLine.size())
    fseek(m_pFile, m_strLine.size(), SEEK_SET);
fpos_t position;
fgetpos(m_pFile, &position);

this then returns the correct position for my file. However, I would still like to understand why this is occurring?


I want to get the position in a text file. For most files I have been reading the first line, storing the position, doing some other stuff and returning to the position afterwards...

m_pFile = Utils::OpenFile(m_strBaseDir + "\\" + Source + "\\" + m_strFile, "r");
m_strLine = Utils::ReadLine(m_pFile);
bEOF = feof(m_pFile) != 0;
if (bEOF)
{
    Utils::CompilerError(m_ErrorCallback, 
        (boost::format("File '%1%' is empty.") % m_strFile).str());
    return false;
}

// Open.
pFileCode = Utils::OpenFile(strGenCode + "\\" + m_strFile, options.c_str());
m_strLine = Utils::Trim(m_strLine);
Utils::WriteLine(pFileCode, m_strLine);

// Store location and start passes.
unsigned int nLineCount = 1;
fpos_t position;
fgetpos(m_pFile, &position);
m_strLine = Utils::ReadLine(m_pFile);
...
fsetpos(m_pFile, &position);
m_strLine = Utils::ReadLine(m_pFile);

With all files provided to me the storage of the fgetpos and fsetpos works correctly. The problem is with a file that I have created which looks like

EG

which is almost identical to the supplied files. The problem is that for the file above fgetpos(m_pFile, &position); is not returning the correct position (I am aware that the fpos_t position is implementation specific). After the first ReadLine I get a position of 58 (edited from 60) so that when I attempt to read the second line with

fsetpos(m_pFile, &position);
m_strLine = Utils::ReadLine(m_pFile);

I get

on 700

instead of

Selection: Function ADJEXCL

Why is fgetpos not returning the position of the end of the first line?


_Note. The Utils.ReadLine method is:

std::string Utils::ReadLine(FILE* file)
{
   if (file == NULL)
      return NULL;
   char buffer[MAX_READLINE];
   if (fgets(buffer, MAX_READLINE, file) != NULL)
   {
      if (buffer != NULL)
      {
         std::string str(buffer);
         Utils::TrimNewLineChar(str);
         return str;
      }
   }
   std::string str(buffer);
   str.clear();
   return str;
}

with

void Utils::TrimNewLineChar(std::string& s)
{
   if (!s.empty() && s[s.length() - 1] == '\n') 
      s.erase(s.length() - 1);
}

Edit. Following the debugging suggestions in the comments I have added the following code

m_pFile = Utils::OpenFile(m_strBaseDir + "\\" + Source + "\\" + m_strFile, "r");
m_strLine = Utils::ReadLine(m_pFile); 
// Here m-strLine = "          Logic Definition Report Chart Version: New Version 700" (64 chars).
long vv = ftell(m_pFile); // Here vv = 58!?

fpos_t pos;
vv = ftell(m_pFile);
fgetpos(m_pFile, &pos); // pos = 58.
fsetpos(m_pFile, &pos);
m_strLine = Utils::ReadLine(m_pFile);

Upvotes: 0

Views: 573

Answers (1)

Ben Voigt
Ben Voigt

Reputation: 283813

Sorry, but your Utils functions have clearly been written by an incompetent. Some issues are just a matter of style. For trimming:

void Utils::TrimNewLineChar(std::string& s)
{
   if (!s.empty() && *s.rbegin() == '\n') 
      s.resize(s.size() - 1); // resize, not erase
}

or in C++11

void Utils::TrimNewLineChar(std::string& s)
{
   if (!s.empty() && s.back() == '\n') 
      s.pop_back();
}

ReadLine is even worse, replace it with:

std::string Utils::ReadLine(FILE* file)
{
   std::string str;
   char buffer[MAX_READLINE];
   if (file != NULL && fgets(buffer, MAX_READLINE, file) != NULL)
   {
      // it is guaranteed that buffer != NULL, since it is an automatic array
      str.assign(buffer);
      Utils::TrimNewLineChar(str);
   }
   // copying buffer into str is useless here
   return str;
}

That last str(buffer) in the original worries me especially. If fgets reaches a newline, fills the buffer, or reaches end of file, you're guaranteed to get a properly terminated string in your buffer. If some other I/O error occurs? Who knows? It might be undefined behavior.

Best not to rely on the value of buffer when fgets fails.

Upvotes: 1

Related Questions