Фичи консольного режима

Персональный блог одноименного форумчанина. Человека и парохода, не побоюсь этого сравнения :)

Модератор: tyomitch

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Фичи консольного режима

Сообщение tyomitch » 17.06.2006 (Сб) 10:36

Самое сложное в консольном режиме -- это корректный ввод и вывод.

* Со вводом тяжелее всего понять, где он кончается. Если STDIN -- это консоль, то прекращать ввод нужно по символу \032. Если это файл, как при перенаправлении из файла, то нужно ждать EOF -- т.е. читать, пока ReadFile не вернёт 0 байтов. Если это труба, как при перенаправлении символом |, то читать нужно до разрыва трубы, т.е. до ошибки ERROR_BROKEN_PIPE -- потому что в этом случае конец файла наступает каждый раз, как только заканчиваются уже положенные в трубу с другого конца данные.

Определить, что является нашим STDIN, отчасти позволяет функция GetFileType -- за тем исключением, что она не позволяет различить консоль и "другое символьное устройство", такое как LPT-порт. Поэтому для проверки хендла на консольность используется полудокументированная фича: проверка двух младших битов хендла. Можете взять на заметку, что установлены оба младших бита бывают только в консольных хендлах.


* С выводом возникают проблемы чуть другого рода: как выводить юникодный текст? Если STDOUT -- это консоль, то можно просто вызывать WriteConsoleW. А если это файл?

Выбранное мной решение -- писать текст в файл непосредственно в Юникоде, при этом, если файл создаётся заново (GetFileSize для STDOUT возвращает 0), то в его начало дописывается Byte-Order Mark (U+FFFE), по которому стандартные программы (например, Блокнот) смогут понять, что в файле записан юникодный текст.

Я не могу, однако, вызывать для вывода юникодного текста WriteConsoleW и WriteFile с одними и теми же параметрами, потому что WriteFile измеряет размер выводимой строки в байтах, а WriteConsoleW -- в символах. Так что приходится делать поправку ещё и на это.


* Последняя отмеченная у меня фича -- это направление вывода в гуёвый диалог. Когда я писал Tiger2, сначала я создал консольную версию; она направляла весь вывод в STDOUT по мере его появления. Потом, когда я нарисовал диалог, у меня не возникло желания переделывать весь готовый и отлаженный код вывода затем, чтобы буферизовать его в некой строке и затем посылать в нужное место (либо в STDOUT, либо в диалог).

Вместо этого я пошёл по пути "выливаем воду из чайника, чем сводим задачу к уже решённой". При создании диалога создаётся труба; её write-end записывается в качестве STDOUT, а из read-end читает в свой буфер отдельный поток, чтобы не замораживать интерфейс на время ожидания результатов. (Кстати, диалог обслуживается двумя потоками: один на GUI, другой на расчёт хеша.)
Изображение

Вернуться в Tyomitch

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 10

    TopList