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 22char *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 48static 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 62int32_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 90static 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 98int32_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 109int32_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 117int32_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 140void 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 147void 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 156static 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 163void BShellEnvBackspace(BShellHandle handle, uint32_t length) 164{ 165 for (uint32_t i = 0; i < length; i++) { 166 BShellEnvOutputString(handle, "\b \b"); 167 } 168} 169 170static 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 196static int32_t BShellEnvExcuteCmd(BShellEnv *shell, BShellCommand *cmd) 197{ 198 return cmd->executer((BShellHandle)shell, shell->argc - cmd->argStart, &shell->args[cmd->argStart]); 199} 200 201static 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 243static 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 274static 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 280static 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 313static 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 323static 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 331BShellKey *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 350SHELLSTATIC 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 397void 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 410int32_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 431int 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 449static 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 460static 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 477void 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 508int32_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 556static 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 573BShellCommand *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 615int32_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 630BShellKey *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 644static 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(¶m->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 662int32_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 699const 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 713const 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 729const 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 743int32_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