iLLD_TC29x  1.0
Ifx_Shell.c
Go to the documentation of this file.
1 /**
2  * \file shell.c
3  * \brief shell functions.
4  *
5  * \version iLLD_1_0_0_11_0
6  * \copyright Copyright (c) 2013 Infineon Technologies AG. All rights reserved.
7  *
8  *
9  * IMPORTANT NOTICE
10  *
11  *
12  * Infineon Technologies AG (Infineon) is supplying this file for use
13  * exclusively with Infineon's microcontroller products. This file can be freely
14  * distributed within development tools that are supporting such microcontroller
15  * products.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
18  * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
20  * INFINEON SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
21  * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
22  *
23  */
24 
25 //---------------------------------------------------------------------------
26 #include "Ifx_Shell.h"
27 #include "_Utilities/Ifx_Assert.h"
29 
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 
34 #define IFX_SHELL_LLD "%lld "
35 #define IFX_SHELL_LLX "%llx "
36 #define IFX_SHELL_LLU "%llu "
37 
38 //---------------------------------------------------------------------------
39 #define IFX_SHELL_MAX_MESSAGE_SIZE 255
40 //---------------------------------------------------------------------------
41 
42 /* Macro to detect space character */
43 #define ISSPACE(c) (((c) == ' ') || ((c) == '\t'))
44 
45 /* Macro to only execute parameter if echo is enabled for this shell */
46 #define IFX_SHELL_IF_ECHO(X) {if (shell->control.echo) {X; }}
47 
48 /* Macro to write lots of spaces */
49 #define IFX_SHELL_WRITE_SPACES(X) \
50  {int ii; for (ii = 0; ii < (X); ii++) {IfxStdIf_DPipe_print(shell->io, " "); }}
51 
52 /* Macro to write lots of backspaces */
53 #define IFX_SHELL_WRITE_BACKSPACES(X) \
54  {int ii; for (ii = 0; ii < (X); ii++) {IfxStdIf_DPipe_print(shell->io, "\b"); }}
55 
56 //---------------------------------------------------------------------------
58 //---------------------------------------------------------------------------
59 void Ifx_Shell_execute(Ifx_Shell *shell, pchar commandLine);
60 void Ifx_Shell_cmdEscapeProcess(Ifx_Shell *shell, char EscapeChar1, char EscapeChar2);
61 
62 //---------------------------------------------------------------------------
63 /**
64  * \brief Check whether the args is already at the end.
65  * \param args The argument null-terminated string
66  */
68 {
69  return ((args == NULL_PTR) || (*args == IFX_SHELL_NULL_CHAR)) ? TRUE : FALSE;
70 }
71 
72 
73 static boolean Ifx_Shell_writeResult(Ifx_Shell *shell, Ifx_SizeT Code)
74 {
75  Ifx_SizeT length = sizeof(Code);
76  boolean result = IfxStdIf_DPipe_write(shell->io, &Code, &length, TIME_INFINITE);
77 
79 
80  return result;
81 }
82 
83 
84 //---------------------------------------------------------------------------
85 boolean Ifx_Shell_showHelpSingle(pchar prefix, const void *commandList, IfxStdIf_DPipe *io)
86 {
87  const Ifx_Shell_Command *command = commandList;
88 
89  while (command->commandLine != NULL_PTR)
90  {
91  if ((prefix != NULL_PTR) && (prefix[0] != IFX_SHELL_NULL_CHAR))
92  {
93  IfxStdIf_DPipe_print(io, "%s ", prefix);
94  }
95 
96  IfxStdIf_DPipe_print(io, command->commandLine);
97  IfxStdIf_DPipe_print(io, command->help);
99  command = &command[1];
100  }
101 
102  return TRUE;
103 }
104 
105 
106 boolean Ifx_Shell_showHelp(pchar args, void *shellPtr, IfxStdIf_DPipe *io)
107 {
108  sint32 i;
109  Ifx_Shell *shell = shellPtr;
110 
111  (void)args; /* ignore compiler warning */
112 
113  for (i = 0; i < IFX_SHELL_COMMAND_LISTS; i++)
114  {
115  if (shell->commandList[i] != NULL_PTR)
116  {
117  Ifx_Shell_showHelpSingle("", shell->commandList[i], io);
118  }
119  }
120 
121  return TRUE;
122 }
123 
124 
125 boolean Ifx_Shell_protocolStart(pchar args, void *data, IfxStdIf_DPipe *io)
126 {
127  Ifx_Shell *shell = data;
128  boolean Result = TRUE;
129 
130  if (Ifx_Shell_matchToken(&args, "?") != FALSE)
131  {
132  IfxStdIf_DPipe_print(io, "Syntax : protocol start" ENDL);
133  IfxStdIf_DPipe_print(io, " > start a protocol" ENDL);
134  }
135  else if (Ifx_Shell_matchToken(&args, "start") != FALSE)
136  {
137  if ((shell->protocol.start != NULL_PTR) && (shell->protocol.object != NULL_PTR))
138  {
139  Result = shell->protocol.start(shell->protocol.object, io);
140  shell->protocol.started = (Result != FALSE);
141 
142  if (shell->protocol.onStart != NULL_PTR)
143  {
144  shell->protocol.onStart(shell->protocol.object, shell->protocol.onStartData);
145  }
146  }
147  else
148  {
149  Result = FALSE;
150  }
151  }
152  else
153  {}
154 
155  return Result;
156 }
157 
158 
159 boolean Ifx_Shell_bbProtocolStart(pchar args, void *data, IfxStdIf_DPipe *io)
160 {
161  boolean result = TRUE;
162 
163  if (Ifx_Shell_matchToken(&args, "?") != FALSE)
164  {
165  IfxStdIf_DPipe_print(io, "Syntax : protocol start" ENDL);
166  IfxStdIf_DPipe_print(io, " > start a protocol" ENDL);
167  }
168  else if (Ifx_Shell_matchToken(&args, "protocol") != FALSE)
169  {
170  result = Ifx_Shell_protocolStart(args, data, io);
171  }
172  else
173  {}
174 
175  return result;
176 }
177 
178 
179 //---------------------------------------------------------------------------
181 {
182  uint32 i;
183 
184  for (i = 0; i < IFX_SHELL_COMMAND_LISTS; i++)
185  {
186  config->commandList[i] = NULL_PTR;
187  }
188 
189  config->standardIo = NULL_PTR;
190  config->echo = TRUE;
191  config->protocol.execute = NULL_PTR;
192  config->protocol.object = NULL_PTR;
193  config->protocol.onStart = NULL_PTR;
194  config->protocol.onStartData = NULL_PTR;
195  config->protocol.start = NULL_PTR;
196  config->protocol.started = FALSE;
197  config->sendResultCode = FALSE;
198  config->showPrompt = TRUE;
199  config->standardIo = NULL_PTR;
200 }
201 
202 
203 boolean Ifx_Shell_init(Ifx_Shell *shell, const Ifx_Shell_Config *config)
204 {
205  sint32 i;
206  char **CmdHistory = NULL_PTR; /* Pointer to array of pointers for command history items */
207 
208  /* Ensure state variable is cleared */
209  memset(shell, 0, sizeof(*shell));
210 
211  shell->protocol = config->protocol;
212  shell->protocol.started = FALSE;
213 
214  shell->io = config->standardIo;
215  shell->control.showPrompt = config->showPrompt;
216  shell->control.sendResultCode = config->sendResultCode;
217  shell->control.echo = config->echo;
218  shell->control.echoError = TRUE;
219  shell->control.enabled = TRUE;
220 
221  shell->locals.escBracketNum = IFX_SHELL_NULL_CHAR; /* Used to cache number in sequence "ESC [ 1/2/3/4 ~" */
223 
224  /* Copy command line buffer pointer into state variable */
225  shell->cmd.cmdStr = shell->locals.cmdStr;
226 
227  /* Initialize command history space and cache pointer */
228  memset(Ifx_Shell_cmdBuffer, 0, sizeof(Ifx_Shell_cmdBuffer));
229  shell->cmdHistory[0] = &Ifx_Shell_cmdBuffer[0];
230 
231  for (i = 0; i < IFX_SHELL_COMMAND_LISTS; i++)
232  {
233  shell->commandList[i] = config->commandList[i];
234  }
235 
236  /* Initialize command history pointers */
237  CmdHistory = shell->cmdHistory;
238 
239  for (i = 1; i < IFX_SHELL_CMD_HISTORY_SIZE; i++)
240  {
241  CmdHistory[i] = &CmdHistory[i - 1][IFX_SHELL_CMD_LINE_SIZE]; /* Items are just offsets into a large allocated area */
242  }
243 
245 
246  /* Pre-load useful commands into history buffer */
247  strcpy(CmdHistory[0], "help");
248  strcpy(CmdHistory[1], "protocol start");
249 
250  if (shell->control.showPrompt != 0)
251  {
252  IfxStdIf_DPipe_print(shell->io, ENDL);
254  }
255 
256  return TRUE;
257 }
258 
259 
261 {
262  Ifx_SizeT i, j; /* Loop variables */
263  Ifx_SizeT count;
264  Ifx_SizeT readCount;
265  boolean NormalKeyPress; /* Indicates if this is a normal keypress, i.e. not part of an escape code */
266 
267  Ifx_Shell_CmdLine *Cmd = &shell->cmd;
268  char *inputbuffer = shell->locals.inputbuffer;
269  char *cmdStr = shell->locals.cmdStr;
270  char **CmdHistory = shell->cmdHistory;
271 
272  if (shell->control.enabled == 0)
273  {
274  return;
275  }
276 
277  if ((shell->protocol.object != NULL_PTR) && (shell->protocol.started != FALSE))
278  {
279  shell->protocol.execute(shell->protocol.object);
280  }
281  else
282  {
283  /**** NORMAL MODE ****/
284 
285  /********************************************************************************/
286  /* Read all characters until enter inclusive. */
287  /* If the command is bigger than IFX_SHELL_CMD_SIZE, the command is ignored. */
288  /* */
289  /* Escape sequences are handled by a state machine. */
290  /* The following escape sequences (prefix "ESC [") are supported: */
291  /* */
292  /* A - up B - down C - right D - left */
293  /* 1~ - HOME 2~ - INSERT 3~ - DELETE 5~ - END */
294  /* */
295  /* Backspace ('\b') is also supported. */
296  /********************************************************************************/
297 
298  count = 0;
299  readCount = IFX_SHELL_CMD_LINE_SIZE - count;
300  IfxStdIf_DPipe_read(shell->io, &inputbuffer[count], &readCount, TIME_NULL);
301  count += readCount;
302 
303  for (i = 0; i < count; i++)
304  {
305  /* By default, we assume character is part of escape sequence */
306  NormalKeyPress = FALSE;
307 
308  /* Process key pressed */
309  switch (inputbuffer[i])
310  {
311  /* New line (ENTER) */
312  case '\n':
313  case '\r':
314  /* Print new line to terminal if requested */
316 
317  /* Execute command if length is valid - i.e. not an over-full buffer
318  * (prevents attempted execution of junk) */
319  if (Cmd->length < IFX_SHELL_CMD_LINE_SIZE)
320  {
321  cmdStr[Cmd->length] = IFX_SHELL_NULL_CHAR; /* Terminate cmdStr */
322 
323  if (Cmd->historyAdd != FALSE)
324  {
325  /* Shuffle history up */
326  for (j = IFX_SHELL_CMD_HISTORY_SIZE - 1; j > 0; j--)
327  {
328  /* Copy text */
329  strncpy(CmdHistory[j], CmdHistory[j - 1], IFX_SHELL_CMD_LINE_SIZE);
330  }
331 
332  /* Copy in new entry */
333  strncpy(CmdHistory[0], cmdStr, IFX_SHELL_CMD_LINE_SIZE);
334  }
335 
336  /* Execute command */
337  Ifx_Shell_execute(shell, cmdStr);
338  }
339 
340  /* Show prompt if in main shell */
341  if (shell->control.showPrompt != 0)
342  {
344  }
345 
346  /* Reset command line buffer length */
347  Cmd->length = 0;
348 
349  /* Reset command line buffer cursor position */
350  Cmd->cursor = 0;
351 
352  /* Clear flag */
353  Cmd->historyAdd = FALSE;
354 
355  /* Ensure we're not in command history list */
357  break;
358 
359  /* Backspace (may occur in middle of text if cursor location is not at end) */
360  case '\b':
361 
362  if (Cmd->cursor > 0)
363  {
364  /* Update on screen */
365  if (shell->control.echo != 0)
366  {
367  /* Move left one character */
368  IfxStdIf_DPipe_print(shell->io, "\b");
369 
370  /* Update line with new characters */
371  for (j = Cmd->cursor; j < Cmd->length; j++)
372  {
373  IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[j]);
374  }
375 
376  /* Write over duplicated character at end */
377  IfxStdIf_DPipe_print(shell->io, " ");
378  IFX_SHELL_WRITE_BACKSPACES((Cmd->length - Cmd->cursor) + 1)
379  }
380 
381  /* Update in command line variable. Shuffle text left */
382  strncpy(&cmdStr[Cmd->cursor - 1], &cmdStr[Cmd->cursor], Cmd->length - Cmd->cursor);
383 
384  /* Terminate string at end of shorter string */
385  cmdStr[Cmd->length - 1] = IFX_SHELL_NULL_CHAR;
386 
387  Cmd->length--;
388  Cmd->cursor--;
389 
390  /* Command line has been modified */
391  Cmd->historyAdd = TRUE;
392  }
393 
394  break;
395 
396  /* Escape character */
397  case '\x1B': /*'\x1B': */
399  break;
400 
401  /* '[' - check to see if this is second part of an escape sequence */
402  case '[':
403 
405  {
406  /* ESC [ pressed */
408  }
409  else
410  {
411  NormalKeyPress = TRUE;
412  }
413 
414  break;
415 
416  /* Check for supported characters in escape sequences ( ESC [ A/B/C/D ) */
417  case 'A':
418  case 'B':
419  case 'C':
420  case 'D':
421 
423  {
424  /* Process arrow keys */
425  Ifx_Shell_cmdEscapeProcess(shell, inputbuffer[i], 0);
426 
427  /* End of escape sequence */
429  }
430  else
431  {
432  NormalKeyPress = TRUE;
433  }
434 
435  break;
436 
437  /* Check for supported characters in escape sequences (ESC [ 2/4/5 ~) */
438  case '1':
439  case '2':
440  case '3':
441  case '4':
442 
444  {
445  /* Store number for use once complete escape sequence is confirmed (below) */
446  shell->locals.escBracketNum = inputbuffer[i];
448  }
449  else
450  {
451  NormalKeyPress = TRUE;
452  }
453 
454  break;
455 
456  /* Check for supported characters in escape sequences (ESC [ 2/4/5 ~) */
457  case '~':
458 
460  {
461  /* Process home/delete/end */
462  Ifx_Shell_cmdEscapeProcess(shell, shell->locals.escBracketNum, '~');
463 
464  /* End of escape sequence */
466  }
467  else
468  {
469  NormalKeyPress = TRUE;
470  }
471 
472  break;
473 
474  /* Normal character - add to command string */
475  default:
476  NormalKeyPress = TRUE;
477  break;
478  }
479 
480  IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, Cmd->length >= Cmd->cursor); /* Sanity check */
481 
482  /* If this was a normal key press (not part of an escape sequence),
483  * add it to the command string */
484  if (NormalKeyPress != FALSE)
485  {
486  /* Ensure state machine is reset */
488 
489  /* If not filled buffer, add in this character */
490  if (Cmd->length < (IFX_SHELL_CMD_LINE_SIZE - 1))
491  {
492  /* Command line has been modified */
493  Cmd->historyAdd = TRUE;
494 
495  /* Copy into command line */
496  cmdStr[Cmd->cursor] = inputbuffer[i];
497  Cmd->cursor++;
498 
499  /* Update length of buffer */
500  Cmd->length = __max(Cmd->length, Cmd->cursor);
501 
502  if (shell->control.echo != 0)
503  {
504  /* echo character to shell output if requested */
505  shell->locals.echo[0] = inputbuffer[i];
506  IfxStdIf_DPipe_print(shell->io, shell->locals.echo);
507  }
508  }
509  else
510  {
511  /* Line too long - ignore further characters */
512  Cmd->historyAdd = FALSE; /* Invalid command line */
513  }
514  }
515  }
516  }
517 }
518 
519 
521 {
522  (void)shell; /* ignore compiler warning; */
523  // tbd free necessary memory
524 }
525 
526 
528 {
529  if (args != NULL_PTR)
530  {
531  while ((*args != IFX_SHELL_NULL_CHAR) && (ISSPACE(*args)))
532  {
533  args = &args[1];
534  }
535  }
536 
537  return args;
538 }
539 
540 
541 boolean Ifx_Shell_matchToken(pchar *argsPtr, pchar token)
542 {
543  pchar savedArguments = *argsPtr;
544  char buffer[256];
545  boolean result = FALSE;
546 
547  if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) != FALSE)
548  {
549  if (strcmp(token, buffer) == 0)
550  {
551  result = TRUE;
552  }
553  }
554 
555  if (result == FALSE)
556  {
557  // No match: don't advance pointer
558  *argsPtr = savedArguments;
559  }
560 
561  return result;
562 }
563 
564 
565 static boolean Ifx_Shell_matchCommand(pchar *argsPtr, pchar *match)
566 {
567  boolean result = FALSE;
568  pchar savedArguments = *argsPtr;
569  pchar savedMatch = *match;
570  char buffer0[256];
571  char buffer1[256];
572 
573  if ((Ifx_Shell_parseToken(argsPtr, buffer0, Ifx_COUNTOF(buffer0)) != FALSE)
574  && (Ifx_Shell_parseToken(match, buffer1, Ifx_COUNTOF(buffer1)) != FALSE))
575  {
576  if (strcmp(buffer1, buffer0) == 0)
577  {
578  result = TRUE;
579  }
580  }
581 
582  if (result == FALSE)
583  {
584  // No match: don't advance pointer
585  *argsPtr = savedArguments;
586  *match = savedMatch;
587  }
588 
589  return result;
590 }
591 
592 
593 boolean Ifx_Shell_parseToken(pchar *argsPtr, char *tokenBuffer, int bufferLength)
594 {
595  int mindex = 0;
596  pchar args = Ifx_Shell_skipWhitespace(*argsPtr);
597 
598  tokenBuffer[0] = IFX_SHELL_NULL_CHAR;
599 
600  if (args == NULL_PTR)
601  {
602  return FALSE;
603  }
604 
605  if (*args == '\"')
606  {
607  args = &args[1];
608 
609  while ((*args != IFX_SHELL_NULL_CHAR) && (*args != '\"'))
610  {
611  if (mindex < bufferLength)
612  {
613  tokenBuffer[mindex] = *args;
614  mindex++;
615  }
616 
617  args = &args[1];
618  }
619 
620  // error if no closing quote
621  if (*args != '\"')
622  {
623  return FALSE;
624  }
625 
626  args = &args[1];
627  }
628  else
629  {
630  // don't allow unquoted empty tokens
631  if (*args == IFX_SHELL_NULL_CHAR)
632  {
633  return FALSE;
634  }
635 
636  while ((*args != IFX_SHELL_NULL_CHAR) && (!ISSPACE(*args)))
637  {
638  if (mindex < bufferLength)
639  {
640  tokenBuffer[mindex] = *args;
641  mindex++;
642  }
643 
644  args = &args[1];
645  }
646  }
647 
648  // make sure string is zero terminated
649  if (bufferLength > 0)
650  {
651  tokenBuffer[__min(mindex, bufferLength - 1)] = IFX_SHELL_NULL_CHAR;
652  }
653 
654  *argsPtr = Ifx_Shell_skipWhitespace(args);
655 
656  return TRUE;
657 }
658 
659 
660 boolean Ifx_Shell_parseAddress(pchar *argsPtr, void **address)
661 {
662  char buffer[32];
663  boolean result;
664 
665  *address = 0;
666 
667  if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
668  {
669  result = FALSE;
670  }
671  else
672  {
673  result = (buffer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(buffer, "%x ", (unsigned int *)address) == 1);
674  }
675 
676  return result;
677 }
678 
679 
680 boolean Ifx_Shell_parseSInt32(pchar *argsPtr, sint32 *value)
681 {
682  sint64 value64;
683  boolean result;
684 
685  *value = 0;
686 
687  if (Ifx_Shell_parseSInt64(argsPtr, &value64) == FALSE)
688  {
689  result = FALSE;
690  }
691  else
692  {
693  *value = (sint32)value64;
694  result = TRUE;
695  }
696 
697  return result;
698 }
699 
700 
701 boolean Ifx_Shell_parseUInt32(pchar *argsPtr, uint32 *value, boolean hex)
702 {
703  uint64 value64;
704  boolean result;
705 
706  *value = 0;
707 
708  if (Ifx_Shell_parseUInt64(argsPtr, &value64, hex) == FALSE)
709  {
710  result = FALSE;
711  }
712  else
713  {
714  *value = (uint32)value64;
715  result = TRUE;
716  }
717 
718  return result;
719 }
720 
721 
722 boolean Ifx_Shell_parseSInt64(pchar *argsPtr, sint64 *value)
723 {
724  char buffer[64];
725  boolean result;
726 
727  *value = 0;
728 
729  if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
730  {
731  result = FALSE;
732  }
733  else
734  {
735  result = (buffer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(buffer, IFX_SHELL_LLD, value) == 1);
736  }
737 
738  return result;
739 }
740 
741 
742 boolean Ifx_Shell_parseUInt64(pchar *argsPtr, uint64 *value, boolean hex)
743 {
744  char buffer[64];
745  boolean result;
746 
747  *value = 0;
748 
749  if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
750  {
751  result = FALSE;
752  }
753  else
754  {
755  char *bufferPointer = buffer;
756 
757  if ((buffer[0] == '0') && (buffer[1] == 'x'))
758  {
759  bufferPointer = &bufferPointer[2];
760  hex = TRUE;
761  }
762 
763  if (hex != FALSE)
764  {
765  result = (bufferPointer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(bufferPointer, IFX_SHELL_LLX, value) == 1);
766  }
767  else
768  {
769  result = (bufferPointer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(bufferPointer, IFX_SHELL_LLU, value) == 1);
770  }
771  }
772 
773  return result;
774 }
775 
776 
777 boolean Ifx_Shell_parseFloat64(pchar *argsPtr, float64 *value)
778 {
779  char buffer[64];
780  boolean result;
781 
782  *value = 0;
783 
784  if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
785  {
786  result = FALSE;
787  }
788  else
789  {
790  result = (buffer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(buffer, "%lf ", value) == 1);
791  }
792 
793  return result;
794 }
795 
796 
797 boolean Ifx_Shell_parseFloat32(pchar *argsPtr, float32 *value)
798 {
799  char buffer[64];
800  boolean result;
801 
802  *value = 0;
803 
804  if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
805  {
806  result = FALSE;
807  }
808  else
809  {
810  result = (buffer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(buffer, "%f ", value) == 1);
811  }
812 
813  return result;
814 }
815 
816 
817 const Ifx_Shell_Command *Ifx_Shell_commandFind(const Ifx_Shell_Command *commandList, pchar commandLine, pchar *args)
818 {
819  const Ifx_Shell_Command *command = commandList;
820  const Ifx_Shell_Command *result = NULL_PTR;
821 
822  while (command->commandLine != NULL_PTR)
823  {
824  pchar commandTemp = (pchar)command->commandLine;
825  pchar commandLineTemp = commandLine;
826  char buffer[256];
827  boolean commandFound = FALSE;
828 
829  while (Ifx_Shell_matchCommand(&commandLineTemp, &commandTemp) != FALSE)
830  {
831  commandFound = TRUE;
832  }
833 
834  if ((commandFound != FALSE) && (Ifx_Shell_parseToken(&commandTemp, buffer, Ifx_COUNTOF(buffer)) == FALSE))
835  {
836  *args = commandLineTemp;
837  result = command;
838  break;
839  }
840 
841  command = &command[1];
842  }
843 
844  return result;
845 }
846 
847 
849 {
850  int i;
851  const Ifx_Shell_Command *shellCommand = NULL_PTR;
852 
853  for (i = 0; i < IFX_SHELL_COMMAND_LISTS; i++)
854  {
855  if (shell->commandList[i] != NULL_PTR)
856  {
857  shellCommand = Ifx_Shell_commandFind(shell->commandList[i], commandLine, args);
858 
859  if (shellCommand != NULL_PTR)
860  {
861  break;
862  }
863  }
864  }
865 
866  return shellCommand;
867 }
868 
869 
870 void Ifx_Shell_execute(Ifx_Shell *shell, pchar commandLine)
871 {
872  pchar args = NULL_PTR;
873  const Ifx_Shell_Command *shellCommand = Ifx_Shell_commandListFind(shell, commandLine, &args);
874 
875  if (shellCommand != NULL_PTR)
876  {
877  if (shellCommand->call(args, shellCommand->data, shell->io) != FALSE)
878  {
879  if (shell->control.sendResultCode != 0)
880  {
881  Ifx_Shell_writeResult(shell, Ifx_Shell_ResultCode_ok);
882  }
883  }
884  else
885  {
886  if (shell->control.sendResultCode != 0)
887  {
888  Ifx_Shell_writeResult(shell, Ifx_Shell_ResultCode_nok);
889  }
890  else if (shell->control.echoError != 0)
891  {
892  IfxStdIf_DPipe_print(shell->io, "\r\nShell command error: %s" ENDL, commandLine);
893  }
894  else
895  {}
896  }
897  }
898  else
899  {
900  if (commandLine[0] != IFX_SHELL_NULL_CHAR)
901  {
902  if (shell->control.sendResultCode != 0)
903  {
904  Ifx_Shell_writeResult(shell, Ifx_Shell_ResultCode_unknown);
905  }
906  else if (shell->control.echoError != 0)
907  {
908  IfxStdIf_DPipe_print(shell->io, "\r\nUnknown command: %s" ENDL, commandLine);
909  }
910  else
911  {}
912  }
913  }
914 }
915 
916 
917 /****************************************************************************************/
918 /* Processes escape sequences, including handling command history. */
919 /* The following escape sequences (prefix "ESC [") are supported: */
920 /* A - up B - down C - right D - left */
921 /* 1~ - HOME 2~ - INSERT 3~ - DELETE 4~ - END */
922 /* */
923 /* Parameters: */
924 /* EscapeChar1 - First character to follow ESC [ */
925 /* EscapeChar2 - Second character following ESC [ , if applicable */
926 /* */
927 /****************************************************************************************/
928 void Ifx_Shell_cmdEscapeProcess(Ifx_Shell *shell, char EscapeChar1, char EscapeChar2)
929 {
930  Ifx_Shell_CmdLine *Cmd = NULL_PTR; /* Command line editing state */
931  char *cmdStr = NULL_PTR; /* Cached pointer to command line being edited */
932  sint32 i = 0; /* Loop variable */
933 
934  /* Validate parameters */
935  boolean result = (shell != NULL_PTR);
936 
938 
939  if (result == FALSE)
940  {
941  return; /* ERROR CASE - no thread data available! */
942  }
943 
944  /* Cache command state and command line pointer */
945  Cmd = &shell->cmd;
946  cmdStr = Cmd->cmdStr;
947 
948  /* Validate command line state */
952 
953  /* Switch on first character after ESC [ */
954  switch (EscapeChar1)
955  {
956  case 'A': /* Up arrow */
957 
959  {
960  /* Not using list at the moment - take most recent item [0] */
961  Cmd->historyItem = 0;
962  }
963  else
964  {
965  if (Cmd->historyItem < (IFX_SHELL_CMD_HISTORY_SIZE - 1))
966  {
967  /* If not already at oldest, go back one in list */
968  Cmd->historyItem++;
969  }
970  }
971 
972  /* Copy text into buffer */
973  strncpy(cmdStr, shell->cmdHistory[Cmd->historyItem], IFX_SHELL_CMD_LINE_SIZE);
974 
975  /* echo to screen if requested */
976  if (shell->control.echo != 0)
977  {
978  IFX_SHELL_WRITE_BACKSPACES(Cmd->cursor) /* Move cursor back to start */
979  IFX_SHELL_WRITE_SPACES(Cmd->length) /* Overwrite text with spaces */
980  IFX_SHELL_WRITE_BACKSPACES(Cmd->length) /* Move cursor back to start */
981  IfxStdIf_DPipe_print(shell->io, cmdStr); /* Copy buffer to screen */
982  }
983 
984  Cmd->cursor = (Ifx_SizeT)strlen(cmdStr); /* Store cursor position */
985  Cmd->length = Cmd->cursor; /* Store command line length */
986  Cmd->historyAdd = FALSE; /* Don't add back to history unless modified */
987  break;
988 
989  case 'B': /* Down arrow */
990 
991  if ((Cmd->historyItem == IFX_SHELL_CMD_HISTORY_NO_ITEM) || (Cmd->historyItem == 0))
992  {
993  /* Not using list at the moment, or have dropped off the end - just clear command line */
994  if (shell->control.echo != 0)
995  {
996  IFX_SHELL_WRITE_BACKSPACES(Cmd->cursor) /* Move cursor back to start */
997  IFX_SHELL_WRITE_SPACES(Cmd->length) /* Overwrite text with spaces */
998  IFX_SHELL_WRITE_BACKSPACES(Cmd->length) /* Move cursor back to start */
999  }
1000 
1001  Cmd->length = 0; /* Reset command line length */
1002  Cmd->cursor = 0;
1003  Cmd->historyItem = IFX_SHELL_CMD_HISTORY_NO_ITEM; /* Ensure we are not using list */
1004  }
1005  else
1006  {
1007  /* Within list - move to more recent entry */
1008  Cmd->historyItem--;
1009 
1010  /* Copy text into buffer */
1011  strncpy(cmdStr, shell->cmdHistory[Cmd->historyItem], IFX_SHELL_CMD_LINE_SIZE);
1012 
1013  if (shell->control.echo != 0)
1014  {
1015  IFX_SHELL_WRITE_BACKSPACES(Cmd->cursor) /* Move cursor back to start */
1016  IFX_SHELL_WRITE_SPACES(Cmd->length) /* Overwrite text with spaces */
1017  IFX_SHELL_WRITE_BACKSPACES(Cmd->length) /* Move cursor back to start */
1018  IfxStdIf_DPipe_print(shell->io, cmdStr); /* Copy buffer to screen */
1019  }
1020 
1021  Cmd->cursor = (Ifx_SizeT)strlen(cmdStr); /* Store cursor position */
1022  Cmd->length = Cmd->cursor; /* Store command line length */
1023  }
1024 
1025  Cmd->historyAdd = FALSE;
1026  break;
1027 
1028  case 'C': /* Right arrow */
1029 
1030  if (Cmd->cursor < Cmd->length)
1031  {
1032  /* Move cursor one place to right */
1033  IFX_SHELL_IF_ECHO(IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[Cmd->cursor])) Cmd->cursor++;
1034  }
1035 
1036  break;
1037 
1038  case 'D': /* Left arrow */
1039 
1040  if (Cmd->cursor > 0)
1041  {
1042  /* Move cursor one place to left */
1043  IFX_SHELL_IF_ECHO(IfxStdIf_DPipe_print(shell->io, "\b")) Cmd->cursor--;
1044  }
1045 
1046  break;
1047 
1048  default:
1049  break;
1050  }
1051 
1052  /* If second character after ESC [ is ~ then switch on number */
1053  if (EscapeChar2 == '~')
1054  {
1055  switch (EscapeChar1)
1056  {
1057  case '1': /* HOME - move to start of buffer */
1058 
1059  if (Cmd->cursor > 0)
1060  {
1061  IFX_SHELL_WRITE_BACKSPACES(Cmd->cursor) Cmd->cursor = 0;
1062  }
1063 
1064  break;
1065 
1066  case '2': /* INSERT - insert blank character at cursor and move all remaining characters right one */
1067 
1068  if ((Cmd->cursor < Cmd->length) && (Cmd->length < (IFX_SHELL_CMD_LINE_SIZE - 1)))
1069  {
1070  /* Update on screen */
1071  if (shell->control.echo != FALSE)
1072  {
1073  /* write over duplicated character at cursor */
1074  IfxStdIf_DPipe_print(shell->io, " ");
1075 
1076  /* Update line with new characters */
1077  for (i = Cmd->cursor; i < Cmd->length; i++)
1078  {
1079  IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[i]);
1080  }
1081 
1082  /* Move cursor back to new place */
1083  IFX_SHELL_WRITE_BACKSPACES((Cmd->length + 1) - Cmd->cursor)
1084  }
1085 
1086  /* Update in command line variable */
1087  for (i = Cmd->length; i > Cmd->cursor; i--)
1088  {
1089  cmdStr[i] = cmdStr[i - 1]; /* Shuffle text right */
1090  }
1091 
1092  cmdStr[Cmd->length + 1] = IFX_SHELL_NULL_CHAR; /* Terminate string at end of longer string */
1093  cmdStr[Cmd->cursor] = ' '; /* Blank character at cursor */
1094 
1095  Cmd->length++; /* Now one character longer */
1096  }
1097 
1098  break;
1099 
1100  case '3': /* DELETE - delete character to right and move all remaining characters left one */
1101 
1102  if (Cmd->cursor < Cmd->length)
1103  {
1104  /* Update on screen */
1105  if (shell->control.echo != 0)
1106  {
1107  for (i = Cmd->cursor; i < (Cmd->length - 1); i++)
1108  {
1109  /* Update line with new characters */
1110  IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[i + 1]);
1111  }
1112 
1113  /* write over duplicated character at end */
1114  IfxStdIf_DPipe_print(shell->io, " ");
1115 
1116  /* Move cursor back to right place */
1118  }
1119 
1120  /* Update in command line variable. Shuffle text left */
1121  strncpy(&cmdStr[Cmd->cursor], &cmdStr[Cmd->cursor + 1], Cmd->length - Cmd->cursor - 1);
1122 
1123  cmdStr[Cmd->length - 1] = IFX_SHELL_NULL_CHAR; /* Terminate string at end of shorter string */
1124  Cmd->length--; /* Now one character shorter */
1125  }
1126 
1127  break;
1128 
1129  case '4': /* END - ensure cursor is at end */
1130 
1131  while (Cmd->cursor < Cmd->length)
1132  {
1133  IFX_SHELL_IF_ECHO(IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[Cmd->cursor])) Cmd->cursor++;
1134  }
1135 
1136  break;
1137 
1138  default:
1139  break;
1140  }
1141  }
1142 }
1143 
1144 
1146 {
1147  // Clear the Rx buffer!
1148  IfxStdIf_DPipe_clearRx(shell->io);
1149  // Enable the shell
1150  shell->control.enabled = 1;
1151 }
1152 
1153 
1155 {
1156  shell->control.enabled = 0;
1157 }
1158 
1159 
1161 {
1162  const Ifx_Shell_Syntax *syntax = syntaxList;
1163 
1164  while (syntax->syntax != NULL_PTR)
1165  {
1166  IfxStdIf_DPipe_print(io, "Syntax : %s" ENDL, syntax->syntax);
1167  IfxStdIf_DPipe_print(io, " > %s" ENDL, syntax->description);
1168  syntax = &syntax[1];
1169  }
1170 }