+++ /dev/null
-// Package printf implements a parser for fmt.Printf-style format
-// strings.
-//
-// It parses verbs according to the following syntax:
-// Numeric -> '0'-'9'
-// Letter -> 'a'-'z' | 'A'-'Z'
-// Index -> '[' Numeric+ ']'
-// Star -> '*'
-// Star -> Index '*'
-//
-// Precision -> Numeric+ | Star
-// Width -> Numeric+ | Star
-//
-// WidthAndPrecision -> Width '.' Precision
-// WidthAndPrecision -> Width '.'
-// WidthAndPrecision -> Width
-// WidthAndPrecision -> '.' Precision
-// WidthAndPrecision -> '.'
-//
-// Flag -> '+' | '-' | '#' | ' ' | '0'
-// Verb -> Letter | '%'
-//
-// Input -> '%' [ Flag+ ] [ WidthAndPrecision ] [ Index ] Verb
-package printf
-
-import (
- "errors"
- "regexp"
- "strconv"
- "strings"
-)
-
-// ErrInvalid is returned for invalid format strings or verbs.
-var ErrInvalid = errors.New("invalid format string")
-
-type Verb struct {
- Letter rune
- Flags string
-
- Width Argument
- Precision Argument
- // Which value in the argument list the verb uses.
- // -1 denotes the next argument,
- // values > 0 denote explicit arguments.
- // The value 0 denotes that no argument is consumed. This is the case for %%.
- Value int
-
- Raw string
-}
-
-// Argument is an implicit or explicit width or precision.
-type Argument interface {
- isArgument()
-}
-
-// The Default value, when no width or precision is provided.
-type Default struct{}
-
-// Zero is the implicit zero value.
-// This value may only appear for precisions in format strings like %6.f
-type Zero struct{}
-
-// Star is a * value, which may either refer to the next argument (Index == -1) or an explicit argument.
-type Star struct{ Index int }
-
-// A Literal value, such as 6 in %6d.
-type Literal int
-
-func (Default) isArgument() {}
-func (Zero) isArgument() {}
-func (Star) isArgument() {}
-func (Literal) isArgument() {}
-
-// Parse parses f and returns a list of actions.
-// An action may either be a literal string, or a Verb.
-func Parse(f string) ([]interface{}, error) {
- var out []interface{}
- for len(f) > 0 {
- if f[0] == '%' {
- v, n, err := ParseVerb(f)
- if err != nil {
- return nil, err
- }
- f = f[n:]
- out = append(out, v)
- } else {
- n := strings.IndexByte(f, '%')
- if n > -1 {
- out = append(out, f[:n])
- f = f[n:]
- } else {
- out = append(out, f)
- f = ""
- }
- }
- }
-
- return out, nil
-}
-
-func atoi(s string) int {
- n, _ := strconv.Atoi(s)
- return n
-}
-
-// ParseVerb parses the verb at the beginning of f.
-// It returns the verb, how much of the input was consumed, and an error, if any.
-func ParseVerb(f string) (Verb, int, error) {
- if len(f) < 2 {
- return Verb{}, 0, ErrInvalid
- }
- const (
- flags = 1
-
- width = 2
- widthStar = 3
- widthIndex = 5
-
- dot = 6
- prec = 7
- precStar = 8
- precIndex = 10
-
- verbIndex = 11
- verb = 12
- )
-
- m := re.FindStringSubmatch(f)
- if m == nil {
- return Verb{}, 0, ErrInvalid
- }
-
- v := Verb{
- Letter: []rune(m[verb])[0],
- Flags: m[flags],
- Raw: m[0],
- }
-
- if m[width] != "" {
- // Literal width
- v.Width = Literal(atoi(m[width]))
- } else if m[widthStar] != "" {
- // Star width
- if m[widthIndex] != "" {
- v.Width = Star{atoi(m[widthIndex])}
- } else {
- v.Width = Star{-1}
- }
- } else {
- // Default width
- v.Width = Default{}
- }
-
- if m[dot] == "" {
- // default precision
- v.Precision = Default{}
- } else {
- if m[prec] != "" {
- // Literal precision
- v.Precision = Literal(atoi(m[prec]))
- } else if m[precStar] != "" {
- // Star precision
- if m[precIndex] != "" {
- v.Precision = Star{atoi(m[precIndex])}
- } else {
- v.Precision = Star{-1}
- }
- } else {
- // Zero precision
- v.Precision = Zero{}
- }
- }
-
- if m[verb] == "%" {
- v.Value = 0
- } else if m[verbIndex] != "" {
- v.Value = atoi(m[verbIndex])
- } else {
- v.Value = -1
- }
-
- return v, len(m[0]), nil
-}
-
-const (
- flags = `([+#0 -]*)`
- verb = `([a-zA-Z%])`
- index = `(?:\[([0-9]+)\])`
- star = `((` + index + `)?\*)`
- width1 = `([0-9]+)`
- width2 = star
- width = `(?:` + width1 + `|` + width2 + `)`
- precision = width
- widthAndPrecision = `(?:(?:` + width + `)?(?:(\.)(?:` + precision + `)?)?)`
-)
-
-var re = regexp.MustCompile(`^%` + flags + widthAndPrecision + `?` + index + `?` + verb)