mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 12:12:25 -05:00 
			
		
		
		
	
		
			
	
	
		
			156 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			156 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | // Package opt implements command-line flag parsing. | ||
|  | package opt // import "modernc.org/opt" | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"fmt" | ||
|  | 	"strings" | ||
|  | ) | ||
|  | 
 | ||
|  | type opt struct { | ||
|  | 	handler func(opt, arg string) error | ||
|  | 	name    string | ||
|  | 
 | ||
|  | 	arg bool // Enable argument, e.g. `-I foo` or `-I=foo` | ||
|  | } | ||
|  | 
 | ||
|  | // A Set represents a set of defined options. | ||
|  | type Set struct { | ||
|  | 	cfg map[string]*opt | ||
|  | 	imm []*opt | ||
|  | } | ||
|  | 
 | ||
|  | // NewSet returns a new, empty option set. | ||
|  | func NewSet() *Set { return &Set{cfg: map[string]*opt{}} } | ||
|  | 
 | ||
|  | // Opt defines a simple option, e.g. `-f`. When the option is found during | ||
|  | // Parse, the handler is called with the value of the option, e.g. "-f". | ||
|  | func (p *Set) Opt(name string, handler func(opt string) error) { | ||
|  | 	p.cfg[name] = &opt{ | ||
|  | 		handler: func(opt, arg string) error { return handler(opt) }, | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // Arg defines a simple option with an argument, e.g. `-I foo` or `-I=foo`. | ||
|  | // Setting imm argument enables additionally `-Ifoo`. When the option is found | ||
|  | // during Parse, the handler is called with the values of the option and the | ||
|  | // argument, e.g. "-I" and "foo" for all of the variants. | ||
|  | func (p *Set) Arg(name string, imm bool, handler func(opt, arg string) error) { | ||
|  | 	switch { | ||
|  | 	case imm: | ||
|  | 		p.imm = append(p.imm, &opt{ | ||
|  | 			handler: handler, | ||
|  | 			name:    name, | ||
|  | 		}) | ||
|  | 	default: | ||
|  | 		p.cfg[name] = &opt{ | ||
|  | 			arg:     true, | ||
|  | 			handler: handler, | ||
|  | 			name:    name, | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // Parse parses opts. Must be called after all options are defined. The handler | ||
|  | // is called for all items in opts that were not defined before using Opt or | ||
|  | // Arg. | ||
|  | // | ||
|  | // If any handler returns a non-nil error, Parse will stop.  If the error is of | ||
|  | // type Skip, the error returned by Parse will contain all the unprocessed | ||
|  | // items of opts. | ||
|  | // | ||
|  | // The opts slice must not be modified by any handler while Parser is | ||
|  | // executing. | ||
|  | func (p *Set) Parse(opts []string, handler func(string) error) (err error) { | ||
|  | 	defer func() { | ||
|  | 		switch err.(type) { | ||
|  | 		case Skip: | ||
|  | 			err = Skip(opts) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	for len(opts) != 0 { | ||
|  | 		opt := opts[0] | ||
|  | 		opt0 := opt | ||
|  | 		opts = opts[1:] | ||
|  | 		var arg string | ||
|  | 	out: | ||
|  | 		switch { | ||
|  | 		case strings.HasPrefix(opt, "-"): | ||
|  | 			name := opt[1:] | ||
|  | 			for _, cfg := range p.imm { | ||
|  | 				if strings.HasPrefix(name, cfg.name) { | ||
|  | 					switch { | ||
|  | 					case name == cfg.name: | ||
|  | 						if len(opts) == 0 { | ||
|  | 							return fmt.Errorf("missing argument of %s", opt) | ||
|  | 						} | ||
|  | 
 | ||
|  | 						if err = cfg.handler(opt, opts[0]); err != nil { | ||
|  | 							return err | ||
|  | 						} | ||
|  | 
 | ||
|  | 						opts = opts[1:] | ||
|  | 					default: | ||
|  | 						opt = opt[:len(cfg.name)+1] | ||
|  | 						val := strings.TrimPrefix(name[len(cfg.name):], "=") | ||
|  | 						if err = cfg.handler(opt, val); err != nil { | ||
|  | 							return err | ||
|  | 						} | ||
|  | 					} | ||
|  | 					break out | ||
|  | 				} | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if n := strings.IndexByte(opt, '='); n > 0 { | ||
|  | 				arg = opt[n+1:] | ||
|  | 				name = opt[1:n] | ||
|  | 				opt = opt[:n] | ||
|  | 			} | ||
|  | 			switch cfg := p.cfg[name]; { | ||
|  | 			case cfg == nil: | ||
|  | 				if err = handler(opt0); err != nil { | ||
|  | 					return err | ||
|  | 				} | ||
|  | 			default: | ||
|  | 				switch { | ||
|  | 				case cfg.arg: | ||
|  | 					switch { | ||
|  | 					case arg != "": | ||
|  | 						if err = cfg.handler(opt, arg); err != nil { | ||
|  | 							return err | ||
|  | 						} | ||
|  | 					default: | ||
|  | 						if len(opts) == 0 { | ||
|  | 							return fmt.Errorf("missing argument of %s", opt) | ||
|  | 						} | ||
|  | 
 | ||
|  | 						if err = cfg.handler(opt, opts[0]); err != nil { | ||
|  | 							return err | ||
|  | 						} | ||
|  | 
 | ||
|  | 						opts = opts[1:] | ||
|  | 					} | ||
|  | 				default: | ||
|  | 					if err = cfg.handler(opt, ""); err != nil { | ||
|  | 						return err | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			if opt == "" { | ||
|  | 				break | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if err = handler(opt); err != nil { | ||
|  | 				return err | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return nil | ||
|  | } | ||
|  | 
 | ||
|  | // Skip is an error that contains all unprocessed items passed to Parse. | ||
|  | type Skip []string | ||
|  | 
 | ||
|  | func (s Skip) Error() string { return fmt.Sprint([]string(s)) } |