diff host/tools/Utils/common/Properties.cpp @ 76:435cced73e2f ecos-v1_3_1-release

eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
author jlarmour
date Tue, 28 Mar 2000 14:10:45 +0000
parents
children 6736c52df507
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/host/tools/Utils/common/Properties.cpp
@@ -0,0 +1,744 @@
+//####COPYRIGHTBEGIN####
+//                                                                          
+// ----------------------------------------------------------------------------
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
+//
+// This program is part of the eCos host tools.
+//
+// This program is free software; you can redistribute it and/or modify it 
+// under the terms of the GNU General Public License as published by the Free 
+// Software Foundation; either version 2 of the License, or (at your option) 
+// any later version.
+// 
+// This program 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 General Public License for 
+// more details.
+// 
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+//
+// ----------------------------------------------------------------------------
+//                                                                          
+//####COPYRIGHTEND####
+// Properties.cpp: implementation of the CProperties class.
+//
+//////////////////////////////////////////////////////////////////////
+#include "Properties.h"
+#if defined (_AFXDLL) || defined(_AFXEXT)
+    // MFC
+    //#ifdef _DEBUG
+    //#undef THIS_FILE
+    //static char THIS_FILE[]=__FILE__;
+    //#define new DEBUG_NEW
+    //#endif
+    #include <assert.h>
+    #include <sys/types.h> 
+    #include <sys/stat.h>
+    #include <direct.h>
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CProperties::CProperties(LPCTSTR pszKey,void *hKey):
+  m_strName(pszKey),
+  m_hKey(hKey)
+{
+}
+
+CProperties::~CProperties()
+{
+    RemoveAll();
+}
+
+void CProperties::RemoveAll()
+{
+    for(int i=ar.size()-1;i>=0;--i){
+        delete (CProperties::CProperty *)ar[i];
+    }
+    ar.clear();
+}
+
+#ifdef _WIN32
+bool CProperties::LoadFromRegistry(HKEY hTopKey,LPCTSTR szRegKey,LPCTSTR pszPrefix)
+{
+  int nPrefixlen=_tcslen(pszPrefix);
+  HKEY hKey;
+  LONG l=RegOpenKeyEx (hTopKey, szRegKey, 0L, KEY_QUERY_VALUE, &hKey);
+  bool rc=(ERROR_SUCCESS==l);
+  if(rc){
+    TCHAR szName[256];
+    DWORD dwSizeName=sizeof szName;
+    DWORD dwMaxDatalen;
+    DWORD dwType;
+    if(ERROR_SUCCESS==RegQueryInfoKey(hKey,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&dwMaxDatalen,NULL,NULL)){
+      char *Data=new char[dwMaxDatalen];
+      DWORD dwDatalen=dwMaxDatalen;
+      for(DWORD dwIndex=0;ERROR_SUCCESS==RegEnumValue(hKey, dwIndex, szName, &dwSizeName, NULL, &dwType, (LPBYTE)Data, &dwDatalen);dwIndex++){ 
+        if(0!=_tcsncmp(pszPrefix,szName,nPrefixlen)){
+          continue;
+        }
+        
+        CProperties::CProperty *p=Lookup(szName+nPrefixlen);
+        if(p){
+          switch(p->Type){
+          case CProperty::Integer:
+            if(REG_DWORD==dwType){
+              p->SetValue(*(int *)Data);
+            } else {
+              //TRACE(_T("Type mismatch - %s: expected REG_DWORD, got %d\n"),(LPCTSTR)p->strName,dwType);
+              rc=false;
+            }
+            break;
+          case CProperty::Bool:
+            if(REG_DWORD==dwType){
+              p->SetValue((bool)0!=*(int *)Data);
+            } else {
+              //TRACE(_T("Type mismatch - %s: expected REG_DWORD, got %d\n"),(LPCTSTR)p->strName,dwType);
+              rc=false;
+            }
+            break;
+          case CProperty::Char:
+            if(REG_DWORD==dwType){
+              p->SetValue(*(char *)Data);
+            } else {
+              //TRACE(_T("Type mismatch - %s: expected REG_DWORD, got %d\n"),(LPCTSTR)p->strName,dwType);
+              rc=false;
+            }
+            break;
+          case CProperty::Short:
+            if(REG_DWORD==dwType){
+              p->SetValue(*(short *)Data);
+            } else {
+              //TRACE(_T("Type mismatch - %s: expected REG_DWORD, got %d\n"),(LPCTSTR)p->strName,dwType);
+              rc=false;
+            }
+            break;
+          case CProperty::Float:
+          case CProperty::Double:
+          case CProperty::szString: 
+          case CProperty::GPString: 
+            if(REG_SZ==dwType){
+              rc&=p->SetValue((LPCTSTR)Data);
+            } else {
+              //TRACE(_T("Type mismatch - %s: expected REG_SZ, got %d\n"),(LPCTSTR)p->strName,dwType);
+              rc=false;
+            }
+            break;
+          case CProperty::Void:
+            if(REG_BINARY==dwType){
+              memcpy(p->pData,Data,min(dwDatalen,p->nLength));
+            } else {
+              //TRACE(_T("Type mismatch - %s: expected REG_BINARY, got %d\n"),(LPCTSTR)p->strName,dwType);
+              rc=false;
+            }
+            break;
+          }
+        } else {
+          //TRACE(_T("CProperties::LoadFromRegistry - unrecognized value %s\\%s\n"),szRegKey,szName);
+          rc=false;
+        }
+        dwSizeName=sizeof szName;
+        dwDatalen=dwMaxDatalen;
+      }
+      delete [] Data;
+      dwSizeName=sizeof szName;
+    }
+    RegCloseKey(hKey);
+  } else {
+    //TRACE(_T("Failed to open %s\n"),szRegKey);
+  }
+  
+  return rc;
+}
+
+bool CProperties::SaveToRegistry(HKEY hTopKey,LPCTSTR szRegKey,LPCTSTR pszPrefix) const
+{
+  HKEY hKey;
+  CreateKey(szRegKey);
+  bool rc=(ERROR_SUCCESS==RegOpenKeyEx (hTopKey, szRegKey, 0L, KEY_SET_VALUE, &hKey));
+  if(rc){
+    for(int i=ar.size()-1;i>=0;--i){
+      // Initializations are simply to avoid compiler warnings.
+      DWORD dwDatalen=0; 
+      DWORD dwType=REG_DWORD;
+      BYTE *Data=0;
+      // strValue and dw *must* be in scope for RegSetValueEx below.
+      DWORD dw;
+      String strValue;
+      CProperties::CProperty *p=(CProperties::CProperty *)ar[i];
+      switch(p->Type){
+        case CProperties::CProperty::Integer:
+        case CProperties::CProperty::Bool:
+        case CProperties::CProperty::Char:
+        case CProperties::CProperty::Short:
+          dwType=REG_DWORD;
+          dwDatalen=sizeof(DWORD);
+          dw=p->GetValue();
+          Data=(BYTE *)&dw;
+          break;
+        case CProperties::CProperty::Float:
+        case CProperties::CProperty::Double:
+        case CProperties::CProperty::szString:
+        case CProperties::CProperty::GPString:
+          strValue=p->GetStringValue();
+          Data=(BYTE *)(LPCTSTR)strValue;
+          dwType=REG_SZ;
+          dwDatalen=(1+strValue.GetLength())*sizeof(_TCHAR);
+          break;
+        case CProperties::CProperty::Void:
+          Data=(BYTE *)p->pData;
+          dwType=REG_BINARY;
+          dwDatalen=p->nLength;
+          break;
+        default:
+          assert(false);
+          break;
+      }
+      String strName(pszPrefix);
+      strName+=p->strName;
+      rc&=(ERROR_SUCCESS==RegSetValueEx(hKey,strName,0,dwType,Data,dwDatalen));
+    }
+  }   
+  RegCloseKey(hKey);
+  return rc;    
+}
+
+// Create all keys down to the one specified
+bool CProperties::CreateKey(LPCTSTR pszKey,HKEY hKey/*=HKEY_CURRENT_USER*/)
+{
+    bool rc=true;
+    LPCTSTR pcStart=pszKey;
+    LPCTSTR pcEnd;
+    do {
+        HKEY hKey2;
+        pcEnd=_tcschr(pcStart,_TCHAR('\\'));
+        if(NULL==pcEnd){
+            pcEnd=pcStart+_tcslen(pcStart);
+        }
+        String strKey(pcStart,pcEnd-pcStart);
+        if(ERROR_SUCCESS!=RegCreateKeyEx(hKey,                // handle to an open key
+              strKey,         // address of subkey name
+              0,           // reserved
+              0,           // address of class string
+              REG_OPTION_NON_VOLATILE,          // special options flag
+              KEY_ALL_ACCESS,        // desired security access
+              NULL,
+                                        // address of key security structure
+              &hKey2,          // address of buffer for opened handle
+              NULL// address of disposition value buffer);
+              )){
+            rc=false;
+            break;
+        }
+        RegCloseKey(hKey);
+        hKey=hKey2;
+        pcStart=pcEnd+1;
+    } while (_TCHAR('\0')!=*pcEnd);
+    RegCloseKey(hKey);
+    return rc;
+}
+
+#endif
+
+bool CProperties::LoadFromCommandString(LPCTSTR psz,LPCTSTR pszPrefix/*=_T("-")*/)
+{
+  bool rc=true;
+  const TCHAR *cNext;
+  int nPrefixlen=_tcslen(pszPrefix);
+  for(LPCTSTR c=_tcsstr(psz,pszPrefix);c;c=_tcsstr(cNext,pszPrefix)){
+    c+=nPrefixlen;
+    const TCHAR *pEq=_tcschr(c,_TCHAR('='));
+    if(NULL==pEq){
+      //TRACE(_T("Failed to find '=' after %s\n"),c);
+      rc=false;
+      break;
+    }
+    String strName(c,pEq-c);
+    CProperties::CProperty *p=Lookup(strName);
+    c=pEq+1;
+    String str;
+    if(_TCHAR('"')==*c){
+      // Value is a quoted string
+      for(cNext=c+1;_TCHAR('"')!=*cNext;cNext++){
+        if(_TCHAR('\\')==*cNext){
+          cNext++;
+        }
+        str+=*cNext;
+      }
+    } else {
+      // Value is simply terminated by whitespace
+      for(cNext=c;_TCHAR('\0')!=*cNext && !_istspace(*cNext);cNext++);
+      str=String(c,cNext-c);
+    }
+    if(p){
+      rc&=p->SetValue(str);
+    } else {
+      //TRACE(_T("Properties: unrecognized attribute %s in command string\n"),(LPCTSTR)strName);
+      rc=false;
+    }
+  }
+  return rc;
+}
+
+CProperties::CProperty * CProperties::Lookup(LPCTSTR pszName)
+{
+    for(int i=ar.size()-1;i>=0;--i){
+        CProperties::CProperty *p=(CProperties::CProperty *)ar[i];
+        if(p->strName==pszName){
+            return p;
+        }
+    }
+    return NULL;
+}
+
+String CProperties::MakeCommandString(LPCTSTR pszPrefix/*=_T("-")*/) const
+{
+  String strResult;
+  bool bFirst=true;
+  for(int i=ar.size()-1;i>=0;--i){
+    String str;    
+    CProperties::CProperty *p=(CProperties::CProperty *)ar[i];
+    switch(p->Type){
+    case CProperties::CProperty::Integer:
+    case CProperties::CProperty::Bool:
+    case CProperties::CProperty::Char:
+    case CProperties::CProperty::Short:
+      str.Format(_T("%s%s=%u"),pszPrefix,(LPCTSTR)p->strName,p->GetValue());
+      break;
+    case CProperties::CProperty::szString:
+    case CProperties::CProperty::GPString:
+    case CProperties::CProperty::Float:
+    case CProperties::CProperty::Double:
+    case CProperties::CProperty::Void:
+      str.Format(_T("%s%s=\"%s\""),pszPrefix,(LPCTSTR)p->strName,(LPCTSTR)p->GetStringValue());
+      break;
+    }
+    if(!bFirst){
+      strResult+=_TCHAR(' ');
+    }
+    bFirst=false;
+    strResult+=str;
+  }
+  return strResult;
+}       
+
+bool CProperties::CreatePathToFile(LPCTSTR pszDir) 
+{
+    // Create intermediate directories
+    #ifdef _WIN32
+    const TCHAR cSep='\\';
+    #else // UNIX
+    const TCHAR cSep='/';
+    #endif
+    for(LPCTSTR c=_tcschr(pszDir,cSep);c;c=_tcschr(c+1,cSep)){
+        #ifdef _WIN32
+        if(c==pszDir+2 && _istalpha(pszDir[0]) && _TCHAR(':')==pszDir[1]){
+            continue; // don't attempt to create "C:"
+        }
+        #endif
+        String strDir(pszDir,c-pszDir);
+        struct _stat buf;
+        if(!(0==_tstat(strDir,&buf) && (S_IFDIR&buf.st_mode))){
+            // Need to create directory
+            bool b=(0==_tmkdir(strDir));
+            //TRACE(_T("Create directory %s rc=%d\n"),(LPCTSTR)strDir,b);
+            if(!b){
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool CProperties::SaveToFile(LPCTSTR pszFileName,LPCTSTR pszPrefix) const
+{
+  CreatePathToFile(pszFileName);
+  // If we have a prefix, we assume we're tagging on to an existing file
+  FILE *f=_tfopen(pszFileName,(_TCHAR('\0')==*pszPrefix)?_T("wt"):_T("at"));
+  if(f){
+    for(int i=ar.size()-1;i>=0;--i){
+      CProperties::CProperty *p=(CProperties::CProperty *)ar[i];
+      String str(pszPrefix);
+      str+=p->strName;
+      str+=_TCHAR('=');
+      switch(p->Type){
+        case CProperties::CProperty::Integer:
+        case CProperties::CProperty::Bool:
+        case CProperties::CProperty::Char:
+        case CProperties::CProperty::Short:
+          {
+            String strN;
+            strN.Format(_T("%u"),p->GetValue());
+            str+=strN;
+          }
+          break;
+        case CProperties::CProperty::Float:
+        case CProperties::CProperty::Double:
+        case CProperties::CProperty::szString:
+        case CProperties::CProperty::GPString:
+        case CProperties::CProperty::Void:
+          str+=p->GetStringValue();
+          break;
+      }
+      str+=_TCHAR('\n');
+      _fputts(str,f);
+    }
+    fclose(f);
+  }
+  return (0!=f);
+}
+
+bool CProperties::LoadFromFile(LPCTSTR pszFileName,LPCTSTR pszPrefix)
+{
+  int nPrefixlen=_tcslen(pszPrefix);
+  FILE *f=_tfopen(pszFileName,_T("rt"));
+  bool rc=(0!=f);
+  if(rc){
+    TCHAR c[256];
+    while(_fgetts(c,sizeof(c)-1,f)){
+      if(_TCHAR('\0')!=c[0]){
+        c[_tcslen(c)-1]=_TCHAR('\0'); // remove trailing \n
+      }
+      if((signed)_tcslen(c)>nPrefixlen && 0==_tcsncmp(c,pszPrefix,nPrefixlen)){
+        TCHAR *pEq=_tcschr(c,_TCHAR('='));
+        if(pEq){
+          const String strName(c+nPrefixlen,pEq-c-nPrefixlen);
+          CProperties::CProperty *p=Lookup(strName);
+          if(p){
+            pEq++;
+            rc&=p->SetValue(pEq);
+          } else {
+            //TRACE(_T("Failed to find %s\n"),(LPCTSTR)strName);
+            rc=false;
+          }
+        }
+      }
+    }
+    fclose(f);
+  }
+  return rc;
+  
+}
+
+CProperties::CProperty::CProperty(LPCTSTR pszName,Typetype type,void *_pData):
+  strName(pszName),
+  Type(type),
+  pData(_pData)
+{
+}
+
+CProperties::CProperty::~CProperty()
+{
+}
+
+void CProperties::Add(LPCTSTR pszName,int &n,int _nDefault) 
+{
+    CProperty *p=new CProperty(pszName,CProperty::Integer,&n);
+    p->nDefault=_nDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,unsigned int &n,unsigned int _nDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::Integer,&n);
+    p->nDefault=_nDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,bool &b,bool _bDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::Bool,&b);
+    p->nDefault=_bDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,char &c,char _cDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::Char,&c);
+    p->nDefault=_cDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,unsigned char &c,unsigned char _cDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::Char,&c);
+    p->nDefault=_cDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,short &s,short _sDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::Short,&s);
+    p->nDefault=_sDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,unsigned short &s,unsigned short _sDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::Short,&s);
+    p->nDefault=_sDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,float &f,float _fDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::Float,&f);
+    p->dDefault=_fDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,double &f,double dDefault) 
+{
+    CProperty *p=new CProperty(pszName,CProperty::Double,&f);
+    p->dDefault=dDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,void *pv,unsigned int _nLength,void *pvDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::Void,pv);
+    p->nLength=_nLength;
+    p->pvDefault=pvDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add(LPCTSTR pszName,LPTSTR s,unsigned int _nLength,LPCTSTR _pszDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::szString,s);
+    p->nLength=_nLength;
+    p->strDefault=_pszDefault;
+    ar.push_back(p);
+}
+
+void CProperties::Add (LPCTSTR pszName,void *pObj,getFn *getFn,putFn *putFn,LPCTSTR pszDefault)
+{
+    CProperty *p=new CProperty(pszName,CProperty::GPString,pObj);
+    p->strDefault=pszDefault;
+    p->pgetFn=getFn;
+    p->pputFn=putFn;
+    p->strDefault=pszDefault;
+    ar.push_back(p);
+}
+
+unsigned long CProperties::CProperty::GetValue() const
+{
+    unsigned long dw;
+    switch(Type){
+        case Integer:
+            dw=*(int *)pData;
+            break;
+        case Bool:
+            dw=*(bool *)pData;
+            break;
+        case Char:
+            dw=*(char *)pData;
+            break;
+        case Short:
+            dw=*(short *)pData;
+            break;
+        default:
+            dw=0;
+            assert(false);
+    }
+    return dw;
+}
+
+const String CProperties::CProperty::GetStringValue() const 
+{
+    String str;
+    switch(Type){
+        case szString:
+            str=(LPCTSTR)(pData); 
+            break;
+        case GPString:
+            str=pgetFn(pData); 
+            break;
+        case CProperties::CProperty::Integer:
+        case CProperties::CProperty::Bool:
+        case CProperties::CProperty::Char:
+        case CProperties::CProperty::Short:
+            str.Format(_T("%u"),GetValue());
+            break;
+        case CProperties::CProperty::Float:
+            str.Format(_T("%e"),*(float *)(pData));
+            break;
+        case CProperties::CProperty::Double:
+            str.Format(_T("%e"),*(double *)(pData));
+            break;
+        case CProperties::CProperty::Void:
+            {
+                unsigned char *c=(unsigned char *)pData;
+                for(unsigned int i=0;i<nLength;i++){
+                    TCHAR buf[3];
+                    _tprintf(buf,_T("%02x"),c[i]);
+                    str+=buf;
+                }
+            }
+            break;
+        default:
+            break;
+    }
+    return str;
+}
+
+bool CProperties::CProperty::SetValue(int n)
+{
+    bool rc=true;
+    switch(Type){
+        case Integer:
+            *(int *)(pData)=n;
+            break;
+        case Bool:
+            *(bool *)(pData)=(0!=n);
+            break;
+        case Char:
+            *(char *)(pData)=(char)n; //FIXME: range checks
+            break;
+        case Short:
+            *(short *)(pData)=(short)n;//FIXME: range checks
+            break;
+        default:
+            //TRACE(_T("Failed to set '%s' to integer value '%d'\n"),(LPCTSTR)strName,n);
+            break;
+    }
+    return rc;
+}
+
+bool CProperties::CProperty::SetValue(double n)
+{
+    bool rc=true;
+    switch(Type){
+        case Double:
+            *(float *)(pData)=(float)n;//FIXME: range checks?
+            break;
+        case Float:
+            *(double *)(pData)=n;
+            break;
+        default:
+            //TRACE(_T("Failed to set '%s' to double value '%f'\n"),(LPCTSTR)strName,n);
+            rc=false;
+            break;
+    }
+
+    return rc;
+}
+
+bool CProperties::CProperty::SetValue(LPCTSTR psz)
+{
+    bool rc=false;
+    TCHAR *pEnd;
+    double d;
+    long l;
+    switch(Type){
+        case szString:
+            _tcsncpy((LPTSTR)pData,psz,nLength);
+            if(nLength<=_tcslen(psz)){
+                ((LPTSTR)pData)[nLength]=_TCHAR('\0');
+            }
+            rc=true;
+            break;
+        case GPString:
+            pputFn(pData,psz);
+            rc=true;
+            break;             
+        case Float:
+            d=_tcstod(psz,&pEnd);
+            rc=(_TCHAR('\0')==*pEnd);
+            if(rc){
+                SetValue((float)d);
+            }
+            break;
+        case Double:
+            d=_tcstod(psz,&pEnd);
+            rc=(_TCHAR('\0')==*pEnd);
+            if(rc){
+                SetValue(d);
+            }
+            break;
+        case Integer:
+        case Bool:
+        case Char:
+        case Short:
+            l=_tcstol(psz,&pEnd,10);
+            rc=(_TCHAR('\0')==*pEnd);
+            if(rc){
+                SetValue((int)l);
+            }
+            break;
+        default:
+            //TRACE(_T("Failed to set '%s' to string value '%s'\n"),(LPCTSTR)strName,psz);
+            break;
+    }
+    return rc;
+}
+
+void CProperties::CProperty::SetDefault()
+{
+    switch(Type){
+        case Bool:
+        case Integer:
+        case Char:
+        case Short:
+            SetValue(nDefault);
+            break;
+        case Float:
+        case Double:
+            SetValue(dDefault);
+            break;
+        case szString:
+        case GPString:
+            SetValue(strDefault);
+            break;
+        case Void:
+            if(pvDefault){
+                memcpy(pData,pvDefault,nLength);
+            }
+            break;
+        default:
+            assert(false);
+    }
+
+}
+
+void CProperties::SetDefaults()
+{
+    for(int i=ar.size()-1;i>=0;--i){
+        ((CProperty*)ar[i])->SetDefault();
+    }
+}
+
+bool CProperties::Load(LPCTSTR pszPrefix)
+{
+    #ifdef _WIN32
+    return m_hKey?LoadFromRegistry((HKEY)m_hKey,m_strName,pszPrefix):LoadFromFile(m_strName,pszPrefix);
+    #else // UNIX
+    return LoadFromFile(m_strName,pszPrefix);
+    #endif
+}
+
+bool CProperties::Save(LPCTSTR pszPrefix)
+{
+    #ifdef _WIN32
+    return m_hKey?SaveToRegistry((HKEY)m_hKey,m_strName,pszPrefix):SaveToFile(m_strName,pszPrefix);
+    #else // UNIX
+    return SaveToFile(m_strName,pszPrefix);
+    #endif
+}
+/*
+bool CProperties::Remove(LPCTSTR pszName)
+{
+    for(int i=ar.size()-1;i>=0;--i){
+        CProperties::CProperty *p=(CProperties::CProperty *)ar[i];
+        if(p->strName==pszName){
+            delete p;
+            ar.RemoveAt(i);
+            return true;
+        }
+    }
+    return false;
+}
+*/