shellmatta_history.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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
  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. bool history_navigate(shellmatta_instance_t *inst, int32_t cnt)
  73. {
  74. bool ret = true;
  75. uint32_t tempReadIdx = 0u;
  76. while((cnt > 0) && (true == ret))
  77. {
  78. if(inst->historyRead != inst->historyEnd)
  79. {
  80. inst->historyRead ++;
  81. }
  82. while(inst->historyRead != inst->historyEnd)
  83. {
  84. inst->historyRead ++;
  85. if(inst->historyRead >= inst->historyBufferSize)
  86. {
  87. inst->historyRead = 0u;
  88. }
  89. if( (inst->historyRead != inst->historyEnd)
  90. && (0u == inst->historyBuffer[inst->historyRead]))
  91. {
  92. if(0u == inst->historyRead)
  93. {
  94. inst->historyRead = inst->historyBufferSize;
  95. }
  96. inst->historyRead --;
  97. cnt -= 1;
  98. break;
  99. }
  100. }
  101. if(inst->historyRead == inst->historyEnd)
  102. {
  103. ret = false;
  104. }
  105. }
  106. while((cnt < 0) && (true == ret))
  107. {
  108. tempReadIdx = inst->historyRead;
  109. while(inst->historyRead != inst->historyStart)
  110. {
  111. if(0u == inst->historyRead)
  112. {
  113. inst->historyRead = inst->historyBufferSize;
  114. }
  115. inst->historyRead --;
  116. if( (inst->historyRead != inst->historyStart)
  117. && (0u == inst->historyBuffer[inst->historyRead]))
  118. {
  119. if(0u == inst->historyRead)
  120. {
  121. inst->historyRead = inst->historyBufferSize;
  122. }
  123. inst->historyRead --;
  124. cnt += 1;
  125. break;
  126. }
  127. }
  128. if(inst->historyRead == inst->historyStart)
  129. {
  130. inst->historyRead = tempReadIdx;
  131. inst->historyReadUp = false;
  132. ret = false;
  133. }
  134. }
  135. return ret;
  136. }
  137. /**
  138. * @brief stores the current command from the instances buffer into the
  139. * history buffer
  140. * @param[in] inst pointer to a shellmatta instance
  141. */
  142. void history_storeCmd(shellmatta_instance_t *inst)
  143. {
  144. uint32_t i;
  145. /** -# check if we have enough room for the command in the history buffer
  146. * and there is a new command to be stored */
  147. if( (inst->historyBufferSize > inst->inputCount)
  148. && (0u != inst->inputCount)
  149. && (true == inst->dirty))
  150. {
  151. /** -# append the command termination */
  152. appendHistoryByte(inst, 0u);
  153. /** -# append the command byte wise in reverse direction */
  154. for(i = inst->inputCount; i > 0u; i --)
  155. {
  156. appendHistoryByte(inst, inst->buffer[i - 1u]);
  157. }
  158. }
  159. /** -# remove the dirty flag - everything is nice and saved */
  160. inst->dirty = false;
  161. }
  162. /**
  163. * @brief navigates in the history buffer by the given number of commands
  164. * @param[in] inst pointer to a shellmatta instance
  165. * @param[in] cnt direction and count to navigate
  166. * @return
  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. ret = getHistoryByte(inst, &byte);
  178. while((ret == true) && (byte != 0u))
  179. {
  180. inst->buffer[inst->inputCount] = byte;
  181. inst->inputCount ++;
  182. inst->cursor ++;
  183. ret = getHistoryByte(inst, &byte);
  184. }
  185. utils_writeEcho(inst, inst->buffer, inst->inputCount);
  186. history_navigate(inst, 1);
  187. inst->dirty = false;
  188. }
  189. /**
  190. * @brief resets the history buffer pointers to show to the most recent
  191. * command again
  192. * @param[in] inst pointer to a shellmatta instance
  193. */
  194. void history_reset(shellmatta_instance_t *inst)
  195. {
  196. inst->historyRead = inst->historyEnd;
  197. inst->historyReadUp = true;
  198. }
  199. /**
  200. * @}
  201. */