github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/encoding/ini/ini.go (about)

     1  // Copyright 2012 <chaishushan{AT}gmail.com>. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package ini implements a simple INI file parser.
     6  package ini
     7  
     8  import (
     9  	"bufio"
    10  	"bytes"
    11  	"errors"
    12  	"fmt"
    13  	"os"
    14  	"regexp"
    15  	"strings"
    16  	"unicode"
    17  )
    18  
    19  var (
    20  	regDoubleQuote = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*\"([^\"]*)\"$")
    21  	regSingleQuote = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*'([^']*)'$")
    22  	regNoQuote     = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*([^#;]+)")
    23  	regNoValue     = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*([#;].*)?")
    24  )
    25  
    26  func LoadFile(filename string) (dict Dict, err error) {
    27  	file, err := os.Open(filename)
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  	defer file.Close()
    32  
    33  	reader := bufio.NewReader(file)
    34  	return load(reader, filename)
    35  }
    36  func LoadString(str string) (dict Dict, err error) {
    37  	reader := bufio.NewReader(bytes.NewReader([]byte(str)))
    38  	return load(reader, "[string]")
    39  }
    40  
    41  func load(reader *bufio.Reader, filename string) (dict Dict, err error) {
    42  
    43  	dict = newDict()
    44  	lineno := 0
    45  	section := ""
    46  
    47  	for err == nil {
    48  		l, _, err := reader.ReadLine()
    49  		if err != nil {
    50  			break
    51  		}
    52  		lineno++
    53  		if len(l) == 0 {
    54  			continue
    55  		}
    56  		line := strings.TrimFunc(string(l), unicode.IsSpace)
    57  
    58  		for line[len(line)-1] == '\\' {
    59  			line = line[:len(line)-1]
    60  			l, _, err := reader.ReadLine()
    61  			if err != nil {
    62  				return nil, err
    63  			}
    64  			line += strings.TrimFunc(string(l), unicode.IsSpace)
    65  		}
    66  
    67  		section, err = parseLine(&dict, section, line)
    68  		if err != nil {
    69  			return nil, errors.New(
    70  				fmt.Sprintf("%v: '%s:%d'.", err, filename, lineno),
    71  			)
    72  		}
    73  	}
    74  
    75  	return
    76  }
    77  
    78  func parseLine(dict *Dict, section, line string) (string, error) {
    79  	// commets
    80  	if line[0] == '#' || line[0] == ';' {
    81  		return section, nil
    82  	}
    83  
    84  	// section name
    85  	if line[0] == '[' && line[len(line)-1] == ']' {
    86  		section = strings.TrimFunc(line[1:len(line)-1], unicode.IsSpace)
    87  		dict.setSection(section)
    88  		return section, nil
    89  	}
    90  
    91  	// key = value
    92  	if section != "" {
    93  		if m := regDoubleQuote.FindAllStringSubmatch(line, 1); m != nil {
    94  			dict.setString(section, m[0][1], m[0][2])
    95  			return section, nil
    96  		} else if m = regSingleQuote.FindAllStringSubmatch(line, 1); m != nil {
    97  			dict.setString(section, m[0][1], m[0][2])
    98  			return section, nil
    99  		} else if m = regNoQuote.FindAllStringSubmatch(line, 1); m != nil {
   100  			dict.setString(section, m[0][1], strings.TrimFunc(m[0][2], unicode.IsSpace))
   101  			return section, nil
   102  		} else if m = regNoValue.FindAllStringSubmatch(line, 1); m != nil {
   103  			dict.setString(section, m[0][1], "")
   104  			return section, nil
   105  		}
   106  	}
   107  
   108  	return section, errors.New("syntax error")
   109  }