package snap import ( "strings" "log" "os" "strconv" ) var die = log.New(os.Stderr, "", 0) func isEscaped(str string) bool { n := len(str) return n > 1 && str[0] == '"' && str[n - 1] == '"'; } func parseEscaped(snapish string) *Relative { if isEscaped(snapish) { snapshot := strings.Trim(snapish, `"`); if(snapshot == "") { die.Fatal("Snapshot cannot be empty \"\"") } return &Relative { snapshot: snapshot, } } return nil } func parseRelativeSyntax(snapish, directionToken string) *Relative { parts := strings.Split(snapish, directionToken) n_parts := len(parts) if n_parts == 1 { return nil; } // Test if the last the last token is a numeric offset if offset, err := strconv.Atoi(parts[n_parts - 1]); err == nil { // Two tokens (e.g. ++ or --) indicates increment syntax if n_parts > 2 && parts[n_parts - 2] == "" { die.Fatal("A snapshot reference cannot be a mix of increment syntax (e.g. my_snap++) and literal syntax (e.g. my_snap+4).") } snapshot := strings.TrimRight(snapish, directionToken + "0123456789") return &Relative { offset: offset, snapshot: snapshot, } } // Parse the increment / decrement syntax // E.g. snapshot+++ or snapshot--- offset := 0; for i := n_parts - 1; i >= 1 && parts[i] == ""; i-- { offset += 1 } return &Relative { offset: offset, snapshot: snapish[:len(snapish) - offset], } } func ToRelative(snapish string) * Relative { if ref := parseEscaped(snapish); ref != nil { return ref; } if ref := parseRelativeSyntax(snapish, "+"); ref != nil { return ref; } if ref := parseRelativeSyntax(snapish, "-"); ref != nil { ref.offset = -ref.offset; return ref; } return &Relative{ snapshot: snapish, }; }