2017-05-09 5 views
0

私はCで小さなシェルプログラムを実装しようとしています。これはstdinからコマンドを読み込み、解析して実行します。Ctrl + Cを元のシェルのように扱います。

[email protected]:/$ some letters^C 
[email protected]:/$ 

ここにある:シェルはちょうど新しいプロンプト裏を返し、あなたはいくつかの文字を入力する場合、または何も入力せず、その後、CNTRL + Cを押してください - 私は、元の殻のようにはCtrl + Cを処理する問題に直面しました単純化されたコードは、それを行うの私のアプローチを表示するには:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <signal.h> 

char  interruption; 

void  read_line(char **str) 
{ 
    char c; 
    int  size; 
    int  i; 

    c = 0; 
    size = 30; 
    i = -1; 
    *str = (char*)malloc(sizeof(char) * size + 1); 
    while (c != '\n' && !interruption) 
    { 
     i++; 
     if (i == size) 
      *str = realloc((void*)*str, (size_t)((size *= 2) + 1)); 
     read(0, &c, 1); 
     (*str)[i] = c; 
    } 
    if (interruption) 
    { 
     free(*str); 
     *str = NULL; 
     interruption = 0; 
    } 
    else 
     (*str)[i] = '\0'; 
} 

void  handler(int sig_num) 
{ 
    (void)sig_num; 
    signal(SIGINT, handler); 
    interruption = 1; 
    printf("\ninterruption happened\n"); 
} 

int   main() 
{ 
    char *str; 

    signal(SIGINT, handler); 
    interruption = 0; 
    while (1) 
    { 
     str = NULL; 
     write(1, "%> ", 3); 
     read_line(&str); 
     if (str) 
      printf("parsing %s\n", str); 
     else 
      printf("skipping...\n"); 
    } 
    return (0); 
} 

私のアプローチでの問題は、私はEnterキーを押したときにだけ読んでいるので、戻らないのCtrl + Cプロンプトを押した後()実際に入力からの読み込みを開始していることです。それは私の学校の割り当てであり、stdinから文字を読むためにread()以外の関数を使うことはできません。

この場合、シェルの動作を再現する正しい方法は何ですか?すべての

+2

あなたは 'read'呼び出しを中断するハンドラを作るために' sigaction'を使う必要があります。 – zwol

+1

[シグナルハンドラでの 'printf()'の使用方法は?](http://stackoverflow.com/questions/16891019/) –

+0

@JonathanLeffler、役に立つリンクをありがとう! – Hemul

答えて

1

まず... NEVER、EVER使用printfやシグナルハンドラ内async-signal-safeであることが保証されていない他の関数。

本当に。ただしないでください。

第2に、signal関数の代わりにsigaction関数を使用してシグナルハンドラをインストールします。

void handler(int sig_num) { 
    (void)sig_num; 
    interruption = 1; 
} 

そして、ここでハンドラをインストールするためのコードです:

struct sigaction action = { 0 }; /* if your compiler frowns at it use {{ 0 }} */ 
action.sa_handler = handler; 
sigaction(SIGINT, &action, NULL); 

今、あなたのプログラムが動作するはずですが、だからここにシグナルハンドラのコードです。

+1

'action'構造体の他の要素が正しくゼロにされていることを確認する必要があります。おそらく 'struct sigaction action = {0};'と書かれていますが、GCCのいくつかのバージョンはこれについて(少なくとも '-Wall'のような挑発の下で)文句を言っています。 –

+0

ありがとうございます。私はイニシャライザを追加しました。 – nsilent22

+0

ありがとうございました!それは私を助けた。 – Hemul

関連する問題