ini-sections, ini-keys, ini-for-each added.
This commit is contained in:
@@ -6,3 +6,7 @@ compiled/
|
||||
\#*
|
||||
.\#*
|
||||
/test.ini
|
||||
|
||||
scribblings/*.js
|
||||
scribblings/*.html
|
||||
scribblings/*.css
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
(set! a b))))
|
||||
|
||||
|
||||
|
||||
(define ini%
|
||||
(class object%
|
||||
(init-field [file #f] [fail #f] [private? #f])
|
||||
@@ -40,11 +39,14 @@
|
||||
(i-set! private? p)
|
||||
this)
|
||||
|
||||
(define/public (get-contents)
|
||||
content)
|
||||
(define/public (sections)
|
||||
(ini-sections content))
|
||||
|
||||
(define/public (contents)
|
||||
content)
|
||||
(define/public (keys section)
|
||||
(ini-keys content section))
|
||||
|
||||
(define/public (for-each f)
|
||||
(ini-for-each f content))
|
||||
|
||||
(define/public (reload)
|
||||
(i-set! content (if (eq? file #f)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#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
|
||||
@@ -11,6 +12,10 @@
|
||||
ini-set!
|
||||
make-ini
|
||||
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
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -30,6 +30,15 @@
|
||||
(make-ini))
|
||||
(make-ini))))
|
||||
|
||||
((sections)
|
||||
(ini-sections content))
|
||||
|
||||
((keys section)
|
||||
(ini-keys content section))
|
||||
|
||||
((for-each f)
|
||||
(ini-for-each f content))
|
||||
|
||||
((set! s k v)
|
||||
(begin
|
||||
(ini-set! content s k v)
|
||||
|
||||
+113
-37
@@ -3,30 +3,40 @@
|
||||
@(require
|
||||
scribble/example
|
||||
scribble/core
|
||||
racket/runtime-path
|
||||
(for-label racket/base
|
||||
racket/string
|
||||
racket/class
|
||||
racket/file))
|
||||
racket/file
|
||||
racket/serialize))
|
||||
|
||||
(define myeval
|
||||
(make-base-eval '(require simple-ini roos)))
|
||||
@(define-runtime-path main-rkt "../main.rkt")
|
||||
|
||||
@(define myeval
|
||||
(make-base-eval `(require (file ,(path->string main-rkt)) roos)))
|
||||
|
||||
@title[#:tag "ini-parser"]{INI File Parser and Writer}
|
||||
|
||||
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
|
||||
|
||||
@defmodule[simple-ini]{This module provides simple facilities for reading and writing INI-style configuration files, allowing interpretation of numeric and boolean values, and modification of the parsed structure.}
|
||||
@defmodule[simple-ini]{This module provides simple facilities for reading and
|
||||
writing INI-style configuration files. It supports strings, numbers, booleans,
|
||||
paths, and serializable Racket values, and allows the parsed configuration to
|
||||
be queried and modified.}
|
||||
|
||||
@section{Creating and Parsing INI Files}
|
||||
|
||||
@defproc[(make-ini) mc-pair?]{
|
||||
Creates a new empty INI structure as a mutable cons pair. This is the base structure for manipulating INI contents.
|
||||
@defproc[(make-ini) is-ini?]{
|
||||
Creates a new, empty INI value. The representation of an INI value is
|
||||
private; use @racket[is-ini?] to recognize it and the procedures in this
|
||||
module to inspect or modify it.
|
||||
}
|
||||
|
||||
@defproc[(file->ini [file path-string?]) mc-pair?]{
|
||||
Reads an INI file from disk and parses it into an internal mutable cons pair (mc-pair) structure.
|
||||
If the file does noet exist, an empty ini structure is made.
|
||||
If file is a symbol?, the file will be constructed from the prefs-dir, the symbol and a suffix ".ini".
|
||||
@defproc[(file->ini [file (or/c path-string? symbol?)]) is-ini?]{
|
||||
Reads an INI file from disk and returns an INI value.
|
||||
If the file does not exist, an empty INI value is returned.
|
||||
If @racket[file] is a symbol, the path consists of the user's preferences
|
||||
directory and the symbol's name with an @filepath{.ini} suffix.
|
||||
|
||||
The parser supports:
|
||||
|
||||
@@ -37,17 +47,24 @@
|
||||
@item{Empty lines}
|
||||
]
|
||||
|
||||
An unrecognized non-empty line raises an exception that includes its line
|
||||
number and contents.
|
||||
|
||||
The keys are stored as symbols, and values are automatically interpreted as:
|
||||
@itemlist[
|
||||
@item{Numbers, if the value matches a number pattern}
|
||||
@item{Booleans, if the value is @tt{#t}, @tt{true}, @tt{#f}, or @tt{false} (case-insensitive)}
|
||||
@item{Paths written with the @tt{PATH:} prefix}
|
||||
@item{Explicit Racket-readable strings written with the @tt{VALUE:} prefix,
|
||||
including strings containing newlines}
|
||||
@item{Serializable Racket values written with the @tt{SER:} prefix}
|
||||
@item{Otherwise, as strings}
|
||||
]
|
||||
}
|
||||
|
||||
@defproc[(ini->file [ini mc-pair?] [file path-string?] [#:private? private? boolean? #f]) void?]{
|
||||
@defproc[(ini->file [ini is-ini?] [file path-string?] [#:private? private? boolean? #f]) void?]{
|
||||
Writes an INI structure (as produced by @racket[file->ini] or @racket[make-ini]) to the specified file.
|
||||
If file is a symbol?, the file will be constructed from the prefs-dir, the symbol and a suffix ".ini".
|
||||
Missing parent directories are created automatically.
|
||||
If @racket[private?] is @racket[#t], Unix-like systems restrict the file to mode @tt{0600} before the INI contents are written.
|
||||
|
||||
The output preserves:
|
||||
@@ -57,25 +74,72 @@
|
||||
@item{Comments (prefixed with @tt{;})}
|
||||
@item{Empty lines}
|
||||
]
|
||||
|
||||
Strings, paths, numbers, and booleans have dedicated encodings. Other values
|
||||
are written using @racket[serialize] and must therefore be serializable.
|
||||
}
|
||||
|
||||
@defproc[(get-ini-file [file (or/c path-string? symbol?)]) path?]{
|
||||
Resolves the file argument used by the API. A symbol is resolved in the
|
||||
user's preferences directory and receives an @filepath{.ini} suffix; a path
|
||||
string is converted to a path without otherwise changing its location.
|
||||
}
|
||||
|
||||
@defproc[(is-ini? [value any/c]) boolean?]{
|
||||
Returns @racket[#t] when @racket[value] is an INI value created by
|
||||
@racket[make-ini] or @racket[file->ini], and @racket[#f] otherwise.
|
||||
}
|
||||
|
||||
@section{Accessing and Modifying Values}
|
||||
|
||||
@defproc[(ini-get [ini mc-pair?]
|
||||
[section symbol?]
|
||||
[key symbol?]
|
||||
@defproc[(ini-get [ini is-ini?]
|
||||
[section (or/c symbol? string?)]
|
||||
[key (or/c symbol? string?)]
|
||||
[def-val any/c])
|
||||
any/c]{
|
||||
Retrieves the value associated with the given @racket[key] in the specified @racket[section] of the INI structure. If the key is not found, returns @racket[def-val].
|
||||
Retrieves the value associated with the given @racket[key] in the specified
|
||||
@racket[section]. Section and key matching is case-insensitive. If the key is
|
||||
not found, returns @racket[def-val].
|
||||
}
|
||||
|
||||
@defproc[(ini-set! [ini mc-pair?]
|
||||
[section symbol?]
|
||||
[key symbol?]
|
||||
@defproc[(ini-set! [ini is-ini?]
|
||||
[section (or/c symbol? string?)]
|
||||
[key (or/c symbol? string?)]
|
||||
[val any/c])
|
||||
mc-pair?]{
|
||||
is-ini?]{
|
||||
Sets the value of @racket[key] in the specified @racket[section] of the INI structure. If the section or key does not exist, it is created. Returns the modified INI structure.}
|
||||
|
||||
@section{Inspecting and Iterating over INI Values}
|
||||
|
||||
@defproc[(ini-sections [ini is-ini?]) (listof symbol?)]{
|
||||
Returns the named sections in source order. Key-value pairs before the first
|
||||
section header belong to the internal top-level section and are not included
|
||||
in this result.
|
||||
}
|
||||
|
||||
@defproc[(ini-keys [ini is-ini?] [section symbol?]) (listof symbol?)]{
|
||||
Returns the keys in @racket[section] in source order. If the section does not
|
||||
exist, returns the empty list. Use @racket['nil] to retrieve keys that occur
|
||||
before the first section header.
|
||||
}
|
||||
|
||||
@defproc[(ini-for-each [proc procedure?] [ini is-ini?]) void?]{
|
||||
Calls @racket[proc] with three arguments---the section, key, and value---for
|
||||
every key-value pair, in source order. Key-value pairs before the first
|
||||
section header use @racket['nil] as their section.
|
||||
|
||||
@examples[#:eval myeval
|
||||
(define settings (make-ini))
|
||||
(ini-set! settings 'server 'port 8080)
|
||||
(ini-set! settings 'server 'tls #t)
|
||||
(ini-sections settings)
|
||||
(ini-keys settings 'server)
|
||||
(ini-for-each
|
||||
(lambda (section key value)
|
||||
(printf "~a.~a = ~v~n" section key value))
|
||||
settings)]
|
||||
}
|
||||
|
||||
|
||||
@section{The @racket[ini%] Racket Class}
|
||||
|
||||
@@ -101,7 +165,7 @@ An OO wrapper around the ini functions.
|
||||
or if some non existing key is read.
|
||||
}
|
||||
|
||||
@defmethod*[([(get-file) path?])]{
|
||||
@defmethod*[([(get-file) (or/c path? #f)])]{
|
||||
Gets the current ini file. See constructor for more information.
|
||||
}
|
||||
|
||||
@@ -126,25 +190,30 @@ An OO wrapper around the ini functions.
|
||||
Enables or disables private file permissions for subsequent writes.
|
||||
}
|
||||
|
||||
@defmethod*[([(get-contents) list?])]{
|
||||
Gets the contents of the ini structure as stored in memory.
|
||||
@defmethod*[([(sections) (listof symbol?)])]{
|
||||
Returns the named sections in source order, as with @racket[ini-sections].
|
||||
}
|
||||
|
||||
@defmethod*[([(contents) list?])]{
|
||||
See get-contents.
|
||||
@defmethod*[([(keys [section symbol?]) (listof symbol?)])]{
|
||||
Returns the keys in @racket[section], as with @racket[ini-keys].
|
||||
}
|
||||
|
||||
@defmethod*[([(for-each [proc procedure?]) void?])]{
|
||||
Calls @racket[proc] with the section, key, and value of each key-value pair,
|
||||
as with @racket[ini-for-each].
|
||||
}
|
||||
|
||||
@defmethod*[([(reload) this])]{
|
||||
Reloads the ini file in memory, or empties the ini structure (eq? file #f).
|
||||
}
|
||||
|
||||
@defmethod*[([(set! [section (or/c symbol? string?)] [key (or/c symbol? string?)] [value any/c?]) this])]{
|
||||
@defmethod*[([(set! [section (or/c symbol? string?)] [key (or/c symbol? string?)] [value any/c]) this])]{
|
||||
Sets the value of the key in the given section. After the set! operation, the ini structure will be written to file.
|
||||
Note. Although ini files can be read from standard .ini formats, the simple-ini format will be enhanced. It wil store values in racket format, so that 'read' can be used to read in the racket value.
|
||||
}
|
||||
|
||||
@defmethod*[([(get [section (or/c symbol? string?)] [key (or/c symbol? string?)] [default-value any/c?]) any/c?]
|
||||
[(get [section (or/c symbol? string?)] [key (or/c symbol? string)]) any/c]
|
||||
@defmethod*[([(get [section (or/c symbol? string?)] [key (or/c symbol? string?)] [default-value any/c]) any/c]
|
||||
[(get [section (or/c symbol? string?)] [key (or/c symbol? string?)]) any/c]
|
||||
)]{
|
||||
Returns the value for the given section and key combination. If this combination does not exist in the ini structure, it will return the default-value. However, if default-value is not given, it will return #f.
|
||||
}
|
||||
@@ -188,7 +257,21 @@ If no file is provided, the object operates in-memory only. Subsequent @racket[s
|
||||
If the file does not exist, the content is reset to an empty INI structure.
|
||||
}
|
||||
|
||||
@defproc[(set! [section symbol?] [key symbol?] [val any/c]) ini]{
|
||||
@defproc[(sections) (listof symbol?)]{
|
||||
Returns the named sections in source order, as with
|
||||
@racket[ini-sections].
|
||||
}
|
||||
|
||||
@defproc[(keys [section symbol?]) (listof symbol?)]{
|
||||
Returns the keys in @racket[section], as with @racket[ini-keys].
|
||||
}
|
||||
|
||||
@defproc[(for-each [proc procedure?]) void?]{
|
||||
Calls @racket[proc] with the section, key, and value of each key-value
|
||||
pair, as with @racket[ini-for-each].
|
||||
}
|
||||
|
||||
@defproc[(set! [section (or/c symbol? string?)] [key (or/c symbol? string?)] [val any/c]) ini]{
|
||||
Sets the value in the INI structure for the given @racket[section] and @racket[key] to @racket[val].
|
||||
|
||||
If a file is associated with the object, the structure is saved to disk immediately.
|
||||
@@ -196,7 +279,7 @@ If no file is provided, the object operates in-memory only. Subsequent @racket[s
|
||||
Returns the INI object itself.
|
||||
}
|
||||
|
||||
@defproc[(get [section symbol?] [key symbol?] [def-val any/c] ...) any/c]{
|
||||
@defproc[(get [section (or/c symbol? string?)] [key (or/c symbol? string?)] [def-val any/c] ...) any/c]{
|
||||
Retrieves the value associated with the given @racket[section] and @racket[key].
|
||||
|
||||
If not found:
|
||||
@@ -206,10 +289,3 @@ If no file is provided, the object operates in-memory only. Subsequent @racket[s
|
||||
@item{Raises an error if @racket[fail] is enabled and no default is given}
|
||||
]
|
||||
}
|
||||
|
||||
@bold{Internal state:}
|
||||
@itemlist[
|
||||
@item{@racket[file*] — the filename (or @racket[#f])}
|
||||
@item{@racket[content] — the mutable INI structure}
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user