Работа с символьними строками


part - текущий элемент раздела



бет3/3
Дата17.11.2023
өлшемі112.3 Kb.
#483586
түріЛабораторная работа
1   2   3
Лабораторная работа на С для системного программирования


part - текущий элемент раздела;
buff1[512] - буфер MBR и boot;
*mbr - указатель на таблицу разделов;
*boot - указатель на корневую запись;
buff2[512] - буфер каталога и текста;
*dir - указатель на часть каталога;
*text - указатель на текстовый буфер;
*fat - указатель на FAT;
job[81] - строка-задание;
jobptr - текущий указатель в job;
cname[12] - текущее имя для поиска;
Fdisk - физический номер диска;
caddr - текущий дисковый адрес;
sect - текущий номер сектора;
clust - текущий номер кластера;
fat16 - признак формата FAT;
fsize - размер файла;
dirnum - номер элемента в каталоге;
FirstSect - абсолютный номер сектора начала;
rootdir=1 - признак корневого каталога или подкаталога (1/0);
lastsect - последний сектор при чтении;
fatalloc=0 - признак выделения памяти.

5.1.3. Описание алгоритм программы


Функция main запрашивает имя файла, потом обрабатывает его и, если все нормально, то запускает вспомогательные функции необходимые для просмотра FAT заданного файла.


Функция Read_Mbr выполняет выборку элемента таблицы разделов для заданного диска.


Функция Read_Boot считывает boot-сектор логического диска, причем для гибкого диска адрес этого сектора назначается - 0, 0, 1, а для жесткого - выбирается из part.


Функция Get_First определяет абсолютный номер начального сектора логического диска и сохраняет его переменной First_Sect. Это значение вычисляется из физического адреса начала, который берется из полей Begin_Hd, Begin_SecTrk элемента таблицы разделов.


Функция Read_Fat считывает в память FAT целиком, адрес начала FAT на диске и ее размер определяются из ранее прочитанного boot-сектора.


Функция Read_13 читает один сектор с помощью прерывания BIOS.


Функция Sect_to_Daddr преобразует номер логического сектора в физический адрес.


Функция Clust_to_Sect преобразует номер кластера в номер сектора.


Функция Next_Clust определяет номер следующего кластера, анализируя FAT. Для последнего кластера (и для корневого каталога) эта функция возвращает нулевое значение.


Функция Get_Name предназначена для лексического разбора задания, она выделяет из задания очередное слово и переназначает jobptr. Пустое (NULL) значение jobptr - свидетельство об исчерпании задания.


Функция Find_Name выполняет поиск имени в каталоге. Здесь cname - требуемое имя, функция возвращает индекс найденного элемента в массиве dir или (-1).


Функция End_of_Job выполняет выдачу на экран различных сообщений при ошибках или при завершении программы.


5.2. Текст программы
/*------------------Лабораторная работа N9--------------------*/
/*--------------"Дисковые структуры данных DOS."--------------*/
/* Подключение стандартных заголовков */
#include
#include
#include
#include
#include
#include
/*-------------------------------------------------------------*/
/* Типи и структуры данных */
#define byte unsigned char
#define word unsigned int
#define dword unsigned long
#define daddr struct DADDR
struct DADDR { /* физический дисковый адрес */
byte h;
word s, t, ts;
};
struct PART { /* структура элемента раздела */
byte Boot, Begin_Hd;
word Begin_SecTrk;
byte SysCode, End_Hd;
word End_SecTrk;
dword RelSec, Size;
};
struct MBR
{ /* стpуктуpа Главной Загрузочной Записи */
char LoadCode[0x1be];
struct PART rt[4];
word EndFlag;
};
struct BootRec
{ /* структура корневой записи */
byte jmp[3], ident[8];
word SectSize;
byte ClustSize;
word ResSect;
byte FatCnt;
word RootSize, TotSecs;
byte Media;
word FatSize, TrkSecs, HeadCnt;
word HidnSecL, HidnSecH;
dword LongTotSecs;
byte Drive, reserved1, DOS4_flag;
dword VolNum;
char VolLabel[11], FatForm[8];
};
struct Dir_Item
{ /* структура элемента директории */
char fname[11];
byte attr;
char reserved[10];
word time, date, cl;
dword size;
};
/*-------------------------------------------------------------*/

/* Описания функций */


