Наступним кроком реалізується вивід атрибутів файлу шляхом виводу зірочок навпроти відповідного атрибуту. Байт атрибуту файлу має наступну структуру [6]:
№ біту | Що означає |
0 | тільки читання |
1 | скритий |
2 | системний |
3 | том |
4 | каталог |
5 | архів (або копія файлу не створювалась) |
Тобто, якщо біт атрибуту файлу буде мати наступне значення 21h, це означатиме, що файл є архівним, він лише для читання.
Передостаннім кроком виводяться час і дата створення файлу у форматі: година:хвилина:секунда день\місяць\рік. Дані, що описують час і дату створення/змінення файлу, потребують накладання масок і здвигів для
№ біта | Операція | № біта | Операція | |||
Час створення | Дата створення | |||||
15 | година (0-23) | (t & 0f800h)>>11 | 15 | рік (0-119)+1980 | d & 001fh | |
14 | 14 | |||||
13 | 13 | |||||
12 | 12 | |||||
11 | 11 | |||||
10 | хвилина (0-59) | (t & 07e0h)>>5 | 10 | |||
9 | 9 | |||||
8 | 8 | місяць (1-12) | (d & 01e0h)>>5 | |||
7 | 7 | |||||
6 | 6 | |||||
5 | 5 | |||||
4 | секунда / 2 (0-30) | t & 001fh | 4 | день (0-31) | (d & f800h)>>9 | |
3 | 3 | |||||
2 | 2 | |||||
1 | 1 | |||||
0 | 0 |
отримання необхідної інформації і представлені в наступному виді [6]:
Перевід двійкових чисел у ASCII-десяткове представлення для виводу на екран реалізується за допомогою функції BinToAscDec модуля BINASC.obj.
Останній крок виводу розміру файлу виконується в два етапи, оскільки розмір файлу міститься у подвійному слові і модуль BSNASC.obj не надає інструменту для переведення двійкових даних у ASCII-рядок.
Спочатку за допомогою функції BinToAscHex модуля BINASC.obj переводиться молодші, а потім старші два байти, переведені у ASCII-шістнадцятирічне представлення.
По завершенні своєї роботи Action знов передає керування викликаючій функції DirEngin, яка повторює пошук файлів і викликає для роботи Action, доки не завершить обробку всіх файлів, що відповідають масці. Після цього DirEngine повертає старий DTA і передає курування основній програмі, яка завершує роботу і повертає код виходу.
Результати роботи програми:
D:\Program\ASM\misk>dr
The DIRWUER wersion 1.0
Romanov Alexander Urievich. KIT-13A NTU"KhPI"
Copyright (C) 2005 by Romanov Alexander
Filename OnR Skr Sys Tom Kat Arh Time Data Size
. * 11:59:18 11\5 \2005 00
.. * 11:59:18 11\5 \2005 00
BLW32.DLL * 12:12:0 14\5 \1996 52020
DEBUG.EXE * * 22:22:0 5 \5 \1999 0518A
USA.BLL * 12:12:0 14\5 \1996 18DCD
MYREP.CBA * 18:48:42 25\1 \2002 01F
DIRECT * 12:27:54 11\5 \2005 00
CATALOG3.CAB * * 22:22:0 5 \5 \1999 425C3
SUHELPER.BIN * * 22:22:0 5 \5 \1999 05C0
SAVE32.COM * * 22:22:0 5 \5 \1999 0398
ASD.LOG * * 13:8 :20 11\8 \2004 0162
IO.SYS * * * 22:22:0 5 \5 \1999 364B6
MSDOS.SYS * * * * 18:30:28 16\7 \2004 0697
08-APRIL.MP3 * 11:42:44 7 \12\2003 B11100
DR.EXE * 12:14:28 11\5 \2005 05A1
DR.BAT * 12:54:34 4 \5 \2005 09B
D:\Program\ASM\misk>dr.exe *.exe
The DIRWUER wersion 1.0
Romanov Alexander Urievich. KIT-13A NTU"KhPI"
Copyright (C) 2005 by Romanov Alexander
Filename OnR Skr Sys Tom Kat Arh Time Data Size
DEBUG.EXE * * 22:22:0 5 \5 \1999 0518A
DR.EXE * 12:14:28 11\5 \2005 05A1
D:\Program\ASM\misk>dr s*.???
The DIRWUER wersion 1.0
Romanov Alexander Urievich. KIT-13A NTU"KhPI"
Copyright (C) 2005 by Romanov Alexander
Filename OnR Skr Sys Tom Kat Arh Time Data Size
SUHELPER.BIN * * 22:22:0 5 \5 \1999 05C0
SAVE32.COM * * 22:22:0 5 \5 \1999 0398
D:\Program\ASM\misk>dr d:\program\asm\misk\direct\*.*
The DIRWUER wersion 1.0
Romanov Alexander Urievich. KIT-13A NTU"KhPI"
Copyright (C) 2005 by Romanov Alexander
Filename OnR Skr Sys Tom Kat Arh Time Data Size
. * 12:27:54 11\5 \2005 00
.. * 12:27:54 11\5 \2005 00
BINASC.ASM * 11:3 :40 8 \5 \2005 0300
PARAMS.ASM * 13:31:20 6 \5 \2005 04E4
TD.EXE * 14:39:40 24\12\2002 784F0
Як видно із приведених результатів програма DR.EXE за умовчанням виводить весь вміст директорії, в якій вона розташована (приклад 1). Інші приклади демонструють різноманітні засоби виклику програми із заданням різноманітних масок, використовуючи символи "*" і "?". Останній приклад демонструє, що виклик DR.exe можна реалізувати і з маскою, що задає повний шлях до директорії, інформацію про яку необхідно вивести.
Таким чином, розроблена програма DR.exe повністю відповідає поставленому завданню про створення програми мовою асемблера, яка виводить вміст директорії, атрибути, розмір і час/дату створення файлів і папок, які в ній містяться.
4. Розробка задачі на мові високого рівня із використанням асемблерних фрагментів коду
Як показала третя глава, розробка програми чисто на асемблері є складним процесом і потребує розробки супутніх (допоміжних) модулів для реалізації моментів, що не пов’язані із основним алгоритмом задачі (таких, як вивід на екран, перетворення двійкових даних у ASCII-рядки, тощо). Мови високого рівня дають можливість реалізувати все автоматично [3]. Такий стан речей спонукає розробити програму, в якій основний алгоритм пошуку DTA і необхідних файлів, що відповідають масці, реалізовані асемблерними вставками, а задачі, пов’язані із розробкою інтерфейсу і виводу даних на екран, реалізовані, наприклад, мовою Pascal.
4.1. Розробка програми на Pascal
Мова Pascal дає можливість створити вказівник типу "запис" (поля "запису" описують атрибут, час, дату, розмір і ім'я файлу) прямо на стандартний буфер DTA, не створюючи власного і не виконуючи зайвих дій по встановленню нової адреси буфера DTA і відновлення старої після завершення програми. Вивід інформації про файл довіряється процедурі, яка обробляє поля вказівника на DTA і виводить дані стандартними функціями Pascal.
На початку програми є сенс запитувати користувача про бажання задати власну маску для файлів, або лишити стандартну ("*.*").
Згідно із зазначеними змінами було розроблено програму DIRWUER.pas, приведену нижче:
{DIRWUER.pas}
Uses crt;
{------FindFirst – шукає перше входження файлу, що відповідає заданій масці}
Function FindFirst (Path : PChar) : Boolean; assembler;
asm
mov ah, 4Eh {в ah номер функції першого пошуку}
mov cx, 3fh {в cx маска для всіх атрибутів файлу}
mov dx, word ptr Path {dx вказує на маску файлу}
int 21h {виклик функції першого пошуку файлу}
mov al, 0 {в al поміщується 0 – код помилки (false)}
jc @Failed {якщо помилка, повернути код помилки,}
inc al {інакше повернути 1 – true }
@Failed:
end;
{------FindNext шукає наступне входження файлів, маска і атрибути яких були задані при попередньому пошуку.}
Function FindNext : Boolean; assembler;
asm
mov ah, 4Fh {в ah номер функції наступного пошуку }
{файлу}
int 21h {пошук наступного файлу за параметром,}
{заданим функцією 4Eh}
mov al, 0 {в al поміщується 0 – код помилки (false)}
jc @Failed {повернути код помилки, якщо помилка}
inc al {інакше повернути 1 – true }
@Failed:
end;
Type
DTA = record {запис описує структуру DTA-буфера}
Reserved : Array[0..$14] of Byte; {резервна область пам'яті}
Attrib : Byte; {поле атрибуту}
Time : Word; {поле часу створення}
Date : Word; {поле дати}
Size : Longint; {розмір}
Name : Array[0..$C] of Char; {ім'я файлу із розширенням}
end;
PDTA = ^DTA; {вказівник на буфер DTA}
{------GetDTAAddress повертає адресу буфера DTA}
Function GetDTAAddress : PDTA; assembler;
asm
mov ah, 2Fh {в ah номер функції пошуку DTA}
int 21h {отримання в as:bx адреси DTA }
push es {в dx через стек передаються дані із es}
pop dx
mov ax, bx {передача в ax даних із bx}
{в dx:ax повертається результат}
end;
Var
DTAAddress : PDTA;
s : string;
Path : PChar;
i : byte;
Label 1;
{------Процедура виводу даних о файлі/директорії згідно із інформацією в DTA}
Procedure ShowEntry;
Begin
Write(DTAAddress^.Name:13,' '); {вивід імені файлу із розширенням}
for i: = 0 to 5 do
if (DTAAddress^.Attrib and (1 shl i)) <>0
then write(' * ') {вивід зірочок навпроти файлів }
else write(' '); {із відповідними атрибутами}
{------Вивід часу створення файлу}
Write(' ',((DTAAddress^.Time and $0f800)shr 11):2);
Write(':',((DTAAddress^.Time and $07e0)shr 5):2,':');
Write(((DTAAddress^.Time and $1f)shl 1):2);
{------Вивід дати створення файлу}
Write(' ',(DTAAddress^.Date and $1f):2,'/');
Write(((DTAAddress^.Date and $01e0)shr 5):2,'/');
Write((((DTAAddress^.Date and $0f800)shr 9)+$07bc):4);
Writeln(' ',DTAAddress^.Size:7); {вивід розміру файлу}
end;
BEGIN
ClrScr; {очистка екрану}
{------Вивід інформації о програмі}
Writeln('The DIRWUER wersion 1.0');
Writeln('Romanov Alexander Urievich. KIT-13A KHPI');
Writeln('Copyright (C) 2005 by Romanov Alexander');
DTAAddress := GetDTAAddress; {встановлення вказівника}
{на адресу DTA}
1:
Write('Input the mask (default: *.*; exit: q): '); {запит на введення маски}
Readln(s); {отримання відповіді}
if s='' then Path:='*.*' {якщо відповіді не має,}
{встановлення стандартної маски}
else if s='q' then halt {якщо відповідь 'q', завершення}
{роботи програми}
else Path:=Addr(s[1]); {встановлення заданої маски}
if FindFirst (Path) then {знаходження першого файлу}
begin
Write('Filename OnR Skr Sys Tom ');
Writeln('Kat Arh Time DataSize'); {вивід заголовка таблиці}
ShowEntry; {вивід на екран даних про файл}
while FindNext do ShowEntry; {доки знайдено наступний файл,}
{виводити дані про нього на екран}
end
else writeln('Failed');{інакше, при незнаходженні}
{жодного файлу, виводиться}
{повідомлення про їх відсутність}
goto 1; {перехід на початок}
END.
Схема алгоритму програми приведена в додатках (Додаток Б).
Програма реалізує запит на введення маски файлу і, згідно із реакцією користувача, встановлює стандартну маску, або введену користувачем. При відповіді q – програма завершується.
Після задання маски встановлюється вказівник на DTA-буфер, після чого програма реалізує пошук файлів, що відповідають масці і вивід даних на екран. Потім програма повертається до початкового кроку запиту нової маски файлів для наступних дій.
Результати роботи програми проілюструємо наступним чином:
The DIRWUER wersion 1.0
Romanov Alexander Urievich. KIT-13A KHPI
Copyright (C) 2005 by Romanov Alexander