Changeset 200 in code for trunk/config/config.go


Ignore:
Timestamp:
Apr 1, 2020, 12:58:14 PM (5 years ago)
Author:
contact
Message:

config: use shlex

This simplifies parsing and allows quoting words.

Closes: https://todo.sr.ht/~emersion/soju/43

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/config/config.go

    r178 r200  
    66        "io"
    77        "os"
    8         "strings"
    9         "unicode"
     8
     9        "github.com/google/shlex"
    1010)
    1111
     
    4747
    4848func Parse(r io.Reader) (*Server, error) {
    49         p := parser{br: bufio.NewReader(r)}
    50         directives, err := p.file()
    51         if err != nil {
    52                 return nil, fmt.Errorf("failed to parse config file: %v", err)
     49        scanner := bufio.NewScanner(r)
     50
     51        var directives []directive
     52        for scanner.Scan() {
     53                words, err := shlex.Split(scanner.Text())
     54                if err != nil {
     55                        return nil, fmt.Errorf("failed to parse config file: %v", err)
     56                } else if len(words) == 0 {
     57                        continue
     58                }
     59
     60                name, params := words[0], words[1:]
     61                directives = append(directives, directive{name, params})
     62        }
     63        if err := scanner.Err(); err != nil {
     64                return nil, fmt.Errorf("failed to read config file: %v", err)
    5365        }
    5466
     
    100112        return nil
    101113}
    102 
    103 type parser struct {
    104         br *bufio.Reader
    105 }
    106 
    107 func (p *parser) skipSpace() error {
    108         for {
    109                 r, _, err := p.br.ReadRune()
    110                 if err == io.EOF {
    111                         break
    112                 } else if err != nil {
    113                         return err
    114                 }
    115                 if !unicode.IsSpace(r) || r == '\n' {
    116                         p.br.UnreadRune()
    117                         break
    118                 }
    119         }
    120         return nil
    121 }
    122 
    123 func (p *parser) atom() (string, error) {
    124         var sb strings.Builder
    125         for {
    126                 r, _, err := p.br.ReadRune()
    127                 if err == io.EOF && sb.Len() > 0 {
    128                         break
    129                 } else if err != nil {
    130                         return "", err
    131                 }
    132                 if unicode.IsSpace(r) {
    133                         p.br.UnreadRune()
    134                         if err := p.skipSpace(); err != nil {
    135                                 return "", err
    136                         }
    137                         break
    138                 }
    139                 sb.WriteRune(r)
    140         }
    141         return sb.String(), nil
    142 }
    143 
    144 func (p *parser) directive() (*directive, error) {
    145         name, err := p.atom()
    146         if err == io.EOF {
    147                 return nil, io.EOF
    148         } else if err != nil {
    149                 return nil, fmt.Errorf("failed to read directive name: %v", err)
    150         }
    151 
    152         var params []string
    153         for {
    154                 r, _, err := p.br.ReadRune()
    155                 if err == io.EOF {
    156                         break
    157                 } else if err != nil {
    158                         return nil, err
    159                 }
    160                 if r == '\n' {
    161                         break
    162                 }
    163                 p.br.UnreadRune()
    164 
    165                 param, err := p.atom()
    166                 if err == io.EOF {
    167                         break
    168                 } else if err != nil {
    169                         return nil, fmt.Errorf("failed to read directive param: %v", err)
    170                 }
    171                 params = append(params, param)
    172         }
    173 
    174         return &directive{name, params}, nil
    175 }
    176 
    177 func (p *parser) file() ([]directive, error) {
    178         var l []directive
    179         for {
    180                 d, err := p.directive()
    181                 if err == io.EOF {
    182                         break
    183                 } else if err != nil {
    184                         return nil, err
    185                 }
    186                 l = append(l, *d)
    187         }
    188         return l, nil
    189 }
Note: See TracChangeset for help on using the changeset viewer.