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

📄 appconf.cpp

📁 这是一款2d游戏引擎
💻 CPP
📖 第 1 页 / 共 4 页
字号:
#include "Core/precomp.h"

/*****************************************************************************\
 * Project:   CppLib: C++ library for Windows/UNIX platfroms                 *
 * File:      config.cpp - implementation of Config class                    *
 *---------------------------------------------------------------------------*
 * Language:  C++                                                            *
 * Platfrom:  any (tested under Windows NT)                                  *
 *---------------------------------------------------------------------------*
 * (c) Karsten Ball黡er & Vadim Zeitlin                                      *
 *     Ballueder@usa.net  Vadim.zeitlin@dptmaths.ens-cachan.fr               *
 *---------------------------------------------------------------------------*
 * Classes:                                                                  *
 *  Config  - manages configuration files or registry database               *
 *---------------------------------------------------------------------------*
 * History:                                                                  *
 *  25.10.97  adapted from wxConfig by Karsten Ball黡er                      *
 *  09.11.97  corrected bug in RegistryConfig::enumSubgroups                 *
 *     --- for further changes see appconf.h or the CVS log ---              *    
\*****************************************************************************/

/**********************************************************************\
 *                                                                    *
 * This library is free software; you can redistribute it and/or      *
 * modify it under the terms of the GNU Library General Public        *
 * License as published by the Free Software Foundation; either       *
 * version 2 of the License, or (at your option) any later version.   *
 *                                                                    *
 * This library is distributed in the hope that it will be useful,    *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  *
 * Library General Public License for more details.                   *
 *                                                                    *
 * You should have received a copy of the GNU Library General Public  *
 * License along with this library; if not, write to the Free         *
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
 *                                                                    *
\**********************************************************************/

//static const char
//*cvs_id = "$Id: appconf.cpp,v 1.8 2003/09/05 20:33:06 mbn Exp $";

// MacOSX mostly behaves like unix
#ifdef __APPLE__
#  define __unix__
#endif

// ============================================================================
// headers, constants, private declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

// standard headers
#ifdef    __WIN32__
#	ifdef  _MSC_VER
    // nonstandard extension used : nameless struct/union
#		pragma warning(disable: 4201)  
#	endif  // VC++

#	include  <windows.h>
#endif    // WIN32

#ifdef	  __unix__
#	include <sys/param.h>
#	include	<sys/stat.h>
#	include <unistd.h>
#	define MAX_PATH	MAXPATHLEN
#endif

#include  <fcntl.h>
#include  <sys/types.h>
#include  <iostream>
#include  <fstream>
#include  <cstring>
#include  <cctype>
#include  <cstdio>
#include  <cstdlib>
#include  <cstdarg>
#include  <cassert>

// our headers
#include  "appconf.h"

// ----------------------------------------------------------------------------
// some debug/error reporting functions
// ----------------------------------------------------------------------------

#if	APPCONF_USE_GETTEXT
#	include	<libintl.h>
#	define	_(x)	dgettext(APPCONF_DOMAIN,x)
#else
#	define	_(x)	(x)
#endif

//using namespace std;

#ifndef   __WXWIN__

// in general, these messages could be treated all differently
// define a standard log function, to be called like printf()
#ifndef LogInfo
#	define   LogInfo     LogError
#endif

// define a standard error log function, to be called like printf()
#ifndef LogWarning
#	define   LogWarning  LogError
#endif

// logs an error message (with a name like that it's really strange)
// message length is limited to 1Kb
void LogError(const char *pszFormat, ...)
{
  char szBuf[1025];

  va_list argptr;
  va_start(argptr, pszFormat);
  vsnprintf(szBuf, 1023, pszFormat, argptr);
  szBuf[1023] = 0;
  va_end(argptr);

  strncat(szBuf, "\n", 1);
  fputs(szBuf, stderr);
}

#endif

#ifdef  __WIN32__

