shellmatta_autocomplete.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Copyright (c) 2019 - 2024 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. #ifdef SHELLMATTA_AUTHENTICATION
  92. if (NULL != inst->userPointer)
  93. {
  94. utils_writeEcho(inst, inst->userPointer->username, strlen(inst->userPointer->username));
  95. utils_writeEcho(inst, "@", 1);
  96. }
  97. #endif
  98. utils_writeEcho(inst, inst->prompt, strlen(inst->prompt));
  99. utils_writeEcho(inst, inst->buffer, inst->inputCount);
  100. tempCursor = inst->cursor;
  101. inst->cursor = inst->inputCount;
  102. utils_rewindCursor(inst, inst->inputCount - tempCursor);
  103. }
  104. }
  105. /** -# on single tab autocomplete as far as possible */
  106. else if(0u != inst->cursor)
  107. {
  108. /** -# loop through all registered commands */
  109. while (NULL != cmd)
  110. {
  111. #ifdef SHELLMATTA_AUTHENTICATION
  112. if (SHELLMATTA_OK != shellmatta_auth_is_cmd_permitted(inst, cmd))
  113. {
  114. cmd = cmd->next;
  115. continue;
  116. }
  117. #endif
  118. /** -# check if command matches the input */
  119. if( (strlen(cmd->cmd) >= inst->cursor)
  120. && (0 == strncmp(cmd->cmd, inst->buffer, inst->cursor)))
  121. {
  122. /** -# store first match */
  123. if(NULL == tempCmd)
  124. {
  125. tempCmd = cmd->cmd;
  126. minLen = strlen(cmd->cmd);
  127. }
  128. /** -# find common part of the matching commands */
  129. else
  130. {
  131. exactMatch = false;
  132. minLen = SHELLMATTA_MIN(strlen(cmd->cmd), minLen);
  133. for(uint32_t i = 0u; i < minLen; i++)
  134. {
  135. if(cmd->cmd[i] != tempCmd[i])
  136. {
  137. minLen = i;
  138. }
  139. }
  140. }
  141. }
  142. /** -# check if command Alias matches the input */
  143. if( (NULL != cmd->cmdAlias)
  144. && (strlen(cmd->cmdAlias) >= inst->cursor)
  145. && (0 == strncmp(cmd->cmdAlias, inst->buffer, inst->cursor)))
  146. {
  147. /** -# store first match */
  148. if(NULL == tempCmd)
  149. {
  150. tempCmd = cmd->cmdAlias;
  151. minLen = strlen(cmd->cmdAlias);
  152. }
  153. /** -# find common part of the matches */
  154. else
  155. {
  156. exactMatch = false;
  157. minLen = SHELLMATTA_MIN(strlen(cmd->cmdAlias), minLen);
  158. for(uint32_t i = 0u; i < minLen; i++)
  159. {
  160. if(cmd->cmdAlias[i] != tempCmd[i])
  161. {
  162. minLen = i;
  163. }
  164. }
  165. }
  166. }
  167. cmd = cmd->next;
  168. }
  169. /** -# autocomplete found command */
  170. if(NULL != tempCmd)
  171. {
  172. /** -# calculate the size of the command to be inserted */
  173. sizeDiff = minLen - inst->cursor;
  174. /** -# copy the found part into the buffer and display it */
  175. utils_insertChars(inst, &(tempCmd[inst->cursor]), sizeDiff);
  176. /** -# on exact match there is no need to double Tab to display all */
  177. if(true == exactMatch)
  178. {
  179. inst->tabCounter = 0u;
  180. }
  181. }
  182. }
  183. else
  184. {
  185. /* nothing to do here */
  186. }
  187. }
  188. /**
  189. * @}
  190. */