void Read_Mbr(void); /* Чтение MBR и поиск требуе-
мого раздела */
void Read_Boot(void); /* Чтение boot-сектора */
void Get_First(void); /* Определение абсолютного номе-
ра сектора начала логического
диска */
void Read_Fat(void); /* Чтение FAT */
void Read_13(void *mem); /* Чтение сектора с омогощью
прерывания 13 */
void Sect_to_Daddr(dword sect); /* Формирование физического дискового
адреса из # сектора */
dword Clust_to_Sect(word clust); /* Вычисление номера сектора
из номера кластера */
word Next_Clust(word clust); /* Выборка следующего кластера
из FAT */
char *Get_Name(char *s, char *d); /* Выделение следующего элемен-
та из строки-задания */
int Find_Name(); /* Поиск имени в каталоге */
void End_of_Job(int n); /* Завершение (при n=0-5 -
аварийное) */
/*-------------------------------------------------------------*/
/* Переменнi */
struct PART part; /* текущий элемент раздела */
byte buff1[512]; /* буфер MBR и boot */
struct MBR *mbr; /* указатель на таблицу разделов */
struct BootRec *boot; /* указатель на корневую запись */
byte buff2[512]; /* буфер каталога и текста */
struct Dir_Item *dir; /* указатель на часть каталога */
char *text; /* указатель на текстовий буфер */
byte *fat; /* указатель на FAT */
char job[81]; /* строка-задание */
char *jobptr; /* текущий указатель в job */
char cname[12]; /* текущее имя для поиска */
byte Fdisk; /* физический номер диска */
daddr caddr; /* текущий дисковый адрес */
dword sect; /* текущий номер сектора */
word clust; /* текущий номер кластера */
byte fat16; /* признак формату FAT */
dword fsize; /* размер файла */
int dirnum; /* номер элемента в каталоге */
dword FirstSect; /* абс.сектор начала */
byte rootdir=1; /* признак корневого каталога
или подкаталога (1/0) */
word lastsect; /* последний сектор при чтении */
byte fatalloc=0; /* признак выделения памяти */
/*-------------------------------------------------------------*/
main() {
int n,i;
textattr(14);
clrscr();
/* ввод имени файла */
cprintf(" Просмотр таблицы FAT. ");
cprintf("Укажите полное имя файла -->");
scanf("%s",job);
/* перевод в верхний регистр */
strupr(job);
/* проверка правильности идентификатора диска */
if ((!isalpha(job[0]))||(job[1]!=':')||(job[2]!='\\')) {
printf("%c%c%c -",job[0],job[1],job[2]);
End_of_Job(0);
}
textattr(10);
clrscr();
printf(" Лабораторная работа N9");
printf(" Дисковые структуры данных DOS.");
textattr(14);
cprintf("Файл %s в FAT занимает такие кластеры :\n",job);
jobptr=job+3;
if (job[0]>'A') {
/* для жесткого диска - физический номер и чтение MBR */
Fdisk=0x80;
Read_Mbr();
}
else /* для гибкого диска - физический номер */
Fdisk=job[0]-'A';
Read_Boot(); /* чтение boot-сектора */
Read_Fat(); /* чтение FAT */
dir=(struct Dir_Item *)buff2;
do { /* рух по каталогам */
if (!rootdir) clust=dir[dirnum].cl; /* начальный кластер */
/* выделение следующего элемента из строки-задания */
jobptr=Get_Name(jobptr,cname);
do { /* пока не дойдем до последнего кластера */
if (rootdir) { /* корневой каталог */
/* нач.сектор корневого кат. и количество секторов */
sect=boot->ResSect+boot->FatSize*boot->FatCnt;
lastsect=boot->RootSize*32/boot->SectSize+sect;
}
else { /* подкаталог */
sect=Clust_to_Sect(clust);
lastsect=boot->ClustSize+sect;
}
/* посекторное чтение всего корневого каталога
или одного кластера подкаталога */
for (; sectSect_to_Daddr(sect);
Read_13(dir);
/* поиск имени в прочитанном секторе */
if ((dirnum=Find_Name())>=0) goto FIND;
}
/* до последнего кластера подкаталога */
}
while (clust=Next_Clust(clust));
/* весь каталог просмотрен, а имя не найдено - ошибка */
printf("%s -",cname);
if (jobptr==NULL) End_of_Job(4);
else End_of_Job(5);

FIND: /* имя найдено */


rootdir=0;
}
while (jobptr!=NULL);
/* найдено имя файла */
/* из каталога получеем 1-й кластер */
clust=dir[dirnum].cl;
textattr(7);
gotoxy(10,4);
cprintf("Нажимайте любую клавишу ");
cprintf(" пока не появится <КОНЕЦ ФАЙЛА>.");
textattr(12);
gotoxy(1,5);
cprintf("-<НАЧАЛО ФАЙЛА>");
gotoxy(1,6);
cprintf("L->");
i=0;
do {
i++;
if((i%10)==0) getch();
textattr(14+16);
cprintf("%4x",clust);

textattr(2);


cprintf("--->");
}
while (clust=Next_Clust(clust));
textattr(12);
cprintf("<КОНЕЦ ФАЙЛА>\n");
gotoxy(1,wherey());
textattr(15+3*16);
cprintf("Количество кластеров в файле: %u ",i);
End_of_Job(7);
}
/*-------------------------------------------------------------*/
/* Чтение MBR и поиск нужного раздела */
void Read_Mbr(void) {
int i;
char ndrive;
word *EndList;
caddr.h=0;
caddr.ts=1;
ndrive='C';
mbr=(struct MBR *)buff1;

NEXT: Read_13(buff1);


for (EndList=(word *)&mbr->rt[(i=0)];
(*EndList!=0xaa55)&&(mbr->rt[i].Size>0L);
EndList=(word *)&mbr->rt[++i]) {
if (mbr->rt[i].SysCode==5) {
caddr.h=mbr->rt[i].Begin_Hd;
caddr.ts=mbr->rt[i].Begin_SecTrk;
goto NEXT;
}
if (ndrive==job[0]) {
movmem(&mbr->rt[i],&part,sizeof(struct PART));
return;
}
else ndrive++;
}
/* требуемый раздел не найден */
printf("%c: -",job[0]);
End_of_Job(1);
}
/*-------------------------------------------------------------*/
/* Чтение boot-сектора */
void Read_Boot(void) {
if (Fdisk<0x80) {
caddr.h=0;
caddr.ts=1;
}
else {
caddr.h=part.Begin_Hd;
caddr.ts=part.Begin_SecTrk;
}
Read_13(buff1);
boot=(struct BootRec *)buff1;
Get_First();
}
/*-------------------------------------------------------------*/
/* Чтение FAT */
void Read_Fat(void) {
dword s, ls;
byte *f;
fat=(byte *)malloc(boot->FatSize*boot->SectSize);
if (fat==NULL) {
printf("Размещение FAT -");
End_of_Job(3);
}
fatalloc=1;
s=boot->ResSect;
ls=s+boot->FatSize;
for (f=fat; sSect_to_Daddr(s);
Read_13(f);
f+=boot->SectSize;
}
/* установление формата FAT */
if (Fdisk>=0x80)
if (part.SysCode==1) fat16=0;
else fat16=1;
else fat16=0;
}
/*-------------------------------------------------------------*/
/* Чтение сектора при помощи прерывания 13 */
void Read_13(void *mem) {
/* mem - адреса в ОП */
union REGS rr;
struct SREGS sr;
rr.h.ah=2;
rr.h.al=1;
rr.h.dl=Fdisk;
rr.h.dh=caddr.h;
rr.x.cx=caddr.ts;
sr.es=FP_SEG(mem);
rr.x.bx=FP_OFF(mem);
int86x(0x13,&rr,&rr,&sr);
/* Проверка ошибок чтения */
if (rr.x.cflag&1) {
printf("%u -",rr.h.ah);
End_of_Job(2);
}
}
/*-------------------------------------------------------------*/
/* Определение абс.номера сектора начала лог.диска */
void Get_First(void) {
word s, t;
if (Fdisk<0x80) FirstSect=0;
else {
/* формирование # сектора из физич. дискового адреса */
t=(part.Begin_SecTrk>>8)|((part.Begin_SecTrk<<2)&0x300);
s=part.Begin_SecTrk&0x3f;
FirstSect=(((dword)t*boot->HeadCnt)+part.Begin_Hd)*
boot->TrkSecs+s-1;
}
}
/*-------------------------------------------------------------*/
/* Формирование физического дискового адреса из # сектора */
void Sect_to_Daddr(dword sect) {
/* sect - номер сектора, caddr - адрес на диске */
dword s;
if (Fdisk>=0x80) sect+=FirstSect;
caddr.s=sect%boot->TrkSecs+1;
s=sect/boot->TrkSecs;
caddr.h=s%boot->HeadCnt;
caddr.t=s/boot->HeadCnt;
caddr.ts=(caddr.t<<8)|caddr.s|((caddr.t&0x300)>>2);
}
/*-------------------------------------------------------------*/
/* Вычисление номера сектора из номера кластера */
dword Clust_to_Sect(word clust) {
/* clust - номер кластера, возвращает номер сектора */
dword ds, s;
ds=boot->ResSect+boot->FatSize*boot->FatCnt+
boot->RootSize*32/boot->SectSize;
s=ds+(clust-2)*boot->ClustSize;
return(s);
}
/*-------------------------------------------------------------*/
/* Выборка следующего кластера из FAT */
word Next_Clust(word clust) {
/* clust - номер кластера, возвращает номер следующего кластера
или 0 - если следующего нет */
word m, s;
if (rootdir) return(0);
if (!fat16) {
m=(clust*3)/2;
s=*(word *)(fat+m);
if(clust%2) /* нечетный элемент */
s>>=4;
else /* четный элемент */
s=s&0x0fff;
if (s>0x0fef) return(0);
else return(s);
}
else {
m=clust*2;
s=*(word *)(fat+m);
if (s>0xffef) return(0);
else return(s);
}
}
/*-------------------------------------------------------------*/
/* Выделение следующего элемента из строки-задания */
char *Get_Name(char *s, char *d) {
/* s - строка задания, d - выделенный элемент, возвращает
указатель на новое начало строки задания. */
char *p,*r;
int i;
for(i=0;i<11;d[i++]=' ');
d[11]='\0';
if ((p=strchr(s,'\\'))==NULL) {
/* последний элемент строки - имя файла */
/* перезапись имени */
for(r=s,i=0; (i<8)&&*r&&(*r!='.'); i++,r++) *(d+i)=*r;
/* перезапись расширения */
if (*r) for(i=0,r++; (i<3)&&*r; i++,r++) *(d+8+i)=*r;
return(NULL);
}
else {
/* следующий элемент - имя подкаталога */
*p='\0';
for(r=s,i=0; (i<11)&&*r; i++,r++) *(d+i)=*r;
return(p+1);
}
}
/*-------------------------------------------------------------*/
/* Поиск имени в каталоге */
int Find_Name() {
int j;
/* cname - найденное имя; возвращает индекс найденного
элемента в массиве dir или (-1) */
for (j=0; jSectSize/sizeof(struct Dir_Item); j++) {
if (dir[j].fname[0]=='\0') {
/* конец использованных элементов каталога */
printf("%s -",cname);
if (jobptr==NULL) End_of_Job(4);
else End_of_Job(5);
}
if ((byte)dir[j].fname[0]!=0xe5) {
if (memcmp(dir[j].fname,cname,11)==0) {
/* если iм`я збiгатся, то:
- при поиске файла элемент не должен иметь атрибутов
"подкаталог" или "метка тома",
- при поиске подкаталога элемент должен иметь атрибут
"подкаталог" */
if (jobptr==NULL)
if ( !(dir[j].attr&0x18) ) return(j);
else
if (dir[j].attr&0x10) return(j);
}
}
}
return(-1);
}
/*-------------------------------------------------------------*/
/* Завершение (при n=0-5 - аварийное) */
void End_of_Job(int n) {
/* n - номер сообщения */
static char *msg[] = {
"неправильный идентификатор диска",
"логический диск отсутствует",
"ошибка чтения",
"нехватка памяти",
"подкаталог не найден",
"файл не найден",
"непредусмотренный конец файла",
"" };
/* освобождение памяти */
if (fatalloc) free(fat);
/* выдача сообщения */
textattr(12+128);
cprintf(" %s\n",msg[n]);
gotoxy(28,wherey());
cprintf(" Нажмите любую клавишу...\n");
textattr(7);
getch();
/* завершение программы */
exit(0);
}

