ファイルなしでも開ける様に+:oコマンドの追加

This commit is contained in:
2026-05-03 20:08:03 +09:00
parent b510b2830f
commit 6415199b8c
4 changed files with 116 additions and 32 deletions

View File

@@ -1,6 +1,8 @@
## 1.2.0 (2026年05月03日) ## 1.2.0 (2026年05月03日)
* Debianでコンパイル出来る様に * Debianでコンパイル出来る様に
* マウス対応の追加 * マウス対応の追加
* ファイルなしでも開ける様に
* `:o`コマンドの追加
## 1.1.0 (2025年12月28日) ## 1.1.0 (2025年12月28日)
* PgUp・PgDownで使ってページを動ける様に * PgUp・PgDownで使ってページを動ける様に

10
main.cc
View File

@@ -39,13 +39,13 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "src/hexeditor.hh" #include "src/hexeditor.hh"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc != 2) { std:: string filename;
std::cerr << "usage: hexagon <filename>\n";
return 1; if (argc > 1) filename = argv[1];
} else filename = "";
try { try {
HexEditor editor(argv[1]); HexEditor editor(filename);
editor.run(); editor.run();
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << "エラー: " << e.what() << "\n"; std::cerr << "エラー: " << e.what() << "\n";

View File

@@ -80,7 +80,7 @@ const std::vector<HexEditor::FileSignature> HexEditor::signatures = {
HexEditor::HexEditor(const std::string &filename) HexEditor::HexEditor(const std::string &filename)
: curPos(0), dpOffset(0), bpr(16), : curPos(0), dpOffset(0), bpr(16),
statusMode(Status_Normal), modified(false), statusMode(Status_Normal), modified(false),
running(true), running(true), hasFile(!filename.empty()),
lastSearchDir(Direction_Forward), lastSearchDir(Direction_Forward),
headerLen(0), headerType("") { headerLen(0), headerType("") {
// SIGINT (CTRL + C)を無効に // SIGINT (CTRL + C)を無効に
@@ -123,39 +123,46 @@ HexEditor::HexEditor(const std::string &filename)
refresh(); refresh();
// ファイルをバッファーに読み込む // ファイルをバッファーに読み込む
std::ifstream file(filename, std::ios::binary); if (hasFile) {
if (!file) { std::ifstream file(filename, std::ios::binary);
endwin(); if (!file) {
throw std::runtime_error("ファイルを開くに失敗"); endwin();
} throw std::runtime_error("ファイルを開くに失敗");
}
buf.assign((std::istreambuf_iterator<char>(file)), {}); buf.assign((std::istreambuf_iterator<char>(file)), {});
file.close(); file.close();
if (buf.empty()) { if (buf.empty()) {
endwin(); endwin();
throw std::runtime_error("ファイルが空です"); throw std::runtime_error("ファイルが空です");
} }
fname = filename; fname = filename;
hasFile = true;
// ファイルヘッダー // ファイルヘッダー
for (const auto &sig : signatures) { for (const auto &sig : signatures) {
if (buf.size() >= sig.signature.size()) { if (buf.size() >= sig.signature.size()) {
bool match = true; bool match = true;
for (size_t i = 0; i < sig.signature.size(); ++i) { for (size_t i = 0; i < sig.signature.size(); ++i) {
if (buf[i] != sig.signature[i]) { if (buf[i] != sig.signature[i]) {
match = false; match = false;
break;
}
}
if (match) {
headerLen = sig.signature.size();
headerType = sig.type;
break; 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") { } else if (statusText == "noh") {
lastSearch = ""; lastSearch = "";
isCommand = true; 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 { } else {
statusMode = Status_Error; statusMode = Status_Error;
statusText.clear(); statusText = "不正なコマンド。";
} }
if (isCommand) { 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 <filename>";
render();
return;
}
std::ifstream file(path, std::ios::binary);
if (!file) {
statusMode = Status_Error;
statusText = "ファイルを開くに失敗: " + path;
render();
return;
}
std::vector<uint8_t> newbuf((std::istreambuf_iterator<char>(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() { void HexEditor::handleSave() {
std::ofstream file(fname, std::ios::binary); std::ofstream file(fname, std::ios::binary);
if (file) { if (file) {
@@ -862,6 +934,14 @@ void HexEditor::input() {
if (statusMode != Status_Normal && statusMode != Status_Error) continue; if (statusMode != Status_Normal && statusMode != Status_Error) continue;
ch = getch(); ch = getch();
if (!hasFile && ch != ':' && ch != 'Z') {
statusMode = Status_Error;
statusText = "ファイルを読み込んでいません。「:o <file>」を御利用下さい。";
render();
return;
}
if ((ch == 'j' || ch == KEY_DOWN) && curPos + bpr < buf.size()) { if ((ch == 'j' || ch == KEY_DOWN) && curPos + bpr < buf.size()) {
curPos += bpr; // 下 curPos += bpr; // 下
if (statusMode == Status_Error) statusMode = Status_Normal; if (statusMode == Status_Error) statusMode = Status_Normal;

View File

@@ -79,6 +79,7 @@ class HexEditor {
bool running; bool running;
std::string lastSearch; std::string lastSearch;
bool isMouse = false; bool isMouse = false;
bool hasFile = false;
WINDOW *hexPanel; WINDOW *hexPanel;
WINDOW *asciiPanel; WINDOW *asciiPanel;
@@ -102,6 +103,7 @@ class HexEditor {
void topbar(); void topbar();
void statusbar(); void statusbar();
void handleCommand(); void handleCommand();
void handleOpen(const std::string &path);
void handleSave(); void handleSave();
void handleQuit(bool force); void handleQuit(bool force);
void handleSearch(); void handleSearch();