]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/iniconf.cpp
'Set to Unspecified' -> 'Set Value to Unspecified'
[wxWidgets.git] / src / os2 / iniconf.cpp
index df53ce5f2139ca591c916be4468d6428b41dffb0..5b352380e66ab6481a771556fa26728202fc5b90 100644 (file)
@@ -4,6 +4,7 @@
 // Author:      David Webster
 // Modified by:
 // Created:     10/09/99
+// RCS-ID:      $Id$
 // Copyright:   David Webster
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
+#if wxUSE_CONFIG
+
 #ifndef   WX_PRECOMP
-  #include  <wx/string.h>
-  #include  <wx/intl.h>
-  #include  <wx/event.h>
-  #include  <wx/app.h>
-  #include  <wx/utils.h>
+    #include  "wx/dynarray.h"
+    #include  "wx/string.h"
+    #include  "wx/intl.h"
+    #include  "wx/event.h"
+    #include  "wx/app.h"
+    #include  "wx/utils.h"
+    #include  "wx/log.h"
 #endif  //WX_PRECOMP
 
-#include  <wx/dynarray.h>
-#include  <wx/log.h>
+#include  "wx/config.h"
 
-#include  <wx/config.h>
-#if wxUSE_CONFIG
-
-#include  <wx/os2/iniconf.h>
+#include  "wx/os2/iniconf.h"
 
 #define INCL_PM
 #include  <os2.h>
@@ -58,7 +59,7 @@ wxIniConfig::wxIniConfig(const wxString& strAppName,
                           localFilename, globalFilename, style)
 {
     m_strLocalFilename = localFilename;
-    if (m_strLocalFilename.IsEmpty())
+    if (m_strLocalFilename.empty())
     {
         m_strLocalFilename = GetAppName() + wxT(".ini");
     }
@@ -72,7 +73,7 @@ wxIniConfig::wxIniConfig(const wxString& strAppName,
     }
 
     // set root path
-    SetPath(wxT(""));
+    SetPath(wxEmptyString);
 }
 
 wxIniConfig::~wxIniConfig()
