#include #include #include #include #include #include #include "history.hpp" #include "appContext.hpp" using namespace std; using namespace knacki::cd; static std::string RelativePathToAbsolute(const string &path) { if (path[0] == '/') return path; char *p = realpath(path.c_str(), nullptr); // FIXME error check string pathResult(p); free(p); return pathResult; } HistoryEntry::HistoryEntry(PTR_TYPE i, const string &e): path(e), index(i) {} HistoryEntry::HistoryEntry(const HistoryEntry &o): path(o.path), index(o.index) {} HistoryEntry &HistoryEntry::operator=(const HistoryEntry &o) { path = o.path; index = o.index; return *this; } const std::string &HistoryEntry::GetPath() const { return path; } PTR_TYPE HistoryEntry::GetIndex() const { return index; } History::History(const string &path): current(-1), prev(-1) { std::ifstream file(path, fstream::in | fstream::binary); Read(file); } HistoryRW::HistoryRW(const string &_path): History(_path), path(_path) {} const std::vector &History::GetEntries() const { return hist; } const HistoryEntry *History::GetHistoryEntry(PTR_TYPE index) const { for (const HistoryEntry &i: GetEntries()) if (i.GetIndex() == index) return &i; return nullptr; } void History::Read(std::istream &file) { PTR_TYPE current = -1; PTR_TYPE prev = -1; unsigned int histIndex =0; std::streamsize size; char *buf = nullptr; std::streamsize bufSize = 0; hist.clear(); if (!file.good() && errno != ENOENT) throw IOError(strerror(errno)); file.seekg(0); if (sizeof(prev) != file.readsome((char *)(&prev), sizeof(prev))) return; if (sizeof(current) != file.readsome((char *)(¤t), sizeof(current))) return; while (file.good()) { if (sizeof(size) != file.readsome((char*)(&size), sizeof(size))) break; if (size > bufSize) { delete[] buf; buf = new char[size](); bufSize = size; } if (size != file.readsome(buf, size)) break; const size_t lastIndex = ++histIndex; hist.push_back(HistoryEntry(lastIndex, string(buf, size))); if (current != -1) if (!--current) this->current = lastIndex; if (prev != -1) if (!--prev) this->prev = lastIndex; } delete []buf; if (this->current == -1) this->current = hist.back().GetIndex(); } void HistoryRW::Write() { size_t written = 0; std::ofstream file(path, fstream::in | fstream::out | fstream::binary | fstream::trunc); if (!file.good()) throw IOError(strerror(errno)); file.write((char*)(&prev), sizeof(prev)); file.write((char*)(¤t), sizeof(current)); for (HistoryEntry i: hist) { const size_t pathLen = i.GetPath().length(); file.write((char*)(&pathLen), sizeof(pathLen)); written += sizeof(pathLen); file.write(i.GetPath().c_str(), sizeof(*(i.GetPath().c_str())) * i.GetPath().size()); written += sizeof(*(i.GetPath().c_str())) * i.GetPath().size(); } } bool HistoryRW::AppendCwd() { char *cwd = get_current_dir_name(); const bool result = Append(cwd); free(cwd); return result; } bool HistoryRW::Append(const HistoryEntry &ent) { const HistoryEntry *e = GetHistoryEntry(ent.GetIndex()); if (e) { // Juste move ptr if (current != e->GetIndex()) { prev = current; current = e->GetIndex(); return true; } else return false; } return Append(ent.GetPath()); } void HistoryRW::TruncateAfter(PTR_TYPE pos) { while (!hist.empty() && hist.back().GetIndex() > pos) hist.pop_back(); } bool HistoryRW::Append(const std::string &path) { if (current != -1) { const HistoryEntry *ent = GetHistoryEntry(current); if (ent && ent->GetPath() == path) return false; TruncateAfter(current); } const size_t lastIndex = hist.size() +1; hist.push_back(HistoryEntry(lastIndex, path)); prev = current; current = lastIndex; return true; } bool HistoryRW::Flush() { if (hist.empty()) return false; hist.clear(); current = prev = -1; return true; } bool History::IsPrevious(const HistoryEntry &e) const { return prev != -1 && prev == e.GetIndex(); } bool History::IsCurrent(const HistoryEntry &e) const { return current != -1 && current == e.GetIndex(); } const HistoryEntry *History::GetNextWorkingDirectory(const AppContext &app) const { const string dest = app.GetArgs().pushArg; if (dest == "-") { const char *buf = nullptr; if (prev != -1) { const HistoryEntry *e = GetHistoryEntry(prev); if (e) return new HistoryEntry(*e); } if ((buf = getenv("OLDPWD"))) return new HistoryEntry(hist.size() +1, buf); else return nullptr; } else if (dest[0] == '-' || dest[0] == '+') { stringstream eventId(dest.c_str() +1); long eventIdLong = 0; eventId >> eventIdLong; eventIdLong = (current > -1 ? current : 0) +(eventIdLong * (dest[0] == '-' ? -1 : 1)); const HistoryEntry *ent = GetHistoryEntry(eventIdLong); return ent ? new HistoryEntry(*ent) : nullptr; } const string absDest = RelativePathToAbsolute(dest); return new HistoryEntry(hist.size() +1, absDest); }