⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 appconf.cpp

📁 这是一款2d游戏引擎
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    if ( m_szCurrentPath == NULL || len > strlen(m_szCurrentPath) ) {
      // old buffer too small, alloc new one
      if ( m_szCurrentPath != NULL )
        delete [] m_szCurrentPath;
      m_szCurrentPath = new char[len + 1];
    }

    // copy and delete pointer returned by normalizePath
    strcpy(m_szCurrentPath, szNormPath);

    delete [] szNormPath;
  }
}

void BaseConfig::setCurrentPath(const char *szPath)
{
  changeCurrentPath();		      // goto root
  changeCurrentPath(szPath);	  // now use relative change
}

const char *BaseConfig::getCurrentPath() const
{
  return m_szCurrentPath == NULL ? "" : m_szCurrentPath;
}

// ----------------------------------------------------------------------------
// filters (NB: filterOut(filterIn()) shouldn't change the string)
// ----------------------------------------------------------------------------

// called before writing
char *BaseConfig::filterOut(const char *szValue)
{
  // quote entire string if it starts with space or with quote
  Bool bDoQuote = isspace(*szValue) || (*szValue == '"');

  // calculate the length of resulting string
  size_t len = Strlen(szValue);

  const char *pcIn = szValue;
  while ( *pcIn ) {
    switch ( *pcIn++ ) {
      case '"':
        if ( !bDoQuote )
          break;
        //else: fall through

      case '\n':
      case '\t':
      case '\\':
        // one for extra '\'
        len++;
        break;
    }
  }

  if ( bDoQuote )
    len += 2;

  char *szBuf = new char[len + 1];
  char *pcOut = szBuf;

  if ( bDoQuote )
    *pcOut++ = '"';

  char c;
  for ( pcIn = szValue; *pcIn != '\0'; pcIn++ ) {
    switch ( *pcIn ) {
      case '\n':
        c = 'n';
        break;

      case '\t':
        c = 't';
        break;

      case '\\':
        c = '\\';
        break;

      case '"':
        if ( bDoQuote )
          c = '"';
        //else: fall through

      default:
        *pcOut++ = *pcIn;
        continue;   // skip special character procession
    }

    // we get here only for special characters
    *pcOut++ = '\\';
    *pcOut++ = c;
  }

  if ( bDoQuote )
    *pcOut++ = '"';

  *pcOut = '\0';

  return szBuf;
}

// called after reading
char *BaseConfig::filterIn(const char *szValue)
{
  // it will be a bit smaller, but who cares
  char *szBuf = new char[Strlen(szValue) + 1];

  const char *pcIn  = szValue;
  char *pcOut = szBuf;

  Bool bQuoted = *pcIn == '"';
  if ( bQuoted )
    pcIn++;

  while ( *pcIn != '\0' ) {
    switch ( *pcIn ) {
      case '\\':
        switch ( *++pcIn ) {
          case 'n':
            *pcOut++ = '\n';
            break;

          case 't':
            *pcOut++ = '\t';
            break;

          case '\\':
            *pcOut++ = '\\';
            break;

          case '"':
          default:
            // ignore '\'
            *pcOut++ = *pcIn;
        }
        break;

      case '"':
        if ( bQuoted ) {
          if ( *(pcIn + 1) != '\0' ) {
            LogWarning(_("invalid string '%s' in configuration file."), szValue);
          }
          break;
        }
        //else: fall through

      default:
        *pcOut++ = *pcIn;
    }

    pcIn++;
  }

  *pcOut = '\0';

  return szBuf;
}

// ----------------------------------------------------------------------------
// implementation of Enumerator subclass
// ----------------------------------------------------------------------------
BaseConfig::Enumerator::Enumerator(size_t nCount, Bool bOwnsStrings)
{
  m_bOwnsStrings = bOwnsStrings;
  m_aszData      = new char *[nCount];
  m_nCount       = 0;
}

// free memory
BaseConfig::Enumerator::~Enumerator()
{
  if ( m_bOwnsStrings ) {
    for ( size_t n = 0; n < m_nCount; n++ )
      delete [] m_aszData[n];
  }

  delete [] m_aszData;
}

void BaseConfig::Enumerator::AddString(char *sz)
{
  m_aszData[m_nCount++] = sz;
}

void BaseConfig::Enumerator::AddString(const char *sz)
{
  assert( !m_bOwnsStrings );

  // we won't delete it (see assert above), so we can cast in "char *"
  m_aszData[m_nCount++] = (char *)sz;
}