const char *SysError()
{
  static char s_szBuf[1024];

  // get error message from system
  LPVOID lpMsgBuf;
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                NULL, GetLastError(), 
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPTSTR)&lpMsgBuf,
                0, NULL);

  // copy it to our buffer and free memory
  strncpy(s_szBuf, (const char *)lpMsgBuf, sizeof(s_szBuf)/sizeof(char));
  LocalFree(lpMsgBuf);

  // returned string is capitalized and ended with '\n' - no good
  s_szBuf[0] = (char)tolower(s_szBuf[0]);
  size_t len = strlen(s_szBuf);
  if ( (len > 0) && (s_szBuf[len - 1] == '\n') )
    s_szBuf[len - 1] = '\0';

  return s_szBuf;
}

#endif

// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------
inline size_t Strlen(const char *pc) { return pc == NULL ? 0 : strlen(pc); }
inline Bool   IsValid(char c) { return isalnum(c) || strchr("_/-!.*%", c); }
inline Bool   IsCSym (char c) { return isalnum(c) || ( c == '_');          }
inline size_t Min(size_t n1, size_t n2) { return n1 < n2 ? n1 : n2; }

#define   SIZE(array)       (sizeof(array)/sizeof(array[0]))

#if APPCONF_CASE_SENSITIVE
# define StrCmp(s1,s2)  strcmp((s1),(s2))
#else
# ifdef   __unix__
//strcasecmp is in string.h
#   define  StrCmp(s1,s2)  strcasecmp((s1),(s2))
# else
#   ifdef _MSC_VER
#     define  StrCmp(s1,s2)  _stricmp((s1),(s2))
#   else
#     error "Please define 'stricmp' function for your compiler."
#   endif // compilers
# endif   // strcasecmp/strcimp
#endif

// perform environment variable substitution
char *ExpandEnvVars(const char *psz)
{
  char *szNewValue = new char[strlen(psz)+1];
  strcpy(szNewValue, psz);
  return szNewValue;
  
  // produces internal comp error on rh 5.2 -- mbn
/*
  // don't change the values the enum elements: they must be equal
  // to the matching [closing] delimiter.
  enum Bracket
  { 
    Bracket_None, 
    Bracket_Normal  = ')', 
    Bracket_Curly   = '}' 
  };
          
  // max size for an environment variable name is fixed
  char szVarName[256];

  // first calculate the length of the resulting string
  size_t nNewLen = 0;
  const char *pcIn;
  for ( pcIn = psz; *pcIn != '\0'; pcIn++ ) {
    switch ( *pcIn ) {
      case '$':
        {
          Bracket bracket;
          switch ( *++pcIn ) {
            case '(': 
              bracket = Bracket_Normal; 
              pcIn++;                   // skip the bracket
              break;

            case '{':
              bracket = Bracket_Curly;
              pcIn++;                   // skip the bracket
              break;

            default:
              bracket = Bracket_None;
          }
          const char *pcStart = pcIn;

          while ( IsCSym(*pcIn) ) pcIn++;

          size_t nCopy = Min(pcIn - pcStart, SIZE(szVarName));
          strncpy(szVarName, pcStart, nCopy);
          szVarName[nCopy] = '\0';

          if ( bracket != Bracket_None ) {
            if ( *pcIn != (char)bracket ) {
              // # what to do? we decide to give warning and ignore 
              //   the opening bracket
              LogWarning(_("'%c' expected in '%s' after '${%s'"), 
                         (char)bracket, psz, szVarName);
              pcIn--;
            }
          }
          else {
            // everything is ok but we took one extra character
            pcIn--;
          }

          // Strlen() acceps NULL as well
          nNewLen += Strlen(getenv(szVarName));
        }
        break;

      case '\\':
        pcIn++;
        // fall through

      default:
        nNewLen++;
    }
  }

  // # we always realloc buffer (could reuse the old one if nNewLen < nOldLen)
  char *szNewValue = new char[nNewLen + 1];
  char *pcOut = szNewValue;

  // now copy it to the new location replacing the variables with their values
  for ( pcIn = psz; *pcIn != '\0'; pcIn++ ) {
    switch ( *pcIn ) {
      case '$':
        {
          Bracket bracket;
          switch ( *++pcIn ) {
            case '(': 
              bracket = Bracket_Normal; 
              pcIn++;                   // skip the bracket
              break;

            case '{':
              bracket = Bracket_Curly;
              pcIn++;                   // skip the bracket
              break;

            default:
              bracket = Bracket_None;
          }
          const char *pcStart = pcIn;

          while ( IsCSym(*pcIn) ) pcIn++;

          size_t nCopy = Min(pcIn - pcStart, SIZE(szVarName));
          strncpy(szVarName, pcStart, nCopy);
          szVarName[nCopy] = '\0';

          if ( bracket != Bracket_None ) {
            if ( *pcIn != (char)bracket ) {
              // warning message already given, just ignore opening bracket
              pcIn--;
            }
          }
          else {
            // everything is ok but we took one extra character
            pcIn--;
          }

          const char *pszValue = getenv(szVarName);
          if ( pszValue != NULL ) {
            strcpy(pcOut, pszValue);
            pcOut += strlen(pszValue);
          }
        }
        break;

      case '\\':
        pcIn++;
        // fall through

      default:
        *pcOut++ = *pcIn;
    }
  }

  *pcOut = '\0';

  return szNewValue;
*/
}

