Files
Matheus Sampaio Queiroga fb6024ec5d big update and move dpkg module
Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
2025-03-13 14:40:14 -03:00

160 lines
4.3 KiB
Go

package deb822
import (
"fmt"
"io"
"slices"
"strconv"
"strings"
"sirherobrine23.com.br/sirherobrine23/go-dpkg/internal/scanner"
)
type Source interface {
IsMultiline() bool
IsBool() bool
IsInt() bool
Len() int
Line(int) string
String() string
ToSlice() []string
ToBool() bool
ToInt() int
}
var (
_ Source = SingleLine("")
_ Source = NumberLine(0)
_ Source = Multiline{}
)
type SingleLine string
func (SingleLine) IsInt() bool { return false }
func (SingleLine) ToInt() int { return 0 }
func (s SingleLine) IsMultiline() bool { return false }
func (s SingleLine) IsBool() bool { return slices.Contains([]string{"yes", "no"}, string(s)) }
func (s SingleLine) ToBool() bool { return s.IsBool() && s.String() == "yes" }
func (s SingleLine) String() string { return string(s) }
func (s SingleLine) Line(int) string { return string(s) }
func (s SingleLine) Len() int { return len(s) }
func (s SingleLine) ToSlice() []string {
if s == "" {
return nil
}
return []string{string(s)}
}
type NumberLine int
func (s NumberLine) IsMultiline() bool { return false }
func (s NumberLine) IsBool() bool { return false }
func (s NumberLine) IsInt() bool { return true }
func (s NumberLine) String() string { return strconv.Itoa(int(s)) }
func (s NumberLine) Line(int) string { return s.String() }
func (s NumberLine) Len() int { return len(s.String()) }
func (s NumberLine) ToSlice() []string { return []string{s.String()} }
func (s NumberLine) ToInt() int { return int(s) }
func (s NumberLine) ToBool() bool { return s == 1 }
type Multiline []string
func (m Multiline) IsMultiline() bool { return len(m) > 1 }
func (m Multiline) IsBool() bool { return slices.Contains([]string{"yes", "no"}, m.String()) }
func (m Multiline) ToBool() bool { return m.IsBool() && m.String() == "yes" }
func (m Multiline) String() string { return strings.Join(m, "\n") }
func (m Multiline) Len() int { return len(m) }
func (m Multiline) ToSlice() []string { return m }
func (Multiline) IsInt() bool { return true }
func (Multiline) ToInt() int { return 0 }
func (m Multiline) Line(i int) string {
if i < 0 || i >= len(m) {
return ""
}
return m[i]
}
// Debian control file
type Deb822 map[string]Source
// Parse control file
func Parse(body []byte) (Deb822, error) {
deb822Map := Deb822{}
if err := deb822Map.UnmarshalBinary(body); err != nil {
return nil, err
}
return deb822Map, nil
}
// Get key, if not exists return SingleLine
func (deb822Map Deb822) Get(key string) Source {
if value, ok := deb822Map[key]; ok {
return value
}
return SingleLine("")
}
// Unmarshall Debian822
func (deb822Map *Deb822) UnmarshalBinary(body []byte) error {
if err := newParse(deb822Map, strings.NewReader(strings.TrimSpace(string(body)))); err != nil {
return err
}
return nil
}
// Parse Debian822 with stream file
func NewParse(r io.Reader) (Deb822, error) {
deb822Map := Deb822{}
if err := newParse(&deb822Map, r); err != nil {
return nil, err
}
return deb822Map, nil
}
// parse Debian822 file
func newParse(deb822Map *Deb822, r io.Reader) error {
multilineKey, scann := "", scanner.NewScanner(r)
for scann.Scan() {
line := scann.Text()
if line == "" {
break // New deb822 ignore
} else if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "-") {
continue // Ignore line
} else if line[0] == ' ' || line[0] == '\t' {
if multilineKey == "" {
return fmt.Errorf("invalid control file, line: %s", line)
} else if line = strings.TrimLeft(line, " \t"); line == "." {
line = "" // Replace . with empty line
}
(*deb822Map)[multilineKey] = append(Multiline((*deb822Map)[multilineKey].ToSlice()), line)
continue
}
keys := strings.SplitN(line, ":", 2)
if len(keys) != 2 {
return fmt.Errorf("invalid line: %s", line)
}
multilineKey, line = keys[0], keys[1]
if line == "" {
(*deb822Map)[multilineKey] = Multiline{}
continue
} else if line[0] == ' ' || line[0] == '\t' {
line = line[1:]
}
if _, ok := (*deb822Map)[multilineKey]; !ok {
(*deb822Map)[multilineKey] = SingleLine(line)
if nu, err := strconv.Atoi(line); err == nil {
(*deb822Map)[multilineKey] = NumberLine(nu)
}
continue
}
(*deb822Map)[multilineKey] = append(Multiline((*deb822Map)[multilineKey].ToSlice()), line)
}
return scann.Err()
}