Файл: jourdain_spravochnik_programmista.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 04.07.2020

Просмотров: 3174

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

JNZ PRTR_ERROR ;переход на обработку ошибки

TEST AL,80H ;принтер занят?

JZ NOT_YET ;если занят, то назад

INC BX ;увеличиваем указатель в буфере данных

DEC DX ;DX указывает на регистр данных

JMP NEXTCHAR ;идем на печать следующего символа


Когда установлен бит 4 управляющего регистра принтера, то

разрешено прерывание принтера. Когда используется прерывание, то

программа не должна ожидать сигнала готовности от принтера, неп-

рерывно опрашивая регистр статуса принтера. Вместо этого, прог-

рамма может послать символ и заниматься другими делами; когда

принтер будет готов для приема следующего символа, то он пошлет

сигнал подтверждения (бит 6 регистра статуса на короткое время

будет установлен в 1) и автоматически будет вызвано прерывание

принтера. Процедура обработки прерывания пошлет на принтер сле-

дующий символ и вернет управление в программу, чтобы она могла

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

прерывания. Когда все данные будут выведены, то прерывание должно

отключить себя. Прерывание принтера во многом аналогично коммуни-

кационному прерыванию, которое обсуждается в [7.1.8].



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

полагаться на это свойство для первого адаптера принтера. На

некоторых адапторах оно работает, а на других нет. Только в слу-

чае последовательной/параллельной карты AT Вы может полагаться на

него полностью. Вместо него можно использовать прерывание тайме-

ра, как объяснено в [2.1.7]. Установите микросхему таймера 8253


так, чтобы прерывание происходило медленнее, чем скорость, с

которой принтер обрабатывает данные. Затем напишите процедуру

обработки прерывания, которая посылает на принтер очередной сим-

вол каждый раз, когда происходит прерывание времени суток. Для

того чтобы обеспечить надежную синхронизацию заставьте процедуру

проверять бит занятости принтера регистра статуса (бит 7) и если

принтер еще занят, то пусть процедура не посылает символ.



6.3.2 Выравнивание правого поля.




Реальное выравнивание правого поля заключается в распределении

пробелов, находящихся в конце строки, равномерно по промежуткам

между словами. Некоторые принтеры имеют специальный режим, кото-

рый автоматически осуществляет это выравнивание. Такую возмож-

ность имеет цветной принтер IBM, посылка управляющего кода

27,77,0 заставляет электронику принтера интерпретировать посту-

пающие данные и форматировать их. В других случаях принтер должен

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

режим, когда выводится символ пробела. В графических режимах

ширина пробела может изменяться на размер до 1/6 размера символа.

К сожалению, многие принтеры на некоторое время останавливаются

при переключении между текстовым и графическим режимами, поэтому


такой метод может оказаться слишком медленным. Другой подход

состоит во вставке обычных символов пробела, распределяя их как

можно более равномерно по строке. Более сложный графический под-

ход описан ниже.

Шаги, которые необходимо выполнить для форматирования с вырав-

ниванием правого поля, следующие. Во-первых, из установок формата

страницы должно быть вычислено число символов в строке. Затем

необходимо подсчитать число символов, занимаемое каждым из после-

довательно введенных слов, включая пробелы между словами. Отдель-

ный счетчик должен подсчитывать число пробелов. Когда общая сумма

символов превзойдет 80 (или ту ширину принтера, которая установ-

лена), то последнее слово должно быть отброшено из этой суммы,

вместе с предшествующим ему пробелом. Число оставшихся свободными

позиций в строке умножается на 6, поскольку каждый символ зани-

мает размер шести точек по горизонтали, а получившееся число

делится на число пробелов между словами.

После печати каждого слова принтер устанавливается в графичес-

кий режим 480 точек в строке и посылает на принтер ряд кодов

ASCII 0. Каждый такой байт сдвигает печатающую головку на одну

точку вправо. Посылаемое число должно быть равно шести для обыч-

ного пробела, плюс результат распределения пустого пространства.

Наконец, если остаток от деления ненулевой, то надо добавить по

одному добавочному байту к первым пробелам, до тех пор пока оста-

ток не будет исчерпан.



Для примера рассмотрим случай, когда строка состоит из 12

слов, содержащих 61 букву, плюс 11 пробелов между словами. Это

оставляет в 80-тисимвольной строке 8 свободных позиций. Эти во-

семь позиций, умноженные на 6 точек, составляют 48 точек дополни-

тельного пространства строки. Поскольку в строке 11 пробелов, то

к каждому из них должно быть добавлено по 4 дополнительные точки

и после этого останутся еще 4 лишние точки, которые надо добавить

по одной к первым четырем пробелам. Тогда первые 4 пробела будут

иметь размер 6 точек нормального пробела, плюс добавочные 5, что

в сумме равно 11. Остальные пробелы этой строки будут иметь раз-

мер 10 точек. Чтобы послать эти данные на принтер, подготовьте

сначала код, посылающий на принтер 1 байт ASCII 0, а затем помес-

тите его в цикл, который выполняйте столько раз, сколько нужно

послать таких байтов. На рис. 6-2 показан этот процесс.

В нижеприведенном примере показаны основы выравнивания по

правому полю. Не забудьте об обработке специальных случаев, таких

как слово, которое длиннее строки (напр., длинный ряд тире).

Процедура нуждается в модификации, которая позволяла бы ей иметь

дело со случаем, когда строка содержит всего несколько слов, как

это бывает в конце параграфа. Не позволяйте ей распределить эти

слова равномерно по всей ширине страницы.


Высокий уровень.



В данном примере, BUFFERPTR указывает на место в буфере дан-

ных, с которого начинается следующая строка, выводимая на печать.


100 S$ = "This text will be printed with right justification

using the printer alternately in text modes and graphics modes."

110 STRINGPTR = 1 'указатель в строке данных S$

120 COLUMNS = 1 'счетчик позиции в строке

130 SPACES = 0 'счетчик пробелов в строке

140 '''вычисляем сколько слов помещается в строке

150 C$ = MID$(S$,STRINGPTR,1) 'получаем символ

160 IF C$ <> " " THEN 190 'если не пробел, то вперед

170 LASTSPACE = COLUMNS 'иначе зпоминаем позицию

180 SPACES = SPACES + 1 'увеличиваем число пробелов

190 COLUMNS = COLUMNS+1 'увеличиваем указатель столбца

200 STRINGPTR = STRINGPTR + 1 'увеличиваем указатель данных

210 IF COLUMNS = 81 THEN 230 'уход по концу строки

220 GOTO 150 'иначе к следующему символу

230 IF C$ <> " " THEN 270 'если последний не пробел, то уход

240 COLUMNS = 79 'иначе длина строки равна 79

250 SPACES = SPACES - 1 'отнимаем последний пробел

260 GOTO 340 'идем на вычисление пробелов

270 C$ = MID$(S$,STRINGPTR+1,1) 'проверяем на конец слова

280 IF C$ <> " " THEN 300 'если не пробел, то уход

290 GOTO 340 'иначе на вычисление пробелов

300 COLUMNS = COLUMNS - LASTSPACE 'возвращаемся к концу слова

310 STRINGPTR = STRINGPTR - COLUMNS + 1 'возвращаем указатель

320 COLUMNS = LASTSPACE - 1 'убираем последний пробел

330 SPACES = SPACES - 1 'уменьшаем число пробелов



340 '''вычисляем число точек на пробел

350 EXTRASPACES = 80 - COLUMNS 'вычисляем число пробелов в конце

360 TOTALSPACES = EXTRASPACES + SPACES 'добавляем к пробелам

370 TOTALDOTS = 6*TOTALSPACES 'вычисляем число точек

380 DOTSPERSPC = TOTALDOTS/SPACES 'получаем число точек на пробел

390 EXTRADOTS = TOTALDOTS MOD SPACES 'остаток от деления

400 '''теперь печатаем первую строчку нашего текста

410 OPEN "LPT1:" AS #1 'открываем принтер

420 PRINTPTR = 1 'указатель на начало буфера данных

430 C$ = MID$(S$,PRINTPTR,1) 'берем символ

440 PRINTPTR = PRINTPTR + 1 'увеличиваем указатель

450 IF C$ = " " THEN 500 'если пробел, то на обработку пробела

460 PRINT #1, C$ 'иначе печатаем символ

470 IF PRINTPTR = COLUMNS + 1 THEN 590 'выход по концу строки

480 GOTO 430 'иначе печатаем следующий символ

490 '''вот процедура печати пробелов

500 PRINT #1, CHR$(27) + "K"; 'переход в графический режим

510 NUMBERDOTS = DOTSPERSPC 'вычисляем число байтов ASCII 0

520 IF EXTRADOTS = 0 THEN 550 'если нет добавочных точек, уход

530 NUMBERDOTS = DOTSPERSPC + 1 'иначе добавляем точку

540 EXTRADOTS = EXTRADOTS - 1 'уменьшаем число добавочных точек

550 PRINT #1, CHR$(NUMBERDOTS); 'посылаем число графических байт

560 PRINT #1, CHR$(0); '

570 FOR N = 1 TO NUMBERDOTS: PRINT #1, CHR$(0): NEXT

580 GOTO 430 'пробел окончен, идем на след. символ

590 PRINT #1, CHR$(13) 'в конце печатаем возврат каретки


Низкий уровень.


Соответствующая ассемблерная процедура слишком длинная, чтобы

приводить ее здесь. Она работает в точности так же, как и проце-

дура на Бейсике, за исключением того, что нет необходимости заво-

дить отдельную переменную, чтобы хранить строку. Нужно просто

установить указатели на начало и конец строки, которую надо напе-

чатать в буфере данных.



6.3.3 Пропорциональная печать.




Вообще говоря, пропорциональная печать требует специального

принтера, который хранит в ПЗУ информацию о ширине каждого симво-


ла. Цветной принтер IBM имеет режим пропорциональной печати,

который включается последовательностью 27,78,1, а выключается -

27,78,0. Программа, которая форматирует вывод на такой принтер,

должна знать информацию о ширине каждого символа (ее можно найти

в документации). Имея эту информацию, она может вычислить сколько

слов поместится на одной строке.

Имейте ввиду, что некоторые матричные принтеры автоматически

выводят пропорциональный текст в режиме за два прохода. Если

слова в строке разделяются добавочными пробелами в графическом

режиме, то принтер может переходить ко второму проходу после

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

строку. Поскольку принтеры относительно медленно меняют направле-



ние перемещения печатающей головки, то в этом случае печать текс-

та, выравненного по правому краю, в пропорциональном режиме может

занимать очень много времени и оказывается непосильной ношей для

принтера. Эта проблема не возникает при однонаправленной пропор-

циональной печати. Отметим, что цветной принтер IBM может автома-

тически комбинировать пропорциональную печать с автоматическим

выравниванием правого края, что делает специальное программирова-

ние ненужным.

Изощренные программисты могут заставить любой графический

принтер печатать в пропорциональном режиме. Программа должна

иметь в памяти картину битов для каждого символа (см. [6.3.4]).

Вместо того, чтобы посылать на принтер код ASCII, который вызы-

вает изображение символа из ПЗУ, используется данная цепочка

битов для создания графического изображения строки текста. Затем

вся нужная строка данных выводится на принтер в графическом режи-

ме. Этот подход расходует много памяти на хранение графических

образов символов, однако он позволяет полностью контролировать

выводимое изображение.


Высокий уровень.


В данном примере включается режим пропорциональной печати, а

затем выводится первая строка выходных данных программы. Ширина

пропорционального шрифта считывается в массив FONTWIDTH из после-

довательного файла.


100 '''считываем массив ширин шрифта

110 DIM FONTWIDTH(127) 'отводим массив для ширин

120 OPEN "FONTS" FOR INPUT AS #1 'открываем файл ширин

130 FOR N = 32 TO 127 'хранятся ширины для кодов 32-127

140 INPUT #1, FONTWIDTH(N) 'читаем ширину из массива

150 NEXT 'следующий элемент

160 '''вычисляем сколько символов поместится в строке

170 CHARPTR = 0 'указатель в буфере

180 LINE$ = "" 'хранит строку для вывода

190 LINELENGTH = 0 'счетчик длины в точках

200 WHILE LINELENGTH <480 'добавляем до заполнения строки

210 C$ = PEEK(BUFFERPTR+CHARPTR) 'берем символ из буфера данных

220 LINELENGTH = LINELENGTH + FONTWIDTH(ASC(C$))

230 LINE$ = LINE$+C$ 'добавляем к строке вывода

240 CHARPTR = CHARPTR+1 'увеличиваем указатель

250 WEND 'на обработку следующего символа

260 '''по концу строки возвращаемся к концу последнего слова

270 IF C$ = "" THEN 310 'если последний пробел, то уход


280 FOR N = LEN(LINE$) TO 1 STEP -1 'идем назад от конца

290 IF MID$(LINE$,N,1) = " " THEN 310 'этот символ пробел?

300 NEXT 'есчли нет, то берем следующий

310 LINELENGTH = N - 1 'если да, то предыдущий - последний

320 '''инициализируем пропорциональную печать и посылаем данные

330 LPRINT CHR$(27);CHR$(78);CHR$(1); 'управляющие коды

340 FOR N = 1 TO LINELENGTH 'для каждого символа

350 LPRINT PEEK(BUFFERPTR+N-1); 'печатаем его

360 NEXT 'и идем на следующий символ



Низкий уровень.


Программа на языке ассемблера должна работать совершенно ана-

логично приведенному бейсиковскому примеру. Одно из преимуществ

ассемблера состоит в том, что для просмотра ширин символов можно

использовать инструкцию XLAT. Поместите символ в AL, DS:DX должны

указывать на таблицу, после чего можно использовать XLAT. Ширина

символа будет возвращена в AL:


;---просмотр ширин символов

LEA SI,DATA_BUFFER ;указываем на буфер данных

LEA BX,WIDTH_TABLE ;указываем на таблицу ширин

MOV AL,[SI] ;получаем байт данных

XLAT WIDTH_TABLE ;теперь его ширина в AL



6.3.4 Печать специальных символов.




Большинство принтеров не поддерживают расширенный набор симво-

лов IBM, однако большинство программ использует специальные сим-

волы псевдографики. Очень полезно иметь возможность печатать эти

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

который имеет графические возможности. Вместо того, чтобы пола-

гаться на ПЗУ принтера, программа должна сама создавать эти сим-

волы и она должна обращаться с принтером определенным образом,

чтобы они были напечатаны на бумаге.

Сама по себе печать специальных символов тривиальна. Просто

разбейте символ на шесть байтов, цепочка битов каждого соответст-

вует структуре точек в каждом из шести столбцов точек, составляю-

щих символ. Например, чтобы напечатать символ горизонтальной

двойной черты, код ASCII которого 205, программа должна вывести

цепочку битов 00100100 шесть раз в режиме 480 точек в строке. Это

количество в точности соответствует ширине символа, поскольку

6/480 равно 1/80 строки. Чтобы перевести принтер именно в этот

графический режим необходимо подать управляющий код 27,75. Затем

пошлите число идущих вслед графических данных, которое передается

в виде пары байт, причем младший байт первый. Наконец, идут сами

6 битов данных, которые в данном случае равны сумме значений

битов 2 и 5 (4 + 32 = 36). Вся последовательность целиком выгля-

дит так: 27, 75, 6, 0, 36, 36, 36, 36, 36, 36. Для более высокого

разрешения могут быть использованы более точные графические режи-

мы; вообще говоря добавочные расходы времени машины ничтожны, по

сравнению со скоростью операций принтера.

Имеется частная проблема, когда символы псевдографики должны

соприкасаться друг с другом по вертикали. Обычно принтеры печа-

тают строку, состоящую из столбца восьми точек, затем спускаются

вниз на высоту 12 точек, оставляя тем самым поле размером в 4