// remove duplicate strings
void BaseConfig::Enumerator::MakeUnique()
{
  char  **aszUnique = new char *[m_nCount];
  size_t  nUnique = 0;
  
  Bool bUnique;
  for ( size_t n = 0; n < m_nCount; n++ ) {
    bUnique = TRUE;
    for ( size_t n2 = n + 1; n2 < m_nCount; n2++ ) {
      if ( StrCmp(m_aszData[n], m_aszData[n2]) == 0 ) {
        bUnique = FALSE;
        break;
      }
    }

    if ( bUnique )
      aszUnique[nUnique++] = m_aszData[n];
    else if ( m_bOwnsStrings )
      delete [] m_aszData[n];
  }

  delete [] m_aszData;
  m_aszData = aszUnique;
  m_nCount = nUnique;
}

// ============================================================================
// implementation of FileConfig class
// ============================================================================

// ----------------------------------------------------------------------------
// FileConfig::ConfigEntry class
// ----------------------------------------------------------------------------

// ctor
FileConfig::ConfigEntry::ConfigEntry(ConfigGroup *pParent, 
                                     ConfigEntry *pNext, 
                                     const char *szName)
{
  m_pParent     = pParent;
  m_pNext       = pNext;
  m_szExpValue  =
  m_szValue     = 
  m_szComment   = NULL;
  m_bDirty      = 
  m_bLocal      = FALSE;

  // check for special prefix
  if ( *szName == APPCONF_IMMUTABLE_PREFIX ) {
    m_bImmutable = TRUE;
    szName++;             // skip prefix
  }
  else
    m_bImmutable = FALSE;

  m_szName  = new char[Strlen(szName) + 1]; 
  strcpy(m_szName, szName);
}

// dtor
FileConfig::ConfigEntry::~ConfigEntry()
{
  if ( m_szName != NULL )
    delete [] m_szName;

  if ( m_szValue != NULL )
    delete [] m_szValue;
    
  if ( m_szComment != NULL )
    delete [] m_szComment;

  if ( m_szExpValue != NULL )
    delete [] m_szExpValue;
}

// set value and dirty flag
void FileConfig::ConfigEntry::SetValue(const char *szValue, 
                                       Bool bLocal, Bool bFromFile)
{
   if ( m_szExpValue != NULL ) {
      delete [] m_szExpValue;
      m_szExpValue = NULL;
   }

   if ( m_szValue != NULL ) {
    // immutable changes can't be overriden (only check it here, because
    // they still can be set the first time)
    if ( m_bImmutable ) {
      LogWarning(_("attempt to change an immutable entry '%s' ignored."),
                 m_szName);
      return;
    }

    delete [] m_szValue;
  }

  // immutable entries are never changed and if an entry was just read
  // from file it shouldn't be dirty neither
  if ( !m_bImmutable && !bFromFile )
    SetDirty();

  m_bLocal = bLocal;
  if ( bLocal ) {
    // to ensure that local entries are saved we make them always dirty
    SetDirty();
  }

  if ( szValue != NULL )
  {
     m_szValue = new char[Strlen(szValue) + 1];
     strcpy(m_szValue, szValue);
  }
  else
  {
     m_szValue = NULL;
     SetDirty(FALSE);
  }
}

// set comment associated with this entry
void FileConfig::ConfigEntry::SetComment(char *szComment)
{
  assert( m_szComment == NULL );  // should be done only once
  
  // ... because we don't copy, just take the pointer
  m_szComment = szComment;
}

// set dirty flag
void FileConfig::ConfigEntry::SetDirty(Bool bDirty)
{
  // ## kludge: local entries are always dirty, otherwise they would be lost
  m_bDirty = m_bLocal ? TRUE : bDirty;
  if ( m_bDirty )
    m_pParent->SetDirty();
}

const char *FileConfig::ConfigEntry::ExpandedValue()
{
  if ( m_szExpValue == NULL ) {
    // we have only to do expansion once
    m_szExpValue = ExpandEnvVars(m_szValue);
  }

  return m_szExpValue;
}

// ----------------------------------------------------------------------------
// FileConfig::ConfigGroup class
// ----------------------------------------------------------------------------

// ctor & dtor
// -----------

FileConfig::ConfigGroup::ConfigGroup(ConfigGroup *pParent, 
                                     ConfigGroup *pNext, 
                                     const char *szName)
{ 
  m_pParent     = pParent; 
  m_pNext       = pNext; 
  m_pEntries    =
  m_pLastEntry  = NULL;
  m_pSubgroups  =
  m_pLastGroup  = NULL;
  m_bDirty      = FALSE;    // no entries yet

  m_szComment   = NULL;
  m_szName      = new char[Strlen(szName) + 1]; 
  strcpy(m_szName, szName); }

FileConfig::ConfigGroup::~ConfigGroup()
{
  // delete all entries
  ConfigEntry *pEntry, *pNextEntry;
  for ( pEntry = m_pEntries; pEntry != NULL; pEntry = pNextEntry ) {
    pNextEntry = pEntry->Next();
    delete pEntry;
  }

  // delete all subgroups
  ConfigGroup *pGroup, *pNextGroup;
  for ( pGroup = m_pSubgroups; pGroup != NULL; pGroup = pNextGroup ) {
    pNextGroup = pGroup->Next();
    delete pGroup;
  }

  if ( m_szName != NULL )
    delete [] m_szName;
}

