# 機能設計書 85-エディタ

## 概要

本ドキュメントは、FreeBSDにおけるテキストエディタ群（ed、ee、vi）の機能設計を記述する。これらはベースシステムに含まれるテキスト編集ユーティリティであり、行指向エディタ（ed）、初心者向けスクリーンエディタ（ee）、高機能スクリーンエディタ（vi/ex）を提供する。

### 本機能の処理概要

**業務上の目的・背景**：テキストエディタはシステム管理・ソフトウェア開発において設定ファイルやソースコードの編集に不可欠なツールである。edはPOSIX標準の行指向エディタとしてスクリプトからの自動編集やリモートセッションでの利用に適し、viは最も広く使われるUNIXスクリーンエディタ、eeは初心者向けの簡易エディタとして位置づけられる。

**機能の利用シーン**：設定ファイルの編集（vi/ee）、スクリプトによる自動テキスト編集（ed）、緊急時のシステム復旧でのファイル修正（ed：端末機能が制限された環境）、ソースコード編集（vi）。

**主要な処理内容**：
1. ed: POSIX標準行指向エディタ。正規表現検索・置換、カットバッファ、undo、アドレス指定による行操作。Kernighan-Plauger「Software Tools in Pascal」のアルゴリズムに基づく実装
2. ee: Easy Editor。メニューバー付きの簡易スクリーンエディタ。curses/termcapベースの画面制御
3. vi: nvi (new vi)。BSDライセンスのvi/exエディタ実装。コマンドモード/挿入モード/exモードの3モード操作、複数バッファ、マクロ、タグジャンプ

**関連システム・外部連携**：termcap/terminfo（端末制御）、正規表現ライブラリ（regex）、ctags（viのタグジャンプ）。

**権限による制御**：一般ユーザで実行可能。編集対象ファイルの書き込み権限が必要。

## 関連画面

該当なし（CLIベースのテキストエディタ）

## 機能種別

テキスト編集処理

## 入力仕様

### 入力パラメータ

#### ed

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -s | flag | No | 診断メッセージ抑制 | - |
| -p string | string | No | プロンプト文字列 | - |
| file | string | No | 編集対象ファイル | - |

#### vi

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -R | flag | No | 読み取り専用モード | - |
| -r file | string | No | リカバリモード | 存在するリカバリファイル |
| -t tag | string | No | タグジャンプ先 | ctagsファイルに定義されたタグ |
| -c command | string | No | 起動時実行exコマンド | 有効なexコマンド |
| file | string | No | 編集対象ファイル | - |

### 入力データソース

編集対象ファイル、標準入力（edのコマンド入力）、端末入力。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 編集済みファイル | file | 編集内容が反映されたテキストファイル |
| 画面出力 | terminal | スクリーンエディタの表示内容 |
| 標準出力（ed） | string | edの出力（行内容、バイト数等） |

### 出力先

ファイルシステム上のファイル、端末画面。

## 処理フロー

### 処理シーケンス（ed）

