Scripts/IniFiles

From J Wiki
Jump to navigation Jump to search

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