Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Program for reading/editing config files? 2

Status
Not open for further replies.

TonyGroves

Programmer
Aug 13, 2003
2,389
IE
I'm looking for a program which reads/edits simple configuration files of the format used by Samba and other (particularly Windows) software, with a structure like:[tt]
[Section]
Key = value[/tt]
The syntax would probably be something like:[tt]
ini read sectionname <infile
ini read sectionname keyname <infile
ini write sectionname keyname valuestring <infile >outfile
ini delete sectionname <infile >outfile
ini delete sectionname keyname <infile >outfile[/tt]

Does anybody know of such a program, to save me reinventing the wheel?

Thanks.
 
Tony,

Pretend your us and re-read your post, it doesn't make much sense (To me anyway). Can you give a more detailed explaination of what your trying to do. Pre & post edited output would be good along with the O/S your using.

Mike

"A foolproof method for sculpting an elephant: first, get a huge block of marble, then you chip away everything that doesn't look like an elephant."

 
I don't know of any such programme, but you could implement it fairly easily in sed, awk or perl.

Annihilannic.
 
Sorry if it's not clear.

Suppose I have a file with contents like:[tt]
[profiles]
path = /home
browsable = yes
[global]
security = user
os level = 65
[/tt]
Now, I want to add (or update) the entry "writable = no" in the [profiles] section, so I would like to be able to issue a shell command something like:[tt]
ini write profiles writable no </etc/prog/config >/etc/prog/config[/tt]
and end up with:[tt]
[profiles]
path = /home
browsable = yes
writable = no
[global]
security = user
os level = 65
[/tt]
Or, I want to read the value of "path" in the "profiles" section:[tt]
ini read profiles path </etc/prog/config[/tt]
and get the output:[tt]
/home[/tt]

And so on ...

This is a very popular config file format, so I wouldn't be surprised if there was something out there already written. I'm using Debian GNU/Linux.
 
Note that this syntax is dangerous and will most likely not work, as you can't read from and write to the same file simultaneously:

[tt]ini write profiles writable no </etc/prog/config >/etc/prog/config[/tt]


Annihilannic.
 
you can't read from and write to the same file simultaneously

I would expect the program would first read the complete file, then make the changes, then write the output, as such config files tend to be small. Anyway, I'm just speculating about how it might work; I'll accept whatever syntax is required.
 
I see... well just so you know, ">" and "<" redirection would be handled by the shell, not the programme itself. They would just need to be standard parameters if you wanted to make the programme intelligent and use a temporary file, then rename it; or rename/copy the original and send the output to the original filename, etc.

I'm not aware of such an existing programme since this ini file syntax is more of a Windowsy thing and is relatively uncommon on Linux/Unix.

Annihilannic.
 
Wouldn't it be easier to have a config file with all the options in already, then use sed to make the alterations.

[profiles]
path = /home
browsable = yes
writable = no
[global]
security = user
os level = 65

sed s/writable = yes/writable = no/

or

sed s/#writable = no/writable = no/

Mike

"A foolproof method for sculpting an elephant: first, get a huge block of marble, then you chip away everything that doesn't look like an elephant."

 
Thanks for that, but it's not quite that simple (for example, you're not taking the [section] into account).

If I have to write it myself, I'll probably use Perl, which has a module called Config::Tiny for handling such files; the input gets read into a data structure (a hash of hashes presumably), you make your changes, then the structure gets written out in the right format.
 
Here is a first pass at implementing in awk:

Code:
#!/usr/bin/awk -f

BEGIN {
        if (ARGC < 4) {
                print "usage: ini <filename> <read|write|delete> <section> [ <keyname> [ <value> ] ]"
                exit 1
        }

        inifile=ARGV[1]
        operation=ARGV[2]
        section=ARGV[3]
        keyname=ARGV[4]
        value=ARGV[5]

        if (0) {
                print "inifile = " inifile
                print "operation = " operation
                print "section = " section
                print "keyname = " keyname
                print "value = " value
                print ""
        }

        while (getline < inifile) {
                if ($0 ~ "[[]"section"[]]") {
                        if (operation != "delete") print
                        while (getline < inifile) {
                                if ($0 ~ "^[[]") {
                                        if (operation == "write") print keyname " = " value
                                        if (operation == "read") break
                                }
                                print
                        }
                } else { if (operation != "read") print }
        }
}

