fileconf.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,084 行 · 第 1/5 页

CPP
2,084
字号
        {
            wxLogWarning(_("can't open user configuration file '%s'."),  m_strLocalFile.c_str() );
        }
    }

    m_isDirty = false;
}

// constructor supports creation of wxFileConfig objects of any type
wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName,
                           const wxString& strLocal, const wxString& strGlobal,
                           long style, wxMBConv& conv)
            : wxConfigBase(::GetAppName(appName), vendorName,
                           strLocal, strGlobal,
                           style),
              m_strLocalFile(strLocal), m_strGlobalFile(strGlobal),
              m_conv(conv)
{
    // Make up names for files if empty
    if ( m_strLocalFile.empty() && (style & wxCONFIG_USE_LOCAL_FILE) )
        m_strLocalFile = GetLocalFileName(GetAppName());

    if ( m_strGlobalFile.empty() && (style & wxCONFIG_USE_GLOBAL_FILE) )
        m_strGlobalFile = GetGlobalFileName(GetAppName());

    // Check if styles are not supplied, but filenames are, in which case
    // add the correct styles.
    if ( !m_strLocalFile.empty() )
        SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);

    if ( !m_strGlobalFile.empty() )
        SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE);

    // if the path is not absolute, prepend the standard directory to it
    // UNLESS wxCONFIG_USE_RELATIVE_PATH style is set
    if ( !(style & wxCONFIG_USE_RELATIVE_PATH) )
    {
        if ( !m_strLocalFile.empty() && !wxIsAbsolutePath(m_strLocalFile) )
        {
            wxString strLocal = m_strLocalFile;
            m_strLocalFile = GetLocalDir();
            m_strLocalFile << strLocal;
        }

        if ( !m_strGlobalFile.empty() && !wxIsAbsolutePath(m_strGlobalFile) )
        {
            wxString strGlobal = m_strGlobalFile;
            m_strGlobalFile = GetGlobalDir();
            m_strGlobalFile << strGlobal;
        }
    }

    SetUmask(-1);

    Init();
}

#if wxUSE_STREAMS

wxFileConfig::wxFileConfig(wxInputStream &inStream, wxMBConv& conv)
            : m_conv(conv)
{
    // always local_file when this constructor is called (?)
    SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE);

    m_pCurrentGroup =
    m_pRootGroup    = new wxFileConfigGroup(NULL, wxEmptyString, this);

    m_linesHead =
    m_linesTail = NULL;

    // translate everything to the current (platform-dependent) line
    // termination character
    wxString strTrans;
    {
        wxString strTmp;

        char buf[1024];
        do
        {
            inStream.Read(buf, WXSIZEOF(buf)-1);  // leave room for the NULL

            const wxStreamError err = inStream.GetLastError();

            if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF )
            {
                wxLogError(_("Error reading config options."));
                break;
            }

            // FIXME: this is broken because if we have part of multibyte
            //        character in the buffer (and another part hasn't been
            //        read yet) we're going to lose data because of conversion
            //        errors
            buf[inStream.LastRead()] = '\0';
            strTmp += conv.cMB2WX(buf);
        }
        while ( !inStream.Eof() );

        strTrans = wxTextBuffer::Translate(strTmp);
    }

    wxMemoryText memText;

    // Now we can add the text to the memory text. To do this we extract line
    // by line from the translated string, until we've reached the end.
    //
    // VZ: all this is horribly inefficient, we should do the translation on
    //     the fly in one pass saving both memory and time (TODO)

    const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault);
    const size_t EOLLen = wxStrlen(pEOL);

    int posLineStart = strTrans.Find(pEOL);
    while ( posLineStart != -1 )
    {
        wxString line(strTrans.Left(posLineStart));

        memText.AddLine(line);

        strTrans = strTrans.Mid(posLineStart + EOLLen);

        posLineStart = strTrans.Find(pEOL);
    }

    // also add whatever we have left in the translated string.
    if ( !strTrans.empty() )
        memText.AddLine(strTrans);

    // Finally we can parse it all.
    Parse(memText, true /* local */);

    SetRootPath();
    ResetDirty();
}

#endif // wxUSE_STREAMS

void wxFileConfig::CleanUp()
{
  delete m_pRootGroup;

  wxFileConfigLineList *pCur = m_linesHead;
  while ( pCur != NULL ) {
    wxFileConfigLineList *pNext = pCur->Next();
    delete pCur;
    pCur = pNext;
  }
}

wxFileConfig::~wxFileConfig()
{
  Flush();

  CleanUp();
}

// ----------------------------------------------------------------------------
// parse a config file
// ----------------------------------------------------------------------------

