Литмир - Электронная Библиотека
Содержание  
A
A

$ <b>./menu2</b>

Choice: Please select an action

a — add new record

d — delete record

q — quit

<b>q</b>

You have chosen: q $ <b>./menu2 &gt; file</b>

You are not a terminal! $

Как это работает

В новом фрагменте программного кода функция

isatty
применяется для проверки связи стандартного вывода с терминалом и прекращения выполнения программы при отсутствии этой связи. Это тот же самый тест, который командная оболочка использует для решения, нужно ли выводить строки приглашения. Возможно и довольно обычно перенаправление и
stdout
, и
stderr
с терминала на другое устройство. Вы можете направить поток ошибок в другой файл:

$ <b>./menu2 &gt;file 2&gt;file.error</b>

$

или объединить оба выводных потока в одном файле:

$ <b>./menu2 &gt;file 2&gt;&amp;1</b>

$

(Если вы не знакомы с перенаправлением вывода, прочтите еще раз главу 2, в которой мы более подробно рассматриваем синтаксические правила, связанные с ним.) В данном случае вам нужно отправить сообщение непосредственно на терминал пользователя.

Диалог с терминалом

Если нужно защитить части вашей программы, взаимодействующие с пользователем, от перенаправления, но разрешить его для других входных и выходных данных, вы должны отделить общение с пользователем от потоков

stdout
и
stderr
. Это можно сделать, непосредственно считывая данные с терминала и прямо записывая данные на терминал. Поскольку ОС Linux с самого начала создавалась, как многопользовательская система, включающая, как правило, множество терминалов, как непосредственно подсоединенных, так и подключенных по сети, как вы сможете определить тот терминал, который следует использовать?

К счастью, Linux и UNIX облегчают жизнь, предоставляя специальное устройство /dev/tty, которое всегда является текущим терминалом или сеансом работы в системе (login session). Поскольку ОС Linux все интерпретирует как файлы, вы можете выполнять обычные файловые операции для чтения с устройства /dev/tty и записи на него.

В упражнении 5.3 вы исправите программу выбора пункта меню так, чтобы можно было передавать параметры в подпрограмму

getchoice
и благодаря этому лучше управлять выводом. Назовите ее menu3.c.

Упражнение 5.3. Применение /dev/tty

Загрузите файл menu2.c и измените программный код так, чтобы входные и выходные данные приходили с устройства /dev/tty и направлялись на это устройство.

#include &lt;stdio.h&gt;

#include &lt;unistd.h&gt;

#include &lt;stdlib.h&gt;

char *menu[] = {

 &quot;a — add new record&quot;, &quot;d — delete record&quot;, &quot;q - quit&quot;, NULL,

};

<i>int getchoice(char* greet, char* choices[], FILE* in, FILE* out);</i>

int main() {

 int choice = 0;

<i> FILE* input;</i>

<i> FILE* output;</i>

 if (!isatty(fileno(stdout))) {

<i>  fprintf(stderr, &quot;You are not a terminal, OK.\n&quot;);</i>

 }

<i> input = fopen(&quot;/dev/tty&quot;, &quot;r&quot;);</i>

<i> output = fopen(&quot;/dev/tty&quot;, &quot;w&quot;);</i>

<i> if (!input || !output) {</i>

<i>  fprintf(stderr, &quot;Unable to open /dev/tty\n&quot;);</i>

<i>  exit(1);</i>

<i> }</i>

 do {

<i>  choice = getchoice(&quot;Please select an action&quot;, menu, input, output);</i>

  printf(&quot;You have chosen: %c\n&quot;, choice);

 } while (choice != 'q');

 exit(0);

}

<i>int getchoice(char* greet, char *choices[], FILE* in, FILE *out) {</i>

 int chosen = 0;

 int selected;

 char **option;

 do {

<i>  fprintf(out, &quot;Choice: %s\n&quot;, greet);</i>

  option = choices;

  while (*option) {

<i>   fprintf(out, &quot;%s\n&quot;, *option);</i>

   option++;

  }

<i>  do {</i>

<i>   selected = fgetc(in);</i>

<i>  } while(selected == '\n');</i>

  option = choices;

  while (*option) {

   if (selected == *option[0]) {

    chosen = 1;

    break;

   }

   option++;

  }

  if (!chosen) {

<i>   fprintf(out, &quot;Incorrect choice, select again\n&quot;);</i>

  }

 } while (!chosen);

 return selected;

}

Теперь, когда вы выполните программу с перенаправленным выводом, вы сможете увидеть строки приглашения, а стандартный вывод программы (обозначающий выбранные пункты меню) перенаправляется в файл, который можно просмотреть позже:

82
{"b":"285844","o":1}