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         BSH_CHECK(shell->prompt != NULL, return BSH_INVALID_PARAM, "strdup prompt failed.");
136     }
137     return 0;
138 }
139 
BShellEnvOutputByte(BShellHandle handle,char data)140 void BShellEnvOutputByte(BShellHandle handle, char data)
141 {
142     BSH_CHECK(handle != NULL, return, "Invalid shell env");
143     printf("%c", data);
144     (void)fflush(stdout);
145 }
146 
BShellEnvOutputResult(BShellHandle handle,int32_t result)147 void BShellEnvOutputResult(BShellHandle handle, int32_t result)
148 {
149     if (result == 0) {
150         return;
151     }
152     printf("result: 0x%08x\r\n", result);
153     (void)fflush(stdout);
154 }
155 
BShellEnvOutputParam(BShellHandle handle,char * var)156 static void BShellEnvOutputParam(BShellHandle handle, char *var)
157 {
158     BShellEnvOutput(handle, (var[0] == '$') ? var + 1 : var);
159     BShellEnvOutputString(handle, " = ");
160     BShellEnvOutputString(handle, BShellEnvGetStringParam(handle, var));
161 }
162 
BShellEnvBackspace(BShellHandle handle,uint32_t length)163 void BShellEnvBackspace(BShellHandle handle, uint32_t length)
164 {
165     for (uint32_t i = 0; i < length; i++) {
166         BShellEnvOutputString(handle, "\b \b");
167     }
168 }
169 
BShellEnvParseParam(BShellEnv * shell)170 static void BShellEnvParseParam(BShellEnv *shell)
171 {
172     uint8_t quotes = 0;
173     uint8_t record = 1;
174     shell->argc = 0;
175     for (uint16_t i = 0; i < shell->length; i++) {
176         char data = *(shell->buffer + i);
177         if ((quotes != 0 || (data != ' ' && data != '\t' && data != ',')) && data != 0) {
178             if (data == '\"') {
179                 quotes = quotes ? 0 : 1;
180             }
181             if (record == 1) {
182                 BSH_CHECK(shell->argc < BSH_PARAMETER_MAX_NUMBER, return, "argc out of range");
183                 shell->args[shell->argc++] = shell->buffer + i;
184                 record = 0;
185             }
186             if (*(shell->buffer + i) == '\\' && *(shell->buffer + i + 1) != 0) {
187                 i++;
188             }
189         } else {
190             *(shell->buffer + i) = 0;
191             record = 1;
192         }
193     }
194 }
195 
BShellEnvExcuteCmd(BShellEnv * shell,BShellCommand * cmd)196 static int32_t BShellEnvExcuteCmd(BShellEnv *shell, BShellCommand *cmd)
197 {
198     return cmd->executer((BShellHandle)shell, shell->argc - cmd->argStart, &shell->args[cmd->argStart]);
199 }
200 
BShellEnvHandleEnter(BShellHandle handle,uint8_t data)201 static int32_t BShellEnvHandleEnter(BShellHandle handle, uint8_t data)
202 {
203     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
204     BShellEnv *shell = (BShellEnv *)handle;
205     if (shell->length == 0) {
206         BShellEnvOutputString(shell, "\n");
207         BShellEnvOutputString(handle, shell->prompt);
208         return 0;
209     }
210 
211     *(shell->buffer + shell->length++) = 0;
212     BShellEnvParseParam(shell);
213     shell->length = 0;
214     shell->cursor = 0;
215     if (shell->argc == 0) {
216         BShellEnvOutputString(shell, shell->prompt);
217         return 0;
218     }
219 
220     BShellEnvOutputString(shell, "\n");
221     if (strcmp((const char *)shell->args[0], "help") == 0) {
222         BShellCmdHelp(handle, shell->argc, shell->args);
223         BShellEnvOutputString(shell, shell->prompt);
224         return 0;
225     }
226     if (shell->args[0][0] == '$') {
227         BShellEnvOutputParam(shell, shell->args[0]);
228         BShellEnvOutputString(shell, shell->prompt);
229         return 0;
230     }
231 
232     BShellCommand *cmd = BShellEnvGetCmd(handle, (uint32_t)shell->argc, shell->args);
233     if (cmd != NULL) {
234         int32_t ret = BShellEnvExcuteCmd(shell, cmd);
235         BShellEnvOutputResult(shell, ret);
236     } else {
237         BShellEnvOutputString(shell, BShellEnvErrString(handle, BSH_CMD_NOT_EXIST));
238     }
239     BShellEnvOutputString(shell, shell->prompt);
240     return 0;
241 }
242 
BShellEnvHandleBackspace(BShellHandle handle,uint8_t code)243 static int32_t BShellEnvHandleBackspace(BShellHandle handle, uint8_t code)
244 {
245     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
246     BShellEnv *shell = (BShellEnv *)handle;
247     if (shell->length == 0) {
248         return 0;
249     }
250     if (shell->cursor == shell->length) {
251         shell->length--;
252         shell->cursor--;
253         shell->buffer[shell->length] = 0;
254         BShellEnvBackspace(handle, 1);
255     } else if (shell->cursor > 0) {
256         for (short i = 0; i < shell->length - shell->cursor; i++) {
257             shell->buffer[shell->cursor + i - 1] = shell->buffer[shell->cursor + i];
258         }
259         shell->length--;
260         shell->cursor--;
261         shell->buffer[shell->length] = 0;
262         BShellEnvOutputByte(shell, '\b');
263         for (short i = shell->cursor; i < shell->length; i++) {
264             BShellEnvOutputByte(shell, shell->buffer[i]);
265         }
266         BShellEnvOutputByte(shell, ' ');
267         for (short i = shell->length - shell->cursor + 1; i > 0; i--) {
268             BShellEnvOutputByte(shell, '\b');
269         }
270     }
271     return 0;
272 }
273 
BShellEnvHandleTab(BShellHandle handle,uint8_t code)274 static int32_t BShellEnvHandleTab(BShellHandle handle, uint8_t code)
275 {
276     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
277     return 0;
278 }
279 
BShellEnvHandleNormal(BShellHandle handle,uint8_t data)280 static void BShellEnvHandleNormal(BShellHandle handle, uint8_t data)
281 {
282     BSH_CHECK(handle != NULL, return, "Invalid shell env");
283     BShellEnv *shell = (BShellEnv *)handle;
284     if (data == 0) {
285         return;
286     }
287     if (shell->length < BSH_COMMAND_MAX_LENGTH - 1) {
288         if (shell->length == shell->cursor) {
289             shell->buffer[shell->length++] = data;
290             shell->cursor++;
291             BShellEnvOutputByte(shell, data);
292         } else {
293             for (uint16_t i = shell->length - shell->cursor; i > 0; i--) {
294                 shell->buffer[shell->cursor + i] = shell->buffer[shell->cursor + i - 1];
295             }
296             shell->buffer[shell->cursor++] = data;
297             shell->buffer[++shell->length] = 0;
298             for (uint16_t i = shell->cursor - 1; i < shell->length; i++) {
299                 BShellEnvOutputByte(shell, shell->buffer[i]);
300             }
301             for (uint16_t i = shell->length - shell->cursor; i > 0; i--) {
302                 BShellEnvOutputByte(shell, '\b');
303             }
304         }
305     } else {
306         BShellEnvOutputString(shell, BShellEnvErrString(handle, BSH_CMD_TOO_LONG));
307         BShellEnvOutputString(shell, shell->prompt);
308 
309         shell->cursor = shell->length;
310     }
311 }
312 
BShellEnvHandleCtrC(BShellHandle handle,uint8_t code)313 static int32_t BShellEnvHandleCtrC(BShellHandle handle, uint8_t code)
314 {
315     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
316     BSH_LOGV("BShellEnvHandleCtrC %d", getpid());
317 #ifndef STARTUP_INIT_TEST
318     kill(getpid(), SIGKILL);
319 #endif
320     return 0;
321 }
322 
BShellEnvHandleEsc(BShellHandle handle,uint8_t code)323 static int32_t BShellEnvHandleEsc(BShellHandle handle, uint8_t code)
324 {
325     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
326     BShellEnv *shell = (BShellEnv *)handle;
327     shell->shellState = BSH_ANSI_ESC;
328     return 0;
329 }
330 
BShellEnvGetDefaultKey(uint8_t code)331 BShellKey *BShellEnvGetDefaultKey(uint8_t code)
332 {
333     static BShellKey defaultKeys[] = {
334         {BSH_KEY_LF, BShellEnvHandleEnter, NULL},
335         {BSH_KEY_CR, BShellEnvHandleEnter, NULL},
336         {BSH_KEY_TAB, BShellEnvHandleTab, NULL},
337         {BSH_KEY_BACKSPACE, BShellEnvHandleBackspace, NULL},
338         {BSH_KEY_DELETE, BShellEnvHandleBackspace, NULL},
339         {BSH_KEY_CTRLC, BShellEnvHandleCtrC, NULL},
340         {BSH_KEY_ESC, BShellEnvHandleEsc, NULL},
341     };
342     for (size_t i = 0; i < sizeof(defaultKeys) / sizeof(defaultKeys[0]); i++) {
343         if (defaultKeys[i].keyCode == code) {
344             return &defaultKeys[i];
345         }
346     }
347     return NULL;
348 }
349 
BShellEnvProcessInput(BShellHandle handle,char data)350 SHELLSTATIC void BShellEnvProcessInput(BShellHandle handle, char data)
351 {
352     BSH_CHECK(handle != NULL, return, "Invalid shell env");
353     BShellEnv *shell = (BShellEnv *)handle;
354     if (shell->shellState == BSH_IN_NORMAL) {
355         BShellKey *key = BShellEnvGetKey(handle, data);
356         if (key != NULL) {
357             key->keyHandle(shell, (uint8_t)data);
358             return;
359         }
360         key = BShellEnvGetDefaultKey(data);
361         if (key != NULL) {
362             key->keyHandle(shell, (uint8_t)data);
363             return;
364         }
365         BShellEnvHandleNormal(shell, data);
366     } else if (shell->shellState == BSH_ANSI_CSI) {
367         switch (data) {
368             case 0x41:  // up
369                 break;
370             case 0x42:  // down
371                 break;
372             case 0x43:  // ->
373                 if (shell->cursor < shell->length) {
374                     BShellEnvOutputByte(handle, shell->buffer[shell->cursor]);
375                     shell->cursor++;
376                 }
377                 break;
378             case 0x44:  // <-
379                 if (shell->cursor > 0) {
380                     BShellEnvOutputByte(shell, '\b');
381                     shell->cursor--;
382                 }
383                 break;
384             default:
385                 break;
386         }
387         shell->shellState = BSH_IN_NORMAL;
388     } else if (shell->shellState == BSH_ANSI_ESC) {
389         if (data == 0x5B) { // input up/down
390             shell->shellState = BSH_ANSI_CSI;
391         } else {
392             shell->shellState = BSH_IN_NORMAL;
393         }
394     }
395 }
396 
BShellEnvLoop(BShellHandle handle)397 void BShellEnvLoop(BShellHandle handle)
398 {
399     BSH_CHECK(handle != NULL, return, "Invalid shell env");
400     BShellEnv *shell = (BShellEnv *)handle;
401     BSH_CHECK(shell->input != NULL, return, "Invalid shell input");
402     while (1) {
403         char data = 0;
404         if (shell->input(&data, 1) == 1) {
405             BShellEnvProcessInput(shell, data);
406         }
407     }
408 }
409 
BShellEnvInit(BShellHandle * handle,const BShellInfo * info)410 int32_t BShellEnvInit(BShellHandle *handle, const BShellInfo *info)
411 {
412     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
413     BSH_CHECK(info != NULL && info->prompt != NULL, return BSH_INVALID_PARAM, "Invalid cmd name");
414 
415     BShellEnv *shell = (BShellEnv *)calloc(1, sizeof(BShellEnv));
416     BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Failed to create shell env");
417     shell->length = 0;
418     shell->cursor = 0;
419     shell->shellState = BSH_IN_NORMAL;
420     shell->input = info->input;
421     shell->prompt = strdup(info->prompt);
422     BSH_CHECK(shell->prompt != NULL, free(shell); return BSH_INVALID_PARAM, "Failed to strdup prompt");
423     shell->command = NULL;
424     shell->param = NULL;
425     shell->keyHandle = NULL;
426     shell->execMode = BSH_EXEC_INDEPENDENT;
427     *handle = (BShellHandle)shell;
428     return 0;
429 }
430 
BShellEnvStart(BShellHandle handle)431 int BShellEnvStart(BShellHandle handle)
432 {
433     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
434     BShellEnv *shell = (BShellEnv *)handle;
435     shell->execMode = BSH_EXEC_TASK;
436     BShellEnvOutputString(handle, BShellEnvErrString(handle, BSH_SHELL_INFO));
437     BShellEnvOutputString(handle, shell->prompt);
438 
439     const CmdInfo infos[] = {
440         {"exit", BShellCmdExit, "exit parameter shell", "exit"},
441         {"help", BShellCmdHelp, "help command", "help"}
442     };
443     for (size_t i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) {
444         BShellEnvRegisterCmd(handle, &infos[i]);
445     }
446     return 0;
447 }
448 
BShellParamFree(BShellParam * param)449 static void BShellParamFree(BShellParam *param)
450 {
451     if (param->desc != NULL) {
452         free(param->desc);
453     }
454     if (param->type == PARAM_STRING && param->value.string != NULL) {
455         free(param->value.string);
456     }
457     free(param);
458 }
459 
BShellCmdFree(BShellCommand * cmd)460 static void BShellCmdFree(BShellCommand *cmd)
461 {
462     if (cmd->desc != NULL) {
463         free(cmd->desc);
464         cmd->desc = NULL;
465     }
466     if (cmd->help != NULL) {
467         free(cmd->help);
468         cmd->help = NULL;
469     }
470     if (cmd->multikey != NULL) {
471         free(cmd->multikey);
472         cmd->multikey = NULL;
473     }
474     free(cmd);
475 }
476 
BShellEnvDestory(BShellHandle handle)477 void BShellEnvDestory(BShellHandle handle)
478 {
479     BSH_CHECK(handle != NULL, return, "Invalid shell env");
480     BShellEnv *shell = (BShellEnv *)handle;
481 
482     BShellCommand *cmd = shell->command;
483     while (cmd != NULL) {
484         shell->command = cmd->next;
485         BShellCmdFree(cmd);
486         cmd = shell->command;
487     }
488 
489     BShellParam *param = shell->param;
490     while (param != NULL) {
491         shell->param = param->next;
492         BShellParamFree(param);
493         param = shell->param;
494     }
495 
496     BShellKey *key = shell->keyHandle;
497     while (key != NULL) {
498         shell->keyHandle = key->next;
499         free(key);
500         key = shell->keyHandle;
501     }
502     if (shell->prompt != NULL) {
503         free(shell->prompt);
504     }
505     free(shell);
506 }
507 
BShellEnvRegisterCmd(BShellHandle handle,const CmdInfo * cmdInfo)508 int32_t BShellEnvRegisterCmd(BShellHandle handle, const CmdInfo *cmdInfo)
509 {
510     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
511     BSH_CHECK(cmdInfo != NULL && cmdInfo->name != NULL, return BSH_INVALID_PARAM, "Invalid cmd name");
512     BSH_CHECK(cmdInfo->executer != NULL, return BSH_INVALID_PARAM, "Invalid cmd executer");
513     BShellEnv *shell = (BShellEnv *)handle;
514     size_t nameLen = strlen(cmdInfo->name) + 1;
515     BShellCommand *cmd = (BShellCommand *)calloc(1, sizeof(BShellCommand) + nameLen);
516     BSH_CHECK(cmd != NULL, return BSH_INVALID_PARAM, "Failed to alloc cmd name %s", cmdInfo->name);
517     cmd->executer = cmdInfo->executer;
518     cmd->argStart = 0;
519     int32_t ret = 0;
520     do {
521         ret = strcpy_s(cmd->name, nameLen, cmdInfo->name);
522         BSH_CHECK(ret == 0, break, "Failed to copy name %s", cmdInfo->name);
523 
524         ret = BSH_SYSTEM_ERR;
525         if (cmdInfo->desc != NULL) {
526             cmd->desc = strdup(cmdInfo->desc);
527             BSH_CHECK(cmd->desc != NULL, break, "Failed to copy desc %s", cmdInfo->name);
528         }
529         if (cmdInfo->help != NULL) {
530             cmd->help = strdup(cmdInfo->help);
531             BSH_CHECK(cmd->help != NULL, break, "Failed to copy help %s", cmdInfo->name);
532         }
533         cmd->multikey = NULL;
534         if (cmdInfo->multikey != NULL && strlen(cmdInfo->multikey) > nameLen) {
535             cmd->multikey = strdup(cmdInfo->multikey);
536             BSH_CHECK(cmd->multikey != NULL, break, "Failed to copy multikey %s", cmdInfo->name);
537             int argc = SplitString(cmd->multikey, " ", cmd->multikeys, (int)ARRAY_LENGTH(cmd->multikeys));
538             BSH_CHECK(argc <= (int)ARRAY_LENGTH(cmd->multikeys) && argc > 0, break, "Invalid multikey");
539             cmd->argStart = argc - 1;
540             if (argc == 1) {
541                 free(cmd->multikey);
542                 cmd->multikey = NULL;
543             }
544         }
545         ret = 0;
546     } while (0);
547     if (ret != 0) {
548         BShellCmdFree(cmd);
549         return ret;
550     }
551     cmd->next = shell->command;
552     shell->command = cmd;
553     return 0;
554 }
555 
GetRealCmdName(const char * name)556 static const char *GetRealCmdName(const char *name)
557 {
558     int i = 0;
559     int last = 0;
560     while (*(name + i) != '\0') {
561         if (*(name + i) == '/') {
562             last = i;
563         }
564         i++;
565     }
566     if (last != 0) {
567         return name + last + 1;
568     } else {
569         return name;
570     }
571 }
572 
BShellEnvGetCmd(BShellHandle handle,int32_t argc,char * argv[])573 BShellCommand *BShellEnvGetCmd(BShellHandle handle, int32_t argc, char *argv[])
574 {
575     BSH_CHECK(handle != NULL, return NULL, "Invalid shell env");
576     BSH_CHECK(argc >= 1, return NULL, "Invalid argc");
577     const char *cmdName = GetRealCmdName(argv[0]);
578     BSH_LOGV("BShellEnvGetCmd %s cmd %s", argv[0], cmdName);
579     BShellEnv *shell = (BShellEnv *)handle;
580     BShellCommand *cmd = shell->command;
581     while (cmd != NULL) {
582         if (strcmp(cmd->name, cmdName) != 0) {
583             cmd = cmd->next;
584             continue;
585         }
586         if (cmd->multikey == NULL) {
587             return cmd;
588         }
589         int32_t i = 0;
590         for (i = 0; i < (int32_t)ARRAY_LENGTH(cmd->multikeys) && i < argc; i++) {
591             if (cmd->multikeys[i] == NULL) {
592                 return cmd;
593             }
594             char *tmp = argv[i];
595             if (i == 0) {
596                 tmp = (char *)cmdName;
597             }
598             if (strcmp(cmd->multikeys[i], tmp) != 0) {
599                 break;
600             }
601         }
602         if (i >= (int32_t)ARRAY_LENGTH(cmd->multikeys)) {
603             return cmd;
604         }
605         if (i >= argc) {
606             if (cmd->multikeys[i] == NULL) {
607                 return cmd;
608             }
609         }
610         cmd = cmd->next;
611     }
612     return NULL;
613 }
614 
BShellEnvRegisterKeyHandle(BShellHandle handle,uint8_t code,BShellkeyHandle keyHandle)615 int32_t BShellEnvRegisterKeyHandle(BShellHandle handle, uint8_t code, BShellkeyHandle keyHandle)
616 {
617     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
618     BSH_CHECK(keyHandle != NULL, return BSH_INVALID_PARAM, "Invalid cmd name");
619     BShellEnv *shell = (BShellEnv *)handle;
620 
621     BShellKey *key = (BShellKey *)calloc(1, sizeof(BShellKey));
622     BSH_CHECK(key != NULL, return BSH_INVALID_PARAM, "Failed to alloc key code %d", code);
623     key->keyCode = code;
624     key->keyHandle = keyHandle;
625     key->next = shell->keyHandle;
626     shell->keyHandle = key;
627     return 0;
628 }
629 
BShellEnvGetKey(BShellHandle handle,uint8_t code)630 BShellKey *BShellEnvGetKey(BShellHandle handle, uint8_t code)
631 {
632     BSH_CHECK(handle != NULL, return NULL, "Invalid shell env");
633     BShellEnv *shell = (BShellEnv *)handle;
634     BShellKey *key = shell->keyHandle;
635     while (key != NULL) {
636         if (key->keyCode == code) {
637             return key;
638         }
639         key = key->next;
640     }
641     return NULL;
642 }
643 
BShellParamSetValue(BShellParam * param,void * value)644 static int32_t BShellParamSetValue(BShellParam *param, void *value)
645 {
646     static uint32_t paramValueLens[] = {
647         sizeof(uint8_t), sizeof(uint16_t), sizeof(uint32_t), sizeof(char *)
648     };
649     if (param->type == PARAM_STRING) {
650         if (param->value.string != NULL) {
651             free(param->value.string);
652         }
653         param->value.string = strdup((char *)value);
654         BSH_CHECK(param->value.string != NULL, return BSH_SYSTEM_ERR, "Failed to copy value for %s", param->name);
655     } else if (param->type < PARAM_STRING) {
656         int ret = memcpy_s(&param->value, sizeof(param->value), value, paramValueLens[param->type]);
657         BSH_CHECK(ret == 0, return BSH_SYSTEM_ERR, "Failed to copy value for %s", param->name);
658     }
659     return 0;
660 }
661 
BShellEnvSetParam(BShellHandle handle,const char * name,const char * desc,BShellParamType type,void * value)662 int32_t BShellEnvSetParam(BShellHandle handle, const char *name, const char *desc, BShellParamType type, void *value)
663 {
664     BSH_CHECK(handle != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
665     BSH_CHECK(name != NULL, return BSH_INVALID_PARAM, "Invalid param name");
666     BSH_CHECK(value != NULL, return BSH_INVALID_PARAM, "Invalid cmd value");
667     BSH_CHECK(type <= PARAM_STRING, return BSH_INVALID_PARAM, "Invalid param type");
668     BShellEnv *shell = (BShellEnv *)handle;
669     const BShellParam *tmp = BShellEnvGetParam(handle, name);
670     if (tmp != NULL) {
671         BSH_CHECK(tmp->type <= type, return BSH_INVALID_PARAM, "Invalid param type %d", tmp->type);
672         return BShellParamSetValue((BShellParam *)tmp, value);
673     }
674     int32_t ret = 0;
675     BShellParam *param = NULL;
676     do {
677         size_t nameLen = strlen(name) + 1;
678         param = (BShellParam *)calloc(1, sizeof(BShellParam) + nameLen);
679         BSH_CHECK(param != NULL, return BSH_SYSTEM_ERR, "Failed to alloc cmd name %s", name);
680         param->type = type;
681         ret = strcpy_s(param->name, nameLen, name);
682         BSH_CHECK(ret == 0, break, "Failed to copy name %s", name);
683         if (desc != NULL) {
684             param->desc = strdup(desc);
685             BSH_CHECK(param->desc != NULL, free(param); return BSH_SYSTEM_ERR, "Failed to set desc");
686         }
687         ret = BShellParamSetValue(param, value);
688         BSH_CHECK(ret == 0, break, "Failed set value for %s", name);
689 
690         param->next = shell->param;
691         shell->param = param;
692     } while (0);
693     if (ret != 0) {
694         BShellParamFree(param);
695     }
696     return ret;
697 }
698 
BShellEnvGetParam(BShellHandle handle,const char * name)699 const BShellParam *BShellEnvGetParam(BShellHandle handle, const char *name)
700 {
701     BSH_CHECK(handle != NULL, return NULL, "Invalid shell env");
702     BShellEnv *shell = (BShellEnv *)handle;
703     BShellParam *param = shell->param;
704     while (param != NULL) {
705         if (strcmp(name, param->name) == 0) {
706             return param;
707         }
708         param = param->next;
709     }
710     return NULL;
711 }
712 
BShellEnvGetStringParam(BShellHandle handle,const char * name)713 const char *BShellEnvGetStringParam(BShellHandle handle, const char *name)
714 {
715     BSH_CHECK(handle != NULL, return "", "Invalid shell env");
716     const BShellParam *param = BShellEnvGetParam(handle, name);
717     if (param == NULL) {
718         return "";
719     }
720     switch (param->type) {
721         case PARAM_STRING:
722             return param->value.string;
723         default:
724             break;
725     }
726     return "";
727 }
728 
BShellEnvGetReservedParam(BShellHandle handle,const char * name)729 const ParamInfo *BShellEnvGetReservedParam(BShellHandle handle, const char *name)
730 {
731     BSH_CHECK(handle != NULL, return NULL, "Invalid shell env");
732     static ParamInfo reservedParams[] = {
733         {PARAM_REVERESD_NAME_CURR_PARAMETER, "current parameter", PARAM_STRING}
734     };
735     for (size_t i = 0; i < sizeof(reservedParams) / sizeof(reservedParams[0]); i++) {
736         if (strcmp(name, reservedParams[i].name) == 0) {
737             return &reservedParams[i];
738         }
739     }
740     return NULL;
741 }
742 
BShellEnvDirectExecute(BShellHandle handle,int argc,char * args[])743 int32_t BShellEnvDirectExecute(BShellHandle handle, int argc, char *args[])
744 {
745     BSH_CHECK(handle != NULL, return -1, "Invalid shell env");
746     BShellCommand *cmd = BShellEnvGetCmd(handle, argc, args);
747     if (cmd != NULL) {
748         int32_t ret = cmd->executer(handle, argc - cmd->argStart, &args[cmd->argStart]);
749         BShellEnvOutputResult(handle, ret);
750     } else {
751         if (argc > 1) {
752             BShellEnvOutputString(handle, BShellEnvErrString(handle, BSH_CMD_NOT_EXIST));
753         }
754         BShellCmdHelp(handle, argc, args);
755     }
756     return 0;
757 }
758