Ola!
Tem mais essa daqui, que já é um aprimoramento dessas mais universais.
/*
* Set of functions to manipulate INI files
* (work in progress...)
*
* - hb_IniGetValue( hIni, [cSection], cKey )
* - hb_IniSetValue( @hIni, [cSection], cKey, xVal, [cIniFile] )
* - hb_IniDelKey( @hIni, cSection, cKey, [cIniFile] )
* - hb_IniDelSECTION( @hIni, cSection, [cIniFile] )
* - hb_IniSaveFile( cIniFile, hIni, [lComments] )
*
* NOTE : case sensitive regarding section/key names
* (could easily modified to become case insensitive, though)
*
* Inspired by Giancarlo Niccolai's \harbour\tests\parseini.prg
* who's also creator of hb_ini* functions family (hbini.prg)
* Greatly helped by Juan Luis Gamero's excellent documentation
* of hashes found @ https://github.com/zgamero/sandbox/wiki/2.7-Hashes
* !Many thanks to both!
*
* GPL
* Pete D. 2014/11/11
*/
// test program
PROCEDURE Main()
LOCAL cIniFile := "MyIni.ini"
LOCAL hIni, cSection, cKey, xVal
IF hb_FileExists( cIniFile )
IF Empty( hIni := hb_iniRead( cIniFile ) )
hb_alert( cIniFile + " is invalid INI file!" )
RETURN
ENDIF
ELSE
hIni := hb_iniNew( .T. )
ENDIF
cSection := "SECTION_ONE"
cKey := "KEY_ONE"
xVal := "Hello!"
IF ! hb_IniSetValue( @hIni, cSection, cKey, xVal ) // create section/key & set value. NO save to .ini file
hb_Alert( "Failed to set value of " + cKey + " of " + cSection + "; debug your code!")
RETURN
ENDIF
hb_IniSetValue( @hIni, "SECTION_TWO", "KEYTWO", "World!", cIniFile ) //create/set AND save to cIniFile
hb_alert( hb_IniGetValue( hIni, "SECTION_ONE", "KEY_ONE" ) ) // sucess.-hopefully :-)
hb_alert( hb_IniGetValue( hIni, "SECTION_ONE", "Key_One" ) ) // failure. wrong cased key
hb_alert( hb_IniGetValue( hIni, "SECTION_TWO", "KEYTWO" ) ) // sucess.
hb_alert( hb_IniGetValue( hIni, "", "NO_Key") ) // fail. nonexistent key
// hb_IniDelKey( @hIni, "SECTION_ONE", "KEY_ONE" ) // uncomment to delete key
// hb_IniDelSection( @hIni, "SECTION_ONE" ) // uncomment to delete section
hb_IniSetValue( @hIni, "SECTION_TWO", "KeyTwo", "Inline comment" + " # note : key names handling is case sensitive" ) //create/set
hb_IniSetValue( @hIni, "SECTION_TWO", "KEyTwo", date() ) //create/set
hb_alert( hb_IniGetValue( hIni, "SECTION_TWO", "KEyTwo") )
hb_alert( hb_IniGetValue( hIni, "SECTION_TWO", "KeyTwo") )
hb_IniSaveFile( cIniFile, hIni, .T. )
hIni := hb_iniRead( cIniFile )
hb_alert( hb_IniGetValue( hIni, "SECTION_TWO", "KeyTwo") )
hb_Run( "start " + cIniFile )
/* INI handling functions */
FUNCTION hb_IniDelKey( /*@*/ hIni, cSection, cKey, cIniFile )
LOCAL aSect
LOCAL lSuccess := .F.
IF hb_HHasKey( hIni, cSection )
aSect := hIni[ cSection ]
hb_HDel( aSect , cKey )
lSuccess := .T.
ELSEIF hb_HHasKey( hIni, cKey )
hb_HDel( hIni , cKey )
lSuccess := .T.
ENDIF
IF lSuccess .AND. ! Empty( cIniFile ) .AND. HB_ISSTRING( cIniFile )
lSuccess := hb_IniSaveFile( cIniFile, hIni, .T. )
ENDIF
RETURN lSuccess
FUNCTION hb_IniDelSECTION( /*@*/ hIni, cSection, cIniFile )
LOCAL lSuccess := .F.
IF hb_HHasKey( hIni, cSection )
hb_HDel( hIni, cSection)
lSuccess := .T.
ENDIF
IF lSuccess .AND. ! Empty( cIniFile ) .AND. HB_ISSTRING( cIniFile )
lSuccess := hb_IniSaveFile( cIniFile, hIni, .T. )
ENDIF
RETURN lSuccess
FUNCTION hb_IniGetValue( hIni, cSection, cKey )
LOCAL RetVal
LOCAL aSect
IF hb_HHasKey( hIni, cSection )
aSect := hIni[ cSection ]
ENDIF
IF HB_ISHASH( aSect )
IF hb_HHasKey( aSect, cKey )
RetVal := hb_HGet( aSect, cKey )
ENDIF
// RetVal := aSect[ cKey ]
ELSE
IF hb_HHasKey( hIni, cKey )
RetVal := hb_HGet( hIni, cKey )
ENDIF
ENDIF
RETURN RetVal
FUNCTION hb_IniSetValue( /*@*/ hIni, cSection, cKey, xVal, cIniFile )
LOCAL hTemp
IF Empty( hIni ) .OR. ! HB_ISHASH( hIni ) .OR. Empty( cKey ) // empty/invalid ini-hash or empty key. really?
RETURN .F.
ENDIF
IF ! hb_PIsByRef( 1 ) // hIni not passed by reference. it may produce unpredictable results. avoid!
RETURN .F.
ENDIF
IF HB_ISNIL( xVal )
xVal := "" // if not value passed set it to a null string, wich practically means
// delete value of the key, eliminating the need of a delValue function
ENDIF
hTemp := hb_HClone( hIni ) // avoid to work directly with hIni (it's passed byref!)
IF ! Empty( cSection )
IF hb_HHasKey( hTemp, cSection ) // section exists?
IF HB_ISHASH( hTemp[ cSection ] ) // is it section? (could be toplevel key: see ELSE)
HB_HSet( hTemp[ cSection ], cKey, xVal )
ELSE // section is not a section! (is a toplevel key) so..
HB_HSet( hTemp, cSection, { => } ) // create new section
HB_HSet( hTemp[ cSection ], cKey, xVal ) // create key and set value
ENDIF
ELSE // section doesn't exist
HB_HSet( hTemp, cSection, { => } ) // create new section
HB_HSet( hTemp[ cSection ], cKey, xVal ) // create key and set value
ENDIF
ELSE // no section passed!
HB_HSet( hTemp, cKey, xVal ) // set toplevel key. (bad practice..?)
ENDIF
hIni := hb_HClone( hTemp ) // update hIni
hTemp := NIL
IF ! Empty( cIniFile ) .AND. HB_ISSTRING( cIniFile )
RETURN hb_IniSaveFile( cIniFile, hTemp, .T. )
ENDIF
RETURN .T.
FUNCTION hb_IniSaveFile( cIniFile, hIni, lComments )
LOCAL cHead, cFoot
hb_Default( lComments, .T. )
IF lComments
cHead := "# " + cIniFile + " - Last change: " + hb_DToC( Date()) +"-"+ Time()
cFoot := hb_EoL()+"# End of " + cIniFile
RETURN hb_iniWrite( cIniFile, hIni, cHead , cFoot, .f. )
ENDIF
RETURN hb_iniWrite( cIniFile, hIni, , , .f. )
Mas não passou no teste de Upper/lower rsrsrs...
Saudações,
Itamar M. Lins Jr.