2020-10-03 16:36:05 +08:00
# Cliparser
2020-10-01 09:53:05 +08:00
2020-10-03 16:36:05 +08:00
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.
Samples
```
data xxxx h
script run x.lua -h
hf 14a raw -h
hf 14b raw -ss
lf search 1
lf config h H
```
2020-10-03 17:21:25 +08:00
even the external tools which we collected into this repo, under folder */tools/* folder uses their own argument parsing.
2020-10-04 21:13:32 +08:00
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
2020-10-03 17:21:25 +08:00
2020-10-03 16:36:05 +08:00
```
2020-10-03 17:21:25 +08:00
[usb] pm3 --> emv
[usb] pm3 --> hf fido
2020-10-03 16:36:05 +08:00
```
2020-10-03 17:21:25 +08:00
2020-10-04 21:13:32 +08:00
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.
2020-10-03 17:21:25 +08:00
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.
2020-10-04 21:13:32 +08:00
After more discussions among @doegox , @iceman1001 and @mrwalker the concept became more clear on how to use the cliparser lib in the _preferred_ way.
2020-10-03 17:21:25 +08:00
2020-10-23 07:24:54 +08:00
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.
2020-10-03 16:36:05 +08:00
![sample of new style helptext ](http://www.icedev.se/proxmark3/helptext.png )
2020-10-01 09:53:05 +08:00
2020-10-04 21:13:32 +08:00
Furthermore @mrwalker offered to take notes and thus this document was created.
2020-10-03 17:21:25 +08:00
2020-10-05 03:57:02 +08:00
This is the _new_ and _preferred_ way to implement _helptext_ and _cli parsing_ for Proxmark3 client commands and it's external tools.
2020-10-03 17:21:25 +08:00
2020-10-03 16:36:05 +08:00
## cliparser setup and use
The parser will format and color and layout as needed.
It will also add the `-h --help` option automatic.
2020-10-01 09:53:05 +08:00
2020-10-03 09:34:33 +08:00
## design comments
2020-10-03 16:36:05 +08:00
2020-10-04 21:13:32 +08:00
* where possible all options should be lowercase.
* extended options preceded with -- should be short
* options provided directly (without an option identifier) should be avoided.
2020-10-05 03:57:02 +08:00
* -vv for extra verbose should be avoided; use of debug level is preferred.
2020-10-04 21:13:32 +08:00
* with --options the equal is not needed (will work with and without) so don't use '='
2020-10-03 09:34:33 +08:00
e.g. cmd --cn 12345
2020-10-01 09:53:05 +08:00
2020-10-03 16:36:05 +08:00
2020-10-03 09:34:33 +08:00
## common options
2020-10-01 09:53:05 +08:00
-h --help : help
--cn : card number
--fn : facility number
--q5 : target is lf q5 card
--raw : raw data
-k --key : key supplied
-n --keyno : key number to use
2020-10-05 03:57:02 +08:00
-v --verbose : flag when output should provide more information, not considered debug.
2020-10-01 09:53:05 +08:00
-1 --buffer : use the sample buffer
2020-10-03 16:36:05 +08:00
## How to implement in source code
2020-10-01 09:53:05 +08:00
### setup the parser data structure
Header file to include
#include "cliparser.h"
In the command function, setup the context
CLIParserContext *ctx;
2020-10-03 17:06:01 +08:00
### define the context
2020-10-05 03:57:02 +08:00
`CLIParserInit (\<context\>, \<description\>, \<notes\n examples ... \>);`
2020-10-01 09:53:05 +08:00
2020-10-03 17:06:01 +08:00
use -> to separate example and example comment and \\n to separate examples.
2020-10-01 09:53:05 +08:00
e.g. lf indala clone -r a0000000a0002021 -> this uses .....
2020-10-04 21:13:32 +08:00
CLIParserInit(& ctx, "lf indala clone",
"clone INDALA UID to T55x7 or Q5/T5555 tag",
"lf indala clone --heden 888\n"
2020-10-01 09:53:05 +08:00
"lf indala clone --fc 123 --cn 1337\n"
"lf indala clone -r a0000000a0002021\n"
"lf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
### define the options
void *argtable[] = {
arg_param_begin,
2020-10-04 21:13:32 +08:00
arg_lit0("l", "long", "optional - long UID 224 bits"),
arg_int0("c", "heden", "< decimal > ", "Cardnumber for Heden 2L format"),
arg_strx0("r", "raw", "< hex > ", "raw bytes"),
2020-10-01 09:53:05 +08:00
arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
arg_int0(NULL, "fc", "< decimal > ", "Facility Code (26 bit format)"),
arg_int0(NULL, "cn", "< decimal > ", "Cardnumber (26 bit format)"),
arg_param_end
};
2020-10-03 16:36:05 +08:00
_All options has a parameter index, since `-h --help` is added automatic, it will be assigned index 0.
2020-10-05 04:19:08 +08:00
Hence all options you add will start at index 1 and upwards. It added in the define "arg_param_begin_
2020-10-03 16:36:05 +08:00
2020-10-05 04:19:08 +08:00
### Notes:
#### bool option. true if supplied
`bool : arg_lit0 ("<short option>", "<long option>", <"description">)`
2020-10-03 09:34:33 +08:00
2020-10-05 04:19:08 +08:00
#### integer that is optional
`optional integer : arg_int0 ("<short option>", "<long option>", "<format>", <"description">)`
2020-10-03 17:06:01 +08:00
2020-10-05 04:19:08 +08:00
#### integer that is required
`required integer : arg_int1 ("<short option>", "<long option>", "<format>", <"description">)`
2020-10-03 09:34:33 +08:00
2020-10-05 04:19:08 +08:00
#### double that is optional
`optional double : arg_dbl0 ("<short option>", "<long option>", "<format>", <"description">)`
2020-10-03 17:06:01 +08:00
2020-10-05 04:19:08 +08:00
#### double that is required
`required double : arg_dbl1 ("<short option>", "<long option>", "<format>", <"description">)`
2020-10-03 09:34:33 +08:00
2020-10-05 04:19:08 +08:00
#### String option that is optional and only one instance can be provided
`optional string : arg_str0 ("<short option>", "<long option>", "<format>", <"description">)`
2020-10-03 17:06:01 +08:00
2020-10-05 04:19:08 +08:00
#### String option that is required and only one instance can be provided
`required string : arg_str1 ("<short option>", "<long option>", "<format>", <"description">)`
2020-10-04 21:13:32 +08:00
2020-10-05 04:19:08 +08:00
#### String option that is optional and can have up to 250 instances provided
`optional string : arg_strx0 ("<short option>", "<long option>", "<format>", <"description">)`
#### String option that is required/at least one instance and can have up to 250 instances
`required string : arg_strx1 ("<short option>", "<long option>", "<format>", <"description">)`
Unsigned values, like u32 and u64 can be accomplished with
#### unsigned integer optional
`optional unsigned : arg_u64_0 ("<short option>", "<long option>", "<format>", <"description">)`
#### unsigned integer required
`required unsigned : arg_u64_1 ("<short option>", "<long option>", "<format>", <"description">)`
2020-10-04 21:13:32 +08:00
**if an option does not have a short or long option, use NULL in its place**
2020-10-01 09:53:05 +08:00
2020-10-05 04:19:08 +08:00
2020-10-01 09:53:05 +08:00
### show the menu
2020-10-05 03:57:02 +08:00
`CLIExecWithReturn(\<context\>, \<command line to parse\>, \<arg/opt table\>, \<return on error\>);`
2020-10-01 09:53:05 +08:00
CLIExecWithReturn(ctx, Cmd, argtable, false);
### clean up
Once you have extracted the options, cleanup the context.
2020-10-05 03:57:02 +08:00
CLIParserFree(ctx);
2020-10-01 09:53:05 +08:00
2020-10-05 03:57:02 +08:00
### retrieving options
2020-10-03 17:21:25 +08:00
The parser will format and color and layout as needed.
It will also add the `-h --help` option automatic.
2020-10-04 21:13:32 +08:00
**bool option**
2020-10-01 09:53:05 +08:00
arg_get_lit(\<context\>, \<opt index\>);
is_long_uid = arg_get_lit(ctx, 1);
2020-10-04 21:13:32 +08:00
**int option**
2020-10-01 09:53:05 +08:00
arg_get_int_def(\<context\>, \<opt index\>, \<default value\>);
cardnumber = arg_get_int_def(ctx, 2, -1);
2020-10-05 04:19:08 +08:00
**uint32**
arg_get_u32_def(\<context\>, \<opt index\>, \<default value\>);
cardnumber = arg_get_u32_def(ctx, 2, 0);
**uint64**
arg_get_u64_def(\<context\>, \<opt index\>, \<default value\>);
cardnumber = arg_get_u64_def(ctx, 2, 0);
2020-10-09 23:32:58 +08:00
**hex option with return**
2020-10-01 09:53:05 +08:00
CLIGetHexWithReturn(\<context\>, \<opt index\>, \<store variable\>, \<ptr to stored length\>);
?? as an array of uint_8 ??
2020-10-09 23:32:58 +08:00
If failed to retrieve hexbuff, it will exit fct
2020-10-04 21:13:32 +08:00
2020-10-01 09:53:05 +08:00
uint8_t aid[2] = {0};
int aidlen;
CLIGetHexWithReturn(ctx, 2, aid, &aidlen);
2020-10-09 23:32:58 +08:00
**hex option**
2020-10-01 09:53:05 +08:00
uint8_t key[24] = {0};
int keylen = 0;
int res_klen = CLIParamHexToBuf(arg_get_str(ctx, 3), key, 24, &keylen);
2020-10-09 23:32:58 +08:00
2020-10-04 21:13:32 +08:00
quick test : seems res_keylen == 0 when ok so not key len ???
2020-10-01 09:53:05 +08:00
2020-10-09 23:32:58 +08:00
**string option return**
2020-10-17 06:20:33 +08:00
CLIGetStrWithReturn(\<context\>,\<opt index\>, \<uint8_t \*\>, \<int \*\>);
2020-10-09 23:32:58 +08:00
If failed to retrieve string, it will exit fct
uint8_t buffer[100];
2020-10-17 06:20:33 +08:00
int slen = sizeof(buffer); // < - slen MUST be the maximum number of characters that you want returned . e . g . Buffer Size
2020-10-09 23:32:58 +08:00
CLIGetStrWithReturn(ctx, 1, buffer, &slen);
**string option**
Getting a char array
2020-10-01 09:53:05 +08:00
2020-10-09 23:32:58 +08:00
int slen = 0;
char format[16] = {0};
int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &slen);
2020-10-01 09:53:05 +08:00
2020-10-09 23:32:58 +08:00
quick test : seem res == 0, then ok. compare res == slen to see how many chars