mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 00:11:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			240 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			240 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
package ssh_config
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
)
 | 
						|
 | 
						|
// Define state functions
 | 
						|
type sshLexStateFn func() sshLexStateFn
 | 
						|
 | 
						|
type sshLexer struct {
 | 
						|
	inputIdx int
 | 
						|
	input    []rune // Textual source
 | 
						|
 | 
						|
	buffer        []rune // Runes composing the current token
 | 
						|
	tokens        chan token
 | 
						|
	line          int
 | 
						|
	col           int
 | 
						|
	endbufferLine int
 | 
						|
	endbufferCol  int
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) lexComment(previousState sshLexStateFn) sshLexStateFn {
 | 
						|
	return func() sshLexStateFn {
 | 
						|
		growingString := ""
 | 
						|
		for next := s.peek(); next != '\n' && next != eof; next = s.peek() {
 | 
						|
			if next == '\r' && s.follow("\r\n") {
 | 
						|
				break
 | 
						|
			}
 | 
						|
			growingString += string(next)
 | 
						|
			s.next()
 | 
						|
		}
 | 
						|
		s.emitWithValue(tokenComment, growingString)
 | 
						|
		s.skip()
 | 
						|
		return previousState
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// lex the space after an equals sign in a function
 | 
						|
func (s *sshLexer) lexRspace() sshLexStateFn {
 | 
						|
	for {
 | 
						|
		next := s.peek()
 | 
						|
		if !isSpace(next) {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		s.skip()
 | 
						|
	}
 | 
						|
	return s.lexRvalue
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) lexEquals() sshLexStateFn {
 | 
						|
	for {
 | 
						|
		next := s.peek()
 | 
						|
		if next == '=' {
 | 
						|
			s.emit(tokenEquals)
 | 
						|
			s.skip()
 | 
						|
			return s.lexRspace
 | 
						|
		}
 | 
						|
		// TODO error handling here; newline eof etc.
 | 
						|
		if !isSpace(next) {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		s.skip()
 | 
						|
	}
 | 
						|
	return s.lexRvalue
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) lexKey() sshLexStateFn {
 | 
						|
	growingString := ""
 | 
						|
 | 
						|
	for r := s.peek(); isKeyChar(r); r = s.peek() {
 | 
						|
		// simplified a lot here
 | 
						|
		if isSpace(r) || r == '=' {
 | 
						|
			s.emitWithValue(tokenKey, growingString)
 | 
						|
			s.skip()
 | 
						|
			return s.lexEquals
 | 
						|
		}
 | 
						|
		growingString += string(r)
 | 
						|
		s.next()
 | 
						|
	}
 | 
						|
	s.emitWithValue(tokenKey, growingString)
 | 
						|
	return s.lexEquals
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) lexRvalue() sshLexStateFn {
 | 
						|
	growingString := ""
 | 
						|
	for {
 | 
						|
		next := s.peek()
 | 
						|
		switch next {
 | 
						|
		case '\r':
 | 
						|
			if s.follow("\r\n") {
 | 
						|
				s.emitWithValue(tokenString, growingString)
 | 
						|
				s.skip()
 | 
						|
				return s.lexVoid
 | 
						|
			}
 | 
						|
		case '\n':
 | 
						|
			s.emitWithValue(tokenString, growingString)
 | 
						|
			s.skip()
 | 
						|
			return s.lexVoid
 | 
						|
		case '#':
 | 
						|
			s.emitWithValue(tokenString, growingString)
 | 
						|
			s.skip()
 | 
						|
			return s.lexComment(s.lexVoid)
 | 
						|
		case eof:
 | 
						|
			s.next()
 | 
						|
		}
 | 
						|
		if next == eof {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		growingString += string(next)
 | 
						|
		s.next()
 | 
						|
	}
 | 
						|
	s.emit(tokenEOF)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) read() rune {
 | 
						|
	r := s.peek()
 | 
						|
	if r == '\n' {
 | 
						|
		s.endbufferLine++
 | 
						|
		s.endbufferCol = 1
 | 
						|
	} else {
 | 
						|
		s.endbufferCol++
 | 
						|
	}
 | 
						|
	s.inputIdx++
 | 
						|
	return r
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) next() rune {
 | 
						|
	r := s.read()
 | 
						|
 | 
						|
	if r != eof {
 | 
						|
		s.buffer = append(s.buffer, r)
 | 
						|
	}
 | 
						|
	return r
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) lexVoid() sshLexStateFn {
 | 
						|
	for {
 | 
						|
		next := s.peek()
 | 
						|
		switch next {
 | 
						|
		case '#':
 | 
						|
			s.skip()
 | 
						|
			return s.lexComment(s.lexVoid)
 | 
						|
		case '\r':
 | 
						|
			fallthrough
 | 
						|
		case '\n':
 | 
						|
			s.emit(tokenEmptyLine)
 | 
						|
			s.skip()
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if isSpace(next) {
 | 
						|
			s.skip()
 | 
						|
		}
 | 
						|
 | 
						|
		if isKeyStartChar(next) {
 | 
						|
			return s.lexKey
 | 
						|
		}
 | 
						|
 | 
						|
		// removed IsKeyStartChar and lexKey. probably will need to readd
 | 
						|
 | 
						|
		if next == eof {
 | 
						|
			s.next()
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	s.emit(tokenEOF)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) ignore() {
 | 
						|
	s.buffer = make([]rune, 0)
 | 
						|
	s.line = s.endbufferLine
 | 
						|
	s.col = s.endbufferCol
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) skip() {
 | 
						|
	s.next()
 | 
						|
	s.ignore()
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) emit(t tokenType) {
 | 
						|
	s.emitWithValue(t, string(s.buffer))
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) emitWithValue(t tokenType, value string) {
 | 
						|
	tok := token{
 | 
						|
		Position: Position{s.line, s.col},
 | 
						|
		typ:      t,
 | 
						|
		val:      value,
 | 
						|
	}
 | 
						|
	s.tokens <- tok
 | 
						|
	s.ignore()
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) peek() rune {
 | 
						|
	if s.inputIdx >= len(s.input) {
 | 
						|
		return eof
 | 
						|
	}
 | 
						|
 | 
						|
	r := s.input[s.inputIdx]
 | 
						|
	return r
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) follow(next string) bool {
 | 
						|
	inputIdx := s.inputIdx
 | 
						|
	for _, expectedRune := range next {
 | 
						|
		if inputIdx >= len(s.input) {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
		r := s.input[inputIdx]
 | 
						|
		inputIdx++
 | 
						|
		if expectedRune != r {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
func (s *sshLexer) run() {
 | 
						|
	for state := s.lexVoid; state != nil; {
 | 
						|
		state = state()
 | 
						|
	}
 | 
						|
	close(s.tokens)
 | 
						|
}
 | 
						|
 | 
						|
func lexSSH(input []byte) chan token {
 | 
						|
	runes := bytes.Runes(input)
 | 
						|
	l := &sshLexer{
 | 
						|
		input:         runes,
 | 
						|
		tokens:        make(chan token),
 | 
						|
		line:          1,
 | 
						|
		col:           1,
 | 
						|
		endbufferLine: 1,
 | 
						|
		endbufferCol:  1,
 | 
						|
	}
 | 
						|
	go l.run()
 | 
						|
	return l.tokens
 | 
						|
}
 |