3 The old style with mixed custom commandline parsing of user parameters or options was messy and confusing. You can find all kinds in the Proxmark3 client.
13 even the external tools which we collected into this repo, under folder */tools/* folder uses their own argument parsing.
16 In order to counter this and unify it, there was discussion over at the official repository a few years ago [link to issue](https://github.com/Proxmark/proxmark3/issues/467) and there it became clear a change is needed. Among the different solutions suggested @merlokk's idea of using the lib cliparser was agreed upon. The lib was adapted and implemented for commands like
23 And then it fell into silence since it wasn't well documented how to use the cliparser. Looking at source code wasn't very efficient. However the need of a better cli parsing was still there.
25 Fast forward today, where more commands has used the cliparser but it still wasn't the natural way when adding a new client command to the Proxmark3 client.
26 After more discussions among @doegox, @iceman1001 and @mrwalker the concept became more clear on how to use the cliparser lib in the _preferred_ way.
28 The aftermath was a design and layout specified which lead to a simpler implementation of the cliparser in the client source code while still unifying all helptexts with the new colours support and a defined layout. As seen below, the simplicity and clearness.
30 ![sample of new style helptext](http://www.icedev.se/proxmark3/helptext.png)
33 Furthermore @mrwalker offered to take notes and thus this document was created.
35 This is the _new_ and _preferred_ way to implement _helptext_ and _cli parsing_ for Proxmark3 client commands and it's external tools.
38 ## cliparser setup and use
40 The parser will format and color and layout as needed.
41 It will also add the `-h --help` option automatic.
45 * where possible all options should be lowercase.
46 * extended options preceded with -- should be short
47 * options provided directly (without an option identifier) should be avoided.
48 * -vv for extra verbose should be avoided; use of debug level is preferred.
49 * with --options the equal is not needed (will work with and without) so don't use '='
57 --fn : facility number
58 --q5 : target is LF T5555/Q5 card
59 --em : target is LF EM4305/4469 card
61 -d --data : hex data supplied
62 -f --file : filename supplied
63 -k --key : key supplied
64 -n --keyno : key number to use
65 -p --pwd : password supplied
66 -v --verbose : flag when output should provide more information, not considered debug.
67 -1 --buffer : use the sample buffer
71 ## How to implement in source code
73 ### setup the parser data structure
74 Header file to include
76 #include "cliparser.h"
78 In the command function, setup the context
80 CLIParserContext *ctx;
83 ### define the context
84 `CLIParserInit (\<context\>, \<description\>, \<notes\n examples ... \>);`
86 use -> to separate example and example comment and \\n to separate examples.
87 e.g. lf indala clone -r a0000000a0002021 -> this uses .....
89 CLIParserInit(&ctx, "lf indala clone",
90 "clone INDALA UID to T55x7 or Q5/T5555 tag",
91 "lf indala clone --heden 888\n"
92 "lf indala clone --fc 123 --cn 1337\n"
93 "lf indala clone -r a0000000a0002021\n"
94 "lf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
96 ### define the options
100 arg_lit0("l", "long", "optional - long UID 224 bits"),
101 arg_int0("c", "heden", "<decimal>", "Cardnumber for Heden 2L format"),
102 arg_strx0("r", "raw", "<hex>", "raw bytes"),
103 arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
104 arg_int0(NULL, "fc", "<decimal>", "Facility Code (26 bit format)"),
105 arg_int0(NULL, "cn", "<decimal>", "Cardnumber (26 bit format)"),
109 _All options has a parameter index, since `-h --help` is added automatic, it will be assigned index 0.
110 Hence all options you add will start at index 1 and upwards. It added in the define "arg_param_begin_
113 #### bool option. true if supplied
114 `bool : arg_lit0 ("<short option>", "<long option>", <"description">)`
116 #### integer that is optional
117 `optional integer : arg_int0 ("<short option>", "<long option>", "<format>", <"description">)`
119 #### integer that is required
120 `required integer : arg_int1 ("<short option>", "<long option>", "<format>", <"description">)`
122 #### double that is optional
123 `optional double : arg_dbl0 ("<short option>", "<long option>", "<format>", <"description">)`
125 #### double that is required
126 `required double : arg_dbl1 ("<short option>", "<long option>", "<format>", <"description">)`
128 #### String option that is optional and only one instance can be provided
129 `optional string : arg_str0 ("<short option>", "<long option>", "<format>", <"description">)`
131 #### String option that is required and only one instance can be provided
132 `required string : arg_str1 ("<short option>", "<long option>", "<format>", <"description">)`
134 #### String option that is optional and can have up to 250 instances provided
135 `optional string : arg_strx0 ("<short option>", "<long option>", "<format>", <"description">)`
137 #### String option that is required/at least one instance and can have up to 250 instances
138 `required string : arg_strx1 ("<short option>", "<long option>", "<format>", <"description">)`
140 Unsigned values, like u32 and u64 can be accomplished with
142 #### unsigned integer optional
143 `optional unsigned : arg_u64_0 ("<short option>", "<long option>", "<format>", <"description">)`
145 #### unsigned integer required
146 `required unsigned : arg_u64_1 ("<short option>", "<long option>", "<format>", <"description">)`
149 **if an option does not have a short or long option, use NULL in its place**
153 `CLIExecWithReturn(\<context\>, \<command line to parse\>, \<arg/opt table\>, \<return on error\>);`
155 CLIExecWithReturn(ctx, Cmd, argtable, false);
158 Once you have extracted the options, cleanup the context.
162 ### retrieving options
165 The parser will format and color and layout as needed.
166 It will also add the `-h --help` option automatic.
170 arg_get_lit(\<context\>, \<opt index\>);
172 is_long_uid = arg_get_lit(ctx, 1);
175 arg_get_int_def(\<context\>, \<opt index\>, \<default value\>);
177 cardnumber = arg_get_int_def(ctx, 2, -1);
181 arg_get_u32_def(\<context\>, \<opt index\>, \<default value\>);
183 cardnumber = arg_get_u32_def(ctx, 2, 0);
186 arg_get_u64_def(\<context\>, \<opt index\>, \<default value\>);
188 cardnumber = arg_get_u64_def(ctx, 2, 0);
191 **hex option with return**
192 CLIGetHexWithReturn(\<context\>, \<opt index\>, \<store variable\>, \<ptr to stored length\>);
193 ?? as an array of uint_8 ??
194 If failed to retrieve hexbuff, it will exit fct
196 uint8_t aid[2] = {0};
198 CLIGetHexWithReturn(ctx, 2, aid, &aidlen);
203 uint8_t key[24] = {0};
205 int res_klen = CLIParamHexToBuf(arg_get_str(ctx, 3), key, 24, &keylen);
207 quick test : seems res_keylen == 0 when ok so not key len ???
209 **string option return**
210 CLIGetStrWithReturn(\<context\>,\<opt index\>, \<uint8_t \*\>, \<int \*\>);
211 If failed to retrieve string, it will exit fct
214 int slen = sizeof(buffer); // <- slen MUST be the maximum number of characters that you want returned. e.g. Buffer Size
215 CLIGetStrWithReturn(ctx, 1, buffer, &slen);
221 char format[16] = {0};
222 int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &slen);
224 quick test : seem res == 0, then ok. compare res == slen to see how many chars