github.com/bhameyie/otto@v0.2.1-0.20160406174117-16052efa52ec/helper/flag/flag.go (about) 1 package flag 2 3 import ( 4 "flag" 5 ) 6 7 // FilterArgs filters the args slice to only include the the flags 8 // in the given flagset and returns a new arg slice that has the 9 // included args as well as a slice that has only the excluded args. 10 // The final returned slice is the positional arguments. 11 func FilterArgs(fs *flag.FlagSet, args []string) ([]string, []string, []string) { 12 // Optimistically make all the length of the arguments. There 13 // should never be so many arguments that this is too ineffecient. 14 inc := make([]string, 0, len(args)) 15 exc := make([]string, 0, len(args)) 16 pos := make([]string, 0, len(args)) 17 18 // Make a map of the valid flags 19 flags := make(map[string]struct{}) 20 fs.VisitAll(func(f *flag.Flag) { 21 flags[f.Name] = struct{}{} 22 }) 23 24 // Go through each, parse out a single argument, and determine where 25 // it should go plus how many of the slots. 26 i := 0 27 for i < len(args) { 28 n, loc := filterOne(flags, args, i) 29 30 // Determine what slice to add the values to 31 var result *[]string 32 switch loc { 33 case filterLocBoth: 34 result = &pos 35 case filterLocInc: 36 result = &inc 37 case filterLocExc: 38 result = &exc 39 } 40 41 // Copy the values 42 *result = append(*result, args[i:i+n]...) 43 44 // Increment i so we continue moving through the arguments 45 i += n 46 } 47 48 return inc, exc, pos 49 } 50 51 type filterLoc byte 52 53 const ( 54 filterLocBoth filterLoc = iota 55 filterLocInc 56 filterLocExc 57 ) 58 59 // filterOne is based very heavily on the official flag package 60 // "parseOne" function. We do this on purpose so that we parse things 61 // as similarly as possible in order to split the args. 62 func filterOne(flags map[string]struct{}, args []string, i int) (int, filterLoc) { 63 // Get the arg 64 s := args[i] 65 if s == "-h" || s == "--help" { 66 return 1, filterLocInc 67 } 68 69 // If the arg is empty, not a flag, or just a "-" then we have to 70 // add it to BOTH lists. 71 if len(s) == 0 || s[0] != '-' || len(s) == 1 { 72 return 1, filterLocBoth 73 } 74 75 // If we hit double minuses, then we return the rest of the args to 76 // BOTH lists. 77 num_minuses := 1 78 if s[1] == '-' { 79 num_minuses++ 80 if len(s) == 2 { // "--" terminates the flags 81 return len(args) - i, filterLocBoth 82 } 83 } 84 85 // Otherwise, get the name. If the syntax is invalid, let's just add it 86 // to both. 87 name := s[num_minuses:] 88 if len(name) == 0 || name[0] == '-' || name[0] == '=' { 89 return 1, filterLocBoth 90 } 91 92 // Check for an argument to the flag 93 has_value := false 94 for i := 1; i < len(name); i++ { // equals cannot be first 95 if name[i] == '=' { 96 has_value = true 97 name = name[0:i] 98 break 99 } 100 } 101 102 // Determine where this will go from here on out 103 pos := filterLocInc 104 if _, valid := flags[name]; !valid { 105 pos = filterLocExc 106 } 107 108 // It must have a value, which might be the next argument. 109 if !has_value && len(args) > i+1 { 110 return 2, pos 111 } 112 113 return 1, pos 114 }