| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #include <algorithm>
- #include <fstream>
- #include <sstream>
- #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<HistoryEntry> &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);
- }
|