5.3. Результаты работы программы


В процессе работы программы на экран выводится информация наподобие следующей:


Лабораторная работа N9
Дисковые структуры данных DOS.
Файл D:\TC\TC.EXE в FAT занимает такие кластеры :
Нажимайте любую клавишу пока не появится <КОНЕЦ ФАЙЛА>.
-<НАЧАЛО ФАЙЛА>
8L->2410--->2411--->2412--->2413--->2414--->2415--->2416--->2417-
-->2418--->2419--->241a--->241b--->241c--->241d--->241e--->241f-
-->2420--->2421--->2422--->2423--->2424--->2425--->2426--->2427-
-->2428--->2429--->242a--->242b--->242c--->242d--->242e--->242f-
-->2430--->2431--->2432--->2433--->2434--->2435--->2436--->2437-
-->2438--->2439--->243a--->243b--->243c--->243d--->243e--->243f-
-->2440--->2441--->2442--->2443--->2444--->2445--->2446--->2447-
-->2448--->2449--->244a--->244b--->244c--->244d--->244e--->244f-
-->2450--->2451--->2452--->2453--->2454--->2455--->2456--->2457-
-->2458--->2459--->245a--->245b--->245c--->245d--->245e--->245f-
-->2460--->2461--->2462--->2463--->2464--->2465--->2466--->2467-
-->2468--->2469--->246a--->246b--->246c--->246d--->246e--->246f-
-->2470--->2471--->2472--->2473--->2474--->2475--->2476--->2477-
-->2478--->2479--->247a--->247b--->247c--->247d--->247e--->247f-
-->2480--->2481--->2482--->2483--->2484--->2485--->2486--->2487-
-->2488--->2489--->248a--->248b--->248c--->248d--->248e--->248f-
-->2490--->2491--->2492--->2493--->2494--->2495--->2496--->2497-
-->2498--->2499--->249a--->249b--->249c--->249d---><КОНЕЦ ФАЙЛА>
Количество кластеров в файле: 142
Нажмите любую клавишу...
Лабораторная работа N10
УПРАВЛЕНИЕ ПРОГРАММАМИ
1. Цель работы