It doesn't cater for the read/write/delete of individual keys though, nor does it check for existing values when setting a value. Notice I changed the syntax slightly to include the source file as the first parameter, and the output just goes to stdout for redirection to a temporary file or wherever. Let me know whether you want to implement in PERL or whether I should keep hacking this one...

Annihilannic.
 
Wow, thanks for that, Annihilannic. I wasn't expecting to have the program written for me here and now!

To be honest, I am a regular Perl user but have never used Awk. And since Perl has the ready-made module Config::Tiny, I'd be crazy not to take advantage of it. So, unless there's a widely-used production-grade program out there already, I'll write it in Perl.

Thanks for all the help, lads!
 
Annihilannic

That's worth a star in my opinion.

Mike

"A foolproof method for sculpting an elephant: first, get a huge block of marble, then you chip away everything that doesn't look like an elephant."

 
Go to and search for the string ini ("ini" is the config file format you're referring to) There are existing libraries for manipulating these types of files in several langauges including PHP, Python, C, and C++.

I'd also be very surprised if there was no Perl module for handling ini files; check CPAN. I just did a search there and found some modules with promising names, such as [tt]AnyData::Format::Ini[/tt] and [tt]Config::INI::Simple[/tt].
 
Code:
[text]

newLISP program to edit .ini files.
No associative arrays are used, and the data is
kept in its original order.

Say the .ini file contains

  [profiles]
  path = /home
  browsable = yes
  [global]
  security = user
  os level = 65

Then
  (get "profiles" "path")
produces
  "/home"
A shorter way is to use symbols:
  (get .profiles .path)
The symbols have had any spaces changed to ".":
  (get .global .os.level)
To change or add, use "put":
  (put .global .os.level 99)
yields
  (("profiles" (("path" "/home") ("browsable" "yes")))
   ("global" (("security" "user") ("os level" 99))))
When adding a new option, use a string instead of
a symbol:
  (put .global "foo" "bar")
Now the new option can be referenced by a symbol:
  (get .global .foo)
To delete an option, use "put" with no value:
  (put .profiles .path)

To see what the output will look like:
  (spill)

  [profiles]
  browsable = yes
  [global]
  security = user
  os level = 99
  foo = bar

To write the data to a file:
  (setq handle (open "out.ini" "w"))
  (spill handle)
  (close handle)

[/text]


(define (parse-option str)
  (parse str {\s*=\s*} 0))

(define (abbrev str)
  (set (sym (append "." (replace " " (string str) "."))) str))

(define (get-section sec-name)
  (lookup sec-name Data))

(define (change the-list key value)
  (if (= nil (lookup key the-list))
    (if value (push (list key value) the-list -1))
    (if value
      (replace-assoc key the-list (list key value))
      (replace-assoc key the-list)))
  the-list)

;; Add or change an option.
(define (put section-name option value , section)
  (abbrev option)
  (setq section (get-section section-name))
  (if value
    (setq section (change section option (string value)))
    (setq section (change section option)))
  (setq Data (change Data section-name section)))

;; Get an option's value.
(define (get section option)
  (lookup option (get-section section)))

(define (add-section str)
  (abbrev str)
  (push (list str '()) Data -1))

(define (del-section str)
  (replace-assoc str Data))

;; Write to screen if no file-handle given.
(define (output str handle)
  (if handle  (write-line str handle)
              (println str)))

;; Write Data in .ini format.
(define (spill handle , section xx yy)
  (dolist (section Data)
    (dolist (xx section)
      (if (list? xx)
        (dolist (yy xx) (output (join yy " = ") handle))
        (output (append "[" xx "]") handle)))))

(define (parse-file handle , line)
  (while (read-line handle)
    (setq line (trim (current-line)))
    (if (regex {^\[(.*)\]$} line)
      (begin
        (add-section $1)
        (setq section-name $1))
      (apply put (flat (list section-name (parse-option line)))))))

; --------------------

(if (> 3 (length (main-args)))
  (begin (println "Name of input file is needed.")(exit 5)))
(setq filename ((main-args) 2))
(if (not (setq handle (open filename "r")))
  (begin (println "Can't open " filename)(exit 5)))
(if (> (length (main-args) 3))  (setq outname ((main-args) 3)))
(parse-file handle)
(close handle)
(println Data)

# (exit)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top