ini-sections, ini-keys, ini-for-each added.

This commit is contained in:
2026-08-31 14:54:09 +02:00
parent a6d2c630bb
commit 9efc2350c0
5 changed files with 251 additions and 59 deletions
+118 -17
View File
@@ -1,16 +1,21 @@
#lang racket/base
(require racket/string)
(require racket/file)
(require racket/port)
(require racket/serialize)
(require racket/string
racket/file
racket/port
racket/serialize
racket/contract)
(provide file->ini
ini->file
ini-get
ini-set!
make-ini
get-ini-file
get-ini-file
ini-sections
ini-keys
ini-for-each
is-ini?
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -18,7 +23,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-struct ini-cfg
(contents #:mutable #t)
((contents #:mutable))
)
(define (output-value v out)
@@ -89,8 +94,12 @@
(build-path pref-dir (string-append (symbol->string f) ".ini")))
(build-path f)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Writes an ini file to the given file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (ini->file ini file #:private? [private? #f])
(define/contract (ini->file ini file #:private? [private? #f])
(->* (ini-cfg? path-string?) (#:private? boolean?) void?)
(let* ((file (get-ini-file file))
(_ (make-parent-directory* file))
(out (if (and private?
@@ -132,11 +141,24 @@
(newline out))
(error "Unknown line format")))))
lines))))
(mcdr ini)))
(close-output-port out)))
(ini-cfg-contents ini)))
(close-output-port out))
(void)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Creates an empty ini structure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (make-ini)
(mcons 'ini (list)))
(make-ini-cfg '()))
(define (is-ini? i)
(ini-cfg? i))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads an ini file to an internal ini structure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (file->ini file*)
(let* ((file (get-ini-file file*))
@@ -168,7 +190,14 @@
(if m-section
(f (append sections (list section)) (list (string->symbol (string-trim (cadr m-section)))) (cdr lines))
(error (format "Unknown INI line\n~a: ~a\n" line-nr line)))))))))))
(mcons 'ini (f '() (list 'nil) lines)))))
(make-ini-cfg (f '() (list 'nil) lines))
)
)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Gets a value from the ini structure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (ini-get ini section key def-val)
(letrec ((g (lambda (ini)
@@ -186,10 +215,17 @@
(f (cdr l))))))))
(f (cdar ini)))
(g (cdr ini)))))))
(g (mcdr ini))))
(g (ini-cfg-contents ini))))
(define (ini-set! ini section key val)
(let ((found #f))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Sets a value in the ini structure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (ini-set! ini section key* val)
(let ((found #f)
(key (string->symbol (format "~a" key*)))
)
(letrec ((for-sect (lambda (sect)
(if (null? sect)
(if found
@@ -215,8 +251,73 @@
(if (section=? section-key section)
(cons (cons section (for-sect (cdr ini-section))) (for-ini (cdr ini)))
(cons ini-section (for-ini (cdr ini)))))))))
(let ((new-ini (for-ini (mcdr ini))))
(set-mcdr! ini new-ini)
ini)))))
(let ((new-ini (for-ini (ini-cfg-contents ini))))
(set-ini-cfg-contents! ini new-ini))
ini))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Gets all sections of the ini file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define/contract (ini-sections cfg)
(-> ini-cfg? (listof symbol?))
(map (λ (sect) (car sect))
(filter (λ (sect) (not (eq? (car sect) 'nil)))
(ini-cfg-contents cfg))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Gets all keys for a given section
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define/contract (ini-keys cfg section)
(-> ini-cfg? symbol? (listof symbol?))
(let ((s (filter (λ (sect) (eq? (car sect) section)) (ini-cfg-contents cfg))))
(if (null? s)
'()
(map cadr
(filter (λ (kv)
(not (eq? (car kv) 'empty))) (cdar s)))
)
)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; iterates over all sections and keys of an ini structure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (any? a) #t)
(define/contract (ini-for-each f cfg)
(-> procedure? ini-cfg? any?)
(for-each (λ (s)
(for-each (λ (kv)
(when (eq? (car kv) 'keyval)
(f (car s) (cadr kv) (caddr kv))))
(cdr s)))
(ini-cfg-contents cfg)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Tests for module library.rkt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module+ test
(require rackunit)
(define (run-ini-tests)
(define test-ini (make-ini))
(ini-set! test-ini 'section1 'key1 "Value 1")
(ini-set! test-ini 'section1 'key2 42)
(ini-set! test-ini 'section1 77 7777)
(ini-set! test-ini 'section2 'key1 (list "Value 1"))
(ini-set! test-ini 'section2 "my-key" (make-hash '((a . 42) (b . "Hi There"))))
(check-equal?
(list 'section1 'section2) (ini-sections test-ini))
test-ini
)
)