OSDN Git Service

Added NT-Shell module to the command task.
[kozos-expbrd/kozos_expbrd.git] / firm / sample / simple_mp3_player / os / ntshell.c
1 /**
2  * @file ntshell.c
3  * @author Shinichiro Nakamura
4  * @brief 小規模組み込みシステム向けのシェルシステムの実装。
5  */
6
7 /*
8  * ===============================================================
9  *  Natural Tiny Shell (NT-Shell)
10  *  Version 0.0.8
11  * ===============================================================
12  * Copyright (c) 2010-2011 Shinichiro Nakamura
13  *
14  * Permission is hereby granted, free of charge, to any person
15  * obtaining a copy of this software and associated documentation
16  * files (the "Software"), to deal in the Software without
17  * restriction, including without limitation the rights to use,
18  * copy, modify, merge, publish, distribute, sublicense, and/or
19  * sell copies of the Software, and to permit persons to whom the
20  * Software is furnished to do so, subject to the following
21  * conditions:
22  *
23  * The above copyright notice and this permission notice shall be
24  * included in all copies or substantial portions of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
28  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
30  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
31  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33  * OTHER DEALINGS IN THE SOFTWARE.
34  * ===============================================================
35  */
36
37 #include "ntshell.h"
38 #include "ntlibc.h"
39
40 #define VERSION_MAJOR 0     /**< メジャー番号。 */
41 #define VERSION_MINOR 0     /**< マイナー番号。 */
42 #define VERSION_RELEASE 8   /**< リリース番号。 */
43
44 /**
45  * @brief 処理で用いるデータ構造体。
46  *
47  * @details
48  * vtrecvはユーザデータのポインタを設定することができる。
49  * Natural Tiny Shellはこれを使って自身の処理で必要な情報を保持する。
50  */
51 typedef struct {
52     text_editor_t *editor;
53     text_history_t *history;
54     int suggest_index;
55     char suggest_source[TEXTEDITOR_MAXLEN];
56     int (*func_read)(char *buf, int cnt);
57     int (*func_write)(const char *buf, int cnt);
58     int (*func_callback)(const char *text, void *extobj);
59     void *func_callback_extobj;
60 } ntshell_user_data_t;
61
62 #define SUGGEST_INDEX(vtp) \
63     ((ntshell_user_data_t *)(vtp)->user_data)->suggest_index
64 #define SUGGEST_SOURCE(vtp) \
65     ((ntshell_user_data_t *)(vtp)->user_data)->suggest_source
66
67 /**
68  * @brief テキストエディタを取得する。
69  *
70  * @param vtp vtrecv構造体。
71  */
72 #define GET_EDITOR(vtp) \
73     ((ntshell_user_data_t *)(vtp)->user_data)->editor
74
75 /**
76  * @brief テキストヒストリを取得する。
77  *
78  * @param vtp vtrecv構造体。
79  */
80 #define GET_HISTORY(vtp) \
81     ((ntshell_user_data_t *)(vtp)->user_data)->history
82
83 /**
84  * @brief シリアルポートから読み込む。
85  *
86  * @param vtp vtrecv構造体。
87  * @param buf 読み込みバッファ。
88  * @param cnt 読み込み文字数。
89  */
90 #define SERIAL_READ(vtp,buf,cnt) \
91     ((ntshell_user_data_t *)(vtp)->user_data)->func_read(buf, cnt)
92
93 /**
94  * @brief シリアルポートへ書き込む。
95  *
96  * @param vtp vtrecv構造体。
97  * @param buf 書き込みバッファ。
98  * @param cnt 書き込み文字数。
99  */
100 #define SERIAL_WRITE(vtp,buf,cnt) \
101     ((ntshell_user_data_t *)(vtp)->user_data)->func_write(buf, cnt)
102
103 /**
104  * @brief コールバックを呼び出す。
105  *
106  * @param vtp vtrecv構造体。
107  * @param text コールバック関数へ渡す文字列。
108  */
109 #define CALLBACK(vtp, text) \
110     ((ntshell_user_data_t *)(vtp)->user_data)->func_callback(text, ((ntshell_user_data_t *)(vtp)->user_data)->func_callback_extobj)
111
112 /**
113  * @brief テキストヒストリで1つ後ろを辿る。
114  * @details
115  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
116  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
117  *
118  * @param vtrecv パーサー。
119  * @param action アクション。
120  * @param ch 入力文字。
121  */
122 static void actfunc_history_prev(
123         vtrecv_t *vtrecv,
124         vtrecv_action_t action,
125         unsigned char ch) {
126     if (text_history_read_point_prev(GET_HISTORY(vtrecv))) {
127         char txt[TEXTHISTORY_MAXLEN];
128         int n = text_history_read(GET_HISTORY(vtrecv), &txt[0], sizeof(txt));
129         if (0 < n) {
130             SERIAL_WRITE(vtrecv, "\x1b[2K", 4);
131             SERIAL_WRITE(vtrecv, "\x1b[80D", 5);
132             SERIAL_WRITE(vtrecv, ">", 1);
133             SERIAL_WRITE(vtrecv, txt, n);
134             text_editor_set_text(GET_EDITOR(vtrecv), txt);
135         }
136     }
137 }
138
139 /**
140  * @brief テキストヒストリで1つ前を辿る。
141  * @details
142  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
143  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
144  *
145  * @param vtrecv パーサー。
146  * @param action アクション。
147  * @param ch 入力文字。
148  */
149 static void actfunc_history_next(
150         vtrecv_t *vtrecv,
151         vtrecv_action_t action,
152         unsigned char ch) {
153     if (text_history_read_point_next(GET_HISTORY(vtrecv))) {
154         char txt[TEXTHISTORY_MAXLEN];
155         int n = text_history_read(GET_HISTORY(vtrecv), &txt[0], sizeof(txt));
156         if (0 < n) {
157             SERIAL_WRITE(vtrecv, "\x1b[2K", 4);
158             SERIAL_WRITE(vtrecv, "\x1b[80D", 5);
159             SERIAL_WRITE(vtrecv, ">", 1);
160             SERIAL_WRITE(vtrecv, txt, n);
161             text_editor_set_text(GET_EDITOR(vtrecv), txt);
162         }
163     }
164 }
165
166 /**
167  * @brief カーソルを左へ移動させる。
168  * @details
169  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
170  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
171  *
172  * @param vtrecv パーサー。
173  * @param action アクション。
174  * @param ch 入力文字。
175  */
176 static void actfunc_cursor_left(
177         vtrecv_t *vtrecv,
178         vtrecv_action_t action,
179         unsigned char ch) {
180     if (text_editor_cursor_left(GET_EDITOR(vtrecv))) {
181         SERIAL_WRITE(vtrecv, "\x1b[1D", 4);
182     }
183 }
184
185 /**
186  * @brief カーソルを右へ移動させる。
187  * @details
188  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
189  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
190  *
191  * @param vtrecv パーサー。
192  * @param action アクション。
193  * @param ch 入力文字。
194  */
195 static void actfunc_cursor_right(
196         vtrecv_t *vtrecv,
197         vtrecv_action_t action,
198         unsigned char ch) {
199     if (text_editor_cursor_right(GET_EDITOR(vtrecv))) {
200         SERIAL_WRITE(vtrecv, "\x1b[1C", 4);
201     }
202 }
203
204 /**
205  * @brief エンターキーの処理を実行する。
206  * @details
207  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
208  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
209  *
210  * @param vtrecv パーサー。
211  * @param action アクション。
212  * @param ch 入力文字。
213  */
214 static void actfunc_enter(
215         vtrecv_t *vtrecv,
216         vtrecv_action_t action,
217         unsigned char ch) {
218     char txt[TEXTEDITOR_MAXLEN];
219     text_editor_get_text(GET_EDITOR(vtrecv), &txt[0], sizeof(txt));
220     text_editor_clear(GET_EDITOR(vtrecv));
221     text_history_write(GET_HISTORY(vtrecv), txt);
222     SERIAL_WRITE(vtrecv, "\r\n", 2);
223     CALLBACK(vtrecv, txt);
224     SERIAL_WRITE(vtrecv, ">", 1);
225 }
226
227 /**
228  * @brief キャンセルキーの処理を実行する。
229  * @details
230  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
231  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
232  *
233  * 一般的なOSのCTRL+C処理はシグナルを発行し、受信したプロセスが
234  * 中断処理を実行する。
235  * ここでのキャンセルは見た目を再現したもので、
236  * 入力中の文字列を破棄してカーソルを新しい入力に備えて復帰させるものだ。
237  *
238  * @param vtrecv パーサー。
239  * @param action アクション。
240  * @param ch 入力文字。
241  */
242 static void actfunc_cancel(
243         vtrecv_t *vtrecv,
244         vtrecv_action_t action,
245         unsigned char ch) {
246     SERIAL_WRITE(vtrecv, "^C\r\n", 4);
247     text_editor_clear(GET_EDITOR(vtrecv));
248     SERIAL_WRITE(vtrecv, ">", 1);
249 }
250
251 /**
252  * @brief 挿入処理を実行する。
253  * @details
254  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
255  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
256  *
257  * @param vtrecv パーサー。
258  * @param action アクション。
259  * @param ch 入力文字。
260  */
261 static void actfunc_insert(
262         vtrecv_t *vtrecv,
263         vtrecv_action_t action,
264         unsigned char ch) {
265
266     /*
267      * 入力があった場合、入力補完状態から抜ける。
268      */
269     SUGGEST_INDEX(vtrecv) = -1;
270
271     /*
272      * テキストエディタを使って文字を文字列に挿入する。
273      */
274     if (text_editor_insert(GET_EDITOR(vtrecv), ch)) {
275         char txt[TEXTEDITOR_MAXLEN];
276         int len = text_editor_get_text(GET_EDITOR(vtrecv), &txt[0], sizeof(txt));
277         int pos = text_editor_cursor_get_position(GET_EDITOR(vtrecv));
278         int n = len - pos;
279         SERIAL_WRITE(vtrecv, (char *)&ch, sizeof(ch));
280         if (n > 0) {
281             int i;
282             SERIAL_WRITE(vtrecv, txt + pos, len - pos);
283             for (i = 0; i < n; i++) {
284                 SERIAL_WRITE(vtrecv, "\x1b[1D", 4);
285             }
286         }
287     }
288 }
289
290 /**
291  * @brief バックスペース処理を実行する。
292  * @details
293  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
294  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
295  *
296  * @param vtrecv パーサー。
297  * @param action アクション。
298  * @param ch 入力文字。
299  */
300 static void actfunc_backspace(
301         vtrecv_t *vtrecv,
302         vtrecv_action_t action,
303         unsigned char ch) {
304     if (text_editor_backspace(GET_EDITOR(vtrecv))) {
305         char txt[TEXTEDITOR_MAXLEN];
306         int len = text_editor_get_text(GET_EDITOR(vtrecv), &txt[0], sizeof(txt));
307         int pos = text_editor_cursor_get_position(GET_EDITOR(vtrecv));
308         int n = len - pos;
309         SERIAL_WRITE(vtrecv, "\x1b[1D", 4);
310         if (n > 0) {
311             int i;
312             SERIAL_WRITE(vtrecv, txt + pos, n);
313             SERIAL_WRITE(vtrecv, " ", 1);
314             for (i = 0; i < n + 1; i++) {
315                 SERIAL_WRITE(vtrecv, "\x1b[1D", 4);
316             }
317         } else {
318             SERIAL_WRITE(vtrecv, " ", 1);
319             SERIAL_WRITE(vtrecv, "\x1b[1D", 4);
320         }
321     }
322 }
323
324 /**
325  * @brief デリート処理を実行する。
326  * @details
327  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
328  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
329  *
330  * @param vtrecv パーサー。
331  * @param action アクション。
332  * @param ch 入力文字。
333  */
334 static void actfunc_delete(
335         vtrecv_t *vtrecv,
336         vtrecv_action_t action,
337         unsigned char ch) {
338     if (text_editor_delete(GET_EDITOR(vtrecv))) {
339         char txt[TEXTEDITOR_MAXLEN];
340         int len = text_editor_get_text(GET_EDITOR(vtrecv), &txt[0], sizeof(txt));
341         int pos = text_editor_cursor_get_position(GET_EDITOR(vtrecv));
342         int n = len - pos;
343         if (n > 0) {
344             int i;
345             SERIAL_WRITE(vtrecv, txt + pos, n);
346             SERIAL_WRITE(vtrecv, " ", 1);
347             for (i = 0; i < n + 1; i++) {
348                 SERIAL_WRITE(vtrecv, "\x1b[1D", 4);
349             }
350         } else {
351             SERIAL_WRITE(vtrecv, " ", 1);
352             SERIAL_WRITE(vtrecv, "\x1b[1D", 4);
353         }
354     }
355 }
356
357 /**
358  * @brief 入力補完処理を実行する。
359  * @details
360  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
361  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
362  *
363  * @param vtrecv パーサー。
364  * @param action アクション。
365  * @param ch 入力文字。
366  */
367 static void actfunc_suggest(
368         vtrecv_t *vtrecv,
369         vtrecv_action_t action,
370         unsigned char ch) {
371     char buf[TEXTEDITOR_MAXLEN];
372     if (SUGGEST_INDEX(vtrecv) < 0) {
373         /*
374          * 入力補完モードにこれから入る場合。
375          * 現在の入力文字列を元に補完候補を取得する。
376          */
377         if (text_editor_get_text(
378                     GET_EDITOR(vtrecv),
379                     SUGGEST_SOURCE(vtrecv),
380                     sizeof(SUGGEST_SOURCE(vtrecv))) > 0) {
381             SUGGEST_INDEX(vtrecv) = 0;
382             if (text_history_find(
383                         GET_HISTORY(vtrecv),
384                         SUGGEST_INDEX(vtrecv),
385                         SUGGEST_SOURCE(vtrecv),
386                         buf,
387                         sizeof(buf)) == 0) {
388                 // 候補が見つかればテキストを設定して、インデックスをメモする。
389                 int n = ntlibc_strlen((const char *)buf);
390                 SERIAL_WRITE(vtrecv, "\x1b[2K", 4);
391                 SERIAL_WRITE(vtrecv, "\x1b[80D", 5);
392                 SERIAL_WRITE(vtrecv, ">", 1);
393                 SERIAL_WRITE(vtrecv, buf, n);
394                 text_editor_set_text(GET_EDITOR(vtrecv), buf);
395             } else {
396                 // 候補がなければ入力補完モードから抜ける。
397                 SUGGEST_INDEX(vtrecv) = -1;
398             }
399         }
400     } else {
401         /*
402          * 既に入力補完モードに入っている場合、
403          * 次の候補を探して見つかればテキストとして設定する。
404          */
405         SUGGEST_INDEX(vtrecv) = SUGGEST_INDEX(vtrecv) + 1;
406         if (text_history_find(
407                     GET_HISTORY(vtrecv),
408                     SUGGEST_INDEX(vtrecv),
409                     SUGGEST_SOURCE(vtrecv),
410                     buf,
411                     sizeof(buf)) == 0) {
412             // 候補が見つかればテキストを設定する。
413             int n = ntlibc_strlen((const char *)buf);
414             SERIAL_WRITE(vtrecv, "\x1b[2K", 4);
415             SERIAL_WRITE(vtrecv, "\x1b[80D", 5);
416             SERIAL_WRITE(vtrecv, ">", 1);
417             SERIAL_WRITE(vtrecv, buf, n);
418             text_editor_set_text(GET_EDITOR(vtrecv), buf);
419         } else {
420             // 候補が見つからなければ元の入力文字列に戻し、入力補完モードから抜ける。
421             int n = ntlibc_strlen(SUGGEST_SOURCE(vtrecv));
422             SERIAL_WRITE(vtrecv, "\x1b[2K", 4);
423             SERIAL_WRITE(vtrecv, "\x1b[80D", 5);
424             SERIAL_WRITE(vtrecv, ">", 1);
425             SERIAL_WRITE(vtrecv, SUGGEST_SOURCE(vtrecv), n);
426             text_editor_set_text(GET_EDITOR(vtrecv), SUGGEST_SOURCE(vtrecv));
427             SUGGEST_INDEX(vtrecv) = -1;
428         }
429     }
430 }
431
432 /**
433  * @brief カーソルを行頭へ移動させる。
434  * @details
435  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
436  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
437  *
438  * @param vtrecv パーサー。
439  * @param action アクション。
440  * @param ch 入力文字。
441  */
442 static void actfunc_cursor_head(
443         vtrecv_t *vtrecv,
444         vtrecv_action_t action,
445         unsigned char ch) {
446     SERIAL_WRITE(vtrecv, "\x1b[80D", 5);
447     SERIAL_WRITE(vtrecv, ">", 1);
448     text_editor_cursor_head(GET_EDITOR(vtrecv));
449 }
450
451 /**
452  * @brief カーソルを行末へ移動させる。
453  * @details
454  * 論理上のテキスト編集装置内でのテキスト編集と編集結果をビューの更新を行なう。
455  * text_editorは論理上のテキスト編集装置であり、ビューに関して一切感知しない。
456  *
457  * @param vtrecv パーサー。
458  * @param action アクション。
459  * @param ch 入力文字。
460  */
461 static void actfunc_cursor_tail(
462         vtrecv_t *vtrecv,
463         vtrecv_action_t action,
464         unsigned char ch) {
465     char buf[TEXTEDITOR_MAXLEN];
466     int len;
467     text_editor_get_text(GET_EDITOR(vtrecv), buf, sizeof(buf));
468     len = ntlibc_strlen((const char *)buf);
469     SERIAL_WRITE(vtrecv, "\x1b[80D", 5);
470     SERIAL_WRITE(vtrecv, ">", 1);
471     SERIAL_WRITE(vtrecv, buf, len);
472     text_editor_cursor_tail(GET_EDITOR(vtrecv));
473 }
474
475 /**
476  * @brief アクションテーブルのデータ構造体。
477  * @details
478  * アクションは状態と入力文字によって与えられる。
479  * アクションに対する関数もここで定義する。
480  */
481 typedef struct {
482     vtrecv_action_t action;
483     unsigned char ch;
484     void (*func)(
485             vtrecv_t *vtrecv,
486             vtrecv_action_t action,
487             unsigned char ch);
488 } ntshell_action_table_t;
489
490 /**
491  * @brief アクションに対する処理関数テーブル。
492  * @details
493  * やってくるコードは仮想端末側の処理に依存する。
494  * よって様々なプラットフォームの様々な仮想端末で試すと良い。
495  *
496  * <table>
497  *   <th>
498  *     <td>Platform</td>
499  *     <td>Tools</td>
500  *   </th>
501  *   <tr>
502  *     <td>Windows</td>
503  *     <td>Hyper Terminal, Poderossa, TeraTerm</td>
504  *   </tr>
505  *   <tr>
506  *     <td>Linux</td>
507  *     <td>minicom, screen, kermit</td>
508  *   </tr>
509  * </table>
510  */
511 static const ntshell_action_table_t action_table[] = {
512     {VTRECV_ACTION_EXECUTE, 0x01, actfunc_cursor_head},
513     {VTRECV_ACTION_EXECUTE, 0x02, actfunc_cursor_left},
514     {VTRECV_ACTION_EXECUTE, 0x03, actfunc_cancel},
515     {VTRECV_ACTION_EXECUTE, 0x04, actfunc_delete},
516     {VTRECV_ACTION_EXECUTE, 0x05, actfunc_cursor_tail},
517     {VTRECV_ACTION_EXECUTE, 0x06, actfunc_cursor_right},
518     {VTRECV_ACTION_EXECUTE, 0x08, actfunc_backspace},
519     {VTRECV_ACTION_EXECUTE, 0x09, actfunc_suggest},
520     {VTRECV_ACTION_EXECUTE, 0x0d, actfunc_enter},
521     {VTRECV_ACTION_EXECUTE, 0x0e, actfunc_history_next},
522     {VTRECV_ACTION_EXECUTE, 0x10, actfunc_history_prev},
523     {VTRECV_ACTION_CSI_DISPATCH, 0x41, actfunc_history_prev},
524     {VTRECV_ACTION_CSI_DISPATCH, 0x42, actfunc_history_next},
525     {VTRECV_ACTION_CSI_DISPATCH, 0x43, actfunc_cursor_right},
526     {VTRECV_ACTION_CSI_DISPATCH, 0x44, actfunc_cursor_left},
527     {VTRECV_ACTION_PRINT, 0x7f, actfunc_backspace},
528 };
529
530 /**
531  * @brief パーサーに対するコールバック関数。
532  * @details vtrecvモジュールのコールバック関数に従った実装である。
533  *
534  * @param vtrecv パーサー。
535  * @param action アクション。
536  * @param ch キャラクタ。
537  */
538 void vtrecv_callback(
539         vtrecv_t *vtrecv,
540         vtrecv_action_t action,
541         unsigned char ch) {
542     ntshell_action_table_t *p;
543     int i;
544     const int ACTTBLSIZ = sizeof(action_table) / sizeof(action_table[0]);
545
546     /*
547      * 制御コードに対する処理はテーブルから探す。
548      */
549     p = (ntshell_action_table_t *)action_table;
550     for (i = 0; i < ACTTBLSIZ; i++) {
551         if ((p->action == action) && (p->ch == ch)) {
552             p->func(vtrecv, action, ch);
553             return;
554         }
555         p++;
556     }
557
558     /*
559      * 通常の文字列は入力として扱う。
560      */
561     if (VTRECV_ACTION_PRINT == action) {
562         actfunc_insert(vtrecv, action, ch);
563         return;
564     }
565
566     /*
567      * ここに到達する場合、
568      * テーブルに含まれない制御コードか、
569      * 通常の文字でない事が考えられる。
570      *
571      * 必要なキー入力に対する動作を加えたい場合、
572      * vtrecvによって得られるコードを調べるために
573      * ここにテストコードを加える事ができる。
574      */
575 }
576
577 /**
578  * @brief Natural Tiny Shellのバージョンを返す。
579  * @details 返すバージョンはリリースバージョンである。
580  *
581  * @param major メージャーバージョン。
582  * @param minor マイナーバージョン。
583  * @param release リリースバージョン。
584  */
585 void ntshell_version(int *major, int *minor, int *release)
586 {
587     *major = VERSION_MAJOR;
588     *minor = VERSION_MINOR;
589     *release = VERSION_RELEASE;
590 }
591
592 /**
593  * @brief Natural Tiny Shellを実行する。
594  * @details この関数は実行を返さない。
595  *
596  * @param p NT-Shellハンドラ。
597  * @param func_read シリアルリード関数。
598  * @param func_write シリアルライト関数。
599  * @param func_callback コールバック関数。
600  * @param func_callback_extobj コールバック関数呼び出し時に渡す拡張オブジェクト。
601  */
602 void ntshell_execute(
603         ntshell_t *p,
604         int (*func_read)(char *buf, int cnt),
605         int (*func_write)(const char *buf, int cnt),
606         int (*func_callback)(const char *text, void *extobj),
607         void *func_callback_extobj)
608 {
609     /*
610      * vtrecvはユーザデータへのポインタを設定できるようになっている。
611      * Natural Tiny Shellはこれを利用してテキストエディタやヒストリ、
612      * リード関数やライト関数、コールバック関数を処理の中で使用できる
613      * ようにしてある。
614      */
615     ntshell_user_data_t user_data;
616
617     user_data.editor = &(p->editor);
618     user_data.history = &(p->history);
619     user_data.func_read = func_read;
620     user_data.func_write = func_write;
621     user_data.func_callback = func_callback;
622     user_data.func_callback_extobj = func_callback_extobj;
623
624     p->vtrecv.user_data = &user_data;
625
626     /*
627      * 各モジュールを初期化する。
628      */
629     vtrecv_init(&(p->vtrecv), vtrecv_callback);
630     text_editor_init(GET_EDITOR(&(p->vtrecv)));
631     text_history_init(GET_HISTORY(&(p->vtrecv)));
632     SUGGEST_INDEX(&(p->vtrecv)) = -1;
633
634     /*
635      * ユーザ入力ループ。
636      */
637     SERIAL_WRITE(&(p->vtrecv), ">", 1);
638     while(1)
639     {
640         unsigned char ch;
641         SERIAL_READ(&(p->vtrecv), (char *)&ch, sizeof(ch));
642         vtrecv_execute(&(p->vtrecv), &ch, sizeof(ch));
643     }
644 }
645