Консультация № 183242
19.05.2011, 16:04
135.47 руб.
0 19 1
Здравствуйте, уважаемые эксперты! Прошу помощи в следующем вопросе:

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

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

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

Обсуждение

давно
Посетитель
7438
7205
20.05.2011, 13:10
общий
Дошли руки и до Вашего вопроса
"по дате" - это как? интервал? больше? меньше? как задавать дату? как задавать каталог? маску файлов?
Можно задать просто в тексте программы, можно спросить, можно задать в командной строке...
Если последнее, то опишите формат, который Вы хотели бы получить.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
20.05.2011, 16:37
общий
20.05.2011, 16:38
Это хорошо, что руки дошли до моего вопроса
По идее:
1. Запуск программы, вывод сообщения о вводе каталога.
2. Пользователь вводит каталог.
3. Вывод сообщения о вводе даты создания файла.
4. Пользователь вводит дату создания файла. Например: 12.05.11
5. Выполняется поиск файлов, которые были созданы именно в этот день, если не в этот день, то их оставляем в покое.
*Если можно: 6. Вывод всех найденных файлов*
7.Вывод сообщения о запросе на их удаление.
Если удалить, то
8. Удаление найденных файлов и выход.
Иначе
9. Оставить их в покое и выход.

Насчёт маски, думаю, что использовать такую: "*.*"
Вроде бы так.
давно
Посетитель
7438
7205
20.05.2011, 16:45
общий
No problem
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
20.05.2011, 17:18
общий
Надо ли проверять дату на корректность?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
20.05.2011, 17:20
общий
Можно.
давно
Посетитель
7438
7205
20.05.2011, 17:20
общий
И где ищем? В указаном каталоге или надо еще просматривать и подкаталоги?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
20.05.2011, 17:23
общий
И в каталоге, и в его подкаталогах.
давно
Посетитель
7438
7205
20.05.2011, 17:25
общий
Вопросов больше не имею Сделаем
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
20.05.2011, 17:26
общий
Спасибо!
давно
Посетитель
7438
7205
22.05.2011, 23:09
общий
это ответ
Здравствуйте, Денис!
Вот и программа.
Разберетесь?

[code h=207]
.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
[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
22.05.2011, 23:25
общий
Блок-схему добавлю позже...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
23.05.2011, 21:35
общий
Ох, не получается даже скомпилировать
Ведь нужно так
tasm dir.asm
Но не создаёт dir.obj

Ошибки при компиляции:
**Error** DIR.ASM(37) Illegal instruction
**Error** DIR.ASM(55) Extra characters on line
**Error** DIR.ASM(59) Extra characters on line
**Error** DIR.ASM(155) Extra characters on line
**Error** DIR.ASM(166) Extra characters on line
**Error** DIR.ASM(185) Extra characters on line
**Error** DIR.ASM(195) Extra characters on line
**Error** DIR.ASM(200) Extra characters on line
**Error** DIR.ASM(205) Extra characters on line
**Error** DIR.ASM(207) Extra characters on line
**Error** DIR.ASM(317) Extra characters on line
Подсажите, как правильно скомпилировать?
давно
Посетитель
7438
7205
23.05.2011, 21:45
общий
Хм, для начала загрузите в "мои файлы" свой исходник и дайте ссылочку.
Похоже, что с ним что-то не так...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
23.05.2011, 21:50
общий
Если я правильно понял то исходник tasm?

https://rfpro.ru/upload/5658 - tasm.exe
Неизвестный
23.05.2011, 22:05
общий
Если .asm, то я ничего не менял в коде
https://rfpro.ru/upload/5659 - dir.asm
давно
Посетитель
7438
7205
24.05.2011, 01:02
общий
Причина в Вашем Tasm-е. Он версии 1.0, не знает многих вещей...
Завтра на работе подправлю, чтобы заработало и на 1.0
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.05.2011, 08:41
общий
Ох, извините.
Большое спасибо!
давно
Посетитель
7438
7205
24.05.2011, 10:03
общий
24.05.2011, 10:11
Вот Вам подправленная программа под tasm 1.0
Надеюсь, Вам не надо говорить, что программа под формат COM, т.е.
надо линкировать с параметром /t

PS Назовите программу как-то по-другому, не dir
dir - зарезервированное слово, используется не буду говорить для чего

[code h=207]
.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
org 100h
start:
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

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

mov date, ax ;сохраним дату
;ищем файлы
push ax
push offset dir
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
PrintStrLoop:
lodsb
cmp al, 0
je PrintStrRet
int 29h
jmp PrintStrLoop
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
push SDPath
push ax
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 ;сохраним позицию, куда будем писать

push offset mm
push 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 ;скопируем имя найденного файла/каталога
push ax
push PathPos
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
push di
push ax
call SearchDir ;, di, ax ;ищем в поддиректории
jmp next

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

push di ;дата равна требуемой!
push es
mov ax, ds ;сохраним путь с именем
add ax, 1000h ;в сегменте за программой
mov es, ax
lea ax, NextPath
push ax
push NOff
call CopyStr ;, ax, NOff
mov NOff, di ;сохраним адрес для следующего имени
pop es
pop 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] ;число дней в месяце
push dx
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 start[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.05.2011, 17:19
общий
Большое спасибо, всё заработало.
Только блок-схемы не помешали бы, но всё-равно большое спасибо!
Форма ответа