FF_INI functions

Started by John Montenigro, November 10, 2006, 12:29:25 PM

Previous topic - Next topic

John Montenigro

Having read the Help file and studied and tested the functions, it appears
that the only FF_INI function that actually writes to an INI file is:
  FF_INI_SetKey

If this is a correct conclusion, then:

1. How would I write only a section header?  For example, I want to create a new INI with only one section header: [CLIENTS]

2. How do I write a line with only the comment character ";" ?

3. Is it possible to write a blank line?

I understand I can do anything to the file using standard file access methods, but I'm asking with regard to FF_INI functions because of the convenience they provide in most every other need related to INI-files...

If I missed some FF_INI functions or my conclusion is incorect, please let me know that, too.

(Why would I think I'd have to ask for such information?  :lol: )


-John


ADDED:
=====

Also noticed that a key that starts with a ";"  gets pushed to the end of the section:

FF_INI_SetKey (temp, "CLIENTS", ";", " ")   'writes:  ;=  but AFTER the next line!!!  ???
FF_INI_SetKey (temp, "CLIENTS", "0003", "Sample, Joe")


Is it possible to comment out an existing line and leave it in place without it getting moved to the bottom of the Section?

-j

========
Hmmm... no replies. How far off base am I?
-j

John Montenigro


TechSupport

hmmm.... I must have missed this question :oops:  I will fire up FireFly tonight and get you a definitive answer. The ini functions were written a long, long, long time ago and I seem to remember that they were from Paul Noble (not sure)???

TechSupport

I just tried to do the things that you question in your post - and it looks like I am running into the same brick wall as you. The FF_INI_SetKey is a simple wrapper around the WinAPI function WritePrivateProfileString and it has some traits that seem odd. For example, it always seems to want to write a key/value pair for a section - if no key/value is being written then it effectively deletes the section if no other key/values exist in the section. This is why you can't seem to write "[CLIENTS]" by itself. I couldn't write a blank line either.

I would not trust that the order that you read and write the sections/keys/values will always be as you expect. Windows is handling all this behind the scenes. That is why your ";" is sometimes appearing at the end rather than the beginning like you want it to.

If your end users are able to edit this ini then I recommend that you use PB's built in file routines to create and handle the file as you need rather than relying on the ini functions. If you are creating a simple ini function to save/restore program state information, then the ini functions should suffice.

John Montenigro

OK Paul, I appreciate your looking into it. I just needed to confirm that I wasn't missing something obvious.

If I don't have that kind of control over things in the file, then I'll edit my specifications!
...I've done a lot of technical writing, and I not-so-kiddingly used to bill myself out as:
  "The Cleanup Team - We turn your bugs into Features!"

Thanks for your help,
-John

(I think the routines were from Eros Olmos.)

Roger Garstang

Does WritePrivateProfileSection do the same thing?  Its help somewhat acts like it doesn't care about the values.

John Montenigro

Roger,
In the materials I was able to locate, I don't remember anything that discussed whether the positions of the values can change (or not).

In all my testing, however, I've never seen the order changed by Win.



Paul,
Here's the link to the Eros Olmi posting:

http://www.powerbasic.com/support/forums/Forum7/HTML/001467.html


Also, I've written a function that permits Setting a Special Line. After I finish testing, I'll post it.

I'll be adding it to my "EO-ini.inc", and if you find it useful, Paul, you can add it to your products.

Thanks for your help,
-John

John Montenigro

I've tested this code and it does what I wanted it to do. Feel free to use it
or adapt it as you choose. No guarantees expressed or implied. YMMV. :D

'jmINI.inc
'
'2006-11-18 by jhm
' created:  INI_SetSpecialLine()
'=================================
'to supplement INI_ functions in eoINI.inc and FireFly
'this code helps in setting a special line into an INI:
'- a Section header with no keys, a blank, or a comment
'============================================

#IF NOT %DEF(%jmIniINC)
 %jmIniINC = 1

 #IF NOT %DEF(%WINAPI)
   #INCLUDE "WIN32API.INC"
 #ENDIF
 #IF NOT %DEF(%EOINIINC)           'may not **always** want the others, but mostly yes...
   #INCLUDE "eoINI.inc"
 #ENDIF

'==========================================
'added 2006-11-18 by jhm
%BEFORE_SECTION     = 1001
%TOP_OF_SECTION     = 1002
%BOTTOM_OF_SECTION  = 1003

'These can now be changed to numeric equates if desired:
$BLANK = " "       'better to use $SPC or SPACE$(1) etc...
$COMMENT = ";"  'initially saw API kill the line if no trailing space, but haven't seen that lately...?

'not really needed, but used during testing:
'$OTHER = "textline"   'not allowed unless preceeded with a ";"
$OTHER = "[NEWSECTION]"  ' yes, inserting just a section header is OK

'============================================  the reason for doing everything else in the file:
FUNCTION INI_SetSpecialLine(BYVAL iniFullspec AS STRING, BYVAL Txt AS STRING, BYVAL Where AS LONG, BYVAL TgtSection AS STRING) AS LONG
   'This function supplements the INI_ functions; helps insert special types of lines into an INI file.
   '- a blank line
   '- a comment line
   '- a [Section] line without any keys below it

   'note that although "Before a Section" and "Bottom of Section" produce the same result, each is specified differently

   LOCAL FilBuf AS LONG, tmp AS STRING, Index AS LONG, sLeft, sRight AS STRING

   FUNCTION = %TRUE    'assume success unless an error arises

   FilBuf& = FREEFILE
   OPEN iniFullspec FOR BINARY AS #FilBuf&
   IF ERR THEN
       FUNCTION = %FALSE
       EXIT FUNCTION
   END IF
   GET$ #FilBuf&, LOF(FilBuf&), tmp$

   Index = INSTR(tmp$, TgtSection)     ' locate the section of interest!
   IF Index = 0 THEN
       FUNCTION = %FALSE
       EXIT FUNCTION
   END IF

   'divide the INI into sLeft$ and sRight$, using the Index from above
   SELECT CASE Where
   CASE %BEFORE_SECTION
       sLeft$  = LEFT$(tmp$, IIF(Index -2 >= 1, Index-2, 0))
       sRight$ = MID$(tmp$, Index)

   CASE %TOP_OF_SECTION
       sLeft$  = LEFT$(tmp$, Index + LEN(TgtSection))
       Index   = INSTR(Index, tmp$, $CRLF)
       sRight$ = MID$(tmp$, Index+2)

   CASE %BOTTOM_OF_SECTION
       Index   = INSTR(Index+1, tmp$, "[")' is actually start of next Section; but looks/acts like %BEFORE_SECTION
       sLeft$  = LEFT$(tmp$, Index-1)
       sRight$ = MID$(tmp$, Index)

   END SELECT

   'get set to write
   SEEK #FilBuf&, 1

   'create the output according to what was requested
   SELECT CASE Txt
   CASE $BLANK
       PUT$ #FilBuf&, sLeft$ & $CRLF & sRight$
   CASE $COMMENT
       'PUT$ #FilBuf&, sLeft$ & "; " & $CRLF & sRight$  ' barely a visible divider...
       PUT$ #FilBuf&, sLeft$ & ";"& STRING$(15, "-") & $CRLF & sRight$   'much better!
   CASE ELSE   ' anything that's not a blank or a comment!
       '$OTHER = "textline"   ' not allowed unless preceeded with a ";"
       IF LEFT$(Txt,1) = "[" THEN   '
           'section header with no keys
           PUT$ #FilBuf&, sLeft$ &       Txt & $CRLF & sRight$
       ELSE
           PUT$ #FilBuf&, sLeft$ & ";" & Txt & $CRLF & sRight$   'these are allowed
       END IF
   END SELECT
   CLOSE #FilBuf&
END FUNCTION                                
'==============================================

#ENDIF




John Montenigro

Here's my test program for the new routine:

You can copy eoini.inc from:
http://www.powerbasic.com/support/forums/Forum7/HTML/001467.html


'write comment to section.bas
'============================
'the purpose of this program is to exercise and test one function: INI_SetSpecialLine()
'
'INI_SetSpecialLine() lets you write ONLY: a blank line, or a comment, or a section name
'
'developed 2006-11-10 by John Montenigro
'==========================================
#COMPILE EXE
#DIM ALL
#INCLUDE "win32api.inc"
#INCLUDE "eoini.inc"    'INI routines developed by Eros Olmi
                       'for code and more details about "eoini.inc", see:
                       '   http://www.powerbasic.com/support/forums/Forum7/HTML/001467.html

#INCLUDE "jmINI.inc"    '  <====  SEE PREVIOUS FORUM MESSAGE

'------------------------------------------------  utility routines for this app
SUB CreateMasterTestIni(BYVAL FileSpec AS STRING)
   ' create "TestIni.i_i"
   LOCAL FilBuf AS LONG, x AS STRING

   x$ =    "[Section 1]" & $CRLF & _
           "Key 1=Key1Value" & $CRLF & _
           "[Section 2]" & $CRLF & _
           "Key 1=Key1Value" & $CRLF & _
           "Key 2=Key2Value" & $CRLF & _
           "[Section 3]" & $CRLF & _
           "Key 1=Key1Value" & $CRLF & _
           "Key 2=Key2Value" & $CRLF & _
           "Key 3=Key3Value" & $CRLF & $CRLF

   FilBuf& = FREEFILE
   OPEN FileSpec FOR BINARY AS #FilBuf&
   IF ERR THEN EXIT SUB
   PUT$ #FilBuf&, x$
   CLOSE #FilBuf&
END SUB

FUNCTION INI_Report(BYVAL iniFile AS STRING) AS STRING
   LOCAL Count AS LONG
   LOCAL SectionList, KeyList, SectionName, Message AS STRING

   'Create a CRLF separated list of all section names inside IniFile
   SectionList = INI_GetSectionsList(IniFile)

   'show the keys under/in each section in the IniFile
   FOR Count = 1 TO PARSECOUNT(SectionList,$CRLF)
       SectionName = PARSE$(SectionList,$CRLF,Count)
       KeyList = INI_GetSectionKeyList(IniFile, SectionName)
       Message = Message & _
                 "This is section number : " & STR$(INI_GetSectionIndex(IniFile, SectionName)) & $CRLF & _
                 "Section name is: " & SectionName & $CRLF & _
                 "Inside this section there are " & STR$(INI_GetSectionTotalKeys(IniFile, SectionName)) & " keys." & $CRLF & _
                 $CRLF & _
                 "Keys inside this section are: " & $CRLF & _
                 $CRLF & _
                 KeyList & $CRLF & $CRLF
       KeyList = ""
       SectionName = ""
   NEXT Count
   FUNCTION = Message
END FUNCTION
'----------------------------------------------------------  general utility
FUNCTION GetWholeFile(BYVAL FileSpec AS STRING) AS STRING
   LOCAL FilBuf AS LONG, tmp AS STRING

   FilBuf& = FREEFILE
   OPEN FileSpec FOR BINARY AS #FilBuf&
   IF ERR THEN
       FUNCTION = ""
       EXIT FUNCTION
   END IF
   GET$ #FilBuf&, LOF(FilBuf&), tmp$
   CLOSE #FilBuf&
   FUNCTION = tmp$
END FUNCTION

FUNCTION Exist(File$) AS LONG
 LOCAL Dummy&
 Dummy& = GETATTR(File$)
 FUNCTION = (ERRCLEAR = 0)
END FUNCTION

FUNCTION AppPath() AS STRING
   LOCAL zTmp AS ASCIIZ * 256
   LOCAL sTmp AS STRING
   LOCAL LenExeName AS LONG
   LenExeName& = GetModuleFileName(BYVAL %NULL, zTmp, SIZEOF(zTmp))
   IF LenExeName& THEN
      LenExeName& = MIN&(LenExeName&, SIZEOF(zTmp))
      sTmp = LEFT$(zTmp, LenExeName&)
      sTmp = LEFT$(sTmp,INSTR(-1,sTmp,"\"))
      FUNCTION = sTmp
   END IF
END FUNCTION


'===============================================
FUNCTION PBMAIN() AS LONG
   LOCAL IniFile, stdIniFile, TgtSection, x AS STRING

   StdIniFile = AppPath & "TestIni.I_I"  'this is the unaltered original; we revert to it after each test
   IniFile = AppPath & "TestIni.INI"

   IF ISFALSE(Exist(StdIniFile)) THEN
       CreateMasterTestIni(StdIniFile)
   END IF

'    MSGBOX INI_Report(IniFile)  'to see what's there at the start

   TgtSection = "[Section 2]"   'let's do all our tests on this one section

'The general concept is:
'    INI_SetSpecialLine(iniFile, What, Where, TgtSection)

FILECOPY StdIniFile, iniFile                                            'prep
   INI_SetSpecialLine(iniFile, $BLANK, %BEFORE_SECTION, TgtSection)    'this is the work
x$ = "$BLANK, %BEFORE_SECTION 2"                                        'prep
MSGBOX GetWholeFile(iniFile),,x$                                        'prep
   MSGBOX INI_Report(IniFile),,x$                                      'report

FILECOPY StdIniFile, iniFile
   INI_SetSpecialLine(iniFile, $BLANK, %TOP_OF_SECTION, TgtSection)
x$ = "$BLANK, %TOP_OF_SECTION 2"
MSGBOX GetWholeFile(iniFile),,x$
   MSGBOX INI_Report(IniFile),,x$

FILECOPY StdIniFile, iniFile
   INI_SetSpecialLine(iniFile, $BLANK, %BOTTOM_OF_SECTION, TgtSection)
x$ = "$BLANK, %BOTTOM_OF_SECTION 2"
MSGBOX GetWholeFile(iniFile),,x$
   MSGBOX INI_Report(IniFile),,x$

FILECOPY StdIniFile, iniFile
   INI_SetSpecialLine(iniFile, $COMMENT, %BEFORE_SECTION, TgtSection)
x$ = "$COMMENT, %BEFORE_SECTION 2"
MSGBOX GetWholeFile(iniFile),,x$
   MSGBOX INI_Report(IniFile),,x$

FILECOPY StdIniFile, iniFile
   INI_SetSpecialLine(iniFile, $COMMENT, %TOP_OF_SECTION, TgtSection)
x$ = "$COMMENT, %TOP_OF_SECTION 2"
MSGBOX GetWholeFile(iniFile),,x$
   MSGBOX INI_Report(IniFile),,x$

FILECOPY StdIniFile, iniFile
   INI_SetSpecialLine(iniFile, $COMMENT, %BOTTOM_OF_SECTION, TgtSection)
x$ = "$COMMENT, %BOTTOM_OF_SECTION 2"
MSGBOX GetWholeFile(iniFile),,x$
   MSGBOX INI_Report(IniFile),,x$

FILECOPY StdIniFile, iniFile
   INI_SetSpecialLine(iniFile, $OTHER, %BEFORE_SECTION, TgtSection)
x$ = "$OTHER, %BEFORE_SECTION 2"
MSGBOX GetWholeFile(iniFile),,x$
   MSGBOX INI_Report(IniFile),,x$

FILECOPY StdIniFile, iniFile
   'NOTE HOW THIS takes over existing Section's keys!                      *****
   INI_SetSpecialLine(iniFile, $OTHER, %TOP_OF_SECTION, TgtSection)
x$ = "$OTHER, %TOP_OF_SECTION 2"
MSGBOX GetWholeFile(iniFile),,x$
   MSGBOX INI_Report(IniFile),,x$

FILECOPY StdIniFile, iniFile
   INI_SetSpecialLine(iniFile, $OTHER, %BOTTOM_OF_SECTION, TgtSection)
x$ = "$OTHER, %BOTTOM_OF_SECTION 2"
MSGBOX GetWholeFile(iniFile),,x$
   MSGBOX INI_Report(IniFile),,x$

'OK, all work correctly


   'now test to see if we can add a key using the other eoini.inc file
   'INI_SetKey (IniFile, "SECTION 1", "NewKey", "This is new")     'this works OK
   INI_SetKey (IniFile, "NEWSECTION", "NewKey", "This is new")     'Yesss!
x$ = "$Adding NewKey with value"
MSGBOX GetWholeFile(iniFile),,x$
   MSGBOX INI_Report(IniFile),,x$

'that's it - all works as intended

END FUNCTION