1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * POSIX getopt for Windows
9  * Code given out at the 1985 UNIFORUM conference in Dallas.
10  *
11  * From std-unix@ut-sally.UUCP (Moderator, John Quarterman) Sun Nov  3 14:34:15 1985
12  * Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site gatech.CSNET
13  * Posting-Version: version B 2.10.2 9/18/84; site ut-sally.UUCP
14  * Path: gatech!akgua!mhuxv!mhuxt!mhuxr!ulysses!allegra!mit-eddie!genrad!panda!talcott!harvard!seismo!ut-sally!std-unix
15  * From: std-unix@ut-sally.UUCP (Moderator, John Quarterman)
16  * Newsgroups: mod.std.unix
17  * Subject: public domain AT&T getopt source
18  * Message-ID: <3352@ut-sally.UUCP>
19  * Date: 3 Nov 85 19:34:15 GMT
20  * Date-Received: 4 Nov 85 12:25:09 GMT
21  * Organization: IEEE/P1003 Portable Operating System Environment Committee
22  * Lines: 91
23  * Approved: jsq@ut-sally.UUC
24  * Here's something you've all been waiting for:  the AT&T public domain
25  * source for getopt(3).  It is the code which was given out at the 1985
26  * UNIFORUM conference in Dallas.  I obtained it by electronic mail
27  * directly from AT&T.  The people there assure me that it is indeed
28  * in the public domain
29  * There is no manual page.  That is because the one they gave out at
30  * UNIFORUM was slightly different from the current System V Release 2
31  * manual page.  The difference apparently involved a note about the
32  * famous rules 5 and 6, recommending using white space between an option
33  * and its first argument, and not grouping options that have arguments.
34  * Getopt itself is currently lenient about both of these things White
35  * space is allowed, but not mandatory, and the last option in a group can
36  * have an argument.  That particular version of the man page evidently
37  * has no official existence, and my source at AT&T did not send a copy.
38  * The current SVR2 man page reflects the actual behavor of this getopt.
39  * However, I am not about to post a copy of anything licensed by AT&T.
40  */
41 
42 #include <assert.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 
47 #include "fsl_common.h"
48 #include "fsl_str.h"
49 
50 #include "fsl_component_generic_list.h"
51 #include "fsl_component_serial_manager.h"
52 
53 #include "fsl_shell.h"
54 
55 /*
56  * The OSA_USED macro can only be defined when the OSA component is used.
57  * If the source code of the OSA component does not exist, the OSA_USED cannot be defined.
58  * OR, If OSA component is not added into project event the OSA source code exists, the OSA_USED
59  * also cannot be defined.
60  * The source code path of the OSA component is <MCUXpresso_SDK>/components/osa.
61  *
62  */
63 #if defined(OSA_USED)
64 
65 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
66 #include "fsl_component_common_task.h"
67 #else
68 #include "fsl_os_abstraction.h"
69 #endif
70 
71 #endif
72 
73 /*******************************************************************************
74  * Definitions
75  ******************************************************************************/
76 #define KEY_ESC (0x1BU)
77 #define KET_DEL (0x7FU)
78 
79 #define SHELL_EVENT_DATA_ARRIVED (1U << 0)
80 #define SHELL_EVENT_DATA_SENT    (1U << 1)
81 
82 #define SHELL_SPRINTF_BUFFER_SIZE (64U)
83 
84 /*! @brief A type for the handle special key. */
85 typedef enum _fun_key_status
86 {
87     kSHELL_Normal   = 0U, /*!< Normal key */
88     kSHELL_Special  = 1U, /*!< Special key */
89     kSHELL_Function = 2U, /*!< Function key */
90 } fun_key_status_t;
91 
92 /*! @brief Data structure for Shell environment. */
93 typedef struct _shell_context_handle
94 {
95     list_label_t commandContextListHead; /*!< Command shellContextHandle list queue head */
96     serial_handle_t serialHandle;        /*!< Serial manager handle */
97     uint8_t
98         serialWriteHandleBuffer[SERIAL_MANAGER_WRITE_HANDLE_SIZE];   /*!< The buffer for serial manager write handle */
99     serial_write_handle_t serialWriteHandle;                         /*!< The serial manager write handle */
100     uint8_t serialReadHandleBuffer[SERIAL_MANAGER_READ_HANDLE_SIZE]; /*!< The buffer for serial manager read handle */
101     serial_read_handle_t serialReadHandle;                           /*!< The serial manager read handle */
102     char *prompt;                                                    /*!< Prompt string */
103 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
104 
105 #if defined(OSA_USED)
106 
107 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
108     common_task_message_t commontaskMsg; /*!< Message for common task */
109 #else
110     uint8_t event[OSA_EVENT_HANDLE_SIZE]; /*!< Event instance */
111     uint8_t taskId[OSA_TASK_HANDLE_SIZE]; /*!< Task handle */
112 #endif
113 
114 #endif
115 
116 #endif
117     char line[SHELL_BUFFER_SIZE];                          /*!< Consult buffer */
118     char hist_buf[SHELL_HISTORY_COUNT][SHELL_BUFFER_SIZE]; /*!< History buffer*/
119     char printBuffer[SHELL_SPRINTF_BUFFER_SIZE];           /*!< Buffer for print */
120     uint32_t printLength;                                  /*!< All length has been printed */
121     uint16_t hist_current;                                 /*!< Current history command in hist buff*/
122     uint16_t hist_count;                                   /*!< Total history command in hist buff*/
123     enum _fun_key_status stat;                             /*!< Special key status */
124     uint8_t cmd_num;                                       /*!< Number of user commands */
125     uint8_t l_pos;                                         /*!< Total line position */
126     uint8_t c_pos;                                         /*!< Current line position */
127     volatile uint8_t notificationPost;                     /*!< The serial manager notification is post */
128     uint8_t exit;                                          /*!< Exit Flag*/
129     uint8_t printBusy;                                     /*!< Print is busy */
130 } shell_context_handle_t;
131 
132 #if 0
133 #define SHELL_STRUCT_OFFSET(type, field) ((size_t) & (((type *)0)->field))
134 #define SHEEL_COMMAND_POINTER(node) \
135     ((shell_command_t *)(((uint32_t)(node)) - SHELL_STRUCT_OFFSET(shell_command_t, link)))
136 #else
137 #define SHEEL_COMMAND_POINTER(node) \
138     ((shell_command_t *)(((uint32_t)(node)) - (sizeof(shell_command_t) - sizeof(list_element_t))))
139 #endif
140 /*******************************************************************************
141  * Prototypes
142  ******************************************************************************/
143 static shell_status_t SHELL_HelpCommand(shell_handle_t shellHandle, int32_t argc, char **argv); /*!< help command */
144 
145 static shell_status_t SHELL_ExitCommand(shell_handle_t shellHandle, int32_t argc, char **argv); /*!< exit command */
146 
147 static int32_t SHELL_ParseLine(const char *cmd, uint32_t len, char *argv[]); /*!< parse line command */
148 
149 static int32_t SHELL_StringCompare(const char *str1, const char *str2, int32_t count); /*!< compare string command */
150 
151 static void SHELL_ProcessCommand(shell_context_handle_t *shellContextHandle, const char *cmd); /*!< process a command */
152 
153 static void SHELL_GetHistoryCommand(shell_context_handle_t *shellContextHandle,
154                                     uint8_t hist_pos); /*!< get commands history */
155 
156 static void SHELL_AutoComplete(shell_context_handle_t *shellContextHandle); /*!< auto complete command */
157 
158 static shell_status_t SHELL_GetChar(shell_context_handle_t *shellContextHandle,
159                                     uint8_t *ch); /*!< get a char from communication interface */
160 
161 static void SHELL_WriteWithCopy(shell_handle_t shellHandle, const char *buffer, uint32_t length);
162 
163 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
164 static void SHELL_Task(void *param); /*!<  Shell task*/
165 #endif
166 
167 /*******************************************************************************
168  * Variables
169  ******************************************************************************/
170 
171 static SHELL_COMMAND_DEFINE(help, "\r\n\"help\": List all the registered commands\r\n", SHELL_HelpCommand, 0);
172 static SHELL_COMMAND_DEFINE(exit, "\r\n\"exit\": Exit program\r\n", SHELL_ExitCommand, 0);
173 
174 static char s_paramBuffer[SHELL_BUFFER_SIZE];
175 
176 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
177 #if defined(OSA_USED)
178 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
179 #else
180 /*
181  * \brief Defines the serial manager task's stack
182  */
183 static OSA_TASK_DEFINE(SHELL_Task, SHELL_TASK_PRIORITY, 1, SHELL_TASK_STACK_SIZE, false);
184 #endif
185 #endif /* OSA_USED */
186 #endif /* SHELL_NON_BLOCKING_MODE */
187 /*******************************************************************************
188  * Code
189  ******************************************************************************/
190 
191 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
SHELL_SerialManagerRxCallback(void * callbackParam,serial_manager_callback_message_t * message,serial_manager_status_t status)192 static void SHELL_SerialManagerRxCallback(void *callbackParam,
193                                           serial_manager_callback_message_t *message,
194                                           serial_manager_status_t status)
195 {
196     shell_context_handle_t *shellHandle;
197 
198     assert(callbackParam);
199     assert(message);
200 
201     shellHandle = (shell_context_handle_t *)callbackParam;
202 
203     if (0U == shellHandle->notificationPost)
204     {
205         shellHandle->notificationPost = 1U;
206 #if defined(OSA_USED)
207 
208 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
209         shellHandle->commontaskMsg.callback      = SHELL_Task;
210         shellHandle->commontaskMsg.callbackParam = shellHandle;
211         (void)COMMON_TASK_post_message(&shellHandle->commontaskMsg);
212 #else
213         (void)OSA_EventSet((osa_event_handle_t)shellHandle->event, SHELL_EVENT_DATA_ARRIVED);
214 #endif
215 
216 #else
217         SHELL_Task(shellHandle);
218 #endif
219     }
220 }
221 #endif
222 
SHELL_WriteBuffer(char * buffer,int32_t * indicator,char val,int len)223 static void SHELL_WriteBuffer(char *buffer, int32_t *indicator, char val, int len)
224 {
225     shell_context_handle_t *shellContextHandle;
226     int i              = 0;
227     shellContextHandle = (shell_context_handle_t *)(void *)buffer;
228 
229     for (i = 0; i < len; i++)
230     {
231         if ((*indicator + 1) >= (int32_t)SHELL_SPRINTF_BUFFER_SIZE)
232         {
233 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
234             if (NULL == shellContextHandle->serialHandle)
235             {
236                 for (uint32_t index = 0; index < ((uint32_t)*indicator); index++)
237                 {
238                     (void)putchar(shellContextHandle->printBuffer[index]);
239                 }
240             }
241             else
242 #endif
243             {
244                 (void)SerialManager_WriteBlocking(shellContextHandle->serialWriteHandle,
245                                                   (uint8_t *)shellContextHandle->printBuffer, (uint32_t)*indicator);
246             }
247 
248             shellContextHandle->printLength += (uint32_t)*indicator;
249             *indicator = 0;
250         }
251 
252         shellContextHandle->printBuffer[*indicator] = val;
253         (*indicator)++;
254     }
255 }
256 
SHELL_Sprintf(void * buffer,const char * formatString,va_list ap)257 static int SHELL_Sprintf(void *buffer, const char *formatString, va_list ap)
258 {
259     shell_context_handle_t *shellContextHandle;
260     uint32_t length;
261     shellContextHandle = (shell_context_handle_t *)buffer;
262 
263     length = (uint32_t)StrFormatPrintf(formatString, ap, (char *)buffer, SHELL_WriteBuffer);
264     shellContextHandle->printLength += length;
265     return (int32_t)length;
266 }
267 
268 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
SHELL_Task(void * param)269 static void SHELL_Task(void *param)
270 #else
271 void SHELL_Task(shell_handle_t shellHandle)
272 #endif
273 {
274 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
275     shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)param;
276 #else
277     shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
278 #endif
279     uint8_t ch;
280 
281     if (NULL != shellContextHandle)
282     {
283 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
284 
285 #if defined(OSA_USED)
286 
287 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
288 #else
289         osa_event_flags_t ev = 0;
290 
291         do
292         {
293             if (KOSA_StatusSuccess == OSA_EventWait((osa_event_handle_t)shellContextHandle->event, osaEventFlagsAll_c,
294                                                     0U, osaWaitForever_c, &ev))
295             {
296                 if (0U != (ev & SHELL_EVENT_DATA_ARRIVED))
297 #endif
298 
299 #endif
300 
301 #endif
302         {
303             shellContextHandle->notificationPost = 0;
304             do
305             {
306                 if ((bool)shellContextHandle->exit)
307                 {
308                     if (shellContextHandle->serialReadHandle != NULL)
309                     {
310                         (void)SerialManager_CloseReadHandle(shellContextHandle->serialReadHandle);
311                         shellContextHandle->serialReadHandle = NULL;
312                     }
313                     if (shellContextHandle->serialWriteHandle != NULL)
314                     {
315                         (void)SerialManager_CloseWriteHandle(shellContextHandle->serialWriteHandle);
316                         shellContextHandle->serialWriteHandle = NULL;
317                     }
318                     break;
319                 }
320                 if (kStatus_SHELL_Success != (shell_status_t)SHELL_GetChar(shellContextHandle, &ch))
321                 {
322                     /* If error occurred when getting a char, exit the task and waiting the new data arriving. */
323                     break;
324                 }
325 
326                 /* Special key */
327                 if (ch == KEY_ESC)
328                 {
329                     shellContextHandle->stat = kSHELL_Special;
330                     continue;
331                 }
332                 else if (shellContextHandle->stat == kSHELL_Special)
333                 {
334                     /* Function key */
335                     if ((char)ch == '[')
336                     {
337                         shellContextHandle->stat = kSHELL_Function;
338                         continue;
339                     }
340                     shellContextHandle->stat = kSHELL_Normal;
341                 }
342                 else if (shellContextHandle->stat == kSHELL_Function)
343                 {
344                     shellContextHandle->stat = kSHELL_Normal;
345 
346                     switch ((char)ch)
347                     {
348                         /* History operation here */
349                         case 'A': /* Up key */
350                             SHELL_GetHistoryCommand(shellContextHandle, (uint8_t)shellContextHandle->hist_current);
351                             if (shellContextHandle->hist_current < (shellContextHandle->hist_count - 1U))
352                             {
353                                 shellContextHandle->hist_current++;
354                             }
355                             break;
356                         case 'B': /* Down key */
357                             SHELL_GetHistoryCommand(shellContextHandle, (uint8_t)shellContextHandle->hist_current);
358                             if (shellContextHandle->hist_current > 0U)
359                             {
360                                 shellContextHandle->hist_current--;
361                             }
362                             break;
363                         case 'D': /* Left key */
364                             if ((bool)shellContextHandle->c_pos)
365                             {
366                                 SHELL_WriteWithCopy(shellContextHandle, "\b", 1);
367                                 shellContextHandle->c_pos--;
368                             }
369                             break;
370                         case 'C': /* Right key */
371                             if (shellContextHandle->c_pos < shellContextHandle->l_pos)
372                             {
373                                 (void)SHELL_Write(shellContextHandle,
374                                                   &shellContextHandle->line[shellContextHandle->c_pos], 1);
375                                 shellContextHandle->c_pos++;
376                             }
377                             break;
378                         default:
379                             /* MISRA C-2012 Rule 16.4 */
380                             break;
381                     }
382                     continue;
383                 }
384                 /* Handle tab key */
385                 else if ((char)ch == '\t')
386                 {
387 #if SHELL_AUTO_COMPLETE
388                     /* Move the cursor to the beginning of line */
389                     uint32_t i;
390                     for (i = 0; i < (uint32_t)shellContextHandle->c_pos; i++)
391                     {
392                         SHELL_WriteWithCopy(shellContextHandle, "\b", 1);
393                     }
394                     /* Do auto complete */
395                     SHELL_AutoComplete(shellContextHandle);
396                     /* Move position to end */
397                     shellContextHandle->l_pos = (uint8_t)strlen(shellContextHandle->line);
398                     shellContextHandle->c_pos = shellContextHandle->l_pos;
399 #endif
400                     continue;
401                 }
402                 /* Handle backspace key */
403                 else if ((ch == KET_DEL) || ((char)ch == '\b'))
404                 {
405                     /* There must be at last one char */
406                     if (shellContextHandle->c_pos == 0U)
407                     {
408                         continue;
409                     }
410 
411                     shellContextHandle->l_pos--;
412                     shellContextHandle->c_pos--;
413 
414                     if (shellContextHandle->l_pos > shellContextHandle->c_pos)
415                     {
416                         (void)memmove(&shellContextHandle->line[shellContextHandle->c_pos],
417                                       &shellContextHandle->line[shellContextHandle->c_pos + 1U],
418                                       (uint32_t)shellContextHandle->l_pos - (uint32_t)shellContextHandle->c_pos);
419                         shellContextHandle->line[shellContextHandle->l_pos] = '\0';
420                         SHELL_WriteWithCopy(shellContextHandle, "\b", 1);
421                         (void)SHELL_Write(shellContextHandle, &shellContextHandle->line[shellContextHandle->c_pos],
422                                           strlen(&shellContextHandle->line[shellContextHandle->c_pos]));
423                         SHELL_WriteWithCopy(shellContextHandle, "  \b", 3);
424 
425                         /* Reset position */
426                         uint32_t i;
427                         for (i = (uint32_t)shellContextHandle->c_pos; i <= (uint32_t)shellContextHandle->l_pos; i++)
428                         {
429                             SHELL_WriteWithCopy(shellContextHandle, "\b", 1);
430                         }
431                     }
432                     else /* Normal backspace operation */
433                     {
434                         SHELL_WriteWithCopy(shellContextHandle, "\b \b", 3);
435                         shellContextHandle->line[shellContextHandle->l_pos] = '\0';
436                     }
437                     continue;
438                 }
439                 else
440                 {
441                     /* MISRA C-2012 Rule 15.7 */
442                 }
443 
444                 /* Input too long */
445                 if (shellContextHandle->l_pos >= (SHELL_BUFFER_SIZE - 1U))
446                 {
447                     shellContextHandle->l_pos = 0U;
448                 }
449 
450                 /* Handle end of line, break */
451                 if (((char)ch == '\r') || ((char)ch == '\n'))
452                 {
453                     static char endoflinechar = '\0';
454 
455                     if (((uint8_t)endoflinechar != 0U) && ((uint8_t)endoflinechar != ch))
456                     {
457                         continue;
458                     }
459                     else
460                     {
461                         endoflinechar = (char)ch;
462                         /* Print new line. */
463                         SHELL_WriteWithCopy(shellContextHandle, "\r\n", 2U); /* MISRA C-2012 Rule 7.4 */
464                         /* If command line is not NULL, will start process it. */
465                         if (0U != strlen(shellContextHandle->line))
466                         {
467                             SHELL_ProcessCommand(shellContextHandle, shellContextHandle->line);
468                         }
469                         /* Print prompt. */
470                         (void)SHELL_Write(shellContextHandle, shellContextHandle->prompt,
471                                           strlen(shellContextHandle->prompt));
472                         /* Reset all params */
473                         shellContextHandle->c_pos = shellContextHandle->l_pos = 0;
474                         shellContextHandle->hist_current                      = 0;
475                         (void)memset(shellContextHandle->line, 0, sizeof(shellContextHandle->line));
476                         continue;
477                     }
478                 }
479 
480                 /* Normal character */
481                 if (shellContextHandle->c_pos < shellContextHandle->l_pos)
482                 {
483                     (void)memmove(&shellContextHandle->line[shellContextHandle->c_pos + 1U],
484                                   &shellContextHandle->line[shellContextHandle->c_pos],
485                                   (uint32_t)shellContextHandle->l_pos - (uint32_t)shellContextHandle->c_pos);
486                     shellContextHandle->line[shellContextHandle->c_pos] = (char)ch;
487                     (void)SHELL_Write(shellContextHandle, &shellContextHandle->line[shellContextHandle->c_pos],
488                                       strlen(&shellContextHandle->line[shellContextHandle->c_pos]));
489                     /* Move the cursor to new position */
490                     uint32_t i;
491                     for (i = (uint32_t)shellContextHandle->c_pos; i < (uint32_t)shellContextHandle->l_pos; i++)
492                     {
493                         SHELL_WriteWithCopy(shellContextHandle, "\b", 1);
494                     }
495                 }
496                 else
497                 {
498                     shellContextHandle->line[shellContextHandle->l_pos] = (char)ch;
499                     (void)SHELL_Write(shellContextHandle, &shellContextHandle->line[shellContextHandle->l_pos], 1);
500                 }
501 
502                 ch = 0;
503                 shellContextHandle->l_pos++;
504                 shellContextHandle->c_pos++;
505             } while (0U == shellContextHandle->exit);
506         }
507 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
508 
509 #if defined(OSA_USED)
510 
511 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
512 #else
513             }
514         } while (1U == gUseRtos_c); /* USE_RTOS = 0 for BareMetal and 1 for OS */
515 #endif
516 
517 #endif
518 
519 #endif
520     }
521 }
522 
523 static shell_status_t SHELL_HelpCommand(shell_handle_t shellHandle, int32_t argc, char **argv)
524 {
525     shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
526     shell_command_t *shellCommandContextHandle;
527     list_element_handle_t p = LIST_GetHead(&shellContextHandle->commandContextListHead);
528 
529     while (p != NULL)
530     {
531         shellCommandContextHandle = SHEEL_COMMAND_POINTER(p);
532         if ((shellCommandContextHandle->pcHelpString != NULL) && (bool)strlen(shellCommandContextHandle->pcHelpString))
533         {
534             (void)SHELL_Write(shellContextHandle, shellCommandContextHandle->pcHelpString,
535                               strlen(shellCommandContextHandle->pcHelpString));
536         }
537 
538         p = LIST_GetNext(p);
539     }
540     return kStatus_SHELL_Success;
541 }
542 
543 static shell_status_t SHELL_ExitCommand(shell_handle_t shellHandle, int32_t argc, char **argv)
544 {
545     shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
546     /* Skip warning */
547     SHELL_WriteWithCopy(shellContextHandle, "\r\nSHELL exited\r\n", strlen("\r\nSHELL exited\r\n"));
548     shellContextHandle->exit = (uint8_t) true;
549     return kStatus_SHELL_Success;
550 }
551 
552 static void SHELL_ProcessCommand(shell_context_handle_t *shellContextHandle, const char *cmd)
553 {
554     shell_command_t *tmpCommand = NULL;
555     const char *tmpCommandString;
556     int32_t argc;
557     char *argv[SHELL_BUFFER_SIZE] = {0};
558     list_element_handle_t p;
559     uint8_t flag = 1;
560     uint8_t tmpCommandLen;
561     uint8_t tmpLen;
562     uint8_t i = 0;
563 
564     tmpLen = (uint8_t)strlen(cmd);
565     argc   = SHELL_ParseLine(cmd, tmpLen, argv);
566 
567     if ((argc > 0))
568     {
569         p = LIST_GetHead(&shellContextHandle->commandContextListHead);
570         while (p != NULL)
571         {
572             tmpCommand       = SHEEL_COMMAND_POINTER(p);
573             tmpCommandString = tmpCommand->pcCommand;
574             tmpCommandLen    = (uint8_t)strlen(tmpCommandString);
575             /* Compare with space or end of string */
576             if ((cmd[tmpCommandLen] == ' ') || (cmd[tmpCommandLen] == (char)0x00))
577             {
578                 if (SHELL_StringCompare(tmpCommandString, argv[0], (int32_t)tmpCommandLen) == 0)
579                 {
580                     /* support commands with optional number of parameters */
581                     if (tmpCommand->cExpectedNumberOfParameters == (uint8_t)SHELL_IGNORE_PARAMETER_COUNT)
582                     {
583                         flag = 0;
584                     }
585                     else if ((tmpCommand->cExpectedNumberOfParameters == 0U) && (argc == 1))
586                     {
587                         flag = 0;
588                     }
589                     else if (tmpCommand->cExpectedNumberOfParameters > 0U)
590                     {
591                         if ((argc - 1) == (int32_t)tmpCommand->cExpectedNumberOfParameters)
592                         {
593                             flag = 0;
594                         }
595                     }
596                     else
597                     {
598                         flag = 1;
599                     }
600                     break;
601                 }
602             }
603             p = LIST_GetNext(p);
604         }
605         if (NULL == p)
606         {
607             tmpCommand = NULL;
608         }
609     }
610 
611     if ((tmpCommand != NULL) && (flag == 1U))
612     {
613         SHELL_WriteWithCopy(
614             shellContextHandle,
615             "\r\nIncorrect command parameter(s).  Enter \"help\" to view a list of available commands.\r\n\r\n",
616             strlen(
617                 "\r\nIncorrect command parameter(s).  Enter \"help\" to view a list of available commands.\r\n\r\n"));
618     }
619     else if (tmpCommand != NULL)
620     {
621         tmpLen = (uint8_t)strlen(cmd);
622         /* Compare with last command. Push back to history buffer if different */
623         if (tmpLen != (uint8_t)SHELL_StringCompare(cmd, shellContextHandle->hist_buf[0], (int32_t)strlen(cmd)))
624         {
625             for (i = SHELL_HISTORY_COUNT - 1U; i > 0U; i--)
626             {
627                 (void)memset(shellContextHandle->hist_buf[i], (int)'\0', SHELL_BUFFER_SIZE);
628                 tmpLen = (uint8_t)strlen(shellContextHandle->hist_buf[i - 1U]);
629                 (void)memcpy(shellContextHandle->hist_buf[i], shellContextHandle->hist_buf[i - 1U], tmpLen);
630             }
631             (void)memset(shellContextHandle->hist_buf[0], (int)'\0', SHELL_BUFFER_SIZE);
632             tmpLen = (uint8_t)strlen(cmd);
633             (void)memcpy(shellContextHandle->hist_buf[0], cmd, tmpLen);
634             if (shellContextHandle->hist_count < SHELL_HISTORY_COUNT)
635             {
636                 shellContextHandle->hist_count++;
637             }
638         }
639         (void)tmpCommand->pFuncCallBack(shellContextHandle, argc, argv);
640     }
641     else
642     {
643         SHELL_WriteWithCopy(
644             shellContextHandle,
645             "\r\nCommand not recognized.  Enter 'help' to view a list of available commands.\r\n\r\n",
646             strlen("\r\nCommand not recognized.  Enter 'help' to view a list of available commands.\r\n\r\n"));
647     }
648 }
649 
650 static void SHELL_GetHistoryCommand(shell_context_handle_t *shellContextHandle, uint8_t hist_pos)
651 {
652     uint32_t i;
653     uint32_t tmp;
654 
655     if (shellContextHandle->hist_buf[0][0] == '\0')
656     {
657         shellContextHandle->hist_current = 0;
658         return;
659     }
660 
661 #if 0 /*hist_pos is passed from hist_current. And hist_current is only changed in case 'A'/'B',as hist_count is 3 \
662          most, it can't be more than 3  */
663     if (hist_pos >= SHELL_HISTORY_COUNT)
664     {
665         hist_pos = SHELL_HISTORY_COUNT - 1U;
666     }
667 #endif
668 
669     tmp = strlen(shellContextHandle->line);
670     /* Clear current if have */
671     if (tmp > 0U)
672     {
673         (void)memset(shellContextHandle->line, (int)'\0', tmp);
674         for (i = 0U; i < tmp; i++)
675         {
676             SHELL_WriteWithCopy(shellContextHandle, "\b \b", 3);
677         }
678     }
679 
680     shellContextHandle->l_pos = (uint8_t)strlen(shellContextHandle->hist_buf[hist_pos]);
681     shellContextHandle->c_pos = shellContextHandle->l_pos;
682     (void)memcpy(shellContextHandle->line, shellContextHandle->hist_buf[hist_pos], shellContextHandle->l_pos);
683     (void)SHELL_Write(shellContextHandle, shellContextHandle->hist_buf[hist_pos],
684                       strlen(shellContextHandle->hist_buf[hist_pos]));
685 }
686 
687 static void SHELL_AutoComplete(shell_context_handle_t *shellContextHandle)
688 {
689     int32_t minLen;
690     list_element_handle_t p;
691     shell_command_t *tmpCommand = NULL;
692     const char *namePtr;
693     const char *cmdName;
694 
695     minLen  = (int32_t)SHELL_BUFFER_SIZE;
696     namePtr = NULL;
697 
698     /* Empty tab, list all commands */
699     if (shellContextHandle->line[0] == '\0')
700     {
701         (void)SHELL_HelpCommand(shellContextHandle, 0, NULL);
702         return;
703     }
704 
705     SHELL_WriteWithCopy(shellContextHandle, "\r\n", 2);
706 
707     /* Do auto complete */
708     p = LIST_GetHead(&shellContextHandle->commandContextListHead);
709     while (p != NULL)
710     {
711         tmpCommand = SHEEL_COMMAND_POINTER(p);
712         cmdName    = tmpCommand->pcCommand;
713         if (SHELL_StringCompare(shellContextHandle->line, cmdName, (int32_t)strlen(shellContextHandle->line)) == 0)
714         {
715             /* Show possible matches */
716             (void)SHELL_Printf(shellContextHandle, "%s    ", cmdName);
717             if (minLen > ((int32_t)strlen(cmdName)))
718             {
719                 namePtr = cmdName;
720                 minLen  = (int32_t)strlen(namePtr);
721             }
722         }
723         p = LIST_GetNext(p);
724     }
725     /* Auto complete string */
726     if (namePtr != NULL)
727     {
728         (void)memcpy(shellContextHandle->line, namePtr, (uint32_t)minLen);
729     }
730     SHELL_PrintPrompt(shellContextHandle);
731     (void)SHELL_Write(shellContextHandle, shellContextHandle->line, strlen(shellContextHandle->line));
732     return;
733 }
734 
735 static int32_t SHELL_StringCompare(const char *str1, const char *str2, int32_t count)
736 {
737     while ((bool)(count--))
738     {
739         if (*str1++ != *str2++)
740         {
741             return (int32_t)(*(str1 - 1) - *(str2 - 1));
742         }
743     }
744     return 0;
745 }
746 
747 static int32_t SHELL_ParseLine(const char *cmd, uint32_t len, char *argv[])
748 {
749     uint32_t argc;
750     char *p;
751     uint32_t position;
752 
753     /* Init params */
754     (void)memset(s_paramBuffer, (int)'\0', len + 1U);
755     (void)memcpy(s_paramBuffer, cmd, len);
756 
757     p        = s_paramBuffer;
758     position = 0;
759     argc     = 0;
760 
761     while (position < len)
762     {
763         /* Skip all blanks */
764         while ((position < len) && ((char)(*p) == ' '))
765         {
766             *p = '\0';
767             p++;
768             position++;
769         }
770 
771         if (position >= len)
772         {
773             break;
774         }
775 
776         /* Process begin of a string */
777         if (*p == '"')
778         {
779             p++;
780             position++;
781             argv[argc] = p;
782             argc++;
783             /* Skip this string */
784             while ((*p != '"') && (position < len))
785             {
786                 p++;
787                 position++;
788             }
789             /* Skip '"' */
790             *p = '\0';
791             p++;
792             position++;
793         }
794         else /* Normal char */
795         {
796             argv[argc] = p;
797             argc++;
798             while (((char)*p != ' ') && (position < len))
799             {
800                 p++;
801                 position++;
802             }
803         }
804     }
805     return (int32_t)argc;
806 }
807 
808 static shell_status_t SHELL_GetChar(shell_context_handle_t *shellContextHandle, uint8_t *ch)
809 {
810     shell_status_t status;
811 
812 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
813     if (NULL == shellContextHandle->serialHandle)
814     {
815         int ret;
816         ret = getchar();
817         if (ret > 0)
818         {
819             *ch    = (uint8_t)ret;
820             status = kStatus_SHELL_Success;
821         }
822         else
823         {
824             status = kStatus_SHELL_Error;
825         }
826     }
827     else
828 #endif
829     {
830 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
831         uint32_t length = 0;
832 
833         (void)SerialManager_TryRead(shellContextHandle->serialReadHandle, ch, 1, &length);
834 
835         if (length > 0U)
836         {
837             status = kStatus_SHELL_Success;
838         }
839         else
840         {
841             status = kStatus_SHELL_Error;
842         }
843 #else
844         status = (shell_status_t)SerialManager_ReadBlocking(shellContextHandle->serialReadHandle, ch, 1);
845 #endif
846     }
847 
848     return status;
849 }
850 
851 shell_status_t SHELL_Init(shell_handle_t shellHandle, serial_handle_t serialHandle, char *prompt)
852 {
853     shell_context_handle_t *shellContextHandle;
854     serial_manager_status_t status = kStatus_SerialManager_Error;
855     (void)status;
856 
857     assert(shellHandle);
858 #if !(!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
859     assert(serialHandle);
860 #endif
861     assert(prompt);
862     assert(SHELL_HANDLE_SIZE >= sizeof(shell_context_handle_t));
863 
864     shellContextHandle = (shell_context_handle_t *)shellHandle;
865 
866     /* memory set for shellHandle */
867     (void)memset(shellHandle, 0, SHELL_HANDLE_SIZE);
868 
869 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
870     if (NULL == serialHandle)
871     {
872     }
873     else
874 #endif
875     {
876 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
877 
878 #if defined(OSA_USED)
879 
880 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
881         (void)COMMON_TASK_init();
882 #else
883         if (KOSA_StatusSuccess != OSA_EventCreate((osa_event_handle_t)shellContextHandle->event, 1U))
884         {
885             return kStatus_SHELL_Error;
886         }
887 
888         if (KOSA_StatusSuccess !=
889             OSA_TaskCreate((osa_task_handle_t)shellContextHandle->taskId, OSA_TASK(SHELL_Task), shellContextHandle))
890         {
891             return kStatus_SHELL_Error;
892         }
893 #endif
894 
895 #endif
896 
897 #endif
898     }
899 
900     shellContextHandle->prompt       = prompt;
901     shellContextHandle->serialHandle = serialHandle;
902 
903 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
904     if (NULL == serialHandle)
905     {
906     }
907     else
908 #endif
909     {
910         shellContextHandle->serialWriteHandle = (serial_write_handle_t)&shellContextHandle->serialWriteHandleBuffer[0];
911         status = SerialManager_OpenWriteHandle(shellContextHandle->serialHandle, shellContextHandle->serialWriteHandle);
912         assert(kStatus_SerialManager_Success == status);
913 
914         shellContextHandle->serialReadHandle = (serial_read_handle_t)&shellContextHandle->serialReadHandleBuffer[0];
915         status = SerialManager_OpenReadHandle(shellContextHandle->serialHandle, shellContextHandle->serialReadHandle);
916         assert(kStatus_SerialManager_Success == status);
917 
918 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
919         status = SerialManager_InstallRxCallback(shellContextHandle->serialReadHandle, SHELL_SerialManagerRxCallback,
920                                                  shellContextHandle);
921         assert(kStatus_SerialManager_Success == status);
922 #endif
923         (void)status;
924     }
925 
926     (void)SHELL_RegisterCommand(shellContextHandle, SHELL_COMMAND(help));
927     (void)SHELL_RegisterCommand(shellContextHandle, SHELL_COMMAND(exit));
928 
929     SHELL_WriteWithCopy(shellContextHandle, "\r\nSHELL build: ", strlen("\r\nSHELL build: "));
930     SHELL_WriteWithCopy(shellContextHandle, __DATE__, strlen(__DATE__));
931     SHELL_WriteWithCopy(shellContextHandle, "\r\nCopyright  2020  NXP\r\n", strlen("\r\nCopyright  2020  NXP\r\n"));
932     SHELL_PrintPrompt(shellContextHandle);
933 
934     return kStatus_SHELL_Success;
935 }
936 
937 shell_status_t SHELL_RegisterCommand(shell_handle_t shellHandle, shell_command_t *shellCommand)
938 {
939     shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
940     assert(shellHandle);
941     assert(shellCommand);
942 
943     /* memory set for shellHandle */
944     (void)memset(&shellCommand->link, 0, sizeof(shellCommand->link));
945 
946     (void)LIST_AddTail(&shellContextHandle->commandContextListHead, &shellCommand->link);
947 
948     return kStatus_SHELL_Success;
949 }
950 
951 shell_status_t SHELL_UnregisterCommand(shell_command_t *shellCommand)
952 {
953     assert(shellCommand);
954 
955     (void)LIST_RemoveElement(&shellCommand->link);
956 
957     /* memory set for shellHandle */
958     (void)memset(&shellCommand->link, 0, sizeof(shellCommand->link));
959 
960     return kStatus_SHELL_Success;
961 }
962 
963 shell_status_t SHELL_Write(shell_handle_t shellHandle, char *buffer, uint32_t length)
964 {
965     shell_context_handle_t *shellContextHandle;
966     uint32_t primask;
967     shell_status_t status;
968 
969     assert(shellHandle);
970     assert(buffer);
971 
972     if (!(bool)length)
973     {
974         return kStatus_SHELL_Success;
975     }
976 
977     shellContextHandle = (shell_context_handle_t *)shellHandle;
978 
979     primask = DisableGlobalIRQ();
980     if ((bool)shellContextHandle->printBusy)
981     {
982         EnableGlobalIRQ(primask);
983         return kStatus_SHELL_Error;
984     }
985     shellContextHandle->printBusy = 1U;
986     EnableGlobalIRQ(primask);
987 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
988     if (NULL == shellContextHandle->serialHandle)
989     {
990         status = kStatus_SHELL_Success;
991         for (uint32_t index = 0; index < length; index++)
992         {
993             (void)putchar(buffer[index]);
994         }
995     }
996     else
997 #endif
998     {
999         status = (shell_status_t)SerialManager_WriteBlocking(shellContextHandle->serialWriteHandle, (uint8_t *)buffer,
1000                                                              length);
1001     }
1002 
1003     shellContextHandle->printBusy = 0U;
1004 
1005     return status;
1006 }
1007 
1008 /* For MISRA to fix const */
1009 static void SHELL_WriteWithCopy(shell_handle_t shellHandle, const char *buffer, uint32_t length)
1010 {
1011     char s_shellWriteCopyBuffer[128];
1012 
1013     assert(length <= 128UL);
1014 
1015     (void)memcpy(s_shellWriteCopyBuffer, buffer, length);
1016     (void)SHELL_Write(shellHandle, s_shellWriteCopyBuffer, length);
1017 }
1018 
1019 int SHELL_Printf(shell_handle_t shellHandle, const char *formatString, ...)
1020 {
1021     shell_context_handle_t *shellContextHandle;
1022     uint32_t length;
1023     uint32_t primask;
1024     va_list ap;
1025 
1026     assert(shellHandle);
1027     assert(formatString);
1028 
1029     shellContextHandle = (shell_context_handle_t *)shellHandle;
1030 
1031     primask = DisableGlobalIRQ();
1032     if ((bool)shellContextHandle->printBusy)
1033     {
1034         EnableGlobalIRQ(primask);
1035         return -1;
1036     }
1037     shellContextHandle->printBusy = 1U;
1038     EnableGlobalIRQ(primask);
1039 
1040     va_start(ap, formatString);
1041 
1042     shellContextHandle->printLength = 0U;
1043     length                          = (uint32_t)SHELL_Sprintf(shellHandle, formatString, ap);
1044 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
1045     if (NULL == shellContextHandle->serialHandle)
1046     {
1047         for (uint32_t index = 0; index < length; index++)
1048         {
1049             (void)putchar(shellContextHandle->printBuffer[index]);
1050         }
1051     }
1052     else
1053 #endif
1054     {
1055         (void)SerialManager_WriteBlocking(shellContextHandle->serialWriteHandle,
1056                                           (uint8_t *)shellContextHandle->printBuffer, length);
1057     }
1058     va_end(ap);
1059 
1060     shellContextHandle->printBusy = 0U;
1061     return (int32_t)shellContextHandle->printLength;
1062 }
1063 
1064 void SHELL_ChangePrompt(shell_handle_t shellHandle, char *prompt)
1065 {
1066     shell_context_handle_t *shellContextHandle;
1067     assert(shellHandle);
1068     assert(prompt);
1069 
1070     shellContextHandle = (shell_context_handle_t *)shellHandle;
1071 
1072     shellContextHandle->prompt = prompt;
1073     SHELL_PrintPrompt(shellContextHandle);
1074 }
1075 
1076 void SHELL_PrintPrompt(shell_handle_t shellHandle)
1077 {
1078     shell_context_handle_t *shellContextHandle;
1079     assert(shellHandle);
1080 
1081     shellContextHandle = (shell_context_handle_t *)shellHandle;
1082 
1083     SHELL_WriteWithCopy(shellContextHandle, "\r\n", 2U); /* MISRA C-2012 Rule 7.4 */
1084     (void)SHELL_Write(shellContextHandle, shellContextHandle->prompt, strlen(shellContextHandle->prompt));
1085 }
1086