history.cpp 5.5 KB

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