aboutsummaryrefslogtreecommitdiff
path: root/cpe/token.go
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2022-02-04 00:35:31 -0500
committerPaul Duncan <pabs@pablotron.org>2022-02-04 00:35:31 -0500
commit9c17b97cd0f83be3fff9fa4e87fd1d29052ea616 (patch)
tree0d97030a0d0c3ad983be281ce89f80571338887f /cpe/token.go
parent92400d731546557d110c9c3cc3906d700f83dda8 (diff)
downloadcvez-9c17b97cd0f83be3fff9fa4e87fd1d29052ea616.tar.bz2
cvez-9c17b97cd0f83be3fff9fa4e87fd1d29052ea616.zip
rename to github.com/pablotron/cvez, remove internal libs
Diffstat (limited to 'cpe/token.go')
-rw-r--r--cpe/token.go99
1 files changed, 99 insertions, 0 deletions
diff --git a/cpe/token.go b/cpe/token.go
new file mode 100644
index 0000000..d88e773
--- /dev/null
+++ b/cpe/token.go
@@ -0,0 +1,99 @@
+package cpe
+
+//go:generate stringer -linecomment -type=tokenType
+
+import (
+ "errors"
+ "fmt"
+)
+
+// token type
+type tokenType byte
+
+const (
+ anyToken tokenType = iota // any
+ naToken // na
+ valToken // val
+)
+
+// token
+type token struct {
+ Type tokenType // token type
+ Val string // token value
+}
+
+// parse buffer into token.
+func newToken(val []byte) token {
+ if len(val) > 0 {
+ switch val[0] {
+ case '*':
+ return token { Type: anyToken }
+ case '-':
+ return token { Type: naToken }
+ default:
+ return token { Type: valToken, Val: string(val) }
+ }
+ } else {
+ // empty value
+ return token { Type: valToken }
+ }
+}
+
+// unterminated escape error
+var unterminatedEsc = errors.New("unterminated escape at end of buffer")
+
+// Parse buffer into list of tokens.
+func tokenize(buf []byte) ([]token, error) {
+ // build result
+ var r []token
+
+ // current token and escape state
+ var curr []byte
+ esc := false
+
+ // build result
+ for _, b := range(buf) {
+ if esc {
+ switch b {
+ // valid escaped characters
+ case '\\', '*', '-', '!', '"', '#', '$', '%', '&', '\'', '(', ')',
+ '+', ',', '/', ':', ';', '<', '=', '>', '@', '[', ']', '^', '`',
+ '{', '|', '}', '~':
+ curr = append(curr, b)
+ esc = false
+ default:
+ return r, fmt.Errorf("invalid escape byte: 0x%02x", b)
+ }
+ } else {
+ switch b {
+ case '\\':
+ esc = true
+ case ':':
+ // push token, clear buffer
+ r = append(r, newToken(curr))
+ curr = nil
+ case 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+ 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '-', '.', '_', '*', '?':
+ curr = append(curr, b)
+ default:
+ return r, fmt.Errorf("invalid byte: 0x%02x", b)
+ }
+ }
+ }
+
+ // check for unterminated escape
+ if esc {
+ return r, unterminatedEsc
+ }
+
+ if len(curr) > 0 {
+ // push token, clear buffer
+ r = append(r, newToken(curr))
+ curr = nil
+ }
+
+ // return success
+ return r, nil
+}