fix one too small
[RRG-proxmark3.git] / client / src / cmdparser.c
blob7421b3f585cf1e823e6869d17921bf31dbda75b7
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // Command parser
17 //-----------------------------------------------------------------------------
19 #include "cmdparser.h"
21 #include <stdio.h>
22 #include <string.h>
24 #include "ui.h"
25 #include "comms.h"
26 #include "util_posix.h" // msleep
29 #define MAX_PM3_INPUT_ARGS_LENGTH 4096
31 bool AlwaysAvailable(void) {
32 return true;
35 bool IfClientDebugEnabled(void) {
36 return g_debugMode;
39 bool IfPm3Present(void) {
40 if (g_session.help_dump_mode)
41 return false;
42 return g_session.pm3_present;
45 bool IfPm3Rdv4Fw(void) {
46 if (IfPm3Present() == false)
47 return false;
48 return (g_pm3_capabilities.is_rdv4);
51 bool IfPm3Flash(void) {
52 if (IfPm3Present() == false)
53 return false;
54 if (g_pm3_capabilities.compiled_with_flash == false)
55 return false;
56 return g_pm3_capabilities.hw_available_flash;
59 bool IfPm3Smartcard(void) {
60 if (IfPm3Present() == false)
61 return false;
62 if (g_pm3_capabilities.compiled_with_smartcard == false)
63 return false;
64 return g_pm3_capabilities.hw_available_smartcard;
67 bool IfPm3FpcUsart(void) {
68 if (IfPm3Present() == false)
69 return false;
70 return g_pm3_capabilities.compiled_with_fpc_usart;
73 bool IfPm3FpcUsartHost(void) {
74 if (IfPm3Present() == false)
75 return false;
76 return g_pm3_capabilities.compiled_with_fpc_usart_host;
79 bool IfPm3FpcUsartHostFromUsb(void) {
80 // true if FPC USART Host support and if talking from USB-CDC interface
81 if (IfPm3Present() == false)
82 return false;
83 if (g_pm3_capabilities.compiled_with_fpc_usart_host == false)
84 return false;
85 return !g_conn.send_via_fpc_usart;
88 bool IfPm3FpcUsartDevFromUsb(void) {
89 // true if FPC USART developer support and if talking from USB-CDC interface
90 if (IfPm3Present() == false)
91 return false;
92 if (g_pm3_capabilities.compiled_with_fpc_usart_dev == false)
93 return false;
95 return !g_conn.send_via_fpc_usart;
98 bool IfPm3FpcUsartFromUsb(void) {
99 // true if FPC USART Host or developer support and if talking from USB-CDC interface
100 return IfPm3FpcUsartHostFromUsb() || IfPm3FpcUsartDevFromUsb();
103 bool IfPm3Lf(void) {
104 if (IfPm3Present() == false)
105 return false;
106 return g_pm3_capabilities.compiled_with_lf;
109 bool IfPm3Hitag(void) {
110 if (IfPm3Present() == false)
111 return false;
112 return g_pm3_capabilities.compiled_with_hitag;
115 bool IfPm3EM4x50(void) {
116 if (IfPm3Present() == false)
117 return false;
118 return g_pm3_capabilities.compiled_with_em4x50;
121 bool IfPm3EM4x70(void) {
122 if (IfPm3Present() == false)
123 return false;
124 return g_pm3_capabilities.compiled_with_em4x70;
127 bool IfPm3Hfsniff(void) {
128 if (IfPm3Present() == false)
129 return false;
130 return g_pm3_capabilities.compiled_with_hfsniff;
133 bool IfPm3Hfplot(void) {
134 if (IfPm3Present() == false)
135 return false;
136 return g_pm3_capabilities.compiled_with_hfplot;
139 bool IfPm3Iso14443a(void) {
140 if (IfPm3Present() == false)
141 return false;
142 return g_pm3_capabilities.compiled_with_iso14443a;
145 bool IfPm3Iso14443b(void) {
146 if (IfPm3Present() == false)
147 return false;
148 return g_pm3_capabilities.compiled_with_iso14443b;
151 bool IfPm3Iso14443(void) {
152 if (IfPm3Present() == false)
153 return false;
154 return g_pm3_capabilities.compiled_with_iso14443a || g_pm3_capabilities.compiled_with_iso14443b;
157 bool IfPm3Iso15693(void) {
158 if (IfPm3Present() == false)
159 return false;
160 return g_pm3_capabilities.compiled_with_iso15693;
163 bool IfPm3Felica(void) {
164 if (IfPm3Present() == false)
165 return false;
166 return g_pm3_capabilities.compiled_with_felica;
169 bool IfPm3Legicrf(void) {
170 if (IfPm3Present() == false)
171 return false;
172 return g_pm3_capabilities.compiled_with_legicrf;
175 bool IfPm3Iclass(void) {
176 if (IfPm3Present() == false)
177 return false;
178 return g_pm3_capabilities.compiled_with_iclass;
181 bool IfPm3NfcBarcode(void) {
182 if (IfPm3Present() == false)
183 return false;
184 return g_pm3_capabilities.compiled_with_nfcbarcode;
187 bool IfPm3Lcd(void) {
188 if (IfPm3Present() == false)
189 return false;
190 return g_pm3_capabilities.compiled_with_lcd;
193 bool IfPm3Zx8211(void) {
194 if (IfPm3Present() == false)
195 return false;
196 return g_pm3_capabilities.compiled_with_zx8211;
199 void CmdsHelp(const command_t Commands[]) {
200 if (Commands[0].Name == NULL) return;
202 PrintAndLogEx(NORMAL, "");
204 int i = 0;
205 while (Commands[i].Name) {
206 if (Commands[i].IsAvailable()) {
207 uint8_t old_printAndLog = g_printAndLog;
208 g_printAndLog &= PRINTANDLOG_PRINT;
209 if (Commands[i].Name[0] == '-' || Commands[i].Name[0] == ' ') {
210 PrintAndLogEx(NORMAL, "%-16s %s", Commands[i].Name, Commands[i].Help);
211 } else {
212 PrintAndLogEx(NORMAL, _GREEN_("%-16s")" %s", Commands[i].Name, Commands[i].Help);
214 g_printAndLog = old_printAndLog;
216 ++i;
218 // empty line needed for the help2json parser
219 PrintAndLogEx(NORMAL, "");
222 int CmdsParse(const command_t Commands[], const char *Cmd) {
224 if (g_session.client_exe_delay != 0) {
225 msleep(g_session.client_exe_delay);
228 // Help dump children
229 if (strcmp(Cmd, "XX_internal_command_dump_XX") == 0) {
230 dumpCommandsRecursive(Commands, 0, false);
231 return PM3_SUCCESS;
233 // Help dump children with help
234 if (strcmp(Cmd, "XX_internal_command_dump_full_XX") == 0) {
235 dumpCommandsRecursive(Commands, 0, true);
236 return PM3_SUCCESS;
238 // Markdown help dump children
239 if (strcmp(Cmd, "XX_internal_command_dump_markdown_XX") == 0) {
240 dumpCommandsRecursive(Commands, 1, false);
241 return PM3_SUCCESS;
243 // Markdown help dump children with help
244 if (strcmp(Cmd, "XX_internal_command_dump_markdown_help_XX") == 0) {
245 dumpCommandsRecursive(Commands, 1, true);
246 return PM3_SUCCESS;
249 if (strcmp(Cmd, "coffee") == 0) {
250 PrintAndLogEx(NORMAL, "");
251 PrintAndLogEx(NORMAL, " ((\n ))\n" _YELLOW_(" .______.\n | |]\n \\ /\n `----ยด\n\n"));
252 return PM3_SUCCESS;
255 if (strcmp(Cmd, "star") == 0) {
256 PrintAndLogEx(NORMAL, "");
257 PrintAndLogEx(NORMAL, " \\o o/");
258 PrintAndLogEx(NORMAL, " v\\ /v");
259 PrintAndLogEx(NORMAL, " <\\ />");
260 PrintAndLogEx(NORMAL, " |\\o/|");
261 PrintAndLogEx(NORMAL, " _\\__o | o__/");
262 PrintAndLogEx(NORMAL, " |/ \\|");
263 PrintAndLogEx(NORMAL, " o/ \\o");
264 PrintAndLogEx(NORMAL, " /v v\\");
265 PrintAndLogEx(NORMAL, " /> <\\");
266 PrintAndLogEx(NORMAL, "");
267 return PM3_SUCCESS;
271 char cmd_name[128] = {0};
272 memset(cmd_name, 0, sizeof(cmd_name));
274 int len = 0;
275 // %n == receives an integer of value equal to the number of chars read so far.
276 // len = max 127
277 sscanf(Cmd, "%127s%n", cmd_name, &len);
279 str_lower(cmd_name);
281 // iceman: I mistyped "list" so many times with "lsit". No more.
282 char *lsit = strstr(cmd_name, "lsit");
283 if (lsit) {
284 lsit[1] = lsit[2] ^ lsit[1];
285 lsit[2] = lsit[1] ^ lsit[2];
286 lsit[1] = lsit[2] ^ lsit[1];
289 // Comment
290 if (cmd_name[0] == '#')
291 return PM3_SUCCESS;
293 // find args, check for -h / --help
294 int tmplen = len;
295 while (Cmd[tmplen] == ' ') {
296 ++tmplen;
299 bool request_help = (strcmp(Cmd + tmplen, "-h") == 0) || (strcmp(Cmd + tmplen, "--help") == 0);
301 int i = 0;
302 while (Commands[i].Name) {
303 if (0 == strcmp(Commands[i].Name, cmd_name)) {
304 if ((Commands[i].Help[0] == '{') || // always allow parsing categories
305 request_help || // always allow requesting help
306 Commands[i].IsAvailable()) {
307 break;
308 } else {
309 PrintAndLogEx(WARNING, "This command is " _YELLOW_("not available") " in this mode");
310 return PM3_ENOTIMPL;
313 ++i;
316 /* try to find exactly one prefix-match */
317 if (!Commands[i].Name) {
318 int last_match = 0;
319 int matches = 0;
321 for (i = 0; Commands[i].Name; i++) {
322 if (!strncmp(Commands[i].Name, cmd_name, strlen(cmd_name)) && Commands[i].IsAvailable()) {
323 last_match = i;
324 matches++;
327 if (matches == 1) {
328 i = last_match;
332 if (Commands[i].Name) {
333 while (Cmd[len] == ' ') {
334 ++len;
336 return Commands[i].Parse(Cmd + len);
337 } else {
338 // show help for selected hierarchy or if command not recognised
339 CmdsHelp(Commands);
342 return PM3_SUCCESS;
345 static char pparent[MAX_PM3_INPUT_ARGS_LENGTH] = {0};
346 static char *parent = pparent;
348 void dumpCommandsRecursive(const command_t cmds[], int markdown, bool full_help) {
349 if (cmds[0].Name == NULL) return;
351 int i = 0;
352 int w_cmd = 25;
353 int w_off = 8;
354 // First, dump all single commands, which are not a container for
355 // other commands
356 if (markdown) {
357 PrintAndLogEx(NORMAL, "|%-*s|%-*s|%s", w_cmd, "command", w_off, "offline", "description");
358 PrintAndLogEx(NORMAL, "|%-*s|%-*s|%s", w_cmd, "-------", w_off, "-------", "-----------");
359 } else if (! full_help) {
360 PrintAndLogEx(NORMAL, "%-*s|%-*s|%s", w_cmd, "command", w_off, "offline", "description");
361 PrintAndLogEx(NORMAL, "%-*s|%-*s|%s", w_cmd, "-------", w_off, "-------", "-----------");
364 while (cmds[i].Name) {
366 if ((cmds[i].Name[0] == '-' || strlen(cmds[i].Name) == 0) && ++i) continue;
367 if (cmds[i].Help[0] == '{' && ++i) continue;
369 const char *cmd_offline = "N";
371 if (cmds[i].IsAvailable()) {
372 cmd_offline = "Y";
375 if (markdown) {
376 PrintAndLogEx(NORMAL, "|`%s%-*s`|%-*s|`%s`", parent, w_cmd - (int)strlen(parent) - 2, cmds[i].Name, w_off, cmd_offline, cmds[i].Help);
377 } else if (full_help) {
378 PrintAndLogEx(NORMAL, "---------------------------------------------------------------------------------------");
379 PrintAndLogEx(NORMAL, _RED_("%s%-*s\n") "available offline: %s", parent, w_cmd - (int)strlen(parent), cmds[i].Name, cmds[i].IsAvailable() ? _GREEN_("yes") : _RED_("no"));
380 cmds[i].Parse("--help");
381 } else {
382 PrintAndLogEx(NORMAL, "%s%-*s|%-*s|%s", parent, w_cmd - (int)strlen(parent), cmds[i].Name, w_off, cmd_offline, cmds[i].Help);
384 ++i;
386 PrintAndLogEx(NORMAL, "\n");
387 i = 0;
389 // Then, print the categories. These will go into subsections with their own tables
390 while (cmds[i].Name) {
392 if ((cmds[i].Name[0] == '-' || strlen(cmds[i].Name) == 0) && ++i) continue;
393 if (cmds[i].Help[0] != '{' && ++i) continue;
395 if (full_help) {
396 PrintAndLogEx(NORMAL, "=======================================================================================");
397 PrintAndLogEx(NORMAL, _RED_("%s%s\n\n ")_CYAN_("%s\n"), parent, cmds[i].Name, cmds[i].Help);
398 } else {
399 PrintAndLogEx(NORMAL, "### %s%s\n\n %s\n", parent, cmds[i].Name, cmds[i].Help);
402 char currentparent[MAX_PM3_INPUT_ARGS_LENGTH] = {0};
403 snprintf(currentparent, sizeof currentparent, "%s%s ", parent, cmds[i].Name);
405 char *old_parent = parent;
406 parent = currentparent;
407 // This is what causes the recursion, since commands Parse-implementation
408 // in turn calls the CmdsParse above.
409 if (markdown) {
410 cmds[i].Parse("XX_internal_command_dump_markdown_XX");
411 } else if (full_help) {
412 cmds[i].Parse("XX_internal_command_dump_full_XX");
413 } else {
414 cmds[i].Parse("XX_internal_command_dump_XX");
417 parent = old_parent;
418 ++i;