shellmatta_autocomplete.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net>
  3. *
  4. * This Source Code Form is subject to the terms of the Mozilla Public
  5. * License, v. 2.0. If a copy of the MPL was not distributed with this
  6. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  7. */
  8. /**
  9. * @file shellmatta_autocomplete.c
  10. * @brief autocomplete function of shellmatta
  11. * @author Stefan Strobel <stefan.strobel@shimatta.net>
  12. */
  13. /**
  14. * @addtogroup shellmatta_autocomplete
  15. * @{
  16. */
  17. #include "shellmatta.h"
  18. #include "shellmatta_autocomplete.h"
  19. #include "shellmatta_utils.h"
  20. #ifdef SHELLMATTA_AUTHENTICATION
  21. #include "shellmatta_auth.h"
  22. #endif
  23. #include <stdint.h>
  24. #include <string.h>
  25. /**
  26. * @brief searches the registered commands for matching ones and prints
  27. * the common part of all matching commands on the output
  28. * if called twice all matching commands are printed
  29. * @param[in] inst pointer to a shellmatta instance
  30. */
  31. void autocomplete_run(shellmatta_instance_t *inst)
  32. {
  33. shellmatta_cmd_t *cmd = inst->cmdList;
  34. char *tempCmd = NULL;
  35. uint32_t minLen = 0u;
  36. bool exactMatch = true;
  37. uint32_t printedLen = 0u;
  38. uint32_t sizeDiff;
  39. uint32_t tempCursor;
  40. /** -# increase the tab counter to print all matching commands next time */
  41. inst->tabCounter++;
  42. /** -# on douple tab show all matching commands */
  43. if (inst->tabCounter > 1u)
  44. {
  45. inst->tabCounter = 0u;
  46. /** -# loop through all registered commands */
  47. while (NULL != cmd)
  48. {
  49. #ifdef SHELLMATTA_AUTHENTICATION
  50. if (SHELLMATTA_OK != shellmatta_auth_is_cmd_permitted(inst, cmd))
  51. {
  52. cmd = cmd->next;
  53. continue;
  54. }
  55. #endif
  56. /** -# check if command matches the input */
  57. if( (strlen(cmd->cmd) >= inst->cursor)
  58. && (0 == strncmp(cmd->cmd, inst->buffer, inst->cursor)))
  59. {
  60. /** -# add newline on first find */
  61. if(0u == printedLen)
  62. {
  63. inst->write("\r\n", 2u);
  64. }
  65. inst->write(cmd->cmd, strlen(cmd->cmd));
  66. printedLen += strlen(cmd->cmd);
  67. inst->write(" ", 4u);
  68. printedLen += 4u;
  69. }
  70. /** -# check if command alias matches the input */
  71. if( (NULL != cmd->cmdAlias)
  72. && (strlen(cmd->cmdAlias) >= inst->cursor)
  73. && (0 == strncmp(cmd->cmdAlias, inst->buffer, inst->cursor)))
  74. {
  75. /** -# add newline on first find */
  76. if(0u == printedLen)
  77. {
  78. inst->write("\r\n", 2u);
  79. }
  80. inst->write(cmd->cmdAlias, strlen(cmd->cmdAlias));
  81. printedLen += strlen(cmd->cmdAlias);
  82. inst->write(" ", 4u);
  83. printedLen += 4u;
  84. }
  85. cmd = cmd->next;
  86. }
  87. /** -# print input again if a commands was found */
  88. if(printedLen > 0u)
  89. {
  90. utils_writeEcho(inst, "\r\n", 2u);
  91. utils_writeEcho(inst, inst->prompt, strlen(inst->prompt));
  92. utils_writeEcho(inst, inst->buffer, inst->inputCount);
  93. tempCursor = inst->cursor;
  94. inst->cursor = inst->inputCount;
  95. utils_rewindCursor(inst, inst->inputCount - tempCursor);
  96. }
  97. }
  98. /** -# on single tab autocomplete as far as possible */
  99. else if(0u != inst->cursor)
  100. {
  101. /** -# loop through all registered commands */
  102. while (NULL != cmd)
  103. {
  104. #ifdef SHELLMATTA_AUTHENTICATION
  105. if (SHELLMATTA_OK != shellmatta_auth_is_cmd_permitted(inst, cmd))
  106. {
  107. cmd = cmd->next;
  108. continue;
  109. }
  110. #endif
  111. /** -# check if command matches the input */
  112. if( (strlen(cmd->cmd) >= inst->cursor)
  113. && (0 == strncmp(cmd->cmd, inst->buffer, inst->cursor)))
  114. {
  115. /** -# store first match */
  116. if(NULL == tempCmd)
  117. {
  118. tempCmd = cmd->cmd;
  119. minLen = strlen(cmd->cmd);
  120. }
  121. /** -# find common part of the matching commands */
  122. else
  123. {
  124. exactMatch = false;
  125. minLen = SHELLMATTA_MIN(strlen(cmd->cmd), minLen);
  126. for(uint32_t i = 0u; i < minLen; i++)
  127. {
  128. if(cmd->cmd[i] != tempCmd[i])
  129. {
  130. minLen = i;
  131. }
  132. }
  133. }
  134. }
  135. /** -# check if command Alias matches the input */
  136. if( (NULL != cmd->cmdAlias)
  137. && (strlen(cmd->cmdAlias) >= inst->cursor)
  138. && (0 == strncmp(cmd->cmdAlias, inst->buffer, inst->cursor)))
  139. {
  140. /** -# store first match */
  141. if(NULL == tempCmd)
  142. {
  143. tempCmd = cmd->cmdAlias;
  144. minLen = strlen(cmd->cmdAlias);
  145. }
  146. /** -# find common part of the matches */
  147. else
  148. {
  149. exactMatch = false;
  150. minLen = SHELLMATTA_MIN(strlen(cmd->cmdAlias), minLen);
  151. for(uint32_t i = 0u; i < minLen; i++)
  152. {
  153. if(cmd->cmdAlias[i] != tempCmd[i])
  154. {
  155. minLen = i;
  156. }
  157. }
  158. }
  159. }
  160. cmd = cmd->next;
  161. }
  162. /** -# autocomplete found command */
  163. if(NULL != tempCmd)
  164. {
  165. /** -# calculate the size of the command to be inserted */
  166. sizeDiff = minLen - inst->cursor;
  167. /** -# copy the found part into the buffer and display it */
  168. utils_insertChars(inst, &(tempCmd[inst->cursor]), sizeDiff, false);
  169. /** -# on exact match there is no need to double Tab to display all */
  170. if(true == exactMatch)
  171. {
  172. inst->tabCounter = 0u;
  173. }
  174. }
  175. }
  176. else
  177. {
  178. /* nothing to do here */
  179. }
  180. }
  181. /**
  182. * @}
  183. */