shellmatta_history.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright (c) 2019 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_history.c
  10. * @brief history buffer functions of shellmatta
  11. * @author Stefan Strobel <stefan.strobel@shimatta.net>
  12. */
  13. /**
  14. * @addtogroup shellmatta_history
  15. * @{
  16. */
  17. #include "shellmatta_history.h"
  18. #include "shellmatta.h"
  19. #include "shellmatta_utils.h"
  20. /**
  21. * @brief appends a byte to the history ring stack buffer
  22. * @param[in] inst pointer to a shellmatta instance
  23. * @param[in] byte byte to append to the history buffer
  24. */
  25. static void appendHistoryByte(shellmatta_instance_t *inst, char byte)
  26. {
  27. /** -# calculate the new history buffer index */
  28. inst->historyEnd ++;
  29. if(inst->historyEnd >= inst->historyBufferSize)
  30. {
  31. inst->historyEnd = 0u;
  32. }
  33. /** -# append the byte */
  34. inst->historyBuffer[inst->historyEnd] = byte;
  35. /** -# check if the we overwrite an existing stored command */
  36. if(inst->historyEnd == inst->historyStart)
  37. {
  38. /** -# move the start pointer to the next termination (0) */
  39. do
  40. {
  41. inst->historyStart ++;
  42. if(inst->historyStart >= inst->historyBufferSize)
  43. {
  44. inst->historyStart = 0u;
  45. }
  46. }while(0u != inst->historyBuffer[inst->historyStart]);
  47. }
  48. }
  49. /**
  50. * @brief reads a byte from the history buffer and decreases the read index
  51. * @param[in] inst pointer to a shellmatta instance
  52. * @param[out] byte pointer to a char where the read out byte will be stored
  53. * @return false: no new byte to read
  54. */
  55. static bool getHistoryByte(shellmatta_instance_t *inst, char *byte)
  56. {
  57. bool ret = false;
  58. /** -# check if we have reached the end of the buffer already */
  59. if(inst->historyRead != inst->historyStart)
  60. {
  61. /** -# read out one byte and decrease the read index */
  62. *byte = inst->historyBuffer[inst->historyRead];
  63. if(0u == inst->historyRead)
  64. {
  65. inst->historyRead = inst->historyBufferSize;
  66. }
  67. inst->historyRead --;
  68. ret = true;
  69. }
  70. return ret;
  71. }
  72. /**
  73. * @brief navigates in the history buffer by the given number of commands
  74. * @param[in, out] inst pointer to a shellmatta instance
  75. * @param[in] cnt direction and count to navigate
  76. * @return false: end of buffer reached
  77. */
  78. bool history_navigate(shellmatta_instance_t *inst, int32_t cnt)
  79. {
  80. bool ret = true;
  81. uint32_t tempReadIdx = 0u;
  82. while((cnt > 0) && (true == ret))
  83. {
  84. if(inst->historyRead != inst->historyEnd)
  85. {
  86. inst->historyRead ++;
  87. }
  88. while(inst->historyRead != inst->historyEnd)
  89. {
  90. inst->historyRead ++;
  91. if(inst->historyRead >= inst->historyBufferSize)
  92. {
  93. inst->historyRead = 0u;
  94. }
  95. if( (inst->historyRead != inst->historyEnd)
  96. && (0u == inst->historyBuffer[inst->historyRead]))
  97. {
  98. if(0u == inst->historyRead)
  99. {
  100. inst->historyRead = inst->historyBufferSize;
  101. }
  102. inst->historyRead --;
  103. cnt -= 1;
  104. break;
  105. }
  106. }
  107. if(inst->historyRead == inst->historyEnd)
  108. {
  109. ret = false;
  110. }
  111. }
  112. while((cnt < 0) && (true == ret))
  113. {
  114. tempReadIdx = inst->historyRead;
  115. while(inst->historyRead != inst->historyStart)
  116. {
  117. if(0u == inst->historyRead)
  118. {
  119. inst->historyRead = inst->historyBufferSize;
  120. }
  121. inst->historyRead --;
  122. if( (inst->historyRead != inst->historyStart)
  123. && (0u == inst->historyBuffer[inst->historyRead]))
  124. {
  125. if(0u == inst->historyRead)
  126. {
  127. inst->historyRead = inst->historyBufferSize;
  128. }
  129. inst->historyRead --;
  130. cnt += 1;
  131. break;
  132. }
  133. }
  134. if(inst->historyRead == inst->historyStart)
  135. {
  136. inst->historyRead = tempReadIdx;
  137. inst->historyReadUp = false;
  138. ret = false;
  139. }
  140. }
  141. return ret;
  142. }
  143. /**
  144. * @brief stores the current command from the instances buffer into the
  145. * history buffer
  146. * @param[in] inst pointer to a shellmatta instance
  147. */
  148. void history_storeCmd(shellmatta_instance_t *inst)
  149. {
  150. uint32_t i;
  151. /** -# check if we have enough room for the command in the history buffer
  152. * and there is a new command to be stored */
  153. if( (inst->historyBufferSize > inst->inputCount)
  154. && (0u != inst->inputCount)
  155. && (true == inst->dirty))
  156. {
  157. /** -# append the command termination */
  158. appendHistoryByte(inst, 0u);
  159. /** -# append the command byte wise in reverse direction */
  160. for(i = inst->inputCount; i > 0u; i --)
  161. {
  162. appendHistoryByte(inst, inst->buffer[i - 1u]);
  163. }
  164. }
  165. /** -# remove the dirty flag - everything is nice and saved */
  166. inst->dirty = false;
  167. }
  168. /**
  169. * @brief restores the command from the history buffer where the read
  170. * index points on
  171. * @param[in] inst pointer to a shellmatta instance
  172. */
  173. void history_restoreCmd(shellmatta_instance_t *inst)
  174. {
  175. char byte;
  176. bool ret = true;
  177. bool anythingToRestore = false;
  178. ret = getHistoryByte(inst, &byte);
  179. /** -# delete the input if there is data in the history buffer */
  180. if(true == ret)
  181. {
  182. utils_clearInput(inst);
  183. anythingToRestore = true;
  184. }
  185. while((ret == true) && (byte != 0u))
  186. {
  187. inst->buffer[inst->inputCount] = byte;
  188. inst->inputCount ++;
  189. inst->cursor ++;
  190. ret = getHistoryByte(inst, &byte);
  191. }
  192. if(true == anythingToRestore)
  193. {
  194. utils_writeEcho(inst, inst->buffer, inst->inputCount);
  195. inst->dirty = false;
  196. }
  197. (void)history_navigate(inst, 1);
  198. }
  199. /**
  200. * @brief resets the history buffer pointers to show to the most recent
  201. * command again
  202. * @param[in] inst pointer to a shellmatta instance
  203. */
  204. void history_reset(shellmatta_instance_t *inst)
  205. {
  206. inst->historyRead = inst->historyEnd;
  207. inst->historyReadUp = true;
  208. }
  209. /**
  210. * @}
  211. */