diff --git a/CHANGELOG.md b/CHANGELOG.md index a801bfc..b59bc9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## 1.2.0 (2026年05月03日) * Debianでコンパイル出来る様に * マウス対応の追加 +* ファイルなしでも開ける様に +* `:o`コマンドの追加 ## 1.1.0 (2025年12月28日) * PgUp・PgDownで使ってページを動ける様に diff --git a/main.cc b/main.cc index 4e81459..d1645b9 100644 --- a/main.cc +++ b/main.cc @@ -39,13 +39,13 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "src/hexeditor.hh" int main(int argc, char *argv[]) { - if (argc != 2) { - std::cerr << "usage: hexagon \n"; - return 1; - } + std:: string filename; + + if (argc > 1) filename = argv[1]; + else filename = ""; try { - HexEditor editor(argv[1]); + HexEditor editor(filename); editor.run(); } catch (const std::exception &e) { std::cerr << "エラー: " << e.what() << "\n"; diff --git a/src/hexeditor.cc b/src/hexeditor.cc index 44fc427..305d51f 100644 --- a/src/hexeditor.cc +++ b/src/hexeditor.cc @@ -80,7 +80,7 @@ const std::vector HexEditor::signatures = { HexEditor::HexEditor(const std::string &filename) : curPos(0), dpOffset(0), bpr(16), statusMode(Status_Normal), modified(false), - running(true), + running(true), hasFile(!filename.empty()), lastSearchDir(Direction_Forward), headerLen(0), headerType("") { // SIGINT (CTRL + C)を無効に @@ -123,39 +123,46 @@ HexEditor::HexEditor(const std::string &filename) refresh(); // ファイルをバッファーに読み込む - std::ifstream file(filename, std::ios::binary); - if (!file) { - endwin(); - throw std::runtime_error("ファイルを開くに失敗"); - } + if (hasFile) { + std::ifstream file(filename, std::ios::binary); + if (!file) { + endwin(); + throw std::runtime_error("ファイルを開くに失敗"); + } - buf.assign((std::istreambuf_iterator(file)), {}); - file.close(); + buf.assign((std::istreambuf_iterator(file)), {}); + file.close(); - if (buf.empty()) { - endwin(); - throw std::runtime_error("ファイルが空です"); - } + if (buf.empty()) { + endwin(); + throw std::runtime_error("ファイルが空です"); + } - fname = filename; + fname = filename; + hasFile = true; - // ファイルヘッダー - for (const auto &sig : signatures) { - if (buf.size() >= sig.signature.size()) { - bool match = true; - for (size_t i = 0; i < sig.signature.size(); ++i) { - if (buf[i] != sig.signature[i]) { - match = false; + // ファイルヘッダー + for (const auto &sig : signatures) { + if (buf.size() >= sig.signature.size()) { + bool match = true; + for (size_t i = 0; i < sig.signature.size(); ++i) { + if (buf[i] != sig.signature[i]) { + match = false; + break; + } + } + + if (match) { + headerLen = sig.signature.size(); + headerType = sig.type; break; } } - - if (match) { - headerLen = sig.signature.size(); - headerType = sig.type; - break; - } } + } else { + fname = "[No File]"; + buf.clear(); + hasFile = false; } // ウィンドウを作成する @@ -516,9 +523,13 @@ void HexEditor::handleCommand() { } else if (statusText == "noh") { lastSearch = ""; isCommand = true; + } else if (statusText.rfind("o ", 0) == 0 || statusText.rfind("open ", 0) == 0) { + std::string path = statusText.substr(statusText.find(' ') + 1); + handleOpen(path); + isCommand = true; } else { statusMode = Status_Error; - statusText.clear(); + statusText = "不正なコマンド。"; } if (isCommand) { @@ -538,6 +549,67 @@ void HexEditor::handleQuit(bool force) { } } +void HexEditor::handleOpen(const std::string &path) { + if (path.empty()) { + statusMode = Status_Error; + statusText = "利用方法: :o "; + render(); + return; + } + + std::ifstream file(path, std::ios::binary); + if (!file) { + statusMode = Status_Error; + statusText = "ファイルを開くに失敗: " + path; + render(); + return; + } + + std::vector newbuf((std::istreambuf_iterator(file)), {}); + file.close(); + + if (newbuf.empty()) { + statusMode = Status_Error; + statusText = "ファイルは空です。"; + render(); + return; + } + + buf = std::move(newbuf); + fname = path; + hasFile = true; + curPos = 0; + dpOffset = 0; + modified = false; + undoStack.clear(); + redoStack.clear(); + lastSearch.clear(); + lastHexSearch.clear(); + headerLen = 0; + headerType = ""; + + for (const auto &sig : signatures) { + if (buf.size() >= sig.signature.size()) { + bool match = true; + for (size_t i = 0; i < sig.signature.size(); ++i) { + if (buf[i] != sig.signature[i]) { + match = false; + break; + } + } + if (match) { + headerLen = sig.signature.size(); + headerType = sig.type; + break; + } + } + } + + statusMode = Status_Normal; + statusText = path + " を開きました。"; + render(); +} + void HexEditor::handleSave() { std::ofstream file(fname, std::ios::binary); if (file) { @@ -862,6 +934,14 @@ void HexEditor::input() { if (statusMode != Status_Normal && statusMode != Status_Error) continue; ch = getch(); + + if (!hasFile && ch != ':' && ch != 'Z') { + statusMode = Status_Error; + statusText = "ファイルを読み込んでいません。「:o 」を御利用下さい。"; + render(); + return; + } + if ((ch == 'j' || ch == KEY_DOWN) && curPos + bpr < buf.size()) { curPos += bpr; // 下 if (statusMode == Status_Error) statusMode = Status_Normal; diff --git a/src/hexeditor.hh b/src/hexeditor.hh index b09e254..75fb1f8 100644 --- a/src/hexeditor.hh +++ b/src/hexeditor.hh @@ -79,6 +79,7 @@ class HexEditor { bool running; std::string lastSearch; bool isMouse = false; + bool hasFile = false; WINDOW *hexPanel; WINDOW *asciiPanel; @@ -102,6 +103,7 @@ class HexEditor { void topbar(); void statusbar(); void handleCommand(); + void handleOpen(const std::string &path); void handleSave(); void handleQuit(bool force); void handleSearch();