Contents

perfectlysoft/perfect-iniparser

A small, dependency-free parser for INI configuration

Requirements

  • Swift 6.2 or later (swift-tools-version: 6.2, Swift 6 language mode).
  • macOS 12 or later, or Linux. CI covers Swift 6.2 and 6.4 on Ubuntu 24.04 and Xcode 26.0.1

and 26.6 on macOS, in debug and release, with warnings as errors.

  • No package dependencies.

Using in your project

.package(url: "https://github.com/PerfectlySoft/Perfect-INIParser.git", from: "5.0.0"),
.product(name: "INIParser", package: "Perfect-INIParser"),

Usage

import INIParser

let ini = try INIParser("/path/to/settings.ini")   // or INIParser(data:), INIParser(string:)

let port = ini.sections["database"]?["port"]        // "143"
let debug = ini.anonymousSection["debug"]           // a variable before any section

Given this file:

; comments start with ; or #
debug = true

[database]
server = 192.0.2.42   ; a trailing comment
port = 143
name = Main Database
password = "a;b#c"

ini.anonymousSection is ["debug": "true"], and ini.sections["database"] is ["server": "192.0.2.42", "port": "143", "name": "Main Database", "password": "\"a;b#c\""].

Syntax

  • Comments: ; or # starts a comment, on a line of its own or after a value. Inside quotes

they're part of the value.

  • Sections: [name] starts a section. Variables before the first section go in

anonymousSection. A repeated section is merged into the earlier one, and a section with no variables doesn't appear in sections.

  • Assignments: key = value. Keys, values and section names are trimmed of surrounding spaces

and tabs; spaces inside them are kept. A value can contain =, [ and ], and can be empty. A later assignment to the same key in the same section replaces the earlier one.

  • Quotes: a value in "…" or '…' keeps its quotes, so password = "a;b#c" gives

"a;b#c" with the quote marks. Strip them yourself if you don't want them.

  • Lines: blank lines are ignored, and a UTF-8 byte order mark at the start of the file is skipped.

Errors

INIParser.Exception.InvalidSyntax is thrown when:

  • a line isn't blank, a comment, a section or an assignment (a key with no =, say);
  • a quote or a [ isn't closed.

INIParser.Exception.InvalidFile is thrown when the data isn't UTF-8. Errors from reading the file itself are passed through unchanged.

Migrating from 4.x

5.0 is the Swift 6 version. The API is the same: INIParser(_:), init(data:), init(string:), sections, anonymousSection and INIParser.Exception. Call sites keep compiling, apart from the first item below. Some files now parse differently:

  • INIParser is a final class and Sendable. Its properties are immutable. Upgrade: you

can no longer subclass it.

  • The public Stack<T> helper is gone. It was an internal detail. Upgrade: use an array.
  • Windows (\r\n) and classic Mac (\r) line endings work. Before, such a file came back as a

single garbled value (thanks to Ilia Sazonov, #5).

  • Spaces inside values, keys and section names are kept. name = John Smith used to give

JohnSmith, and [My Section] gave MySection. Upgrade: if you looked up keys or sections with the spaces removed, use the names as written in the file.

  • [ and ] inside a value are kept. list = [1,2] used to give 1,2.
  • ; and # inside quotes are part of the value. Such a line used to be dropped silently, or

to throw InvalidSyntax.

  • Lines of only spaces or tabs are ignored. They used to throw InvalidSyntax.
  • A leading UTF-8 byte order mark is skipped when the text is passed as a String. It used

to become part of the first key.

Everything else is unchanged.

Legacy

The pre-Swift-6 code (4.0.0) is on the legacy branch. Stay on 4.x if you can't move to Swift 6.2.

License

Apache 2.0. See LICENSE.

Package Metadata

Repository: perfectlysoft/perfect-iniparser

Default branch: main

README: README.md