/* termios テストプログラム */ /* 入力プロンプト */ /* ToDo */ /* Tab: コマンド/オプション補完 */ /* Ctrl-D: 補完候補一覧表示 */ /* Ctrl-Y: Ctrl-U, Ctrl-W, Dtrl-K で削除した文字列をペースト */ #include #include #include #include #include #include #define BUFSIZE 1024 #define HISTSIZE 1000 /* エスケープ種別 */ #define NOESCAPE 0 /* 特殊キー入力なし */ #define UPKEY 1 /* 上キー入力 */ #define DOWNKEY 2 /* 下キー入力 */ #define LEFTKEY 3 /* 左キー入力 */ #define RIGHTKEY 4 /* 右キー入力 */ #define PROMPT() \ { \ printf("\r[prompt(%02x:%02d/%02d:%02d/%02d)] %s\033[K", \ inch, incur, incnt, histcur, histnew, inbuff); \ \ /* カーソル位置を補正 */ \ for (intmp = incnt; intmp > incur; intmp--) { \ printf("\033[1D"); \ } \ } int main() { struct termios save_term; struct termios temp_term; int wretc; int inch; /* 入力文字 */ char inbuff[BUFSIZE]; /* 入力バッファ */ int incnt; /* バッファ内入力文字数 */ int incur; /* バッファ内カーソル位置 */ int intmp; /* バッファ編集用一時変数 */ char *space; /* 検索したスペース位置 */ int spaceidx; /* 検索したスペース位置のインデクス */ int escape; /* 特殊キー入力時のエスケープ種別 */ char swap; /* 入れ替えよう文字変数 */ char history[BUFSIZE][HISTSIZE]; /* ヒストリバッファ */ int histold; /* 再古ヒストリエントリ番号 */ int histnew; /* 再新ヒストリエントリ番号 */ int histcur; /* 現在のヒストリエントリ番号 */ int histtmp; /* 一時エントリ番号 */ int overlap; /* オーバラップ判定変数 */ /* 現在の入力設定を取得 */ wretc = tcgetattr(fileno(stdin), &save_term); if (wretc == -1) { perror("tcgetattr ERROR"); exit(1); } /* 現在の入力設定をコピー */ temp_term = save_term; /* 設定を変更 */ temp_term.c_iflag &= IGNCR; /* CR の入力を無視する */ temp_term.c_lflag &= ~ICANON; /* 非カノニカルモードにする */ temp_term.c_lflag &= ~ECHO; /* 入力のエコーを行わないようにする */ temp_term.c_lflag &= ~ISIG; /* シグナルを無視する */ wretc = tcsetattr(fileno(stdin), TCSANOW, &temp_term); if (wretc == -1) { perror("tcsetattr ERROR"); exit(1); } /* 入力を受け付ける */ inch = '\0'; histold = 0; histnew = 0; histcur = 0; overlap = 0; while (1) { incnt = 0; incur = 0; inbuff[0] = '\0'; escape = NOESCAPE; PROMPT(); /* 一行分の入力 */ while (1) { if (escape == NOESCAPE) { inch = getchar(); } if (inch == 0x0d) { /* ENTER が入力された */ inbuff[incnt] = '\0'; if (incnt == 0) { printf("\n"); } else { printf("\ninput = %s\n", inbuff); } break; } else if (inch == 0x04) { /* Ctrl-D が入力された */ if (incnt == 0) { /* 終了 */ strcpy(inbuff, "exit"); break; } else if (incur < incnt) { /* カーソル位置の文字を削除 */ for (intmp = incur; intmp < incnt; intmp++) { inbuff[intmp] = inbuff[intmp + 1]; } incnt--; } else { printf("\n"); } } else if (inch == 0x08) { /* BackSpace/Ctrl-H が入力された */ if (incur > 0) { if (incur == incnt) { incnt--; incur = incnt; inbuff[incnt] = '\0'; } else { incur--; for (intmp = incur; intmp < incnt; intmp++) { inbuff[intmp] = inbuff[intmp + 1]; } incnt--; } } } else if (inch == 0x7f) { /* Delete が入力された */ /* カーソル位置の文字を削除 */ if (incnt > 0 && incur < incnt) { for (intmp = incur; intmp < incnt; intmp++) { inbuff[intmp] = inbuff[intmp + 1]; } incnt--; } } else if (inch == 0x15) { /* Ctrl-U が入力された */ /* バッファをクリアする */ incnt = 0; incur = incnt; inbuff[incnt] = '\0'; } else if (inch == 0x17) { /* Ctrl-W キーが入力された */ if (incur > 0) { /* カーソル位置より前に単語があるかどうか検索 */ for (intmp = incur - 1; intmp > 0; intmp--) { if (inbuff[intmp] != ' ') { break; } } /* 単語の先頭を検索 */ for (; intmp > 0; intmp--) { if (inbuff[intmp] == ' ') { intmp++; break; } } spaceidx = intmp; /* カーソル位置以降を見つけた空白位置or行頭まで詰める */ for (intmp = 0; intmp <= incnt - incur; intmp++) { inbuff[spaceidx + intmp] = inbuff[incur + intmp]; } incnt -= incur - spaceidx; incur = spaceidx; } } else if (inch == 0x0b) { /* Ctrl-K キーが入力された */ /* カーソルよりも後ろを削除 */ inbuff[incur] = '\0'; incnt = incur; } else if (inch == 0x14) { /* Ctrl-T キーが入力された */ if (incur < incnt) { /* カーソル位置とカーソル位置の前の文字を入れ替える */ if (incur > 0) { swap = inbuff[incur - 1]; inbuff[incur - 1] = inbuff[incur]; inbuff[incur] = swap; /* カーソルを一つ進める */ incur++; } } else { if (incur > 1) { /* カーソル位置の前とカーソル位置の前の前を入れ替える */ swap = inbuff[incur - 2]; inbuff[incur - 2] = inbuff[incur - 1]; inbuff[incur - 1] = swap; } } } else if (inch == 0x0c) { /* Ctrl-L キーが入力された */ /* 画面フラッシュ */ printf("\033[2J"); /* プロンプトを端末の先頭へ */ printf("\033[0;0H"); } else if (inch == 0x01) { /* Ctrl-A キーが入力された */ /* カーソルを行頭へ移動する */ if (incur > 0) { for (intmp = 0; intmp < incnt; intmp++){ printf("\033[1D"); } incur = 0; } } else if (inch == 0x05) { /* Ctrl-E キーが入力された */ /* カーソルを行末へ移動する */ if (incur < incnt) { for (intmp = incur; intmp < incnt; intmp++) { printf("\033[1C"); } incur = incnt; } } else if (inch == 0x02 || escape == LEFTKEY) { /* Ctrl-B/左キーが入力された */ /* カーソルを一つ前に移動する */ if (incur > 0) { incur--; printf("\033[1D"); } escape = NOESCAPE; } else if (inch == 0x06 || escape == RIGHTKEY) { /* Ctrl-F/右キーが入力された */ /* カーソルを一つ後に移動する */ if (incur < incnt) { incur++; printf("\033[1C"); } escape = NOESCAPE; } else if (inch == 0x10 || escape == UPKEY) { /* Ctrl-P/上キーが入力された */ if (histcur == histnew) { /* 現在入力中の文字列を記憶する */ strcpy(history[histcur], inbuff); } if (histcur != histold) { histcur--; if (histcur == -1) { histcur = HISTSIZE - 1; } strcpy(inbuff, history[histcur]); incnt = strlen(inbuff); incur = incnt; } escape = NOESCAPE; } else if (inch == 0x0e || escape == DOWNKEY) { /* Ctrl-N/下キーが入力された */ if (histcur != histnew) { histcur++; if (histcur == HISTSIZE) { histcur = 0; } strcpy(inbuff, history[histcur]); incnt = strlen(inbuff); incur = incnt; } escape = NOESCAPE; } else if (inch == 0x1b) { /* エスケープ文字が入力された */ inch = getchar(); if (inch == '[') { inch = getchar(); switch (inch) { case 'A': /* 上キーが入力された */ escape = UPKEY; break; case 'B': /* 下キーが入力された */ escape = DOWNKEY; break; case 'C': /* 右キーが入力された */ escape = RIGHTKEY; break; case 'D': /* 左キーが入力された */ escape = LEFTKEY; break; default: /* それ以外のキーが入力された */ /* 無視する */ break; } } else { /* 文字をストリームに戻す */ ungetc(inch, stdin); } } else { /* 制御文字でない場合にのみ入力バッファに入力する */ if (iscntrl(inch) == 0) { if (incnt < BUFSIZE - 1) { if (incur == incnt) { /* カーソルは行末にある */ inbuff[incnt] = inch; incnt++; incur = incnt; inbuff[incnt] = '\0'; } else { /* カーソルは行末にない */ /* カーソル以降の文字を後ろにずらす */ for (intmp = incnt; intmp >= incur; intmp--) { inbuff[intmp + 1] = inbuff[intmp]; } /* 入力文字を挿入する */ inbuff[incur] = inch; incnt++; incur++; } } } } PROMPT(); } if (strcmp(inbuff, "exit") == 0) { break; } if (strcmp(inbuff, "history") == 0) { histtmp = histold; while (histtmp != histnew) { printf("[%d] %s\n", histtmp, history[histtmp]); histtmp++; if (histtmp == HISTSIZE) { histtmp = 0; } } printf("[%d] %s\n", histtmp, history[histtmp]); } if (strlen(inbuff) != 0) { strcpy(history[histnew], inbuff); histnew++; if (histnew == HISTSIZE) { /* ヒストリがオーバラップした */ histnew = 0; overlap = 1; } if (overlap == 1) { histold = histnew + 1; if (histold == HISTSIZE) { histold = 0; } } histcur = histnew; } } /* 設定を元に戻す */ wretc = tcsetattr(fileno(stdin), TCSANOW, &save_term); if (wretc == -1) { perror("tcsetattr ERROR"); exit(1); } }