Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

RFpro.ru: Ассемблер? Это просто! Учимся программировать


Хостинг портала RFpro.ru:
Московский хостер
Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64

РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты данной рассылки

Boriss
Статус: Академик
Рейтинг: 2670
∙ повысить рейтинг »
Абаянцев Юрий Леонидович aka Ayl
Статус: Профессионал
Рейтинг: 2266
∙ повысить рейтинг »
Жерар
Статус: Профессор
Рейтинг: 2156
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И СОФТ / Программирование / Assembler (Ассемблер)

Номер выпуска:1450
Дата выхода:24.05.2011, 16:30
Администратор рассылки:Лысков Игорь Витальевич (Старший модератор)
Подписчиков / экспертов:215 / 64
Вопросов / ответов:1 / 1

Вопрос № 183242: Здравствуйте, уважаемые эксперты! Прошу помощи в следующем вопросе: Необходимо разработать программу для поиска и удаления файлов по дате в заданном каталоге с подкаталогами. И ещё желательно сделать блок-схему по работе как процедур, так и пр...



Вопрос № 183242:

Здравствуйте, уважаемые эксперты! Прошу помощи в следующем вопросе:

Необходимо разработать программу для поиска и удаления файлов по дате в заданном каталоге с подкаталогами. И ещё желательно сделать блок-схему по работе как процедур, так и программы в целом.

Платформа: DOS, Тип ассемблера: TASM, Тип процессора: i8086. - вроде бы указал всё нужное.

Заранее спасибо.

Отправлен: 19.05.2011, 16:04
Вопрос задал: Денис (Посетитель)
Всего ответов: 1
Страница вопроса »


Отвечает Лысков Игорь Витальевич (Старший модератор) :
Здравствуйте, Денис!
Вот и программа.
Разберетесь?

Код :
 .model tiny, pascal

;структура, необходимая для поиска
_DTA struc
bRes db 21 dup (?)
bAttr db ?
dwTime dw ?
dwDate dw ?
ddSize dd ?
bName db 13 dup (?)
bLast db ?
_DTA ends

 .data
NCnt dw 0 ;счетчик найденных файлов
NOff dw 0 ;смещение для следующего имени
date dw 0 ;дата файла в спец формате
mm db '*.*',0 ;маска для поиска
sDir db 'Enter directory: $'
sDate db 0dh,0ah,'Enter date (dd.mm.yy): $'
sFound db 0dh,0ah,'Found $'
sFiles db ' files.$'
sDel db ' Delete ? (y,n)$'
sDel1 db 0dh, 0ah, 'Deleted $'
sAny db 0dh,0ah,'Press any key$'
;число дней в месяцах (для контроля правильности даты)
;учитывается високосный февраль
nDays db 31,28,31,30,31,30,31,31,30,31,30,31

;структура для ввода имены каталога
_name db 128
cntn db ?
dir db 128 dup (?)

;структура для ввода времени
_date db 11
cntd db ?
dated db 11 dup (?)

 .code
 .186
 .startup

 lea dx, sDir ;вводим каталог
 mov ah, 9
 int 21h
 lea dx, _name
 mov ah, 0ah
 int 21h

 xor bx, bx  ;заменим последний код 0dh на 0
 mov bl, cntn
 mov byte ptr dir[bx], 0

repeat:    ;цикл ввода правильной даты
 lea dx, sDate ;вводим дату в виде dd.mm.yy
 mov ah, 9  ;можно dd.mm и даже dd
 int 21h
 lea dx, _date
 mov ah, 0ah
 int 21h

;проверяем и конвертируем дату в спец формат
 call ConvertDate, offset dated
 jc repeat  ;если ошибка, то на повтор

 mov date, ax ;сохраним дату
;ищем файлы
 call SearchDir, ax, offset dir
;удаляем
 call Delete

PrintAny:
 lea dx, sAny
 mov ah, 9
 int 21h

 xor ax, ax
 int 16h

 mov ax, 4c00h
 int 21h

