На главную Назад
Добро пожаловать, уважаемый посетитель!

Прежде, чем перейти к упомянутому примеру, необходимо рассмотреть

формируемую DOS структуру данных - блок управления файлом FCB (File

Control Block), который является существенным элементом файловой

системы и участвует во всех файловых операциях.

 

Блок управления файлом обеспечивает связь пользовательской

программы с функциями DOS. При любой файловой операции происходит

обращение к блоку FCB. На Фиг.5.5 показан состав стандартного

блока FCB. Имеется модификация блока FCB, называемая расширенным

блоком FCB, которая применяется в специальных случаях, когда нужно

"скрыть" файл. Скрытый файл защищен от записи. Это значит, что

программа не может модифицировать содержимое этого файла, не

изменив предварительно его блока FCB. Скрытый файл не фигурирует в

листинге справочника. Скрыть файл - один из простейших способов

защиты файла от неумелого пользователя. В приводимых примерах

используются только стандартные блоки FCB.

 

Поля данных блока FCB охватывают все атрибуты файла. Номер

дисковода, имя и тип файла составляют идентификатор файла. Размер

файла и дата яаляются атрибутами файла, которые приводятся в

листинге справочника. Оставшиеся поля - текущий номер блока, длина

записи и номер записи при произвольном доступе - служат для

определения местоположения внутри файла при операциях чтения и

записи. Длина записи указывает на число байтов в определяемой

пользователем записи. Так как все операции чтения и записи в файл

начинаются с границы записи, то длина записи определяет количество

данных, обрабатываемых во время каждой из этих операций.

Существуют два способа определения текущей записи при обращении

к файлу. При первом, последовательном, способе записи

обрабатываются по порядку. При этом текущий номер блока и

относительный номер записи определяют запись, которая будет

обрабатываться следующей. По мере того, как программа выполняет

операции чтения или записи, DOS увеличивает на 1 относительный

номер записи, чтобы он указывал на следующую запись. Выполнение

ЪДДДДї

0 ііНомер носителя

ГДДДДЕДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДї

1 ііііііі іі Имя файла

ГДДДДЕДДДДЕДДДДЕДДДДБДДДДБДДДДБДДДДБДДДДЩ

9 ііііРасширение

ГДДДДЕДДДДЕДДДДЩ

0С іііТекущий блок

ГДДДДЕДДДДґ

0E іііРазмер записи

ГДДДДЕДДДДЕДДДДВДДДДї

10 іііііРазмер файла

ГДДДДЕДДДДЕДДДДБДДДДЩ

14 іііДата

ГДДДДЕДДДДЕДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДДї

16 ііііііі ііі іЗарезервировано

ГДДДДЕДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДДЩ

20 ііОтносительная запись

ГДДДДЕДДДДВДДДДВДДДДї(нумерация в блоке)

21 іііііНомер записи

АДДДДБДДДДБДДДДБДДДДЩпрямого доступа



Фиг. 5.5 Блок управления файлом

 

последовательных операций идет в направлении от начала к концу

файла. Примером последовательного файла служит программный файл на

языке ассемблера. Ассемблер осуществляет чтение записей от начала

до конца этого файла.

 

Программа может обращаться к файлу, используя также и

произвольный доступ. Произвольный в данном случае не означает, что

запись выбирается случайным образом. Наоборот, это значит, что

программа может выбрать в качестве следующей любую запись в файле.

По-другому такой файл называют файлом с прямым доступом, так как у

программы имеется непосредственный доступ к любой записи.

 

Программа может обращаться к файлу любым из двух указанных

способов. При последовательных операциях DOS автоматически изменяет

в блоке FCB значение поля относительного номера записи. При

произвольном доступе к файлу номер записи должен определяться

программой. В файловой системе файл с произвольным доступом

является аналогом вектора. Точно так же, как для обращения к любому

элементу вектора программа должна задать значение соответствующего

индекса, так и при обращение к записи в файле с произвольным

доступом номер записи должен определяться программой.

 

Теперь можно рассмотреть пример программы, использующей блок

FCB и функции DOS. На Фиг. 5.6 приведена длинная программа, которая

реально мало что делает. Ее цель - продемонстрировать использование

блока FCB и функци DOS, связанных с прерыванием 21H. Однако

содержащиеся в этой программе операции могут применяться в реальных

