Главная страница  Межпроцессное взаимодействие (состязание) 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 [ 102 ] 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

Если нет, функция быстро завершается. После этого она входит в свой главный цикл. Этот цикл очень похож на цикл в функции in transfer в файле tty.c. При помощи вызовов phys copy локальный буфер объемом 64 символа заполняется данными из пользовательского буфера, обновляются указатель на начало буфера и счетчик символов, после чего все символы из локального буфера переносятся в массив cons->c ramqueue, дополненные байтом атрибутов. Позже эти данные будут выведены на экран посредством flush. Как вы могли видеть на рис. 3.26, существует несколько способов осуществить эту передачу. Можно вызывать out char для каждого символа, но лишь в расчете на ситуацию, когда при выводе символов не потребуется ни одна из специальных функций out char, не выводится ESC-последовательность, ширина экрана не будет превышена и cons->c ramqueue не заполнена. Если все функции out char не требуются, символ можно поместить в cons->c ramqueue напрямую, вместе с байтом атрибутов (поле cons->c attr), а все переменные cons->c rwords (индекс в очереди), cons->c column (отслеживает текущий столбец на экране) и tbuf (указатель на буфер) инкрементируются. Прямой перенос символов в cons->c ramqueue соответствует штриховой линии с левой стороны рис. 3.26. При необходимости вызывается out char. Этот вызов занимается всеми подсчетами и по мере надобности вызывает функцию flush, которая выполняет окончательную передачу данных в видеопамять. Перекачка данных из пользовательского буфера в локальный производится до тех пор, пока значение в поле tp->tty outleft говорит о том, что еще есть символы и не установлен флаг tp->tty inhibited. Если передача останавливается, в результате завершения вызова write или потому, что установлен флаг tp->ttyjnhibited, то чтобы передать последние символы из очереди в память экрана, опять вызывается flush. Когда операция завершена, при помощи tty reply отправляется ответное сообщение (операция завершена, когда поле tp->tty outleft содержит нулевое значение).

В дополнение к вызовам cons write из handle events, символы на консоль могут выводить функции echo и rawecho в аппаратно-независимой части задачи терминала. Если текущим терминалом является консоль, косвенные вызовы через указатель tp->tty echo перенаправляются к функции cons echo. Она делает свою работу, вызывая out char и затем flush. Пользователь вводит данные символ за символом, и ему предпочтительно, чтобы эхо отображалось сразу же, без видимой задержки, поэтому помещать символы в очередь было бы недостаточно.

Итак, теперь мы добрались до функции out char. Сначала она проверяет, вводится ли сейчас ESC-последовательность, вызывая parse escape, и если это так, немедленно завершается. В противном случае управление передается в конструкцию switch, которая проверяет различные особые случаи: нулевой символ, символ забоя, символ звонка и т. п. Несложно проследить, как обрабатывается большая часть этих ситуаций. Самые сложные варианты - символы перевода строки и табуляции, поскольку они сложным образом меняют координаты курсора на экране и могут вызвать прокрутку. Последняя проверка выполняется на код ESC. Если он обнаруживается, устанавливается флаг cons->c esc state и последующие вызовы out char будут перенаправляться в parse escape до тех пор, пока последовательность не завершится. Если превышена ширина экрана, при необходимости делается прокрутка экрана и вызывается flush. Прежде чем поместить символ



в выходную очередь, проверяется, заполнена ли она, и если заполнена, вызывается flush. Как мы видели ранее в cons write, при занесении символа в очередь необходимо учесть это, обновив значения нескольких переменных.

Далее следует функция scrolLscreen. Она выполняет как прокрутку вверх, то есть нормальную прокрутку, ожидаемую при заполнении нижней строки экрана, и прокрутку вниз, которая необходима при попытке установить курсор выше верхней границы экрана. Для каждого направления прокрутки возможны три метода. Это проистекает из требования поддержки различных типов видеокарт.

Мы рассмотрим случай прокрутки вверх. Сначала переменной chars присваивается значение, равное размеру экрана минус 1. Когда прокрутка делается программно, для ее выполнения достаточно одного вызова функции vid vid copy, которая скопирует chars символов на одну строку ниже в памяти. Эта функция умеет переходить в начало области при достижении ее конца, и наоборот. Так, если ей указано скопировать блок памяти, начало которого выходит за верхнюю фаницу памяти, то не укладывающиеся в область видеопамяти данные будут взяты из ее нижней части, то есть видеопамять рассматривается как круговой (замкнутый) массив. Простота этого вызова не скрывает такой недостаток, как низкая скорость выполнения операции. Даже несмотря на то, что подпрофамма vid vid copy написана на языке ассемблера (ее код хранится в файле klib386.s), для ее выполнения необходимо скопировать 3840 байт, что довольно большая работа даже для тщательно вылизанного кода.

