Как отправить символ новой строки на стандартный ввод в c и позволить fgets (cmdline, MAXLINE, stdin) получить его? - PullRequest
1 голос
/ 25 марта 2020

В настоящее время я создаю программу оболочки в c. Мне необходимо использовать сигналы для захвата сигнала CTRL- C и вывода «Использовать выход», чтобы попросить пользователя использовать мою встроенную команду выхода для выхода из myshell. Я добавил обработчик сигнала для вывода «Использовать выход», но не смог заставить мою оболочку выводить [/]> после «Использовать выход».

Ожидаемый результат:

[assignment2] > ^C
Use exit
[assignment2] > ^C
Use exit
[assignment2] > ^C
Use exit
[assignment2] > exit

Однако, вывод моей программы не имел выхода [assignment2]> после каждого ^ C Используйте выход, мне нужно было бы нажать Enter на моей клавиатуре, чтобы [assignment2]> отобразился:

[assignment2] > ^C
Use exit
^C
Use exit
^C
Use exit
[assignment2] > exit

Я подозреваю, что после обработки сигнала программа все еще застревает в fgets (cmdline, MAXLINE, stdin), так что программа не продолжает до начала, пока l oop не распечатает [assignment2] > как показано ниже в моем коде:

Мой код для функции сигнала myshell и handle:

// Signal handler funciton
void handler(int signal){
   switch(signal) {
      case SIGINT:
        write(STDOUT_FILENO, "\nUse exit\n", 10);
        break;
      case SIGTSTP:
        write(STDOUT_FILENO, "\nUse exit\n", 10);
        break;
      case SIGQUIT:
        write(STDOUT_FILENO, "\nUse exit\n", 10);
        break;
}

int main(){
   // Add signal handler
   if (signal(SIGINT, handler) == SIG_ERR) {
      perror("signal");
    } else if (signal(SIGTSTP, handler) == SIG_ERR){
      perror("signal");
    } else if (signal(SIGQUIT, handler) == SIG_ERR){
      perror("signal");
    }

    // ...... init cmdline and cwd char

    while(1){
       char dir[MAXPATH];
       getcwd(cwd, sizeof(cwd));
       printf("[%s] > ", parsecwd(cwd));

       if (get_cmd_line(cmdline) == -1) // The program is stuck inside this funciton
            continue; /* empty line handling */

        eval(cmdline); /* Evaluate and process the cmd input*/
    }
}


int get_cmd_line(char *cmdline)
{
    int i;
    int n;
    if (!fgets(cmdline, MAXLINE, stdin))  // The program is stuck in this fgets
        return -1;
    // Ignore the newline character
    n = strlen(cmdline);
    cmdline[--n] = '\0';
    i = 0;
    while (i < n && cmdline[i] == ' ') {
        ++i;
    }
    if (i == n) {
        // Empty command
        return -1;
    }
    return 0;
}

Я попытался добавить запись (STDIN_FILENO, "\ n", 1) в обработчик сигнала как таковой, чтобы попытаться передать новую строку в fgets (cmdline, MAXLINE, stdin), чтобы он возвращал -1 для продолжения до начала, пока l oop:

switch(signal) {
      case SIGINT:
        write(STDOUT_FILENO, "\nUse exit\n", 10);
        write(STDIN_FILENO, "\n", 1);
        break;
      case SIGTSTP:
        write(STDOUT_FILENO, "\nUse exit\n", 10);
        write(STDIN_FILENO, "\n", 1)
        break;
      ....

Но это не решает проблему, это просто распечатывает новую строку в терминале. * 10 17 *

Есть идеи, как решить эту проблему? Спасибо.

1 Ответ

3 голосов
/ 25 марта 2020

Реализация стандартной библиотеки (glib c) signal использует семантику BSD, что означает, что системные вызовы будут «перезапущены» (вместо сбоя) при возникновении сигнала.

При таком поведении, например, fgets не возвращается после завершения обработчика сигнала.

Для управления этим поведением используйте рекомендованную функцию sigaction. В частности, убедитесь, что флаг SA_RESTART не установлен:

struct sigaction action = { 0 };  // Initialize all members to zero or null

action.sa_handler = &handler;
sigaction(SIGINT, &action, NULL);

Таким образом, функция fgets вернется с указателем NULL, а errno должно быть равно EINTR .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...