// find
// ----

FileConfig::ConfigGroup *
            FileConfig::ConfigGroup::FindSubgroup(const char *szName) const
{
  ConfigGroup *pGroup;
  for ( pGroup = m_pSubgroups; pGroup != NULL; pGroup = pGroup->Next() ) {
    if ( !StrCmp(pGroup->Name(), szName) )
      return pGroup;
  }

  return NULL;
}

FileConfig::ConfigEntry *
            FileConfig::ConfigGroup::FindEntry(const char *szName) const
{
  ConfigEntry *pEntry;
  for ( pEntry = m_pEntries; pEntry != NULL; pEntry = pEntry->Next() ) {
    if ( !StrCmp(pEntry->Name(), szName) )
      return pEntry;
  }

  return NULL;
}

// add
// ---

// add an item at the bottom of the stack (i.e. it's a LILO really)
FileConfig::ConfigGroup *FileConfig::ConfigGroup::AddSubgroup(const char *szName)
{
  ConfigGroup *pGroup = new ConfigGroup(this, NULL, szName);

  if ( m_pSubgroups == NULL ) {
    m_pSubgroups = 
    m_pLastGroup = pGroup;
  }
  else {
    m_pLastGroup = m_pLastGroup->m_pNext = pGroup;
  }

  return pGroup;
}

// add an item at the bottom
FileConfig::ConfigEntry *FileConfig::ConfigGroup::AddEntry(const char *szName)
{
  ConfigEntry *pEntry = new ConfigEntry(this, NULL, szName);
  
  if ( m_pEntries == NULL ) {
    m_pEntries   = 
    m_pLastEntry = pEntry;
  }
  else {
    m_pLastEntry->SetNext(pEntry);
    m_pLastEntry = pEntry;
  }

  return pEntry;
}

// delete
// ------

Bool FileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
{
  ConfigGroup *pGroup, *pPrevGroup = NULL;
  for ( pGroup = Subgroup(); pGroup != NULL; pGroup = pGroup->Next() ) {
    if ( StrCmp(pGroup->Name(), szName) == 0 ) {
      break;
    }

    pPrevGroup = pGroup;
  }

  if ( pGroup == NULL )
    return FALSE;

  // remove the next element in the linked list
  if ( pPrevGroup == NULL ) {
    m_pSubgroups = pGroup->Next();
  }
  else {
    pPrevGroup->m_pNext = pGroup->Next();
  }

  // adjust pointer to the last element
  if ( pGroup->Next() == NULL ) {
    m_pLastGroup = pPrevGroup == NULL ? m_pSubgroups : pPrevGroup;
  }
  
  // shouldn't have any entries/subgroups or they would be never deleted
  // resulting in memory leaks (or we then should delete them here)
  assert( pGroup->Entries() == NULL && pGroup->Subgroup() == NULL );
  delete pGroup;

  return TRUE;
}

Bool FileConfig::ConfigGroup::DeleteEntry(const char *szName)
{
  ConfigEntry *pEntry, *pPrevEntry = NULL;
  for ( pEntry = Entries(); pEntry != NULL; pEntry = pEntry->Next() ) {
    if ( StrCmp(pEntry->Name(), szName) == 0 ) {
      break;
    }

    pPrevEntry = pEntry;
  }

  if ( pEntry == NULL )
    return FALSE;

  // remove the element from the linked list
  if ( pPrevEntry == NULL ) {
    m_pEntries = pEntry->Next();
  }
  else {
    pPrevEntry->SetNext(pEntry->Next());
  }

  // adjust the pointer to the last element
  if ( pEntry->Next() == NULL ) {
    m_pLastEntry = pPrevEntry == NULL ? m_pEntries : pPrevEntry;
  }

  // ... and free memory
  delete pEntry;

  m_pParent->SetDirty();

  return TRUE;
}

// deletes this group if it has no more entries/subgroups
Bool FileConfig::DeleteIfEmpty()
{
  // check if there any other subgroups/entries left
  if ( m_pCurGroup->Entries() != NULL || m_pCurGroup->Subgroup() != NULL )
    return FALSE;

  if ( m_pCurGroup->Parent() == NULL ) {
    // top group, can't delete it but mark it as not dirty,
    // so that local config file will not even be created
    m_pCurGroup->SetDirty(FALSE);
  }
  else {
    // delete current group
    const char *szName = m_pCurGroup->Name();
    m_pCurGroup = m_pCurGroup->Parent();
    m_pCurGroup->DeleteSubgroup(szName);
  }

  // recursively call ourselves
  DeleteIfEmpty();

  return TRUE;

⌨️ 快捷键说明

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