Профаммная прокрутка никогда не выбирается по умолчанию. Пользователь может включить ее, если аппаратная не работает или по каким-то причинам нежелательна. Одна из таких причин - желание использовать команду screendump, чтобы иметь возможность сохранить экранную память в файл. При использовании аппаратной прокрутки эта команда не дает ожидаемого результата, так как начало видеопамяти наверняка не совпадает с началом видимой на экране области. Если выбрана не профаммная прокрутка, то в первой части составного условия проверяется значение переменной wrap. Эта переменная содержит TRUE для старых экранов, поддерживающих аппаратную прокрутку, и, если проверка не выполняется, в ветви else производится простая аппаратная прокрутка. Соответственно, значение указателя на начало экранной области, используемого видеоконтроллером, cons->c orig, изменяется так, чтобы указывать на первый символ той строки, которая окажется наверху экрана. Если wrap равна FALSE, проверка составного условия продолжается. Теперь проверяется, поместится ли перемещаемый блок памяти в той области памяти, которая отведена для консоли. Если нет, то при помощи vid vid copy содержимое копируется физически, в начало области видеопамяти. Если же адреса не перекрываются, делается простая аппаратная прокрутка, всегда практикуемая в более старых видеоконтроллерах. Для этого изменяется значение cons->c org, и новое значение указателя на начало области заносится в нужный управляющий регистр контроллера. Соответствующий вызов делается позднее, как и вызов, очищающий нижнюю строку экрана.

Код прокрутки вниз очень похож на тот, что прокручивает экран вверх. В конце нижняя строка экрана очищается при помощи вызова mem vid copy, обновляются значения некоторых переменных и делается проверка того, что координаты



курсора имеют приемлемые значения. При необходимости, если, например, ESC-последовательность переместила курсор на столбец с отрицательным номером, координаты корректируются. В завершение вычисляется, где должен быть курсор, и это значение сравнивается с cons->c cur. Если значения не совпадают, а обрабатываемая память принадлежит текущей виртуальной консоли, то, чтобы записать корректные значения в регистр контроллера, делается вызов подпрограммы set 6845.

Число или


Не ESC

Вызов do escape

Не число или ;

Накопление числовых аргументов

Рис. 3.28. Конечный автомат для обработки ESC-последовательностей

На рис. 3.28 показано, как можно представить разбор ESC-последовательностей при помощи конечного автомата. Этот автомат реализуется подпрофаммой parse escape, вызываемой в начале кода out char, если поле cons->c esc state не равно нулю. Сам символ ESC обнаруживается в out char, и переменная cons-> c esc state переводится в состояние 1. Когда получен следующий символ, функция parse escape подготавливается к обработке дальнейшей информации: значение ХО заносится в поле cons->c escJntro, указатель на начало массива параметров, cons->c esc paramv[0], заносится в cons->c esc paramp, а сам массив параметров заполняется нулями. Затем проверяется первый символ, следующий за ESC. Допустимыми значениями являются [ и М . В первом случае [ копируется в переменную cons->c escJntro, и автомат переходит в состояние 2. Во втором случае вызывается функция do escape, которая выполняет действие, и автомат возвращается в состояние 0. Если же за BSC последовал недопустимый символ, он игнорируется, а дальше все обрабатывается как обычно.

Когда автомат получает последовательность ESC [, следующий полученный символ обрабатывается в состоянии 2. В этой точке возможны три варианта. Если на входе числовой символ, его значение добавляется к увеличенному в десять раз значению параметра, на который в текущий момент указывает cons->c esc paramp (сначала этот указатель ссылается на cons->c esc paramv[0], и все параметры равны нулю). Здесь состояние автомата пока не меняется. Это позволяет передавать параметры в виде последовательности чисел, накапливая их итог, хотя максимальное значение, в текущий момент распознаваемое MINIX, равно 80. Оно может быть использовано в последовательности, перемещающей курсор в указанную позицию на экране. Если получено не число, а точка с запятой, тогда



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 [ 102 ] 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.