mirror of
				https://gitea.com/gitea/tea.git
				synced 2025-10-31 01:05:26 +01:00 
			
		
		
		
	Add Makefile / .drone.yml, use go module with vendor (#20)
* add Makefile / .drone.yml, use go module with vendor * Update .drone.yml Co-Authored-By: lunny <xiaolunwen@gmail.com>
This commit is contained in:
		
							
								
								
									
										28
									
								
								vendor/github.com/src-d/gcfg/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/src-d/gcfg/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| Copyright (c) 2012 Péter Surányi. Portions Copyright (c) 2009 The Go | ||||
| Authors. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
|    * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
|    * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
|    * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										4
									
								
								vendor/github.com/src-d/gcfg/README
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/src-d/gcfg/README
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| Gcfg reads INI-style configuration files into Go structs; | ||||
| supports user-defined types and subsections. | ||||
|  | ||||
| Package docs: https://godoc.org/gopkg.in/gcfg.v1 | ||||
							
								
								
									
										145
									
								
								vendor/github.com/src-d/gcfg/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								vendor/github.com/src-d/gcfg/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | ||||
| // Package gcfg reads "INI-style" text-based configuration files with | ||||
| // "name=value" pairs grouped into sections (gcfg files). | ||||
| // | ||||
| // This package is still a work in progress; see the sections below for planned | ||||
| // changes. | ||||
| // | ||||
| // Syntax | ||||
| // | ||||
| // The syntax is based on that used by git config: | ||||
| // http://git-scm.com/docs/git-config#_syntax . | ||||
| // There are some (planned) differences compared to the git config format: | ||||
| //  - improve data portability: | ||||
| //    - must be encoded in UTF-8 (for now) and must not contain the 0 byte | ||||
| //    - include and "path" type is not supported | ||||
| //      (path type may be implementable as a user-defined type) | ||||
| //  - internationalization | ||||
| //    - section and variable names can contain unicode letters, unicode digits | ||||
| //      (as defined in http://golang.org/ref/spec#Characters ) and hyphens | ||||
| //      (U+002D), starting with a unicode letter | ||||
| //  - disallow potentially ambiguous or misleading definitions: | ||||
| //    - `[sec.sub]` format is not allowed (deprecated in gitconfig) | ||||
| //    - `[sec ""]` is not allowed | ||||
| //      - use `[sec]` for section name "sec" and empty subsection name | ||||
| //    - (planned) within a single file, definitions must be contiguous for each: | ||||
| //      - section: '[secA]' -> '[secB]' -> '[secA]' is an error | ||||
| //      - subsection: '[sec "A"]' -> '[sec "B"]' -> '[sec "A"]' is an error | ||||
| //      - multivalued variable: 'multi=a' -> 'other=x' -> 'multi=b' is an error | ||||
| // | ||||
| // Data structure | ||||
| // | ||||
| // The functions in this package read values into a user-defined struct. | ||||
| // Each section corresponds to a struct field in the config struct, and each | ||||
| // variable in a section corresponds to a data field in the section struct. | ||||
| // The mapping of each section or variable name to fields is done either based | ||||
| // on the "gcfg" struct tag or by matching the name of the section or variable, | ||||
| // ignoring case. In the latter case, hyphens '-' in section and variable names | ||||
| // correspond to underscores '_' in field names. | ||||
| // Fields must be exported; to use a section or variable name starting with a | ||||
| // letter that is neither upper- or lower-case, prefix the field name with 'X'. | ||||
| // (See https://code.google.com/p/go/issues/detail?id=5763#c4 .) | ||||
| // | ||||
| // For sections with subsections, the corresponding field in config must be a | ||||
| // map, rather than a struct, with string keys and pointer-to-struct values. | ||||
| // Values for subsection variables are stored in the map with the subsection | ||||
| // name used as the map key. | ||||
| // (Note that unlike section and variable names, subsection names are case | ||||
| // sensitive.) | ||||
| // When using a map, and there is a section with the same section name but | ||||
| // without a subsection name, its values are stored with the empty string used | ||||
| // as the key. | ||||
| // It is possible to provide default values for subsections in the section | ||||
| // "default-<sectionname>" (or by setting values in the corresponding struct | ||||
| // field "Default_<sectionname>"). | ||||
| // | ||||
| // The functions in this package panic if config is not a pointer to a struct, | ||||
| // or when a field is not of a suitable type (either a struct or a map with | ||||
| // string keys and pointer-to-struct values). | ||||
| // | ||||
| // Parsing of values | ||||
| // | ||||
| // The section structs in the config struct may contain single-valued or | ||||
| // multi-valued variables. Variables of unnamed slice type (that is, a type | ||||
| // starting with `[]`) are treated as multi-value; all others (including named | ||||
| // slice types) are treated as single-valued variables. | ||||
| // | ||||
| // Single-valued variables are handled based on the type as follows. | ||||
| // Unnamed pointer types (that is, types starting with `*`) are dereferenced, | ||||
| // and if necessary, a new instance is allocated. | ||||
| // | ||||
| // For types implementing the encoding.TextUnmarshaler interface, the | ||||
| // UnmarshalText method is used to set the value. Implementing this method is | ||||
| // the recommended way for parsing user-defined types. | ||||
| // | ||||
| // For fields of string kind, the value string is assigned to the field, after | ||||
| // unquoting and unescaping as needed. | ||||
| // For fields of bool kind, the field is set to true if the value is "true", | ||||
| // "yes", "on" or "1", and set to false if the value is "false", "no", "off" or | ||||
| // "0", ignoring case. In addition, single-valued bool fields can be specified | ||||
| // with a "blank" value (variable name without equals sign and value); in such | ||||
| // case the value is set to true. | ||||
| // | ||||
| // Predefined integer types [u]int(|8|16|32|64) and big.Int are parsed as | ||||
| // decimal or hexadecimal (if having '0x' prefix). (This is to prevent | ||||
| // unintuitively handling zero-padded numbers as octal.) Other types having | ||||
| // [u]int* as the underlying type, such as os.FileMode and uintptr allow | ||||
| // decimal, hexadecimal, or octal values. | ||||
| // Parsing mode for integer types can be overridden using the struct tag option | ||||
| // ",int=mode" where mode is a combination of the 'd', 'h', and 'o' characters | ||||
| // (each standing for decimal, hexadecimal, and octal, respectively.) | ||||
| // | ||||
| // All other types are parsed using fmt.Sscanf with the "%v" verb. | ||||
| // | ||||
| // For multi-valued variables, each individual value is parsed as above and | ||||
| // appended to the slice. If the first value is specified as a "blank" value | ||||
| // (variable name without equals sign and value), a new slice is allocated; | ||||
| // that is any values previously set in the slice will be ignored. | ||||
| // | ||||
| // The types subpackage for provides helpers for parsing "enum-like" and integer | ||||
| // types. | ||||
| // | ||||
| // Error handling | ||||
| // | ||||
| // There are 3 types of errors: | ||||
| // | ||||
| //  - programmer errors / panics: | ||||
| //    - invalid configuration structure | ||||
| //  - data errors: | ||||
| //    - fatal errors: | ||||
| //      - invalid configuration syntax | ||||
| //    - warnings: | ||||
| //      - data that doesn't belong to any part of the config structure | ||||
| // | ||||
| // Programmer errors trigger panics. These are should be fixed by the programmer | ||||
| // before releasing code that uses gcfg. | ||||
| // | ||||
| // Data errors cause gcfg to return a non-nil error value. This includes the | ||||
| // case when there are extra unknown key-value definitions in the configuration | ||||
| // data (extra data). | ||||
| // However, in some occasions it is desirable to be able to proceed in | ||||
| // situations when the only data error is that of extra data. | ||||
| // These errors are handled at a different (warning) priority and can be | ||||
| // filtered out programmatically. To ignore extra data warnings, wrap the | ||||
| // gcfg.Read*Into invocation into a call to gcfg.FatalOnly. | ||||
| // | ||||
| // TODO | ||||
| // | ||||
| // The following is a list of changes under consideration: | ||||
| //  - documentation | ||||
| //    - self-contained syntax documentation | ||||
| //    - more practical examples | ||||
| //    - move TODOs to issue tracker (eventually) | ||||
| //  - syntax | ||||
| //    - reconsider valid escape sequences | ||||
| //      (gitconfig doesn't support \r in value, \t in subsection name, etc.) | ||||
| //  - reading / parsing gcfg files | ||||
| //    - define internal representation structure | ||||
| //    - support multiple inputs (readers, strings, files) | ||||
| //    - support declaring encoding (?) | ||||
| //    - support varying fields sets for subsections (?) | ||||
| //  - writing gcfg files | ||||
| //  - error handling | ||||
| //    - make error context accessible programmatically? | ||||
| //    - limit input size? | ||||
| // | ||||
| package gcfg // import "github.com/src-d/gcfg" | ||||
							
								
								
									
										41
									
								
								vendor/github.com/src-d/gcfg/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/github.com/src-d/gcfg/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| package gcfg | ||||
|  | ||||
| import ( | ||||
| 	"gopkg.in/warnings.v0" | ||||
| ) | ||||
|  | ||||
| // FatalOnly filters the results of a Read*Into invocation and returns only | ||||
| // fatal errors. That is, errors (warnings) indicating data for unknown | ||||
| // sections / variables is ignored. Example invocation: | ||||
| // | ||||
| //  err := gcfg.FatalOnly(gcfg.ReadFileInto(&cfg, configFile)) | ||||
| //  if err != nil { | ||||
| //      ... | ||||
| // | ||||
| func FatalOnly(err error) error { | ||||
| 	return warnings.FatalOnly(err) | ||||
| } | ||||
|  | ||||
| func isFatal(err error) bool { | ||||
| 	_, ok := err.(extraData) | ||||
| 	return !ok | ||||
| } | ||||
|  | ||||
| type extraData struct { | ||||
| 	section    string | ||||
| 	subsection *string | ||||
| 	variable   *string | ||||
| } | ||||
|  | ||||
| func (e extraData) Error() string { | ||||
| 	s := "can't store data at section \"" + e.section + "\"" | ||||
| 	if e.subsection != nil { | ||||
| 		s += ", subsection \"" + *e.subsection + "\"" | ||||
| 	} | ||||
| 	if e.variable != nil { | ||||
| 		s += ", variable \"" + *e.variable + "\"" | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| var _ error = extraData{} | ||||
							
								
								
									
										7
									
								
								vendor/github.com/src-d/gcfg/go1_0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/src-d/gcfg/go1_0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| // +build !go1.2 | ||||
|  | ||||
| package gcfg | ||||
|  | ||||
| type textUnmarshaler interface { | ||||
| 	UnmarshalText(text []byte) error | ||||
| } | ||||
							
								
								
									
										9
									
								
								vendor/github.com/src-d/gcfg/go1_2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/src-d/gcfg/go1_2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| // +build go1.2 | ||||
|  | ||||
| package gcfg | ||||
|  | ||||
| import ( | ||||
| 	"encoding" | ||||
| ) | ||||
|  | ||||
| type textUnmarshaler encoding.TextUnmarshaler | ||||
							
								
								
									
										273
									
								
								vendor/github.com/src-d/gcfg/read.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								vendor/github.com/src-d/gcfg/read.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,273 @@ | ||||
| package gcfg | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/src-d/gcfg/scanner" | ||||
| 	"github.com/src-d/gcfg/token" | ||||
| 	"gopkg.in/warnings.v0" | ||||
| ) | ||||
|  | ||||
| var unescape = map[rune]rune{'\\': '\\', '"': '"', 'n': '\n', 't': '\t', 'b': '\b'} | ||||
|  | ||||
| // no error: invalid literals should be caught by scanner | ||||
| func unquote(s string) string { | ||||
| 	u, q, esc := make([]rune, 0, len(s)), false, false | ||||
| 	for _, c := range s { | ||||
| 		if esc { | ||||
| 			uc, ok := unescape[c] | ||||
| 			switch { | ||||
| 			case ok: | ||||
| 				u = append(u, uc) | ||||
| 				fallthrough | ||||
| 			case !q && c == '\n': | ||||
| 				esc = false | ||||
| 				continue | ||||
| 			} | ||||
| 			panic("invalid escape sequence") | ||||
| 		} | ||||
| 		switch c { | ||||
| 		case '"': | ||||
| 			q = !q | ||||
| 		case '\\': | ||||
| 			esc = true | ||||
| 		default: | ||||
| 			u = append(u, c) | ||||
| 		} | ||||
| 	} | ||||
| 	if q { | ||||
| 		panic("missing end quote") | ||||
| 	} | ||||
| 	if esc { | ||||
| 		panic("invalid escape sequence") | ||||
| 	} | ||||
| 	return string(u) | ||||
| } | ||||
|  | ||||
| func read(c *warnings.Collector, callback func(string, string, string, string, bool) error, | ||||
| 	fset *token.FileSet, file *token.File, src []byte) error { | ||||
| 	// | ||||
| 	var s scanner.Scanner | ||||
| 	var errs scanner.ErrorList | ||||
| 	s.Init(file, src, func(p token.Position, m string) { errs.Add(p, m) }, 0) | ||||
| 	sect, sectsub := "", "" | ||||
| 	pos, tok, lit := s.Scan() | ||||
| 	errfn := func(msg string) error { | ||||
| 		return fmt.Errorf("%s: %s", fset.Position(pos), msg) | ||||
| 	} | ||||
| 	for { | ||||
| 		if errs.Len() > 0 { | ||||
| 			if err := c.Collect(errs.Err()); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		switch tok { | ||||
| 		case token.EOF: | ||||
| 			return nil | ||||
| 		case token.EOL, token.COMMENT: | ||||
| 			pos, tok, lit = s.Scan() | ||||
| 		case token.LBRACK: | ||||
| 			pos, tok, lit = s.Scan() | ||||
| 			if errs.Len() > 0 { | ||||
| 				if err := c.Collect(errs.Err()); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			if tok != token.IDENT { | ||||
| 				if err := c.Collect(errfn("expected section name")); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			sect, sectsub = lit, "" | ||||
| 			pos, tok, lit = s.Scan() | ||||
| 			if errs.Len() > 0 { | ||||
| 				if err := c.Collect(errs.Err()); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			if tok == token.STRING { | ||||
| 				sectsub = unquote(lit) | ||||
| 				if sectsub == "" { | ||||
| 					if err := c.Collect(errfn("empty subsection name")); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				pos, tok, lit = s.Scan() | ||||
| 				if errs.Len() > 0 { | ||||
| 					if err := c.Collect(errs.Err()); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if tok != token.RBRACK { | ||||
| 				if sectsub == "" { | ||||
| 					if err := c.Collect(errfn("expected subsection name or right bracket")); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				if err := c.Collect(errfn("expected right bracket")); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			pos, tok, lit = s.Scan() | ||||
| 			if tok != token.EOL && tok != token.EOF && tok != token.COMMENT { | ||||
| 				if err := c.Collect(errfn("expected EOL, EOF, or comment")); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			// If a section/subsection header was found, ensure a | ||||
| 			// container object is created, even if there are no | ||||
| 			// variables further down. | ||||
| 			err := c.Collect(callback(sect, sectsub, "", "", true)) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		case token.IDENT: | ||||
| 			if sect == "" { | ||||
| 				if err := c.Collect(errfn("expected section header")); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			n := lit | ||||
| 			pos, tok, lit = s.Scan() | ||||
| 			if errs.Len() > 0 { | ||||
| 				return errs.Err() | ||||
| 			} | ||||
| 			blank, v := tok == token.EOF || tok == token.EOL || tok == token.COMMENT, "" | ||||
| 			if !blank { | ||||
| 				if tok != token.ASSIGN { | ||||
| 					if err := c.Collect(errfn("expected '='")); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				pos, tok, lit = s.Scan() | ||||
| 				if errs.Len() > 0 { | ||||
| 					if err := c.Collect(errs.Err()); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				if tok != token.STRING { | ||||
| 					if err := c.Collect(errfn("expected value")); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				v = unquote(lit) | ||||
| 				pos, tok, lit = s.Scan() | ||||
| 				if errs.Len() > 0 { | ||||
| 					if err := c.Collect(errs.Err()); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				if tok != token.EOL && tok != token.EOF && tok != token.COMMENT { | ||||
| 					if err := c.Collect(errfn("expected EOL, EOF, or comment")); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			err := c.Collect(callback(sect, sectsub, n, v, blank)) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		default: | ||||
| 			if sect == "" { | ||||
| 				if err := c.Collect(errfn("expected section header")); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			if err := c.Collect(errfn("expected section header or variable declaration")); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	panic("never reached") | ||||
| } | ||||
|  | ||||
| func readInto(config interface{}, fset *token.FileSet, file *token.File, | ||||
| 	src []byte) error { | ||||
| 	// | ||||
| 	c := warnings.NewCollector(isFatal) | ||||
| 	firstPassCallback := func(s string, ss string, k string, v string, bv bool) error { | ||||
| 		return set(c, config, s, ss, k, v, bv, false) | ||||
| 	} | ||||
| 	err := read(c, firstPassCallback, fset, file, src) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	secondPassCallback := func(s string, ss string, k string, v string, bv bool) error { | ||||
| 		return set(c, config, s, ss, k, v, bv, true) | ||||
| 	} | ||||
| 	err = read(c, secondPassCallback, fset, file, src) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return c.Done() | ||||
| } | ||||
|  | ||||
| // ReadWithCallback reads gcfg formatted data from reader and calls | ||||
| // callback with each section and option found. | ||||
| // | ||||
| // Callback is called with section, subsection, option key, option value | ||||
| // and blank value flag as arguments. | ||||
| // | ||||
| // When a section is found, callback is called with nil subsection, option key | ||||
| // and option value. | ||||
| // | ||||
| // When a subsection is found, callback is called with nil option key and | ||||
| // option value. | ||||
| // | ||||
| // If blank value flag is true, it means that the value was not set for an option | ||||
| // (as opposed to set to empty string). | ||||
| // | ||||
| // If callback returns an error, ReadWithCallback terminates with an error too. | ||||
| func ReadWithCallback(reader io.Reader, callback func(string, string, string, string, bool) error) error { | ||||
| 	src, err := ioutil.ReadAll(reader) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	fset := token.NewFileSet() | ||||
| 	file := fset.AddFile("", fset.Base(), len(src)) | ||||
| 	c := warnings.NewCollector(isFatal) | ||||
|  | ||||
| 	return read(c, callback, fset, file, src) | ||||
| } | ||||
|  | ||||
| // ReadInto reads gcfg formatted data from reader and sets the values into the | ||||
| // corresponding fields in config. | ||||
| func ReadInto(config interface{}, reader io.Reader) error { | ||||
| 	src, err := ioutil.ReadAll(reader) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	fset := token.NewFileSet() | ||||
| 	file := fset.AddFile("", fset.Base(), len(src)) | ||||
| 	return readInto(config, fset, file, src) | ||||
| } | ||||
|  | ||||
| // ReadStringInto reads gcfg formatted data from str and sets the values into | ||||
| // the corresponding fields in config. | ||||
| func ReadStringInto(config interface{}, str string) error { | ||||
| 	r := strings.NewReader(str) | ||||
| 	return ReadInto(config, r) | ||||
| } | ||||
|  | ||||
| // ReadFileInto reads gcfg formatted data from the file filename and sets the | ||||
| // values into the corresponding fields in config. | ||||
| func ReadFileInto(config interface{}, filename string) error { | ||||
| 	f, err := os.Open(filename) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	src, err := ioutil.ReadAll(f) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	fset := token.NewFileSet() | ||||
| 	file := fset.AddFile(filename, fset.Base(), len(src)) | ||||
| 	return readInto(config, fset, file, src) | ||||
| } | ||||
							
								
								
									
										121
									
								
								vendor/github.com/src-d/gcfg/scanner/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								vendor/github.com/src-d/gcfg/scanner/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package scanner | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"sort" | ||||
| ) | ||||
|  | ||||
| import ( | ||||
| 	"github.com/src-d/gcfg/token" | ||||
| ) | ||||
|  | ||||
| // In an ErrorList, an error is represented by an *Error. | ||||
| // The position Pos, if valid, points to the beginning of | ||||
| // the offending token, and the error condition is described | ||||
| // by Msg. | ||||
| // | ||||
| type Error struct { | ||||
| 	Pos token.Position | ||||
| 	Msg string | ||||
| } | ||||
|  | ||||
| // Error implements the error interface. | ||||
| func (e Error) Error() string { | ||||
| 	if e.Pos.Filename != "" || e.Pos.IsValid() { | ||||
| 		// don't print "<unknown position>" | ||||
| 		// TODO(gri) reconsider the semantics of Position.IsValid | ||||
| 		return e.Pos.String() + ": " + e.Msg | ||||
| 	} | ||||
| 	return e.Msg | ||||
| } | ||||
|  | ||||
| // ErrorList is a list of *Errors. | ||||
| // The zero value for an ErrorList is an empty ErrorList ready to use. | ||||
| // | ||||
| type ErrorList []*Error | ||||
|  | ||||
| // Add adds an Error with given position and error message to an ErrorList. | ||||
| func (p *ErrorList) Add(pos token.Position, msg string) { | ||||
| 	*p = append(*p, &Error{pos, msg}) | ||||
| } | ||||
|  | ||||
| // Reset resets an ErrorList to no errors. | ||||
| func (p *ErrorList) Reset() { *p = (*p)[0:0] } | ||||
|  | ||||
| // ErrorList implements the sort Interface. | ||||
| func (p ErrorList) Len() int      { return len(p) } | ||||
| func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] } | ||||
|  | ||||
| func (p ErrorList) Less(i, j int) bool { | ||||
| 	e := &p[i].Pos | ||||
| 	f := &p[j].Pos | ||||
| 	if e.Filename < f.Filename { | ||||
| 		return true | ||||
| 	} | ||||
| 	if e.Filename == f.Filename { | ||||
| 		return e.Offset < f.Offset | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Sort sorts an ErrorList. *Error entries are sorted by position, | ||||
| // other errors are sorted by error message, and before any *Error | ||||
| // entry. | ||||
| // | ||||
| func (p ErrorList) Sort() { | ||||
| 	sort.Sort(p) | ||||
| } | ||||
|  | ||||
| // RemoveMultiples sorts an ErrorList and removes all but the first error per line. | ||||
| func (p *ErrorList) RemoveMultiples() { | ||||
| 	sort.Sort(p) | ||||
| 	var last token.Position // initial last.Line is != any legal error line | ||||
| 	i := 0 | ||||
| 	for _, e := range *p { | ||||
| 		if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line { | ||||
| 			last = e.Pos | ||||
| 			(*p)[i] = e | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
| 	(*p) = (*p)[0:i] | ||||
| } | ||||
|  | ||||
| // An ErrorList implements the error interface. | ||||
| func (p ErrorList) Error() string { | ||||
| 	switch len(p) { | ||||
| 	case 0: | ||||
| 		return "no errors" | ||||
| 	case 1: | ||||
| 		return p[0].Error() | ||||
| 	} | ||||
| 	return fmt.Sprintf("%s (and %d more errors)", p[0], len(p)-1) | ||||
| } | ||||
|  | ||||
| // Err returns an error equivalent to this error list. | ||||
| // If the list is empty, Err returns nil. | ||||
| func (p ErrorList) Err() error { | ||||
| 	if len(p) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return p | ||||
| } | ||||
|  | ||||
| // PrintError is a utility function that prints a list of errors to w, | ||||
| // one error per line, if the err parameter is an ErrorList. Otherwise | ||||
| // it prints the err string. | ||||
| // | ||||
| func PrintError(w io.Writer, err error) { | ||||
| 	if list, ok := err.(ErrorList); ok { | ||||
| 		for _, e := range list { | ||||
| 			fmt.Fprintf(w, "%s\n", e) | ||||
| 		} | ||||
| 	} else if err != nil { | ||||
| 		fmt.Fprintf(w, "%s\n", err) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										342
									
								
								vendor/github.com/src-d/gcfg/scanner/scanner.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								vendor/github.com/src-d/gcfg/scanner/scanner.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,342 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Package scanner implements a scanner for gcfg configuration text. | ||||
| // It takes a []byte as source which can then be tokenized | ||||
| // through repeated calls to the Scan method. | ||||
| // | ||||
| // Note that the API for the scanner package may change to accommodate new | ||||
| // features or implementation changes in gcfg. | ||||
| // | ||||
| package scanner | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| import ( | ||||
| 	"github.com/src-d/gcfg/token" | ||||
| ) | ||||
|  | ||||
| // An ErrorHandler may be provided to Scanner.Init. If a syntax error is | ||||
| // encountered and a handler was installed, the handler is called with a | ||||
| // position and an error message. The position points to the beginning of | ||||
| // the offending token. | ||||
| // | ||||
| type ErrorHandler func(pos token.Position, msg string) | ||||
|  | ||||
| // A Scanner holds the scanner's internal state while processing | ||||
| // a given text.  It can be allocated as part of another data | ||||
| // structure but must be initialized via Init before use. | ||||
| // | ||||
| type Scanner struct { | ||||
| 	// immutable state | ||||
| 	file *token.File  // source file handle | ||||
| 	dir  string       // directory portion of file.Name() | ||||
| 	src  []byte       // source | ||||
| 	err  ErrorHandler // error reporting; or nil | ||||
| 	mode Mode         // scanning mode | ||||
|  | ||||
| 	// scanning state | ||||
| 	ch         rune // current character | ||||
| 	offset     int  // character offset | ||||
| 	rdOffset   int  // reading offset (position after current character) | ||||
| 	lineOffset int  // current line offset | ||||
| 	nextVal    bool // next token is expected to be a value | ||||
|  | ||||
| 	// public state - ok to modify | ||||
| 	ErrorCount int // number of errors encountered | ||||
| } | ||||
|  | ||||
| // Read the next Unicode char into s.ch. | ||||
| // s.ch < 0 means end-of-file. | ||||
| // | ||||
| func (s *Scanner) next() { | ||||
| 	if s.rdOffset < len(s.src) { | ||||
| 		s.offset = s.rdOffset | ||||
| 		if s.ch == '\n' { | ||||
| 			s.lineOffset = s.offset | ||||
| 			s.file.AddLine(s.offset) | ||||
| 		} | ||||
| 		r, w := rune(s.src[s.rdOffset]), 1 | ||||
| 		switch { | ||||
| 		case r == 0: | ||||
| 			s.error(s.offset, "illegal character NUL") | ||||
| 		case r >= 0x80: | ||||
| 			// not ASCII | ||||
| 			r, w = utf8.DecodeRune(s.src[s.rdOffset:]) | ||||
| 			if r == utf8.RuneError && w == 1 { | ||||
| 				s.error(s.offset, "illegal UTF-8 encoding") | ||||
| 			} | ||||
| 		} | ||||
| 		s.rdOffset += w | ||||
| 		s.ch = r | ||||
| 	} else { | ||||
| 		s.offset = len(s.src) | ||||
| 		if s.ch == '\n' { | ||||
| 			s.lineOffset = s.offset | ||||
| 			s.file.AddLine(s.offset) | ||||
| 		} | ||||
| 		s.ch = -1 // eof | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // A mode value is a set of flags (or 0). | ||||
| // They control scanner behavior. | ||||
| // | ||||
| type Mode uint | ||||
|  | ||||
| const ( | ||||
| 	ScanComments Mode = 1 << iota // return comments as COMMENT tokens | ||||
| ) | ||||
|  | ||||
| // Init prepares the scanner s to tokenize the text src by setting the | ||||
| // scanner at the beginning of src. The scanner uses the file set file | ||||
| // for position information and it adds line information for each line. | ||||
| // It is ok to re-use the same file when re-scanning the same file as | ||||
| // line information which is already present is ignored. Init causes a | ||||
| // panic if the file size does not match the src size. | ||||
| // | ||||
| // Calls to Scan will invoke the error handler err if they encounter a | ||||
| // syntax error and err is not nil. Also, for each error encountered, | ||||
| // the Scanner field ErrorCount is incremented by one. The mode parameter | ||||
| // determines how comments are handled. | ||||
| // | ||||
| // Note that Init may call err if there is an error in the first character | ||||
| // of the file. | ||||
| // | ||||
| func (s *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode Mode) { | ||||
| 	// Explicitly initialize all fields since a scanner may be reused. | ||||
| 	if file.Size() != len(src) { | ||||
| 		panic(fmt.Sprintf("file size (%d) does not match src len (%d)", file.Size(), len(src))) | ||||
| 	} | ||||
| 	s.file = file | ||||
| 	s.dir, _ = filepath.Split(file.Name()) | ||||
| 	s.src = src | ||||
| 	s.err = err | ||||
| 	s.mode = mode | ||||
|  | ||||
| 	s.ch = ' ' | ||||
| 	s.offset = 0 | ||||
| 	s.rdOffset = 0 | ||||
| 	s.lineOffset = 0 | ||||
| 	s.ErrorCount = 0 | ||||
| 	s.nextVal = false | ||||
|  | ||||
| 	s.next() | ||||
| } | ||||
|  | ||||
| func (s *Scanner) error(offs int, msg string) { | ||||
| 	if s.err != nil { | ||||
| 		s.err(s.file.Position(s.file.Pos(offs)), msg) | ||||
| 	} | ||||
| 	s.ErrorCount++ | ||||
| } | ||||
|  | ||||
| func (s *Scanner) scanComment() string { | ||||
| 	// initial [;#] already consumed | ||||
| 	offs := s.offset - 1 // position of initial [;#] | ||||
|  | ||||
| 	for s.ch != '\n' && s.ch >= 0 { | ||||
| 		s.next() | ||||
| 	} | ||||
| 	return string(s.src[offs:s.offset]) | ||||
| } | ||||
|  | ||||
| func isLetter(ch rune) bool { | ||||
| 	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch >= 0x80 && unicode.IsLetter(ch) | ||||
| } | ||||
|  | ||||
| func isDigit(ch rune) bool { | ||||
| 	return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) | ||||
| } | ||||
|  | ||||
| func (s *Scanner) scanIdentifier() string { | ||||
| 	offs := s.offset | ||||
| 	for isLetter(s.ch) || isDigit(s.ch) || s.ch == '-' { | ||||
| 		s.next() | ||||
| 	} | ||||
| 	return string(s.src[offs:s.offset]) | ||||
| } | ||||
|  | ||||
| func (s *Scanner) scanEscape(val bool) { | ||||
| 	offs := s.offset | ||||
| 	ch := s.ch | ||||
| 	s.next() // always make progress | ||||
| 	switch ch { | ||||
| 	case '\\', '"': | ||||
| 		// ok | ||||
| 	case 'n', 't', 'b': | ||||
| 		if val { | ||||
| 			break // ok | ||||
| 		} | ||||
| 		fallthrough | ||||
| 	default: | ||||
| 		s.error(offs, "unknown escape sequence") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *Scanner) scanString() string { | ||||
| 	// '"' opening already consumed | ||||
| 	offs := s.offset - 1 | ||||
|  | ||||
| 	for s.ch != '"' { | ||||
| 		ch := s.ch | ||||
| 		s.next() | ||||
| 		if ch == '\n' || ch < 0 { | ||||
| 			s.error(offs, "string not terminated") | ||||
| 			break | ||||
| 		} | ||||
| 		if ch == '\\' { | ||||
| 			s.scanEscape(false) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	s.next() | ||||
|  | ||||
| 	return string(s.src[offs:s.offset]) | ||||
| } | ||||
|  | ||||
| func stripCR(b []byte) []byte { | ||||
| 	c := make([]byte, len(b)) | ||||
| 	i := 0 | ||||
| 	for _, ch := range b { | ||||
| 		if ch != '\r' { | ||||
| 			c[i] = ch | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
| 	return c[:i] | ||||
| } | ||||
|  | ||||
| func (s *Scanner) scanValString() string { | ||||
| 	offs := s.offset | ||||
|  | ||||
| 	hasCR := false | ||||
| 	end := offs | ||||
| 	inQuote := false | ||||
| loop: | ||||
| 	for inQuote || s.ch >= 0 && s.ch != '\n' && s.ch != ';' && s.ch != '#' { | ||||
| 		ch := s.ch | ||||
| 		s.next() | ||||
| 		switch { | ||||
| 		case inQuote && ch == '\\': | ||||
| 			s.scanEscape(true) | ||||
| 		case !inQuote && ch == '\\': | ||||
| 			if s.ch == '\r' { | ||||
| 				hasCR = true | ||||
| 				s.next() | ||||
| 			} | ||||
| 			if s.ch != '\n' { | ||||
| 				s.scanEscape(true) | ||||
| 			} else { | ||||
| 				s.next() | ||||
| 			} | ||||
| 		case ch == '"': | ||||
| 			inQuote = !inQuote | ||||
| 		case ch == '\r': | ||||
| 			hasCR = true | ||||
| 		case ch < 0 || inQuote && ch == '\n': | ||||
| 			s.error(offs, "string not terminated") | ||||
| 			break loop | ||||
| 		} | ||||
| 		if inQuote || !isWhiteSpace(ch) { | ||||
| 			end = s.offset | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	lit := s.src[offs:end] | ||||
| 	if hasCR { | ||||
| 		lit = stripCR(lit) | ||||
| 	} | ||||
|  | ||||
| 	return string(lit) | ||||
| } | ||||
|  | ||||
| func isWhiteSpace(ch rune) bool { | ||||
| 	return ch == ' ' || ch == '\t' || ch == '\r' | ||||
| } | ||||
|  | ||||
| func (s *Scanner) skipWhitespace() { | ||||
| 	for isWhiteSpace(s.ch) { | ||||
| 		s.next() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Scan scans the next token and returns the token position, the token, | ||||
| // and its literal string if applicable. The source end is indicated by | ||||
| // token.EOF. | ||||
| // | ||||
| // If the returned token is a literal (token.IDENT, token.STRING) or | ||||
| // token.COMMENT, the literal string has the corresponding value. | ||||
| // | ||||
| // If the returned token is token.ILLEGAL, the literal string is the | ||||
| // offending character. | ||||
| // | ||||
| // In all other cases, Scan returns an empty literal string. | ||||
| // | ||||
| // For more tolerant parsing, Scan will return a valid token if | ||||
| // possible even if a syntax error was encountered. Thus, even | ||||
| // if the resulting token sequence contains no illegal tokens, | ||||
| // a client may not assume that no error occurred. Instead it | ||||
| // must check the scanner's ErrorCount or the number of calls | ||||
| // of the error handler, if there was one installed. | ||||
| // | ||||
| // Scan adds line information to the file added to the file | ||||
| // set with Init. Token positions are relative to that file | ||||
| // and thus relative to the file set. | ||||
| // | ||||
| func (s *Scanner) Scan() (pos token.Pos, tok token.Token, lit string) { | ||||
| scanAgain: | ||||
| 	s.skipWhitespace() | ||||
|  | ||||
| 	// current token start | ||||
| 	pos = s.file.Pos(s.offset) | ||||
|  | ||||
| 	// determine token value | ||||
| 	switch ch := s.ch; { | ||||
| 	case s.nextVal: | ||||
| 		lit = s.scanValString() | ||||
| 		tok = token.STRING | ||||
| 		s.nextVal = false | ||||
| 	case isLetter(ch): | ||||
| 		lit = s.scanIdentifier() | ||||
| 		tok = token.IDENT | ||||
| 	default: | ||||
| 		s.next() // always make progress | ||||
| 		switch ch { | ||||
| 		case -1: | ||||
| 			tok = token.EOF | ||||
| 		case '\n': | ||||
| 			tok = token.EOL | ||||
| 		case '"': | ||||
| 			tok = token.STRING | ||||
| 			lit = s.scanString() | ||||
| 		case '[': | ||||
| 			tok = token.LBRACK | ||||
| 		case ']': | ||||
| 			tok = token.RBRACK | ||||
| 		case ';', '#': | ||||
| 			// comment | ||||
| 			lit = s.scanComment() | ||||
| 			if s.mode&ScanComments == 0 { | ||||
| 				// skip comment | ||||
| 				goto scanAgain | ||||
| 			} | ||||
| 			tok = token.COMMENT | ||||
| 		case '=': | ||||
| 			tok = token.ASSIGN | ||||
| 			s.nextVal = true | ||||
| 		default: | ||||
| 			s.error(s.file.Offset(pos), fmt.Sprintf("illegal character %#U", ch)) | ||||
| 			tok = token.ILLEGAL | ||||
| 			lit = string(ch) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										332
									
								
								vendor/github.com/src-d/gcfg/set.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								vendor/github.com/src-d/gcfg/set.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,332 @@ | ||||
| package gcfg | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/gob" | ||||
| 	"fmt" | ||||
| 	"math/big" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/src-d/gcfg/types" | ||||
| 	"gopkg.in/warnings.v0" | ||||
| ) | ||||
|  | ||||
| type tag struct { | ||||
| 	ident   string | ||||
| 	intMode string | ||||
| } | ||||
|  | ||||
| func newTag(ts string) tag { | ||||
| 	t := tag{} | ||||
| 	s := strings.Split(ts, ",") | ||||
| 	t.ident = s[0] | ||||
| 	for _, tse := range s[1:] { | ||||
| 		if strings.HasPrefix(tse, "int=") { | ||||
| 			t.intMode = tse[len("int="):] | ||||
| 		} | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| func fieldFold(v reflect.Value, name string) (reflect.Value, tag) { | ||||
| 	var n string | ||||
| 	r0, _ := utf8.DecodeRuneInString(name) | ||||
| 	if unicode.IsLetter(r0) && !unicode.IsLower(r0) && !unicode.IsUpper(r0) { | ||||
| 		n = "X" | ||||
| 	} | ||||
| 	n += strings.Replace(name, "-", "_", -1) | ||||
| 	f, ok := v.Type().FieldByNameFunc(func(fieldName string) bool { | ||||
| 		if !v.FieldByName(fieldName).CanSet() { | ||||
| 			return false | ||||
| 		} | ||||
| 		f, _ := v.Type().FieldByName(fieldName) | ||||
| 		t := newTag(f.Tag.Get("gcfg")) | ||||
| 		if t.ident != "" { | ||||
| 			return strings.EqualFold(t.ident, name) | ||||
| 		} | ||||
| 		return strings.EqualFold(n, fieldName) | ||||
| 	}) | ||||
| 	if !ok { | ||||
| 		return reflect.Value{}, tag{} | ||||
| 	} | ||||
| 	return v.FieldByName(f.Name), newTag(f.Tag.Get("gcfg")) | ||||
| } | ||||
|  | ||||
| type setter func(destp interface{}, blank bool, val string, t tag) error | ||||
|  | ||||
| var errUnsupportedType = fmt.Errorf("unsupported type") | ||||
| var errBlankUnsupported = fmt.Errorf("blank value not supported for type") | ||||
|  | ||||
| var setters = []setter{ | ||||
| 	typeSetter, textUnmarshalerSetter, kindSetter, scanSetter, | ||||
| } | ||||
|  | ||||
| func textUnmarshalerSetter(d interface{}, blank bool, val string, t tag) error { | ||||
| 	dtu, ok := d.(textUnmarshaler) | ||||
| 	if !ok { | ||||
| 		return errUnsupportedType | ||||
| 	} | ||||
| 	if blank { | ||||
| 		return errBlankUnsupported | ||||
| 	} | ||||
| 	return dtu.UnmarshalText([]byte(val)) | ||||
| } | ||||
|  | ||||
| func boolSetter(d interface{}, blank bool, val string, t tag) error { | ||||
| 	if blank { | ||||
| 		reflect.ValueOf(d).Elem().Set(reflect.ValueOf(true)) | ||||
| 		return nil | ||||
| 	} | ||||
| 	b, err := types.ParseBool(val) | ||||
| 	if err == nil { | ||||
| 		reflect.ValueOf(d).Elem().Set(reflect.ValueOf(b)) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func intMode(mode string) types.IntMode { | ||||
| 	var m types.IntMode | ||||
| 	if strings.ContainsAny(mode, "dD") { | ||||
| 		m |= types.Dec | ||||
| 	} | ||||
| 	if strings.ContainsAny(mode, "hH") { | ||||
| 		m |= types.Hex | ||||
| 	} | ||||
| 	if strings.ContainsAny(mode, "oO") { | ||||
| 		m |= types.Oct | ||||
| 	} | ||||
| 	return m | ||||
| } | ||||
|  | ||||
| var typeModes = map[reflect.Type]types.IntMode{ | ||||
| 	reflect.TypeOf(int(0)):    types.Dec | types.Hex, | ||||
| 	reflect.TypeOf(int8(0)):   types.Dec | types.Hex, | ||||
| 	reflect.TypeOf(int16(0)):  types.Dec | types.Hex, | ||||
| 	reflect.TypeOf(int32(0)):  types.Dec | types.Hex, | ||||
| 	reflect.TypeOf(int64(0)):  types.Dec | types.Hex, | ||||
| 	reflect.TypeOf(uint(0)):   types.Dec | types.Hex, | ||||
| 	reflect.TypeOf(uint8(0)):  types.Dec | types.Hex, | ||||
| 	reflect.TypeOf(uint16(0)): types.Dec | types.Hex, | ||||
| 	reflect.TypeOf(uint32(0)): types.Dec | types.Hex, | ||||
| 	reflect.TypeOf(uint64(0)): types.Dec | types.Hex, | ||||
| 	// use default mode (allow dec/hex/oct) for uintptr type | ||||
| 	reflect.TypeOf(big.Int{}): types.Dec | types.Hex, | ||||
| } | ||||
|  | ||||
| func intModeDefault(t reflect.Type) types.IntMode { | ||||
| 	m, ok := typeModes[t] | ||||
| 	if !ok { | ||||
| 		m = types.Dec | types.Hex | types.Oct | ||||
| 	} | ||||
| 	return m | ||||
| } | ||||
|  | ||||
| func intSetter(d interface{}, blank bool, val string, t tag) error { | ||||
| 	if blank { | ||||
| 		return errBlankUnsupported | ||||
| 	} | ||||
| 	mode := intMode(t.intMode) | ||||
| 	if mode == 0 { | ||||
| 		mode = intModeDefault(reflect.TypeOf(d).Elem()) | ||||
| 	} | ||||
| 	return types.ParseInt(d, val, mode) | ||||
| } | ||||
|  | ||||
| func stringSetter(d interface{}, blank bool, val string, t tag) error { | ||||
| 	if blank { | ||||
| 		return errBlankUnsupported | ||||
| 	} | ||||
| 	dsp, ok := d.(*string) | ||||
| 	if !ok { | ||||
| 		return errUnsupportedType | ||||
| 	} | ||||
| 	*dsp = val | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| var kindSetters = map[reflect.Kind]setter{ | ||||
| 	reflect.String:  stringSetter, | ||||
| 	reflect.Bool:    boolSetter, | ||||
| 	reflect.Int:     intSetter, | ||||
| 	reflect.Int8:    intSetter, | ||||
| 	reflect.Int16:   intSetter, | ||||
| 	reflect.Int32:   intSetter, | ||||
| 	reflect.Int64:   intSetter, | ||||
| 	reflect.Uint:    intSetter, | ||||
| 	reflect.Uint8:   intSetter, | ||||
| 	reflect.Uint16:  intSetter, | ||||
| 	reflect.Uint32:  intSetter, | ||||
| 	reflect.Uint64:  intSetter, | ||||
| 	reflect.Uintptr: intSetter, | ||||
| } | ||||
|  | ||||
| var typeSetters = map[reflect.Type]setter{ | ||||
| 	reflect.TypeOf(big.Int{}): intSetter, | ||||
| } | ||||
|  | ||||
| func typeSetter(d interface{}, blank bool, val string, tt tag) error { | ||||
| 	t := reflect.ValueOf(d).Type().Elem() | ||||
| 	setter, ok := typeSetters[t] | ||||
| 	if !ok { | ||||
| 		return errUnsupportedType | ||||
| 	} | ||||
| 	return setter(d, blank, val, tt) | ||||
| } | ||||
|  | ||||
| func kindSetter(d interface{}, blank bool, val string, tt tag) error { | ||||
| 	k := reflect.ValueOf(d).Type().Elem().Kind() | ||||
| 	setter, ok := kindSetters[k] | ||||
| 	if !ok { | ||||
| 		return errUnsupportedType | ||||
| 	} | ||||
| 	return setter(d, blank, val, tt) | ||||
| } | ||||
|  | ||||
| func scanSetter(d interface{}, blank bool, val string, tt tag) error { | ||||
| 	if blank { | ||||
| 		return errBlankUnsupported | ||||
| 	} | ||||
| 	return types.ScanFully(d, val, 'v') | ||||
| } | ||||
|  | ||||
| func newValue(c *warnings.Collector, sect string, vCfg reflect.Value, | ||||
| 	vType reflect.Type) (reflect.Value, error) { | ||||
| 	// | ||||
| 	pv := reflect.New(vType) | ||||
| 	dfltName := "default-" + sect | ||||
| 	dfltField, _ := fieldFold(vCfg, dfltName) | ||||
| 	var err error | ||||
| 	if dfltField.IsValid() { | ||||
| 		b := bytes.NewBuffer(nil) | ||||
| 		ge := gob.NewEncoder(b) | ||||
| 		if err = c.Collect(ge.EncodeValue(dfltField)); err != nil { | ||||
| 			return pv, err | ||||
| 		} | ||||
| 		gd := gob.NewDecoder(bytes.NewReader(b.Bytes())) | ||||
| 		if err = c.Collect(gd.DecodeValue(pv.Elem())); err != nil { | ||||
| 			return pv, err | ||||
| 		} | ||||
| 	} | ||||
| 	return pv, nil | ||||
| } | ||||
|  | ||||
| func set(c *warnings.Collector, cfg interface{}, sect, sub, name string, | ||||
| 	 value string, blankValue bool, subsectPass bool) error { | ||||
| 	// | ||||
| 	vPCfg := reflect.ValueOf(cfg) | ||||
| 	if vPCfg.Kind() != reflect.Ptr || vPCfg.Elem().Kind() != reflect.Struct { | ||||
| 		panic(fmt.Errorf("config must be a pointer to a struct")) | ||||
| 	} | ||||
| 	vCfg := vPCfg.Elem() | ||||
| 	vSect, _ := fieldFold(vCfg, sect) | ||||
| 	if !vSect.IsValid() { | ||||
| 		err := extraData{section: sect} | ||||
| 		return c.Collect(err) | ||||
| 	} | ||||
| 	isSubsect := vSect.Kind() == reflect.Map | ||||
| 	if subsectPass != isSubsect { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if isSubsect { | ||||
| 		vst := vSect.Type() | ||||
| 		if vst.Key().Kind() != reflect.String || | ||||
| 			vst.Elem().Kind() != reflect.Ptr || | ||||
| 			vst.Elem().Elem().Kind() != reflect.Struct { | ||||
| 			panic(fmt.Errorf("map field for section must have string keys and "+ | ||||
| 				" pointer-to-struct values: section %q", sect)) | ||||
| 		} | ||||
| 		if vSect.IsNil() { | ||||
| 			vSect.Set(reflect.MakeMap(vst)) | ||||
| 		} | ||||
| 		k := reflect.ValueOf(sub) | ||||
| 		pv := vSect.MapIndex(k) | ||||
| 		if !pv.IsValid() { | ||||
| 			vType := vSect.Type().Elem().Elem() | ||||
| 			var err error | ||||
| 			if pv, err = newValue(c, sect, vCfg, vType); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			vSect.SetMapIndex(k, pv) | ||||
| 		} | ||||
| 		vSect = pv.Elem() | ||||
| 	} else if vSect.Kind() != reflect.Struct { | ||||
| 		panic(fmt.Errorf("field for section must be a map or a struct: "+ | ||||
| 			"section %q", sect)) | ||||
| 	} else if sub != "" { | ||||
| 		err := extraData{section: sect, subsection: &sub} | ||||
| 		return c.Collect(err) | ||||
| 	} | ||||
| 	// Empty name is a special value, meaning that only the | ||||
| 	// section/subsection object is to be created, with no values set. | ||||
| 	if name == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 	vVar, t := fieldFold(vSect, name) | ||||
| 	if !vVar.IsValid() { | ||||
| 		var err error | ||||
| 		if isSubsect { | ||||
| 			err = extraData{section: sect, subsection: &sub, variable: &name} | ||||
| 		} else { | ||||
| 			err = extraData{section: sect, variable: &name} | ||||
| 		} | ||||
| 		return c.Collect(err) | ||||
| 	} | ||||
| 	// vVal is either single-valued var, or newly allocated value within multi-valued var | ||||
| 	var vVal reflect.Value | ||||
| 	// multi-value if unnamed slice type | ||||
| 	isMulti := vVar.Type().Name() == "" && vVar.Kind() == reflect.Slice || | ||||
| 		vVar.Type().Name() == "" && vVar.Kind() == reflect.Ptr && vVar.Type().Elem().Name() == "" && vVar.Type().Elem().Kind() == reflect.Slice | ||||
| 	if isMulti && vVar.Kind() == reflect.Ptr { | ||||
| 		if vVar.IsNil() { | ||||
| 			vVar.Set(reflect.New(vVar.Type().Elem())) | ||||
| 		} | ||||
| 		vVar = vVar.Elem() | ||||
| 	} | ||||
| 	if isMulti && blankValue { | ||||
| 		vVar.Set(reflect.Zero(vVar.Type())) | ||||
| 		return nil | ||||
| 	} | ||||
| 	if isMulti { | ||||
| 		vVal = reflect.New(vVar.Type().Elem()).Elem() | ||||
| 	} else { | ||||
| 		vVal = vVar | ||||
| 	} | ||||
| 	isDeref := vVal.Type().Name() == "" && vVal.Type().Kind() == reflect.Ptr | ||||
| 	isNew := isDeref && vVal.IsNil() | ||||
| 	// vAddr is address of value to set (dereferenced & allocated as needed) | ||||
| 	var vAddr reflect.Value | ||||
| 	switch { | ||||
| 	case isNew: | ||||
| 		vAddr = reflect.New(vVal.Type().Elem()) | ||||
| 	case isDeref && !isNew: | ||||
| 		vAddr = vVal | ||||
| 	default: | ||||
| 		vAddr = vVal.Addr() | ||||
| 	} | ||||
| 	vAddrI := vAddr.Interface() | ||||
| 	err, ok := error(nil), false | ||||
| 	for _, s := range setters { | ||||
| 		err = s(vAddrI, blankValue, value, t) | ||||
| 		if err == nil { | ||||
| 			ok = true | ||||
| 			break | ||||
| 		} | ||||
| 		if err != errUnsupportedType { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if !ok { | ||||
| 		// in case all setters returned errUnsupportedType | ||||
| 		return err | ||||
| 	} | ||||
| 	if isNew { // set reference if it was dereferenced and newly allocated | ||||
| 		vVal.Set(vAddr) | ||||
| 	} | ||||
| 	if isMulti { // append if multi-valued | ||||
| 		vVar.Set(reflect.Append(vVar, vVal)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										435
									
								
								vendor/github.com/src-d/gcfg/token/position.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										435
									
								
								vendor/github.com/src-d/gcfg/token/position.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,435 @@ | ||||
| // Copyright 2010 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // TODO(gri) consider making this a separate package outside the go directory. | ||||
|  | ||||
| package token | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
| // Positions | ||||
|  | ||||
| // Position describes an arbitrary source position | ||||
| // including the file, line, and column location. | ||||
| // A Position is valid if the line number is > 0. | ||||
| // | ||||
| type Position struct { | ||||
| 	Filename string // filename, if any | ||||
| 	Offset   int    // offset, starting at 0 | ||||
| 	Line     int    // line number, starting at 1 | ||||
| 	Column   int    // column number, starting at 1 (character count) | ||||
| } | ||||
|  | ||||
| // IsValid returns true if the position is valid. | ||||
| func (pos *Position) IsValid() bool { return pos.Line > 0 } | ||||
|  | ||||
| // String returns a string in one of several forms: | ||||
| // | ||||
| //	file:line:column    valid position with file name | ||||
| //	line:column         valid position without file name | ||||
| //	file                invalid position with file name | ||||
| //	-                   invalid position without file name | ||||
| // | ||||
| func (pos Position) String() string { | ||||
| 	s := pos.Filename | ||||
| 	if pos.IsValid() { | ||||
| 		if s != "" { | ||||
| 			s += ":" | ||||
| 		} | ||||
| 		s += fmt.Sprintf("%d:%d", pos.Line, pos.Column) | ||||
| 	} | ||||
| 	if s == "" { | ||||
| 		s = "-" | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // Pos is a compact encoding of a source position within a file set. | ||||
| // It can be converted into a Position for a more convenient, but much | ||||
| // larger, representation. | ||||
| // | ||||
| // The Pos value for a given file is a number in the range [base, base+size], | ||||
| // where base and size are specified when adding the file to the file set via | ||||
| // AddFile. | ||||
| // | ||||
| // To create the Pos value for a specific source offset, first add | ||||
| // the respective file to the current file set (via FileSet.AddFile) | ||||
| // and then call File.Pos(offset) for that file. Given a Pos value p | ||||
| // for a specific file set fset, the corresponding Position value is | ||||
| // obtained by calling fset.Position(p). | ||||
| // | ||||
| // Pos values can be compared directly with the usual comparison operators: | ||||
| // If two Pos values p and q are in the same file, comparing p and q is | ||||
| // equivalent to comparing the respective source file offsets. If p and q | ||||
| // are in different files, p < q is true if the file implied by p was added | ||||
| // to the respective file set before the file implied by q. | ||||
| // | ||||
| type Pos int | ||||
|  | ||||
| // The zero value for Pos is NoPos; there is no file and line information | ||||
| // associated with it, and NoPos().IsValid() is false. NoPos is always | ||||
| // smaller than any other Pos value. The corresponding Position value | ||||
| // for NoPos is the zero value for Position. | ||||
| // | ||||
| const NoPos Pos = 0 | ||||
|  | ||||
| // IsValid returns true if the position is valid. | ||||
| func (p Pos) IsValid() bool { | ||||
| 	return p != NoPos | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
| // File | ||||
|  | ||||
| // A File is a handle for a file belonging to a FileSet. | ||||
| // A File has a name, size, and line offset table. | ||||
| // | ||||
| type File struct { | ||||
| 	set  *FileSet | ||||
| 	name string // file name as provided to AddFile | ||||
| 	base int    // Pos value range for this file is [base...base+size] | ||||
| 	size int    // file size as provided to AddFile | ||||
|  | ||||
| 	// lines and infos are protected by set.mutex | ||||
| 	lines []int | ||||
| 	infos []lineInfo | ||||
| } | ||||
|  | ||||
| // Name returns the file name of file f as registered with AddFile. | ||||
| func (f *File) Name() string { | ||||
| 	return f.name | ||||
| } | ||||
|  | ||||
| // Base returns the base offset of file f as registered with AddFile. | ||||
| func (f *File) Base() int { | ||||
| 	return f.base | ||||
| } | ||||
|  | ||||
| // Size returns the size of file f as registered with AddFile. | ||||
| func (f *File) Size() int { | ||||
| 	return f.size | ||||
| } | ||||
|  | ||||
| // LineCount returns the number of lines in file f. | ||||
| func (f *File) LineCount() int { | ||||
| 	f.set.mutex.RLock() | ||||
| 	n := len(f.lines) | ||||
| 	f.set.mutex.RUnlock() | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| // AddLine adds the line offset for a new line. | ||||
| // The line offset must be larger than the offset for the previous line | ||||
| // and smaller than the file size; otherwise the line offset is ignored. | ||||
| // | ||||
| func (f *File) AddLine(offset int) { | ||||
| 	f.set.mutex.Lock() | ||||
| 	if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset < f.size { | ||||
| 		f.lines = append(f.lines, offset) | ||||
| 	} | ||||
| 	f.set.mutex.Unlock() | ||||
| } | ||||
|  | ||||
| // SetLines sets the line offsets for a file and returns true if successful. | ||||
| // The line offsets are the offsets of the first character of each line; | ||||
| // for instance for the content "ab\nc\n" the line offsets are {0, 3}. | ||||
| // An empty file has an empty line offset table. | ||||
| // Each line offset must be larger than the offset for the previous line | ||||
| // and smaller than the file size; otherwise SetLines fails and returns | ||||
| // false. | ||||
| // | ||||
| func (f *File) SetLines(lines []int) bool { | ||||
| 	// verify validity of lines table | ||||
| 	size := f.size | ||||
| 	for i, offset := range lines { | ||||
| 		if i > 0 && offset <= lines[i-1] || size <= offset { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// set lines table | ||||
| 	f.set.mutex.Lock() | ||||
| 	f.lines = lines | ||||
| 	f.set.mutex.Unlock() | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // SetLinesForContent sets the line offsets for the given file content. | ||||
| func (f *File) SetLinesForContent(content []byte) { | ||||
| 	var lines []int | ||||
| 	line := 0 | ||||
| 	for offset, b := range content { | ||||
| 		if line >= 0 { | ||||
| 			lines = append(lines, line) | ||||
| 		} | ||||
| 		line = -1 | ||||
| 		if b == '\n' { | ||||
| 			line = offset + 1 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// set lines table | ||||
| 	f.set.mutex.Lock() | ||||
| 	f.lines = lines | ||||
| 	f.set.mutex.Unlock() | ||||
| } | ||||
|  | ||||
| // A lineInfo object describes alternative file and line number | ||||
| // information (such as provided via a //line comment in a .go | ||||
| // file) for a given file offset. | ||||
| type lineInfo struct { | ||||
| 	// fields are exported to make them accessible to gob | ||||
| 	Offset   int | ||||
| 	Filename string | ||||
| 	Line     int | ||||
| } | ||||
|  | ||||
| // AddLineInfo adds alternative file and line number information for | ||||
| // a given file offset. The offset must be larger than the offset for | ||||
| // the previously added alternative line info and smaller than the | ||||
| // file size; otherwise the information is ignored. | ||||
| // | ||||
| // AddLineInfo is typically used to register alternative position | ||||
| // information for //line filename:line comments in source files. | ||||
| // | ||||
| func (f *File) AddLineInfo(offset int, filename string, line int) { | ||||
| 	f.set.mutex.Lock() | ||||
| 	if i := len(f.infos); i == 0 || f.infos[i-1].Offset < offset && offset < f.size { | ||||
| 		f.infos = append(f.infos, lineInfo{offset, filename, line}) | ||||
| 	} | ||||
| 	f.set.mutex.Unlock() | ||||
| } | ||||
|  | ||||
| // Pos returns the Pos value for the given file offset; | ||||
| // the offset must be <= f.Size(). | ||||
| // f.Pos(f.Offset(p)) == p. | ||||
| // | ||||
| func (f *File) Pos(offset int) Pos { | ||||
| 	if offset > f.size { | ||||
| 		panic("illegal file offset") | ||||
| 	} | ||||
| 	return Pos(f.base + offset) | ||||
| } | ||||
|  | ||||
| // Offset returns the offset for the given file position p; | ||||
| // p must be a valid Pos value in that file. | ||||
| // f.Offset(f.Pos(offset)) == offset. | ||||
| // | ||||
| func (f *File) Offset(p Pos) int { | ||||
| 	if int(p) < f.base || int(p) > f.base+f.size { | ||||
| 		panic("illegal Pos value") | ||||
| 	} | ||||
| 	return int(p) - f.base | ||||
| } | ||||
|  | ||||
| // Line returns the line number for the given file position p; | ||||
| // p must be a Pos value in that file or NoPos. | ||||
| // | ||||
| func (f *File) Line(p Pos) int { | ||||
| 	// TODO(gri) this can be implemented much more efficiently | ||||
| 	return f.Position(p).Line | ||||
| } | ||||
|  | ||||
| func searchLineInfos(a []lineInfo, x int) int { | ||||
| 	return sort.Search(len(a), func(i int) bool { return a[i].Offset > x }) - 1 | ||||
| } | ||||
|  | ||||
| // info returns the file name, line, and column number for a file offset. | ||||
| func (f *File) info(offset int) (filename string, line, column int) { | ||||
| 	filename = f.name | ||||
| 	if i := searchInts(f.lines, offset); i >= 0 { | ||||
| 		line, column = i+1, offset-f.lines[i]+1 | ||||
| 	} | ||||
| 	if len(f.infos) > 0 { | ||||
| 		// almost no files have extra line infos | ||||
| 		if i := searchLineInfos(f.infos, offset); i >= 0 { | ||||
| 			alt := &f.infos[i] | ||||
| 			filename = alt.Filename | ||||
| 			if i := searchInts(f.lines, alt.Offset); i >= 0 { | ||||
| 				line += alt.Line - i - 1 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (f *File) position(p Pos) (pos Position) { | ||||
| 	offset := int(p) - f.base | ||||
| 	pos.Offset = offset | ||||
| 	pos.Filename, pos.Line, pos.Column = f.info(offset) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Position returns the Position value for the given file position p; | ||||
| // p must be a Pos value in that file or NoPos. | ||||
| // | ||||
| func (f *File) Position(p Pos) (pos Position) { | ||||
| 	if p != NoPos { | ||||
| 		if int(p) < f.base || int(p) > f.base+f.size { | ||||
| 			panic("illegal Pos value") | ||||
| 		} | ||||
| 		pos = f.position(p) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
| // FileSet | ||||
|  | ||||
| // A FileSet represents a set of source files. | ||||
| // Methods of file sets are synchronized; multiple goroutines | ||||
| // may invoke them concurrently. | ||||
| // | ||||
| type FileSet struct { | ||||
| 	mutex sync.RWMutex // protects the file set | ||||
| 	base  int          // base offset for the next file | ||||
| 	files []*File      // list of files in the order added to the set | ||||
| 	last  *File        // cache of last file looked up | ||||
| } | ||||
|  | ||||
| // NewFileSet creates a new file set. | ||||
| func NewFileSet() *FileSet { | ||||
| 	s := new(FileSet) | ||||
| 	s.base = 1 // 0 == NoPos | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // Base returns the minimum base offset that must be provided to | ||||
| // AddFile when adding the next file. | ||||
| // | ||||
| func (s *FileSet) Base() int { | ||||
| 	s.mutex.RLock() | ||||
| 	b := s.base | ||||
| 	s.mutex.RUnlock() | ||||
| 	return b | ||||
|  | ||||
| } | ||||
|  | ||||
| // AddFile adds a new file with a given filename, base offset, and file size | ||||
| // to the file set s and returns the file. Multiple files may have the same | ||||
| // name. The base offset must not be smaller than the FileSet's Base(), and | ||||
| // size must not be negative. | ||||
| // | ||||
| // Adding the file will set the file set's Base() value to base + size + 1 | ||||
| // as the minimum base value for the next file. The following relationship | ||||
| // exists between a Pos value p for a given file offset offs: | ||||
| // | ||||
| //	int(p) = base + offs | ||||
| // | ||||
| // with offs in the range [0, size] and thus p in the range [base, base+size]. | ||||
| // For convenience, File.Pos may be used to create file-specific position | ||||
| // values from a file offset. | ||||
| // | ||||
| func (s *FileSet) AddFile(filename string, base, size int) *File { | ||||
| 	s.mutex.Lock() | ||||
| 	defer s.mutex.Unlock() | ||||
| 	if base < s.base || size < 0 { | ||||
| 		panic("illegal base or size") | ||||
| 	} | ||||
| 	// base >= s.base && size >= 0 | ||||
| 	f := &File{s, filename, base, size, []int{0}, nil} | ||||
| 	base += size + 1 // +1 because EOF also has a position | ||||
| 	if base < 0 { | ||||
| 		panic("token.Pos offset overflow (> 2G of source code in file set)") | ||||
| 	} | ||||
| 	// add the file to the file set | ||||
| 	s.base = base | ||||
| 	s.files = append(s.files, f) | ||||
| 	s.last = f | ||||
| 	return f | ||||
| } | ||||
|  | ||||
| // Iterate calls f for the files in the file set in the order they were added | ||||
| // until f returns false. | ||||
| // | ||||
| func (s *FileSet) Iterate(f func(*File) bool) { | ||||
| 	for i := 0; ; i++ { | ||||
| 		var file *File | ||||
| 		s.mutex.RLock() | ||||
| 		if i < len(s.files) { | ||||
| 			file = s.files[i] | ||||
| 		} | ||||
| 		s.mutex.RUnlock() | ||||
| 		if file == nil || !f(file) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func searchFiles(a []*File, x int) int { | ||||
| 	return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1 | ||||
| } | ||||
|  | ||||
| func (s *FileSet) file(p Pos) *File { | ||||
| 	// common case: p is in last file | ||||
| 	if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size { | ||||
| 		return f | ||||
| 	} | ||||
| 	// p is not in last file - search all files | ||||
| 	if i := searchFiles(s.files, int(p)); i >= 0 { | ||||
| 		f := s.files[i] | ||||
| 		// f.base <= int(p) by definition of searchFiles | ||||
| 		if int(p) <= f.base+f.size { | ||||
| 			s.last = f | ||||
| 			return f | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // File returns the file that contains the position p. | ||||
| // If no such file is found (for instance for p == NoPos), | ||||
| // the result is nil. | ||||
| // | ||||
| func (s *FileSet) File(p Pos) (f *File) { | ||||
| 	if p != NoPos { | ||||
| 		s.mutex.RLock() | ||||
| 		f = s.file(p) | ||||
| 		s.mutex.RUnlock() | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Position converts a Pos in the fileset into a general Position. | ||||
| func (s *FileSet) Position(p Pos) (pos Position) { | ||||
| 	if p != NoPos { | ||||
| 		s.mutex.RLock() | ||||
| 		if f := s.file(p); f != nil { | ||||
| 			pos = f.position(p) | ||||
| 		} | ||||
| 		s.mutex.RUnlock() | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
| // Helper functions | ||||
|  | ||||
| func searchInts(a []int, x int) int { | ||||
| 	// This function body is a manually inlined version of: | ||||
| 	// | ||||
| 	//   return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1 | ||||
| 	// | ||||
| 	// With better compiler optimizations, this may not be needed in the | ||||
| 	// future, but at the moment this change improves the go/printer | ||||
| 	// benchmark performance by ~30%. This has a direct impact on the | ||||
| 	// speed of gofmt and thus seems worthwhile (2011-04-29). | ||||
| 	// TODO(gri): Remove this when compilers have caught up. | ||||
| 	i, j := 0, len(a) | ||||
| 	for i < j { | ||||
| 		h := i + (j-i)/2 // avoid overflow when computing h | ||||
| 		// i ≤ h < j | ||||
| 		if a[h] <= x { | ||||
| 			i = h + 1 | ||||
| 		} else { | ||||
| 			j = h | ||||
| 		} | ||||
| 	} | ||||
| 	return i - 1 | ||||
| } | ||||
							
								
								
									
										56
									
								
								vendor/github.com/src-d/gcfg/token/serialize.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/src-d/gcfg/token/serialize.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| // Copyright 2011 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package token | ||||
|  | ||||
| type serializedFile struct { | ||||
| 	// fields correspond 1:1 to fields with same (lower-case) name in File | ||||
| 	Name  string | ||||
| 	Base  int | ||||
| 	Size  int | ||||
| 	Lines []int | ||||
| 	Infos []lineInfo | ||||
| } | ||||
|  | ||||
| type serializedFileSet struct { | ||||
| 	Base  int | ||||
| 	Files []serializedFile | ||||
| } | ||||
|  | ||||
| // Read calls decode to deserialize a file set into s; s must not be nil. | ||||
| func (s *FileSet) Read(decode func(interface{}) error) error { | ||||
| 	var ss serializedFileSet | ||||
| 	if err := decode(&ss); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	s.mutex.Lock() | ||||
| 	s.base = ss.Base | ||||
| 	files := make([]*File, len(ss.Files)) | ||||
| 	for i := 0; i < len(ss.Files); i++ { | ||||
| 		f := &ss.Files[i] | ||||
| 		files[i] = &File{s, f.Name, f.Base, f.Size, f.Lines, f.Infos} | ||||
| 	} | ||||
| 	s.files = files | ||||
| 	s.last = nil | ||||
| 	s.mutex.Unlock() | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Write calls encode to serialize the file set s. | ||||
| func (s *FileSet) Write(encode func(interface{}) error) error { | ||||
| 	var ss serializedFileSet | ||||
|  | ||||
| 	s.mutex.Lock() | ||||
| 	ss.Base = s.base | ||||
| 	files := make([]serializedFile, len(s.files)) | ||||
| 	for i, f := range s.files { | ||||
| 		files[i] = serializedFile{f.name, f.base, f.size, f.lines, f.infos} | ||||
| 	} | ||||
| 	ss.Files = files | ||||
| 	s.mutex.Unlock() | ||||
|  | ||||
| 	return encode(ss) | ||||
| } | ||||
							
								
								
									
										83
									
								
								vendor/github.com/src-d/gcfg/token/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								vendor/github.com/src-d/gcfg/token/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Package token defines constants representing the lexical tokens of the gcfg | ||||
| // configuration syntax and basic operations on tokens (printing, predicates). | ||||
| // | ||||
| // Note that the API for the token package may change to accommodate new | ||||
| // features or implementation changes in gcfg. | ||||
| // | ||||
| package token | ||||
|  | ||||
| import "strconv" | ||||
|  | ||||
| // Token is the set of lexical tokens of the gcfg configuration syntax. | ||||
| type Token int | ||||
|  | ||||
| // The list of tokens. | ||||
| const ( | ||||
| 	// Special tokens | ||||
| 	ILLEGAL Token = iota | ||||
| 	EOF | ||||
| 	COMMENT | ||||
|  | ||||
| 	literal_beg | ||||
| 	// Identifiers and basic type literals | ||||
| 	// (these tokens stand for classes of literals) | ||||
| 	IDENT  // section-name, variable-name | ||||
| 	STRING // "subsection-name", variable value | ||||
| 	literal_end | ||||
|  | ||||
| 	operator_beg | ||||
| 	// Operators and delimiters | ||||
| 	ASSIGN // = | ||||
| 	LBRACK // [ | ||||
| 	RBRACK // ] | ||||
| 	EOL    // \n | ||||
| 	operator_end | ||||
| ) | ||||
|  | ||||
| var tokens = [...]string{ | ||||
| 	ILLEGAL: "ILLEGAL", | ||||
|  | ||||
| 	EOF:     "EOF", | ||||
| 	COMMENT: "COMMENT", | ||||
|  | ||||
| 	IDENT:  "IDENT", | ||||
| 	STRING: "STRING", | ||||
|  | ||||
| 	ASSIGN: "=", | ||||
| 	LBRACK: "[", | ||||
| 	RBRACK: "]", | ||||
| 	EOL:    "\n", | ||||
| } | ||||
|  | ||||
| // String returns the string corresponding to the token tok. | ||||
| // For operators and delimiters, the string is the actual token character | ||||
| // sequence (e.g., for the token ASSIGN, the string is "="). For all other | ||||
| // tokens the string corresponds to the token constant name (e.g. for the | ||||
| // token IDENT, the string is "IDENT"). | ||||
| // | ||||
| func (tok Token) String() string { | ||||
| 	s := "" | ||||
| 	if 0 <= tok && tok < Token(len(tokens)) { | ||||
| 		s = tokens[tok] | ||||
| 	} | ||||
| 	if s == "" { | ||||
| 		s = "token(" + strconv.Itoa(int(tok)) + ")" | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // Predicates | ||||
|  | ||||
| // IsLiteral returns true for tokens corresponding to identifiers | ||||
| // and basic type literals; it returns false otherwise. | ||||
| // | ||||
| func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end } | ||||
|  | ||||
| // IsOperator returns true for tokens corresponding to operators and | ||||
| // delimiters; it returns false otherwise. | ||||
| // | ||||
| func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end } | ||||
							
								
								
									
										23
									
								
								vendor/github.com/src-d/gcfg/types/bool.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/src-d/gcfg/types/bool.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| package types | ||||
|  | ||||
| // BoolValues defines the name and value mappings for ParseBool. | ||||
| var BoolValues = map[string]interface{}{ | ||||
| 	"true": true, "yes": true, "on": true, "1": true, | ||||
| 	"false": false, "no": false, "off": false, "0": false, | ||||
| } | ||||
|  | ||||
| var boolParser = func() *EnumParser { | ||||
| 	ep := &EnumParser{} | ||||
| 	ep.AddVals(BoolValues) | ||||
| 	return ep | ||||
| }() | ||||
|  | ||||
| // ParseBool parses bool values according to the definitions in BoolValues. | ||||
| // Parsing is case-insensitive. | ||||
| func ParseBool(s string) (bool, error) { | ||||
| 	v, err := boolParser.Parse(s) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	return v.(bool), nil | ||||
| } | ||||
							
								
								
									
										4
									
								
								vendor/github.com/src-d/gcfg/types/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/src-d/gcfg/types/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| // Package types defines helpers for type conversions. | ||||
| // | ||||
| // The API for this package is not finalized yet. | ||||
| package types | ||||
							
								
								
									
										44
									
								
								vendor/github.com/src-d/gcfg/types/enum.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/src-d/gcfg/types/enum.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| package types | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // EnumParser parses "enum" values; i.e. a predefined set of strings to | ||||
| // predefined values. | ||||
| type EnumParser struct { | ||||
| 	Type      string // type name; if not set, use type of first value added | ||||
| 	CaseMatch bool   // if true, matching of strings is case-sensitive | ||||
| 	// PrefixMatch bool | ||||
| 	vals map[string]interface{} | ||||
| } | ||||
|  | ||||
| // AddVals adds strings and values to an EnumParser. | ||||
| func (ep *EnumParser) AddVals(vals map[string]interface{}) { | ||||
| 	if ep.vals == nil { | ||||
| 		ep.vals = make(map[string]interface{}) | ||||
| 	} | ||||
| 	for k, v := range vals { | ||||
| 		if ep.Type == "" { | ||||
| 			ep.Type = reflect.TypeOf(v).Name() | ||||
| 		} | ||||
| 		if !ep.CaseMatch { | ||||
| 			k = strings.ToLower(k) | ||||
| 		} | ||||
| 		ep.vals[k] = v | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Parse parses the string and returns the value or an error. | ||||
| func (ep EnumParser) Parse(s string) (interface{}, error) { | ||||
| 	if !ep.CaseMatch { | ||||
| 		s = strings.ToLower(s) | ||||
| 	} | ||||
| 	v, ok := ep.vals[s] | ||||
| 	if !ok { | ||||
| 		return false, fmt.Errorf("failed to parse %s %#q", ep.Type, s) | ||||
| 	} | ||||
| 	return v, nil | ||||
| } | ||||
							
								
								
									
										86
									
								
								vendor/github.com/src-d/gcfg/types/int.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/src-d/gcfg/types/int.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| package types | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // An IntMode is a mode for parsing integer values, representing a set of | ||||
| // accepted bases. | ||||
| type IntMode uint8 | ||||
|  | ||||
| // IntMode values for ParseInt; can be combined using binary or. | ||||
| const ( | ||||
| 	Dec IntMode = 1 << iota | ||||
| 	Hex | ||||
| 	Oct | ||||
| ) | ||||
|  | ||||
| // String returns a string representation of IntMode; e.g. `IntMode(Dec|Hex)`. | ||||
| func (m IntMode) String() string { | ||||
| 	var modes []string | ||||
| 	if m&Dec != 0 { | ||||
| 		modes = append(modes, "Dec") | ||||
| 	} | ||||
| 	if m&Hex != 0 { | ||||
| 		modes = append(modes, "Hex") | ||||
| 	} | ||||
| 	if m&Oct != 0 { | ||||
| 		modes = append(modes, "Oct") | ||||
| 	} | ||||
| 	return "IntMode(" + strings.Join(modes, "|") + ")" | ||||
| } | ||||
|  | ||||
| var errIntAmbig = fmt.Errorf("ambiguous integer value; must include '0' prefix") | ||||
|  | ||||
| func prefix0(val string) bool { | ||||
| 	return strings.HasPrefix(val, "0") || strings.HasPrefix(val, "-0") | ||||
| } | ||||
|  | ||||
| func prefix0x(val string) bool { | ||||
| 	return strings.HasPrefix(val, "0x") || strings.HasPrefix(val, "-0x") | ||||
| } | ||||
|  | ||||
| // ParseInt parses val using mode into intptr, which must be a pointer to an | ||||
| // integer kind type. Non-decimal value require prefix `0` or `0x` in the cases | ||||
| // when mode permits ambiguity of base; otherwise the prefix can be omitted. | ||||
| func ParseInt(intptr interface{}, val string, mode IntMode) error { | ||||
| 	val = strings.TrimSpace(val) | ||||
| 	verb := byte(0) | ||||
| 	switch mode { | ||||
| 	case Dec: | ||||
| 		verb = 'd' | ||||
| 	case Dec + Hex: | ||||
| 		if prefix0x(val) { | ||||
| 			verb = 'v' | ||||
| 		} else { | ||||
| 			verb = 'd' | ||||
| 		} | ||||
| 	case Dec + Oct: | ||||
| 		if prefix0(val) && !prefix0x(val) { | ||||
| 			verb = 'v' | ||||
| 		} else { | ||||
| 			verb = 'd' | ||||
| 		} | ||||
| 	case Dec + Hex + Oct: | ||||
| 		verb = 'v' | ||||
| 	case Hex: | ||||
| 		if prefix0x(val) { | ||||
| 			verb = 'v' | ||||
| 		} else { | ||||
| 			verb = 'x' | ||||
| 		} | ||||
| 	case Oct: | ||||
| 		verb = 'o' | ||||
| 	case Hex + Oct: | ||||
| 		if prefix0(val) { | ||||
| 			verb = 'v' | ||||
| 		} else { | ||||
| 			return errIntAmbig | ||||
| 		} | ||||
| 	} | ||||
| 	if verb == 0 { | ||||
| 		panic("unsupported mode") | ||||
| 	} | ||||
| 	return ScanFully(intptr, val, verb) | ||||
| } | ||||
							
								
								
									
										23
									
								
								vendor/github.com/src-d/gcfg/types/scan.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/src-d/gcfg/types/scan.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| package types | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"reflect" | ||||
| ) | ||||
|  | ||||
| // ScanFully uses fmt.Sscanf with verb to fully scan val into ptr. | ||||
| func ScanFully(ptr interface{}, val string, verb byte) error { | ||||
| 	t := reflect.ValueOf(ptr).Elem().Type() | ||||
| 	// attempt to read extra bytes to make sure the value is consumed | ||||
| 	var b []byte | ||||
| 	n, err := fmt.Sscanf(val, "%"+string(verb)+"%s", ptr, &b) | ||||
| 	switch { | ||||
| 	case n < 1 || n == 1 && err != io.EOF: | ||||
| 		return fmt.Errorf("failed to parse %q as %v: %v", val, t, err) | ||||
| 	case n > 1: | ||||
| 		return fmt.Errorf("failed to parse %q as %v: extra characters %q", val, t, string(b)) | ||||
| 	} | ||||
| 	// n == 1 && err == io.EOF | ||||
| 	return nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Lunny Xiao
					Lunny Xiao