;вывод на экран ASCII строки
PrintStr proc
 lodsb
 cmp al, 0
 je PrintStrRet
 int 29h
 jmp PrintStr
PrintStrRet:
 ret
PrintStr endp

;копирование ASCII строки strSrc в strDst
CopyStr proc strSrc:word, strDst:word
 mov si, strSrc
 mov di, strDst
CopyStrLoop:
 lodsb
 stosb
 cmp al, 0
 jne CopyStrLoop
 ret
CopyStr endp

;удаление ранее найденных файлов
;с выдачей запроса
Delete proc
;выдача сообщения "Found NN files. Delete? (y,n)"
 lea dx, sFound ;Found
 mov ah, 9
 int 21h
 mov ax, NCnt ;NN
 call PrintNum
 lea dx, sFiles ;files
 mov ah, 9
 int 21h

 cmp NCnt, 0  ;если ничего не найдего
 je DelRet  ;то нечего и удалять

 lea dx, sDel ;Delete? (y,n)
 mov ah, 9
 int 21h

 mov ah, 0  ;Ждем
 int 16h
 or al, 20h  ;Превратим в маленькую буковку
 cmp al, 'y'
 jne DelRet  ;не y - ничего не делаем
    ;удаляем
 push ds  ;перейдем в сегмент с именами
 mov cx, NCnt ;количество имен
 mov ax, ds
 add ax, 1000h ;сегмент с именами
 mov ds, ax  ;ds для адреса имени
 mov es, ax  ;es для поиска следующего
 xor di, di  ;адрес имени
 xor bx, bx  ;счетчик удаленных
DeleteLoop:   ;по всем именам
 mov dx, di  ;ds:dx адрес имени удаляемого файла
 mov ah, 41h
 int 21h  ;удаляем!
 jc DeleteNext 
 inc bx  ;считаем реально удаленные
DeleteNext:
 push cx  ;найдем путь и имя следующего файла
 mov al, 0
 mov cx, 0ffffh
 repne scasb  ;ищем завершающий 0
 pop cx
 loop DeleteLoop ;по всем
 pop ds  ;востановим сегмент данных программы

 lea dx, sDel1 ;сообщение Deleted 
 mov ah, 9
 int 21h
 mov ax, bx  ;NN
 call PrintNum
 lea dx, sFiles ;files
 mov ah, 9
 int 21h
DelRet:
 ret
Delete endp

;Рекурсивная процедура поиска файлов
;параметры: дата и путь к каталогу
SearchDir proc SDDate:word, SDPath:word
local dta:_DTA, olddta:word:2
local NextPath:byte:128
local PathPos:word

;скопируем путь в локальный буфер
 lea ax, NextPath
 call CopyStr, SDPath, ax
;добавим в конце слеш, если его нет
 dec di
 cmp byte ptr [di-1],':' ;после диска слеш не добавляем!
 je SetLen
 cmp byte ptr [di-1],'\'
 je SetLen
 mov word ptr [di], '\'
 inc di
SetLen:
 mov PathPos, di  ;сохраним позицию, куда будем писать

 call CopyStr, offset mm, di ;добавим маску *.*

 push es   ;сохраним адрес старой DTA
 mov ah, 2fh
 int 21h
 mov olddta, bx
 mov olddta+2, es
 pop es

 mov ah, 1ah   ;установим новую DTA
 lea dx, dta
 int 21h

 mov ah, 4Eh   ;Ищем первый файл по маске
 lea dx, NextPath   ;путь с маской для поиска
 mov cx, 10h   ;ищем файлы с поддерикториями
 mov di, SDDate  ;дата, которую будем искать
DirLoop:
 int 21h    ;ищем первого/следующего
 jc found_error  ;ошибка?
 push di   ;сохраним дату
 lea ax, dta.bName  ;скопируем имя найденного файла/каталога
 call CopyStr, ax, PathPos ;с позиции PathPos (за слешем)
 pop di
 test byte ptr dta.bAttr, 10h ;проверим атрибут - подкаталог?
 jz FileFound  ;нашли файл
     ;подкаталог
 cmp word ptr dta.bName, '.' ;. и .. пропустим
 je next
 cmp word ptr dta.bName, '..'
 je next

 lea ax, NextPath
 call SearchDir, di, ax ;ищем в поддиректории
 jmp next

FileFound:
 cmp dta.dwDate, di  ;для файла сравниваем даты
 jne next

 push di es   ;дата равна требуемой!
 mov ax, ds   ;сохраним путь с именем
 add ax, 1000h  ;в сегменте за программой
 mov es, ax
 lea ax, NextPath
 call CopyStr, ax, NOff
 mov NOff, di  ;сохраним адрес для следующего имени
 pop es di
 inc NCnt   ;считаем

 mov al, 0dh   ;выведем на экран
 int 29h
 mov al, 0ah
 int 29h
 lea si, NextPath
 call PrintStr

next:
 mov ah, 4Fh   ; Ищем следующий
 jmp DirLoop   ; Продолжаем

found_error:
 cmp ax, 12h   ; ошибка 12h - завершение поиска
 je finish
;здесь анализ всех остальных ошибок
;надо бы, для полноты картины, проанализироать,
;но можно убрать вообще все от found_error до finish (последнюю оставить)
finish:
 push ds   ;восстановим DTA
 mov ah, 1ah
 lds dx, dword ptr olddta
 int 21h
 pop ds
 ret
SearchDir endp

;определение, является ли год nYear високосным
;параметры: ah - число дней в месяце, 
;bh - месяц (1-12), в случае високосного
;года увеличиваем для февраля ah на 1
;алгоритм:
; 1. Год делится на 400 -> високосный -> конец 
; 2. Год делится на 100 -> не високосный -> конец 
; 3. Год делится на 4 -> високосный -> конец 
; 4. Год не високосный -> конец
IsVisokosny proc nYear:word
 cmp bh, 2
 jne IVRet  ;рассматриваем только 2 месяц
 xor cx, cx  ;добавка = 0
 push ax
 push dx
 mov si, 400
 mov ax, nYear
 xor dx, dx
 div si  ;делим на 400
 test dx, dx
 jz VisokosnyYes ;нацело - високосный
 mov si, 100
 mov ax, nYear
 xor dx, dx
 div si  ;делим на 100
 test dx, dx
 jz VisokosnyNo ;нацело - невисокосный
 mov ax, nYear
 test al, 3
 jnz VisokosnyNo ;на 4 не делится - невисокосный
VisokosnyYes:   ;високосный
 inc cx  ;добавка = 1
VisokosnyNo:
 pop dx
 pop ax
 add ah, cl  ;добавляем поправку
IVRet:
 ret
IsVisokosny endp

;ввод числа (части даты)
GetNum  proc
 lodsb   ;первый символ
 sub al, '0'
 jc GNErr  ;< 0 - ошибка
 cmp al, 9
 ja GNErr  ;> 9 - ошибка
 mov dl, al  ;сохраним
 lodsb   ;следующий символ
 cmp al, 0dh
 je GNRet  ;конец строки - на выход
 cmp al, '.'
 je GNRet  ;точка - на выход
 sub al, '0'
 jc GNErr  ;< 0 - ошибка
 cmp al, 9
 ja GNErr  ;> 9 - ошибка
 xchg al, dl
 mov ah, 10
 mul ah
 add dx, ax  ;в dx день
 lodsb   ;следующий символ
 cmp al, 0dh
 je GNRet  ;конец строки - на выход
 cmp al, '.'
 jne GNErr  ;точка - на выход
GNRet:
 clc   ;все ок
 ret
GNErr:
 stc   ;ошибка
 ret
GetNum  endp

