Смекни!
smekni.com

Вивід вмісту каталогу y середовищі MS DOS (стр. 2 из 6)

Дана функція записує CXбайт даних в файл, або пристрій, заданий описувачем в BX. В AHпоміщується номер функції, BXмістить описувач[6]:

0 Стандартний пристрій вводу (звичайна клавіатура)

1 Стандартний пристрій виводу (звичайний екран)

2 Стандартний пристрій помилок (CON-екран)

3 Стандартний пристрій AUX(COM1)

4 Стандартний принтер (LPT1)

Регістрова пара DS:DXадресується на буфер. В CXміститься кількість записуваних байт.

Функція повертає в AXкод помилки при умові, що CFвстановився в 1, або кількість реально зчитаних байтів в AL.

Для нас дана функція цікава як інструмент для виводу даних на екран, тому в BXмає бути занесено 1.

Приклад:

movah, 40h ; код функції

movbx, 1 ; вивід на екран

movdx, offsetsstring ; в dxзміщення рядка виводу

movcx, FFh ; в cxкількість символів, що виводяться

int 21h

Даний фрагмент коду виводить на екран рядок символів, що містяться в змінній sstring.

4Chфункція INT21h[6]

Вхід: AH 4Ch

AL код виходу

Вихід: не має

Функція завершення програми (EXIT). Повертає управління від породженого процесу його батьківському процесу. Встановлює код виходу (його можна опитати функцією WAIT(4Dh)).

В AХміститься номер функції, в AL– код виходу:

0 нормальне завершення

1 завершення через Ctrl-Break(INT23h)

2 завершення по критичній помилці пристрою (INT24h)

3 завершення через функцію KEEP(31h)

Приклад:

movax, 04ch ; в al– код виходу

int 21h ; в ah– номер функції

Даний фрагмент коду задає нормальне завершення роботи програми (повертається код виходу – 0).

3. Розробка задачі на мові асемблер

3.1. Допоміжні процедури

Очевидно, що основна програма потребує допоміжні процедури для отримання необхідних параметрів, які задає користувач в командному рядку при визові програми. Серед них: процедури вводу/виводу даних на консоль, обробки ASCIIрядків, а також перетворення числових даних у ASCIIформат для подальшого їх виведення на екран. Для цього були розроблені спеціальні модулі PARAMS.asm, STRIO.asmта BINASC.asm, які містять необхідні процедури. Розглянемо їх окремо.

3.1.1. Модуль PARAMS.asm

Традиційно, програми MSDOSдозволяють користувачу вводити в командному рядку одне чи більше імен файлів і інші дані. Для нас це цікаве можливістю одразу при визові основної програми DR.exeзадавати шлях до директорії та маску файлів, які ми бажаємо вивести на екран[7].

Наприклад:

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

MODELsmall

TailLenEQU0080h ; зміщення байта із довжиною рядка

; параметрів

CommandTailEQU0081h ; зміщення першого символу рядка

; параметрів

DATASEG

numParamsDW? ; кількість параметрів

paramsDB128 DUP(?) ; буфер на 128 байт для хвоста команди

CODESEG

PUBLIC ParamCount, GetParams, GetOneParam

; -------------------------------------------------------------------------------------------

; Separators внутрішня процедура для перевірки на пробіли, табуляцію,

; повернення каретки

; ------------------------------------------------------------------------------------------

; Вхід ds:si адреса символу, що перевіряється

; Вихід ZF=1 символ є пробілом, табуляцією чи поверненням каретки

ZF=1 символ не є роздільником

; Регістри не змінюються

; -------------------------------------------------------------------------------------------

PROC Separators

push ax ; збереження у стеку ax

moval, [si] ; в alпоміщується символ із ds:si

cmpal, 020h ; порівняння alіз пробілом

je @@10 ; якщо так, то перехід

cmpal, 009h ; порівняння alіз табуляцією

je @@10 ; якщо так, то перехід

cmpal, 00Dh ; порівняння alіз символом повернення

; каретки

@@10:

popax ; відновлення ax

ret ; повернення до викликаючої програми

ENDPSeparators

; -------------------------------------------------------------------------------------------

; ParamCount повертає кількість параметрів у хвості команди

; -------------------------------------------------------------------------------------------

; Вхід не має

; Вихід CX кількість параметрів командного рядка

; Регістри CX

; -------------------------------------------------------------------------------------------

PROCParamCount

movcx, [numParams] ; отримати значення змінної numParams

ret ; повернення до викликаючої програми

ENDPParamCount

; -------------------------------------------------------------------------------------------

; GetParams занесення параметрів командного рядка DOSу буфер

; -------------------------------------------------------------------------------------------

; Вхід ds префікс сегмента програми (PSP) (адресує PSP, якщо його

; не змінювали)

; es сегмент даних програми

; Вихід [params] початок буфера заповненого даними

; [numParams] кількість параметрів

; ds сегмент даних програми

; Регістри al, bx, dx, si, di, ds

; -------------------------------------------------------------------------------------------

PROCGetParams

;------Ініціалізація cxі індексних регістрів siі di

pushax ; збереження регістрів

