ChiaYen Kan / Mbed 2 deprecated Nucleo_L053R8_NTShell

Dependencies:   mbed

Revision:
0:4d2c4db9c88e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NTShell/src/ntshell.c	Thu Mar 19 06:07:58 2015 +0000
@@ -0,0 +1,689 @@
+/**
+ * @file ntshell.c
+ * @author Shinichiro Nakamura
+ * @brief 小規模組み込みシステム向けのシェルシステムの実装。
+ */
+
+/*
+ * ===============================================================
+ *  Natural Tiny Shell (NT-Shell)
+ * ===============================================================
+ * Copyright (c) 2010-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include "ntshell.h"
+#include "ntlibc.h"
+
+#define VERSION_MAJOR   0   /**< メジャー番号。 */
+#define VERSION_MINOR   2   /**< マイナー番号。 */
+#define VERSION_RELEASE 0   /**< リリース番号。 */
+
+#define INITCODE    (0x4367)    /**< 初期化確認コード。 */
+
+/**
+ * @brief 未使用変数宣言。
+ *
+ * @param N 未使用変数。
+ */
+#define UNUSED_VARIABLE(N)      do { (void)(N); } while (0)
+
+/**
+ * @brief サジェストのインデックス番号。
+ *
+ * @param HANDLE ハンドル。
+ */
+#define SUGGEST_INDEX(HANDLE)   ((HANDLE)->suggest_index)
+
+/**
+ * @brief サジェストのソース文字列。
+ *
+ * @param HANDLE ハンドル。
+ */
+#define SUGGEST_SOURCE(HANDLE)  ((HANDLE)->suggest_source)
+
+/**
+ * @brief テキストエディタを取得する。
+ *
+ * @param HANDLE ハンドル。
+ */
+#define GET_EDITOR(HANDLE)      (&((HANDLE)->editor))
+
+/**
+ * @brief テキストヒストリを取得する。
+ *
+ * @param HANDLE ハンドル。
+ */
+#define GET_HISTORY(HANDLE)     (&((HANDLE)->history))
+
+/**
+ * @brief シリアルポートから読み込む。
+ *
+ * @param HANDLE ハンドル。
+ * @param BUF 読み込みバッファ。
+ * @param CNT 読み込み文字数。
+ *
+ * @return 実際に読み込んだ文字数。
+ */
+#define SERIAL_READ(HANDLE, BUF, CNT)   ((HANDLE)->func_read(BUF, CNT, (HANDLE)->extobj))
+
+/**
+ * @brief シリアルポートへ書き込む。
+ *
+ * @param HANDLE ハンドル。
+ * @param BUF 書き込みバッファ。
+ * @param CNT 書き込み文字数。
+ *
+ * @return 実際に書き込んだ文字数。
+ */
+#define SERIAL_WRITE(HANDLE, BUF, CNT)  ((HANDLE)->func_write(BUF, CNT, (HANDLE)->extobj))
+
+/**
+ * @brief シリアルポートへプロンプトを書き込む。
+ *
+ * @param HANDLE ハンドル。
+ */
+#define PROMPT_WRITE(HANDLE)            SERIAL_WRITE((HANDLE), (HANDLE)->prompt, ntlibc_strlen((HANDLE)->prompt))
+
+/**
+ * @brief シリアルポートへ改行を書き込む。
+ *
+ * @param HANDLE ハンドル。
+ */
+#define PROMPT_NEWLINE(HANDLE)          SERIAL_WRITE((HANDLE), NTSHELL_PROMPT_NEWLINE, ntlibc_strlen(NTSHELL_PROMPT_NEWLINE))
+
+/**
+ * @brief コールバックを呼び出す。
+ *
+ * @param HANDLE ハンドル。
+ * @param TEXT コールバック関数へ渡す文字列。
+ */
+#define CALLBACK(HANDLE, TEXT)          ((HANDLE)->func_callback((TEXT), (HANDLE)->extobj))
+
+#define VTSEND_ERASE_LINE(HANDLE)       (vtsend_erase_line(&((HANDLE)->vtsend)))
+#define VTSEND_CURSOR_HEAD(HANDLE)      (vtsend_cursor_backward(&((HANDLE)->vtsend), 80))
+#define VTSEND_CURSOR_PREV(HANDLE)      (vtsend_cursor_backward(&((HANDLE)->vtsend), 1))
+#define VTSEND_CURSOR_NEXT(HANDLE)      (vtsend_cursor_forward(&((HANDLE)->vtsend), 1))
+
+/**
+ * @brief テキストヒストリで1つ後ろを辿る。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_history_prev(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    if (text_history_read_point_prev(GET_HISTORY(ntshell))) {
+        char txt[TEXTHISTORY_MAXLEN];
+        int n = text_history_read(GET_HISTORY(ntshell), &txt[0], sizeof(txt));
+        if (0 < n) {
+            VTSEND_ERASE_LINE(ntshell);
+            VTSEND_CURSOR_HEAD(ntshell);
+            PROMPT_WRITE(ntshell);
+            SERIAL_WRITE(ntshell, txt, n);
+            text_editor_set_text(GET_EDITOR(ntshell), txt);
+        }
+    }
+}
+
+/**
+ * @brief テキストヒストリで1つ前を辿る。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_history_next(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    if (text_history_read_point_next(GET_HISTORY(ntshell))) {
+        char txt[TEXTHISTORY_MAXLEN];
+        int n = text_history_read(GET_HISTORY(ntshell), &txt[0], sizeof(txt));
+        if (0 < n) {
+            VTSEND_ERASE_LINE(ntshell);
+            VTSEND_CURSOR_HEAD(ntshell);
+            PROMPT_WRITE(ntshell);
+            SERIAL_WRITE(ntshell, txt, n);
+            text_editor_set_text(GET_EDITOR(ntshell), txt);
+        }
+    }
+}
+
+/**
+ * @brief カーソルを左へ移動させる。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_cursor_left(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    if (text_editor_cursor_left(GET_EDITOR(ntshell))) {
+        VTSEND_CURSOR_PREV(ntshell);
+    }
+}
+
+/**
+ * @brief カーソルを右へ移動させる。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_cursor_right(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    if (text_editor_cursor_right(GET_EDITOR(ntshell))) {
+        VTSEND_CURSOR_NEXT(ntshell);
+    }
+}
+
+/**
+ * @brief エンターキーの処理を実行する。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_enter(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    char txt[TEXTEDITOR_MAXLEN];
+    text_editor_get_text(GET_EDITOR(ntshell), &txt[0], sizeof(txt));
+    text_editor_clear(GET_EDITOR(ntshell));
+    text_history_write(GET_HISTORY(ntshell), txt);
+    PROMPT_NEWLINE(ntshell);
+    CALLBACK(ntshell, txt);
+    PROMPT_WRITE(ntshell);
+}
+
+/**
+ * @brief キャンセルキーの処理を実行する。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * 一般的なOSのCTRL+C処理はシグナルを発行し、受信したプロセスが
+ * 中断処理を実行する。
+ * ここでのキャンセルは見た目を再現したもので、
+ * 入力中の文字列を破棄してカーソルを新しい入力に備えて復帰させるものだ。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_cancel(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    text_editor_clear(GET_EDITOR(ntshell));
+    SERIAL_WRITE(ntshell, "^C", 2);
+    PROMPT_NEWLINE(ntshell);
+    PROMPT_WRITE(ntshell);
+}
+
+/**
+ * @brief 挿入処理を実行する。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_insert(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    /*
+     * 入力があった場合、入力補完状態から抜ける。
+     */
+    SUGGEST_INDEX(ntshell) = -1;
+
+    /*
+     * テキストエディタを使って文字を文字列に挿入する。
+     */
+    if (text_editor_insert(GET_EDITOR(ntshell), ch)) {
+        char txt[TEXTEDITOR_MAXLEN];
+        int len = text_editor_get_text(GET_EDITOR(ntshell), &txt[0], sizeof(txt));
+        int pos = text_editor_cursor_get_position(GET_EDITOR(ntshell));
+        int n = len - pos;
+        SERIAL_WRITE(ntshell, (char *)&ch, sizeof(ch));
+        if (n > 0) {
+            int i;
+            SERIAL_WRITE(ntshell, txt + pos, len - pos);
+            for (i = 0; i < n; i++) {
+                VTSEND_CURSOR_PREV(ntshell);
+            }
+        }
+    }
+}
+
+/**
+ * @brief バックスペース処理を実行する。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_backspace(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    if (text_editor_backspace(GET_EDITOR(ntshell))) {
+        char txt[TEXTEDITOR_MAXLEN];
+        int len = text_editor_get_text(GET_EDITOR(ntshell), &txt[0], sizeof(txt));
+        int pos = text_editor_cursor_get_position(GET_EDITOR(ntshell));
+        int n = len - pos;
+        VTSEND_CURSOR_PREV(ntshell);
+        if (n > 0) {
+            int i;
+            SERIAL_WRITE(ntshell, txt + pos, n);
+            SERIAL_WRITE(ntshell, " ", 1);
+            for (i = 0; i < n + 1; i++) {
+                VTSEND_CURSOR_PREV(ntshell);
+            }
+        } else {
+            SERIAL_WRITE(ntshell, " ", 1);
+            VTSEND_CURSOR_PREV(ntshell);
+        }
+    }
+}
+
+/**
+ * @brief デリート処理を実行する。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_delete(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    if (text_editor_delete(GET_EDITOR(ntshell))) {
+        char txt[TEXTEDITOR_MAXLEN];
+        int len = text_editor_get_text(GET_EDITOR(ntshell), &txt[0], sizeof(txt));
+        int pos = text_editor_cursor_get_position(GET_EDITOR(ntshell));
+        int n = len - pos;
+        if (n > 0) {
+            int i;
+            SERIAL_WRITE(ntshell, txt + pos, n);
+            SERIAL_WRITE(ntshell, " ", 1);
+            for (i = 0; i < n + 1; i++) {
+                VTSEND_CURSOR_PREV(ntshell);
+            }
+        } else {
+            SERIAL_WRITE(ntshell, " ", 1);
+            VTSEND_CURSOR_PREV(ntshell);
+        }
+    }
+}
+
+/**
+ * @brief 入力補完処理を実行する。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_suggest(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    char buf[TEXTEDITOR_MAXLEN];
+    if (SUGGEST_INDEX(ntshell) < 0) {
+        /*
+         * 入力補完モードにこれから入る場合。
+         * 現在の入力文字列を元に補完候補を取得する。
+         */
+        if (text_editor_get_text(
+                    GET_EDITOR(ntshell),
+                    SUGGEST_SOURCE(ntshell),
+                    sizeof(SUGGEST_SOURCE(ntshell))) > 0) {
+            SUGGEST_INDEX(ntshell) = 0;
+            if (text_history_find(
+                        GET_HISTORY(ntshell),
+                        SUGGEST_INDEX(ntshell),
+                        SUGGEST_SOURCE(ntshell),
+                        buf,
+                        sizeof(buf)) == 0) {
+                // 候補が見つかればテキストを設定して、インデックスをメモする。
+                int n = ntlibc_strlen((const char *)buf);
+                VTSEND_ERASE_LINE(ntshell);
+                VTSEND_CURSOR_HEAD(ntshell);
+                PROMPT_WRITE(ntshell);
+                SERIAL_WRITE(ntshell, buf, n);
+                text_editor_set_text(GET_EDITOR(ntshell), buf);
+            } else {
+                // 候補がなければ入力補完モードから抜ける。
+                SUGGEST_INDEX(ntshell) = -1;
+            }
+        }
+    } else {
+        /*
+         * 既に入力補完モードに入っている場合、
+         * 次の候補を探して見つかればテキストとして設定する。
+         */
+        SUGGEST_INDEX(ntshell) = SUGGEST_INDEX(ntshell) + 1;
+        if (text_history_find(
+                    GET_HISTORY(ntshell),
+                    SUGGEST_INDEX(ntshell),
+                    SUGGEST_SOURCE(ntshell),
+                    buf,
+                    sizeof(buf)) == 0) {
+            // 候補が見つかればテキストを設定する。
+            int n = ntlibc_strlen((const char *)buf);
+            VTSEND_ERASE_LINE(ntshell);
+            VTSEND_CURSOR_HEAD(ntshell);
+            PROMPT_WRITE(ntshell);
+            SERIAL_WRITE(ntshell, buf, n);
+            text_editor_set_text(GET_EDITOR(ntshell), buf);
+        } else {
+            // 候補が見つからなければ元の入力文字列に戻し、入力補完モードから抜ける。
+            int n = ntlibc_strlen(SUGGEST_SOURCE(ntshell));
+            VTSEND_ERASE_LINE(ntshell);
+            VTSEND_CURSOR_HEAD(ntshell);
+            PROMPT_WRITE(ntshell);
+            SERIAL_WRITE(ntshell, SUGGEST_SOURCE(ntshell), n);
+            text_editor_set_text(GET_EDITOR(ntshell), SUGGEST_SOURCE(ntshell));
+            SUGGEST_INDEX(ntshell) = -1;
+        }
+    }
+}
+
+/**
+ * @brief カーソルを行頭へ移動させる。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_cursor_head(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    VTSEND_CURSOR_HEAD(ntshell);
+    PROMPT_WRITE(ntshell);
+    text_editor_cursor_head(GET_EDITOR(ntshell));
+}
+
+/**
+ * @brief カーソルを行末へ移動させる。
+ * @details
+ * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
+ * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
+ *
+ * @param ntshell ハンドラ。
+ * @param action アクション。
+ * @param ch 入力文字。
+ */
+static void actfunc_cursor_tail(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch)
+{
+    char buf[TEXTEDITOR_MAXLEN];
+    int len;
+    UNUSED_VARIABLE(action);
+    UNUSED_VARIABLE(ch);
+    text_editor_get_text(GET_EDITOR(ntshell), buf, sizeof(buf));
+    len = ntlibc_strlen((const char *)buf);
+    VTSEND_CURSOR_HEAD(ntshell);
+    PROMPT_WRITE(ntshell);
+    SERIAL_WRITE(ntshell, buf, len);
+    text_editor_cursor_tail(GET_EDITOR(ntshell));
+}
+
+/**
+ * @brief アクションテーブルのデータ構造体。
+ * @details
+ * アクションは状態と入力文字によって与えられる。
+ * アクションに対する関数もここで定義する。
+ */
+typedef struct {
+    vtrecv_action_t action;
+    unsigned char ch;
+    void (*func)(ntshell_t *ntshell, vtrecv_action_t action, unsigned char ch);
+} ntshell_action_table_t;
+
+/**
+ * @brief アクションに対する処理関数テーブル。
+ * @details
+ * やってくるコードは仮想端末側の処理に依存する。
+ * よって様々なプラットフォームの様々な仮想端末で試すと良い。
+ *
+ * <table>
+ *   <th>
+ *     <td>Platform</td>
+ *     <td>Tools</td>
+ *   </th>
+ *   <tr>
+ *     <td>Windows</td>
+ *     <td>Hyper Terminal, Poderossa, TeraTerm</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Linux</td>
+ *     <td>minicom, screen, kermit</td>
+ *   </tr>
+ * </table>
+ */
+static const ntshell_action_table_t action_table[] = {
+    {VTRECV_ACTION_EXECUTE, 0x01, actfunc_cursor_head},
+    {VTRECV_ACTION_EXECUTE, 0x02, actfunc_cursor_left},
+    {VTRECV_ACTION_EXECUTE, 0x03, actfunc_cancel},
+    {VTRECV_ACTION_EXECUTE, 0x04, actfunc_delete},
+    {VTRECV_ACTION_EXECUTE, 0x05, actfunc_cursor_tail},
+    {VTRECV_ACTION_EXECUTE, 0x06, actfunc_cursor_right},
+    {VTRECV_ACTION_EXECUTE, 0x08, actfunc_backspace},
+    {VTRECV_ACTION_EXECUTE, 0x09, actfunc_suggest},
+    {VTRECV_ACTION_EXECUTE, 0x0d, actfunc_enter},
+    {VTRECV_ACTION_EXECUTE, 0x0e, actfunc_history_next},
+    {VTRECV_ACTION_EXECUTE, 0x10, actfunc_history_prev},
+    {VTRECV_ACTION_CSI_DISPATCH, 0x41, actfunc_history_prev},
+    {VTRECV_ACTION_CSI_DISPATCH, 0x42, actfunc_history_next},
+    {VTRECV_ACTION_CSI_DISPATCH, 0x43, actfunc_cursor_right},
+    {VTRECV_ACTION_CSI_DISPATCH, 0x44, actfunc_cursor_left},
+    {VTRECV_ACTION_CSI_DISPATCH, 0x7e, actfunc_delete},
+    {VTRECV_ACTION_PRINT, 0x7f, actfunc_delete},
+};
+
+/**
+ * @brief パーサーに対するコールバック関数。
+ * @details vtrecvモジュールのコールバック関数に従った実装である。
+ *
+ * @param vtrecv パーサー。
+ * @param action アクション。
+ * @param ch キャラクタ。
+ */
+void vtrecv_callback(vtrecv_t *vtrecv, vtrecv_action_t action, unsigned char ch)
+{
+    ntshell_action_table_t *p;
+    int i;
+    const int ACTTBLSIZ = sizeof(action_table) / sizeof(action_table[0]);
+
+    /*
+     * 制御コードに対する処理はテーブルから探す。
+     */
+    p = (ntshell_action_table_t *)action_table;
+    for (i = 0; i < ACTTBLSIZ; i++) {
+        if ((p->action == action) && (p->ch == ch)) {
+            p->func(vtrecv->user_data, action, ch);
+            return;
+        }
+        p++;
+    }
+
+    /*
+     * 通常の文字列は入力として扱う。
+     */
+    if (VTRECV_ACTION_PRINT == action) {
+        actfunc_insert(vtrecv->user_data, action, ch);
+        return;
+    }
+
+    /*
+     * ここに到達する場合、
+     * テーブルに含まれない制御コードか、
+     * 通常の文字でない事が考えられる。
+     *
+     * 必要なキー入力に対する動作を加えたい場合、
+     * vtrecvによって得られるコードを調べるために
+     * ここにテストコードを加える事ができる。
+     */
+}
+
+/**
+ * @brief Natural Tiny Shellを初期化する。
+ *
+ * @param p NT-Shellハンドラ。
+ * @param func_read シリアルリード関数。
+ * @param func_write シリアルライト関数。
+ * @param func_callback コールバック関数。
+ * @param extobj コールバック関数呼び出し時に渡す拡張オブジェクト。
+ */
+void ntshell_init(ntshell_t *p,
+    NTSHELL_SERIAL_READ func_read,
+    NTSHELL_SERIAL_WRITE func_write,
+    NTSHELL_USER_CALLBACK func_callback,
+    void *extobj)
+{
+    /*
+     * vtrecvはユーザデータへのポインタを設定できるようになっている。
+     * Natural Tiny Shellはこれを利用してテキストエディタやヒストリ、
+     * リード関数やライト関数、コールバック関数を処理の中で使用できる
+     * ようにしてある。
+     */
+    p->func_read = func_read;
+    p->func_write = func_write;
+    p->func_callback = func_callback;
+    p->extobj = extobj;
+    ntlibc_strcpy(p->prompt, NTSHELL_PROMPT_DEFAULT);
+
+    p->vtrecv.user_data = p;
+
+    /*
+     * 各モジュールを初期化する。
+     */
+    vtsend_init(&(p->vtsend), func_write, 0);
+    vtrecv_init(&(p->vtrecv), vtrecv_callback);
+    text_editor_init(GET_EDITOR(p));
+    text_history_init(GET_HISTORY(p));
+    SUGGEST_INDEX(p) = -1;
+
+    /*
+     * 初期化確認コードを設定する。
+     */
+    p->initcode = INITCODE;
+}
+
+/**
+ * @brief Natural Tiny Shellを実行する。
+ * @details この関数は実行を返さない。
+ *
+ * @param p NT-Shellハンドラ。
+ */
+void ntshell_execute(ntshell_t *p)
+{
+    /*
+     * 初期化確認コードを検証する。
+     */
+    if (p->initcode != INITCODE) {
+      return;
+    }
+
+    /*
+     * ユーザ入力ループ。
+     */
+    PROMPT_WRITE(p);
+    while (1) {
+        unsigned char ch;
+        SERIAL_READ(p, (char *)&ch, sizeof(ch));
+        vtrecv_execute(&(p->vtrecv), &ch, sizeof(ch));
+    }
+}
+
+/**
+ * @brief Natural Tiny Shellのプロンプトを設定する。
+ */
+void ntshell_set_prompt(ntshell_t *p, const char *prompt)
+{
+    /*
+     * 初期化確認コードを検証する。
+     */
+    if (p->initcode != INITCODE) {
+      return;
+    }
+
+    ntlibc_strcpy(p->prompt, prompt);
+}
+
+/**
+ * @brief Natural Tiny Shellのバージョンを返す。
+ * @details 返すバージョンはリリースバージョンである。
+ *
+ * @param major メージャーバージョン。
+ * @param minor マイナーバージョン。
+ * @param release リリースバージョン。
+ */
+void ntshell_version(int *major, int *minor, int *release)
+{
+    *major = VERSION_MAJOR;
+    *minor = VERSION_MINOR;
+    *release = VERSION_RELEASE;
+}
+
+