void wxFileConfig::Parse(wxTextBuffer& buffer, bool bLocal)
{
  const wxChar *pStart;
  const wxChar *pEnd;
  wxString strLine;

  size_t nLineCount = buffer.GetLineCount();

  for ( size_t n = 0; n < nLineCount; n++ )
  {
    strLine = buffer[n];

    // add the line to linked list
    if ( bLocal )
    {
      LineListAppend(strLine);

      // let the root group have its start line as well
      if ( !n )
      {
        m_pCurrentGroup->SetLine(m_linesTail);
      }
    }


    // skip leading spaces
    for ( pStart = strLine; wxIsspace(*pStart); pStart++ )
      ;

    // skip blank/comment lines
    if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') )
      continue;

    if ( *pStart == wxT('[') ) {          // a new group
      pEnd = pStart;

      while ( *++pEnd != wxT(']') ) {
        if ( *pEnd == wxT('\\') ) {
            // the next char is escaped, so skip it even if it is ']'
            pEnd++;
        }

        if ( *pEnd == wxT('\n') || *pEnd == wxT('\0') ) {
            // we reached the end of line, break out of the loop
            break;
        }
      }

      if ( *pEnd != wxT(']') ) {
        wxLogError(_("file '%s': unexpected character %c at line %d."),
                   buffer.GetName(), *pEnd, n + 1);
        continue; // skip this line
      }

      // group name here is always considered as abs path
      wxString strGroup;
      pStart++;
      strGroup << wxCONFIG_PATH_SEPARATOR
               << FilterInEntryName(wxString(pStart, pEnd - pStart));

      // will create it if doesn't yet exist
      SetPath(strGroup);

      if ( bLocal )
      {
        if ( m_pCurrentGroup->Parent() )
          m_pCurrentGroup->Parent()->SetLastGroup(m_pCurrentGroup);
        m_pCurrentGroup->SetLine(m_linesTail);
      }

      // check that there is nothing except comments left on this line
      bool bCont = true;
      while ( *++pEnd != wxT('\0') && bCont ) {
        switch ( *pEnd ) {
          case wxT('#'):
          case wxT(';'):
            bCont = false;
            break;

          case wxT(' '):
          case wxT('\t'):
            // ignore whitespace ('\n' impossible here)
            break;

          default:
            wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."),
                         buffer.GetName(), n + 1, pEnd);
            bCont = false;
        }
      }
    }
    else {                        // a key
      const wxChar *pEnd = pStart;
      while ( *pEnd && *pEnd != wxT('=') /* && !wxIsspace(*pEnd)*/ ) {
        if ( *pEnd == wxT('\\') ) {
          // next character may be space or not - still take it because it's
          // quoted (unless there is nothing)
          pEnd++;
          if ( !*pEnd ) {
            // the error message will be given below anyhow
            break;
          }
        }

        pEnd++;
      }

      wxString strKey(FilterInEntryName(wxString(pStart, pEnd).Trim()));

      // skip whitespace
      while ( wxIsspace(*pEnd) )
        pEnd++;

      if ( *pEnd++ != wxT('=') ) {
        wxLogError(_("file '%s', line %d: '=' expected."),
                   buffer.GetName(), n + 1);
      }
      else {
        wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey);

        if ( pEntry == NULL ) {
          // new entry
          pEntry = m_pCurrentGroup->AddEntry(strKey, n);
        }
        else {
          if ( bLocal && pEntry->IsImmutable() ) {
            // immutable keys can't be changed by user
            wxLogWarning(_("file '%s', line %d: value for immutable key '%s' ignored."),
                         buffer.GetName(), n + 1, strKey.c_str());
            continue;
          }
          // the condition below catches the cases (a) and (b) but not (c):
          //  (a) global key found second time in global file
          //  (b) key found second (or more) time in local file
          //  (c) key from global file now found in local one
          // which is exactly what we want.
          else if ( !bLocal || pEntry->IsLocal() ) {
            wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."),
                         buffer.GetName(), n + 1, strKey.c_str(), pEntry->Line());

          }
        }

        if ( bLocal )
          pEntry->SetLine(m_linesTail);

        // skip whitespace
        while ( wxIsspace(*pEnd) )
          pEnd++;

        wxString value = pEnd;
        if ( !(GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS) )
            value = FilterInValue(value);

        pEntry->SetValue(value, false);
      }
    }
  }
}

// ----------------------------------------------------------------------------
// set/retrieve path
// ----------------------------------------------------------------------------

void wxFileConfig::SetRootPath()
{
  m_strPath.Empty();
  m_pCurrentGroup = m_pRootGroup;
}

bool
wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents)
{
  wxArrayString aParts;

  if ( strPath.empty() ) {
    SetRootPath();
    return true;
  }

  if ( strPath[0] == wxCONFIG_PATH_SEPARATOR ) {
    // absolute path
    wxSplitPath(aParts, strPath);
  }
  else {
    // relative path, combine with current one
    wxString strFullPath = m_strPath;
    strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
    wxSplitPath(aParts, strFullPath);
  }

  // change current group
  size_t n;
  m_pCurrentGroup = m_pRootGroup;
  for ( n = 0; n < aParts.Count(); n++ ) {
    wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]);
    if ( pNextGroup == NULL )
    {
      if ( !createMissingComponents )
        return false;

      pNextGroup = m_pCurrentGroup->AddSubgroup(aParts[n]);
    }

    m_pCurrentGroup = pNextGroup;
  }

  // recombine path parts in one variable
  m_strPath.Empty();
  for ( n = 0; n < aParts.Count(); n++ ) {
    m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
  }

  return true;
}

void wxFileConfig::SetPath(const wxString& strPath)
{
  DoSetPath(strPath, true /* create missing path components */);
}

// ----------------------------------------------------------------------------
// enumeration
// ----------------------------------------------------------------------------

bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const
{
  lIndex = 0;
  return GetNextGroup(str, lIndex);
}

bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
{
  if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) {
    str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name();
    return true;
  }
  else
    return false;
}

bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const
{
  lIndex = 0;
  return GetNextEntry(str, lIndex);
}

bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
{
  if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) {
    str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name();
    return true;
  }
  else
    return false;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?