46975 (588456), страница 2
Текст из файла (страница 2)
Наприклад:
c > DR c:\windows\*.sys
Тобто даний ввід має викликати програму DR.exe, яка виведе усі файли із розширенням .sys, які знаходяться за адресою c:\windows. Мова асемблера не дає нам вбудованих механізмів реалізації даної можливості, тому виникає необхідність розробки власного програмного модуля для роботи із командним рядком.
При завантаженні exe-файлу command.com створює в пам'яті PSP блок (256 байт), у якому, серед іншої інформації, містить текст, який йде після імені програми (хвіст команди). Перед початком виконання програми адреса PSP міститься в регістровій парі ds:es. Хвіст команди починається зі зміщення 80h (до FFh) і займає 128 байт, при чому перший символ знаходиться за зміщенням 81h, а в 80h міститься кількість символів хвоста команди [4, 6].
Ідея модуля PARAMS.asm в тому, що створюється власний 128-ми байтовий буфер, в який (за допомогою функції GetParams) копіюється хвіст команди, а потім виконується обробка отриманих даних за допомогою функції GetOneParam (отримання адреси параметра за номером) і ParamCount (отримання кількості параметрів).
Параметри в хвості команди розділені пробілами, останній символ – символ повернення каретки.
На основі сказаного було розроблено наступний програмний модуль:
IDEAL
MODEL small
TailLen EQU 0080h ; зміщення байта із довжиною рядка
; параметрів
CommandTail EQU 0081h ; зміщення першого символу рядка
; параметрів
DATASEG
numParams DW ? ; кількість параметрів
params DB 128 DUP (?) ; буфер на 128 байт для хвоста команди
CODESEG
PUBLIC ParamCount, GetParams, GetOneParam
; -------------------------------------------------------------------------------------------
; Separators внутрішня процедура для перевірки на пробіли, табуляцію,
; повернення каретки
; ------------------------------------------------------------------------------------------
; Вхід ds:si адреса символу, що перевіряється
; Вихід ZF=1 символ є пробілом, табуляцією чи поверненням каретки
ZF=1 символ не є роздільником
; Регістри не змінюються
; -------------------------------------------------------------------------------------------
PROC Separators
push ax ; збереження у стеку ax
mov al, [si] ; в al поміщується символ із ds:si
cmp al, 020h ; порівняння al із пробілом
je @@10 ; якщо так, то перехід
cmp al, 009h ; порівняння al із табуляцією
je @@10 ; якщо так, то перехід
cmp al, 00Dh ; порівняння al із символом повернення
; каретки
@@10:
pop ax ; відновлення ax
ret ; повернення до викликаючої програми
ENDP Separators
; -------------------------------------------------------------------------------------------
; ParamCount повертає кількість параметрів у хвості команди
; -------------------------------------------------------------------------------------------
; Вхід не має
; Вихід CX кількість параметрів командного рядка
; Регістри CX
; -------------------------------------------------------------------------------------------
PROC ParamCount
mov cx, [numParams] ; отримати значення змінної numParams
ret ; повернення до викликаючої програми
ENDP ParamCount
; -------------------------------------------------------------------------------------------
; GetParams занесення параметрів командного рядка DOS у буфер
; -------------------------------------------------------------------------------------------
; Вхід ds префікс сегмента програми (PSP) (адресує PSP, якщо його
; не змінювали)
; es сегмент даних програми
; Вихід [params] початок буфера заповненого даними
; [numParams] кількість параметрів
; ds сегмент даних програми
; Регістри al, bx, dx, si, di, ds
; -------------------------------------------------------------------------------------------
PROC GetParams
;------Ініціалізація cx і індексних регістрів si і di
push ax ; збереження регістрів
push bx
push dx
push si
push di
xor ch, ch ; обнуління верхньої половини cx
mov cl, [ds:TailLen] ; в cx довжина параметрів
inc cx ; включити символ повернення каретки
mov si, CommandTail ; адреса параметрів поміщується в si
mov di, offset params ; адреса призначення поміщується в di
; ------Пропуск початкових пробілів і табуляції
@@10:
call Separators ; пропуск пробілів і табуляції
jne @@20 ; перехід, якщо пробілів і табуляції не має
inc si ; пропуск символу
loop @@10 ; цикл, доки не скінчиться обробка, або cx=0
; ------Копіювання параметрів рядка в буфер params
@@20:
push cx ; збереження cx у стеку
jcxz @@30 ; пропуск копіювання, якщо cx=0
cld ; збільшення на 1 si і di
rep movsb ; копіювання cx байтів із ds:si в es:di
; ------Перетворення пробілів в 0 і встановлення numParams
@@30:
push es
pop ds ; ds = es
pop cx ; відновлення cx (довжину)
xor bx, bx ; обнуління bx, лічильник параметрів
jcxz @@60 ; пропуск циклу якщо cx=0 (довжина)
mov si, offset params ; поміщення адреси параметрів в si
@@40:
call Separators ; перевірка на пробіли, табуляцію,
; повернення каретки
jne @@50 ; перехід, якщо не знайдено роздільник
mov [byte ptr si], 0 ; заміна роздільника на 0
inc bx ; збільшення лічильника кількості
; параметрів
@@50:
inc si ; переміщення указника на наступний
; символ
loop @@40 ; виконувати в циклі, доки cx ≠ 0
@@60:
mov [numParams], bx ; збереження в numParams кількість
; параметрів
pop ax ; відновлення регістрів
pop bx
pop dx
pop si
pop di
ret ; повернення до батьківської програми
ENDP GetParams
; -------------------------------------------------------------------------------------------
; GetOneParam отримати адресу параметра за номером
; -------------------------------------------------------------------------------------------
; Вхід cx номер параметра (має бути менше значення в numParams)
; Вихід di зміщення ASCII рядка із потрібним параметром
; Регістри di
; -------------------------------------------------------------------------------------------
PROC GetOneParam
push ax ; збереження регістрів ax і cx
push cx
xor al, al ; обнуління al (ініціалізація шуканого
; значення 0)
mov di, offset params ; адреса параметрів рядка
jcxz @@99 ; якщо номер параметра (cx) дорівнює 0,
; то вихід
cmp cx, [numParams] ; порівняння cx із кількістю параметрів
jae @@99 ; вихід, якщо передано неіснуючого
; параметру
cld ; автоматичне збільшення di
@@10:
scasb ; пошук нульового обмежувача
jnz @@10 ; повтор, доки не знайдено 0
loop @@10 ; повтор, доки в cx не буде 0
@@99:
pop cx ; відновлення регістрів cx, ax
pop ax
ret ; повернення до викликаючої програми
ENDP GetOneParam
END
Таким чином, програмний модуль PARAMS.asm є зручним інструментом для реалізації роботи із командним рядком і буде використаний в основній програмі.
3.1.2. Модуль STRIO.asm
Оскільки важливою частиною основної програми, згідно із завданням, буде вивід текстових рядків на екран, то є необхідність у створенні спеціального програмного модуля, який би містив процедури для обробки і виводу ASCII рядків на екран. Пряме використання функцій DOS в основній програмі є незручним, оскільки є потреба у спрощенні коду для його сприйняття.
З цих міркувань було розроблено програмний модуль STRIO.asm, в якому міститься п’ять спеціальних функцій: StrLength (визначає кількість символів, записаних в ASCII рядку), дві функції виводу ASCII-рядків на екран – StrWrite і StrWrite2, а також функцію NewLine (перехід на новий рядок) та WriteSimv (виводить на екран заданий символ необхідну кількість разів).
Слід зазначити, що даний програмний модуль не містить функцій читання із консолі в рядок, однак основна програма отримує дані із PSP DOS-а і опрацьовує вже створені дані, а тому не потребує якихось додаткових вказівок через консоль від користувача, всі необхідні специфічні дані (наприклад, маска файлів) користувач може задати в командному рядку при визові основної програми.
Код програмного модуля STRIO.ASM приведений нижче:
IDEAL
MODEL small
ASCnull EQU 0 ; ASCII нуль
ASCcr EQU 13 ; ASCII символ повернення каретки
ASClf EQU 10 ; ASCII символ вертикальної табуляції
; (прогону рядка)
CODESEG
PUBLIC StrLength, StrWrite, StrWrite2, NewLine, WriteSimv
; ------------------------------------------------------------------------------------------
; StrLength підраховує кількість ненульових символів в рядку
; -------------------------------------------------------------------------------------------
; Вхід 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, є зручними і простими інструментами виводу інформації на стандартний пристрій виводу і будуть використані в основній програмі.
