задачах.

Microsoft (R) Macro Assembler Version 5.001/1/80 04:02:12

Фиг. 5.6 Пример использования функций ДОС Page1-1

 

 

PAGE,132

TITLEФиг. 5.6 Пример использования функций ДОС

0000CODESEGMENT

005CORG05CH; Положение первого поля FCB

005CFCBLABELBYTE; Метка всего поля FCB

005C?? FCB_DRIVE DB? ; Номер устройства

005D0008[FCB_NAMEDB8 DUP (?); Имя файла

??

]

00650003[FCB_EXTDB3 DUP (?); Тип файла

??

]

 

0068????FCB_BLOCK DW? ; Номер текущего блока

006A????FCB_RECORD_SIZEDW? ; Размер записи

006C????????FCB_FILE_SIZEDD? ; Размер файла

0070????FCB_DATEDW? ; Дата последнего изменения

0072000A[FCB_RESVDB10 DUP (?); Зарезервировано ДОС

??

]

007C?? FCB_CURRENT_RECORDDB?; Номер текущей записи

007D????????FCB_RANDOM_RECORDDD?; Номер записи при прямом

;доступе

0090ORG090H

0090DISK_TRANSFER_ADDRESSLABELBYTE; Буфер для данных

 

0100ORG100H

ASSUMECS:CODE,DS:CODE,ES:CODE

0100E9 01CD RJMPPROGRAM_START; Переход на начало программы

 

= 0020RECORD_SIZEEQU32; Размер записи

010303 00 00 00 00KEYBOARD_BUFFER DB3, 0, 0, 0, 0; Буфер ввода с клавиатуры

010894 A0 A9 AB 20 E3 A6FILE_ERROR_MSGDB'Файл уже существует', 10, 13, '$'

A5 20 E1 E3 E9 A5 E1

E2 A2 E3 A5 E2 0A 0D

24

011E8D A5 A2 AE A7 AC AEBAD_OPEN_MSGDB'Невозможно открыть файл', 10, 13, '$'

A6 AD AE 20 AE E2 AA

E0 EB E2 EC 20 E4 A0

A9 AB 0A 0D 24

01388E E8 A8 A1 AA A0 20BAD_WRITE_MSGDB'Ошибка при записи в файл', 10, 13, '$'

AF E0 A8 20 A7 A0 AF

A8 E1 A8 20 A2 20 E4

A0 A9 AB 0A 0D 24

01538E E8 A8 A1 AA A0 20BAD_READ_MSGDB'Ошибка при чтении файла', 10, 13, '$'

AF E0 A8 20 E7 E2 A5

AD A8 A8 20 E4 A0 A9

AB A0 0A 0D 24

016D8E E8 A8 A1 AA A0 20BAD_CLOSE_MSGDB'Ошибка при закрытии файла', 10, 13, '$'

 

Фиг. 5.6 Пример использования функциямй DOS (начало)

AF E0 A8 20 A7 A0 AA

E0 EB E2 A8 A8 20 E4

A0 A9 AB A0 0A 0D 24

 

01898F E0 A8 20 A2 A2 AEINPUT_BAD_MSGDB'При вводе требуется два символа', 10, 13, '$'

A4 A5 20 E2 E0 A5 A1

E3 A5 E2 E1 EF 20 A4

A2 A0 20 E1 A8 AC A2

AE AB A0 0A 0D 24

01AB82 A2 AE A4 20 A4 AECHAR_BAD_MSGDB'Ввод должен быть: символ|символ', 10, 13, '$'

AB A6 A5 AD 20 A1 EB

E2 EC 3A 20 E1 A8 AC

A2 AE AB 7C E1 A8 AC

A2 AE AB 0A 0D 24

 

;-----Установка буфера (Области связи с диском)

 

01CDPROGRAM_START:

01CDB4 1AMOVAH, 1AH; Установка буфера

01CF8D 16 0090 RLEADX, DISK_TRANSFER_ADDRESS

01D3CD 21INT21H

 

;-----Поиск файла

 

01D5B4 11MOVAH, 11H; Поиск файла с заданным

01D78D 16 005C RLEADX, FCB;именем

01DBCD 21INT21H

01DD0A C0ORAL, AL

01DF75 0AJNZNO_FILE; Переход если файл новый

01E18D 16 0108 RLEADX, FILE_ERROR_MSG; Сообщение о неправильном

01E5ERROR_EXIT:; имени файла

01E5B4 09MOVAH, 9H; Вывод сообщения на экран

01E7CD 21INT21H;и выход из программы

01E9CD 20INT20H

 

;-----Создание нового файла

01EBNO_FILE:

01EBB4 16MOVAH, 16H; Создание файла

01ED8D 16 005C RLEADX, FCB

01F1CD 21INT21H

01F30A C0ORAL, AL; Проверка на успех

01F574 06JZCREATE_OK

01F78D 16 011E RLEADX, BAD_OPEN_MSG; Сообщение об ошибке при

01FBEB E8JMPERROR_EXIT;создании файла

 

;-----Установка параметров FCB

01FDCREATE_OK:

01FDC6 06 007C R 00MOVFCB_CURRENT_RECORD, 0; Инициализация номера

0202C7 06 007D R 0000MOVWORD PTR FCB_RANDOM_RECORD, 0;записи

0208C7 06 007F R 0000MOVWORD PTR FCB_RANDOM_RECORD+2, 0

020EC7 06 006A R 0020MOVWORD PTR FCB_RECORD_SIZE, RECORD_SIZE

 

Фиг. 5.6 Пример использования функциямй DOS (продолжение)

;-----Вывод в файл

 

0214B0 41MOVAL, 'A'; В этом цикле выводятся

0216CHARACTER_LOOP:; символы алфавита

 

02168D 3E 0090 RLEADI, DISK_TRANSFER_ADDRESS

021AB9 0020MOVCX, RECORD_SIZE

021DF3/ AAREPSTOSB; Заполнение буфера символами

021F50 PUSHAX; Сохранение символа

02208D 16 005C RLEADX, FCB

0224B4 15MOVAH, 15H; Последовательный вывод

0226CD 21INT21H;блока символов

02280A C0ORAL, AL; Проверка на ошибку

022A58 POPAX; Восстановление символа

022B74 06JZWRITE_OK

022D8D 16 0138 RLEADX, BAD_WRITE_MSG; Ошибка записи

0231EB B2JMPERROR_EXIT

0233WRITE_OK:

0233FE C0INCAL; Следующий символ

02353C 5BCMPAL, 'Z'+1; Проверка на окончание вывода

023775 DDJNECHARACTER_LOOP; Вывод следующего символа

 

;-----Изменение файла

0239KEYBOARD_LOOP:; Цикл ввода символов

02398D 16 0103 RLEADX, KEYBOARD_BUFFER;с клавиатуры и

023DB4 0AMOVAH, 0AH;изменение файла

023FCD 21INT21H; Ввод с клавиатуры

024180 3E 0104 R 02CMPKEYBOARD_BUFFER+1, 2; Было введено два символа?

024674 0AJEKEY_INPUT_OK

02488D 16 0189 RLEADX, INPUT_BAD_MSG; Сообщение об ошибке

024CKEYBOARD_ERROR:

024CB4 09MOVAH, 9H

024ECD 21INT21H; Печать сообщения об ошибке

0250EB E7JMPKEYBOARD_LOOP; Повторный ввод

0252KEY_INPUT_OK:

02528D 16 01AB RLEADX, CHAR_BAD_MSG; Установка указателя на

;сообщение об ошибке

0256A0 0105 RMOVAL, KEYBOARD_BUFFER+2; Выборка первого символа

02593C 24CMPAL, '$'; Сравнение с символом конца

025B75 03JNECHANGE_RECORD; Изменение записи

025DEB 5C 90JMPPROGRAM_EXIT

 

;-----Чтение старой записи из файла

0260CHANGE_RECORD:

02603C 41CMPAL, 'A'; Проверка на то, что символ

02627C E8JLKEYBOARD_ERROR;находится в диапазоне A-Z

02643C 5ACMPAL, 'Z'

026677 E4JAKEYBOARD_ERROR

02682A E4SUBAH, AH; Преобразование символа в

026A2C 41SUBAL, 'A';номер записи

026CA3 007D RMOVword ptr FCB_RANDOM_RECORD, AX; Занесение номера в FCB

026F8D 16 005C RLEADX, FCB

0273B4 21MOVAH, 21H; Прямое чтение записи

0275CD 21INT21H

 

Фиг. 5.6 Пример использования функциямй DOS (продолжение)

02770A C0ORAL, AL; Проверка на ошибку

027974 07JERANDOM_RECORD_OK

027B8D 16 0153 RLEADX, BAD_READ_MSG; Сообщение об ошибке

 

027FE9 01E5 RJMPERROR_EXIT

 

;-----Вывод старой записи на экран

 

0282RANDOM_RECORD_OK:

0282C6 06 00B0 R 0AMOVDISK_TRANSFER_ADDRESS+32, 10; Занесение символов конца

0287C6 06 00B1 R 0DMOVDISK_TRANSFER_ADDRESS+33, 13;строки и конца вывода

028CC6 06 00B2 R 24MOVDISK_TRANSFER_ADDRESS+34, '$';в буфер

0291B4 09MOVAH, 9H

02938D 16 0090 RLEADX, DISK_TRANSFER_ADDRESS

0297CD 21INT21H; Вывод записи на экран

 

;-----Изменение файла

 

0299A0 0106 RMOVAL, KEYBOARD_BUFFER+3; Выборка символа, на который будет

029CB9 001FMOVCX, RECORD_SIZE-1;заменяться содержимое записи

029F8D 3E 0091 RLEADI, DISK_TRANSFER_ADDRESS+1

02A3F3/ AAREPSTOSB; Замена 31 символа

02A5B4 22MOVAH, 22H

02A78D 16 005C RLEADX, FCB

02ABCD 21INT21H; Прямая запись на файла на

;старое место

02AD0A C0ORAL, AL; Проверка на ошибку

02AF74 07JZRANDOM_WRITE_OK

02B18D 16 0138 RLEADX, BAD_WRITE_MSG; Сообщение об ошибке

02B5E9 01E5 RJMPERROR_EXIT

02B8RANDOM_WRITE_OK:

02B8E9 0239 RJMPKEYBOARD_LOOP; Обработка следующей записи

 

;-----Конец программы

 

02BBPROGRAM_EXIT:

02BBB4 10MOVAH, 10H; Закрытие файла

02BD8D 16 005C RLEADX, FCB

02C1CD 21INT21H

02C30A C0ORAL, AL; Проверка на ошибку

02C574 07JZCLOSE_OK

02C78D 16 016D RLEADX, BAD_CLOSE_MSG; Сообщение об ошибке

02CBE9 01E5 RJMPERROR_EXIT

02CECLOSE_OK:

02CECD 20INT20H; Возврат в ДОС

02D0CODEENDS

END

 

Фиг. 5.6 Пример использования функциямй DOS (продолжение)

 

Приведенная программа состоит из двух частей. В первой части

создается файл из 26 записей длиной по 32 байта. Каждая запись

соответствует одной букве алфавита: запись 1 - это "AAAA...A",

запись 2 - "BBBB...B" и т.д. Данный файл формируется

последовательно. Во второй части программы этот файл Mincho"'>рассматривается как файл с произвольным доступом. В ответ на

введенный пользователем с клавиатуры запрос программа считывает и

выводит на дисплей одну из 26 записей. С помощью этого же ввода

осущкствляется редактирование записи: 31 символ записи, начиная со

второго, заменяется на значение, которое вводится с клавиатуры.

Выполнение программы завершается при вводе с клавиатуры символа

"$".

 

В этом примере моделируется справочная база данных. На первом

этапе программа осуществляет формирование этой базы данных. На

втором этапе выполняется обработка произвольных запросов к базе

данных и редактирование ее содержимого. Хотя любая реальная

программа управления базой данных гораздо сложнее, чем приведенный

здесь пример, однако он является хорошей иллюстрацией основных

функций, относящихся к работе с файлами.

 

Программа, приведенная на Фиг. 5.6, - это файл типа .COM. В

следующем разделе мы обсудим различие между этим файлом и файлом

типа .EXE. Использование в данном примере файла типа .COM позволяет

для завершения работы программы воспользоваться прерыванием INT

20H. В случае файла типа .COM начало программы в сегменте должно

иметь смещение 100H. Первые 100H байт программного сегмента

называются программным префиксом PSP и предназначены для хранения

некоторых специальных данных, которые используются программной,

написанной на языке ассемблера.

 

Смещение блока FCB в сегменте равно 05CH, и использование в