```
1. 初期化
   └─ シグナルハンドラ設定、setjmpによるエラー回復ポイント設定
2. ファイル読み込み（指定時）
   └─ 編集バッファにファイル内容をロード
3. コマンドループ
   └─ 1行ずつコマンド読み取り → アドレス解析 → コマンド実行
4. コマンド処理
   ├─ a: 追加、c: 変更、d: 削除、i: 挿入
   ├─ s: 正規表現置換、g: グローバルコマンド
   ├─ r: ファイル読込、w: ファイル書込
   └─ u: アンドゥ、q: 終了
5. 終了処理
   └─ 未保存変更の確認、リソース解放
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[初期化・シグナル設定]
    B --> C{ファイル指定?}
    C -->|Yes| D[ファイル読込]
    C -->|No| E[コマンドループ]
    D --> E
    E --> F[コマンド入力読取]
    F --> G[アドレス解析]
    G --> H[コマンド実行]
    H --> I{qコマンド?}
    I -->|No| E
    I -->|Yes| J{未保存変更?}
    J -->|Yes| K[警告表示]
    J -->|No| L[終了]
    K --> E
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-85-01 | edバッファ管理 | Rodney Ruddockのバッファリングアルゴリズムに基づく一時ファイル使用 | edの内部バッファ管理 |
| BR-85-02 | vi 3モード | コマンドモード/挿入モード/exモードの3モード切替 | vi操作時 |
| BR-85-03 | ed未保存警告 | q実行時に未保存変更があれば1回目は警告、2回目で終了 | edのqコマンド |
| BR-85-04 | viリカバリ | クラッシュ時にスワップファイルからセッション回復可能 | vi -rオプション |
| BR-85-05 | argv[0]切替 | vi/ex/viewはargv[0]により動作モードが変わる | nviバイナリ起動時 |

### 計算ロジック

edのアドレス計算: 「.」（現在行）、「$」（最終行）、「/pattern/」（正規表現検索）、「+/-n」（相対行）、「n,m」（範囲指定）の組み合わせで対象行を決定する。

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | ファイルアクセスエラー | 書込権限なし | エラーメッセージ表示 |
| - | 不正コマンド（ed） | 認識できないedコマンド | "?"表示（-vで詳細） |
| - | 正規表現エラー | 不正な正規表現パターン | エラーメッセージ表示 |

### リトライ仕様

リトライは行わない。edはsetjmpによりエラーからコマンドループに復帰する。

## トランザクション仕様

edは一時バッファファイルを使用し、wコマンド実行時に元ファイルを更新する。viはスワップファイルを使用してクラッシュリカバリを実現する。

## パフォーマンス要件

- edは大規模ファイルに対して一時ファイルベースのバッファリングにより、メモリ制約下でも動作可能
- viのnvi実装は効率的な画面更新アルゴリズムにより、低帯域端末でも快適に動作

## セキュリティ考慮事項

- edの!コマンドおよびviの:!コマンドでシェルコマンド実行が可能（信頼できない入力に注意）
- viのスワップファイルに編集中の機密データが含まれる可能性

## 備考

- edはAndrew Moore実装（1993年）、Kernighan-Plaugerアルゴリズムベース
- viはnvi (new vi) - Keith Bostic による BSD ライセンス再実装
- eeはFreeBSD独自の簡易エディタ。usr.bin/ee/にNLS（National Language Support）対応
- vi/exのソースはusr.bin/vi/配下にex/vi共通コードとして管理

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する（ed）

edの内部データ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ed.h | `bin/ed/ed.h` | 行バッファ管理構造体、undoバッファ、グローバル変数定義 |

**読解のコツ**: edはsetjmp/longjmpを使ったエラー回復パターンを多用する。`env`変数（main.c:54-57行目）がエラー回復ポイント。

#### Step 2: エントリーポイントを理解する（ed）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | main.c | `bin/ed/main.c` | main()関数。コマンドループ、コマンドディスパッチ |

**主要処理フロー**:
1. **53-57行目**: sigjmp_buf env（エラー回復ポイント）
2. **59-60行目**: stdinbuf[1]（標準入力バッファ）

#### Step 3: 各処理モジュール（ed）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | buf.c | `bin/ed/buf.c` | 一時ファイルベースのバッファ管理 |
| 3-2 | io.c | `bin/ed/io.c` | ファイル読み書き |
| 3-3 | re.c | `bin/ed/re.c` | 正規表現検索・置換 |
| 3-4 | sub.c | `bin/ed/sub.c` | 置換処理 |
| 3-5 | glbl.c | `bin/ed/glbl.c` | グローバルコマンド(g/G) |
| 3-6 | undo.c | `bin/ed/undo.c` | アンドゥ処理 |

#### Step 4: vi/ex の構造

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | config.h | `usr.bin/vi/config.h` | nviのビルド設定 |
| 4-2 | ex_def.h | `usr.bin/vi/ex_def.h` | exコマンド定義 |
| 4-3 | options_def.h | `usr.bin/vi/options_def.h` | viオプション定義 |

**読解のコツ**: nviはex/vi/common の3層構造。exディレクトリにexモード処理、vi_extern.hにviモードの外部関数宣言。

### プログラム呼び出し階層図

```
ed main()
    |
    +-- sigaction()             # シグナルハンドラ設定
    +-- setjmp(env)             # エラー回復ポイント
    |
    +-- [コマンドループ]
    |       +-- get_tty_line()  # コマンド入力
    |       +-- extract_addr()  # アドレス解析
    |       +-- exec_command()  # コマンド実行
    |           +-- buf.c       # バッファ操作
    |           +-- io.c        # ファイルI/O
    |           +-- re.c        # 正規表現
    |           +-- sub.c       # 置換
    |           +-- glbl.c      # グローバルコマンド
    |           +-- undo.c      # アンドゥ

vi (nvi)
    |
    +-- main() -> editor()
    +-- [コマンドモード]
    |       +-- vi キーバインド処理
    +-- [挿入モード]
    |       +-- テキスト入力処理
    +-- [exモード]
            +-- ex コマンド解析・実行
```

### データフロー図

```
[入力]                    [処理]                        [出力]

端末入力 ──> ed: コマンド解析 ──> 編集バッファ ──> ファイル書込
             アドレス計算
             正規表現マッチ

端末入力 ──> vi: モード切替 ──> 画面バッファ ──> 端末出力/ファイル書込
             キーバインド処理    スワップファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| main.c | `bin/ed/main.c` | ソース | edメインプログラム・コマンドループ |
| ed.h | `bin/ed/ed.h` | ヘッダ | edデータ構造・定数定義 |
| buf.c | `bin/ed/buf.c` | ソース | バッファ管理（一時ファイル） |
| io.c | `bin/ed/io.c` | ソース | ファイルI/O |
| re.c | `bin/ed/re.c` | ソース | 正規表現処理 |
| sub.c | `bin/ed/sub.c` | ソース | 置換処理 |
| glbl.c | `bin/ed/glbl.c` | ソース | グローバルコマンド |
| undo.c | `bin/ed/undo.c` | ソース | アンドゥ処理 |
| config.h | `usr.bin/vi/config.h` | ヘッダ | nviビルド設定 |
| ex_def.h | `usr.bin/vi/ex_def.h` | ヘッダ | exコマンド定義 |
| vi_extern.h | `usr.bin/vi/vi_extern.h` | ヘッダ | viモード外部関数宣言 |
| ex_extern.h | `usr.bin/vi/ex_extern.h` | ヘッダ | exモード外部関数宣言 |
| common_extern.h | `usr.bin/vi/common_extern.h` | ヘッダ | 共通外部関数宣言 |
| pathnames.h | `usr.bin/vi/pathnames.h` | ヘッダ | パス定義 |
| options_def.h | `usr.bin/vi/options_def.h` | ヘッダ | viオプション定義 |
| nls/ | `usr.bin/ee/nls/` | リソース | ee多言語対応メッセージ |
