19.12.2015, 21:58
общий
это ответ
Здравствуйте, muhaeva.elza!
Держите программу.
В ней много разных интересных моментов, например, использование структур,
а особенно, реализация сортировки... Изучайте, вникайте...
Будут вопросы - спрашивайте. Но программа достаточно неочевидная,
без самостоятельного скурпулезного разбора у Вас ничего не получится!
[code lang=asm h=200]
TITLE FAIL(EXE)
assume CS:code, DS:data
;некоторые структуры для удобства адресации данных
_dta struc ;ДТА
dta_res db 21 dup(?) ;резерв
dta_attr db ? ;атрибут файла
dta_time dw ? ;время файла
dta_date dw ? ;дата файла
dta_size_lo dw ? ;младшее слово длины файла
dta_size_hi dw ? ;старшее слово длины файла
dta_name db 13 dup (?) ;имя файла ASCIIZ, заканчивающееся 0
_dta ends
;структура, описывающая элемент для хранения найденного
;имени файла, его длины, а также поле, используемое для сортировки
_files struc
files_name db 13 dup (?) ;имя файла ASCIIZ
files_size_lo dw ? ;младшее слово длины файла
files_size_hi dw ? ;старшее слово длины файла
files_pointer dw ? ;указатель на структуру _files
_files ends
;структура, описывающая элемент для печати строки
_print struc
print_pos dw ? ;позиция курсора, low - колонка, high - строка
print_pstr dw ? ;указатель на строку ASCIIZ
_print ends
; описываем сегмент кода
code segment
PROGRAM_START: ; метка точки входа программы
; настройка регистра DS
mov AX, data
mov DS, AX
; освобождение памяти
mov AX, abcd ; сегментный адрес конца программы
mov DX, ES ; сегментный адрес начала программы
sub AX, DX ; размер программы в параграфах
mov BX, AX ; оставим его в BX
mov AH, 4ah ; функция изменения размера блока
int 21h
mov ax, 000dh ;переходим в графический режим 320х200
int 10h
lea si, directory ;адрес буфера для имени текущей директории
call GetDir ;сформируем имя текущей директории
lea di, text ;адрес массива, задающего набор строк для вывода
call print_text ;выводим текст на экран
call FindFiles ;ищем все файлы в текущей директории
call SortFiles ;сортируем по возрастанию длины файла
call PrintFiles ;выводим на экран
mov ah, 0
int 16h
mov ax, 0003h ;возвращаемся в текстовый режим
int 10h
mov ax, 4c00h
INT 21h ;вызов прерывание окончания работы программы
;вывод массива текста на экран
;параметр: di - адрес массива _print
print_text proc near
mov dx, [_print ptr di].print_pos ;строка, колонка
cmp dx, -1 ;дошли до конца?
je print_text_ret
mov si, [_print ptr di].print_pstr ;адрес строки
call print_str ;выводим с указанной позиции
add di, size _print ;на следующий элемент массива структур
jmp print_text
print_text_ret:
ret
print_text endp
;вывод строки [si] с указанной [dx] позиции
print_str proc near
mov ah, 2
xor bx, bx
int 10h ;позиция курсора
print_str_loop:
lodsb
cmp al, 0 ;строка заканчивается нулем
je print_str_ret
mov ah, 0eh ;функция выводит в текущей позиции курсора и
;автоматически смещает курсор на 1 вправо
mov bl, 0eh ;атрибут
int 10h
jmp print_str_loop
print_str_ret:
ret
print_str endp
;получаем имя полного пути текущей директории в [si]
GetDir proc near
mov ah, 19h ;текущий диск, 0 - А
int 21h
add al, 'A' ;делаем из номера букву
mov [si], al
mov ax,'\:' ;отделяем <диск>:/
mov word ptr [si+1], ax
add si,3 ;на позицию собственно имени директории
mov ah, 47h ;функция получения имени полного пути текущей директории
mov dl,0 ;текущего диска
int 21h
ret
GetDir endp
;поиск всех файлов и заполнение массива структур _files
FindFiles proc near
lea dx, dta ;зададим область DTA, необходимую для поиска
mov ah, 1ah
int 21h
lea di, files ;адрес массива _files
xor bp, bp ;счетчик файлов
lea dx, spec ;маска файлов "*.*"
mov cx, 0 ;атрибут файлов, которые ищем
mov ah,4eh ;начало поиска
search_loop:
int 21h
jc f_end ;ищем, пока ищется. В конце будет С=1 и АХ=12h
;возможны другие ошибки, но мы их для простоты
;проверять не будем, даже 12h. Выходим из поиска по С=1
lea si,dta.dta_name ;адрес имени файла в ДТА
;копируем в элемент массива _files
xor bx,bx ;будем индексировать с помощью bx
copy_name_loop:
lodsb
mov [_files ptr di+bx].files_name, al
inc bx
cmp al,0 ;копируем, включая завершающий 0
jne copy_name_loop
;копируем длину файла
mov ax, word ptr dta.dta_size_lo
mov [_files ptr di].files_size_lo,ax
mov ax, word ptr dta.dta_size_hi
mov [_files ptr di].files_size_hi,ax
mov [_files ptr di].files_pointer,di
add di,size _files ;на следующий элемент _files
inc bp ;считаем
mov ah,4fh ;продолжение поиска, dx не должен портиться!
jmp search_loop
f_end:
mov cx,bp ;возвращаем в СХ количество найденных файлов
ret
FindFiles endp
;Сортировка массива files по увеличению длины файла
;Используется сортировка "пузырьком"
;Чтобы меньше менять местами, введено поле указателя,
;которое и будет меняться местами
SortFiles proc near
lea si,files ;адрес массива
;найдем адрес последнего элемента массива
;будем по нему определять конец массива
mov ax,size _files ;размер элемента массива
mul cx ;умножаем на их количество
add ax,offset files - size _files ;минус размер одного
mov dx,ax ;dx - адрес последнего элемента массива
Sort_loop1: ;цикл по первому указателю
lea di,[si+size _files] ;второй начинается со следующего
Sort_loop2: ;цикл по второму указателю
cmp di,dx ;второй дошел до конца массива?
ja Sort_next1 ;если да, то на увеличение первого указателя
mov bx,[_files ptr si].files_pointer ;получаем укзатели на элементы
mov bp,[_files ptr di].files_pointer
;и сравниваем длины файлов
mov ax,ds:[_files ptr bp].files_size_hi ;сначала старшее слово
cmp ax,[_files ptr bx].files_size_hi ;сравнение беззнаковое!
jb Sort_change ;если второй меньше первого, то меняем местами
ja Sort_next2 ;если больше, то на увеличение второго указателя
mov ax,ds:[_files ptr bp].files_size_lo ;если равно, то сравниваем младшее слово
cmp ax,[_files ptr bx].files_size_lo
jae Sort_next2 ;если больше или равно, то на увеличение второго указателя
Sort_change: ;меняем местати
mov ax,[_files ptr di].files_pointer ;указатели в массиве
xchg ax,[_files ptr si].files_pointer
mov [_files ptr di].files_pointer,ax
xchg bx,bp ;и в регистрах
Sort_next2:
add di,size _files ;второй указатель - на следующий элемент
jmp Sort_loop2
Sort_next1:
add si,size _files ;увеличиваем первый указатель
cmp si,dx ;дошли до последнего?
jb Sort_loop1 ;нет - продолжаем
ret
SortFiles endp
;вывод имен файлов с их длинами
;cx - количество элементов массива
;выводим только столько, сколько помещается на экран, не более 17
PrintFiles proc near
lea si,files ;адрес массива files
mov bp,0804h ;начальная позиция курсора
cmp cx,17 ;проверим количество
jle print_names_loop
mov cx,17
print_names_loop:
mov dx,bp ;позиция для очередного элемента
push si ;сохраним адрес элемента массива
mov si,[_files ptr si].files_pointer ;адрес отсортированного элемента массива
push si ;сохраним его
call print_str ;выводим имя файла
pop si ;вернем адрес элемента массива
mov ax,[_files ptr si].files_size_lo ;длина файла
mov dx,[_files ptr si].files_size_hi
call PrintLen ;преобразуем число в строку и выведем
pop si ;вернем адрес в неотсортированном массиве
add si,size _files ;на следующий элемент
add bp,0100h ;смещаемся на строку ниже
loop print_names_loop
ret
PrintFiles endp
;вывод числа dx:ax в виде строки
;строка выравнивается по правому краю
;подпрограмма корректно выведет число до 655350000
PrintLen proc near
push cx ;сохраним счетчик элементов
lea di,number ;адрес буфера для строки-числа
mov si,di ;запомним для вывода
mov cx,' ' ;очистим 14 байт пробелами
mov [di],cx
mov [di+2],cx
mov [di+4],cx
mov [di+6],cx
mov [di+8],cx
mov [di+10],cx
mov [di+12],cx
mov byte ptr [di+15],0 ;закроем строку нулем
add di,14 ;на адрес последнего символа
;заполнять будем от младшего к старшему
mov cx,10000 ;разделим сначала на 10000
;сразу делить на 10 нельзя!
;может дать ошибку для больших чисел
div cx
mov cx,10 ;дальше будем делить на 10
test ax,ax ;число больше 10000?
jne big_number ;да, сначала выведем младшие 4 разряда
mov ax, dx ;<10000 - выводим число заведомо меньшее 10000
jmp small_number
big_number: ;выводим ровно 4 младшие цифры
push ax ;сохраним частное для дальнейшего вывода
mov ax,dx ;выводим остаток (4 младшие цифры)
xor dx,dx
div cx
or dl,'0'
mov [di],dl ;единицы
dec di
xor dx,dx
div cx
or dl,'0'
mov [di],dl ;десятки
dec di
xor dx,dx
div cx
or dl,'0'
mov [di],dl ;сотни
dec di
or al,'0'
mov [di],al ;тысячи
dec di
pop ax
small_number: ;выводим столько разрядов, сколько есть
xor dx,dx
div cx
or dl,'0'
mov [di],dl ;очередной разряд
dec di
test ax,ax
jne small_number ;пока есть что-то
mov dx,bp ;позиция вывода
add dx,15 ;вправо на 15 колонок
call print_str ;выводим строку-число на экран
pop cx
ret
PrintLen endp
code ends ;конец сегмента кода
; описание сегмента данных (переменные)
data segment
;массив для вывода кста на экран
text _print <0011h,cout1>
_print <0104h,cout2>
_print <020ch,cout3>
_print <0308h,cout4>
_print <040fh,cout5>
_print <050ah,cout6>
_print <0604h,directory>
_print <-1> ;признак конца массива
COUT1 DB "Rabota",0
COUT2 DB "Sistemnoe programnoe obespecenie",0
COUT3 DB "Studenta gruppi ",0
COUT4 DB "FIO",0
COUT5 DB "Variant #4",0
COUT6 db "Spisok failov v papke:",0
spec db "*.*",0 ;маска для поиска файлов
number db 16 dup(?) ;буфер для преобразования числа в строку
directory db 64 dup(?) ;буфер для имени текущей директории
dta _DTA <> ;область ДТА для поиска
files _files 1000 dup(<>) ;массив для хранения найденных имен файлов и их длин
;максимально - 1000 штук :)
data ends
; описываем сегмент стека
stk segment stack
dw 256 dup (?) ; выделяем под стек 256 слов
stk ends
abcd segment 'endseg' ; фиктивный сегмент для определения размера программы
abcd ends
end PROGRAM_START ; конец программы
[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен