ini

package module
v0.0.0-...-beddee2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2025 License: MIT Imports: 15 Imported by: 0

README

go-ini

Package ini provides tools for working with the INI data format, for the Go programming language.

Documention

Online documentation, which includes examples, can be found at: http://godoc.org/github.com/reiver/go-ini

GoDoc

Example

Here is an example of how to unmarshal INI data:

import "github.com/reiver/go-ini"

// ...

var inidata []byte = []byte(`
apple  = 1
banana = 2
cherry = 3

[count]

once   = ۱

twice  = ۱, ۲

thrice = ۱, ۲, ۳

fource = ۱, ۲, ۳, ۴

`)

// ...

err := ini.Unmarshal(inidata, dst)
if nil != err {
	return err
}

Classic INI Format

The classic INI data format looks like this:

; This is a comment.

[section]

key=value

apple=one
banana=two
cherry=three


[person]
name=Joe Blow
organization=Acme Inc.

De Facto INI Format

Beyond the classic INI format, there is a de facto INI format, that includes some widely used extensions.

The de facto INI format also includes an additional syntax for comments, and an additional syntax for key-value pairs.

For example:

; This is a comment in the classic INI format.

[section]
key=value

apple=one
banana=two
cherry=three


[person]
name=Joe Blow
organization=Acme Inc.

# This is also a comment in the de facto INI format.

[de facto]
length: 5cm
count: ۵
color: red

Multi-Line Values

There are 2 ways to create multi-line string values

name = line 1\
line 2\
line 3

And:

name &END
line 1
line 2
line 3
END

(`END` could be replaced with whatever you want the string-termination token to be.)

## Import

To import package **ini** use `import` code like the following:

import "github.com/reiver/go-ini"


## Installation

To install package **ini** do the following:

GOPROXY=direct go get github.com/reiver/go-ini


## Author

