• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "shell_bas.h"
16 #include <fcntl.h>
17 #include <signal.h>
18 
19 #include "init_utils.h"
20 #include "shell_utils.h"
21 
BShellEnvErrString(BShellHandle handle,int32_t err)22 char *BShellEnvErrString(BShellHandle handle, int32_t err)
23 {
24     static BShellErrInfo shellErrString[] = {
25         {BSH_SHELL_INFO, "\r\n\r\n"
26                         "+=========================================================+\r\n"
27                         "|               Parameter shell v"BSH_VERSION"                    |\r\n"
28                         "+=========================================================+\r\n"
29         },
30         {BSH_CMD_TOO_LONG, "\r\nWarnig: Command is too long\r\n"},
31         {BSH_SHOW_CMD_LIST, "Command list:\r\n"},
32         {BSH_CMD_NOT_EXIST, "Command not found\r\n"}
33     };
34     for (size_t i = 0; i < sizeof(shellErrString) / sizeof(shellErrString[0]); i++) {
35         if ((int32_t)shellErrString[i].err == err) {
36             return shellErrString[i].desc;
37         }
38     }
39     BSH_CHECK(handle != NULL, return "System unknown err", "Invalid shell env");
40     BShellEnv *shell = (BShellEnv *)handle;
41     int len = sprintf_s(shell->data, sizeof(shell->data) - 1, "System unknown err 0x%08x", err);
42     if (len <= 0) {
43         BSH_LOGE("Write shell data size failed.");
44     }
45     return shell->data;
46 }
47 
BShellCmdOutputCmdHelp(BShellHandle handle,BShellCommand * cmd)48 static void BShellCmdOutputCmdHelp(BShellHandle handle, BShellCommand *cmd)
49 {
50     BShellEnvOutputString(handle, "    ");
51     int32_t spaceLength = BShellEnvOutputString(handle, cmd->help);
52     spaceLength = BSH_CMD_NAME_END - spaceLength;
53     spaceLength = (spaceLength > 0) ? spaceLength : 4; // 4 min
54     do {
55         BShellEnvOutputString(handle, " ");
56     } while (--spaceLength);
57     BShellEnvOutputString(handle, "--");
58     BShellEnvOutputString(handle, cmd->desc);
59     BShellEnvOutputString(handle, "\r\n");
60 }
61 
BShellCmdHelp(BShellHandle handle,int32_t argc,char * argv[])62 int32_t BShellCmdHelp(BShellHandle handle, int32_t argc, char *argv[])
63 {
64     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
65     BShellEnv *shell = (BShellEnv *)handle;
66     BShellEnvOutputString(handle, BShellEnvErrString(handle, BSH_SHOW_CMD_LIST));
67 
68     int show = 0;
69     BShellCommand *cmd = shell->command;
70     while (cmd != NULL) {
71         if ((argc >= 1) &&
72             (strncmp(argv[0], cmd->name, strlen(argv[0])) == 0) &&
73             (strncmp(argv[0], "help", strlen(argv[0])) != 0)) {
74             BShellCmdOutputCmdHelp(handle, cmd);
75             show = 1;
76         }
77         cmd = cmd->next;
78     }
79     if (show) {
80         return 0;
81     }
82     cmd = shell->command;
83     while (cmd != NULL) {
84         BShellCmdOutputCmdHelp(handle, cmd);
85         cmd = cmd->next;
86     }
87     return 0;
88 }
89 
BShellCmdExit(BShellHandle handle,int32_t argc,char * argv[])90 static int32_t BShellCmdExit(BShellHandle handle, int32_t argc, char *argv[])
91 {
92 #ifndef STARTUP_INIT_TEST
93     kill(getpid(), SIGINT);
94 #endif
95     return 0;
96 }
97 
BShellEnvOutput(BShellHandle handle,char * fmt,...)98 int32_t BShellEnvOutput(BShellHandle handle, char *fmt, ...)
99 {
100     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
101     va_list list;
102     va_start(list, fmt);
103     int len = vfprintf(stdout, fmt, list);
104     va_end(list);
105     (void)fflush(stdout);
106     return len;
107 }
108 
BShellEnvOutputString(BShellHandle handle,const char * string)109 int32_t BShellEnvOutputString(BShellHandle handle, const char *string)
110 {
111     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
112     printf("%s", string);
113     (void)fflush(stdout);
114     return strlen(string);
115 }
116 
BShellEnvOutputPrompt(BShellHandle handle,const char * prompt)117 int32_t BShellEnvOutputPrompt(BShellHandle handle, const char *prompt)
118 {
119     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
120     BSH_CHECK(prompt != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
121     BShellEnv *shell = (BShellEnv *)handle;
122     if (shell->prompt != NULL) {
123         free(shell->prompt);
124     }
125     size_t promptLen = strlen(prompt);
126     if (promptLen > BSH_CMD_NAME_END) {
127         shell->prompt = strdup(prompt + promptLen - BSH_CMD_NAME_END);
128         if (shell->prompt != NULL) {
129             shell->prompt[0] = '.';
130             shell->prompt[1] = '.';
131             shell->prompt[2] = '.'; // 2 index
132         }
133     } else {
134         shell->prompt = strdup(prompt);
135     }
136     return 0;
137 }
138 
BShellEnvOutputByte(BShellHandle handle,char data)139 void BShellEnvOutputByte(BShellHandle handle, char data)
140 {
141     BSH_CHECK(handle != NULL, return, "Invalid shell env");
142     printf("%c", data);
143     (void)fflush(stdout);
144 }
145 
BShellEnvOutputResult(BShellHandle handle,int32_t result)146 void BShellEnvOutputResult(BShellHandle handle, int32_t result)
147 {
148     if (result == 0) {
149         return;
150     }
151     printf("result: 0x%08x\r\n", result);
152     (void)fflush(stdout);
153 }
154 
BShellEnvOutputParam(BShellHandle handle,char * var)155 static void BShellEnvOutputParam(BShellHandle handle, char *var)
156 {
157     BShellEnvOutput(handle, (var[0] == '$') ? var + 1 : var);
158     BShellEnvOutputString(handle, " = ");
159     BShellEnvOutputString(handle, BShellEnvGetStringParam(handle, var));
160 }
161 
BShellEnvBackspace(BShellHandle handle,uint32_t length)162 void BShellEnvBackspace(BShellHandle handle, uint32_t length)
163 {
164     for (uint32_t i = 0; i < length; i++) {
165         BShellEnvOutputString(handle, "\b \b");
166     }
167 }
168 
BShellEnvParseParam(BShellEnv * shell)169 static void BShellEnvParseParam(BShellEnv *shell)
170 {
171     uint8_t quotes = 0;
172     uint8_t record = 1;
173     shell->argc = 0;
174     for (uint16_t i = 0; i < shell->length; i++) {
175         char data = *(shell->buffer + i);
176         if ((quotes != 0 || (data != ' ' && data != '\t' && data != ',')) && data != 0) {
177             if (data == '\"') {
178                 quotes = quotes ? 0 : 1;
179             }
180             if (record == 1) {
181                 BSH_CHECK(shell->argc < BSH_PARAMETER_MAX_NUMBER, return, "argc out of range");
182                 shell->args[shell->argc++] = shell->buffer + i;
183                 record = 0;
184             }
185             if (*(shell->buffer + i) == '\\' && *(shell->buffer + i + 1) != 0) {
186                 i++;
187             }
188         } else {
189             *(shell->buffer + i) = 0;
190             record = 1;
191         }
192     }
193 }
194 
BShellEnvExcuteCmd(BShellEnv * shell,BShellCommand * cmd)195 static int32_t BShellEnvExcuteCmd(BShellEnv *shell, BShellCommand *cmd)
196 {
197     return cmd->executer((BShellHandle)shell, shell->argc - cmd->argStart, &shell->args[cmd->argStart]);
198 }
199 
BShellEnvHandleEnter(BShellHandle handle,uint8_t data)200 static int32_t BShellEnvHandleEnter(BShellHandle handle, uint8_t data)
201 {
202     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
203     BShellEnv *shell = (BShellEnv *)handle;
204     if (shell->length == 0) {
205         BShellEnvOutputString(shell, "\n");
206         BShellEnvOutputString(handle, shell->prompt);
207         return 0;
208     }
209 
210     *(shell->buffer + shell->length++) = 0;
211     BShellEnvParseParam(shell);
212     shell->length = 0;
213     shell->cursor = 0;
214     if (shell->argc == 0) {
215         BShellEnvOutputString(shell, shell->prompt);
216         return 0;
217     }
218 
219     BShellEnvOutputString(shell, "\n");
220     if (strcmp((const char *)shell->args[0], "help") == 0) {
221         BShellCmdHelp(handle, shell->argc, shell->args);
222         BShellEnvOutputString(shell, shell->prompt);
223         return 0;
224     }
225     if (shell->args[0][0] == '$') {
226         BShellEnvOutputParam(shell, shell->args[0]);
227         BShellEnvOutputString(shell, shell->prompt);
228         return 0;
229     }
230 
231     BShellCommand *cmd = BShellEnvGetCmd(handle, (uint32_t)shell->argc, shell->args);
232     if (cmd != NULL) {
233         int32_t ret = BShellEnvExcuteCmd(shell, cmd);
234         BShellEnvOutputResult(shell, ret);
235     } else {
236         BShellEnvOutputString(shell, BShellEnvErrString(handle, BSH_CMD_NOT_EXIST));
237     }
238     BShellEnvOutputString(shell, shell->prompt);
239     return 0;
240 }
241 
BShellEnvHandleBackspace(BShellHandle handle,uint8_t code)242 static int32_t BShellEnvHandleBackspace(BShellHandle handle, uint8_t code)
243 {
244     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
245     BShellEnv *shell = (BShellEnv *)handle;
246     if (shell->length == 0) {
247         return 0;
248     }
249     if (shell->cursor == shell->length) {
250         shell->length--;
251         shell->cursor--;
252         shell->buffer[shell->length] = 0;
253         BShellEnvBackspace(handle, 1);
254     } else if (shell->cursor > 0) {
255         for (short i = 0; i < shell->length - shell->cursor; i++) {
256             shell->buffer[shell->cursor + i - 1] = shell->buffer[shell->cursor + i];
257         }
258         shell->length--;
259         shell->cursor--;
260         shell->buffer[shell->length] = 0;
261         BShellEnvOutputByte(shell, '\b');
262         for (short i = shell->cursor; i < shell->length; i++) {
263             BShellEnvOutputByte(shell, shell->buffer[i]);
264         }
265         BShellEnvOutputByte(shell, ' ');
266         for (short i = shell->length - shell->cursor + 1; i > 0; i--) {
267             BShellEnvOutputByte(shell, '\b');
268         }
269     }
270     return 0;
271 }
272 
BShellEnvHandleTab(BShellHandle handle,uint8_t code)273 static int32_t BShellEnvHandleTab(BShellHandle handle, uint8_t code)
274 {
275     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
276     return 0;
277 }
278 
BShellEnvHandleNormal(BShellHandle handle,uint8_t data)279 static void BShellEnvHandleNormal(BShellHandle handle, uint8_t data)
280 {
281     BSH_CHECK(handle != NULL, return, "Invalid shell env");
282     BShellEnv *shell = (BShellEnv *)handle;
283     if (data == 0) {
284         return;
285     }
286     if (shell->length < BSH_COMMAND_MAX_LENGTH - 1) {
287         if (shell->length == shell->cursor) {
288             shell->buffer[shell->length++] = data;
289             shell->cursor++;
290             BShellEnvOutputByte(shell, data);
291         } else {
292             for (uint16_t i = shell->length - shell->cursor; i > 0; i--) {
293                 shell->buffer[shell->cursor + i] = shell->buffer[shell->cursor + i - 1];
294             }
295             shell->buffer[shell->cursor++] = data;
296             shell->buffer[++shell->length] = 0;
297             for (uint16_t i = shell->cursor - 1; i < shell->length; i++) {
298                 BShellEnvOutputByte(shell, shell->buffer[i]);
299             }
300             for (uint16_t i = shell->length - shell->cursor; i > 0; i--) {
301                 BShellEnvOutputByte(shell, '\b');
302             }
303         }
304     } else {
305         BShellEnvOutputString(shell, BShellEnvErrString(handle, BSH_CMD_TOO_LONG));
306         BShellEnvOutputString(shell, shell->prompt);
307 
308         shell->cursor = shell->length;
309     }
310 }
311 
BShellEnvHandleCtrC(BShellHandle handle,uint8_t code)312 static int32_t BShellEnvHandleCtrC(BShellHandle handle, uint8_t code)
313 {
314     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
315     BSH_LOGV("BShellEnvHandleCtrC %d", getpid());
316 #ifndef STARTUP_INIT_TEST
317     kill(getpid(), SIGKILL);
318 #endif
319     return 0;
320 }
321 
BShellEnvHandleEsc(BShellHandle handle,uint8_t code)322 static int32_t BShellEnvHandleEsc(BShellHandle handle, uint8_t code)
323 {
324     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
325     BShellEnv *shell = (BShellEnv *)handle;
326     shell->shellState = BSH_ANSI_ESC;
327     return 0;
328 }
329 
BShellEnvGetDefaultKey(uint8_t code)330 BShellKey *BShellEnvGetDefaultKey(uint8_t code)
331 {
332     static BShellKey defaultKeys[] = {
333         {BSH_KEY_LF, BShellEnvHandleEnter, NULL},
334         {BSH_KEY_CR, BShellEnvHandleEnter, NULL},
335         {BSH_KEY_TAB, BShellEnvHandleTab, NULL},
336         {BSH_KEY_BACKSPACE, BShellEnvHandleBackspace, NULL},
337         {BSH_KEY_DELETE, BShellEnvHandleBackspace, NULL},
338         {BSH_KEY_CTRLC, BShellEnvHandleCtrC, NULL},
339         {BSH_KEY_ESC, BShellEnvHandleEsc, NULL},
340     };
341     for (size_t i = 0; i < sizeof(defaultKeys) / sizeof(defaultKeys[0]); i++) {
342         if (defaultKeys[i].keyCode == code) {
343             return &defaultKeys[i];
344         }
345     }
346     return NULL;
347 }
348 
BShellEnvProcessInput(BShellHandle handle,char data)349 SHELLSTATIC void BShellEnvProcessInput(BShellHandle handle, char data)
350 {
351     BSH_CHECK(handle != NULL, return, "Invalid shell env");
352     BShellEnv *shell = (BShellEnv *)handle;
353     if (shell->shellState == BSH_IN_NORMAL) {
354         BShellKey *key = BShellEnvGetKey(handle, data);
355         if (key != NULL) {
356             key->keyHandle(shell, (uint8_t)data);
357             return;
358         }
359         key = BShellEnvGetDefaultKey(data);
360         if (key != NULL) {
361             key->keyHandle(shell, (uint8_t)data);
362             return;
363         }
364         BShellEnvHandleNormal(shell, data);
365     } else if (shell->shellState == BSH_ANSI_CSI) {
366         switch (data) {
367             case 0x41:  // up
368                 break;
369             case 0x42:  // down
370                 break;
371             case 0x43:  // ->
372                 if (shell->cursor < shell->length) {
373                     BShellEnvOutputByte(handle, shell->buffer[shell->cursor]);
374                     shell->cursor++;
375                 }
376                 break;
377             case 0x44:  // <-
378                 if (shell->cursor > 0) {
379                     BShellEnvOutputByte(shell, '\b');
380                     shell->cursor--;
381                 }
382                 break;
383             default:
384                 break;
385         }
386         shell->shellState = BSH_IN_NORMAL;
387     } else if (shell->shellState == BSH_ANSI_ESC) {
388         if (data == 0x5B) { // input up/down
389             shell->shellState = BSH_ANSI_CSI;
390         } else {
391             shell->shellState = BSH_IN_NORMAL;
392         }
393     }
394 }
395 
BShellEnvLoop(BShellHandle handle)396 void BShellEnvLoop(BShellHandle handle)
397 {
398     BSH_CHECK(handle != NULL, return, "Invalid shell env");
399     BShellEnv *shell = (BShellEnv *)handle;
400     BSH_CHECK(shell->input != NULL, return, "Invalid shell input");
401     while (1) {
402         char data = 0;
403         if (shell->input(&data, 1) == 1) {
404             BShellEnvProcessInput(shell, data);
405         }
406     }
407 }
408 
BShellEnvInit(BShellHandle * handle,const BShellInfo * info)409 int32_t BShellEnvInit(BShellHandle *handle, const BShellInfo *info)
410 {
411     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
412     BSH_CHECK(info != NULL && info->prompt != NULL, return BSH_INVALID_PARAM, "Invalid cmd name");
413 
414     BShellEnv *shell = (BShellEnv *)calloc(1, sizeof(BShellEnv));
415     BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Failed to create shell env");
416     shell->length = 0;
417     shell->cursor = 0;
418     shell->shellState = BSH_IN_NORMAL;
419     shell->input = info->input;
420     shell->prompt = strdup(info->prompt);
421     shell->command = NULL;
422     shell->param = NULL;
423     shell->keyHandle = NULL;
424     shell->execMode = BSH_EXEC_INDEPENDENT;
425     *handle = (BShellHandle)shell;
426     return 0;
427 }
428 
BShellEnvStart(BShellHandle handle)429 int BShellEnvStart(BShellHandle handle)
430 {
431     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
432     BShellEnv *shell = (BShellEnv *)handle;
433     shell->execMode = BSH_EXEC_TASK;
434     BShellEnvOutputString(handle, BShellEnvErrString(handle, BSH_SHELL_INFO));
435     BShellEnvOutputString(handle, shell->prompt);
436 
437     const CmdInfo infos[] = {
438         {"exit", BShellCmdExit, "exit parameter shell", "exit"},
439         {"help", BShellCmdHelp, "help command", "help"}
440     };
441     for (size_t i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) {
442         BShellEnvRegisterCmd(handle, &infos[i]);
443     }
444     return 0;
445 }
446 
BShellParamFree(BShellParam * param)447 static void BShellParamFree(BShellParam *param)
448 {
449     if (param->desc != NULL) {
450         free(param->desc);
451     }
452     if (param->type == PARAM_STRING && param->value.string != NULL) {
453         free(param->value.string);
454     }
455     free(param);
456 }
457 
BShellCmdFree(BShellCommand * cmd)458 static void BShellCmdFree(BShellCommand *cmd)
459 {
460     if (cmd->desc != NULL) {
461         free(cmd->desc);
462         cmd->desc = NULL;
463     }
464     if (cmd->help != NULL) {
465         free(cmd->help);
466         cmd->help = NULL;
467     }
468     if (cmd->multikey != NULL) {
469         free(cmd->multikey);
470         cmd->multikey = NULL;
471     }
472     free(cmd);
473 }
474 
BShellEnvDestory(BShellHandle handle)475 void BShellEnvDestory(BShellHandle handle)
476 {
477     BSH_CHECK(handle != NULL, return, "Invalid shell env");
478     BShellEnv *shell = (BShellEnv *)handle;
479 
480     BShellCommand *cmd = shell->command;
481     while (cmd != NULL) {
482         shell->command = cmd->next;
483         BShellCmdFree(cmd);
484         cmd = shell->command;
485     }
486 
487     BShellParam *param = shell->param;
488     while (param != NULL) {
489         shell->param = param->next;
490         BShellParamFree(param);
491         param = shell->param;
492     }
493 
494     BShellKey *key = shell->keyHandle;
495     while (key != NULL) {
496         shell->keyHandle = key->next;
497         free(key);
498         key = shell->keyHandle;
499     }
500     if (shell->prompt != NULL) {
501         free(shell->prompt);
502     }
503     free(shell);
504 }
505 
BShellEnvRegisterCmd(BShellHandle handle,const CmdInfo * cmdInfo)506 int32_t BShellEnvRegisterCmd(BShellHandle handle, const CmdInfo *cmdInfo)
507 {
508     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
509     BSH_CHECK(cmdInfo != NULL && cmdInfo->name != NULL, return BSH_INVALID_PARAM, "Invalid cmd name");
510     BSH_CHECK(cmdInfo->executer != NULL, return BSH_INVALID_PARAM, "Invalid cmd executer");
511     BShellEnv *shell = (BShellEnv *)handle;
512     size_t nameLen = strlen(cmdInfo->name) + 1;
513     BShellCommand *cmd = (BShellCommand *)calloc(1, sizeof(BShellCommand) + nameLen);
514     BSH_CHECK(cmd != NULL, return BSH_INVALID_PARAM, "Failed to alloc cmd name %s", cmdInfo->name);
515     cmd->executer = cmdInfo->executer;
516     cmd->argStart = 0;
517     int32_t ret = 0;
518     do {
519         ret = strcpy_s(cmd->name, nameLen, cmdInfo->name);
520         BSH_CHECK(ret == 0, break, "Failed to copy name %s", cmdInfo->name);
521 
522         ret = BSH_SYSTEM_ERR;
523         if (cmdInfo->desc != NULL) {
524             cmd->desc = strdup(cmdInfo->desc);
525             BSH_CHECK(cmd->desc != NULL, break, "Failed to copy desc %s", cmdInfo->name);
526         }
527         if (cmdInfo->help != NULL) {
528             cmd->help = strdup(cmdInfo->help);
529             BSH_CHECK(cmd->help != NULL, break, "Failed to copy help %s", cmdInfo->name);
530         }
531         cmd->multikey = NULL;
532         if (cmdInfo->multikey != NULL && strlen(cmdInfo->multikey) > nameLen) {
533             cmd->multikey = strdup(cmdInfo->multikey);
534             BSH_CHECK(cmd->multikey != NULL, break, "Failed to copy multikey %s", cmdInfo->name);
535             int argc = SplitString(cmd->multikey, " ", cmd->multikeys, (int)ARRAY_LENGTH(cmd->multikeys));
536             BSH_CHECK(argc <= (int)ARRAY_LENGTH(cmd->multikeys) && argc > 0, break, "Invalid multikey");
537             cmd->argStart = argc - 1;
538             if (argc == 1) {
539                 free(cmd->multikey);
540                 cmd->multikey = NULL;
541             }
542         }
543         ret = 0;
544     } while (0);
545     if (ret != 0) {
546         BShellCmdFree(cmd);
547         return ret;
548     }
549     cmd->next = shell->command;
550     shell->command = cmd;
551     return 0;
552 }
553 
GetRealCmdName(const char * name)554 static const char *GetRealCmdName(const char *name)
555 {
556     int i = 0;
557     int last = 0;
558     while (*(name + i) != '\0') {
559         if (*(name + i) == '/') {
560             last = i;
561         }
562         i++;
563     }
564     if (last != 0) {
565         return name + last + 1;
566     } else {
567         return name;
568     }
569 }
570 
BShellEnvGetCmd(BShellHandle handle,int32_t argc,char * argv[])571 BShellCommand *BShellEnvGetCmd(BShellHandle handle, int32_t argc, char *argv[])
572 {
573     BSH_CHECK(handle != NULL, return NULL, "Invalid shell env");
574     BSH_CHECK(argc >= 1, return NULL, "Invalid argc");
575     const char *cmdName = GetRealCmdName(argv[0]);
576     BSH_LOGV("BShellEnvGetCmd %s cmd %s", argv[0], cmdName);
577     BShellEnv *shell = (BShellEnv *)handle;
578     BShellCommand *cmd = shell->command;
579     while (cmd != NULL) {
580         if (strcmp(cmd->name, cmdName) != 0) {
581             cmd = cmd->next;
582             continue;
583         }
584         if (cmd->multikey == NULL) {
585             return cmd;
586         }
587         int32_t i = 0;
588         for (i = 0; i < (int32_t)ARRAY_LENGTH(cmd->multikeys) && i < argc; i++) {
589             if (cmd->multikeys[i] == NULL) {
590                 return cmd;
591             }
592             char *tmp = argv[i];
593             if (i == 0) {
594                 tmp = (char *)cmdName;
595             }
596             if (strcmp(cmd->multikeys[i], tmp) != 0) {
597                 break;
598             }
599         }
600         if (i >= (int32_t)ARRAY_LENGTH(cmd->multikeys)) {
601             return cmd;
602         }
603         if (i >= argc) {
604             if (cmd->multikeys[i] == NULL) {
605                 return cmd;
606             }
607         }
608         cmd = cmd->next;
609     }
610     return NULL;
611 }
612 
BShellEnvRegisterKeyHandle(BShellHandle handle,uint8_t code,BShellkeyHandle keyHandle)613 int32_t BShellEnvRegisterKeyHandle(BShellHandle handle, uint8_t code, BShellkeyHandle keyHandle)
614 {
615     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
616     BSH_CHECK(keyHandle != NULL, return BSH_INVALID_PARAM, "Invalid cmd name");
617     BShellEnv *shell = (BShellEnv *)handle;
618 
619     BShellKey *key = (BShellKey *)calloc(1, sizeof(BShellKey));
620     BSH_CHECK(key != NULL, return BSH_INVALID_PARAM, "Failed to alloc key code %d", code);
621     key->keyCode = code;
622     key->keyHandle = keyHandle;
623     key->next = shell->keyHandle;
624     shell->keyHandle = key;
625     return 0;
626 }
627 
BShellEnvGetKey(BShellHandle handle,uint8_t code)628 BShellKey *BShellEnvGetKey(BShellHandle handle, uint8_t code)
629 {
630     BSH_CHECK(handle != NULL, return NULL, "Invalid shell env");
631     BShellEnv *shell = (BShellEnv *)handle;
632     BShellKey *key = shell->keyHandle;
633     while (key != NULL) {
634         if (key->keyCode == code) {
635             return key;
636         }
637         key = key->next;
638     }
639     return NULL;
640 }
641 
BShellParamSetValue(BShellParam * param,void * value)642 static int32_t BShellParamSetValue(BShellParam *param, void *value)
643 {
644     static uint32_t paramValueLens[] = {
645         sizeof(uint8_t), sizeof(uint16_t), sizeof(uint32_t), sizeof(char *)
646     };
647     if (param->type == PARAM_STRING) {
648         if (param->value.string != NULL) {
649             free(param->value.string);
650         }
651         param->value.string = strdup((char *)value);
652         BSH_CHECK(param->value.string != NULL, return BSH_SYSTEM_ERR, "Failed to copy value for %s", param->name);
653     } else if (param->type < PARAM_STRING) {
654         int ret = memcpy_s(&param->value, sizeof(param->value), value, paramValueLens[param->type]);
655         BSH_CHECK(ret == 0, return BSH_SYSTEM_ERR, "Failed to copy value for %s", param->name);
656     }
657     return 0;
658 }
659 
BShellEnvSetParam(BShellHandle handle,const char * name,const char * desc,BShellParamType type,void * value)660 int32_t BShellEnvSetParam(BShellHandle handle, const char *name, const char *desc, BShellParamType type, void *value)
661 {
662     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
663     BSH_CHECK(name != NULL, return BSH_INVALID_PARAM, "Invalid param name");
664     BSH_CHECK(value != NULL, return BSH_INVALID_PARAM, "Invalid cmd value");
665     BSH_CHECK(type <= PARAM_STRING, return BSH_INVALID_PARAM, "Invalid param type");
666     BShellEnv *shell = (BShellEnv *)handle;
667     const BShellParam *tmp = BShellEnvGetParam(handle, name);
668     if (tmp != NULL) {
669         BSH_CHECK(tmp->type <= type, return BSH_INVALID_PARAM, "Invalid param type %d", tmp->type);
670         return BShellParamSetValue((BShellParam *)tmp, value);
671     }
672     int32_t ret = 0;
673     BShellParam *param = NULL;
674     do {
675         size_t nameLen = strlen(name) + 1;
676         param = (BShellParam *)calloc(1, sizeof(BShellParam) + nameLen);
677         BSH_CHECK(param != NULL, return BSH_SYSTEM_ERR, "Failed to alloc cmd name %s", name);
678         param->type = type;
679         ret = strcpy_s(param->name, nameLen, name);
680         BSH_CHECK(ret == 0, break, "Failed to copy name %s", name);
681         if (desc != NULL) {
682             param->desc = strdup(desc);
683         }
684         ret = BShellParamSetValue(param, value);
685         BSH_CHECK(ret == 0, break, "Failed set value for %s", name);
686 
687         param->next = shell->param;
688         shell->param = param;
689     } while (0);
690     if (ret != 0) {
691         BShellParamFree(param);
692     }
693     return ret;
694 }
695 
BShellEnvGetParam(BShellHandle handle,const char * name)696 const BShellParam *BShellEnvGetParam(BShellHandle handle, const char *name)
697 {
698     BSH_CHECK(handle != NULL, return NULL, "Invalid shell env");
699     BShellEnv *shell = (BShellEnv *)handle;
700     BShellParam *param = shell->param;
701     while (param != NULL) {
702         if (strcmp(name, param->name) == 0) {
703             return param;
704         }
705         param = param->next;
706     }
707     return NULL;
708 }
709 
BShellEnvGetStringParam(BShellHandle handle,const char * name)710 const char *BShellEnvGetStringParam(BShellHandle handle, const char *name)
711 {
712     BSH_CHECK(handle != NULL, return "", "Invalid shell env");
713     const BShellParam *param = BShellEnvGetParam(handle, name);
714     if (param == NULL) {
715         return "";
716     }
717     switch (param->type) {
718         case PARAM_STRING:
719             return param->value.string;
720         default:
721             break;
722     }
723     return "";
724 }
725 
BShellEnvGetReservedParam(BShellHandle handle,const char * name)726 const ParamInfo *BShellEnvGetReservedParam(BShellHandle handle, const char *name)
727 {
728     BSH_CHECK(handle != NULL, return NULL, "Invalid shell env");
729     static ParamInfo reservedParams[] = {
730         {PARAM_REVERESD_NAME_CURR_PARAMETER, "current parameter", PARAM_STRING}
731     };
732     for (size_t i = 0; i < sizeof(reservedParams) / sizeof(reservedParams[0]); i++) {
733         if (strcmp(name, reservedParams[i].name) == 0) {
734             return &reservedParams[i];
735         }
736     }
737     return NULL;
738 }
739 
BShellEnvDirectExecute(BShellHandle handle,int argc,char * args[])740 int32_t BShellEnvDirectExecute(BShellHandle handle, int argc, char *args[])
741 {
742     BSH_CHECK(handle != NULL, return -1, "Invalid shell env");
743     BShellCommand *cmd = BShellEnvGetCmd(handle, argc, args);
744     if (cmd != NULL) {
745         int32_t ret = cmd->executer(handle, argc - cmd->argStart, &args[cmd->argStart]);
746         BShellEnvOutputResult(handle, ret);
747     } else {
748         if (argc > 1) {
749             BShellEnvOutputString(handle, BShellEnvErrString(handle, BSH_CMD_NOT_EXIST));
750         }
751         BShellCmdHelp(handle, argc, args);
752     }
753     return 0;
754 }
755