File 0012-unvis-switch-to-methods-for-parser.patch of Package go-mtree

From 9bd1dffd9b0dc0671f9559d4ad6c4622a35fbeb7 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <cyphar@cyphar.com>
Date: Mon, 22 Sep 2025 02:07:21 +1000
Subject: [PATCH 12/25] unvis: switch to methods for parser

Passing the parsers as an argument is very C-like and is not really as
idiomadic as just using methods (in my defence, I was still pretty green
when I wrote this code and I was trying to port some logic from C).

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
 pkg/govis/unvis.go | 61 ++++++++++++++++++++++++++--------------------
 1 file changed, 34 insertions(+), 27 deletions(-)

diff --git a/pkg/govis/unvis.go b/pkg/govis/unvis.go
index 5dbf9356fcc7..c6f8cc14dcfb 100644
--- a/pkg/govis/unvis.go
+++ b/pkg/govis/unvis.go
@@ -36,7 +36,13 @@ var (
 type unvisParser struct {
 	tokens []rune
 	idx    int
-	flag   VisFlag
+	flags  VisFlag
+}
+
+// Input resets the parser with a new input string.
+func (p *unvisParser) Input(input string) {
+	p.tokens = []rune(input)
+	p.idx = 0
 }
 
 // Next moves the index to the next character.
@@ -57,11 +63,11 @@ func (p *unvisParser) End() bool {
 	return p.idx >= len(p.tokens)
 }
 
-func newParser(input string, flag VisFlag) *unvisParser {
+func newParser(flags VisFlag) *unvisParser {
 	return &unvisParser{
-		tokens: []rune(input),
+		tokens: nil,
 		idx:    0,
-		flag:   flag,
+		flags:  flags,
 	}
 }
 
@@ -69,8 +75,8 @@ func newParser(input string, flag VisFlag) *unvisParser {
 // codes, this is IMO much easier to read than the ugly 80s coroutine code used
 // by the original unvis(3) parser. Here's the EBNF for an unvis sequence:
 //
-// <input>           ::= (<rune>)*
-// <rune>            ::= ("\" <escape-sequence>) | ("%" <escape-hex>) | <plain-rune>
+// <input>           ::= (<element>)*
+// <element>         ::= ("\" <escape-sequence>) | ("%" <escape-hex>) | <plain-rune>
 // <plain-rune>      ::= any rune
 // <escape-sequence> ::= ("x" <escape-hex>) | ("M" <escape-meta>) | ("^" <escape-ctrl) | <escape-cstyle> | <escape-octal>
 // <escape-meta>     ::= ("-" <escape-meta1>) | ("^" <escape-ctrl>)
@@ -80,7 +86,7 @@ func newParser(input string, flag VisFlag) *unvisParser {
 // <escape-hex>      ::= [0-9a-f] [0-9a-f]
 // <escape-octal>    ::= [0-7] ([0-7] ([0-7])?)?
 
-func unvisPlainRune(p *unvisParser) ([]byte, error) {
+func (p *unvisParser) plainRune() ([]byte, error) {
 	ch, err := p.Peek()
 	if err != nil {
 		return nil, fmt.Errorf("plain rune: %w", err)
@@ -89,7 +95,7 @@ func unvisPlainRune(p *unvisParser) ([]byte, error) {
 	return []byte(string(ch)), nil
 }
 
-func unvisEscapeCStyle(p *unvisParser) ([]byte, error) {
+func (p *unvisParser) escapeCStyle() ([]byte, error) {
 	ch, err := p.Peek()
 	if err != nil {
 		return nil, fmt.Errorf("escape cstyle: %w", err)
@@ -128,7 +134,7 @@ func unvisEscapeCStyle(p *unvisParser) ([]byte, error) {
 	return []byte(output), nil
 }
 
-func unvisEscapeDigits(p *unvisParser, base int, force bool) ([]byte, error) {
+func (p *unvisParser) escapeDigits(base int, force bool) ([]byte, error) {
 	var code int
 
 	for i := int(0xFF); i > 0; i /= base {
@@ -160,7 +166,7 @@ func unvisEscapeDigits(p *unvisParser, base int, force bool) ([]byte, error) {
 	return []byte{char}, nil
 }
 
-func unvisEscapeCtrl(p *unvisParser, mask byte) ([]byte, error) {
+func (p *unvisParser) escapeCtrl(mask byte) ([]byte, error) {
 	ch, err := p.Peek()
 	if err != nil {
 		return nil, fmt.Errorf("escape ctrl: %w", err)
@@ -178,7 +184,7 @@ func unvisEscapeCtrl(p *unvisParser, mask byte) ([]byte, error) {
 	return []byte{mask | char}, nil
 }
 
-func unvisEscapeMeta(p *unvisParser) ([]byte, error) {
+func (p *unvisParser) escapeMeta() ([]byte, error) {
 	ch, err := p.Peek()
 	if err != nil {
 		return nil, fmt.Errorf("escape meta: %w", err)
@@ -190,7 +196,7 @@ func unvisEscapeMeta(p *unvisParser) ([]byte, error) {
 	case '^':
 		// The same as "\^..." except we apply a mask.
 		p.Next()
-		return unvisEscapeCtrl(p, mask)
+		return p.escapeCtrl(mask)
 
 	case '-':
 		p.Next()
@@ -211,7 +217,7 @@ func unvisEscapeMeta(p *unvisParser) ([]byte, error) {
 	return nil, fmt.Errorf("escape meta: %w %q", errUnknownEscapeChar, ch)
 }
 
-func unvisEscapeSequence(p *unvisParser) ([]byte, error) {
+func (p *unvisParser) escapeSequence() ([]byte, error) {
 	ch, err := p.Peek()
 	if err != nil {
 		return nil, fmt.Errorf("escape sequence: %w", err)
@@ -223,26 +229,26 @@ func unvisEscapeSequence(p *unvisParser) ([]byte, error) {
 		return []byte("\\"), nil
 
 	case '0', '1', '2', '3', '4', '5', '6', '7':
-		return unvisEscapeDigits(p, 8, false)
+		return p.escapeDigits(8, false)
 
 	case 'x':
 		p.Next()
-		return unvisEscapeDigits(p, 16, true)
+		return p.escapeDigits(16, true)
 
 	case '^':
 		p.Next()
-		return unvisEscapeCtrl(p, 0x00)
+		return p.escapeCtrl(0x00)
 
 	case 'M':
 		p.Next()
-		return unvisEscapeMeta(p)
+		return p.escapeMeta()
 
 	default:
-		return unvisEscapeCStyle(p)
+		return p.escapeCStyle()
 	}
 }
 
-func unvisRune(p *unvisParser) ([]byte, error) {
+func (p *unvisParser) element() ([]byte, error) {
 	ch, err := p.Peek()
 	if err != nil {
 		return nil, err
@@ -251,22 +257,23 @@ func unvisRune(p *unvisParser) ([]byte, error) {
 	switch ch {
 	case '\\':
 		p.Next()
-		return unvisEscapeSequence(p)
+		return p.escapeSequence()
 
 	case '%':
 		// % HEX HEX only applies to HTTPStyle encodings.
-		if p.flag&VisHTTPStyle == VisHTTPStyle {
+		if p.flags&VisHTTPStyle == VisHTTPStyle {
 			p.Next()
-			return unvisEscapeDigits(p, 16, true)
+			return p.escapeDigits(16, true)
 		}
 	}
-	return unvisPlainRune(p)
+	return p.plainRune()
 }
 
-func unvis(p *unvisParser) (string, error) {
+func (p *unvisParser) unvis(input string) (string, error) {
+	p.Input(input)
 	var output []byte
 	for !p.End() {
-		ch, err := unvisRune(p)
+		ch, err := p.element()
 		if err != nil {
 			return "", err
 		}
@@ -283,8 +290,8 @@ func Unvis(input string, flags VisFlag) (string, error) {
 	if unknown := flags &^ visMask; unknown != 0 {
 		return "", unknownVisFlagsError{flags: flags}
 	}
-	p := newParser(input, flags)
-	output, err := unvis(p)
+	p := newParser(flags)
+	output, err := p.unvis(input)
 	if err != nil {
 		return "", fmt.Errorf("unvis '%s': %w", input, err)
 	}
-- 
2.51.0

openSUSE Build Service is sponsored by