Package **ini** was written by [Charles Iliya Krempeaux](http://reiver.link)

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Append

func Append(p []byte, content any, nesting ...string) ([]byte, error)

Append is similar to Marshal except that it appends.

See also Marshal, ToString and Write

func AppendKeyValue

func AppendKeyValue(p []byte, key string, value string) []byte

AppendKeyValue appends the INI representation of a key-vaue pair.

You might use this function is you are implementing the Marshaler interface for a custom type. And in particular, use it (directly or indirectly) from you Marshal method.

Also see KeyValueToString and WriteKeyValue

Example
var buffer [256]byte
var p []byte = buffer[0:0]

var key string = "Banana"
var value string = "TWO"

p = ini.AppendKeyValue(p, key, value) // <---------

var result string = string(p)

fmt.Print(result)
Output:

Banana = TWO

func AppendSectionHeader

func AppendSectionHeader(p []byte, name ...string) []byte

AppendSectionHeader appends the INI representation of a section header.

You might use this function is you are implementing the Marshaler interface for a custom type. And in particular, use it (directly or indirectly) from you MarshalINI method.

In INI, a section used to create something to a single records. For example:

[basket]

apple = 1
Banana = 2
CHERRY = 3
dAtE = 4

And in this example, the section-header is:

[basket]

Which could be created with a call similar to:

p = ini.AppendSectionHeader(p, "basket")

For another example, this call:

p = ini.AppendSectionHeader(p, "yek", "do", "se")

Would producde the section-header:

[yek.do.se]

Also see SectionHeaderToString and WriteSectionHeader

Also, AppendSectionHeader shouldn't be confused with AppendSequenceHeader

Example
var buffer [256]byte
var p []byte = buffer[0:0]

p = ini.AppendSectionHeader(p, "apple", "Banana", "CHERRY") // <---------

var result string = string(p)

fmt.Print(result)
Output:

[apple.Banana.CHERRY]

func AppendSequenceHeader

func AppendSequenceHeader(p []byte, name ...string) []byte

AppendSequenceHeader appends the INI representation of a sequence-header.

You might use this function is you are implementing the Marshaler interface for a custom type. And in particular, use it (directly or indirectly) from you MarshalINI method.

In INI, a sequence is used to create something similar to database records. For example:

[[fruits]]

apple = ONE
Banana = TWO
CHERRY = THREE
dAtE = FOUR

[[fruits]]

apple = 1
Banana = 2
CHERRY = 3
dAtE = 4

[[fruits]]

apple = once
Banana = twice
CHERRY = thrice
dAtE = fource

And in this example, the sequence-header is:

[[fruits]]

Which could be created with a call similar to:

p = ini.AppendSequenceHeader(p, "fruits")

For another example, this call:

p = ini.AppendSequenceHeader(p, "yek", "do", "se")

Would producde the sequence-header:

[[yek.do.se]]

Also see SequenceHeaderToString and WriteSequenceHeader

Also, AppendSequenceHeader shouldn't be confused with AppendSectionHeader

func CreateInvalidDestinationTypeError

func CreateInvalidDestinationTypeError(value any) error

CreateInvalidDestinationTypeError returns a InvalidDestinationTypeError.

func DecodeKey

func DecodeKey(key string) string

DecodeKey (potentially) decodes a key (from a key-value pair) from its valid INI content form.

func KeyValueToString

func KeyValueToString(key string, value string) string

See also AppendKeyValue and WriteKeyValue

Example
var key string = "Banana"
var value string = "TWO"

var result string = ini.KeyValueToString(key, value) // <---------

fmt.Print(result)
Output:

Banana = TWO

func Marshal

func Marshal(content any, nesting ...string) ([]byte, error)

Marshal returns the INI encoding of `content`.

Some Go built-in types have an ini-content represention; such as map[string]any and map[string]string

A custom type can also have an ini-content by implementing the Marshaler interface.

See also Append, ToString and Write

Example of calling Marshal without a nesting:

bytes, err := ini.Marshal(data)

Example of calling Marshal with a nesting:

bytes, err := ini.Marshal(data, "dairy", "milk")
Example (MapStringAny)
var src = map[string]any{
	"cookies":  "2",
	"crackers": "1",
	"dairy": map[string]string{
		"cheese": "20",
		"milk":   "2",
		"yogurt": "12",
	},
	"fruits": map[string]string{
		"apple":  "ONE",
		"Banana": "TWO",
		"CHERRY": "THREE",
	},
}

p, err := ini.Marshal(src) // <---------

if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

var result string = string(p)

fmt.Print(result)
Output:

cookies = 2
crackers = 1
[dairy]
cheese = 20
milk = 2
yogurt = 12
[fruits]
apple = ONE
Banana = TWO
CHERRY = THREE
Example (MapStringAny_2)
var m = map[string]any{
	"aardvark": "adult",
	"meese":    "pair",
	"moose":    "single",
	"dairy": map[string]any{
		"cheese": "20",
		"milk": map[string]string{
			"1%": "2",
			"2%": "1",
		},
		"yogurt": "12",
	},
	"fruits": map[string]string{
		"apple":  "ONCE",
		"Banana": "TWICE",
		"CHERRY": "THRICE",
		"dAtE":   "FOURCE",
	},
	"z": map[string]any{
		"z-1": map[string]any{
			"z-1-1": "HERE",
			"z-1-2": map[string]string{
				"z-1-2-1": "(1)",
				"z-1-2-2": "(2)",
				"z-1-2-3": "(3)",
			},
		},
	},
}

result, err := ini.Marshal(m) // <---------

if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

fmt.Printf("%s", result)
Output:

aardvark = adult
meese = pair
moose = single
[dairy]
cheese = 20
yogurt = 12
[dairy.milk]
1% = 2
2% = 1
[fruits]
apple = ONCE
Banana = TWICE
CHERRY = THRICE
dAtE = FOURCE
[z]
[z.z-1]
z-1-1 = HERE
[z.z-1.z-1-2]
z-1-2-1 = (1)
z-1-2-2 = (2)
z-1-2-3 = (3)
Example (MapStringString)
var src = map[string]string{
	"apple":  "ONE",
	"Banana": "TWO",
	"CHERRY": "THREE",
}

p, err := ini.Marshal(src) // <---------

if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

var result string = string(p)

fmt.Print(result)
Output:

apple = ONE
Banana = TWO
CHERRY = THREE
Example (SliceMapStringString)
var src = []map[string]string{
	map[string]string{
		"apple":  "ONE",
		"Banana": "TWO",
		"CHERRY": "THREE",
		"dAtE":   "FOUR",
	},
	map[string]string{
		"apple":  "1",
		"Banana": "2",
		"CHERRY": "3",
		"dAtE":   "4",
	},
	map[string]string{
		"apple":  "once",
		"Banana": "twice",
		"CHERRY": "thrice",
		"dAtE":   "fource",
	},
}

p, err := ini.Marshal(src, "fruits") // <---------

if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

var result string = string(p)

fmt.Print(result)
Output:

[[fruits]]
apple = ONE
Banana = TWO
CHERRY = THREE
dAtE = FOUR
[[fruits]]
apple = 1
Banana = 2
CHERRY = 3
dAtE = 4
[[fruits]]
apple = once
Banana = twice
CHERRY = thrice
dAtE = fource

func SectionHeaderToString

func SectionHeaderToString(name ...string) string

See also AppendSectionHeader and WriteSectionHeader

Example
var result string = ini.SectionHeaderToString("apple", "Banana", "CHERRY") // <---------

fmt.Print(result)
Output:

[apple.Banana.CHERRY]

func SequenceHeaderToString

func SequenceHeaderToString(name ...string) string

See also AppendSequenceHeader and WriteSequenceHeader

func SortKeys

func SortKeys(keys []string)

SortKeys sorts a record's keys in a human-friendly and humane way.

func ToString

func ToString(value any) (string, error)

See also Marshal and Write

Example (MapStringAny)
var src = map[string]any{
	"cookies":  "2",
	"crackers": "1",
	"dairy": map[string]string{
		"cheese": "20",
		"milk":   "2",
		"yogurt": "12",
	},
	"fruits": map[string]string{
		"apple":  "ONE",
		"Banana": "TWO",
		"CHERRY": "THREE",
	},
}

var result string
var err error

result, err = ini.ToString(src)
if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

fmt.Print(result)
Output:

cookies = 2
crackers = 1
[dairy]
cheese = 20
milk = 2
yogurt = 12
[fruits]
apple = ONE
Banana = TWO
CHERRY = THREE
Example (MapStringString)
var src = map[string]string{
	"apple":  "ONE",
	"Banana": "TWO",
	"CHERRY": "THREE",
}

var result string
var err error

result, err = ini.ToString(src)
if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

fmt.Print(result)
Output:

apple = ONE
Banana = TWO
CHERRY = THREE

func Unmarshal

func Unmarshal(data []byte, dst any) error

Unmarshal parses the INI-encoded data and stores the result in the value pointed to by 'dst'. If 'dst' is nil or not a pointer, Unmarshal returns an InvalidDestinationTypeError.

func ValueOf

func ValueOf(v any) (string, error)

ValueOf returns the ini-string value of a type, if it has one.

Many Go built-in types have a ini-string value.

A custom type can also have an ini-string value by implementing the Valuer interface.

func Write

func Write(dst io.Writer, src any) error

Write writes the INI encoding of `src` to `dst`.

See also Marshal and ToString

Example (MapStringAny)
var src = map[string]any{
	"cookies":  "2",
	"crackers": "1",
	"dairy": map[string]string{
		"cheese": "20",
		"milk":   "2",
		"yogurt": "12",
	},
	"fruits": map[string]string{
		"apple":  "ONE",
		"Banana": "TWO",
		"CHERRY": "THREE",
	},
}

var buffer bytes.Buffer
var writer io.Writer = &buffer

err := ini.Write(writer, src)
if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

var result string = buffer.String()

fmt.Print(result)
Output:

cookies = 2
crackers = 1
[dairy]
cheese = 20
milk = 2
yogurt = 12
[fruits]
apple = ONE
Banana = TWO
CHERRY = THREE
Example (MapStringString)
var src = map[string]string{
	"apple":  "ONE",
	"Banana": "TWO",
	"CHERRY": "THREE",
}

var buffer bytes.Buffer
var writer io.Writer = &buffer

err := ini.Write(writer, src)
if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

var result string = buffer.String()

fmt.Print(result)
Output:

apple = ONE
Banana = TWO
CHERRY = THREE

func WriteKeyValue

func WriteKeyValue(dst io.Writer, key string, value string) error

See also AppendKeyValue and KeyValueToString

Example
var buffer bytes.Buffer
var writer io.Writer = &buffer

var key string = "Banana"
var value string = "TWO"

err := ini.WriteKeyValue(writer, key, value) // <---------
if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

var result string = buffer.String()

fmt.Print(result)
Output:

Banana = TWO

func WriteSectionHeader

func WriteSectionHeader(dst io.Writer, name ...string) error

See also AppendSectionHeader and SectionHeaderToString

Example
var buffer bytes.Buffer
var writer io.Writer = &buffer

err := ini.WriteSectionHeader(writer, "apple", "Banana", "CHERRY") // <---------

if nil != err {
	fmt.Printf("ERROR: %s\n", err)
	return
}

var result string = buffer.String()

fmt.Print(result)
Output:

[apple.Banana.CHERRY]

func WriteSequenceHeader

func WriteSequenceHeader(dst io.Writer, name ...string) error

See also AppendSequenceHeader and SequenceHeaderToString

Types

type InvalidDestinationTypeError

type InvalidDestinationTypeError struct {
	// contains filtered or unexported fields
}

InvalidDestinationTypeError is returned by Unmarshal if it is given a 'destination' to unmarshal whose type is not supported by Unmarshal.

You can create an InvalidDestinationTypeError using CreateInvalidDestinationTypeError.

InvalidDestinationTypeError has a method named InvalidDestinationTypeError.InvalidType that will return the name of the invalid-type a Go `string`.

Example
var bytes []byte = []byte(
	`[stuff]

apple = once
Banana = twice
CHERRY = thrice
dAtE = fource
`)

var dst float64

err := ini.Unmarshal(bytes, &dst)

if nil != err {
	switch casted := err.(type) {
	case ini.InvalidDestinationTypeError:
		fmt.Printf("ini.Unmarshal() cannot unmarshal into something of type %s\n", casted.InvalidType())
	default:
		fmt.Println("unknown error:", err)
	}
}
Output:

ini.Unmarshal() cannot unmarshal into something of type *float64

func (InvalidDestinationTypeError) Error

func (receiver InvalidDestinationTypeError) Error() string

Error makes InvalidDestinationTypeError fit the built-in Go `error` interface.

func (InvalidDestinationTypeError) InvalidType

func (receiver InvalidDestinationTypeError) InvalidType() string

InvalidType returns the name of the invalid-type as a Go `string`.

type Marshaler

type Marshaler interface {
	MarshalINI([]byte, ...string) ([]byte, error)
}

Marshaler is used by non-simple custom types to return its INI value.

Behind the scenes, Marshaler is used by Marshaler

If you are implmenting your own MarshalINI method for your own custom type, then you are likely going to use one or more of these functions: Append, AppendKeyValue, AppendSectionHeader, AppendSequenceHeader.

Note that if your custom-type is instead a simple custom type, then it should instead implement Valuer instead of Marshaler.

Example
package main

import (
	"fmt"
	"strconv"

	"github.com/reiver/go-ini"
)

type MyCustomType struct {
	color  string
	number uint64
}

func (receiver MyCustomType) MarshalINI(p []byte, nesting ...string) ([]byte, error) {
	if 0 < len(nesting) {
		p = ini.AppendSectionHeader(p, nesting...)
	}

	p = ini.AppendKeyValue(p, "color", receiver.color)
	p = ini.AppendKeyValue(p, "number", strconv.FormatUint(receiver.number, 10))

	return p, nil
}

func main() {

	var value = MyCustomType{
		color:  "red",
		number: 18,
	}

	result, err := ini.ToString(value)
	if nil != err {
		fmt.Printf("ERROR: %s\n", err)
		return
	}

	fmt.Print(result)

}
Output:


color = red
number = 18

type Publisher

type Publisher interface {
	PublishINIComment(string) error
	PublishINIKeyValue(string, string) error
	PublishINISectionHeader(...string) error
	PublishINISequenceHeader(...string) error
}

type Record

type Record struct {
	// contains filtered or unexported fields
}

func EmptyRecord

func EmptyRecord() Record

func NewEmptyRecord

func NewEmptyRecord() *Record

func (*Record) Append

func (receiver *Record) Append(value string, name string)

func (*Record) Chain

func (receiver *Record) Chain(fn func(*Record)) *Record

func (*Record) ChainAppend

func (receiver *Record) ChainAppend(value string, name string) *Record

func (*Record) ChainSet

func (receiver *Record) ChainSet(name string, values ...string) *Record

func (*Record) ChainUnset

func (receiver *Record) ChainUnset(name string) *Record

func (Record) First

func (receiver Record) First(name string) (string, bool)

func (Record) FirstElse

func (receiver Record) FirstElse(name string, alternative string) string

func (Record) GoString

func (receiver Record) GoString() string

func (Record) Has

func (receiver Record) Has(name string) bool

func (Record) IsEmpty

func (receiver Record) IsEmpty() bool

func (Record) Keys

func (receiver Record) Keys() []string

func (Record) Last

func (receiver Record) Last(name string) (string, bool)

func (Record) LastElse

func (receiver Record) LastElse(name string, alternative string) string

func (Record) Len

func (receiver Record) Len() int

func (*Record) Set

func (receiver *Record) Set(name string, values ...string)

func (*Record) ToRecord

func (receiver *Record) ToRecord() Record

ToRecord returns the `ini.Record` version of a `*ini.Record`.

One way this is useful is if you are trying to construct a record. For example:

var record ini.Record = ini.NewEmptyRecord().ChainSet("a","1").ToRecord()

func (*Record) Unset

func (receiver *Record) Unset(name string)

func (Record) Values

func (receiver Record) Values(name string) []string

type Setter

type Setter interface {
	SetININameValue(name string, value string) error
}

type Valuer

type Valuer interface {
	INIValue() (string, error)
}

Valuer is used by custom types to return its INI value that can be represented by as a simple INI value.

Behind the scenes, Valuer is used by ValueOf

For example:

type MyStruct struct {
	// ..
}

func (recevier MyStruct) INIValue() (string, error) {
	// ...
}

For custom types that would be represented by more than just a simple INI value, see Marshaler

Directories

Path Synopsis
internal
eol

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL