#include <dos.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
  unsigned mcb_seg;
  void far *dev_cb;
  void far *file_tab;
  void far *clock_dr;
  void far *con_dr;
  unsigned max_btbl;
  void far *disk_buf;
  void far *drv_info;
  void far *fcb_tabl;
  unsigned fcb_size;
  unsigned char num_bdev;
  unsigned char lastdriv;
} CVT;
typedef CVT far* LPCVT;

typedef struct _DDCB_
{
  unsigned char drv_num;
  unsigned char drv_numd;
  unsigned sec_size;
  unsigned char clu_size;
  unsigned char clu_base;
  unsigned boot_siz;
  unsigned char fat_num;
  unsigned max_dir;
  unsigned data_sec;
  unsigned hi_clust;
  unsigned char fat_size;
  char reserv1;
  unsigned root_sec;
  void far *drv_addr;
  unsigned char media;
  unsigned char acc_flag;
  struct _DDCB_ far *next;
  unsigned reserv2;
  unsigned built;
} DDCB;
typedef DDCB far* LPDDCB;

void main(void);
LPDDCB get_fddcb(LPCVT cvt);
LPDDCB get_nddcb(LPDDCB ddcb);

void main(void)
{
  union REGS regs;
  struct SREGS sregs;
  LPCVT     lpCVT;
  LPDDCB    lpDDCB;

  printf("\nБлоки управления дисковыми устройствами DDCB"
    "\n(C) Фролов А.В., 1995\n\n");

  // Получаем адрес векторной таблицы связи
  regs.h.ah = 0x52;
  intdosx(&regs, &regs, &sregs);

  // Передвигаем указатель на поле msb_seg
  lpCVT = (LPCVT)MK_FP(sregs.es, regs.x.bx - 2);

  // Получаем адрес первого блока DDCB
  lpDDCB = get_fddcb(lpCVT);

  for(;;)
  {
    // Если это последний блок, завершаем цикл
    if(lpDDCB == NULL) break;
      printf("Адрес DDCB:                         %Fp\n"
	"Номер устройства:                   %d\n"
	"Дополнительный номер:               %d\n"
	"Размер сектора:                     %d\n"
	"Размер кластера в секторах:         %d\n"
	"База размера кластера:              %d\n"
	"Зарезервировано секторов:           %d\n"
	"Число копий FAT:                    %d\n"
	"Макс. файлов в корневом каталоге :  %d\n"
	"Первый кластер данных:              %d\n"
	"Всего кластеров:                    %ld\n"
	"Размер FAT в секторах:              %d\n"
	"Первый сектор корневого каталога:   %d\n"
	"Поле reserv1:                       %01X\n"
	"Адрес драйвера:                     %Fp\n"
	"Байт описателя среды носителя:      %01X\n"
	"Флаг доступа:                       %01X\n"
	"Адрес следующего DDCB:              %Fp\n"
	"Поле reserv2:                       %04X\n"
	"Блок заполнен:                      %04X\n"
	"-------------------------------------\n\n",
	 lpDDCB, lpDDCB->drv_num,  lpDDCB->drv_numd,
	 lpDDCB->sec_size, lpDDCB->clu_size,
	 lpDDCB->clu_base, lpDDCB->boot_siz,
	 lpDDCB->fat_num,  lpDDCB->max_dir,
	 lpDDCB->data_sec, lpDDCB->hi_clust,
	 lpDDCB->fat_size, lpDDCB->root_sec,
	 lpDDCB->reserv1,  lpDDCB->drv_addr,
	 lpDDCB->media,    lpDDCB->acc_flag,
	 lpDDCB->next,     lpDDCB->reserv2,
	 lpDDCB->built);

      // Получаем адрес следующего блока DDCB
      lpDDCB = get_nddcb(lpDDCB);
  }
}

// ---------------------------------------------
// get_fddcb
// Функция возвращает адрес первого блока DDCB.
// В качестве параметра ей следует передать
// адрес векторной таблицы связи
// ---------------------------------------------
LPDDCB get_fddcb(LPCVT cvt)
{
  LPDDCB ddcb;
  ddcb = (LPDDCB)cvt->dev_cb;
  return(ddcb);
}

// ---------------------------------------------
// get_nddcb
// Функция возвращает адрес следующего блока DDCB
// ---------------------------------------------
LPDDCB get_nddcb(LPDDCB ddcb)
{
  LPDDCB ddcb_n;

  ddcb_n = (LPDDCB)ddcb->next;
  if(FP_OFF(ddcb_n) == 0xffff)
    return((LPDDCB)NULL);
  return(ddcb_n);
}

