Scripts/IniFiles
Read from and Write to INI files
This script defines verbs to cover the Windows API functions for reading and writing INI (or *.ini) files. The use of INI files to store configuration information for applications has been deprecated in favour of the Registry or XML files. Nevertheless some of us working with older/simpler applications may find the following useful.
getPPAllKeys v Gets all the keynames and values in an INI file getPPSection v Gets all the keys and values for a section of an INI file getPPSectionNames v Gets section names from an INI file getPPString v Gets the value of a key from an INI file getPPValue v Gets a key value from an INI file without comments getPPVals v Gets and interprets a key value from an INI file join v Unbox and delimit a list of boxed items y with x makeString v Creates space-delimited string from numeric list, list of boxed literals or numbers makeVals v Interprets a string as numeric or list of boxed literals writePPString v Writes key and key value to an INI file writePPSection v Writes list of key;keyvalue lists to an INI file
NOTE
The following definitions need to be corrected/changed for J6.01, but have all been made for J6.02.
GetPrivateProfileStringA and WritePrivateProfileStringA in the J6.01 distributed file ~system/packages/winapi/win32api.dat are incorrect and need to be corrected for getPPString and writePPString to work. Also the definition for GetPrivateProfileSectionNamesA is not included in win32api.dat and needs to be added for getPPSectionNames to work.
Usage
[{{#file: "example.ini"}} Download script: example.ini ]
[Control] BatchMode=1 # Run in batch mode? nCycles=10 #Number of cycles to run for BrkAtModule=ModuleFour #Module to break after Resume=0 # Resume? ResumeAtModule=ModuleTwo #Name of module to resume at [Formats] #This section defines display formats Colors=Red Blue Yellow Green Border=240 240 240 #color for borders BlackWhite=0 [EmptySection] [User] Name=Joe Bloggs Email=bloggs@mydomain.com FavMovie=The Lion King Birthdate= 2002 5 12 #year month day
Interact with the INI file as follows:
load jpath '~temp/inifiles.ijs' fln=: jpath '~temp/example.ini' getPPSectionNames fln ┌───────┬───────┬────────────┬────┐ │Control│Formats│EmptySection│User│ └───────┴───────┴────────────┴────┘ getPPString fln;'Formats';'Border' 240 240 240 #color for borders getPPValue fln;'Formats';'Border' 240 240 240 datatype getPPValue fln;'Formats';'Border' literal getPPVals fln;'Formats';'Border' 240 240 240 datatype getPPVals fln;'Formats';'Border' integer getPPVals fln;'Formats';'Colors' ┌───┬────┬──────┬─────┐ │Red│Blue│Yellow│Green│ └───┴────┴──────┴─────┘ getPPSection fln;'User' ┌─────────┬───────────────────┐ │Name │Joe Bloggs │ ├─────────┼───────────────────┤ │Email │bloggs@mydomain.com│ ├─────────┼───────────────────┤ │FavMovie │The Lion King │ ├─────────┼───────────────────┤ │Birthdate│2002 5 12 │ └─────────┴───────────────────┘ getPPAllSections fln ┌───────┬──────────────┬─────────────────────┐ │Control│BatchMode │1 │ ├───────┼──────────────┼─────────────────────┤ │Control│nCycles │10 │ ├───────┼──────────────┼─────────────────────┤ ... ├───────┼──────────────┼─────────────────────┤ │User │FavMovie │The Lion King │ ├───────┼──────────────┼─────────────────────┤ │User │Birthdate │2002 5 12 │ └───────┴──────────────┴─────────────────────┘ writePPString fln;'Formats';'Colors';<'Brown';'Pink';'Purple' 1 getPPString fln;'Formats';'Colors' Brown Pink Purple getPPVals fln;'Formats';'Colors' ┌─────┬────┬──────┐ │Brown│Pink│Purple│ └─────┴────┴──────┘ writePPString fln;'Formats';'Default';200 200 200 1 getPPSection fln;'Formats' ┌──────────┬─────────────────┐ │Colors │Brown Pink Purple│ ├──────────┼─────────────────┤ │Border │240 240 240 │ ├──────────┼─────────────────┤ │BlackWhite│0 │ ├──────────┼─────────────────┤ │Default │200 200 200 │ └──────────┴─────────────────┘
Code
You can download the three files example.ini, inifiles.ijs and testinifiles.ijs packaged together as one zip file by choosing the Literate item in the More Actions drop-down list at the top of the page. [{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.cover functions for winapi functions for reading from & writing to INI files require 'winapi strings'
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*getPPAllKeys v Gets all the keynames and values in an INI file NB. returns 3 column matrix, NB. 0{"1 sectionnames, 1{"1 keynames, 2{"1 keyvalues NB. y is the full filename of INI file getPPAllSections=: 3 : 0 snmes=. getPPSectionNames y keys=. getPPSection each <"1 (boxopen y),.snmes nkys=. #@> keys NB. number of keys in each section keys=. ;(nkys>0)#keys NB. compress out empty sections (nkys#snmes),.keys )
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*getPPSection v Gets all the keys and values for a section of an INI file NB. returns 2 column matrix NB. 0{"1 keynames, 1{"1 keyvalues getPPSection=: 3 : 0 'fnme snme'=. y len=. #str=. 32767$' ' 'len val'=. 0 2{'GetPrivateProfileSectionA'win32api snme;str;len;fnme val=. ({.a.),len{.val NB. line delimiter is {.a. (null) val=. <;._1 val val=. dtb each '#' taketo each val msk=. 0< #@> val NB. lines of non-zero length val=. msk#val ><;._1 each '=',each val )
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*getPPSectionNames v Gets section names from an INI file NB. returns list of boxed section names from the INI file NB. y is full path to INI file getPPSectionNames=: 3 : 0 fnme=. y len=. #str=. 32767$' ' 'len val'=. 0 1{'GetPrivateProfileSectionNamesA'win32api str;len;fnme <;._2 val=. len{.val )
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*getPPString v Gets the value of a key from an INI file NB. returns string of value of specified key NB. y is 3-item list of boxed strings NB. 0{ The full path to the INI file NB. 1{ Section Name NB. 2{ Key Name NB. e.g. getPPString 'c:\myini.ini';'Install';'InstallPath' getPPString=: 3 : 0 'fnme snme knme'=. y len=. #str=. 32767$' ' 'len val'=. 0 4{'GetPrivateProfileStringA'win32api snme;knme;'';str;len;fnme val=. len{.val )
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*getPPValue v Gets a key value from an INI file without comments NB. returns key value without comments NB. y is 3-item list of boxed strings NB. 0{ filename of ini file, NB. 1{ name of Section NB. 2{ name of Key NB. x is optional character used to delineate start of comments for line NB. e.g. getPPValue 'c:\myini.ini';'Install';'InstallPath' getPPValue=: 3 : 0 '#' getPPValue y NB. default comment delimiter is # : rval=. getPPString y NB. get raw value of Key rval=. dtb x taketo rval NB. get cleaned Key value (x is the comment delimiter) )
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*getPPVals v Gets and interprets a key value from an INI file NB. if can be interpreted as numeric, returns numeric list NB. if string contains spaces, returns list of boxed literals NB. else returns string of key value NB. y is 3-item list of boxed strings NB. 0{ filename of ini file, NB. 1{ name of Section NB. 2{ name of Key NB. x is optional character used to delineate start of comments for line NB. e.g. getPPVals 'c:\myini.ini' 'Install' 'InstallPath' getPPVals=: 3 : 0 '#' getPPVals y NB. default comment delimiter is # : 'delim err'=. 2{.!.(<_999999) boxopen x val=. delim getPPValue y NB. get cleaned value of Key err makeVals val )
join was proposed in the forum JForum:programming/2007-June/007077 . I agree with Oleg that this verb, or an equivalent, would be a useful addition to the strings.ijs standard library. [{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*join v Unbox and delimit a list of boxed items y with x NB. from forum post NB. http://www.jsoftware.com/pipermail/programming/2007-June/007077.html NB. eg. '","' join 'item1';'item2' NB. eg. LF join 'item1';'item2' NB. eg. 99 join <&> i.8 join=: ' '&$. : (4 : '(;@(#^:_1!.(<x))~ 1 0$~_1 2 p.#) y') NB. ignore $.
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*makeString v Creates space-delimited string from numeric list, list of boxed literals or numbers NB. returns space-delimited string or unchanged y, if y is literal NB. y is string, numeric list, list of boxed literals and/or numbers makeString=:[: ' '&join 8!:0
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*makeVals v Interprets a string as numeric or list of boxed literals NB. if y can be interpreted as all numeric, returns numeric list NB. elseif y contains spaces or commas, returns list of boxed literals NB. else returns original string NB. y is a string NB. x is optional numeric value used to signify non-numeric. NB. Choose value for x that will not be valid numeric in your data. makeVals=: 3 : 0 _999999 makeVals y : err=. x val=. ', ' charsub y NB. values delimited by commas and/or spaces if. -.+./err= nums=. err&". val do. val=. nums end. if. ' ' e. val do. val=. <;._1 ' ',deb val end. val )
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*writePPString v Writes key and key value to an INI file NB. returns Boolean, 1 if wrote OK, otherwise 0. NB. y is 4-item list of boxed info on key value to write NB. 0{ The full path to the INI file NB. 1{ Section Name NB. 2{ Key Name NB. 3{ The values to write (string, numeric list or NB. list of boxed literals and/or numbers) writePPString=: 3 : 0 'fnme snme knme val'=. y val=. makeString val res=. 'WritePrivateProfileStringA'win32api snme;knme;val;fnme 0{:: res )
[{{#file: "inifiles.ijs"}} Download script: inifiles.ijs ]
NB.*writePPSection v Writes list of key;keyvalue lists to an INI file NB. returns Boolean, 1 if wrote OK, otherwise 0. NB. y is 4-item list of boxed info on key values to write NB. 0{ The full path to the INI file NB. 1{ Section Name NB. 2{ list of 2-item boxed lists NB. 0{"1 keynames NB. 1{"1 keyvalues (string, numeric list or NB. list of boxed literals and/or numbers) writePPSection=: 3 : 0 'fnme snme keys'=. y null={.a. keys=. (makeString each 1{"1 keys) (1)}"0 1 keys NB. make keyvalues all strings keys=. '=' join each <"1 keys NB. join each key and keyvalue with '=' keys=. null,~ null join keys NB. join key,keyvalue pairs with null. Terminate with null NB. max length for keys is 65,535 bytes res=. 'WritePrivateProfileSectionA'win32api snme;keys;fnme 0{:: res )
[{{#file: "testinifiles.ijs"}} Download script: testinifiles.ijs ]
NB. Put cursor on a line and press Ctrl+r NB. to run the line in your ijx session. NB. Assumes you have placed example.ini in your J temp directory Note 'examples to run with example.ini' fln=: jpath '~temp/example.ini' getPPSectionNames fln getPPString fln;'Formats';'Border' getPPValue fln;'Formats';'Border' datatype getPPValue fln;'Formats';'Border' getPPVals fln;'Formats';'Border' datatype getPPVals fln;'Formats';'Border' getPPVals fln;'Formats';'Colors' getPPSection fln;'User' getPPAllSections fln writePPString fln;'Formats';'Colors';<'Brown';'Pink';'Purple' getPPString fln;'Formats';'Colors' getPPVals fln;'Formats';'Colors' writePPString fln;'Formats';'Default';200 200 200 getPPSection fln;'Formats' )
Contributed by -- Ric Sherlock <<DateTime(2007-08-16T02:05:54Z)>>
See Also
- The inifiles addon : cross-platform & more functionality.