Binary editor like vI 'bi'

　biは、viにユーザーインターフェースを似せて作ったバイナリエディタです。僕が1991年12月にASCII-netにMS-DOS用として載せたのが始まりでした。あれから33年経っています。viにユーザーインターフェースを似せて作られたバイナリエディタは、他に、1996年、linux用にbviというものがGerhard Buergmann氏によって発表されましたが、僕の方が早かった。biの最初のバージョンはCによって作られましたが、現在リリースのバージョンは、pythonで書かれています。
ANSIターミナルのエスケープシーケンスを使っているので、ANSIターミナル用です。pythonが動作する、ANSIターミナルのlinux、unix、FreeBSDやPOSIX準拠のOSで動作すると思います。開発環境、動作検証はArchLinuxとFreeBSDでしました。Archlinuxの場合はシバンは#!/usr/bin/pythonで、FreeBSDの場合は、#!/usr/local/bin/python3にしてください。

 
```text:bi.doc

vi風バイナリエディタ 'bi'

デザイン・開発：Taisuke Maekawa (fygar256)

概要
--------

BIは、UNIXエディタ 'vi' のインターフェースを模倣して設計されたバイナリエディタです。
名前 (BI) は、Binary editor like vI の略称です。viとバイナリ愛好家向けです。

コマンドリファレンス

編集モードのコマンド

<16進キー> ----- データ設定
hjkl または矢印キー ----- カーソル移動
^F ^B ----- 1ページ移動 (256バイト)
^D ^U ----- 半ページ移動 (128バイト)
^L ----- 画面再描画
^Y ----- utf8エンコードのトグル
^ ----- 行の左端へジャンプ
$ ----- 行の右端へジャンプ
m[a-z] ----- 現在位置をマーク
'[a-z] ----- マークされたポイントへジャンプ

n ----- 次の位置を検索
N ----- 最後の位置を検索
M ----- マークを表示

p ----- ヤンクバッファを貼り付け（上書き）
P ----- ヤンクバッファを貼り付け（挿入）
q ----- 終了
x ----- 1バイト削除
Z ----- 書き込み終了

/ ----- コマンドライン検索モードへ
: ----- コマンドラインモードへ

コマンドラインモードの場合

# ----- コメント。'#' の後は無視されます
/<regexp> ----- 正規表現文字列を検索
//xx xx xx ... ----- バイナリデータを検索
!<string> ----- シェルを起動
@<string> ----- python exec()を呼び出す
?<value> ----- 値を10進、16進、8進、ASCII、2進で表示
q ----- 終了
q! ----- 終了を上書き
wq,wq! ----- 書き込み終了
w ----- ファイルに書き込み
w <filename> ----- ファイル<filename>に書き込み
r ----- 元ファイルを読み込む
t <ファイル名> ----- ファイル名を指定してサイレントモードでスクリプトを実行
T <ファイル名> ----- ファイル名を指定して冗長モードでスクリプトを実行
n ----- 次の文字列を検索
N ----- 最後の文字列を検索
[offset] ----- アドレスへジャンプ
[offset]m[a-z] ----- 位置をマーク
[offset]o<文字列> ----- [オフセット] 以降の文字列を上書き
[offset]O<文字列> ----- [オフセット] の位置に文字列を挿入
[offset]R<ファイル名> ----- ファイルを読み込み [オフセット] の位置に挿入
[offset]r<ファイル名> ----- [オフセット] 以降のファイルを読み込み（上書き）
[offset] p ----- ヤンクバッファを貼り付け（上書き）
[offset] P ----- ヤンクバッファを貼り付け（挿入）
[offset]I xx xx xx ... [*<length>] ----- データを length 回繰り返し挿入
[offset]i xx xx xx ... [*<length>] ----- データを length 回繰り返しオーバーライト.

y/str ----- ヤンクバッファに文字列をヤンク
y//xx xx xx ... ----- ヤンクバッファにデータをヤンク
<start>,<end> d ----- 範囲指定で削除（データはヤンクされます）
<start>,<end> C <dest> ----- <dest>にデータを挿入 (データはヤンクされます)
<start>,<end> c <dest> ----- データをコピー（データはヤンクされます）
[start,end] s /regexp/str ----- 正規表現をstrで置換
[start,end] s /regexp//xx xx xx ... ----- 正規表現をデータで置換
[start,end] s //xx xx xx .../str ----- data1 を str に置換
[start,end] s //xx xx xx ...//xx xx xx ... ----- data1 を data2 に置換
[start],[end] y ----- ヤンクバッファにヤンク
<start>,<end> f xx xx xx ... - データで埋める（範囲指定）
[start,end]|<data> ----- データとのビット単位論理和
[start,end]&<data> ----- データとのビット単位論理積
[start,end]^<data> ----- データとのビット単位排他的論理和
[start,end]~ ----- ビット単位NOT
[start,end]<[[times],[01]] - ビット0,1で左シフト、またはバイト単位回転
[start,end]>[[times],[01]] - ビット0,1で右シフト、またはバイト単位回転
[start,end]<<[[times],[01]] - ビット0,1で左シフト、またはマルチバイト単位回転
[start,end]>>[[times],[01]] - ビット0,1で右シフト、またはマルチバイト単位回転
[start,end] v <dest> ----- データを移動
<start>,<end>w<filename> ---- ファイルにデータを書き込む
<CR> (コマンドなし) または <ESC> ----- 画面モードに戻る

備考

正規表現は文字列検索に使用できます。
正規表現では、'/' をエスケープ文字 '\' でエスケープできます。

コマンド内にコメントを記述するには '#' を使用します。セミコロンを含むコマンドは、
エスケープ文字 '\' を使って記述する必要があります。

上記のコマンドで現在位置を省略値とする場合は、`[]` で囲まれた値は省略できます。
's'コマンドは例外で、<start>,<end>を省略すると、ファイル全体に作用します。

値 <end> は、'*<length>' を使って、<end>=<start>+<length>-1 のように渡すことができます。

コマンドラインでは、次のように単純な式で値を指定する必要があります。

<expression> := <factor> | <factor> [+|-] <factor>

factor は、16 進数または 先頭に '%' が付いた 10 進数の数値です。
また、マーク位置として '[a-z]、ファイルの先頭として 0 を指定して値を
指定することもできます。 .を現在の位置、$ をファイルの末尾として扱います。
Pythonのeval()式も'{}'で括って値として渡すことができます。
例えば、{0xff^0x55}のようにです。
'{}'の中で、ファイルの内容の1バイトは、mem[x]で取得することができます。xには、cpとして、カレントポジションを指定することができます。

v コマンドには少し癖があります。<start> から <end> までのデータを削除し、<dest> に移動します。
ただし、dest==filesize の場合は、削除されたデータはデータの末尾 + 1 に移動され、dest>filesize
の場合は、ファイルの末尾 + 1 から dest までを 0 で埋め、削除されたデータを dest から書き込みます。

^Lは、utf-8のマルチバイトを扱う境界を0から3の間でスイッチします。
もし、utf-8のマルチバイト文字が正しく表示されなかったら、数回^Lを押して下さい

^Yは、utf-8のエンコードを禁止、または許可のトグルをします。もし、utf-8の
エンコードで画面が乱れるときは、禁止することができます。初期値は禁止です。

スクリプト機能

bi にはスクリプト機能があります。
bi スクリプトの名前は 'file.bi' です。スクリプトファイルの指定のコマンドライン構文は、'bi [-v] -s file.bi targetfile' のようになります。

Python exec()
    Pythonのexec()はチューリング完全なので、全ての処理が'@'
    コマンドで書けます。
    例：0~255の値を持つ1024バイトは次のようにして生成できます。

    @for i in range(1024):\n    setmem(i,i%256) # 0~255 4回繰り返し

    importをすると、そのモジュールは、biのグローバル空間に置かれます。

高速化

biを高速化する必要があったら、pyinstallerというpythonコンパイラでコンパイルすることができます。pyinstaller --onefile bi.py

★注意

undo コマンドはまだサポートされていません。

危険

'@'コマンドで、無闇にbiのグローバル変数を書き換えると、システムがエラーを
起こし、予期せぬ動作をすることがあります。biのグローバル変数をいじるときは
十分注意して下さい

------ 履歴 -----
1991-12-4 ハードディスクのバックアップに使っていたフロッピーディスクのセクタが失われました。
1991-12-5 仕方なく DUMP と C プログラムを使ってファイルを修復しました。
1991-12-6 ファイルエディタの作成を開始しました。これが「急いで」という意味です。
1991-12-7 コーディング。
1991-12-8 コーディング。
1991-12-9 とりあえず完成。
1991-12-10 ディスクがいっぱいになった場合のエラーチェックを追加しました。
1991-12-20? ASCII-pcs junk.test に投稿しましたが、メンテナンスによりすぐに削除されました。
1992-01-18 q、q!、wq を区別しました。bi に名前を変更しました。
1992-01-23 ドキュメントを書き直しました (バージョン 0.9999)
1992-02-05 wq のバグを修正しました (バージョン 0.99992)
1992-02-10 メモリ割り当てエラーのバグを修正しました (バージョン 0.99998)
^D、^U コマンドを追加しました
--- Linux 版は以下の通りです。
2025-03-29 バージョン 1.98
2025-03-30 バージョン 1.989 デバッグ情報、x コマンド、M コマンド、' コマンド、m コマンドを追加しました。
2025-03-31 バージョン 1.9893 コマンドラインコマンドを追加しました。!、w、q、wq、wq!、w<file> コマンドを追加しました。
2025-04-01 バージョン 1.98951 y、d、p、P コマンド追加
2025-04-02 バージョン 1.98953 r、R コマンド追加
2025-04-02 バージョン 1.98955 i、f コマンド追加
2025-04-02 バージョン 1.9896 c、m コマンド追加
2025-04-03 バージョン 1.9897 s、S、w コマンド追加
2025-04-03 バージョン 1.9899 /、?、N、n コマンド追加
2025-04-03 Linux 版がほぼ完成しました。
2025-04-04 バグ修正完了。バージョン 2.0
2025-04-11 バージョン 2.1 若干の調整。
2025-04-12 バージョン 2.2 正規表現をサポートしました。
2025-04-12 バージョン 2.3 u コマンドを追加しました。
2025-04-12 バージョン 2.4 統一表記のため '?' を '//' に変更しました。
2025-04-13 バージョン 2.5 a コマンドを追加しました。
2025-04-13 バージョン 2.5.5 統一表記のため 'u' を 'y' に変更しました。
2025-04-13 バージョン 2.5.7 シェル呼び出しのバグを修正しました。
2025-04-13 バージョン 2.6.0 &,^,|,~ コマンドを追加しました。開始パラメータと終了パラメータを取得するための調整を行いました。
2025-04-13 バージョン 2.6.9 将来のスクリプト表記と検索コマンドの調整のため 'm' を 'v' に変更しました。
2025-04-14 バージョン 2.7.0 スクリプト機能を追加しました。
2025-04-14 バージョン 2.7.3 若干の調整
2025-04-14 バージョン 2.8.0 簡単な式機能の追加と若干の調整
2025-04-14 バージョン 2.8.3 コマンドラインパラメータで <end> 値を渡す際に '%' プレフィックスを追加し、若干の調整
2025-04-14 バージョン 2.8.5 rotate コマンドと shift コマンドを追加しました。
2025-04-15 バージョン 2.9.1 マルチバイトシフトと回転のバグを修正
2025-04-15 バージョン 2.9.5 コメントのバグを修正
2025-04-15 バージョン 2.9.6 若干の調整と 'o' コマンドを追加しました。
2025-04-15 バージョン 2.9.7 若干の調整と 'O' コマンドを追加しました。
2025-04-16 バージョン 3.0.0 ファイル書き込みフラグ（lastchange、modified）のバグ修正
2025-04-19 バージョン 3.0.1 コマンドラインパーシングのバグを修正、若干の調整。
2025-04-19 バージョン 3.0.2 iコマンドのバグ修正。
2025-04-20 バージョン 3.0.3 write file時のパーミッションチェックを付ける
2025-04-20 バージョン 3.0.4 viに準じるためにコマンド名変更、若干の調整
2025-04-20 バージョン 3.0.5 バグ修正
2025-04-21 バージョン 3.0.6 正規表現バグ修正
2025-04-21 バージョン 3.0.8 正規表現検索高速化
2025-04-23 バージョン 3.0.9 'd'コマンドバグ修正
2025-04-24 バージョン 3.1.0 データを16,2,8,10進、ASCII-CODEで表示する機能を付ける
2025-04-24 バージョン 3.2.0 日本語用に3バイトまでのutf-8のマルチバイトを扱えるようにする
2025-04-26 バージョン 3.3.0 メモリオーバーフローのエラーチェックを付ける
2025-04-26 バージョン 3.3.1 メッセージ出力を標準とエラー出力に分ける
2025-04-26 バージョン 3.4.0 pythonのeval()式を'{}'で括って値として渡せるようにする
2025-04-26 バージョン 3.4.1 (eval()式などを)10進、16進、8進、ASCII、2進で表示する機能を付ける
2025-05-01 バージョン 3.4.3 '{}'の中で、mem[x](編集しているファイルの1バイト)と、cp(カレントポジション)を指定することができるようにする。'@'コマンド追加。
2025-05-04 バージョン 3.4.3.5 pythonとの記法統一のため調整。
2025-05-04 バージョン 3.4.4 utf8フルサポート。
2025-05-09 バージョン 3.4.4.7 stable.
--------------------

このプログラムを適用した結果については一切責任を負いません。

```
### コード 'bi.py'

https://gist.github.com/fygar256/779bf834f8a18d6df58de042dd8a0097

### GitHub リポジトリ

https://github.com/fygar256/bi/

### インストール&実行

```
#### installation (others)
git clone https://github/fygar256/bi/
cd bi
chmod +x bi.py
sudo cp bi.py /usr/bin/bi

sudo cp bi.1.gz /usr/share/man/man1/
sudo mandb

#### execution
bi file
```

##### デバッグ協力

パシフィックソフトウェア開発（株）

##### スクリーンショット

![screenshot-2025-04-17 17-57-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315399/3a7366ac-d3d2-4207-a52d-cf2137cbf416.png)

##### マスコットキャラクター

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315399/2a1a8ae2-1671-4ba6-bc30-5758e93861eb.png" width="300">