aboutsummaryrefslogtreecommitdiff
path: root/internal/scfg/reader.go
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-04-06 09:26:46 +0800
committerRunxi Yu <me@runxiyu.org>2025-04-06 09:27:53 +0800
commitda1d8f4e7c332c7109427915e6459b10209cedce (patch)
tree280b921be3b51f93d82d916b4eaa89387b7102cc /internal/scfg/reader.go
parentgit2c, git2d: Rename cmd1 and cmd2 descriptively (diff)
downloadforge-da1d8f4e7c332c7109427915e6459b10209cedce.tar.gz
forge-da1d8f4e7c332c7109427915e6459b10209cedce.tar.zst
forge-da1d8f4e7c332c7109427915e6459b10209cedce.zip
Move the Go stuff to ./forged/v0.1.32
Diffstat (limited to 'internal/scfg/reader.go')
-rw-r--r--internal/scfg/reader.go157
1 files changed, 0 insertions, 157 deletions
diff --git a/internal/scfg/reader.go b/internal/scfg/reader.go
deleted file mode 100644
index 6a2bedc..0000000
--- a/internal/scfg/reader.go
+++ /dev/null
@@ -1,157 +0,0 @@
-// SPDX-License-Identifier: MIT
-// SPDX-FileCopyrightText: Copyright (c) 2020 Simon Ser <https://emersion.fr>
-
-package scfg
-
-import (
- "bufio"
- "fmt"
- "io"
- "os"
- "strings"
-)
-
-// This limits the max block nesting depth to prevent stack overflows.
-const maxNestingDepth = 1000
-
-// Load loads a configuration file.
-func Load(path string) (Block, error) {
- f, err := os.Open(path)
- if err != nil {
- return nil, err
- }
- defer f.Close()
-
- return Read(f)
-}
-
-// Read parses a configuration file from an io.Reader.
-func Read(r io.Reader) (Block, error) {
- scanner := bufio.NewScanner(r)
-
- dec := decoder{scanner: scanner}
- block, closingBrace, err := dec.readBlock()
- if err != nil {
- return nil, err
- } else if closingBrace {
- return nil, fmt.Errorf("line %v: unexpected '}'", dec.lineno)
- }
-
- return block, scanner.Err()
-}
-
-type decoder struct {
- scanner *bufio.Scanner
- lineno int
- blockDepth int
-}
-
-// readBlock reads a block. closingBrace is true if parsing stopped on '}'
-// (otherwise, it stopped on Scanner.Scan).
-func (dec *decoder) readBlock() (block Block, closingBrace bool, err error) {
- dec.blockDepth++
- defer func() {
- dec.blockDepth--
- }()
-
- if dec.blockDepth >= maxNestingDepth {
- return nil, false, fmt.Errorf("exceeded max block depth")
- }
-
- for dec.scanner.Scan() {
- dec.lineno++
-
- l := dec.scanner.Text()
- words, err := splitWords(l)
- if err != nil {
- return nil, false, fmt.Errorf("line %v: %v", dec.lineno, err)
- } else if len(words) == 0 {
- continue
- }
-
- if len(words) == 1 && l[len(l)-1] == '}' {
- closingBrace = true
- break
- }
-
- var d *Directive
- if words[len(words)-1] == "{" && l[len(l)-1] == '{' {
- words = words[:len(words)-1]
-
- var name string
- params := words
- if len(words) > 0 {
- name, params = words[0], words[1:]
- }
-
- startLineno := dec.lineno
- childBlock, childClosingBrace, err := dec.readBlock()
- if err != nil {
- return nil, false, err
- } else if !childClosingBrace {
- return nil, false, fmt.Errorf("line %v: unterminated block", startLineno)
- }
-
- // Allows callers to tell apart "no block" and "empty block"
- if childBlock == nil {
- childBlock = Block{}
- }
-
- d = &Directive{Name: name, Params: params, Children: childBlock, lineno: dec.lineno}
- } else {
- d = &Directive{Name: words[0], Params: words[1:], lineno: dec.lineno}
- }
- block = append(block, d)
- }
-
- return block, closingBrace, nil
-}
-
-func splitWords(l string) ([]string, error) {
- var (
- words []string
- sb strings.Builder
- escape bool
- quote rune
- wantWSP bool
- )
- for _, ch := range l {
- switch {
- case escape:
- sb.WriteRune(ch)
- escape = false
- case wantWSP && (ch != ' ' && ch != '\t'):
- return words, fmt.Errorf("atom not allowed after quoted string")
- case ch == '\\':
- escape = true
- case quote != 0 && ch == quote:
- quote = 0
- wantWSP = true
- if sb.Len() == 0 {
- words = append(words, "")
- }
- case quote == 0 && len(words) == 0 && sb.Len() == 0 && ch == '#':
- return nil, nil
- case quote == 0 && (ch == '\'' || ch == '"'):
- if sb.Len() > 0 {
- return words, fmt.Errorf("quoted string not allowed after atom")
- }
- quote = ch
- case quote == 0 && (ch == ' ' || ch == '\t'):
- if sb.Len() > 0 {
- words = append(words, sb.String())
- }
- sb.Reset()
- wantWSP = false
- default:
- sb.WriteRune(ch)
- }
- }
- if quote != 0 {
- return words, fmt.Errorf("unterminated quoted string")
- }
- if sb.Len() > 0 {
- words = append(words, sb.String())
- }
- return words, nil
-}