ConfigLib — Configuration Library
Persistent key/value storage using INI files. Save user preferences, application settings, game progress, and other data that persists between program executions. Cross-platform with automatic path resolution.
| Category | Count | Description |
|---|---|---|
| File Creation | 2 | cfg_open#, cfg_open_auto# |
| String Operations | 4 | cfg_set#, cfg_get$, cfg_sets#, cfg_gets$ |
| Numeric Operations | 4 | cfg_setn#, cfg_getn, cfg_setns#, cfg_getns |
| Boolean Operations | 4 | cfg_setb#, cfg_getb, cfg_setbs#, cfg_getbs |
| Key/Section Query | 3 | cfg_exists, cfg_haskey, cfg_section_exists |
| Key/Section Mgmt | 4 | cfg_delete#, cfg_deletekey#, cfg_section_delete#, cfg_clear# |
| Enumeration | 4 | cfg_sections$, cfg_keys$, cfg_sectioncount, cfg_keycount |
| File Operations | 5 | cfg_save, cfg_reload#, cfg_filename$, cfg_modified, cfg_autosave# |
| Utility | 1 | cfg_path$ |
| Feature | Description |
|---|---|
| INI Format | Human-readable [Section] key=value text files |
| Default Section | Empty string "" maps to the General section |
| Auto-Save Mode | Optional immediate write after every change |
| Default Values | All get functions accept a default for missing keys |
| Memory | Config objects are garbage-collected; unsaved changes saved on cleanup |
Storage Locations
Config files are stored in platform-appropriate directories automatically.
| Platform | Path |
|---|---|
| Windows | Documents\Plan9Basic\Config\ |
| Linux | ~/.config/Plan9Basic/ |
| macOS | ~/Library/Application Support/Plan9Basic/ |
| Android | App documents /Config/ |
| iOS | App documents /Config/ |
' Simple filename -> platform config dir + .ini cfg1# = cfg_open#("settings") ' Windows: Documents\Plan9Basic\Config\settings.ini ' Full path used as-is cfg2# = cfg_open#("/home/user/myconfig.ini")
ⓘ Note: If no extension is given,
.ini is added automatically. Use cfg_path$() to get the config directory path.INI File Format
[General] username=John theme=dark [Window] width=800 height=600 maximized=0 [Recent] file1=C:\Documents\report.txt file2=C:\Documents\notes.txt
| Element | Format |
|---|---|
| Sections | Enclosed in square brackets: [SectionName] |
| Key/Value | Separated by = |
| Encoding | UTF-8 |
| Comments | Not supported in the file format |
Config File Functions
| Function | Signature | Description |
|---|---|---|
cfg_open#(filename$) | cfg_open#@$ | Open/create config with manual save |
cfg_open_auto#(filename$) | cfg_open_auto#@$ | Open/create config with auto-save enabled |
' Manual save - changes written only on cfg_save() cfg# = cfg_open#("myapp") cfg_sets#(cfg#, "username", "John") cfg_setns#(cfg#, "volume", 75) cfg_save(cfg#) ' Auto-save - every change written immediately cfg# = cfg_open_auto#("critical_settings") cfg_sets#(cfg#, "lastSave", "2025-01-21") ' saved instantly cfg_setns#(cfg#, "counter", 42) ' saved instantly
| Mode | Best For |
|---|---|
cfg_open# (manual) | Batch updates, Save/Cancel UI, many rapid changes |
cfg_open_auto# (auto) | Critical settings, simple apps, infrequent changes |
String Operations
| Function | Signature | Description |
|---|---|---|
cfg_set#(c#, section$, key$, val$) | cfg_set#@#$$$ | Set string in section |
cfg_get$(c#, section$, key$, def$) | cfg_get$@#$$$ | Get string from section (with default) |
cfg_sets#(c#, key$, val$) | cfg_sets#@#$$ | Set string in default (General) section |
cfg_gets$(c#, key$, def$) | cfg_gets$@#$$ | Get string from default section (with default) |
cfg# = cfg_open#("settings") ' With explicit section cfg_set#(cfg#, "User", "name", "Alice") cfg_set#(cfg#, "User", "email", "alice@example.com") cfg_set#(cfg#, "Display", "theme", "dark") name$ = cfg_get$(cfg#, "User", "name", "Guest") theme$ = cfg_get$(cfg#, "Display", "theme", "light") ' Default section (General) cfg_sets#(cfg#, "language", "en") lang$ = cfg_gets$(cfg#, "language", "en") cfg_save(cfg#)
Numeric Operations
| Function | Signature | Description |
|---|---|---|
cfg_setn#(c#, section$, key$, val) | cfg_setn#@#$$n | Set number in section |
cfg_getn(c#, section$, key$, def) | cfg_getn@#$$n | Get number from section (with default) |
cfg_setns#(c#, key$, val) | cfg_setns#@#$n | Set number in default section |
cfg_getns(c#, key$, def) | cfg_getns@#$n | Get number from default section (with default) |
cfg# = cfg_open#("game") ' With section cfg_setn#(cfg#, "Window", "width", 1024) cfg_setn#(cfg#, "Window", "height", 768) cfg_setn#(cfg#, "Audio", "volume", 0.8) width = cfg_getn(cfg#, "Window", "width", 800) volume = cfg_getn(cfg#, "Audio", "volume", 1.0) ' Default section cfg_setns#(cfg#, "highScore", 15000) best = cfg_getns(cfg#, "highScore", 0) cfg_save(cfg#)
Boolean Operations
Booleans are stored as 0 (false) or 1 (true) in the INI file.
| Function | Signature | Description |
|---|---|---|
cfg_setb#(c#, section$, key$, val) | cfg_setb#@#$$n | Set boolean in section (0=false, non-zero=true) |
cfg_getb(c#, section$, key$, def) | cfg_getb@#$$n | Get boolean from section (returns 1 or 0) |
cfg_setbs#(c#, key$, val) | cfg_setbs#@#$n | Set boolean in default section |
cfg_getbs(c#, key$, def) | cfg_getbs@#$n | Get boolean from default section |
cfg# = cfg_open#("prefs") ' With section cfg_setb#(cfg#, "Features", "darkMode", 1) cfg_setb#(cfg#, "Features", "notifications", 0) darkMode = cfg_getb(cfg#, "Features", "darkMode", 0) if darkMode = 1 then println "Dark mode enabled" endif ' Default section - first run detection firstRun = cfg_getbs(cfg#, "firstRun", 1) if firstRun = 1 then println "Welcome! First time running the app." cfg_setbs#(cfg#, "firstRun", 0) cfg_save(cfg#) endif
Key and Section Query
| Function | Signature | Description |
|---|---|---|
cfg_exists(c#, section$, key$) | cfg_exists@#$$ | Key exists in section? (1/0) |
cfg_haskey(c#, key$) | cfg_haskey@#$ | Key exists in default section? (1/0) |
cfg_section_exists(c#, section$) | cfg_section_exists@#$ | Section exists? (1/0) |
cfg# = cfg_open#("settings") if cfg_exists(cfg#, "User", "email") = 1 then println "Email: "; cfg_get$(cfg#, "User", "email", "") endif if cfg_haskey(cfg#, "license") = 1 then println "Licensed version" else println "Trial version" endif if cfg_section_exists(cfg#, "SaveGame") = 1 then println "Save game found!" else println "No save - starting new game" endif
Key and Section Management
| Function | Signature | Description |
|---|---|---|
cfg_delete#(c#, section$, key$) | cfg_delete#@#$$ | Delete key from section |
cfg_deletekey#(c#, key$) | cfg_deletekey#@#$ | Delete key from default section |
cfg_section_delete#(c#, section$) | cfg_section_delete#@#$ | Delete entire section and all its keys |
cfg_clear#(c#) | cfg_clear#@# | Clear all sections and keys |
cfg# = cfg_open#("settings") ' Delete specific key cfg_delete#(cfg#, "User", "temporaryToken") cfg_deletekey#(cfg#, "tempData") ' Delete entire section cfg_section_delete#(cfg#, "SaveGame") ' Reset everything cfg_clear#(cfg#) cfg_sets#(cfg#, "language", "en") cfg_setns#(cfg#, "volume", 100) cfg_save(cfg#) println "Settings reset to defaults"
Enumeration Functions
| Function | Signature | Description |
|---|---|---|
cfg_sections$(c#) | cfg_sections$@# | Comma-separated list of all section names |
cfg_keys$(c#, section$) | cfg_keys$@#$ | Comma-separated list of keys in section |
cfg_sectioncount(c#) | cfg_sectioncount@# | Number of sections |
cfg_keycount(c#, section$) | cfg_keycount@#$ | Number of keys in section |
cfg# = cfg_open#("settings") println "Sections: "; cfg_sections$(cfg#) ' Output: General,User,Window,Audio println "Section count: "; cfg_sectioncount(cfg#) println "Window keys: "; cfg_keys$(cfg#, "Window") ' Output: width,height,x,y,maximized println "Key count: "; cfg_keycount(cfg#, "User")
File Operations
| Function | Signature | Description |
|---|---|---|
cfg_save(c#) | cfg_save@# | Save to disk (1=success, 0=failure) |
cfg_reload#(c#) | cfg_reload#@# | Reload from disk, discard unsaved changes |
cfg_filename$(c#) | cfg_filename$@# | Full file path of config file |
cfg_modified(c#) | cfg_modified@# | Unsaved changes? (1/0) |
cfg_autosave#(c#, enabled) | cfg_autosave#@#n | Enable (1) or disable (0) auto-save |
cfg# = cfg_open#("settings") cfg_sets#(cfg#, "theme", "dark") ' Check modified state if cfg_modified(cfg#) = 1 then println "Unsaved changes!" endif ' Save if cfg_save(cfg#) = 1 then println "Saved to: "; cfg_filename$(cfg#) else println "Save failed!" endif ' Discard changes cfg_sets#(cfg#, "theme", "experimental") cfg_reload#(cfg#) println "Changes discarded" ' Toggle auto-save cfg_autosave#(cfg#, 1) cfg_sets#(cfg#, "critical", "data") ' saved instantly cfg_autosave#(cfg#, 0) cfg_sets#(cfg#, "batch1", "v1") cfg_sets#(cfg#, "batch2", "v2") cfg_save(cfg#) ' save all at once
Utility Functions
| Function | Signature | Description |
|---|---|---|
cfg_path$() | cfg_path$@ | Platform-specific config directory path |
println "Config dir: "; cfg_path$() ' Windows: ...\Documents\Plan9Basic\Config ' Linux: ~/.config/Plan9Basic ' macOS: ~/Library/Application Support/Plan9Basic
Complete Examples
Application Settings
' Simple settings manager cfg# = cfg_open_auto#("myapp") if cfg_haskey(cfg#, "initialized") = 0 then println "First run - setting defaults..." cfg_sets#(cfg#, "initialized", "yes") cfg_sets#(cfg#, "language", "en") cfg_setns#(cfg#, "volume", 80) cfg_setbs#(cfg#, "fullscreen", 0) endif println "Language: "; cfg_gets$(cfg#, "language", "en") println "Volume: "; cfg_getns(cfg#, "volume", 80) println "Fullscreen: "; cfg_getbs(cfg#, "fullscreen", 0) println "Config: "; cfg_filename$(cfg#)
Game Save System
' Save/load game with sections cfg# = cfg_open#("savegame") if cfg_section_exists(cfg#, "Player") = 1 then println "Loading saved game..." name$ = cfg_get$(cfg#, "Player", "name", "Hero") level = cfg_getn(cfg#, "Player", "level", 1) gold = cfg_getn(cfg#, "Player", "gold", 0) health = cfg_getn(cfg#, "Player", "health", 100) else println "Starting new game..." name$ = "Hero" level = 1 gold = 100 health = 100 endif println name$; " - Level "; level; ", Gold: "; gold; ", HP: "; health ' Simulate gameplay gold = gold + 50 level = level + 1 ' Save cfg_set#(cfg#, "Player", "name", name$) cfg_setn#(cfg#, "Player", "level", level) cfg_setn#(cfg#, "Player", "gold", gold) cfg_setn#(cfg#, "Player", "health", health) cfg_save(cfg#) println "Game saved!"
Window Position Memory
' Remember window position cfg# = cfg_open#("window") x = cfg_getn(cfg#, "Position", "x", 100) y = cfg_getn(cfg#, "Position", "y", 100) w = cfg_getn(cfg#, "Position", "width", 800) h = cfg_getn(cfg#, "Position", "height", 600) maximized = cfg_getb(cfg#, "Position", "maximized", 0) println "Position: "; x; ", "; y println "Size: "; w; " x "; h ' Save new position cfg_setn#(cfg#, "Position", "x", x + 50) cfg_setn#(cfg#, "Position", "y", y + 30) cfg_save(cfg#)
Recent Files List
' Manage recent files list cfg# = cfg_open#("recent") ' Display current println "Recent files:" for i = 1 to 5 key$ = "file" + stri$(i, 0) if cfg_exists(cfg#, "Recent", key$) = 1 then println " "; i; ". "; cfg_get$(cfg#, "Recent", key$, "") endif next ' Add new file (shift others down) newFile$ = "C:\\Documents\\report_2025.txt" for i = 4 to 1 step -1 keyFrom$ = "file" + stri$(i, 0) keyTo$ = "file" + stri$(i + 1, 0) if cfg_exists(cfg#, "Recent", keyFrom$) = 1 then cfg_set#(cfg#, "Recent", keyTo$, cfg_get$(cfg#, "Recent", keyFrom$, "")) endif next cfg_set#(cfg#, "Recent", "file1", newFile$) cfg_save(cfg#)
Multi-User Profiles
' User profiles with sections cfg# = cfg_open#("profiles") println "Sections: "; cfg_sections$(cfg#) ' Create / update a profile profileName$ = "Player1" cfg_set#(cfg#, profileName$, "displayName", "John Doe") cfg_setn#(cfg#, profileName$, "highScore", 25000) cfg_setn#(cfg#, profileName$, "gamesPlayed", 42) cfg_setb#(cfg#, profileName$, "soundEnabled", 1) cfg_save(cfg#) println "Profile '"; profileName$; "':" println " Name: "; cfg_get$(cfg#, profileName$, "displayName", "?") println " Score: "; cfg_getn(cfg#, profileName$, "highScore", 0) println " Games: "; cfg_getn(cfg#, profileName$, "gamesPlayed", 0)
Configuration Dump
' Dump all configuration data cls cfg# = cfg_open#("settings") if cfg_sectioncount(cfg#) = 0 then cfg_sets#(cfg#, "appName", "TestApp") cfg_setns#(cfg#, "version", 1.5) cfg_set#(cfg#, "Database", "host", "localhost") cfg_setn#(cfg#, "Database", "port", 5432) cfg_save(cfg#) endif println "File: "; cfg_filename$(cfg#) println "Sections: "; cfg_sectioncount(cfg#) println "Modified: "; cfg_modified(cfg#) println "Section list: "; cfg_sections$(cfg#)
Quick Reference
| Function | Signature | Description |
|---|---|---|
cfg_open#(f$) / cfg_open_auto#(f$) | cfg_open*#@$ | Open config (manual / auto-save) |
cfg_set#(c#, sec$, k$, v$) | cfg_set#@#$$$ | Set string in section |
cfg_get$(c#, sec$, k$, def$) | cfg_get$@#$$$ | Get string from section |
cfg_sets#(c#, k$, v$) | cfg_sets#@#$$ | Set string (default section) |
cfg_gets$(c#, k$, def$) | cfg_gets$@#$$ | Get string (default section) |
cfg_setn#(c#, sec$, k$, v) | cfg_setn#@#$$n | Set number in section |
cfg_getn(c#, sec$, k$, def) | cfg_getn@#$$n | Get number from section |
cfg_setns#(c#, k$, v) | cfg_setns#@#$n | Set number (default section) |
cfg_getns(c#, k$, def) | cfg_getns@#$n | Get number (default section) |
cfg_setb#(c#, sec$, k$, v) | cfg_setb#@#$$n | Set boolean in section |
cfg_getb(c#, sec$, k$, def) | cfg_getb@#$$n | Get boolean from section |
cfg_setbs#(c#, k$, v) | cfg_setbs#@#$n | Set boolean (default section) |
cfg_getbs(c#, k$, def) | cfg_getbs@#$n | Get boolean (default section) |
cfg_exists(c#, sec$, k$) | cfg_exists@#$$ | Key exists in section? (1/0) |
cfg_haskey(c#, k$) | cfg_haskey@#$ | Key exists in default section? (1/0) |
cfg_section_exists(c#, sec$) | cfg_section_exists@#$ | Section exists? (1/0) |
cfg_delete#(c#, sec$, k$) | cfg_delete#@#$$ | Delete key from section |
cfg_deletekey#(c#, k$) | cfg_deletekey#@#$ | Delete key (default section) |
cfg_section_delete#(c#, sec$) | cfg_section_delete#@#$ | Delete entire section |
cfg_clear#(c#) | cfg_clear#@# | Clear all data |
cfg_sections$(c#) | cfg_sections$@# | List all sections (comma-separated) |
cfg_keys$(c#, sec$) | cfg_keys$@#$ | List keys in section |
cfg_sectioncount(c#) | cfg_sectioncount@# | Number of sections |
cfg_keycount(c#, sec$) | cfg_keycount@#$ | Number of keys in section |
cfg_save(c#) | cfg_save@# | Save to disk (1/0) |
cfg_reload#(c#) | cfg_reload#@# | Reload from disk |
cfg_filename$(c#) | cfg_filename$@# | Config file path |
cfg_modified(c#) | cfg_modified@# | Unsaved changes? (1/0) |
cfg_autosave#(c#, n) | cfg_autosave#@#n | Enable/disable auto-save |
cfg_path$() | cfg_path$@ | Config directory path |
28 functions across 9 categories (+ 2 open modes).