package main import ( "bytes" "errors" "fmt" "io" "strings" "unicode" ) type Submodule struct { Name string Path string } var SyntaxError error = errors.New("Syntax error") func (sub *Submodule) parseSubmoduleName(line string) error { line = strings.TrimSpace(line) if line[0:10] != "submodule " { return SyntaxError } r := strings.NewReader(line[10:]) ch, _, err := r.ReadRune() for ; ; ch, _, err = r.ReadRune() { if err != nil { return fmt.Errorf("%c %d", ch, 32) } if !unicode.IsSpace(ch) { break } } if ch != '"' { return fmt.Errorf("%c %d", ch, 36) // return SyntaxError } var b strings.Builder for ch, _, err = r.ReadRune(); ch != '"'; ch, _, err = r.ReadRune() { if err != nil { return fmt.Errorf("%c %d", ch, 32) } b.WriteRune(ch) } if ch != '"' { return fmt.Errorf("%c %d", ch, 45) // return SyntaxError } ch, _, err = r.ReadRune() if ch != ']' || err != nil { return fmt.Errorf("%c %d, %w", ch, 50, err) // return SyntaxError } sub.Name = b.String() for ch, _, err = r.ReadRune(); ; ch, _, _ = r.ReadRune() { if err == io.EOF { return nil } if !unicode.IsSpace(ch) { return SyntaxError } } } func (s *Submodule) parseKeyValue(line string) error { eqLoc := strings.Index(line, "=") if eqLoc < 0 || eqLoc == len(line)-1 { return SyntaxError } key := strings.ToLower(strings.TrimSpace(line[0:eqLoc])) val := strings.TrimSpace(line[eqLoc+1:]) if len(val) == 0 { return SyntaxError } switch key { case "path": s.Path = val } return nil } func ParseSubmodulesFile(reader io.Reader) ([]Submodule, error) { data, err := io.ReadAll(reader) if err != nil { return nil, err } var sub *Submodule ret := []Submodule{} lines := bytes.Split(data, []byte("\n")) for _, l := range lines { line := string(bytes.TrimSpace(l)) if len(line) == 0 { continue } if line[0] == '[' { if sub != nil { ret = append(ret, *sub) } sub = &Submodule{} if err := sub.parseSubmoduleName(line[1:]); err != nil { return nil, err } } else if sub == nil { return nil, SyntaxError } else { if err := sub.parseKeyValue(line); err != nil { return nil, err } } } if sub != nil { ret = append(ret, *sub) } return ret, nil }