pushbx

push dx

push si

push di

xor ch, ch ; обнуління верхньої половини cx

movcl, [ds:TailLen] ; в cxдовжина параметрів

inccx ; включити символ повернення каретки

movsi, CommandTail ; адреса параметрів поміщується в si

movdi, offsetparams ; адреса призначення поміщується в di

; ------Пропуск початкових пробілів і табуляції

@@10:

callSeparators ; пропуск пробілів і табуляції

jne @@20 ; перехід, якщо пробілів і табуляції не має

incsi ; пропуск символу

loop @@10 ; цикл, доки не скінчиться обробка, абоcx=0

; ------Копіювання параметрів рядка в буфер params

@@20:

pushcx ; збереження cxу стеку

jcxz @@30 ; пропуск копіювання, якщо cx=0

cld ; збільшення на 1 siі di

repmovsb ; копіювання cxбайтів із ds:siв es:di

; ------Перетворення пробілів в 0 і встановлення numParams

@@30:

push es

pop ds ; ds=es

popcx ; відновлення cx(довжину)

xorbx, bx ; обнуління bx, лічильник параметрів

jcxz @@60 ; пропуск циклу якщоcx=0 (довжина)

movsi, offsetparams ; поміщення адреси параметрів в si

@@40:

callSeparators ; перевірка на пробіли, табуляцію,

; повернення каретки

jne @@50 ; перехід, якщо не знайдено роздільник

mov [byteptrsi], 0 ; заміна роздільника на 0

incbx ; збільшення лічильника кількості

; параметрів

@@50:

incsi ; переміщення указника на наступний

; символ

loop @@40 ; виконувати в циклі, доки cx≠0

@@60:

mov [numParams], bx ; збереження в numParamsкількість

; параметрів

popax ; відновлення регістрів

popbx

popdx

pop si

pop di

ret ; повернення до батьківської програми

ENDPGetParams

; -------------------------------------------------------------------------------------------

; GetOneParam отримати адресу параметра за номером

; -------------------------------------------------------------------------------------------

; Вхід cx номер параметра (має бути менше значення в numParams)

; Вихід di зміщення ASCIIрядка із потрібним параметром

; Регістри di

; -------------------------------------------------------------------------------------------

PROCGetOneParam

pushax ; збереження регістрів axі cx

pushcx

xoral, al ; обнуління al(ініціалізація шуканого

; значення 0)

movdi, offsetparams ; адреса параметрів рядка

jcxz@@99 ; якщо номер параметра(cx) дорівнює 0,

; то вихід

cmpcx, [numParams] ; порівняння cxіз кількістю параметрів

jae @@99 ; вихід, якщо передано неіснуючого

; параметру

cld ; автоматичне збільшення di

@@10:

scasb ; пошук нульового обмежувача

jnz @@10 ; повтор, доки не знайдено 0

loop @@10 ; повтор, доки в cxне буде 0

@@99:

popcx ; відновлення регістрів cx, ax

popax

ret ; повернення до викликаючої програми

ENDPGetOneParam

END

Таким чином, програмний модуль PARAMS.asmє зручним інструментом для реалізації роботи із командним рядком і буде використаний в основній програмі.

3.1.2. Модуль STRIO.asm

Оскільки важливою частиною основної програми, згідно із завданням, буде вивід текстових рядків на екран, то є необхідність у створенні спеціального програмного модуля, який би містив процедури для обробки і виводу ASCIIрядків на екран. Пряме використання функцій DOSв основній програмі є незручним, оскільки є потреба у спрощенні коду для його сприйняття.

З цих міркувань було розроблено програмний модуль STRIO.asm, в якому міститься п’ять спеціальних функцій: StrLength (визначає кількість символів, записаних в ASCIIрядку), дві функції виводу ASCII-рядків на екран – StrWriteі StrWrite2, а також функцію NewLine(перехід на новий рядок) та WriteSimv(виводить на екран заданий символ необхідну кількість разів).

Слід зазначити, що даний програмний модуль не містить функцій читання із консолі в рядок, однак основна програма отримує дані із PSPDOS-а і опрацьовує вже створені дані, а тому не потребує якихось додаткових вказівок через консоль від користувача, всі необхідні специфічні дані (наприклад, маска файлів) користувач може задати в командному рядку при визові основної програми.

Код програмного модуля STRIO.ASMприведений нижче:

IDEAL

MODEL small

ASCnull EQU 0 ; ASCIIнуль

ASCcr EQU 13 ; ASCIIсимвол повернення каретки

ASClfEQU 10 ; ASCIIсимвол вертикальної табуляції

; (прогону рядка)

CODESEG

PUBLIC StrLength, StrWrite, StrWrite2, NewLine, WriteSimv

; ------------------------------------------------------------------------------------------

; StrLength підраховує кількість ненульових символів в рядку

; -------------------------------------------------------------------------------------------

; Вхід di адреса ASCIIрядка

; Вихід cx кількість ненульових символів в рядку

; Регістри cx

; -------------------------------------------------------------------------------------------

PROCStrLength

pushax ; зберегти у стеку змінювані