Изучение принципов управления программами в MS DOS и приобретение практических навыков работы с префиксом программного сегмента и его полями.


2. Темы для предварительной проработки

Префикс программного сегмента и его структура, назначение его полей.


Определение версии DOS и получение адреса PSP программы.
3. Постановка задачи

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


4. Порядок выполнения работы

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


5. Пример решения задачи
5.1. Разработка алгоритма решения

5.1.1. Структура программы


Программа состоит из основной программы и двух функций:


void get_DOS_version_h(void) - функция, возвращающая в глобальной переменной dos_ver старшее число номера версии DOS.
void addr_PSP (void) - функция, получающая сегментный адрес префикса программного сегмента программы и возвращающая его в глобальной переменной pid.

5.1.2. Описание переменных


Переменные, глобальные для всей программы:


p_psp - указатель на структуру struct PSP,
pid - сегментный адрес PSP;
dos_ver - старшее число номера версии DOS;
i - вспомогательная переменная, используемая для просмотра таблицы файлов задачи (JFT), которая представляет собой массив из 20 элементов (хотя возможно, что их число отлично от 20, поэтому размер массива определим из поля JFT_size);
l - переменная, используемая для вывода содержимого сегмента окружения DOS и определения числа строк вызова (для версии DOS 3.0 и выше);
s - переменная, которая вначале используется как указатель на таблицу файлов задачи, затем на строки сегмента окружения и строки вызова;
rr - переменная, которая используется для задания значений регистров общего назначения при вызове прерывания.

5.1.3. Описание алгоритма программы


Данная программа производит распечатку основных полей своего PSP. Для этого префикс программного сегмента представим в виде следующей структуры:


struct psp
{ /* ФОРМАТ PSP */
byte ret_op[2]; /* команда INT 20h */
word end_of_mem; /* вершина доступной памяти */
byte reserved1;
byte old_call_dos[5]; /* старый вызов DOS */
void *term_ptr; /* адрес завершения */
void *ctrlbrk_ptr; /* адрес обработчика Ctrl+Break */
void *criterr_ptr; /* адрес обработчика крит.ошибок */
word father_psp; /* PID родителя */
byte JFT[20]; /* таблица файлов программы */
word env_seg; /* адрес окружения */
void *stack_ptr; /* адрес стека */
word JFT_size; /* размер таблицы файлов */
byte *JFT_ptr; /* адрес таблицы файлов */
byte reserved2[24];
byte new_call_dos[3]; /* новый вызов DOS */
} *p_psp;

Поле ret_op используется для возможного завершения программы по команде RET 0, поле old_call_dos, содержит команду вызова диспетчера функций DOS. Обращение к этому полю в программе может использоваться вместо команды INT 21h, но в современных версиях DOS для этих целей лучше обращаться к полю new_call_dos.


