; Вхід di адреса ASCII рядка
; Вихід cx кількість ненульових символів в рядку
; Регістри cx
; -------------------------------------------------------------------------------------------
PROC StrLength
push ax ; зберегти у стеку змінювані
push di ; регістри ax, di
xor al, al ; в al поміщується шуканий символ 0
mov cx, 0ffffh ; в cx максимальна глибина пошуку
cld ; автоматичне збільшення di
repnz scasb ; шукати al, доки [di] або cx не стане 0
not cx ; логічне заперечення cx
dec cx ; зменшення cx на 1 – довжина рядка
pop di ; відновлення регістрів
pop ax
ret ; повернення до викликаючої програми
ENDP StrLength
; -------------------------------------------------------------------------------------------
; StrWrite вивід рядка на стандартний пристрій виводу
; StrWrite2 вивід заданої кількості символів рядка на консоль
; -------------------------------------------------------------------------------------------
; Вхід di адреса ASCII рядка
; cx кількість записуваних символів (для StrWrite2)
; Вихід символьний рядок виводиться на стандартний пристрій
; виводу
Регістри cx (для StrWrite)
; -------------------------------------------------------------------------------------------
PROC StrWrite
call StrLength ; встановити в cx довжину рядка
PROC StrWrite2 ; друга змінна точка входу
push ax ; збереження змінюваних регістрів
push bx
push dx
mov bx, 1 ; задання стандартного пристрою виводу
mov dx, di ; адресація ASCII рядка в ds:dx
mov ah, 40h ; в ax номер функції, що виконує запис
; в файл або на пристрій виводу
int 21h ; виклик 21 переривання DOS
pop dx ; відновлення збережених регістрів
pop bx ; із стеку
pop ax
ret ; повернення до визиваючої програми
ENDP StrWrite2
ENDP StrWrite
; -------------------------------------------------------------------------------------------
; NewLine перейти на новий рядок на стандартному пристрої виводу
; -------------------------------------------------------------------------------------------
; Вхід не має
; Вихід на пристрій виводу посилаються символи повернення
; каретки і прогону рядка
; Регістри не має
; -------------------------------------------------------------------------------------------
PROC NewLine
push ax ; збереження регістрів у стек
push dx
mov ah, 2 ; в ah номер функції виводу символу у DOS
mov dl, ASCcr ; в dl символ повернення каретки
int 21h ; вивести символ повернення каретки
mov dl, ASClf ; в dl символ прогону рядку
int 21h ; вивести символ прогону рядку
pop dx ; відновлення регістрів із стеку
pop ax
ret ; повернення до викликаючої програми
ENDP NewLine
; -------------------------------------------------------------------------------------------
; WriteSimv вивід на стандартний пристрій виводу заданий символ
; визначену кількість разів
; -------------------------------------------------------------------------------------------
; Вхід dl код символу
; cx кількість виводів символу
; Вихід на пристрій виводу задану кількість разів посилається
; переданий символ
;Регістри не має
; -------------------------------------------------------------------------------------------
PROC WriteSimv
push ax ; збереження регістрів
push cx
@@01:
mov ah,02 ; в ah номер функції DOS запису символу
int 21h ; вивести заданий символ
loop @@01 ; повторювати доки cx≠0
pop cx ; відновлення регістрів
pop ax
ret ; повернення до викликаючої програми
ENDP WriteSimv
END
Функції, надані програмним модулем STRIO.asm, є зручними і простими інструментами виводу інформації на стандартний пристрій виводу і будуть використані в основній програмі.
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 частини:
1) Отримання конфігураційних даних із консолі і, при їх відсутності, встановлення стандартної маски файлів;
2) Пошук файлів, що відповідають масці, і заповнення внутрішнього буферу їх DTA (процедура DirEgine);
3) Саме обробка 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