46975 (588456), страница 3
Текст из файла (страница 3)
3.1.3. Модуль BINASC.asm
Мови високого рівня надають програмісту можливість безпосередньо зчитувати і виводити числові значення. Нажаль, мова асемблера таких інструментів не має. В основній програмі значна частина роботи пов’язана з виводом із деякого буфера даних на екран . Однак дані в буфері зберігаються у вигляді двійкових слів того чи іншого типу. З'являється необхідність перетворення двійкових даних у ASCII-рядки, щоб у подальшому їх можна було вивести на екран. Дану проблему і покликані вирішити функції модуля BINASC.asm. Модуль складається із чотирьох функцій: допоміжних функцій HexDigit (перетворення чотирьохбітового значення у ASCII-цифру) і NumToAscii (перетворення беззнакового двійкового числа у ASCII-рядок), а також двох функцій BinToAscHex і BinToAscDec, які встановлюють систему числення і викликають вищезгадані функції.
Слід зазначити, що функція BinToAscDec зручна для перетворення і подальшого виводу чисел типу "слово" у вигляді десяткового числа.
Функцію BinToAscHex можна використовувати для виводу подвійного слова у вигляді шістнадцятирічного числа, послідовно перетворюючи і виводячи спочатку молодші два, а потім і старші байти, на екран.
Це дозволяє вирішити проблему обробки чотирьохбайтових даних, оскільки звичайні регістри є двохбайтовими і перетворення такого числа у, наприклад, десяткове представлення є проблематичним.
Код програмного модуля BINASC.asm приведено нижче:
IDEAL
MODEL small
ASCnull EQU 0 ; нульовий ASCII-символ
DATASEG
CODESEG
PUBLIC HexDigit, NumToAscii
PUBLIC BinToAscHex, BinToAscDec
; -------------------------------------------------------------------------------------------
; HexDigit перетворює чотирьохбітове значення в ASCII-цифру
; -------------------------------------------------------------------------------------------
; Вхід dl значення від 0 до 15
; Вихід dl шістнадцятирічний еквівалент ASCII-цифри
; Регістри dl
; -------------------------------------------------------------------------------------------
PROC HexDigit
cmp dl, 10 ; перевірка, чи є dl < 10
; (тобто менше шістнадцятирічного 'А')
jb @@10 ; якщо так, то перехід
add dl, 'A'-10 ; перетворити в A, B, C, D, E або F
ret ; повернення до викликаючої програми
@@10:
or dl, '0' ; перетворити в числа від 0 до 9
ret ; повернення до викликаючої програми
ENDP HexDigit
; -------------------------------------------------------------------------------------------
; NumToAscii перетворює беззнакове двійкове значення у ASCII-рядок
; згідно із заданою системою числення
; -------------------------------------------------------------------------------------------
; Вхід ax двохбайтове число, яке перетворюється
; bx основа системи числення результату (2 – двійкова,
; 10 – десяткова, 16 – шістнадцятирічна)
; cx мінімальна кількість цифр, що виводяться
; di адреса рядка для результату
; Вихід di вказує на новостворений рядок із результатом
; Регістри не має
; -------------------------------------------------------------------------------------------
PROC NumToASCII
push dx ; збереження змінюваних регістрів
push di
push si
xor si, si ; встановити лічильник цифр у стеку в 0
jcxz @@20 ; якщо cx = 0, то перехід
@@10:
xor dx, dx ; обнуління dx; ax розширюється до
; 32-х-бітного dxax
div bx ; в ax результат ділення на bx, в dx залишок
call HexDigit ; перетворення числа в dl в ASCII-пару
push dx ; збереження цифри в стеку
inc si ; збільшення лічильника цифр у стеку
loop @@10 ; виконувати цикл, доки не оброблена
; мінімальна кількість цифр
@@20:
inc cx ; встановити cx=1, якщо не усі цифри
; оброблені
or ax, ax ; перевірка ax на обробку всіх цифр
jnz @@10 ; якщо ax≠a, продовження перетворень
mov cx, si ; в cx поміщується кількість цифр у стеку
jcxz @@40 ; пропуск наступного циклу, якщо cx=0
cld ; автоматичне збільшення di
@@30:
pop ax ; в ax поміщується цифра із стеку
stosb ; запис цифри в рядок і збільшення di
loop @@30 ; в циклі вивід cx цифр
@@40:
mov [byte di], ASCnull ; записується 0 у кінець рядка
pop si ; відновлення регістрів
pop di
pop dx
ret ; повернення до викликаючої програми
ENDP NumToASCII
; -------------------------------------------------------------------------------------------
; BinTo AscHex перетворює двійкове значення в шістнадцятирічні
; ASCII-рядки
; -------------------------------------------------------------------------------------------
; Вхід ax двохбайтове значення, що перетворюється
; cx мінімальна кількість чисел, що виводиться
; di адреса рядка для результату
; Вихід di вказує на рядок із сформованим результатом
; Регістри не має
; -------------------------------------------------------------------------------------------
PROC BinToAscHex
mov bx, 16 ; в bx встановити основу шістнадцятирічної
; системи числення - 16
call NumToAscii ; перетворення числа із ax в ASCII-рядок,
; на який вказує di
ret ; повернення до викликаючої програми
ENDP BinToAscHex
; -------------------------------------------------------------------------------------------
; BinTo AscHex перетворює двійкове значення в десяткові ASCII-рядки
; -------------------------------------------------------------------------------------------
; Вхід ax двохбайтове значення, що перетворюється
; cx мінімальна кількість чисел, що виводиться
; di адреса рядка для результату
; Вихід di вказує на рядок із сформованим результатом
; Регістри не має
; -------------------------------------------------------------------------------------------
PROC BinToAscDec
mov bx, 10 ; в bx встановити основу десяткової
; системи числення – 10
call NumToAscii ; перетворення числа із ax в ASCII-рядок,
; на який вказує di
ret ; повернення до викликаючої програми
ENDP BinToAscDec
END
Таким чином програмний модуль BINASC.asm дає нам спеціальні функції, що дозволяють перетворити і вивести на екран дані із DTA, що описують файли.
3.2. Розробка основної програми DR.asm
Модулі PARAMS.asm, STRIO.asm і BINASC.asm складають функціональну базу програмних інструментів для розробки основної програми. Згідно із поставленою задачею, програма має знаходити файли, задані маскою, копіювати DTA, що їх описує, у власний буфер, обробляти отримані дані і виводити необхідну інформацію на екран, а потім переходити до наступного файлу, що відповідає масці, доки не обробить всі.
Таким чином задачу можна розбити на 3 частини:
-
Отримання конфігураційних даних із консолі і, при їх відсутності, встановлення стандартної маски файлів;
-
Пошук файлів, що відповідають масці, і заповнення внутрішнього буферу їх DTA (процедура DirEgine);
-
Саме обробка DTA, вивід даних на екран (процедура Action).
Спираючись на викладені міркування, було створено основну програму DR.asm:
IDEAL
MODEL small
STACK 256
FileName EQU 30 ; зміщення імені файлу в буфері dirData
DATASEG
exCode DB 0 ; код виходу
defaultSpec DB '*.*', 0 ; стандартній ASCII-шаблон маски
DTAseg DW ? ; сегмент для DTA
DTAofs DW ? ; зміщення для DTA
dirData DB 43 DUP (?) ; буфер для запису вмісту каталогу
buffer DB 6 DUP (?) ; буфер для збереження проміжних
; ASCII-рядків
point DB ' * ',0 ; ASCII-шаблон зірочки
tit1 DB 'The DIRWUER wersion 1.0',10,13, 'Romanov Alexander Urievich. KIT-13A NTU"KhPI"',10,13,'Copyright (C) 2005 by Romanov Alexander',0 ; інформація о програмі
tabl DB 'Filename OnR Skr Sys Tom Kat Arh Time
Data Size',0 ; заголовок таблиці
CODESEG
EXTRN GetParams:Proc, GetOneParam:Proc, ParamCount:Proc
із params.obj
EXTRN StrLength:Proc, StrWrite:Proc
EXTRN NewLine:Proc, WriteSimv:Proc, StrWrite2:Proc
; із strio.obj
EXTRN BinToAscHex:Proc, BinToAscDec:Proc
; із Binasc.obj
Start:
mov ax, @data ; встановлює в ax адресу сегмента даних
mov es, ax ; встановлює в es адресу сегмента даних
; ------Отримання даних із командного рядка
call GetParams ; отримати параметри із командного рядка
; (ds=PSP)
call NewLine ; перехід на новий рядок
; ------Виведення інформації о програмі
mov di,offset tit1 ; адреса рядка з інформацією о програмі
call StrWrite ; вивід інформації о програмі на консоль
call NewLine ; перехід на новий рядок
; ------Вибір маски
call ParamCount ; отримання в cx число параметрів
mov di, offset defaultSpec ; встановити di вказівником на
; стандартний шаблон маски
or cx, cx ; перевірка cx на наявність 0
jz @@10 ; якщо cx=0, перехід
xor cx, cx ; обнуління cx (номер параметру)
call GetOneParam ; отримати адресу параметра
; ------Виклик підпрограми обробника
@@10:
mov bx, offset Action ; поміщення в bx адреси процедури Action
call DirEngine ; виклик процедури DirEngine розгляду
; каталогу
; ------Завершення роботи
Exit:
call NewLine ; перехід на новий рядок
mov ah, 04Ch ; в ah номер функції виходу із програми
mov al, [exCode] ; в al код виходу
int 21h ; виклик DOS, завершення програми
; -------------------------------------------------------------------------------------------
; DirEngine перегляд каталогу
; -------------------------------------------------------------------------------------------
; Вхід cx:bx адреса підпрограми Action
; ds:di адреса ASCII-рядка для пошуку (маска)
; Вихід викликає процедуру Action при кожному знаходженні
; файла, що відповідає масці
Регістри ax, cx, dl, di
; -------------------------------------------------------------------------------------------
PROC DirEngine
; ------Виведення заголовку таблиці
push di ; збереження di у стеку
mov di,offset tabl ; в di зміщення рядка заголовка таблиці
; ASCII
call StrWrite ; вивід на екран заголовка таблиці
call NewLine
pop di ; відновлення di
; ------Отримання поточного DTA
push es ; збереження змінюваних регістрів
push bx
mov ah, 2Fh ; в ah номер функції DOS отримання DTA
int 21h ; отримати поточний DTA
mov [DTAseg], es ; збереження адреси сегмента DTA
mov [DTAofs], bx ; збереження адреси зміщення DTA
pop bx ; відновлення регістрів
pop es
; ------Встановлення нового DTA в глобальному 43-байтовому буфері dirData
mov dx, offset dirData ; адреса змінної dirData поміщується
; в ds:dx
mov ah, 1Ah ; а ah номер функції DOS встановлення
; DTA
int 21h ; встановлення нового DTA
; ------Перевірка каталогу на співпадіння імен файлів із маскою в ds:dx
mov ah, 4Eh ; в ah номер функції DOS першого
; пошуку
mov cx, 10h ; атрибут файлів і директорій
mov dx, di ; поміщення адреси рядка в ds:dx
jmp short @@20 ; пропуск наступної дії
@@10:
mov ah, 4Fh ; в ah номер функції DOS продовження
; пошуку
@@20:
int 21h ; пошук першого/наступного входження
jc @@99 ; вихід при помилці, або закінченні
call bx ; виклик процедури Action
jmp @@10 ; повтор дій
@@99:
; ------Відновлення початкової адреси DTA
push ds ; збереження ds у стеку
mov ds, [DTAseg] ; встановлення старої адреси DTA в ds:dx
mov dx, [DTAofs]
mov ah, 1Ah ; в ah номер функції DOS встановлення
; DTA
int 21h ; повернення до старої DTA
pop ds ; відновлення ds
ret ; завершення процедури
ENDP DirEngine
; -------------------------------------------------------------------------------------------
; Action виводить дані про файл із буфера dirData
; -------------------------------------------------------------------------------------------
; Вхід dirData DTA файла
; Вихід виводить дані про файл (назву, атрибути, дату/час створення,
; розмір)
; Регістри ax, dl, di, cx
; -------------------------------------------------------------------------------------------
PROC Action
push bx ; збереження регістрів
; ------Вивід імені файлу
mov di, offset dirData + FileName ; в di зміщення початку імені файлу
call StrWrite ; вивід імені на екран
call StrLength ; отримання в cx довжини імені
sub cx, 15 ; виявлення на скільки довжина імені
neg cx ; файлу менше поля із 15 символів
mov dl, ' ' ; в dl символ пробілу
call WriteSimv ; вивести на екран необхідну, для
; доповнення поля із 15 символів,
