Поле end_of_mem содержит сегментный адрес конца доступной памяти в системе. В три поля: term_ptr, ctrlbrk_ptr, criterr_ptr DOS при загрузке программы копирует содержимое векторов прерываний: 22h, 23h, 24, представляющее собой адреса обработчиков: завершения программы, комбинации клавиш Ctrl+Break, критической ошибки - соответственно. Предполагается, что программа может свободно перенаправить эти векторы на собственные обработчики соответствующих ситуаций, но от забот по восстановлению векторов программа избавляется, так как при ее завершении DOS сама восстанавливает векторы из соответствующих полей PSP завершаемой программы. Для аналогичных целей предназначено и поле stack_ptr - в нем сохраняется (а при завершении - из него восстанавливается) адрес стека, использовавшегося до вызова программы. Поле, именуемое father_psp, содержит сегментный адрес PSP родителя - программы, запустившей данную программу, обычно родителем является COMMAND.COM.


При загрузке программы DOS, кроме программного сегмента, создает для нее еще и сегмент окружения. Сегмент окружения содержит ASCIIZ-строки, задающие значения некоторых глобальных переменных, эти значения могут устанавливаться командой DOS SET, они доступны командным файлам и - через PSP - программам. Набор строк окружения заканчивается пустой ASCIIZ-строкой (нулем). В DOS 3.0 и выше за ним следует еще 2-байтное число строк вызова (обычно 1) и далее - строка (или строки) вызова программы. Обычно в первую (до строк вызова) часть порождаемой программы копируется содержимое окружения программы-родителя. Программа имеет доступ к своему сегменту окружения через поле env_seg PSP, содержащее сегментный адрес окружения.


Поле JFT (Job File Table - Таблица Файлов Задачи) представляет собой массив из 20 однобайтных элементов. При открытии программой файла DOS формирует для него блок-описатль в системной таблице файлов и помещает ссылку на него (его номер) в свободный элемент JFT. Дескриптор файла, возвращаемый программе DOS при открытии файла, является номером элемента в JFT. При запуске программы первые пять элементов создаваемой для нее JFT содержат ссылки на системные файлы, остальные свободны. При обработке JFT DOS использует не прямое обращение к полю JFT PSP, а косвенное - через поле JFT_ptr, а в качастве ограничителя размера JFT - не константу 20, а значение поля JFT_size PSP.