// ============================================================================
// implementation of the class BaseConfig
// ============================================================================

// ----------------------------------------------------------------------------
// ctor and dtor
// ----------------------------------------------------------------------------

BaseConfig::BaseConfig()
{
   m_szCurrentPath = NULL;
   m_bRecordDefaults = FALSE;
}

BaseConfig::~BaseConfig()
{
  if ( m_szCurrentPath != NULL )
    delete [] m_szCurrentPath;
}

void
BaseConfig::recordDefaults(Bool enable)
{
   m_bRecordDefaults = enable;
}

// ----------------------------------------------------------------------------
// handle long int and double values
// ----------------------------------------------------------------------------

Bool
BaseConfig::writeEntry(const char *szKey, long int Value)
{
   char buffer[APPCONF_STRBUFLEN]; // ugly
   sprintf(buffer, "%ld", Value);
   return writeEntry(szKey,buffer);
}

Bool
BaseConfig::writeEntry(const char *szKey, double Value)
{
   char buffer[APPCONF_STRBUFLEN]; // ugly
   sprintf(buffer,"%g", Value);
   return writeEntry(szKey,buffer);
}	

long int
BaseConfig::readEntry(const char *szKey, long int Default) const
{
   const char *cptr = readEntry(szKey,(const char *)NULL);
   if(cptr)
      return atol(cptr);
   else
   {
      if(m_bRecordDefaults)
	 ((BaseConfig *)this)->writeEntry(szKey,Default);
      return Default;
   }
}

double
BaseConfig::readEntry(const char *szKey, double Default) const
{
   const char *cptr = readEntry(szKey,(const char *)NULL);
   if(cptr)
      return atof(cptr);
   else
   {
      if(m_bRecordDefaults)
	 ((BaseConfig *)this)->writeEntry(szKey,Default);
      return Default;
   }
}

// ----------------------------------------------------------------------------
// set/get current path
// ----------------------------------------------------------------------------

// this function resolves all ".." (but not '/'!) in the path
// returns pointer to dynamically allocated buffer, free with "delete []"
// ## code here is inefficient and difficult to understand, to rewrite
char *BaseConfig::normalizePath(const char *szStartPath, const char *szPath)
{
  char    *szNormPath;

  // array grows in chunks of this size
#define   COMPONENTS_INITIAL    (10)

  char   **aszPathComponents;   // component is something between 2 '/'
  size_t   nComponents = 0,
           nMaxComponents;

  aszPathComponents = new char *[nMaxComponents = COMPONENTS_INITIAL];

  const char *pcStart;   // start of last component
  const char *pcIn;

  // concatenate the two adding APPCONF_PATH_SEPARATOR to the end if not there
  size_t len = Strlen(szStartPath);
  size_t nOldLen = len + Strlen(szPath) + 1;
  szNormPath = new char[nOldLen + 1];
  strcpy(szNormPath, szStartPath);
  szNormPath[len++] = APPCONF_PATH_SEPARATOR;
  szNormPath[len] = '\0';
  strcat(szNormPath, szPath);

  // break combined path in components
  Bool bEnd = FALSE;
  for ( pcStart = pcIn = szNormPath; !bEnd; pcIn++ ) {
    if ( *pcIn == APPCONF_PATH_SEPARATOR || *pcIn == '\0' ) {
      if ( *pcIn == '\0' )
        bEnd = TRUE;

      // another component - is it "." or ".."?
      if ( *pcStart == '.' ) {
        if ( pcIn == pcStart + 1 ) {
          // "./" - ignore
          pcStart = pcIn + 1;
          continue;
        }
        else if ( (pcIn == pcStart + 2) && (*(pcStart + 1) == '.') ) {
          // "../" found - delete last component
          if ( nComponents > 0 ) {
            delete [] aszPathComponents[--nComponents];
          }
          else {
            LogWarning(_("extra '..' in the path '%s'."), szPath);
          }

          pcStart = pcIn + 1;
          continue;
        }
      }
      else if ( pcIn == pcStart ) {
        pcStart = pcIn + 1;
        continue;
      }

      // normal component, add to the list

      // grow array?
      if ( nComponents == nMaxComponents ) {    
        // realloc array
        char **aszOld = aszPathComponents;
        nMaxComponents += COMPONENTS_INITIAL;
        aszPathComponents = new char *[nMaxComponents];

        // move data
        memmove(aszPathComponents, aszOld, 
                sizeof(aszPathComponents[0]) * nComponents);

        // free old
        delete [] aszOld;
      }

      // do add
      aszPathComponents[nComponents] = new char[pcIn - pcStart + 1];
      strncpy(aszPathComponents[nComponents], pcStart, pcIn - pcStart);
      aszPathComponents[nComponents][pcIn - pcStart] = '\0';
      nComponents++;

      pcStart = pcIn + 1;
    }
  }

  if ( nComponents == 0 ) {
    // special case
    szNormPath[0] = '\0';
  }
  else {
    // put all components together
    len = 0;
    for ( size_t n = 0; n < nComponents; n++ ) {
      // add '/' before each new component except the first one
      if ( len != 0 ) {
        szNormPath[len++] = APPCONF_PATH_SEPARATOR;
      }
      szNormPath[len] = '\0';

      // concatenate
      strcat(szNormPath, aszPathComponents[n]);

      // update length
      len += strlen(aszPathComponents[n]);

      // and free memory
      delete [] aszPathComponents[n];
    }
  }

  delete [] aszPathComponents;

  return szNormPath;
}

void BaseConfig::changeCurrentPath(const char *szPath)
{
  // special case (default value)
  if ( Strlen(szPath) == 0 ) {
    if ( m_szCurrentPath != NULL ) {
      delete [] m_szCurrentPath;
      m_szCurrentPath = NULL;
    }
  }    
  else {
    char *szNormPath;

    // if absolute path, start from top, otherwise from current
    if ( *szPath == APPCONF_PATH_SEPARATOR )
      szNormPath = normalizePath("", szPath + 1);
    else
      szNormPath = normalizePath(m_szCurrentPath ? m_szCurrentPath : "", szPath);

    size_t len = Strlen(szNormPath);

⌨️ 快捷键说明

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