├── .github └── workflows │ ├── go-linux.yml │ ├── go-macos.yml │ └── go-windows.yml ├── .gitignore ├── LICENSE ├── README.md ├── argparser ├── constants.go ├── helpers.go ├── methods.go ├── types.go └── vars.go ├── examples ├── .gitignore └── bools │ ├── .vscode │ ├── launch.json │ └── settings.json │ ├── go.mod │ ├── go.sum.example │ └── main.go ├── go.mod ├── go.sum └── tests └── args_test.go /.github/workflows/go-linux.yml: -------------------------------------------------------------------------------- 1 | name: Go-linux 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.18 20 | 21 | - name: Test 22 | run: go test -v ./... -------------------------------------------------------------------------------- /.github/workflows/go-macos.yml: -------------------------------------------------------------------------------- 1 | name: Go-macos 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: macos-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.18 20 | 21 | - name: Test 22 | run: go test -v ./... -------------------------------------------------------------------------------- /.github/workflows/go-windows.yml: -------------------------------------------------------------------------------- 1 | name: Go-windows 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: windows-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.18 20 | 21 | - name: Test 22 | run: go test -v ./... -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .docker_build/ 3 | bin/ 4 | *.exe 5 | vendor/ 6 | sibylBinary 7 | PsychoPass 8 | sibylSystem 9 | *.old.go 10 | woto_files/ 11 | tmp_files/ 12 | labs/ 13 | *.old.go 14 | *.db 15 | *.log 16 | 17 | # ignore debug binary file 18 | __debug_bin 19 | 20 | # ignore config file 21 | config.ini 22 | *.token 23 | triggers.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2022 ALiwoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arg Parser 2 | ==================================== 3 | 4 | 5 | 6 | A rich tool for parsing flags and values in pure Golang. 7 | No additional library is required and you can use everywhere. 8 | 9 | 10 | 11 | ## Features 12 | 13 | * Supporting different formats: 14 | ```go 15 | int (int64, int32, int16, int8) 16 | uint (uint64, uint32, uint16, uint8) 17 | string // (you can easily convert any type to string) 18 | bool // yes, on, true, 1 = true; no, off, false, 0 = false 19 | ``` 20 | 21 | * Easily convert each type to another types. with only one functions. 22 | 23 | * Low time order! It's as fast as spliting two strings and then joining them together XD 24 | 25 | * Simple algorithms. You can easily read the algorithms used in this library, and you are allowed to copy and use them in your own projects (even if they are in Golang or not)! 26 | 27 | * No additional libs. You don't have to waste your time and storage for downloading another libraries and dependencies. Only this lib, will meet your needs. 28 | 29 | * Supports multi flags with the same name (Of course they have different indexes). 30 | 31 | * Rigorously tested. We are testing the lib in any possible ways. If you find out a bug, please create an issue on our [issue tracker](https://github.com/aliwoto/argparser/issues). We will check it and solve the problem 32 | 33 |
34 | 35 | ## Examples: 36 | 37 | ### parsing a command is a simple work! 38 | 39 | ```go 40 | 41 | const text = "/test --flag1 true --flag2 on" + 42 | " --flag3 false" + 43 | " --flag4 \"Hello, how are you?\"" + 44 | " --flag5 off\n\n\n\n\n\n" + 45 | " --flag6 123456789" 46 | 47 | //----------------------------------------------------- 48 | 49 | // parse it and get an *EventArgs value. 50 | args, err := argparser.ParseArg(boolTest) 51 | if err != nil { 52 | // if the format of the text is not correct, 53 | // you will get an error. 54 | // if you find out any bug here, please report us. 55 | // if the text doesn't contain ant command, you will 56 | // get error (it should start with command.) 57 | log.Fatal(err) 58 | } 59 | 60 | // check if it contains any flag with name `flag1` or not? 61 | if args.HasFlag("flag1", "anotherFlag") { 62 | // doesn't matter this 63 | log.Println("it has flag1 or anotherFlag") 64 | } 65 | 66 | // get a flag's value as bool. 67 | // if the flags are not present in EventArgs at all, 68 | // this method will return false. 69 | // if it's on, yes, true, 1 (one integer), it returns true 70 | // if it's off, no, false, 0, it returns false 71 | // if it's string, it will return true 72 | // if it doesn't have any value (empty string), it returns true 73 | // 74 | b1 := args.GetAsBool("flag1") 75 | if b1 { 76 | log.Println("it's true!") 77 | } else { 78 | log.Println("it's false!") 79 | } 80 | 81 | s1 := args.GetAsString("flag4") 82 | log.Println(s1) // Hello, how are you? 83 | 84 | // lets try more than one flag this time. 85 | // this method will search for the flags you passed to it. 86 | // if the first flag doesn't exist, it will look 87 | // for another one. 88 | // if there are no such flags at all, it will return you 89 | // `0, false` 90 | // if the first flag exists but it can't be 91 | // converted to integer, it will give you `0, false`s 92 | i1, ok := args.GetAsInteger("flag6", "flag10") 93 | if !ok { 94 | log.Println("couldn't parse flag value to integer") 95 | } else { 96 | log.Println("oh yeah, the integer value is ", i1) 97 | } 98 | 99 | ``` 100 | 101 | > need more examples? 102 | then take a look at [example directory](examples/)! 103 | 104 |
105 | 106 | ## How to get started? 107 | 108 | * Download the library with the standard go get command: 109 | 110 | `go get github.com/ALiwoto/argparser` 111 | 112 | 113 | ## Support and Contributions 114 | 115 | If you think you have found a bug or have a feature request, feel free to use our [issue tracker](https://github.com/ALiwoto/argparser/issues). Before opening a new issue, please search to see if your problem has already been reported or not. Try to be as detailed as possible in your issue reports. 116 | 117 | If you need help using argparser or have other questions we suggest you to join our [telegram community](https://t.me/chiruzon). Please do not use the GitHub issue tracker for personal support requests. 118 | 119 | 120 | ## Docs 121 | 122 | Docs can be found [here](https://pkg.go.dev/github.com/ALiwoto/argparser). 123 | > Be sure to read them carefuly! 124 | 125 | ## License 126 | 127 | The argparser project is under the [MIT License](https://opensource.org/licenses/MIT). 128 | See the [LICENSE](LICENSE) file for more details. -------------------------------------------------------------------------------- /argparser/constants.go: -------------------------------------------------------------------------------- 1 | // argparser Project 2 | // Copyright (C) 2021-2022 ALiwoto 3 | // This file is subject to the terms and conditions defined in 4 | // file 'LICENSE', which is part of the source code. 5 | 6 | package argparser 7 | 8 | const ( 9 | NoneFlagType FlagType = iota 10 | BoolFlagType 11 | StringFlagType 12 | UInt8FlagType 13 | UInt16FlagType 14 | UInt32FlagType 15 | UInt64FlagType 16 | Int8FlagType 17 | Int16FlagType 18 | Int32FlagType 19 | Int64FlagType 20 | ) 21 | 22 | const ( 23 | NoneTypeStr = "None" 24 | BoolTypeStr = "bool" 25 | StringTypeStr = "string" 26 | UInt8TypeStr = "uint8" 27 | UInt16TypeStr = "uint16" 28 | UInt32TypeStr = "uint32" 29 | UInt64TypeStr = "uint64" 30 | Int8TypeStr = "int8" 31 | Int16TypeStr = "int16" 32 | Int32TypeStr = "int32" 33 | Int64TypeStr = "int64" 34 | ) 35 | 36 | // common and global HLCs. 37 | const ( 38 | TrueHlc = "true" 39 | YesHlc = "yes" 40 | OnHlc = "on" 41 | FalseHlc = "false" 42 | NoHlc = "no" 43 | OffHlc = "off" 44 | ) 45 | -------------------------------------------------------------------------------- /argparser/helpers.go: -------------------------------------------------------------------------------- 1 | // argparser Project 2 | // Copyright (C) 2021-2022 ALiwoto 3 | // This file is subject to the terms and conditions defined in 4 | // file 'LICENSE', which is part of the source code. 5 | 6 | package argparser 7 | 8 | import ( 9 | "errors" 10 | "strings" 11 | 12 | ws "github.com/ALiwoto/ssg/ssg" 13 | ) 14 | 15 | func ParseArg(text string, prefixes []rune) (e *EventArgs, err error) { 16 | return ParseArgWithOptions(text, &ParseOptions{ 17 | Prefixes: prefixes, 18 | }) 19 | } 20 | 21 | // ParseArgWithOptions will parse the whole text into an EventArg and will return it. 22 | func ParseArgWithOptions(text string, options *ParseOptions) (e *EventArgs, err error) { 23 | if text == "" { 24 | return nil, errors.New("ParseArgWithOptions: text cannot be empty") 25 | } 26 | 27 | if options == nil { 28 | options = GetDefaultParseOptions() 29 | } 30 | 31 | if len(options.Prefixes) == 0 { 32 | options.Prefixes = DefaultPrefixes 33 | } 34 | 35 | ss := ws.Ss(text) 36 | if !ss.HasRunePrefix(options.Prefixes...) { 37 | return nil, errors.New("ParseArgWithOptions: input text is not a command") 38 | } 39 | 40 | cmdR := ss.SplitStr(ws.SPACE_VALUE) 41 | if len(cmdR) == ws.BaseIndex { 42 | return nil, errors.New("ParseArgWithOptions: unable to get the command") 43 | } 44 | 45 | cmd := cmdR[ws.BaseIndex] 46 | if cmd.IsEmpty() { 47 | return nil, errors.New("ParseArgWithOptions: length of the command cannot be zero") 48 | } 49 | 50 | cmdSs := cmd.TrimStr(toStrArray(options.Prefixes)...) 51 | if cmdSs.IsEmpty() { 52 | return nil, errors.New("ParseArgWithOptions: command cannot be only whitespace") 53 | } 54 | 55 | cmdStr := cmdSs.GetValue() 56 | 57 | e = &EventArgs{ 58 | command: cmdStr, 59 | options: options, 60 | } 61 | 62 | // lock the special characters such as "--", ":", "=". 63 | ss.LockSpecial() 64 | 65 | tmpOSs := ss.SplitStr(ws.FLAG_PREFIX) 66 | // check if we have any flags or not. 67 | // I think this is not necessary actually, 68 | // but I just added it to prevent some cases of 69 | // panics. and also it will reduce the time order 70 | // I guess. 71 | if len(tmpOSs) < ws.BaseTwoIndex { 72 | // please notice that we should send the original 73 | // text to this function. 74 | // because our locked QString contains JA characters 75 | // and should not be used here. 76 | lookRaw(&text, e) 77 | return e, nil 78 | } else { 79 | tmpFirstValue := tmpOSs[ws.BaseIndex] 80 | tmpFirstValue.UnlockSpecial() 81 | firstValue := tmpFirstValue.GetValue()[ws.BaseOneIndex:] 82 | firstValue = strings.TrimPrefix(firstValue, e.command) 83 | firstValue = strings.TrimSpace(firstValue) 84 | e.firstValue = firstValue 85 | } 86 | 87 | flagsR := tmpOSs[ws.BaseOneIndex:] 88 | // it means it has no flags available. 89 | // so return the e. 90 | if len(flagsR) == ws.BaseIndex { 91 | // please notice that we should send the original 92 | // text to this method. 93 | // because our locked QString contains JA characters 94 | // and should not be used here. 95 | lookRaw(&text, e) 96 | return e, nil 97 | } 98 | 99 | myFlags := make([]Flag, ws.BaseIndex) 100 | tmp := ws.EMPTY 101 | var tmpFlag Flag 102 | var tmpArr []ws.QString 103 | 104 | for i, current := range flagsR { 105 | tmpFlag = Flag{ 106 | index: i, 107 | } 108 | 109 | tmp = ws.EMPTY 110 | // let me explain you something here. 111 | // it really does matter how you pass these constants to this functions. 112 | // first of all should be equal. 113 | // and then double dot (':') 114 | // and in the end, it should be space. 115 | // please don't forget that you should prioritize them. 116 | tmpArr = current.SplitStrFirst(ws.EqualStr, ws.DdotSign, ws.SPACE_VALUE) 117 | 118 | tmpFlag.setNameQ(tmpArr[ws.BaseIndex]) 119 | if len(tmpArr) == ws.BaseIndex { 120 | tmpFlag.setNilValue() 121 | myFlags = append(myFlags, tmpFlag) 122 | continue 123 | } 124 | 125 | for i, ar := range tmpArr { 126 | if i == ws.BaseIndex { 127 | // ignore first slice, because it's flag name. 128 | continue 129 | } 130 | 131 | ar.UnlockSpecial() 132 | tmp += ar.GetValue() 133 | } 134 | tmpFlag.setRealValue(fixTmpStr(tmp)) 135 | 136 | myFlags = append(myFlags, tmpFlag) 137 | } 138 | 139 | e.setFlags(myFlags) 140 | 141 | return e, nil 142 | } 143 | 144 | func ParseArgDefault(text string) (e *EventArgs, err error) { 145 | return ParseArgWithOptions(text, GetDefaultParseOptions()) 146 | } 147 | 148 | func GetDefaultParseOptions() *ParseOptions { 149 | return &ParseOptions{ 150 | Prefixes: DefaultPrefixes, 151 | } 152 | } 153 | 154 | func toStrArray(r []rune) []string { 155 | var s []string 156 | for _, v := range r { 157 | s = append(s, string(v)) 158 | } 159 | s = append(s, ws.SPACE_VALUE) 160 | return s 161 | } 162 | 163 | func fixTmpStr(tmp string) string { 164 | tmp = strings.TrimSpace(tmp) 165 | if strings.HasPrefix(tmp, ws.EqualStr) { 166 | tmp = strings.TrimPrefix(tmp, ws.EqualStr) 167 | tmp = strings.TrimSpace(tmp) 168 | } 169 | tmp = strings.Trim(tmp, ws.STR_SIGN) 170 | return tmp 171 | } 172 | 173 | // look raw will look for raw data. 174 | // please use this function when and only when 175 | // no flags are provided for our commands. 176 | func lookRaw(text *string, e *EventArgs) { 177 | myStr := strings.SplitN(*text, e.command, ws.BaseTwoIndex) 178 | if len(myStr) < ws.BaseTwoIndex { 179 | return 180 | } 181 | 182 | tmp := strings.Join(myStr[ws.BaseOneIndex:], ws.EMPTY) 183 | tmp = strings.TrimSpace(tmp) 184 | 185 | e.rawData = tmp 186 | } 187 | 188 | func ToBoolType(value string) (v, isBool bool) { 189 | value = strings.TrimSpace(value) 190 | value = strings.ToLower(value) 191 | switch value { 192 | case TrueHlc, YesHlc, OnHlc: 193 | return true, true 194 | case FalseHlc, NoHlc, OffHlc: 195 | return false, true 196 | default: 197 | return false, false 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /argparser/methods.go: -------------------------------------------------------------------------------- 1 | // argparser Project 2 | // Copyright (C) 2021-2022 ALiwoto 3 | // This file is subject to the terms and conditions defined in 4 | // file 'LICENSE', which is part of the source code. 5 | 6 | package argparser 7 | 8 | import ( 9 | "strconv" 10 | "strings" 11 | 12 | ws "github.com/ALiwoto/ssg/ssg" 13 | ) 14 | 15 | //--------------------------------------------------------- 16 | 17 | func (f *Flag) setName(name string) { 18 | name = strings.TrimSpace(name) 19 | f.name = name 20 | } 21 | 22 | func (f *Flag) setNameQ(q ws.QString) { 23 | f.setName(q.GetValue()) 24 | } 25 | 26 | func (f *Flag) setNilValue() { 27 | f.value = nil 28 | f.fType = NoneFlagType 29 | } 30 | 31 | func (f *Flag) setRealValue(value string) { 32 | tmp := strings.TrimSpace(value) 33 | if len(tmp) == ws.BaseIndex { 34 | f.setAsBool(true) 35 | f.setAsEmpty() 36 | return 37 | } 38 | 39 | myI, err := strconv.ParseInt(value, ws.BaseTen, ws.Base64Bit) 40 | if err == nil { 41 | f.setAsInt(&myI) 42 | return 43 | } 44 | 45 | if tmp[ws.BaseIndex] == ws.CHAR_STR { 46 | myInt := len(tmp) - ws.BaseOneIndex 47 | if tmp[myInt] == ws.CHAR_STR { 48 | tmp = strings.TrimPrefix(tmp, ws.STR_SIGN) 49 | tmp = strings.TrimSuffix(tmp, ws.STR_SIGN) 50 | f.setAsString(&tmp) 51 | return 52 | } 53 | } 54 | 55 | v, isBool := ToBoolType(value) 56 | if isBool { 57 | f.setAsBool(v) 58 | return 59 | } 60 | 61 | f.setAsString(&value) 62 | } 63 | 64 | func (f *Flag) setAsBool(value bool) { 65 | f.value = value 66 | f.fType = BoolFlagType 67 | } 68 | 69 | func (f *Flag) setAsEmpty() { 70 | f.emptyT = true 71 | } 72 | 73 | func (f *Flag) setAsString(value *string) { 74 | f.value = *value 75 | f.fType = StringFlagType 76 | } 77 | 78 | func (f *Flag) setAsInt(value *int64) { 79 | f.value = *value 80 | f.fType = Int64FlagType 81 | } 82 | 83 | // GetValue will return you the value of this flag. 84 | // remember that value can be 85 | func (f *Flag) GetValue() interface{} { 86 | return f.value 87 | } 88 | 89 | // GetType will return you the type of 90 | // the value this flag. it's an enum. 91 | func (f *Flag) GetType() FlagType { 92 | return f.fType 93 | } 94 | 95 | // GetIndex will return you the index of this flag. 96 | // index of a flag is a unique int. 97 | // even if the name of two flags are the same, their 98 | // index will not be the same. 99 | func (f *Flag) GetIndex() int { 100 | return f.index 101 | } 102 | 103 | // GetName will give you the name of this flag. 104 | // it's not unique actually. 105 | // for example: 106 | // `/command --test "hello" --test = "HI!" 107 | func (f *Flag) GetName() string { 108 | return f.name 109 | } 110 | 111 | // GetValueAndType returns both value and type of this 112 | // flag. originally it has internal usage, but maybe 113 | // you want to use it in your own package, so I made it 114 | // public! 115 | func (f *Flag) GetValueAndType() (interface{}, FlagType) { 116 | return f.GetValue(), f.GetType() 117 | } 118 | 119 | // GetAsString will give you the value as an string. 120 | // for example if value is `true` (with flag type of 121 | // `bool`), then the string will be "true". 122 | // or if it's 10(an integer), it will give you: "10". 123 | func (f *Flag) GetAsString() string { 124 | v, t := f.GetValueAndType() 125 | if t == StringFlagType { 126 | vS, ok := v.(string) 127 | if !ok { 128 | return NoneTypeStr 129 | } 130 | 131 | return vS 132 | } 133 | 134 | if t == BoolFlagType { 135 | vB, ok := v.(bool) 136 | if !ok { 137 | return NoneTypeStr 138 | } 139 | 140 | if vB { 141 | return TrueHlc 142 | } else { 143 | return FalseHlc 144 | } 145 | } 146 | 147 | if t.IsInteger() { 148 | vI, ok := v.(int64) 149 | if !ok { 150 | return NoneTypeStr 151 | } 152 | 153 | return strconv.FormatInt(vI, ws.BaseTen) 154 | } 155 | 156 | return NoneTypeStr 157 | } 158 | 159 | func (f *Flag) isEmpty() bool { 160 | return f.emptyT || f.fType == NoneFlagType 161 | } 162 | 163 | func (f *Flag) GetAsInteger() (vI int64, ok bool) { 164 | v, t := f.GetValueAndType() 165 | if t == StringFlagType { 166 | vS, ok := v.(string) 167 | if !ok { 168 | return ws.BaseIndex, false 169 | } 170 | 171 | vS = strings.ReplaceAll(vS, ws.SPACE_VALUE, ws.EMPTY) 172 | vS = strings.ReplaceAll(vS, ws.STR_SIGN, ws.EMPTY) 173 | vI, err := strconv.ParseInt(vS, ws.BaseTen, ws.Base64Bit) 174 | if err != nil { 175 | return ws.BaseIndex, false 176 | } 177 | 178 | return vI, true 179 | } 180 | 181 | if t == BoolFlagType { 182 | vB, ok := v.(bool) 183 | if !ok { 184 | return ws.BaseIndex, false 185 | } 186 | 187 | if vB { 188 | return ws.BaseOneIndex, true 189 | } else { 190 | return ws.BaseIndex, true 191 | } 192 | } 193 | 194 | if t.IsInteger() { 195 | vI, ok := v.(int64) 196 | if !ok { 197 | return ws.BaseIndex, false 198 | } 199 | 200 | return vI, true 201 | } 202 | 203 | return ws.BaseIndex, false 204 | } 205 | 206 | func (f *Flag) GetAsBool() bool { 207 | v, t := f.GetValueAndType() 208 | if t == StringFlagType { 209 | vS, ok := v.(string) 210 | if !ok { 211 | return false 212 | } 213 | 214 | vS = strings.ReplaceAll(vS, ws.SPACE_VALUE, ws.EMPTY) 215 | vS = strings.ReplaceAll(vS, ws.STR_SIGN, ws.EMPTY) 216 | vB, ok := ToBoolType(vS) 217 | if !ok { 218 | return false 219 | } 220 | 221 | return vB 222 | } 223 | 224 | if t == BoolFlagType { 225 | vB, ok := v.(bool) 226 | if !ok { 227 | return false 228 | } 229 | 230 | return vB 231 | } 232 | 233 | if t.IsInteger() { 234 | vI, ok := v.(int64) 235 | if !ok { 236 | return false 237 | } 238 | 239 | return vI != ws.BaseIndex 240 | } 241 | 242 | return false 243 | } 244 | 245 | //--------------------------------------------------------- 246 | func (e *EventArgs) GetCommand() string { 247 | return e.command 248 | } 249 | 250 | // CompareCommand will compare the command of this event arg 251 | // with the given command. This function is case sensitive, 252 | // if you want to compare it case insensitive, then use 253 | // CheckCommand method. 254 | func (e *EventArgs) CompareCommand(cmd string) bool { 255 | cmd = strings.TrimLeft(cmd, ws.GET_SLASH) 256 | return e.command == cmd 257 | } 258 | 259 | // CheckCommand will compare the command of this event arg 260 | // with the given command. This function is case insensitive, 261 | // if you want to compare it case sensitive, then use 262 | // CompareCommand method. 263 | func (e *EventArgs) CheckCommand(cmd string) bool { 264 | cmd = strings.TrimLeft(cmd, ws.GET_SLASH) 265 | return strings.EqualFold(e.command, cmd) 266 | } 267 | 268 | func (e *EventArgs) GetFlags() []Flag { 269 | return e.flags 270 | } 271 | 272 | func (e *EventArgs) HasFlag(names ...string) bool { 273 | for _, current := range e.flags { 274 | for _, name := range names { 275 | if strings.EqualFold(current.name, name) { 276 | return true 277 | } 278 | } 279 | } 280 | 281 | return false 282 | } 283 | 284 | func (e *EventArgs) HasFlags(names ...string) bool { 285 | for _, current := range e.flags { 286 | for _, name := range names { 287 | if !strings.EqualFold(current.name, name) { 288 | return false 289 | } 290 | } 291 | } 292 | 293 | return true 294 | } 295 | 296 | func (e *EventArgs) HasRawData() bool { 297 | return !ws.IsEmpty(&e.rawData) 298 | } 299 | 300 | func (e *EventArgs) GetIndexFlag(index int) *Flag { 301 | if index < ws.BaseIndex || index >= e.GetLength() { 302 | return nil 303 | } 304 | 305 | return &e.flags[index] 306 | } 307 | 308 | func (e *EventArgs) GetFlag(names ...string) *Flag { 309 | for _, current := range e.flags { 310 | for _, name := range names { 311 | if strings.EqualFold(current.name, name) { 312 | return ¤t 313 | } 314 | } 315 | } 316 | 317 | return nil 318 | } 319 | 320 | func (e *EventArgs) GetLength() int { 321 | return len(e.flags) 322 | } 323 | 324 | func (e *EventArgs) IsEmpty() bool { 325 | return len(e.flags) == ws.BaseIndex 326 | } 327 | 328 | func (e *EventArgs) IsEmptyOrRaw() bool { 329 | return e.IsEmpty() && len(e.rawData) == ws.BaseIndex 330 | } 331 | 332 | // GetAsString will give you the string value of the flag 333 | // with the specified name. 334 | // if there is no flag with this name, or there is an 335 | // error on our path, it will return you an empty string. 336 | func (e *EventArgs) GetAsString(name ...string) string { 337 | f := e.GetFlag(name...) 338 | if f == nil { 339 | return ws.EMPTY 340 | } 341 | 342 | return f.GetAsString() 343 | } 344 | 345 | // GetAsStringOrRaw will give you the string value of the flag 346 | // with the specified name. 347 | // if there is no flag with this name, or there is an 348 | // error on our path, it will return you the raw data in the 349 | // EventArgs struct. 350 | func (e *EventArgs) GetAsStringOrRaw(name ...string) string { 351 | tmp := e.GetAsString(name...) 352 | 353 | if ws.IsEmpty(&tmp) { 354 | return e.rawData 355 | } 356 | 357 | return tmp 358 | } 359 | 360 | // GetAsString will give you the integer value of the flag 361 | // with the specified name. 362 | // if there is no flag with this name, or there is an 363 | // error on our path, it will return you zero and false. 364 | func (e *EventArgs) GetAsInteger(name ...string) (vI int64, ok bool) { 365 | f := e.GetFlag(name...) 366 | if f == nil { 367 | return ws.BaseIndex, false 368 | } 369 | 370 | return f.GetAsInteger() 371 | } 372 | 373 | // GetAsString will give you the integer value of the flag 374 | // with the specified name. 375 | // if there is no flag with this name, or there is an 376 | // error on our path, it will return you zero and false. 377 | func (e *EventArgs) GetAsIntegerOrRaw(name ...string) (vI int64, ok bool) { 378 | if e.IsEmpty() || name == nil { 379 | str := e.GetAsStringOrRaw() 380 | vI, err := strconv.ParseInt(str, ws.BaseTen, ws.Base64Bit) 381 | if err != nil { 382 | return ws.BaseIndex, false 383 | } 384 | 385 | return vI, true 386 | } else { 387 | return e.GetAsInteger(name...) 388 | } 389 | } 390 | 391 | func (e *EventArgs) GetFirstNoneEmptyValue() string { 392 | for _, current := range e.flags { 393 | if !current.isEmpty() { 394 | return current.GetAsString() 395 | } 396 | } 397 | 398 | // lets return raw data here; as it is the last resort. 399 | if e.rawData != "" { 400 | return e.rawData 401 | } 402 | 403 | return e.firstValue 404 | } 405 | 406 | // GetAsString will give you the boolean value of the flag 407 | // with the specified name. 408 | // if there is no flag with this name, or there is an 409 | // error on our path, it will return you false. 410 | func (e *EventArgs) GetAsBool(name ...string) bool { 411 | f := e.GetFlag(name...) 412 | if f == nil { 413 | return false 414 | } 415 | 416 | return f.GetAsBool() 417 | } 418 | 419 | func (e *EventArgs) setFlags(f []Flag) { 420 | e.flags = f 421 | } 422 | 423 | //--------------------------------------------------------- 424 | 425 | func (t *FlagType) ToString() string { 426 | switch *t { 427 | case NoneFlagType: 428 | return NoneTypeStr 429 | case BoolFlagType: 430 | return BoolTypeStr 431 | case StringFlagType: 432 | return StringTypeStr 433 | case UInt8FlagType: 434 | return UInt8TypeStr 435 | case UInt16FlagType: 436 | return UInt16TypeStr 437 | case UInt32FlagType: 438 | return UInt32TypeStr 439 | case UInt64FlagType: 440 | return UInt64TypeStr 441 | case Int8FlagType: 442 | return Int8TypeStr 443 | case Int16FlagType: 444 | return Int16TypeStr 445 | case Int32FlagType: 446 | return Int32TypeStr 447 | case Int64FlagType: 448 | return Int64TypeStr 449 | } 450 | 451 | return NoneTypeStr 452 | } 453 | 454 | func (t *FlagType) Compare(value *FlagType) bool { 455 | return false 456 | } 457 | 458 | func (t *FlagType) IsInteger() bool { 459 | return *t == Int8FlagType || 460 | *t == Int16FlagType || 461 | *t == Int32FlagType || 462 | *t == Int64FlagType || 463 | *t == UInt8FlagType || 464 | *t == UInt16FlagType || 465 | *t == UInt32FlagType || 466 | *t == UInt64FlagType 467 | } 468 | 469 | func (t *FlagType) IsString() bool { 470 | return *t == StringFlagType 471 | } 472 | 473 | //--------------------------------------------------------- 474 | -------------------------------------------------------------------------------- /argparser/types.go: -------------------------------------------------------------------------------- 1 | // argparser Project 2 | // Copyright (C) 2021-2022 ALiwoto 3 | // This file is subject to the terms and conditions defined in 4 | // file 'LICENSE', which is part of the source code. 5 | 6 | package argparser 7 | 8 | type FlagType uint8 9 | 10 | // Flag is the options passed along with the commands 11 | // by users. they should send them with prefix "--", 12 | // but we will remove them in the pTools. 13 | type Flag struct { 14 | name string 15 | index int 16 | value interface{} 17 | fType FlagType 18 | emptyT bool 19 | } 20 | 21 | type EventArgs struct { 22 | options *ParseOptions 23 | command string // command without '/' or '!' 24 | flags []Flag 25 | rawData string 26 | firstValue string 27 | } 28 | 29 | type ParseOptions struct { 30 | Prefixes []rune 31 | } 32 | -------------------------------------------------------------------------------- /argparser/vars.go: -------------------------------------------------------------------------------- 1 | // argparser Project 2 | // Copyright (C) 2021-2022 ALiwoto 3 | // This file is subject to the terms and conditions defined in 4 | // file 'LICENSE', which is part of the source code. 5 | 6 | package argparser 7 | 8 | var ( 9 | DefaultPrefixes = []rune{ 10 | '/', 11 | '!', 12 | } 13 | ) 14 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | examples 2 | examples.exe -------------------------------------------------------------------------------- /examples/bools/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Package", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${workspaceFolder}/main.go" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /examples/bools/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /examples/bools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ALiwoto/argparser/examples 2 | 3 | go 1.16 4 | 5 | require ( 6 | ) 7 | -------------------------------------------------------------------------------- /examples/bools/go.sum.example: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ALiwoto/argparser/48cf155c3231ea9849c505d3c73bbcdbc86f851b/examples/bools/go.sum.example -------------------------------------------------------------------------------- /examples/bools/main.go: -------------------------------------------------------------------------------- 1 | // argparser Project 2 | // Copyright (C) 2021-2022 wotoTeam, ALiwoto 3 | // This file is subject to the terms and conditions defined in 4 | // file 'LICENSE', which is part of the source code. 5 | 6 | package main 7 | 8 | import ( 9 | "log" 10 | 11 | "github.com/ALiwoto/argparser/argparser" 12 | ) 13 | 14 | const boolTest = "/test --flag1 true --flag2 on" + 15 | " --flag3 false" + 16 | " --flag4 NO" + 17 | " --flag5 off" 18 | 19 | func main() { 20 | args, err := argparser.ParseArgDefault(boolTest) 21 | if err != nil { 22 | log.Fatal(err) 23 | } 24 | 25 | if args.HasFlag("flag1", "anotherFlag") { 26 | log.Println("it has flag1 or anotherFlag") 27 | } 28 | 29 | b1 := args.GetAsBool("flag1") 30 | if b1 { 31 | log.Println("it's true!") 32 | } else { 33 | log.Println("it's false!") 34 | } 35 | 36 | s1 := args.GetAsString("flag4") 37 | log.Println(s1) 38 | 39 | // lets try more than one flag this time. 40 | // this method will search for the flags you passed to it. 41 | // if the first flag doesn't exist, it will look 42 | // for another one. 43 | // if there are no such flags at all, it will return you 44 | // `0, false` 45 | // if the first flag exists but it can't be 46 | // converted to integer, it will give you `0, false`s 47 | i1, ok := args.GetAsInteger("flag6", "flag10") 48 | if !ok { 49 | log.Println("couldn't parse flag value to integer") 50 | } else { 51 | log.Println("oh yeah, the integer value is ", i1) 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ALiwoto/argparser 2 | 3 | go 1.18 4 | 5 | require github.com/ALiwoto/ssg v1.1.38 6 | 7 | require golang.org/x/text v0.18.0 // indirect 8 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/ALiwoto/ssg v1.1.38 h1:nVGsObrzLv174qzNva29Ki9x7xkmtUWsX3cMEimT/Bo= 2 | github.com/ALiwoto/ssg v1.1.38/go.mod h1:977/edS++uXWeyaTA9giTWPi8QubiIkb6ij0+0tC9gU= 3 | golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= 4 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 5 | golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= 6 | golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 7 | -------------------------------------------------------------------------------- /tests/args_test.go: -------------------------------------------------------------------------------- 1 | // argparser Project 2 | // Copyright (C) 2021-2022 ALiwoto 3 | // This file is subject to the terms and conditions defined in 4 | // file 'LICENSE', which is part of the source code. 5 | 6 | package args_test 7 | 8 | import ( 9 | "log" 10 | "testing" 11 | 12 | "github.com/ALiwoto/argparser/argparser" 13 | ) 14 | 15 | const ( 16 | cmd1 = `/command1 hello` 17 | cmd2 = `/command2 --action ban --word:hello` 18 | cmd3 = `/command3 --action warn --trigger:how are you?` 19 | cmd4 = `/command4 --action gban --trigger:I hate you --reason = 20 | "trolling, spamming, using unsuitable words for the group 21 | and raiding."` 22 | cmd5 = `/command5 --o --f I like this --action gban --trigger:I hate you --reason = 23 | "trolling, spamming, using unsuitable words for the group 24 | and raiding." --h = true` 25 | 26 | cmd6 = `/command6 no longer exists --o --f I like this --action gban --trigger:I hate you --reason = 27 | "trolling, spamming, using unsuitable words for the group 28 | and raiding." --h = true` 29 | cmd7 = `/scan@DominatorRobot --f earning money spam` 30 | ) 31 | 32 | func TestArgs1(t *testing.T) { 33 | arg, err := argparser.ParseArgDefault(cmd1) 34 | if err != nil { 35 | t.Error(err) 36 | return 37 | } 38 | if arg == nil { 39 | t.Error("arg is nil") 40 | return 41 | } 42 | if !arg.CompareCommand("/command1") { 43 | t.Error("command is not /command1") 44 | return 45 | } 46 | 47 | if arg.GetLength() != 0 { 48 | t.Error("arg length is not zero") 49 | return 50 | } 51 | 52 | if !arg.HasRawData() { 53 | t.Error("arg has no raw data") 54 | return 55 | } 56 | 57 | log.Println(arg.GetAsStringOrRaw()) 58 | } 59 | 60 | func TestArgs2(t *testing.T) { 61 | arg, err := argparser.ParseArgDefault(cmd2) 62 | if err != nil { 63 | t.Error(err) 64 | return 65 | } 66 | if arg == nil { 67 | t.Error("arg is nil") 68 | return 69 | } 70 | if !arg.CompareCommand("/command2") { 71 | t.Error("command is not /command2") 72 | return 73 | } 74 | if arg.GetLength() != 2 { 75 | t.Error("arg length is not 2") 76 | return 77 | } 78 | if arg.HasRawData() { 79 | t.Error("arg has raw data") 80 | return 81 | } 82 | act := arg.GetAsStringOrRaw("action") 83 | if act != "ban" { 84 | t.Error("action is not ban") 85 | return 86 | } 87 | if arg.GetAsString("keyword", "word", "trigger") != "hello" { 88 | t.Error("keyword is not hello") 89 | return 90 | } 91 | log.Println("we will", arg.GetAsString("action"), 92 | "users if they use \""+ 93 | arg.GetAsString("keyword", "word", "trigger")+ 94 | "\" in the group") 95 | } 96 | 97 | func TestArgs3(t *testing.T) { 98 | arg, err := argparser.ParseArgDefault(cmd3) 99 | if err != nil { 100 | t.Error(err) 101 | return 102 | } 103 | if arg == nil { 104 | t.Error("arg is nil") 105 | return 106 | } 107 | if !arg.CompareCommand("/command3") { 108 | t.Error("command is not /command3") 109 | return 110 | } 111 | if arg.GetLength() != 2 { 112 | t.Error("arg length is not 2") 113 | return 114 | } 115 | if arg.HasRawData() { 116 | t.Error("arg has raw data") 117 | return 118 | } 119 | act := arg.GetAsStringOrRaw("action") 120 | if act != "warn" { 121 | t.Error("action is not warn") 122 | return 123 | } 124 | if arg.GetAsString("keyword", "word", "trigger") != "how are you?" { 125 | t.Error("keyword is not \"how are you?\"") 126 | return 127 | } 128 | log.Println("we will", arg.GetAsString("action"), 129 | "users if they use \""+ 130 | arg.GetAsString("keyword", "word", "trigger")+ 131 | "\" in the group") 132 | } 133 | 134 | func TestArgs4(t *testing.T) { 135 | arg, err := argparser.ParseArgDefault(cmd4) 136 | if err != nil { 137 | t.Error(err) 138 | return 139 | } 140 | if arg == nil { 141 | t.Error("arg is nil") 142 | return 143 | } 144 | if !arg.CompareCommand("/command4") { 145 | t.Error("command is not /command4") 146 | return 147 | } 148 | if arg.GetLength() != 3 { 149 | t.Error("arg length is not 3") 150 | return 151 | } 152 | if arg.HasRawData() { 153 | t.Error("arg has raw data") 154 | return 155 | } 156 | act := arg.GetAsStringOrRaw("action") 157 | if act != "gban" { 158 | t.Error("action is not gban") 159 | return 160 | } 161 | if arg.GetAsString("keyword", "word", "trigger") != "I hate you" { 162 | t.Error("keyword is not \"I hate you\"") 163 | return 164 | } 165 | reason := arg.GetAsString("reason") 166 | log.Println("we will", act, 167 | "users if they use \""+ 168 | arg.GetAsString("keyword", "word", "trigger")+ 169 | "\" in the group.", "the reason will be: \""+reason+"\"") 170 | } 171 | 172 | func TestArgs5(t *testing.T) { 173 | arg, err := argparser.ParseArgDefault(cmd5) 174 | if err != nil { 175 | t.Error(err) 176 | return 177 | } 178 | 179 | if arg == nil { 180 | t.Error("arg is nil") 181 | return 182 | } 183 | 184 | if !arg.CompareCommand("/command5") { 185 | t.Error("command is not /command5") 186 | return 187 | } 188 | 189 | if arg.GetLength() != 6 { 190 | t.Error("arg length is not 6") 191 | return 192 | } 193 | 194 | if arg.HasRawData() { 195 | t.Error("arg has raw data") 196 | return 197 | } 198 | 199 | act := arg.GetAsStringOrRaw("action") 200 | if act != "gban" { 201 | t.Error("action is not gban") 202 | return 203 | } 204 | 205 | if arg.GetAsString("keyword", "word", "trigger") != "I hate you" { 206 | t.Error("keyword is not \"I hate you\"") 207 | return 208 | } 209 | 210 | if arg.GetFirstNoneEmptyValue() != "I like this" { 211 | t.Error("first none empty value is incorrect") 212 | return 213 | } 214 | 215 | reason := arg.GetAsString("reason") 216 | log.Println("we will", act, 217 | "users if they use \""+ 218 | arg.GetAsString("keyword", "word", "trigger")+ 219 | "\" in the group.", "the reason will be: \""+reason+"\"") 220 | } 221 | 222 | func TestArgs6(t *testing.T) { 223 | arg, err := argparser.ParseArgDefault(cmd6) 224 | if err != nil { 225 | t.Error(err) 226 | return 227 | } 228 | 229 | if arg == nil { 230 | t.Error("arg is nil") 231 | return 232 | } 233 | 234 | if !arg.CompareCommand("/command6") { 235 | t.Error("command is not /command6") 236 | return 237 | } 238 | 239 | if arg.GetLength() != 6 { 240 | t.Error("arg length is not 6") 241 | return 242 | } 243 | 244 | if arg.HasRawData() { 245 | t.Error("arg has raw data") 246 | return 247 | } 248 | 249 | act := arg.GetAsStringOrRaw("action") 250 | if act != "gban" { 251 | t.Error("action is not gban") 252 | return 253 | } 254 | 255 | if arg.GetAsString("keyword", "word", "trigger") != "I hate you" { 256 | t.Error("keyword is not \"I hate you\"") 257 | return 258 | } 259 | 260 | if arg.GetFirstNoneEmptyValue() != "I like this" { 261 | t.Error("first none empty value is incorrect") 262 | return 263 | } 264 | 265 | reason := arg.GetAsString("reason") 266 | log.Println("we will", act, 267 | "users if they use \""+ 268 | arg.GetAsString("keyword", "word", "trigger")+ 269 | "\" in the group.", "the reason will be: \""+reason+"\"") 270 | } 271 | 272 | func TestArgs7(t *testing.T) { 273 | arg, err := argparser.ParseArgDefault(cmd7) 274 | if err != nil { 275 | t.Error(err) 276 | return 277 | } 278 | 279 | if arg == nil { 280 | t.Error("arg is nil") 281 | return 282 | } 283 | 284 | if !arg.CompareCommand("/scan@DominatorRobot") { 285 | t.Error("command is not /scan@DominatorRobot") 286 | return 287 | } 288 | 289 | if arg.HasRawData() { 290 | t.Error("arg has raw data") 291 | return 292 | } 293 | 294 | if !arg.HasFlag("f", "force") { 295 | t.Error("flag f is not set") 296 | return 297 | } 298 | 299 | if arg.GetFirstNoneEmptyValue() != "earning money spam" { 300 | t.Error("first none empty value is incorrect") 301 | return 302 | } 303 | } 304 | --------------------------------------------------------------------------------