history.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #include <unistd.h>
  2. #include <string.h>
  3. #include <errno.h>
  4. #include <algorithm>
  5. #include <fstream>
  6. #include <sstream>
  7. #include "history.hpp"
  8. #include "appContext.hpp"
  9. using namespace std;
  10. using namespace knacki::cd;
  11. static std::string RelativePathToAbsolute(const string &path)
  12. {
  13. if (path[0] == '/')
  14. return path;
  15. char *p = realpath(path.c_str(), nullptr);
  16. string pathResult(p);
  17. free(p);
  18. return pathResult;
  19. }
  20. HistoryEntry::HistoryEntry(PTR_TYPE i, const string &e): path(e), index(i)
  21. {}
  22. HistoryEntry::HistoryEntry(const HistoryEntry &o): path(o.path), index(o.index)
  23. {}
  24. HistoryEntry &HistoryEntry::operator=(const HistoryEntry &o)
  25. {
  26. path = o.path;
  27. index = o.index;
  28. return *this;
  29. }
  30. const std::string &HistoryEntry::GetPath() const
  31. { return path; }
  32. PTR_TYPE HistoryEntry::GetIndex() const
  33. { return index; }
  34. History::History(const string &path): current(-1), prev(-1)
  35. {
  36. std::ifstream file(path, fstream::in | fstream::binary);
  37. Read(file);
  38. }
  39. HistoryRW::HistoryRW(const string &_path): History(_path), path(_path)
  40. {}
  41. const std::vector<HistoryEntry> &History::GetEntries() const
  42. { return hist; }
  43. const HistoryEntry *History::GetHistoryEntry(PTR_TYPE index) const
  44. {
  45. for (const HistoryEntry &i: GetEntries())
  46. if (i.GetIndex() == index)
  47. return &i;
  48. return nullptr;
  49. }
  50. void History::Read(std::istream &file)
  51. {
  52. PTR_TYPE current = -1;
  53. PTR_TYPE prev = -1;
  54. unsigned int histIndex =0;
  55. size_t size;
  56. char *buf = nullptr;
  57. size_t bufSize = 0;
  58. hist.clear();
  59. if (!file.good() && errno != ENOENT)
  60. throw IOError(strerror(errno));
  61. file.seekg(0);
  62. if (sizeof(prev) != file.readsome((char *)(&prev), sizeof(prev)))
  63. return;
  64. if (sizeof(current) != file.readsome((char *)(&current), sizeof(current)))
  65. return;
  66. while (file.good())
  67. {
  68. if (sizeof(size) != file.readsome((char*)(&size), sizeof(size)))
  69. break;
  70. if (size > bufSize)
  71. {
  72. delete[] buf;
  73. buf = new char[size]();
  74. bufSize = size;
  75. }
  76. if (size != file.readsome(buf, size))
  77. break;
  78. const size_t lastIndex = ++histIndex;
  79. hist.push_back(HistoryEntry(lastIndex, string(buf, size)));
  80. if (current != -1)
  81. if (!--current)
  82. this->current = lastIndex;
  83. if (prev != -1)
  84. if (!--prev)
  85. this->prev = lastIndex;
  86. }
  87. delete []buf;
  88. if (this->current == -1)
  89. this->current = hist.back().GetIndex();
  90. }
  91. void HistoryRW::Write()
  92. {
  93. size_t written = 0;
  94. std::ofstream file(path, fstream::in | fstream::out | fstream::binary | fstream::trunc);
  95. if (!file.good())
  96. throw IOError(strerror(errno));
  97. file.write((char*)(&prev), sizeof(prev));
  98. file.write((char*)(&current), sizeof(current));
  99. for (HistoryEntry i: hist)
  100. {
  101. const size_t pathLen = i.GetPath().length();
  102. file.write((char*)(&pathLen), sizeof(pathLen));
  103. written += sizeof(pathLen);
  104. file.write(i.GetPath().c_str(), sizeof(*(i.GetPath().c_str())) * i.GetPath().size());
  105. written += sizeof(*(i.GetPath().c_str())) * i.GetPath().size();
  106. }
  107. }
  108. bool HistoryRW::AppendCwd()
  109. {
  110. char *cwd = get_current_dir_name();
  111. const bool result = Append(cwd);
  112. free(cwd);
  113. return result;
  114. }
  115. bool HistoryRW::Append(const HistoryEntry &ent)
  116. {
  117. const HistoryEntry *e = GetHistoryEntry(ent.GetIndex());
  118. if (e)
  119. {
  120. // Juste move ptr
  121. if (current != e->GetIndex())
  122. {
  123. prev = current;
  124. current = e->GetIndex();
  125. return true;
  126. }
  127. else
  128. return false;
  129. }
  130. return Append(ent.GetPath());
  131. }
  132. void HistoryRW::TruncateAfter(PTR_TYPE pos)
  133. {
  134. while (!hist.empty() && hist.back().GetIndex() > pos)
  135. hist.pop_back();
  136. }
  137. bool HistoryRW::Append(const std::string &path)
  138. {
  139. if (current != -1)
  140. {
  141. const HistoryEntry *ent = GetHistoryEntry(current);
  142. if (ent && ent->GetPath() == path)
  143. return false;
  144. TruncateAfter(current);
  145. }
  146. const size_t lastIndex = hist.size() +1;
  147. hist.push_back(HistoryEntry(lastIndex, path));
  148. prev = current;
  149. current = lastIndex;
  150. return true;
  151. }
  152. bool HistoryRW::Flush()
  153. {
  154. if (hist.empty())
  155. return false;
  156. hist.clear();
  157. current = prev = -1;
  158. return true;
  159. }
  160. bool History::IsPrevious(const HistoryEntry &e) const
  161. { return prev != -1 && prev == e.GetIndex(); }
  162. bool History::IsCurrent(const HistoryEntry &e) const
  163. { return current != -1 && current == e.GetIndex(); }
  164. const HistoryEntry *History::GetNextWorkingDirectory(const AppContext &app) const
  165. {
  166. const string dest = app.GetArgs().pushArg;
  167. if (dest == "-")
  168. {
  169. const char *buf = nullptr;
  170. if (prev != -1)
  171. {
  172. const HistoryEntry *e = GetHistoryEntry(prev);
  173. if (e)
  174. return new HistoryEntry(*e);
  175. }
  176. if (buf = getenv("OLDPWD"))
  177. return new HistoryEntry(hist.size() +1, buf);
  178. else
  179. return nullptr;
  180. }
  181. else if (dest[0] == '-' || dest[0] == '+')
  182. {
  183. stringstream eventId(dest.c_str() +1);
  184. long eventIdLong = 0;
  185. eventId >> eventIdLong;
  186. eventIdLong = (current > -1 ? current : 0) +(eventIdLong * (dest[0] == '-' ? -1 : 1));
  187. const HistoryEntry *ent = GetHistoryEntry(eventIdLong);
  188. return ent ? new HistoryEntry(*ent) : nullptr;
  189. }
  190. const string absDest = RelativePathToAbsolute(dest);
  191. return new HistoryEntry(hist.size() +1, absDest);
  192. }