├── .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 |
--------------------------------------------------------------------------------