;проверка даты на корректность
;bl - день, bh - месяц, dx - год
CmpDate proc
 xor ax, ax
 mov al, bh  ;месяц
 cmp al, 1
 jl CmpDateErr
 cmp al, 12
 jg CmpDateErr ;должен быть [1,12]
 cmp bl, 1
 jl CmpDateErr ;день от 1 до максимального для месяца
 mov si, ax  ;месяц
 mov ah, nDays[si-1] ;число дней в месяце
 call IsVisokosny,dx ;поправка на високосный год
 cmp bl, ah  ;проверка на макс число
 jg CmpDateErr
 clc   ;дата корректна
 ret
CmpDateErr:
 stc   ;ошибка
 ret
CmpDate endp

;конвертация даты в спец формат
;параметр - адрес строки с датой dd.mm.yy
ConvertDate proc pDate:word
 mov si, pDate ;адрес строки
 xor dx, dx  ;обнулим на всякий случай
 call GetNum  ;день
 jc CDErr  ;ошибка?
 mov bl, dl  ;сохраним в bl
 cmp al, 0dh  ;конец строки?
 je CDDay  ;доформируем текущей датой

 call GetNum  ;месяц
 jc CDErr  ;ошибка?
 mov bh, dl  ;сохраним в bh
 cmp al, 0dh  ;конец строки?
 je CDMonth  ;доформируем текущей датой

 call GetNum  ;год
 jc CDErr  ;ошибка?
 cmp al, 0dh  ;если не конец строки
 jne CDErr  ;то ошибка!

 add dx, 2000 ;добавим до года старшие разряды
CDCmpDate:
 call CmpDate  ;проверим на корректность
 jc CDErr  ;ошибка?
    ;сконвертируем в спец формат
 sub dx, 1980 ;yyyyyyym mmmddddd - побитное содержимое полей
 shl dx, 9
 xor ax, ax
 mov al, bh
 shl ax, 5
 or al, bl
 or ax, dx
 clc
 ret
CDErr:
 stc   ;ошибка
 ret
CDMonth:
 mov ah, 2ah  ;добавим текущий год
 int 21h
 mov dx, cx
 jmp CDCmpDate ;на проверку

CDDay:
 mov ah, 2ah  ;добавим текущие месяц и год
 int 21h
 mov bh, dh
 mov dx, cx
 jmp CDCmpDate ;на проверку
ConvertDate endp

PrintNum proc  ;вывод беззнакового числа из ax
 push cx  ;сохраним счетчик колонок
 mov bx, 10  ;будем делить на 10
 xor cx, cx  ;счетчик цифр
DivLoop:
 xor dx, dx  ;готовимся к делению dx:ax / bx
 div bx  ;ax - частное, dx - остаток=очередной младшей цифре
 push dx  ;сохраним цифру в стеке
 inc cx  ;посчитаем
 test ax, ax  ;продолжим, пока не 0
 jnz DivLoop
 mov ah, 2  ;функция вывода
PrintLoop:   ;будем выводить в обратном порядке, начиная со старшей шифры
 pop ax  ;восстановим очередной разряд
 or al, '0'  ;превратим в символ
 int 29h  ;выведем
 loop PrintLoop
 pop cx  ;восстановим счетчик колонок матрицы
 ret
PrintNum endp

 end

-----
Люби своего ближнего, как самого себя

Ответ отправил: Лысков Игорь Витальевич (Старший модератор)
Ответ отправлен: 22.05.2011, 23:09
Номер ответа: 267299
Украина, Кировоград
Тел.: +380957525051
ICQ # 234137952
Mail.ru-агент: igorlyskov@mail.ru

Вам помог ответ? Пожалуйста, поблагодарите эксперта за это!
Как сказать этому эксперту "спасибо"?
  • Отправить SMS #thank 267299 на номер 1151 (Россия) | Еще номера »
  • Отправить WebMoney:


  • Оценить выпуск »
    Нам очень важно Ваше мнение об этом выпуске рассылки!

    Задать вопрос экспертам этой рассылки »

    Скажите "спасибо" эксперту, который помог Вам!

    Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА
    на короткий номер 1151 (Россия)

    Номер ответа и конкретный текст СМС указан внизу каждого ответа.

    Полный список номеров »

    * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов)
    ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
    *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.



    В избранное