После всего, сказанного выше, не составляет труда написать программу, осуществляющую форматный вывод своего префикса программного сегмента. Для в начале необходимо определить версию DOS (с помощью функции get_DOS_version_h() и получить адрес PSP (с помощью функции addr_PSP()).


Функция get_DOS_version_h() определяет старшее число номера версии DOS, используя для этого функцию DOS 30h (прерывание 21h), которая возвращает в регистре AL старшее число номера версии, а в регистре AH - младшее число. Нас интересует только значение регистра AL.


Функция addr_PSP() возвращает сегментный адрес PSP путем использования функции DOS 62h:


Вход: AH = 62h
Выход: BX = сегментный адрес PSP текущего процесса.

5.2. Текст программы


/*----------------Лабораторная работа N10-----------------*/
/*----------------"Управление программами"----------------*/

/* Подключение стандартных заголовков */


#include
#include

/* Типы данных */


#define byte unsigned char
#define word unsigned int

/* Описание функций */


void get_DOS_version_h(void); /* Определение версии DOS */
void addr_PSP (void); /* Получение адреса PSP */

struct psp


{ /* ФОРМАТ PSP */
byte ret_op[2]; /* команда INT 20h */
word end_of_mem; /* вершина доступной памяти */
byte reserved1;
byte old_call_dos[5]; /* старый вызов DOS */
void *term_ptr; /* адрес завершения */
void *ctrlbrk_ptr; /* адрес обработчика Ctrl+Break */
void *criterr_ptr; /* адрес обработчика крит.ошибок */
word father_psp; /* PID родителя */
byte JFT[20]; /* таблица файлов программы */
word env_seg; /* адрес окружения */
void *stack_ptr; /* адрес стека */
word JFT_size; /* размер таблицы файлов */
byte *JFT_ptr; /* адрес таблицы файлов */
byte reserved2[24];
byte new_call_dos[3]; /* новый вызов DOS */
} *p_psp;

word pid; /* сегм.адрес PSP */


int dos_ver, /* версия DOS */
i, l, j;
char *s;
union REGS rr;

main()
{


textbackground(0);
clrscr();
textattr(0x0a);
cprintf("---------------");
cprintf(" Лабораторная работа N10 ");
cprintf("---------------");
cprintf("---------------");
cprintf(" Управление программами ");
cprintf("---------------");
textcolor(11);
get_DOS_version_h();
addr_PSP();
/* распечатка PSP */
cprintf("\n\n Адрес PID = %04X\n\n\r",pid);
p_psp=(struct psp *)MK_FP(pid,0);
textcolor(10);
cprintf("Команды:\n\r");
cprintf("--------\n\r");
textcolor(14);
cprintf(" Завершение - int 20h:");
textcolor(12);
cprintf(" %02X %02X\n\r",p_psp->ret_op[0],p_psp->ret_op[1]);
textcolor(14);
cprintf(" Старый вызов DOS: ");
textcolor(12);
for (i=0;i<5;cprintf("%02X ",p_psp->old_call_dos[i++]));
textcolor(14);
cprintf("\n\r Новый вызов DOS: ");
textcolor(12);
for(i=0;i<3;cprintf("%02X ",p_psp->new_call_dos[i++]));
textcolor(10);
cprintf("\n\n\rАдреса:\n\r");
cprintf("-------\n\r");
textcolor(14);
cprintf(" Конец памяти: ");
textcolor(12);
cprintf("%04X:0000\n\r",p_psp->end_of_mem);
textcolor(14);
cprintf(" Обработчик завершения: ");
textcolor(12);
cprintf("%Fp\n\r",p_psp->term_ptr);
textcolor(14);
cprintf(" Обработчик Ctrl+Break: ");
textcolor(12);
cprintf("%Fp\n\r",p_psp->ctrlbrk_ptr);
textcolor(14);
cprintf(" Обработчик критич.ошибки: ");
textcolor(12);
cprintf("%Fp\n\r",p_psp->criterr_ptr);
textcolor(14);
cprintf(" Стек: ");
textcolor(12);
cprintf("%Fp\n\n\r",p_psp->stack_ptr);
textcolor(14);
cprintf("\n\rРодитель: ");
textcolor(12);
cprintf("%04X ",p_psp->father_psp);
textcolor(0x8b);
cprintf("\n\n\rНажмите любую клавишу ...\n\r\7");
getch();
clrscr();
textattr(0x0a);
cprintf("---------------");
cprintf(" Лабораторная работа N10 ");
cprintf("---------------");
cprintf("---------------");
cprintf(" Управление программами ");
cprintf("---------------");
/* Распечатка таблицы файлов */
s=p_psp->JFT_ptr;
textcolor(10);
cprintf("\n\n\rТаблица файлов: ");
textcolor(12);
cprintf("%Fp (%d) ",s,p_psp->JFT_size);
textcolor(11);
if (s==(byte *)p_psp+0x18)
cprintf(" - в этом же PSP");
cprintf("\n\r");
for (i=0; ++i<=p_psp->JFT_size; cprintf("%d ",*(s++)));
textcolor(10);
cprintf("\n\n\rОкружение DOS: ");
textcolor(12);
cprintf("%04X\n\r",p_psp->env_seg);
s=(char *)MK_FP(p_psp->env_seg,0);
textcolor(11);
while(l=strlen(s))
{
cprintf(" %s\n\r",s);
s+=l+1;

}
if (dos_ver>2)


{
/* для DOS 3.0 и дальше можно получить строку вызова */
s++;
l=*((int *)s);
textcolor(10);
cprintf("\n\rЧисло строк вызова: ");
textcolor(12);
cprintf("%d\n\r",l);
s+=2;
textcolor(11);
for(i=0; i{
cprintf("%s\n\r",s);
s+=strlen(s)+1;
}
}
textattr(0x8b);
cprintf("\n\n\n\n\rНажмите любую клавишу ...\7");
textattr(0x07);
cprintf("\n\r");
getch();
clrscr();
}

/* Определение версии DOS */


void get_DOS_version_h(void)
{
rr.h.ah=0x30;
intdos(&rr,&rr);
dos_ver=rr.h.al;
}

/* Получение адреса PSP */


void addr_PSP (void)
{
rr.h.ah=0x62;
intdos(&rr,&rr);
pid=rr.x.bx;
}
5.6. Результаты работы программы

В процессе работы программы на экран была выведена следующая информация:


--------------------------------------------------------------------------------
--------------- Лабораторная работа N10 ---------------
--------------- Управление программами ---------------
Адрес PID = 0BA0

Команды:
--------


Завершение - int 20h: CD 20
Старый вызов DOS: 9A F0 FE 1D F0
Новый вызов DOS: CD 21 CB

Адреса:
-------


Конец памяти: 9FC0:0000
Обработчик завершения: 0AFA:02B1
Обработчик Ctrl+Break: 0AFA:014A
Обработчик критич.ошибки: 0AFA:0155
Стек: 0E04:0F94
Родитель: 0AFA

Таблица файлов: 0BA0:0018 (20) - в этом же PSP


1 1 1 0 2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1

Окружение DOS: 0A1E


CONFIG=STD
COMSPEC=C:\DOS\COMMAND.COM
PROMPT=$p$g
PATH=D:\WIN;C:\;C:\DOS;C:\ARH;C:\NC;C:\BAT;D:\TP;D:\TP7;D:\BC\BIN
TEMP=d:\~TMP

Число строк вызова: 1


D:\TC\TC_LAB10.EXE
Лабораторная работа N11
ДРАЙВЕРЫ DOS
1. Цель работы

Просмотреть список драйверов, которые в данный момент загружены в конкретной ПЭВМ.


2. Темы для предварительной проработки

Системные управляющие блоки DOS.


Драйверы устройств.
3. Постановка задачи

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


4. Порядок выполнения работы

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


5. Пример решения задачи
5.1. Разработка алгоритма решения

5.1.1. Структура программы


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


Функции GetSym, GetAtr, PutSym,
PutAtr описаны в лабораторной работе N7.
void clrbuf(void) - функция очищает буфер клавиатуры.
void MemW(x,y,xr,yr) - функция запоминает содержимое области экрана.
void RmmW(x,y,xr,yr) - функция восстанавливает сохраненную область экрана функцией MemW на экране.
void ClrW(x1,y1,x2,y2,s,a) - функция очищает прямоугольную область на экране заданным символом и атрибутом.
void FlDrv(void) - функция выводит в окно подробное описание атрибутов драйвера.

5.1.2. Описание переменных


Переменные глобальные для всей программы:


xk,yk - координаты курсора;
cc - переменная для хранения кода нажатой клавиши;
bm[rx][ry][2] - буфер для запоминания области на экране.

В программе описана следующая структура заголовка драйвера:


struct DR_HEAD {
struct dr_head *next; /* адрес следующего */
word attr; /* атрибуты */
word strat_off, intr_off; /* смещения секций */
char name[8]; /* имя */
};

5.1.3. Описание алгоритма программы


Основная программа main() осуществляет просмотор списка драйверов и выводит на экран информацию о них при помощи вспомогательных функций.


Функция clrbuf(void) читает символы из буфера клавиатуры, пока он не опустеет.


Функция MemW(x,y,xr,yr) использует для обращения к видеопамяти функции GetSym, GetAtr. x, y - координаты левого верхнего угла прямоугольной области экрана. 8xr, yr - размеры области по горизонтали и вертикали соответственно.


Функция RmmW(x,y,xr,yr) использует для обращения к видеопамяти функции PutSym, PutAtr. x, y - координаты левого верхнего угла прямоугольной области экрана. xr, yr - размеры области по горизонтали и вертикали соответственно.


Функция ClrW(x1,y1,x2,y2,s,a) - использует для обращения к видеопамяти функции PutSym, PutAtr. x1, y1, x2, y2 - координаты прямоугольной области. s, a - символ и атрибут соответственно для заполнения области экрана.


Функция FlDrv(void) рассматривает побитно байт атрибута драйвера и может выдавать информацию в соответствии со значением атрибута.
Слово атрибутов драйвера в старшем разряде содержит признак символьного (1) или блочного (0) устройства. Интерпретация остальных разрядов слова атрибутов существенно разная для символьных и блочных устройств. Для символьных устройств слово атрибутов имеет формат:
1 e b 0 p 0 0 0 0 l 0 0 c n o i,

а для блочных устройств:


0 e m 0 p 0 0 0 0 l 0 0 0 0 s 0,
где i - драйвер консоли ввода;
o - драйвер консоли вывода;
n - драйвер нулевого (пустого) устройства;
c - драйвер часов;
l - драйвер поддерживает функции, введенные в DOS 3.2;
p - драйвер выполняет операции Open/Close;
b - драйвер неIBM-овского блочного устройства;
e - драйвер поддерживает функции IOCTL;
s - драйвер поддерживает 32-битную адресацию сектора;
m - драйвер определяет тип диска проверкой 1-го байта FAT.
По правилам DOS кодовая часть драйвера состоит из двух секций, называемых секцией стратегии и секцией обработки прерываний. Поля strat_off и intr_off заголовка содержат смещения этих секций от начала драйвера. Поле name для символьного устройства содержит имя устройства (возможно, дополненное пробелами), а для блочного - первый байт этого поля содержит количество устройств, поддерживаемых драйвером.

При помощи поля next, заполняемого системой при загрузке драйвера, все драйверы (системные и устанавливаемые) связываются в список. Начало этого списка - заголовок драйвера NUL в CVT. Значение FFFFh в части смещения поля next является признаком конца списка (такой же признак конца используется и в списках, образуемых другими управляющими блоками). Главная программа примера отслеживает этот список.


5.2. Текст программы
/*----------------Лабораторная работа N11-----------------*/
/*--------------"Просмотр списка драйверов."--------------*/
#include
#include
/*-----------------------Константы----------------------- */
#define byte unsigned char
#define word unsigned int
#define ATR(x,z) if(drv->attr&x){cprintf(" %s\n\r",z);y++;}
#define DA(x,y) (struct DR_HEAD *)MK_FP(x,y);
#define VSEG 0xb800 /* Сегментный адрес видеопамяти */
#define byte unsigned char
#define word unsigned int
#define Enter 13
#define rx 50
#define ry 13

int xk,yk;


word cc;
byte bm[rx][ry][2];
8struct DR_HEAD { /* заголовок драйвера */
struct DR_HEAD *next;
word attr, strat_addr, intr_addr;
char name[8];
} *drv; /* адрес текущего драйвера */
struct DR_HEAD *clock, *con; /* Адреса CLOCK$ и CON */
union REGS rr;
struct SREGS sr;
int i, y, y1;

/*---------------------------------------------------*/


void clrbuf(void)
{
while(kbhit()) getch();
}
/*--------------Чтение символа из видеопамяти-------------*/
byte GetSym(x1,y1)
int x1,y1;
{
return(peekb(VSEG,y1*160+x1*2));
}
/*-------------Чтение атрибута из видеопамяти-------------*/
byte GetAtr(x1,y1)
int x1,y1;
{
return(peekb(VSEG,y1*160+x1*2+1));
}
/*-------------Запись символа в видеопамять---------------*/
void PutSym(x1,y1,sym)
int x1,y1;
byte sym;
{
pokeb(VSEG,y1*160+x1*2,sym);
}
/*-------------Запись атрибута в видеопамять--------------*/
void PutAtr(x1,y1,atr)
8int x1,y1;
byte atr;
{
pokeb(VSEG,y1*160+x1*2+1,atr);
}
/*--------------------------------------------------------*/
void MemW(x,y,xr,yr)
int x,y,xr,yr;
{
int i,j;
for (j=y;j<(y+yr);j++)
for (i=x;i<(x+xr);i++)
{
bm[i][j][0]=GetSym(i,j);
bm[i][j][1]=GetAtr(i,j);
}
}
/*--------------------------------------------------------*/
void RmmW(x,y,xr,yr)
int x,y,xr,yr;
{
int i,j;
for (j=y;j<(y+yr);j++)
for (i=x;i<(x+xr);i++)
{
PutSym(i,j,bm[i][j][0]);
PutAtr(i,j,bm[i][j][1]);
}
}
/*--------------------------------------------------------*/
void ClrW(x1,y1,x2,y2,s,a)
int x1,y1,x2,y2;
byte s,a;
{
int i,j;
for (j=y1;jfor (i=x1;i{
if (s!=0) PutSym(i,j,s);
PutAtr(i,j,a);
}
}
/*--------------------------------------------------------*/
void FlDrv(void)
{
int xm,ym;
xm=wherex();
ym=wherey();
MemW(0,1,rx,ry);
ClrW(1,2,rx,ry,0,7);
ClrW(0,1,rx-2,ry-2,32,16);
gotoxy(1,2);
textattr(15+16*3);
cprintf("*** Атрибуты драйвера %5u ***",cc);
gotoxy(1,3);
textattr(15+16);
if (drv==clock) cprintf(" активный CLOCK$");
if (drv==con) cprintf(" активный CON");
gotoxy(1,4);
textattr(14+16);
if (drv->attr&0x8000)
{
ATR(1,"консоль ввода")
ATR(2,"консоль вывода")
ATR(4,"нулевое устройство")
ATR(8,"CLOCK$ (часы)")
ATR(0x2000,"поддерживает OUB")
}
else
{
ATR(2,"32-байтный адрес сектора")
ATR(0x2000,"читает media FAT")
}
ATR(0x40,"поддерживает функции DOS 3.2")
ATR(0x800,"поддерживает Open/Close")
ATR(0x4000,"поддерживает IOCTL")
gotoxy(1,12);
textattr(15+16*3+128);
cprintf("*** Нажмите любую клавишу... ***");
if (getch()==0) getch();
RmmW(0,1,rx,ry);
gotoxy(xm,ym);

}
/*--------------------------------------------------------*/


main() {
int c;
/* получение адреса CVT */
rr.h.ah=0x52; intdosx(&rr,&rr,&sr);
/* адрес драйвера часов */
clock=DA(peek(sr.es,rr.x.bx+10),peek(sr.es,rr.x.bx+8));
/* адрес драйвера консоли */
con=DA(peek(sr.es,rr.x.bx+14),peek(sr.es,rr.x.bx+12));
/* адрес NUL-драйвера */
textattr(10);
clrscr();
cprintf("---------------");
cprintf(" Лабораторная работа N11 ");
cprintf("---------------");
cprintf("---------------");
cprintf(" Просмотр списка драйверов. ");
cprintf("---------------");

drv=DA(sr.es,rr.x.bx+34);


textattr(7);
gotoxy(8,3);
cprintf("Нажимайте ,а для рассмотрения атрибутов",
"драйвера .");
textattr(12);
gotoxy(28,4);
cc=1;
cprintf("Список драйверов устройств :\n\r");
while(FP_OFF(drv)!=0xffff) {
textattr(15);
cprintf("%5u",cc);
textattr(14);
cprintf(" Адрес - %Fp ",drv);
textattr(11);
cprintf(" атрибуты - %04X ",drv->attr);
textattr(13);
if (drv->attr&0x8000)
for (i=0;i<8; cprintf("%c",drv->name[i++]));
else cprintf("блочный - %d",drv->name[0]);
cprintf("\n\r"); y=0;
while ((c=getch())==Enter)FlDrv();
if (c==0) getch();
drv=drv->next; /* адрес след.драйвера */
cc++;
}
textattr(12+128);
cprintf("Конец списка. Нажмите любую клавишу...\n");
getch();
textattr(7);
}
5.3. Результаты работы программы

В процессе работы программы на экран была выведена следующая информация о распределении памяти:


--------------------------------------------------------------------------------
--------------- Лабораторная работа N11 ---------------
--------------- Просмотр списка драйверов. ---------------
Нажимайте ,а для рассмотрения атрибутов драйвера .
Список драйверов устройств :
1 Адрес - 011C:0048 атрибуты - 8004 NUL
2 Адрес - 02A6:0000 атрибуты - 8000 SETVERXX
3 Адрес - 025D:0000 атрибуты - A000 XMSXXXX0
4 Адрес - 0070:0023 атрибуты - 8013 CON
5 Адрес - 0070:0035 атрибуты - 8000 AUX
6 Адрес - 0070:0047 атрибуты - A0C0 PRN
7 Адрес - 0070:0059 атрибуты - 8008 CLOCK$
8 Адрес - 0070:006B атрибуты - 08C2 блочный - 4
9 Адрес - 0070:007B атрибуты - 8000 COM1
10 Адрес - 0070:008D атрибуты - A0C0 LPT1
11 Адрес - 0070:009F атрибуты - A0C0 LPT2
12 Адрес - 0070:00B8 атрибуты - A0C0 LPT3
13 Адрес - 0070:00CA атрибуты - 8000 COM2

14 Адрес - 0070:00DC атрибуты - 8000 COM3


15 Адрес - 0070:00EE атрибуты - 8000 COM4
Конец списка. Нажмите любую клавишу...

--------------------------------------------------------------------------------


При нажатии клавиши Enter открывается окно в котором подробно расписываются атрибуты драйвера. Например, атрибуты драйвера 8:


------------------------------------------------
------------------------------------------------
----------- Атрибуты драйвера 8 ------------
------------------------------------------------
---- 32-байтный адрес сектора ------------------
---- поддерживает функции DOS 3.2 --------------
---- поддерживает Open/Close -------------------
------------------------------------------------
------------------------------------------------
------------------------------------------------
------------------------------------------------
------------------------------------------------
--------- Нажмите любую клавишу... -----------


Достарыңызбен бөлісу:
1   2   3




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет