Разработка командного процессора, реализующего команды dir и mkdir на ассемблере
Министерство образования и науки Республики Беларусь
Белорусский Государственный Университет Информатики и Радиоэлектроники
______________________________________________________________________
Факультет Компьютерного Проектирования
Пояснительная записка
к курсовому проекту по теме
"Разработка коммандного процессора"
Выполнил
студент гр.410703
Федосенко Д.В.
Руководитель работы
Ширинский В.П.
Минск 1996
Содержание
Введение
1. Анализ технического задания .................................
2. Разработка алгоритма ........................................
3. Разработка структуры данных .................................
4. Кодирование алгоритма .......................................
5. Тестирование и отладка программы ............................
Заключение .....................................................
Литература .....................................................
Приложение .....................................................
Введение
Появление микропроцессоров в 60-е годы связано с разработкой ин-
тегральных схем (ИС). Интегральные схемы объединяли в себе различные
электронные компоненты в единый элемент на силиконовом чипе. Разработ-
чики установили этот крошечный чипв устройство, напоминающее сороко-
ножку, и включили его в функциональные системы. В начале 70-х годов
микрокомпьютеры на процессоре Intel 8008 возвестили о первом поколе-
нии микропроцессоров.
К 1974 г. появилось второе поколение микропроцессоров общего наз-
начения Intel 8080. Данный успех побудил другие фирмы к производству
процессоров Intel 8080 или аналогичных.
В 1878 г. фирма Intel выпустила процессор третьего поколения -
Intel 8086, который обеспечивал некоторую совместимость с 8080 и яв-
лялся значительным продвижением вперед в данной области. Для поддер-
жки более простых устройств и обеспечения совместимости с устройства-
ми ввода-вывода того времени Intel разработал разновидность процессо-
ра 8086 - процессор 8088, который в 1981 г. ьыл выбран фирмой IBM для
ее персональных компьютеров.
Более развитыми версиями являются для процессора 8088 процессор
80186, а для процессора 8086 - процессоры 80186, 80286, 80386, кото-
рые обеспечили дополнительные возможности и повысили мощность вычисле-
ний.
Распространение микропроцессоров послужило причиной пересмотра от-
ношения к языку Фсскмблер по двум основным причинам. Во-первых, прог-
раммы, написанные на языке Ассемблер, требуют знаительно меньше обье-
ма памяти и времени выполнения. Во-вторых, знание языка Ассемблер и
результирующего машинного кода дыет понимание архитектуры машины, что
врядли обеспечивается при работе на языках высокого уровня. Хотя
большинство специалистов в области программного обеспечения ведут раз-
работки на языках высокого уровня, таких, как Паскаль или СИ, что про-
ще при написании программ, но наиболее мощное и эффективное програм-
мное обеспечение полностью или частично написано на языке Ассемблер.
1. Анализ технического задания
В данном курсовом проекте необходимо разработать программу на язы-
ке Ассемблер для МП Intel 8086 реализующую функции командного процес-
сора DIR и MKDIR. Т.е. наша программа должна создавать подкаталог c
указанием диска и маршрута (функция MKDIR) и выводить, указанный
пользоватем каталог. Вовремя создания подкаталога вносятся изменения в
таблицу размещения файлов (FAT), с тем чтобы сектора, используемые
этим подкаталогам были доступны другим файлам.
Для роботы с дисковой памятью в расширенной версии DOS нам понадо-
бятся операции, которые включают использование строк в формате ASCIIZ
для начальной установки дисковода, пути доступа и имени файла; файло-
вого номера для доступу к файлу; специальных кодов возврата.
Для создания подкаталога методом дескриптора файла используется
функция 39H прерывания 21H. В DS:DX заносится строка ASCIIZ , содержа-
щей идентификацию файла (все параметры необязательные), строка должна
завершаться 00H, например:
PATHNAME DB 'C:\UTIL\NU.EXE',0
Обратная косая (или прямая косая) используется в качестве разделителя.
Hулевой байт (zero) завершает строку (отсюда название ASCIIZ).
При успешной операции создания подкаталога, флаг CF устанавливает-
ся в 0. При неуспешной операции флаг CF устанавливается в 1, а в ре-
гистр AX помещается код ошибки, зависящий от операции (таблица 1.1), в
нашем случае, если не найден указанный диск или путь, то в AX возвра-
щается код ошибки 03. В имени создаваемого подкаталога не могут быть
использованы следующие символы:
" : ; / \ | ? * + = [ ] . , < >
Таблица 1.1
┌────┬──────────────────────────────────────┐
│ N │ Описание ошибки │
├────┼──────────────────────────────────────┤
│ 01 │ Ошибка номера функции │
│ 02 │ Файл не найден │
│ 03 │ Путь доступа не найден │
│ 04 │ Открыто слишком много файлов │
│ 05 │ Доступ не разрешен │
│ 06 │ Ошибка файлового номера │
│ 07 │ Блок управления памятью разрушен │
│ 08 │ Hедостаточно памяти │
│ 09 │ Ошибка адреса блока памяти │
│ 10 │ Ошибка оборудования │
│ 11 │ Ошибка формата │
│ 12 │ Ошибка кода доступа │
│ 13 │ Ошибка данных │
│ 15 │ Ошибка дисковода │
│ 16 │ Попытка удалить оглавление │
│ 17 │ Hе то устройтво │
│ 18 │ Hет больше файлов │
└────┴──────────────────────────────────────┘
Для организации работы, нам понадобится знание структуры записи
файла каталогов, которая приведена в таблице 1.2.
Таблица 1.2
┌───┬──────────┬───────┬───────────────────────────┐
│ N │ Смещение │ Длина │ Значение поля │
│ │ (байт) │ (байт)│ │
├───┼──────────┼───────┼───────────────────────────┤
│1 │ 0 │ 8 │ Имя файла │
├───┼──────────┼───────┼───────────────────────────┤
│2 │ 8 │ 3 │ Расширение имени файла │
├───┼──────────┼───────┼───────────────────────────┤
│3 │ 11 │ 1 │ Байт атрибутов файлов │
├───┼──────────┼───────┼───────────────────────────┤
│4 │ 12 │ 10 │ Зарезервировано для DOS │
├───┼──────────┼───────┼───────────────────────────┤
│5 │ 22 │ 2 │ Время │
├───┼──────────┼───────┼───────────────────────────┤
│6 │ 24 │ 2 │ Дата │
├───┼──────────┼───────┼───────────────────────────┤
│7 │ 26 │ 2 │ Стартовый номер кластера │
├───┼──────────┼───────┼───────────────────────────┤
│8 │ 28 │ 4 │ Размер файла │
└───┴──────────┴───────┴───────────────────────────┘
Вторая функция курсового проекта (команда DIR), будет реализова-
на с помощью 21-го прерывания. Функции 21-го прерывания, которые мы
будем использовать, рассмотрены в 4 главе.
2. Разработка алгоритма
Разработаем алгоритм для разрабатываемой программы. Данные в прог-
рамму будем передавать в командной строке. Далее будем анализировать
командную строку следующим образом:
1. Если командная строка пуста, то выводим подсказку;
2. Если встречается первым ключ /D - то выводим текущий директорий;
3. Если встречается первым ключ /M - информируем пользователя о
том, что он забыл указать имя поддиректория, для его создания;
4. После этого записываем все до первого пробела в строку PATH -
это будет маска файлов.
5. Анализируя далее, смотрим, если стоит /D - то выводим директо-
рий по маске, если стоит /M - то создаем подкаталог по маске.
Блок схема алгоритма приведена в приложении.
3. Разработка структуры данных
В курсовом проекте задействовано множество переменных:
┌─────────┬────────────────────────────────────────────────────────────┐
│Hазвание │ Содержание переменной │
├─────────┼────────────────────────────────────────────────────────────┤
│ HelpStr │ Текст подсказки │
│ stringT │ К байт всего на данном диске │
│ stringF │ К байт свободно на диске │
│ stringU │ Вывод содержимого каталога │
│ err_m1 │ Ошибка номера функции! │
│ err_m2 │ Файл не найден! │
│ err_m3 │ Путь доступа не найден! │
│ err_m4 │ Открыто слишком много файлов! │
│ ok_make │ Подкаталог создан! │
│ no_make │ Подкаталог не создан, т.к. вы не указали его имя! │
│ │ Для вывода подсказке запустите программу без параметров. │
│ str_f │ Вы не указали ключ! │
│ str_k │ Вы указали неверный ключ! │
│ totalKB │ Ячейка для хранения объема диска │
│ freeKB │ Ячейка для хранения размера свободного места │
│ temp │ Рабочая переменная │
│ path │ Текущий каталог (пока не определен - пустой) │
│ NewDTA │ Описываем структуру DTA │
│ AttrF │ Атрибут файла │
│ TimeF │ Время создания файла │
│ DateF │ Дата создания файла │
│ SizeF │ Размер файла │
│ NameF │ Имя файла вместе с расширением │
└─────────┴────────────────────────────────────────────────────────────┘
Процедуры, входящие в курсовой проект:
┌─────────────────────────────────────────────────────────────────────────┐
│ Процедура высчитывает и выводит время создания файла/каталога │
│ WrtTime │
├─────────────────────────────────────────────────────────────────────────┤
│ Процедура высчитывает и выводит дату создания файла/каталога │
│ WrtDate │
├─────────────────────────────────────────────────────────────────────────┤
│ Забивает пробелами поле, в которое записывается имя файла (NameF) │
│ Это необходимо для того, чтобы не было наложений имен файлов при выводе │
│ ClrName │
├─────────────────────────────────────────────────────────────────────────┤
│ Выводит имя каталога на экран │
│ WrtDir │
├─────────────────────────────────────────────────────────────────────────┤
│ Выводит имя файла на экран │
│ WrtFile │
├─────────────────────────────────────────────────────────────────────────┤
│ Выводит метку текущего диска │
│ WLabel │
├─────────────────────────────────────────────────────────────────────────┤
│ Производит перевод строки и возврат каретки │
│ crlf │
├─────────────────────────────────────────────────────────────────────────┤
│ Выводит на экран текущий каталог │
│ curdir │
├─────────────────────────────────────────────────────────────────────────┤
│ Получает информацию о диске. Номер диска берет из строки поиска │
│ После вызова в AX - количество секторов в кластере │
│ в BX - число свободных кластеров │
│ в CX - число байтов в секторе │
│ в DX - число кластеров на диске │
│ GetInfo │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ Выводит размер текущего диска в Килобайтах │
│ totsize │
├─────────────────────────────────────────────────────────────────────────┤
│ Выводит размер свободного пространства │
│ текущего диска в Килобайтах │
│ fresize │
├─────────────────────────────────────────────────────────────────────────┤
│ Процедура вывода числа в десятичном формате │
│ Decimal │
└─────────────────────────────────────────────────────────────────────────┘
4. Кодирование алгоритма
Запишем разработанный нами алгоритм в мнемокоде на языке Ассемблер.
Далее более подробно опишем основные прерывания, которые будем ис-
пользовать.
Основным прерыванием, используемым в программе, является прерыва-
ния INT 21H (DOS Functions). Используемые функции этого прерывания
следующие:
Параметры Описание
Входные: AH 02H - Вывод на дисплей
DL символ для посылки на стандартное устройство
Выходные: нет
───────────────────────────────────────────────────────────────────────────
Входные: AH 09H - Вывод строки на дисплей
DS:DX Адрес строки, заканчивающаяся знаком '$' (ASCII 24H)
Выходные: нет
───────────────────────────────────────────────────────────────────────────
Входные: AH 1aH - Установка адреса DTA.
DS:DX адресс DTA области
Выходные: нет
───────────────────────────────────────────────────────────────────────────
Входные: AH 19H - Получить информацию о текущем диске
Выходные: AL DOS current default drive number (0=A, 1=B, и т.д.)
───────────────────────────────────────────────────────────────────────────
Входные: AH 36H - Получить информацию о свободном месте на диске
DL drive number (0=default, 1=A, и т.д.)
Выходные: AX ffffH если DL было invalid drive number
иначе количество секторов верно
BX количество свободных секторов (allocation units)
CX байт на сектор (обычно 512)
DX общее количество секторов на диске
Доп.информация: Выходная информация обычно подсчитывается как
общий размер диска и количество свободного места на диске:
Если AX = ffffH, то вы не правильно указали диск.
Иначе, свободного места в байтах = (AX * CX * BX)
общий размер в байтах = (AX * CX * DX)
Если сектора по 512 байт, более просто подсчитывать КБ:
свободного места в КБ = (AX * BX) / 2
общий размер в КБ = (AX * DX) / 2
───────────────────────────────────────────────────────────────────────────
Входные: AH 3fH - Создать подкаталог
Функция описывалась нами ранее.
───────────────────────────────────────────────────────────────────────────
Входные: AH 47H - Информация о текущем директории
DL drive number (0=default, 1=A, etc.)
DS:SI address of a local buffer to hold a pathname (64 bytes)
Выходные: AX передается ошибка (Таблица 1.1)
───────────────────────────────────────────────────────────────────────────
Входные: AH 4fH - Hайти следующий совпадающий файл
DS:DX адресс данных с предыдущего 4eH поиска файла
───────────────────────────────────────────────────────────────────────────
Входные: AH 4eH - Hвайти первый совпадающий файл
DS:DX строка пути к файлу ASCIIZ
CX атрибут файлы для поиска
───────────────────────────────────────────────────────────────────────────
Кроме 21h прерывания мы использовали функцию 0eH прерывания INT 10H:
Данная функция обеспечивает вывод символа на монитор в режиме те-
летайпа. Для выполнения этой функции в AL помещают выводимый символ, в
BL цвет текста и номер строницы в BH. Hапример, символы: CR (0dH), LF
(0aH), звуковой сигнал (07H) и т.д. Данная функция автоматически кур-
сор, переводит символы на следующую строку, выполняет прокрутку экра-
на и сохраняет текущие атрибуты экрана.
Также мы использовали прерывание INT 20H для выхода в DOS. Оно не
имеет параметров.
Полный текст программы приведен в Приложении.
5. Тестирование и отладка программы
D:\ASM>kp.com <ВВОД>
KP v1.0, Copyright (c) 1997, БГУИР, Федосенко Д.В.
При запуске без параметров выводит подказку
Запуск с параметром должен иметь вид: kp диск:\каталог\маска [/D] [/M]
Где маска (при использовании /D) - любые символы и имена, включая * и ?
(при использовании /M) - название подкаталога.
/D - вывод директория по маске /M - создание подкаталога по маске
Например:kp C:\LANG\BP\*.* /D - вывод всех файлов и каталогов из C:\LANG\BP
kp C:\* /D - вывод только каталогов из корневого каталога диска C:
kp C:\UTIL /M - создание подкаталога UTIL в корневом диска С:
kp /D - вывод всех файлов и каталогов по текущему пути
Если ВЫ используете /M, то указывать название подкаталога обязательно!
D:\ASM>kp c:\cd\*.* /D <ВВОД>
Вывод содержимого каталога c:\cd\*.*
Метка диска DIMKA
. <КАТАЛОГ> 29/01/97 18:18:44
.. <КАТАЛОГ> 29/01/97 18:18:44
read_me.txt 1834 19/11/96 17:58:40
rcdsim.com 6604 13/09/95 03:00:00
loadcd.exe 0352 13/09/95 03:00:00
rcdpc.sys 4231 13/09/95 03:00:00
run_me.bat 40 06/02/97 13:54:38
307240К байт всего на данном диске
6160К байт свободно на диске
D:\ASM>kp c:\cd\util /M <ВВОД>
c:\cd\util
Подкаталог создан!
D:\ASM>kp c:\cd\*.* /D
Вывод содержимого каталога c:\cd\*.*
Метка диска DIMKA
. <КАТАЛОГ> 29/01/97 18:18:44
.. <КАТАЛОГ> 29/01/97 18:18:44
UTIL <КАТАЛОГ> 10/04/97 19:57:48
read_me.txt 1834 19/11/96 17:58:40
rcdsim.com 6604 13/09/95 03:00:00
loadcd.exe 0352 13/09/95 03:00:00
rcdpc.sys 4231 13/09/95 03:00:00
run_me.bat 40 06/02/97 13:54:38
307240К байт всего на данном диске
6152К байт свободно на диске
D:\ASM>kp * /D <ВВОД>
Вывод содержимого каталога *
Метка диска NPACD
. <КАТАЛОГ> 19/02/97 19:20:34
.. <КАТАЛОГ> 19/02/97 19:20:34
THELP6<КАТАЛОГ> 07/04/97 22:08:48
483552К байт всего на данном диске
8928К байт свободно на диске
В процессе тестирования были замечены проблемы с выводом информа-
ции при работе в системе WINDOWS95 (v4.0095). Автор надеется, что с
выходом системы WINDOWS98 проблем не будет.
Заключение
В процессе выполнения курсового проекта я более широко изучил фун-
кции прерываний DOS и BIOS. Hаучился применять их на практике, а так-
же ознакомился со структурой построения программы, реализующей фун-
кйии коммандного процессора. Hаучился пользоваться справочной и дру-
гой литературой.
Литература
1. Бек Л. Введение в системной программирование
2. Соловьев Г.H. Операционная система ЭВМ, Высшая школа, 1989г
3. Краковяк С. Основы организации и функционирования операционной
системы ЭВМ
4. Вишняков В.А., Петровский А.А. Системное обеспечение микроЭВМ
5. Hортон П. Персональный компьютер фирмы IBM и операционная система
MS-DOS
6. Финогенов К.Г. Самоучитель по системным функциям MS-DOS
7. Абель П. Язык ассемблер для IBM PC и программирования, Высшая шко-
ла, 1992г
Приложение
;----------------------------------------
; Курсовой проект по дисциплине
; "Системное программное обеспечение"
; студента гр.410703 Федосенко Д.В.
; (c)1997 БГУИР
;----------------------------------------
.MODEL TINY
.CODE
ORG 100h
begin: jmp start
HelpStr db 13,10,'KP v1.0, Copyright (c) 1997, БГУИР, Федосенко Д.В.'
db 13,10,13,10,'При запуске без параметров выводит подказку'
db 13,10,'Запуск с параметром должен иметь вид: kp диск:
\каталог\маска [/D] [/M]'
db 13,10,'Где маска (при использовании /D) - любые символы и
имена, включая * и ?'
db 13,10,' (при использовании /M) - название
подкаталога.'
db 13,10,'/D - вывод директория по маске
/M - создание подкаталога по маске'
db 13,10,'Например:kp C:\LANG\BP\*.* /D - вывод всех файлов
и каталогов из C:\LANG\BP'
db 13,10,' kp C:\* /D - вывод только каталогов из
корневого каталога диска C:'
db 13,10,' kp C:\UTIL /M - создание подкаталога UTIL
в корневом каталоге диска С:'
db 13,10,' kp /D - вывод всех файлов и каталогов по
текущему пути'
db 13,10,'Если ВЫ используете /M, то указывать название
подкаталога обязательно!',13,10,'$'
stringT db 'К байт всего на данном диске',13,10,'$'
stringF db 'К байт свободно на диске',13,10,'$'
stringU db 13,10,'Вывод содержимого каталога $'
err_m1 db 13,10,'Ошибка номера функции! $'
err_m2 db 13,10,'Файл не найден! $'
err_m3 db 13,10,'Путь доступа не найден! $'
err_m4 db 13,10,'Открыто слишком много файлов! $'
ok_make db 13,10,'Подкаталог создан! $'
no_make db 13,10,'Подкаталог не создан, т.к. вы не указали его имя!'
db 13,10,'Для вывода подсказке запустите программу без
параметров.',10,13,'$'
str_f db 13,10,'Вы не указали ключ! $'
str_k db 13,10,'Вы указали неверный ключ! $'
totalKB dd 0 ; Ячейка для хранения объема диска
freeKB dd 0 ; Ячейка для хранения размера свободного места
space db ' $' ; Строка разделения
temp dw 0 ; Рабочая переменная
path db 65 dup (0) ; Текущий каталог (пока не определен - пустой)
NewDTA db 21 dup (0) ; Описываем структуру DTA
AttrF db 0 ; Атрибут файла
TimeF dw 0 ; Время создания файла
DateF dw 0 ; Дата создания файла
SizeF dd 0 ; Размер файла
NameF db 13 dup (0) ; Имя файла вместе с расширением
start:
push cs ; Заносим во все регистры сегмент кода
pop ds ;
push cs ;
pop es ;
;Проверяем строку параметров
mov cl,ds:[80h] ; Число символов параметров
cmp cl,0 ; Не равно-ли число параметров нулю ?
je help ; Если параметров нет, переходим
cmp cl,1 ; Если один параметр, например файл запущен
je help ; по Ctrl-Enter в NC, то тоже выходим
mov al,ds:[82h] ; Проверяем на ввод без маски
cmp al,'/' ; Наклонная черта ?
jne not_help ; Нет - выходим
mov al,ds:[83h] ; Да - смотрим дальше
cmp al,'M' ; Если введено /M
je not_m
cmp al,'D' ; Если введно /D
je noparam
jmp not_help
help:
mov ah,9 ; Вывод подсказки
lea dx,HelpStr
int 21h
ret ; Выход в DOS
not_m:
mov ah,9 ; Подкаталог не созданб т.к. вы не
lea dx,no_make ; указали имя
int 21h
ret ; Выход в DOS
not_help: ; Если маска введена
mov ch,0
mov di,81h ; Адрес первого символа параметра
mov al,' ' ; Сканировать будем до первого пробела
CheckParam:
repe scasb ; Запускаем сканирование строки
jne IsParam
IsParam: ; Если пробел найден
mov si,di ; Запоминаем адрес
dec si ; Уменьшаем на единицу
lea di,path ; Устанавливаем адрес строки параметров
inc cl
MoveParam:
lodsb ; Загружаем один символ строки параметров
cmp al,' ' ; Проверяем, не равен ли он пробелу
je EndMoveParam ; Если равен, значит конец строки
stosb ; Иначе пересылаем в строку параметров - path
loop MoveParam ; Цикл до конца строки
EndMoveParam:
push ax ;сохраним на всякий случай
lodsb ;загружаем еще один символ
cmp al,'/' ;если это /
je okk
mov ah,9 ;иначе вываливаемся с error
lea dx,str_F
int 21h
int 20h
okk: lodsb ;загружаем еще один символ
cmp al,'D' ;если это /D
je Dire ;то запуск DirE
cmp al,'M' ;если это /M
je MakeE ;то запускаем MakeE
mov ah,9 ;иначе вываливаемся с error
lea dx,str_K
int 21h
int 20h
DirE: pop ax
mov al,0 ; Добавляем символ NUL к строке параметров
mov [di],al
mov ah,9 ; Функция вывода строки
lea dx,stringU ; В DX - адрес строки
int 21h ; Выводим строку "Текущий каталог"
mov ah,40h ; Выводим маску поиска
mov bx,01
mov cx,50
lea dx,path
int 21h
call crlf ; Перевод строки, возврат каретки
jmp skip_curdir ; Обходим определение текущего каталога
NoParam: ; Если не заданы параметры
call curdir ; Определяем текущий каталог
skip_curdir:
lea dx,NewDTA ; Устанавливаем указатель на свою область DTA
mov ah,1Ah
int 21h
call WLabel ; Выводим метку диска
mov ah,4eh ; Функция находит первый каталог с маской *.*
mov cx,10h ; В CX - атрибут каталога - 10h
lea dx,path ; В DX - путь для поиска (был определен выше)
int 21h
jc NowFiles ; Если ни одного каталога нет, ищем файлы
call WrtDir ; Выводим имя первого найденного каталога
FindNextDir:
mov ah,4fh ; Функция продолжает поиск, начатый ф-цией 4eh
int 21h
jc NowFiles ; Если больше каталогов нет, ищем файлы
call WrtDir ; Выводим найденный каталог
jmp FindNextDir ; Переходим на поиск следующего
NowFiles:
mov ah,4eh ; Функция находит первый файл с маской *.*
mov cx,27h ; В CX - атрибут файла - 27h (RO+Hid+Sys+Arc)
lea dx,path ; В DX - путь для поиска файлов
int 21h
jc halt ; Если файлов нет, то на выход
call WrtFile ; Если файл найден, выводим его имя
FindNextFile:
mov ah,4fh ; Функция продолжает поиск файлов
int 21h
jc halt ; Если больше файлов нет, то на выход
call WrtFile ; Выводим имя файла на экран
jmp FindNextFile ; Переход на поиск следующего файла
halt: call crlf ; Перевод строки, возврат каретки
call totsize ; Вывод объема диска
call fresize ; Вывод оставшегося места
ret ; Выход в DOS
;------------- создание подкаталога ---------------------------------
MakeE: pop ax ; восстанавливаем ax
mov al,0 ; Добавляем символ NUL к строке параметров
mov [di],al
mov ah,40h ; Выводим маску поиска
mov bx,01
mov cx,50
lea dx,path
int 21h
mov ah,39h ; функция создания подкаталога
lea dx,path
int 21h ; выполнить
cmp ax,01h ; проверка на ошибку #1
je p_err1
cmp ax,02h ; проверка на ошибку #2
je p_err2
cmp ax,03h ; проверка на ошибку #3
je p_err3
cmp ax,04h ; проверка на ошибку #4
je p_err4
mov ah,9h ; Ошибки нет!
lea dx,ok_make ; Вывод строки - Подкаталог создан
int 21h
int 20h ; Выход в DOS
;-------- Обработка ошибок --------------------------------
p_err1: mov ah,9h
lea dx,err_m1
int 21h
int 20h
p_err2: mov ah,9h
lea dx,err_m2
int 21h
int 20h
p_err3: mov ah,9h
lea dx,err_m3
int 21h
int 20h
p_err4: mov ah,9h
lea dx,err_m4
int 21h
int 20h ; Выход в DOS
;------------------------------------------------------------------------
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;:: Процедура высчитывает и выводит время создания файла/каталога :::
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
WrtTime proc near
mov ah,9
lea dx,space
int 21h
mov ax,TimeF
shr ax,11
call DecWrt
mov ax,0e3ah
int 10h
mov ax,TimeF
shl ax,5
shr ax,10
call DecWrt
mov ax,0e3ah
int 10h
mov ax,TimeF
shl ax,11
shr ax,10
call DecWrt
ret
WrtTime endp
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;::: Процедура высчитывает и выводит дату создания файла/каталога :::
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
WrtDate proc near
mov ah,9
lea dx,space
int 21h
mov ax,DateF
shl ax,11
shr ax,11
call DecWrt
mov ax,0e2fh
int 10h
mov ax,DateF
shl ax,7
shr ax,12
call DecWrt
mov ax,0e2fh
int 10h
mov ax,DateF
shr ax,9
add ax,80
call DecWrt
ret
WrtDate endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; Забивает пробелами поле, в которое записывается имя файла (NameF) ::
; Это необходимо для того, чтобы не было наложений имен файлов при выводе ::
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ClrName proc near
lea si,NameF ; Получаем адрес имени файла
mov cx,1
rp: cmp cx,13 ; Если CX=13, то имя обработано полностью
je vihod ; поэтому выходим
mov al,0 ; Заносим код символа 0 (пустой символ)
mov [si],al ; Записываем пустой символ в строку NameF
inc si ; Увеличиваем адрес строки
inc cx ; Увеличиваем счетчик записаных символов
jmp rp ; Повторяем цикл
vihod: ret
ClrName endp
;::::::::::::::::::::::::::::::::::::::
;::: Выводит имя каталога на экран ::::
;::::::::::::::::::::::::::::::::::::::
WrtDir proc near
cmp AttrF,10h ; Проверяем атрибут: если 10h, то каталог
jne exit1 ; Иначе на выход
mov ah,40h ; Функция вывода строки
mov bx,01
mov cx,12 ; Выводим 13 символов
lea dx,NameF ; В DX - адрес строки вывода
int 21h
mov ah,9
lea dx,dirstr
int 21h
call WrtDate
call WrtTime
call crlf ; Перевод строки, возврат каретки
exit1: call ClrName ; Чистим поле вывода
ret
dirstr db '<КАТАЛОГ>$'
WrtDir endp
;:::::::::::::::::::::::::::::::::::::::
;::: Выводит имя файла на экран ::::::::
;:::::::::::::::::::::::::::::::::::::::
WrtFile proc near
cmp AttrF,10h ; Проверяем атрибут: если не файл, то выходим
je exit2
lea si,NameF ; Загружанм адрес строки в SI
mov cx,1
loop1:
cmp cx,13 ; Проверяем, если CX=13, то вывод закончен
je exit2 ; выходим
mov al,[si] ; Заносим в AL выводимый символ
cmp al,65 ; Сравниваем его с 'A'
jl skip1 ; Если меньше, то не переводим в нижний регистр
cmp al,90 ; Сравниваем AL с 'Z'
jg skip1 ; Если больше, то не переводим в нижний регистр
add al,32 ; Переводим символ в нижний регистр
skip1:
mov dl,al
mov ah,02 ; Функция вывода символа на экран
int 21h
inc si ; Увеличиваем адрес
inc cx ; Увеличиваем сченчик
jmp loop1 ; Переход на следующий символ
exit2:
call ClrName ; Чистим поле вывода
mov ax,word ptr SizeF
mov dx,word ptr SizeF+2
call Decimal
call WrtDate
call WrtTime
call crlf
ret
WrtFile endp
;:::::::::::::::::::::::::::::::::::::::
;::: Выводит метку текущего диска ::::::
;:::::::::::::::::::::::::::::::::::::::
WLabel proc near
call ClrName ; Чистим поле вывода
mov ah,9 ; Функция вывода строки на экран
lea dx,StringL ; В DX - адрес строки
int 21h
lea si,path4
mov ah,19h ; Получаем текущий диск
int 21h
add al,41h ; Переводим его в букву
mov [si],al ; Заносим во временную строку
lea si,path ; Путь поиска
lea di,path4 ; Временная строка
mov al,[si] ; Берем первый символ пути поиска
cmp al,65 ; Буква диска 'A'?
jl not_xchg ; Если меньше, выходим
cmp al,122 ; Буква диска 'z'?
jg not_xchg ; Если больше, выходим
cmp al,91 ; Если '[' - выход
je not_xchg
cmp al,92 ; Если '\' - выход
je not_xchg
cmp al,93 ; Если ']' - выход
je not_xchg
cmp al,94 ; Если '^' - выход
je not_xchg
cmp al,95 ; Если '_' - выход
je not_xchg
cmp al,96 ; Если '`' - выход
je not_xchg
mov [di],al
not_xchg:
mov ah,4eh ; Ищем файл
mov cx,08h ; с атрибутом 08h, т.е. метку тома
lea dx,path4 ; В DX - путь для поиска
int 21h
mov ah,40h ; Функция вывода строки на экран
mov bx,01
mov cx,13 ; Выводим 13 символов
lea dx,NameF ; В DX - адрес строки
int 21h
call crlf ; Перевод строки, возврат каретки
call crlf ; Перевод строки, возврат каретки
call ClrName ; Чистим поле вывода
ret
StringL db 'Метка диска $'
path4 db 'c:\*.*',0 ; Первый символ будет заменен на текущий диск
WLabel endp
;::::::::::::::::::::::::::::::::::::::::::::::::::::::
;:::: Производит перевод строки и возврат каретки :::::
;::::::::::::::::::::::::::::::::::::::::::::::::::::::
crlf proc near
mov ax,0e0dh ; Функция вывода символа
int 10h ; Выводим символ 13 на экран
mov ax,0e0ah ; Функция вывода символа
int 10h ; Выводим символ 10 на экран
ret
crlf endp
;::::::::::::::::::::::::::::::::::::::::::
;::: Выводит на экран текущий каталог :::::
;::::::::::::::::::::::::::::::::::::::::::
curdir proc near
mov ah,9 ; Функция вывода строки
lea dx,stringC ; В DX - адрес строки
int 21h ; Выводим строку "Текущий каталог"
lea si,path
mov ah,19h ; Получаем текущий диск
int 21h
add al,41h ; Переводим его в букву
mov [si],al
inc si
mov al,58 ; Добавляем символ ':'
mov [si],al
inc si
mov al,92 ; Добавляем символ '\'
mov [si],al
mov ah,47h ; Функция получения текущего каталога
mov dl,00
lea si,path+3 ; Добавляем к диску каталог
int 21h
lea si,path ; Производим посимвольный вывод полного пути
a10loop:
cmp byte ptr [si],0
je a20exit
mov al,[si]
mov dl,al
mov ah,02
int 21h
inc si
jmp a10loop
a20exit:
; Добавляем к текущему пути маску *.* для поиска каталогов и файлов
dec si ; Уменьшаем адрес на 1 и получаем последний
mov al,[si] ; символ, а не NUL
inc si ; Возвращаем назад SI
cmp al,92 ; Проверяем, если посл. символ - слэш, то выход
je skip_slash
mov al,92 ; Иначе добавляем символ '\'
mov [si],al
inc si
skip_slash:
mov al,42 ; Добавляем символ '*'
mov [si],al
inc si
mov al,46 ; Добавляем символ '.'
mov [si],al
inc si
mov al,42 ; Добавляем символ '*'
mov [si],al
inc si
mov al,0 ; Добавляем символ NUL
mov [si],al
call crlf
ret
stringC db 13,10,'Текущий каталог $'
curdir endp
Div1024 proc near
mov cx,10
dd20: shr ax,1
shr dx,1
jnc dd30
or ah,10000000b
dd30: loop dd20
ret
Div1024 endp
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;:: Получает информацию о диске. Номер диска берет из строки поиска :::
;:: После вызова в AX - количество секторов в кластере :::
;:: в BX - число свободных кластеров :::
;:: в CX - число байтов в секторе :::
;:: в DX - число кластеров на диске :::
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
GetInfo proc near
mov dl,0 ; В DL заносим 0, т.е. текущий диск
lea si,path ; Получаем букву диска из пути поиска
mov al,[si]
sub al,40h ; Переводим ее в цифру
cmp al,0 ; Номер диска 0 ?
jl not_1 ; Если меньше, выходим
cmp al,26 ; Номер диска 26 ?
jg again ; Если больше, то идем на проверку строчных букв
jmp mov_val ; Переход на обработку
again:
sub al,32 ; Если буква диска строчная, уменьшаем еще раз
cmp al,0 ; Номер диска 0 ?
jl not_1 ; Если меньше, выходим
cmp al,26 ; Номер диска 26 ?
jg not_1 ; Если больше, выходим
mov_val:
mov dl,al ; Заносим номер диска
not_1:
mov ah,36h ; Функция получения информации о диске
int 21h
ret
GetInfo endp
;::::::::::::::::::::::::::::::::::::::::::::::::::
;:: Выводит размер текущего диска в Килобайтах ::::
;::::::::::::::::::::::::::::::::::::::::::::::::::
totsize proc near
call GetInfo
mov temp,dx ; Запоминаем число кластеров
mul cx ; Умножаем число секторов на размер сектора
mul temp ; Умножаем все на количество кластеров
call Div1024 ; Делим на 1024 и получаем размер в Кбайтах
mov word ptr totalKB,ax ; Запоминаем младшее и старшее слово
mov word ptr totalKB+2,dx ; полученного результата
call Decimal
mov ah,9
lea dx,stringT
int 21h
ret
totsize endp
;:::::::::::::::::::::::::::::::::::::::::::::::
;::: Выводит размер свободного пространства ::::
;::: текущего диска в Килобайтах ::::
;:::::::::::::::::::::::::::::::::::::::::::::::
fresize proc near
call GetInfo
mul cx
mul bx
call Div1024
mov word ptr freeKB,ax
mov word ptr freeKB+2,dx
call Decimal
mov ah,9
lea dx,stringF
int 21h
ret
fresize endp
DecWrt proc near
lea si,outst ; очищаем строку
mov cl,0
mov [si],cl
mov [si+1],cl
lea si,outst
mov cl,48
mov [si],cl
mov cx,0010
lea si,outst+1
a20: cmp ax,0010
jb a30
xor dx,dx
div cx
or dl,30h
mov [si],dl
dec si
jmp a20
a30: or al,30h
mov [si],al
mov ah,40h ; выводим строку
mov bx,01
mov cx,02
lea dx,outst
int 21h
ret
outst db ' '
DecWrt endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::
;:: Процедура вывода числа в десятичном формате ::::
;:::::::::::::::::::::::::::::::::::::::::::::::::::
Decimal proc C uses es di bx cx dx ds
mov bx,10
push cs
pop es
push ax ; Заполняем массив DecString байтами 00
xor ax,ax ;
cld ;
mov cx,3 ;
lea di,DecStr ;
rep stosw ;
pop ax ;
lea di,DecStr+5 ; DI адресует последний байт массива
std
div bx
push ax
mov ax,dx
or al,30h ; Преобразуем в ASCII-символ.
stosb
pop ax
c10:
xor cx,cx
c20:
cmp ax,bx ; Делимое в AX, делитель в BX.
jb c30 ; Частное накапливается в CX.
sub ax,bx ; Деление методом вычитания
inc cx ; (страхует от переполнения)
jmp c20
c30:
or al,30h ; Переводим в ASCII
stosb ; Заносим в DecString
mov ax,cx
cmp ax,bx
jae c10
or al,0
jz c50
or al,30h
stosb
c50:
mov ah,9
lea dx,space
int 21h
mov ah,9
lea dx,DecStr
int 21h
ret
DecStr db 6 dup (0)
db '$'
Decimal endp
end begin
▐
▌
РBР[1]F*.FRM*.MAC
<
Б