@@ -85,91 +86,100 @@ wxIniConfig::~wxIniConfig()
 
 void wxIniConfig::SetPath(const wxString& strPath)
 {
-  wxArrayString aParts;
+    wxArrayString aParts;
 
-  if ( strPath.IsEmpty() ) {
-    // nothing
-  }
-  else if ( strPath[(size_t) 0] == wxCONFIG_PATH_SEPARATOR ) {
-    // absolute path
-    wxSplitPath(aParts, strPath);
-  }
-  else {
-    // relative path, combine with current one
-    wxString strFullPath = GetPath();
-    strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
-    wxSplitPath(aParts, strFullPath);
-  }
+    if ( strPath.empty() )
+    {
+        // nothing
+    }
+    else if ( strPath[(size_t) 0] == wxCONFIG_PATH_SEPARATOR )
+    {
+        // absolute path
+        wxSplitPath(aParts, strPath);
+    }
+    else
+    {
+        // relative path, combine with current one
+        wxString strFullPath = GetPath();
+        strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
+        wxSplitPath(aParts, strFullPath);
+    }
 
-  size_t nPartsCount = aParts.Count();
-  m_strPath.Empty();
-  if ( nPartsCount == 0 ) {
-    // go to the root
-    m_strGroup = (wxChar*)PATH_SEP_REPLACE;
-  }
-  else {
-    // translate
-    m_strGroup = aParts[(size_t) 0];
-    for ( size_t nPart = 1; nPart < nPartsCount; nPart++ ) {
-      if ( nPart > 1 )
-        m_strPath << PATH_SEP_REPLACE;
-      m_strPath << aParts[nPart];
+    size_t nPartsCount = aParts.Count();
+    m_strPath.Empty();
+    if ( nPartsCount == 0 )
+    {
+        // go to the root
+        m_strGroup = (wxChar*)PATH_SEP_REPLACE;
+    }
+    else
+    {
+        // translate
+        m_strGroup = aParts[(size_t) 0];
+        for ( size_t nPart = 1; nPart < nPartsCount; nPart++ )
+        {
+            if ( nPart > 1 )
+                m_strPath << PATH_SEP_REPLACE;
+            m_strPath << aParts[nPart];
+        }
     }
-  }
 
-  // other functions assume that all this is true, i.e. there are no trailing
-  // underscores at the end except if the group is the root one
-  wxASSERT( (m_strPath.IsEmpty() || m_strPath.Last() != PATH_SEP_REPLACE) &&
-            (m_strGroup == wxString((wxChar)PATH_SEP_REPLACE) ||
-             m_strGroup.Last() != PATH_SEP_REPLACE) );
+    // other functions assume that all this is true, i.e. there are no trailing
+    // underscores at the end except if the group is the root one
+    wxASSERT( (m_strPath.empty() || m_strPath.Last() != PATH_SEP_REPLACE) &&
+              (m_strGroup == wxString((wxChar)PATH_SEP_REPLACE) ||
+               m_strGroup.Last() != PATH_SEP_REPLACE) );
 }
 
 const wxString& wxIniConfig::GetPath() const
 {
-  static wxString s_str;
+    static wxString s_str;
 
-  // always return abs path
-  s_str = wxCONFIG_PATH_SEPARATOR;
+    // always return abs path
+    s_str = wxCONFIG_PATH_SEPARATOR;
 
-  if ( m_strGroup == wxString((wxChar)PATH_SEP_REPLACE) ) {
-    // we're at the root level, nothing to do
-  }
-  else {
-    s_str << m_strGroup;
-    if ( !m_strPath.IsEmpty() )
-      s_str << wxCONFIG_PATH_SEPARATOR;
-    for ( const wxChar *p = m_strPath; *p != '\0'; p++ ) {
-      s_str << (*p == PATH_SEP_REPLACE ? wxCONFIG_PATH_SEPARATOR : *p);
+    if ( m_strGroup == wxString((wxChar)PATH_SEP_REPLACE) )
+    {
+        // we're at the root level, nothing to do
+    }
+    else
+    {
+        s_str << m_strGroup;
+        if ( !m_strPath.empty() )
+            s_str << wxCONFIG_PATH_SEPARATOR;
+        for ( const wxChar *p = m_strPath; *p != '\0'; p++ )
+        {
+            s_str << (*p == PATH_SEP_REPLACE ? wxCONFIG_PATH_SEPARATOR : *p);
+      }
     }
-  }
 
-  return s_str;
+    return s_str;
 }
 
 wxString wxIniConfig::GetPrivateKeyName(const wxString& szKey) const
 {
-  wxString strKey;
+    wxString strKey;
 
-  if ( !m_strPath.IsEmpty() )
-    strKey << m_strPath << PATH_SEP_REPLACE;
+    if ( !m_strPath.empty() )
+        strKey << m_strPath << PATH_SEP_REPLACE;
 
-  strKey << szKey;
+    strKey << szKey;
 
-  return strKey;
+    return strKey;
 }
 
 wxString wxIniConfig::GetKeyName(const wxString& szKey) const
 {
-  wxString strKey;
+    wxString strKey;
 
-  if (m_strGroup != wxString((wxChar)PATH_SEP_REPLACE))
-    strKey << m_strGroup << PATH_SEP_REPLACE;
-  if ( !m_strPath.IsEmpty() )
-    strKey << m_strPath << PATH_SEP_REPLACE;
+    if (m_strGroup != wxString((wxChar)PATH_SEP_REPLACE))
+        strKey << m_strGroup << PATH_SEP_REPLACE;
+    if ( !m_strPath.empty() )
+        strKey << m_strPath << PATH_SEP_REPLACE;
 
-  strKey << szKey;
+    strKey << szKey;
 
-  return strKey;
+    return strKey;
 }
 
 // ----------------------------------------------------------------------------
@@ -177,32 +187,32 @@ wxString wxIniConfig::GetKeyName(const wxString& szKey) const
 // ----------------------------------------------------------------------------
 
 // not implemented
-bool wxIniConfig::GetFirstGroup(wxString& str, long& lIndex) const
+bool wxIniConfig::GetFirstGroup(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
 {
-  wxFAIL_MSG(wxT("not implemeted"));
+    wxFAIL_MSG(wxT("not implemeted"));
 
-  return FALSE;
+    return false;
 }
 
-bool wxIniConfig::GetNextGroup (wxString& str, long& lIndex) const
+bool wxIniConfig::GetNextGroup(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
 {
-  wxFAIL_MSG(wxT("not implemeted"));
+    wxFAIL_MSG(wxT("not implemeted"));
 
-  return FALSE;
+    return false;
 }
 
-bool wxIniConfig::GetFirstEntry(wxString& str, long& lIndex) const
+bool wxIniConfig::GetFirstEntry(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
 {
-  wxFAIL_MSG(wxT("not implemeted"));
+    wxFAIL_MSG(wxT("not implemeted"));
 
-  return FALSE;
+    return false;
 }
 
-bool wxIniConfig::GetNextEntry (wxString& str, long& lIndex) const
+bool wxIniConfig::GetNextEntry(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
 {
-  wxFAIL_MSG(wxT("not implemeted"));
+    wxFAIL_MSG(wxT("not implemeted"));
 
-  return FALSE;
+    return false;
 }
 
 // ----------------------------------------------------------------------------
@@ -210,49 +220,49 @@ bool wxIniConfig::GetNextEntry (wxString& str, long& lIndex) const
 // ----------------------------------------------------------------------------
 
 // not implemented
-size_t wxIniConfig::GetNumberOfEntries(bool bRecursive) const
+size_t wxIniConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const
 {
-  wxFAIL_MSG(wxT("not implemeted"));
+    wxFAIL_MSG(wxT("not implemeted"));
 
-  return (size_t)-1;
+    return (size_t)-1;
 }
 
-size_t wxIniConfig::GetNumberOfGroups(bool bRecursive) const
+size_t wxIniConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const
 {
-  wxFAIL_MSG(wxT("not implemeted"));
+    wxFAIL_MSG(wxT("not implemeted"));
 
-  return (size_t)-1;
+    return (size_t)-1;
 }
 
-bool wxIniConfig::HasGroup(const wxString& strName) const
+bool wxIniConfig::HasGroup(const wxString& WXUNUSED(strName)) const
 {
-  wxFAIL_MSG(wxT("not implemeted"));
+    wxFAIL_MSG(wxT("not implemeted"));
 
-  return FALSE;
+    return false;
 }
 
-bool wxIniConfig::HasEntry(const wxString& strName) const
+bool wxIniConfig::HasEntry(const wxString& WXUNUSED(strName)) const
 {
-  wxFAIL_MSG(wxT("not implemeted"));
+    wxFAIL_MSG(wxT("not implemeted"));
 
-  return FALSE;
+    return false;
 }
 
 // is current group empty?
 bool wxIniConfig::IsEmpty() const
 {
-  char szBuf[1024];
+    char szBuf[1024];
 
 //  GetPrivateProfileString(m_strGroup, NULL, "",
 //                          szBuf, WXSIZEOF(szBuf), m_strLocalFilename);
-  if ( !::IsEmpty(szBuf) )
-    return FALSE;
+    if ( !::wxIsEmpty(szBuf) )
+        return false;
 
 //  GetProfileString(m_strGroup, NULL, "", szBuf, WXSIZEOF(szBuf));
-//  if ( !::IsEmpty(szBuf) )
-    return FALSE;
+//  if ( !::wxIsEmpty(szBuf) )
+//      return false;
 
-  return TRUE;
+    return true;
 }
 
 // ----------------------------------------------------------------------------
@@ -261,103 +271,112 @@ bool wxIniConfig::IsEmpty() const
 
 bool wxIniConfig::Read(const wxString& szKey, wxString *pstr) const
 {
-  wxConfigPathChanger path(this, szKey);
-  wxString strKey = GetPrivateKeyName(path.Name());
+    wxConfigPathChanger path(this, szKey);
+    wxString strKey = GetPrivateKeyName(path.Name());
 
-  wxChar szBuf[1024]; // @@ should dynamically allocate memory...
+    wxChar szBuf[1024]; // @@ should dynamically allocate memory...
 
-  // first look in the private INI file
+    // first look in the private INI file
 
-  // NB: the lpDefault param to GetPrivateProfileString can't be NULL
+    // NB: the lpDefault param to GetPrivateProfileString can't be NULL
 //  GetPrivateProfileString(m_strGroup, strKey, "",
 //                          szBuf, WXSIZEOF(szBuf), m_strLocalFilename);
-  if ( ::IsEmpty((PSZ)szBuf) ) {
-    // now look in win.ini
-    wxString strKey = GetKeyName(path.Name());
-//    GetProfileString(m_strGroup, strKey, "", szBuf, WXSIZEOF(szBuf));
-  }
+    if ( ::wxIsEmpty((PSZ)szBuf) )
+    {
+        // now look in win.ini
+        wxString strKey = GetKeyName(path.Name());
+        // GetProfileString(m_strGroup, strKey, "", szBuf, WXSIZEOF(szBuf));
+    }
+
+    if ( ::wxIsEmpty((PSZ)szBuf) )
+    {
+        return false;
+    }
 
-  if ( ::IsEmpty((PSZ)szBuf) ) {
-    return FALSE;
-  }
-  else {
     *pstr = szBuf ;
-    return TRUE;
-  }
+    return true;
 }
 
 bool wxIniConfig::Read(const wxString& szKey, wxString *pstr,
                        const wxString& szDefault) const
 {
-  wxConfigPathChanger path(this, szKey);
-  wxString strKey = GetPrivateKeyName(path.Name());
+    wxConfigPathChanger path(this, szKey);
+    wxString strKey = GetPrivateKeyName(path.Name());
 
-  wxChar szBuf[1024]; // @@ should dynamically allocate memory...
+    wxChar szBuf[1024]; // @@ should dynamically allocate memory...
 
-  // first look in the private INI file
+    // first look in the private INI file
 
-  // NB: the lpDefault param to GetPrivateProfileString can't be NULL
-//  GetPrivateProfileString(m_strGroup, strKey, "",
-//                          szBuf, WXSIZEOF(szBuf), m_strLocalFilename);
-  if ( ::IsEmpty((PSZ)szBuf) ) {
-    // now look in win.ini
-    wxString strKey = GetKeyName(path.Name());
-//    GetProfileString(m_strGroup, strKey, "", szBuf, WXSIZEOF(szBuf));
-  }
+    // NB: the lpDefault param to GetPrivateProfileString can't be NULL
+    // GetPrivateProfileString(m_strGroup, strKey, "",
+    //                         szBuf, WXSIZEOF(szBuf), m_strLocalFilename);
+    if ( ::wxIsEmpty((PSZ)szBuf) )
+    {
+      // now look in win.ini
+      wxString strKey = GetKeyName(path.Name());
+      // GetProfileString(m_strGroup, strKey, "", szBuf, WXSIZEOF(szBuf));
+    }
 
-  if ( ::IsEmpty((PSZ)szBuf) ) {
-    *pstr = szDefault;
-    return FALSE;
-  }
-  else {
-    *pstr = szBuf ;
-    return TRUE;
-  }
+    if ( ::wxIsEmpty((PSZ)szBuf) )
+    {
+        *pstr = szDefault;
+        return false;
+    }
+    else
+    {
+        *pstr = szBuf ;
+        return true;
+    }
 }
 
 bool wxIniConfig::Read(const wxString& szKey, long *pl) const
 {
-  wxConfigPathChanger path(this, szKey);
-  wxString strKey = GetPrivateKeyName(path.Name());
-
-  // hack: we have no mean to know if it really found the default value or
-  // didn't find anything, so we call it twice
-
-  static const int nMagic  = 17; // 17 is some "rare" number
-  static const int nMagic2 = 28; // arbitrary number != nMagic
-  long lVal = 0; // = GetPrivateProfileInt(m_strGroup, strKey, nMagic, m_strLocalFilename);
-  if ( lVal != nMagic ) {
-    // the value was read from the file
-    *pl = lVal;
-    return TRUE;
-  }
+    wxConfigPathChanger path(this, szKey);
+    wxString strKey = GetPrivateKeyName(path.Name());
 
-  // is it really nMagic?
-//  lVal = GetPrivateProfileInt(m_strGroup, strKey, nMagic2, m_strLocalFilename);
-  if ( lVal == nMagic2 ) {
-    // the nMagic it returned was indeed read from the file
-    *pl = lVal;
-    return TRUE;
-  }
+    // hack: we have no mean to know if it really found the default value or
+    // didn't find anything, so we call it twice
+
+    static const int nMagic  = 17; // 17 is some "rare" number
+    static const int nMagic2 = 28; // arbitrary number != nMagic
+    long lVal = 0; // = GetPrivateProfileInt(m_strGroup, strKey, nMagic, m_strLocalFilename);
 
-  // no, it was just returning the default value, so now look in win.ini
-//  *pl = GetProfileInt(GetVendorName(), GetKeyName(szKey), *pl);
+    if ( lVal != nMagic )
+    {
+        // the value was read from the file
+        *pl = lVal;
+        return true;
+    }
+
+    // is it really nMagic?
+    // lVal = GetPrivateProfileInt(m_strGroup, strKey, nMagic2, m_strLocalFilename);
+    if ( lVal == nMagic2 )
+    {
+        // the nMagic it returned was indeed read from the file
+        *pl = lVal;
+        return true;
+    }
 
-  return TRUE;
+    // no, it was just returning the default value, so now look in win.ini
+    // *pl = GetProfileInt(GetVendorName(), GetKeyName(szKey), *pl);
+
+    return true;
 }
 
-bool wxIniConfig::Write(const wxString& szKey, const wxString& szValue)
+bool wxIniConfig::Write(const wxString& szKey, const wxString& WXUNUSED(szValue))
 {
-  wxConfigPathChanger path(this, szKey);
-  wxString strKey = GetPrivateKeyName(path.Name());
+    wxConfigPathChanger path(this, szKey);
+    wxString strKey = GetPrivateKeyName(path.Name());
 
-  bool bOk = FALSE; // = WritePrivateProfileString(m_strGroup, strKey,
+    bool bOk = false; // = WritePrivateProfileString(m_strGroup, strKey,
 //                                       szValue, m_strLocalFilename) != 0;
 
-  if ( !bOk )
-    wxLogLastError("WritePrivateProfileString");
+    if ( !bOk )
+    {
+        wxLogLastError(wxT("WritePrivateProfileString"));
+    }
 
-  return bOk;
+    return bOk;
 }
 
 bool wxIniConfig::Write(const wxString& szKey, long lValue)
@@ -371,9 +390,9 @@ bool wxIniConfig::Write(const wxString& szKey, long lValue)
 
 bool wxIniConfig::Flush(bool /* bCurrentOnly */)
 {
-  // this is just the way it works
-//  return WritePrivateProfileString(NULL, NULL, NULL, m_strLocalFilename) != 0;
-  return FALSE;
+    // this is just the way it works
+    // return WritePrivateProfileString(NULL, NULL, NULL, m_strLocalFilename) != 0;
+    return false;
 }
 
 // ----------------------------------------------------------------------------
@@ -382,27 +401,29 @@ bool wxIniConfig::Flush(bool /* bCurrentOnly */)
 
 bool wxIniConfig::DeleteEntry(const wxString& szKey, bool bGroupIfEmptyAlso)
 {
-  // passing NULL as value to WritePrivateProfileString deletes the key
-//  if ( !Write(szKey, (const char *)NULL) )
-//    return FALSE;
-  wxConfigPathChanger path(this, szKey);
-  wxString strKey = GetPrivateKeyName(path.Name());
+    // passing NULL as value to WritePrivateProfileString deletes the key
+    // if ( !Write(szKey, (const char *)NULL) )
+    //     return false;
+    wxConfigPathChanger path(this, szKey);
+    wxString strKey = GetPrivateKeyName(path.Name());
 
-//  if (WritePrivateProfileString(m_strGroup, szKey,
-//                                         (const char*) NULL, m_strLocalFilename) == 0)
-//    return FALSE;
+    // if (WritePrivateProfileString(m_strGroup, szKey,
+    //                               (const char*) NULL, m_strLocalFilename) == 0)
+    //    return false;
 
-  if ( !bGroupIfEmptyAlso || !IsEmpty() )
-    return TRUE;
+    if ( !bGroupIfEmptyAlso || !IsEmpty() )
+        return true;
 
-  // delete the current group too
-  bool bOk = FALSE; // = WritePrivateProfileString(m_strGroup, NULL,
-//                                       NULL, m_strLocalFilename) != 0;
+    // delete the current group too
+    bool bOk = false; // = WritePrivateProfileString(m_strGroup, NULL,
+                      //                             NULL, m_strLocalFilename) != 0;
 
-  if ( !bOk )
-    wxLogLastError("WritePrivateProfileString");
+    if ( !bOk )
+    {
+        wxLogLastError(wxT("WritePrivateProfileString"));
+    }
 
-  return bOk;
+    return bOk;
 }
 
 bool wxIniConfig::DeleteGroup(const wxString& szKey)
@@ -411,11 +432,13 @@ bool wxIniConfig::DeleteGroup(const wxString& szKey)
 
   // passing NULL as section name to WritePrivateProfileString deletes the
   // whole section according to the docs
-  bool bOk = FALSE; // = WritePrivateProfileString(path.Name(), NULL,
-  //                                     NULL, m_strLocalFilename) != 0;
+  bool bOk = false; // = WritePrivateProfileString(path.Name(), NULL,
+                    //                             NULL, m_strLocalFilename) != 0;
 
   if ( !bOk )
-    wxLogLastError("WritePrivateProfileString");
+  {
+    wxLogLastError(wxT("WritePrivateProfileString"));
+  }
 
   return bOk;
 }
@@ -426,42 +449,43 @@ bool wxIniConfig::DeleteGroup(const wxString& szKey)
 
 bool wxIniConfig::DeleteAll()
 {
-  // first delete our group in win.ini
-//  WriteProfileString(GetVendorName(), NULL, NULL);
+    // first delete our group in win.ini
+    // WriteProfileString(GetVendorName(), NULL, NULL);
 
-  // then delete our own ini file
-  wxChar szBuf[MAX_PATH];
-  size_t nRc = 0; // = GetWindowsDirectory(szBuf, WXSIZEOF(szBuf));
-  if ( nRc == 0 )
-  {
-    wxLogLastError("GetWindowsDirectory");
-  }
-  else if ( nRc > WXSIZEOF(szBuf) )
-  {
-    wxFAIL_MSG(_("buffer is too small for Windows directory."));
-  }
+    // then delete our own ini file
+    wxChar szBuf[MAX_PATH];
+    size_t nRc = 0; // = GetWindowsDirectory(szBuf, WXSIZEOF(szBuf));
+    if ( nRc == 0 )
+    {
+        wxLogLastError(wxT("GetWindowsDirectory"));
+    }
+    else if ( nRc > WXSIZEOF(szBuf) )
+    {
+        wxFAIL_MSG(_("buffer is too small for Windows directory."));
+    }
 
-  wxString strFile = szBuf;
-  strFile << wxT('\\') << m_strLocalFilename;
+    wxString strFile = szBuf;
+    strFile << wxT('\\') << m_strLocalFilename;
 
-  if ( !wxRemoveFile(strFile) ) {
-    wxLogSysError(_("Can't delete the INI file '%s'"), strFile.c_str());
-    return FALSE;
-  }
+    if ( !wxRemoveFile(strFile) )
+    {
+        wxLogSysError(_("Can't delete the INI file '%s'"), strFile.c_str());
+        return false;
+    }
 
-  return TRUE;
+    return true;
 }
 
-bool wxIniConfig::RenameEntry(const wxString& oldName, const wxString& newName)
+bool wxIniConfig::RenameEntry(const wxString& WXUNUSED(oldName), const wxString& WXUNUSED(newName))
 {
     // Not implemented
-    return FALSE;
+    return false;
 }
 
-bool wxIniConfig::RenameGroup(const wxString& oldName, const wxString& newName)
+bool wxIniConfig::RenameGroup(const wxString& WXUNUSED(oldName), const wxString& WXUNUSED(newName))
 {
     // Not implemented
-    return FALSE;
+    return false;
 }
 
 #endif //wxUSE_CONFIG