Выход из режима прослушивания чтения при нажатии Ctrl + c в C

Переписываю шелл на C и столкнулся с проблемой.

При написании команды — например, echo "this — мы получили новое приглашение («dquote>», в zsh), и мы можем выйти из него с помощью «Ctrl + c» и вернуться к нашей последней командной строке.

я застрял там; Я просто не могу выйти из своей функции чтения (послушайте «dquote>»), я пытался записать на стандартный вывод EOF при нажатии «ctrl + c», но он не читает его.

Я переключился на неканонический режим. Я ловлю сигнал с signal(SIGINT, sig_hand);

затем я выполняю эту часть кода, когда сигнал пойман:

static void sig_hand(int sig)
{
    if (g_shell.is_listen_bracket) // if is the first prompt or no
        putchar(4); // EOT
    else
    {
        putstr("\n");
        print_prompt();
    }
}

и моя функция чтения:

int     j;
char    command[ARG_MAX];
char    buff[3];

j = -1;
while (1)
{
    bzero(buff, 3);
    read(0, buff, 3);
    if (buff[0] == 4 && !buff[1] && !buff[2])
        return (ctrl_d(shell));
    else if (isprint(buff[0]) && !buff[1] && !buff[2]) // if is between 32 and 126 (ascii)
    {
        command[++j] = buff[0];
        putchar(buff[0]);
    }
}
command[++j] = '\0';
return (strdup(command));

Итак, мой код ожидает «read (0, buff, 3);», и я хочу выйти из него при нажатии ctrl + c.

Спасибо за помощь !


person Victor D    schedule 22.03.2017    source источник
comment
спасибо за ваш ответ, но это школьный проект, и эта функция не разрешена.   -  person Victor D    schedule 22.03.2017
comment
Непонятно, в чем ваша проблема, поскольку вы не показали никакого кода и не обсудили, манипулируете ли вы обработкой сигналов или настройками терминала в своей оболочке. Вы можете найти канонический и неканонический ввод терминала полезным, или это может быть отвлекающим маневром. Вам следует обсудить (а лучше показать), как ваша оболочка обрабатывает сигналы. Control-C должен генерировать SIGINT; если ваша оболочка игнорирует это или неправильно обрабатывает это, это может объяснить вашу проблему.   -  person Jonathan Leffler    schedule 22.03.2017
comment
Ну, технически это не функция, хотя кажется.   -  person wildplasser    schedule 22.03.2017
comment
Я отредактировал свой вопрос. (Ctrl + D работает хорошо)   -  person Victor D    schedule 22.03.2017
comment
Если Ctrl+D работает хорошо, вы должны работать в DOS/Windows.   -  person wildplasser    schedule 22.03.2017
comment
Примечание. read(0, buff, 3) может возвращать {-1,0,1,2 или 3} Обрабатывать все случаи. Также: command[++j] = buff[0]; должно минимум быть command[j++] = buff[0]; (плюс вы можете зациклить на 'j' до возвращаемого значения, которое вы получили от read() )   -  person wildplasser    schedule 22.03.2017


Ответы (1)


Не думайте о EOF как о символе, который вы можете 'напечатать в stdout', это состояние, в котором может находиться дескриптор файла, и это означает, что больше не поступают данные. Чтобы перевести stdout в состояние EOF, вам придется вызвать close(), что, скорее всего, не то, что вам нужно.

Осторожно - 0x04 на самом деле EOT, конец передачи.

В любом случае, почему вы хотите отправить EOT в stdout вашего приложения? Если бы это вело себя так, как вы думаете, то эмулятор терминала (или что-то еще, что подключено к вашему стандартному выходу) завершил бы работу, а не вашу оболочку, и уж точно не вернул бы вашу оболочку из 'ожидания больше ввода" в состояние "ожидание ввода".

Вам нужно обработать ^C в обработчике сигнала и соответствующим образом настроить состояние вашей оболочки, заставив ее отказаться от текущего режима ввода и перерисовать базовую подсказку.


Изменить: вам нужно помнить, что ваша «оболочка» записывает текст (вывод) и управляющие символы в эмулятор терминала, а эмулятор терминала записывает текст (ввод) и управляющие символы в вашу «оболочку». '.

Если вы хотите изменить подсказку с dquote> на mysh$, то вы должны обновить терминал, записав в него новую подсказку.

Чтобы отслеживать, что вы сейчас делаете, лучше всего использовать машину состояний подход. У вас может быть несколько состояний, в том числе:

  1. INPUT_WAITING
  2. INPUT_WAITING_CONT
  3. COMMAND_RUN

Находясь в состоянии INPUT_WAITING, вы печатаете приглашение mysh$ и обрабатываете ввод. Когда получена новая строка, вы должны решить «есть ли у нас вся информация?», прежде чем перейти к состоянию INPUT_WAITING_CONT, если нет, или к состоянию COMMAND_RUN, если да.

Состояние INPUT_WAIT_CONT распечатывает приглашение dquote> и выполняет аналогичные действия... 'достаточно ли информации?' Да: COMMAND_RUN, Нет: INPUT_WAIT_CONT.

Затем вам нужно вернуться к состоянию INPUT_WAIT и перерисовать подсказку mysh$, когда пользователь нажимает ^C или когда выполнение команды завершено.

person Attie    schedule 22.03.2017
comment
Я перепутал EOF и EOT, извините. Ctrl + d отправляет EOT, который считывается функцией read. Поэтому я подумал, что если я смогу написать EOT, read прочитает его, и я смогу правильно его обработать, как ^C. отказаться от текущего ввода как? Это мой вопрос. - person Victor D; 23.03.2017
comment
Ctrl + d send a EOT which is read by read function Не в UNIX. Обычно ^D обрабатывается драйвером терминала (и транслируется в событие EOF), программа чтения никогда не видит 0x04. - person wildplasser; 23.03.2017