программе этого на первый взгляд произвольного адреса имеет

определенные основания. Запись информации в данный блок FCB

осуществляется командным процессором, входящим в состав DOS. После

того, как пользователь вызвал программу, указав ее имя, DOS

просматривает оставшуюся часть командной строки в поисках имен

файлов. Первое встретившееся в команде имя помещается в блок FCB,

смещение которого равно 05CH. Если в командной строке будет еще

одно имя, то оно запишется в блок FCB со смещением 06CH. Так как в

нашеи примере фигурирует только один файл, то используют только

блок FCB со смещением 05CH. Запуск описываемой программы

осуществляется с помощью следующей синтаксической конструкции:

 

A> FIG5=6 TEST.FIL

 

FIG5=6 - имя программы. В каталоге программа фигурирует под

именем FIG5=6.COM. Файл TEST.FIL является файлом, который программа

создает и затем модифицирует. Интерпретатор командных строк

выбирает имя "TEST.FIL" и помещает его в соответствующее поле блока

FCB со смещением 05CH. Рассматривая имя файла в качестве параметра

командной строки, можно с помощью описываемой программы создавать и

модифицировать любой файл. Если бы имя файла входило в ассемблерную

программу, мы могли бы работать только с единственным файлом.

 

Начиная со смещения 05CH, текст программы соответствует

структуре блока FCB. Первая ячейка идентифицируется меткой блока

FCB. Каждое из полей FCB имеет свою метку и длину, так что

программа может обрабатывать их непосредственно. Например, чтобы

задать длину записи, программа модифицирует переменную

FCB_RECORD_SIZE.

 

Начиная с адреса 080H помещается еще одно специальное поле

программного префикса. Эта область памяти размером 128 байт

отводится по умолчанию под область связи с диском DTA (Disk

Transfer Area) и используется DOS в качестве буфера для всех

файловых записей. Всякий раз, записывая или читая запись, DOS

использует буфер области DTA. Во время инициализации DOS

устанавливает смещение области DTA в программном сегменте равным

080H. Программа может изменить это значение, используя функцию 1AH

прерывания 21H. Это смещение должно быть изменено, еслм длина

записи больше, чем 128 байт. В рассматриваемом примере область

связи с диском сдвигается до смещения в сегменте, равного 90H. Это

связано с тем, что блок FCB со смещением 05CH выходит за границу с

адресом 80H. Если бы граница области DTA определялась соглашением,

принятым по умолчанию, то при передаче файлов информация в

последнем байте блока FCB была бы разрушена. В этом байте

записывается номер записи при произвольном доступе к файлу. Так как

в данной программе для чтения-записи данных используется

произвольный доступ, упомянутое наложение информации необходимо

исключить.

 

Первая команда программы имеет смещение 100H и является

переходом на фактическое начало программы. Такая структура

программы может показаться неэффективной, однако ассемблирование

происходит гораздо успешней, если все данные помещаются перед

командами, которые на них ссылаются. Фактически в программе могут

быть ошибки, если она содержит ссылки на данные вперед. Поэтому для

большей надежности данные помещаются в начале программы.

 

В первой части программы устанавливается область связи с

диском. В данной программе эта буферная область имеет смещение 90H.

Так как длина записи равняется только 32 байтам, то впереди

программы имется достаточно места.

 

Далее в программе используется прерывание 21H и функция DOS для

поиска файла с именем, совпадающим с именем, записанным в блоке

FCB. Обратите внимание, что пара регистров DC:DX указывает на блок

FCB, как и должно быть при любых файловых операциях. Если система

обнаружит файл с идентичным именем, программа завершит работу,

выдав сообщение об ошибке и сохранив существующий уже файл. В

данной программе обрабатываются только новые файлы. Существующие

файлы здесь никак не используются, однако гарантируется, что их

содержимое программой не сотрется. Конечно, в реальной практике

програма была бы составлена так, чтобы охватывать случай как новых,

так и уже существующих файлов.

 

Создание файла обеспечивается участком программы, помещенным

NO_FILE. Формировать блок FCB до этого данной программе не нужно,

так как он был сформирован командным процессором. Если описываемая

файловая операция не сможет быть выполнена, например, из-за

отсутствия свободного места на диске или отсутствия места в

каталоге диска, то программа завершит выполнение и выдаст

соответствующее сообщение об ошибке.

При любом обращении DOS к файлу программа должна, прежде всего,

открыть файл. Процедура открытия файла устанавливает связь между

операционной системой и пользовательской программой. В процессе

этой операции DOS просматривает справочник диска, находит нужный

файл (или не находит, что соответствует сбойной ситуации) и

заполняет поле блока FCB, относящееся к длине файла. После того,

как файл открыт, DOS не должна просматривать справочник диска

всякий раз, когда происходит обращение к файлу. Система DOS

сохраняет в блоке FCB информацию о файле до тех пор, пока она этот

файл не "закроет". Термины "закрыть" и "открыть" файл еще раз

указывают на связь с традиционным делопроизводством. Папку с файлом

документов нужно открыть прежде, чем можно будет ознакомиться с

содержащимся в ней бумагами, и закрыть до того, как ее уберут снова

в бюро.

 

В рассматриваемом примере открытие файла происходит при его

создании. Если бы такой файл уже существовал, связь с ним была бы

установлена с помощью функции открытия файла (AH=0FH). Если

открытие файла произошло успешно, программма изменяет значения

некоторых полей блока FCB. В частности, длина записи должна быть

установлена равной 32 байт, так как по умолчанию DOS считает ее

равной 128 байт.

 

Часть программы с именем CHARACTER_LOOP передает в файл 26

записей. Определяющий символ каждой записи передается в буфер

области DTA оператором REP STOSB. Отдельные записи передаются на

диск с помощью функции последовательной записи (AH=0AH). Программа

также выполняет проверку на отсутствие ошибок.

 

Начиная с метки KEYBOARD_LOOP программа переходит от

формирования файла к запросу=коррекции записей в нем. В данном

примере используется буферированный ввод с клавиатуры,

поддерживаемый DOS. Это позволяет пользователю вводить строку из

двух символов и, если необходимо, осуществлять редактирование.

После ввода двух символов должна быть нажата клавиша окончания

ввода. Программа выполняет проверку правильности ввода, и если

последний не удовлетворяет требованиям, то он отвергается и

выдается сообщение об ошибке.

 

При вводе пользователем символа "$" программа заканчивает

работу. В случае же ввода символов от "A" до "Z" программа

осуществляет чтение соответствующей записи и выводит на дисплей ее

содержимое. В оставшиеся 31 байт буфера программа записывает второй

из введенных с клавиатуры символов. Модицифированная таким образом

запись передается на диск в режиме произвольного доступа.

 

В заключительной части программы осуществляется закрытие файла.

Аналогично тому, как функция открытия файла устанавливала связь

между DOS и пользовательской программой,

 

??????

 

файла существенно для гарантии того, что DOS записала на диск все

модифицированные записи. Во время нормального выполнения программы

DOS может оставить несколько последних записей в буфере. Это

ускоряет выполнение, так как DOS не должна обращаться к диску по

поводу каждой записи. Функция закрытия файла осуществляет запись на

диск содержимого буфера.

 

Приведенный на Фиг. 5.6 пример программы иллюстрирует основные

способы обращения к файлу с помощью DOS. Эта программа ничего

полезного не выполняет, однако приближение ее к реальным задачам

потребовало бы намного большего числа команд, которые мало что

прояснили бы в отношении использования функций DOS. В данной

программе важно обратить внимание на необходимость проверки ошибок

после каждой операции, выполняемой DOS. В то время, как DOS с

помощью прерывания 24H обрабатывает аппаратные ошибки,

пользовательская программа должна разрешать такие ситуации, как

совпадение имен файлов или отсутствие свободного места на дискете.

В данном примере обработка ошибок проста и состоит из вывода

соответствующего сообщения и завершения работ программы. Обработка

ошибок в реальных программах значительно сложнее и более актуальна,

так как в этом случае возможность потери важной информации должна

быть исключена.

 

И наконец, возможно, что проработав с данной программой, вы

будете не очень удовлетворены ею как пользователь: в ней

отсутствует запрос на ввод данных, сообщения об ошибках лаконичны и

некоторые из выводимых сообщений частично накладываются на

предыдущие, затирая их. Данная программа нуждается в доработке

прежде, чем ею сможет воспользоваться кто-либо, не участвовавший в

ее написании или тщательно в ней не разобравшийся.


 

Mail.ru