mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-03 19:17:29 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			123 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package parse
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"io"
 | 
						|
	"unicode"
 | 
						|
)
 | 
						|
 | 
						|
type (
 | 
						|
	// lexer is a utility which can get values, token by
 | 
						|
	// token, from a Reader. A token is a word, and tokens
 | 
						|
	// are separated by whitespace. A word can be enclosed
 | 
						|
	// in quotes if it contains whitespace.
 | 
						|
	lexer struct {
 | 
						|
		reader *bufio.Reader
 | 
						|
		token  token
 | 
						|
		line   int
 | 
						|
	}
 | 
						|
 | 
						|
	// token represents a single parsable unit.
 | 
						|
	token struct {
 | 
						|
		file string
 | 
						|
		line int
 | 
						|
		text string
 | 
						|
	}
 | 
						|
)
 | 
						|
 | 
						|
// load prepares the lexer to scan an input for tokens.
 | 
						|
func (l *lexer) load(input io.Reader) error {
 | 
						|
	l.reader = bufio.NewReader(input)
 | 
						|
	l.line = 1
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// next loads the next token into the lexer.
 | 
						|
// A token is delimited by whitespace, unless
 | 
						|
// the token starts with a quotes character (")
 | 
						|
// in which case the token goes until the closing
 | 
						|
// quotes (the enclosing quotes are not included).
 | 
						|
// Inside quoted strings, quotes may be escaped
 | 
						|
// with a preceding \ character. No other chars
 | 
						|
// may be escaped. The rest of the line is skipped
 | 
						|
// if a "#" character is read in. Returns true if
 | 
						|
// a token was loaded; false otherwise.
 | 
						|
func (l *lexer) next() bool {
 | 
						|
	var val []rune
 | 
						|
	var comment, quoted, escaped bool
 | 
						|
 | 
						|
	makeToken := func() bool {
 | 
						|
		l.token.text = string(val)
 | 
						|
		return true
 | 
						|
	}
 | 
						|
 | 
						|
	for {
 | 
						|
		ch, _, err := l.reader.ReadRune()
 | 
						|
		if err != nil {
 | 
						|
			if len(val) > 0 {
 | 
						|
				return makeToken()
 | 
						|
			}
 | 
						|
			if err == io.EOF {
 | 
						|
				return false
 | 
						|
			}
 | 
						|
			panic(err)
 | 
						|
		}
 | 
						|
 | 
						|
		if quoted {
 | 
						|
			if !escaped {
 | 
						|
				if ch == '\\' {
 | 
						|
					escaped = true
 | 
						|
					continue
 | 
						|
				} else if ch == '"' {
 | 
						|
					quoted = false
 | 
						|
					return makeToken()
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if ch == '\n' {
 | 
						|
				l.line++
 | 
						|
			}
 | 
						|
			if escaped {
 | 
						|
				// only escape quotes
 | 
						|
				if ch != '"' {
 | 
						|
					val = append(val, '\\')
 | 
						|
				}
 | 
						|
			}
 | 
						|
			val = append(val, ch)
 | 
						|
			escaped = false
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if unicode.IsSpace(ch) {
 | 
						|
			if ch == '\r' {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			if ch == '\n' {
 | 
						|
				l.line++
 | 
						|
				comment = false
 | 
						|
			}
 | 
						|
			if len(val) > 0 {
 | 
						|
				return makeToken()
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if ch == '#' {
 | 
						|
			comment = true
 | 
						|
		}
 | 
						|
 | 
						|
		if comment {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if len(val) == 0 {
 | 
						|
			l.token = token{line: l.line}
 | 
						|
			if ch == '"' {
 | 
						|
				quoted = true
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		val = append(val, ch)
 | 
						|
	}
 | 
						|
}
 |