Nickolay.info. Алгоритмы. Упражнения на резидентные программы под DOS

Когда-то была очень интересная тема. Сегодня DOS-резиденты получится запустить, разве что, под очень хорошим эмулятором. Под DOSbox я пока не пробовал.

"Корректор" . При обнаружении на экране символа - точка программа ищет следующую за ней маленькую букву и заменяет ее на большую, отмечая первое слово следующего предложения изменением цвета фона.

#include <dos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
unsigned ZAM;  //Режим замены
unsigned SIZE; // Размер программы в параграфах
unsigned HIGH; // Верхняя граница сегмента данных
 
// Указатели на "старые" вектора прерываний
void interrupt (*TIMSAV)(...),interrupt (*KBSAV)(...);
 
char save[2000][2]; // Массив для хранения экрана
 
char (far *q)[25][80][2]=(char (far*)[25][80][2])0xB8000000;
 
static char sss[100],xx[8]={" "};
 
void putstr(char *s,int x, int y) {
while(*s !=NULL)                        // 25 строк по 80 символов по 2
     {                                               // байта на символ
     (*q)[y][x ][0] = *s++;        // запись символа в видеопамять
     (*q)[y][x++][1] = 0x0E;       // запись атрибута - желтый на черном
     }
}
 
void Save (void) {
 int k=0;
 for (int y=0; y<25; y++)
 for (int x=0; x<80; x++) {
  save[k][0]=(*q)[y][x][0];
  save[k][1]=(*q)[y][x][1];
  k++;
 }
}
 
void Restore (void ) {
 int k=0;
 for (int y=0; y<25; y++)
 for (int x=0; x<80; x++) {
  (*q)[y][x][0]=save[k][0];
  (*q)[y][x][1]=save[k][1];
  k++;
 }
}
 
long clock=0;
#define TICKS 120
#define SCAN 53         // Скан-код клавиши "?"
#define ALT 8           // Бит нажатия ALT в байте состояния клавиатуры
 
void interrupt KEYB(...) {  //Прерывание от клавиатуры
 char kbval;
 if (ZAM) {
  ZAM=0;
  Restore ();
  goto OLD;
 }
 kbval=peekb(0,0x417);
 if (inportb(0x60)==SCAN) {
  if ((kbval & ALT) !=0) {
   kbval=inportb(0x61);
   outportb(0x61,kbval | 0x80);
   outportb(0x61,kbval);
   outportb(0x20,0x20);
   ZAM=!ZAM;		    // Переключение режима
   if (ZAM) {
    clock=0;
    Save ();
   }
   else {
    Restore ();
   }
   return; // Выход из прерывания
  }
 }
OLD:
 (*KBSAV)();
}
 
int row,col;
char cc;
 
char toupper_ (char c) {
 if (c>96 && c<123 || c>159 && c<176) c-=32; // a-z, а-п
 else if (c>223 && c<240) c-=80; // р-я
 return c;
}
 
int Div (char c) {
 if ((c==' ') || (c=='\r') || (c=='\n') || (c=='\t')) return 1;
 return 0;
}
 
void interrupt PLTIME(...) { // Обработчик прерывания по таймеру
 (*TIMSAV)(); // эмуляция прерывания по старому вектору
 clock++;
 if ((clock==18) && (ZAM)) {
  do {
   if ((*q)[row][col][0]=='.') {
    do {
     col++;
     if (col==80) break;
     cc=(*q)[row][col][0];
     if (cc>96 && cc<123 || cc>159 && cc<176 || cc>223 && cc<240) {
      (*q)[row][col][0]=toupper_(cc);
      while ((col<80) && (!Div((*q)[row][col][0]))) {
       (*q)[row][col][1]=(*q)[row][col][1] ^ 0x66;
       col++;
      }
      goto ZZ;
     }
    } while (1);
    break;
   }
   col++;
   if (col>=80) {
    col=0; row++;
    if (row>=25) {
     row=0;
     break;
    }
   }
  } while (1);
ZZ:
  clock=0;
 }
 else if (clock==TICKS) {
  clock=0;
  ZAM=1; row=col=0;
 }
}
 
void main() {
HIGH=(unsigned)malloc(1);              // Верхний адрес сегмента данных
SIZE=(_DS-_CS)+(HIGH >> 4)+1;           // DS-CS - размер сегмента кода
				  // HIGH >> 4 - размер сегмента данных
printf("Объем резидента %d KB\n\r",SIZE >> 6);
TIMSAV=getvect(0x08);                       // сохранить старые вектора
setvect(0x08,PLTIME);                           // прерывания таймера и
KBSAV=getvect(0x9);                          // клавиатуры и установить
setvect(0x9,KEYB);                                       // собственные
keep(0,SIZE);                     // Завершиться с сохранением в памяти
}

Поиск в видеопамяти идентификаторов и констант (цепочка букв или цифр) и перестановка символов относительно середины слова (инверсия слова).

#include <dos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
unsigned ZAM;  //Режим замены
unsigned SIZE; // Размер программы в параграфах
unsigned HIGH; // Верхняя граница сегмента данных
 
// Указатели на "старые" вектора прерываний
void interrupt (*TIMSAV)(...),interrupt (*KBSAV)(...);
 
char save[2000][2]; // Массив для хранения экрана
 
char (far *q)[25][80][2]=(char (far*)[25][80][2])0xB8000000;
 
static char sss[100],xx[8]={" "};
 
void putstr(char *s,int x, int y) {
while(*s !=NULL)                        // 25 строк по 80 символов по 2
     {                                               // байта на символ
     (*q)[y][x ][0] = *s++;        // запись символа в видеопамять
     (*q)[y][x++][1] = 0x0E;       // запись атрибута - желтый на черном
     }
}
 
void Save (void) {
 int k=0;
 for (int y=0; y<25; y++)
 for (int x=0; x<80; x++) {
  save[k][0]=(*q)[y][x][0];
  save[k][1]=(*q)[y][x][1];
  k++;
 }
}
 
void Restore (void ) {
 int k=0;
 for (int y=0; y<25; y++)
 for (int x=0; x<80; x++) {
  (*q)[y][x][0]=save[k][0];
  (*q)[y][x][1]=save[k][1];
  k++;
 }
}
 
long clock=0;
#define TICKS 120
#define SCAN 53         // Скан-код клавиши "?"
#define ALT 8           // Бит нажатия ALT в байте состояния клавиатуры
 
void interrupt KEYB(...) {  //Прерывание от клавиатуры
 char kbval;
 if (ZAM) {
  ZAM=0;
  Restore ();
  goto OLD;
 }
 kbval=peekb(0,0x417);
 if (inportb(0x60)==SCAN) {
  if ((kbval & ALT) !=0) {
   kbval=inportb(0x61);
   outportb(0x61,kbval | 0x80);
   outportb(0x61,kbval);
   outportb(0x20,0x20);
   ZAM=!ZAM;		    // Переключение режима
   if (ZAM) {
    clock=0;
    Save ();
   }
   else {
    Restore ();
   }
   return; // Выход из прерывания
  }
 }
OLD:
 (*KBSAV)();
}
 
int row=0,col=0,s,e,i,k;
char cc;
 
int IsLetter (char c) {
 if ((c>64) && (c<91) || (c>96) && (c<123) || (c>47) && (c<58) ||
     (c>96) && (c<123) || (c>159) && (c<176)) return 1;
 return 0;
}
 
void interrupt PLTIME(...) { // Обработчик прерывания по таймеру
 (*TIMSAV)(); // эмуляция прерывания по старому вектору
 clock++;
 if ((clock==18) && (ZAM)) {
  do {
   if (IsLetter((*q)[row][col][0])) {
    s=col;
    while ((col<80) && (IsLetter((*q)[row][col][0]))) {
     col++; e=col;
    }
    i=s; k=col-1;
    do {
     cc=(*q)[row][i][0];
     (*q)[row][i][0]=(*q)[row][k][0];
     (*q)[row][k][0]=cc;
     i++; k--;
     if (i>=k) break;
    } while (1);
    break;
   }
   col++;
   if (col>=80) {
    col=0; row++;
    if (row>=25) {
     row=0;
     break;
    }
   }
  } while (1);
  clock=0;
 }
 else if (clock==TICKS) {
  clock=0;
  ZAM=1; row=col=0;
 }
}
 
void main() {
HIGH=(unsigned)malloc(1);              // Верхний адрес сегмента данных
SIZE=(_DS-_CS)+(HIGH >> 4)+1;           // DS-CS - размер сегмента кода
				  // HIGH >> 4 - размер сегмента данных
printf("Объем резидента %d KB\n\r",SIZE >> 6);
TIMSAV=getvect(0x08);                       // сохранить старые вектора
setvect(0x08,PLTIME);                           // прерывания таймера и
KBSAV=getvect(0x9);                          // клавиатуры и установить
setvect(0x9,KEYB);                                       // собственные
keep(0,SIZE);                     // Завершиться в сохранением в памяти
}

Впрочем, вот эту программку не поленился выполнить в эмуляторе DOS. Отображает по Alt+? идущие часы. В отличие от двух предыдущих, насколько я помню, не отлажена :)

#include <dos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
unsigned SHO;                            // Признак высвечивания часов
unsigned SIZE;                        // Размер программы в параграфах
unsigned HIGH;                      // Верхняя граница сегмента данных
 
                        // Указатели на функции обработки прерываний -
                                        // "старые" вектора прерываний
 
void interrupt (*TIMSAV)(...),interrupt (*KBSAV)(...);
 
char save[30][2];                 // Массив для хранения строки экрана
 
                                // Указатель на страницу 0 видеопамяти
 
char (far *q)[25][80][2]=(char (far*)[25][80][2])0xB8000000;
 
static char sss[100],xx[8]={" "};
 
              // Вывод строки непосредственно в 0-страницу видеопамяти
void putstr(char *s,int x, int y)
{
while(*s !=NULL)                       // 25 строк по 80 символов по 2
     {                                              // байта на символ
     (*q)[y][x ][0] = *s++;            // запись символа в видеопамять
     (*q)[y][x++][1] = 0xE;      // запись атрибута - желтый на черном
     }
}
 
char *to10(char *p,int n)
{
*p++ = n/10+'0';
*p++ = n%10+'0';
return p;
}
 
void interrupt KEYB(...)
{
#define SCAN 53                                // Скан-код клавиши "?"
#define ALT 8          // Бит нажатия ALT в байте состояния клавиатуры
char kbval;                                       // в байте 0000:0417
kbval=peekb(0,0x417);
if (inportb(0x60)==SCAN)
     {                                  // Нажатие "?" при нажатой ALT
     if ((kbval & ALT) !=0)
          {                            // Сброс контроллера клавиатуры
          kbval=inportb(0x61);
          outportb(0x61,kbval | 0x80);
          outportb(0x61,kbval);
          outportb(0x20,0x20);
          SHO=!SHO;                // Переключение режима высвечивания
                                  // часов и сохранение/восстановление
                                           // строки экрана под часами
          for (int x=50; x<70; x++)
               if (SHO)
               {
               save[x-50][0]=(*q)[0][x][0];
               save[x-50][1]=(*q)[0][x][1];
               }
          else
               {
               (*q)[0][x][0]=save[x-50][0];
               (*q)[0][x][1]=save[x-50][1];
               }
          return;                               // Выход из прерывания
          }
     }                                    // Иначе эмуляция прерывания
(*KBSAV)();                                      // по старому вектору
}
 
                                            // Счетчики тиков и секунд
int clock=0;
long clock1=0;
 
                                   // Обработчик прерывания по таймеру
void interrupt PLTIME(...)
{
(*TIMSAV)();                         // эмуляция прерывания по старому
clock++;                                                    // вектору
if (clock==18)                                     // подсчет 18 тиков
     {                                                              //
     clock1++;                                      // число секунд +1
     clock=0;
if (SHO)                          // вывод часов в формате "=HH:MM:SS"
          {
          char *p=sss;
          *p++ = '=';
          p=to10(p,(int)(clock1/3600));
     *p++ = ':';
          p=to10(p,(int)(clock1/60)%60);
     *p++ = ':';
          p=to10(p,(int)(clock1%60));
          *p=0;
          putstr(sss,50,0);
          }
     }
}
 
                                                 // Основная программа
void main()
{
struct time T;
HIGH=(unsigned)malloc(1);             // Верхний адрес сегмента данных
SIZE=(_DS-_CS)+(HIGH >> 4)+1;          // DS-CS - размер сегмента кода
                                  // HIGH >>4 - размер сегмента данных
printf("Объем резидента %d KB\n\r",SIZE >> 6);
gettime(&T);                              // Установить счетчик секунд
clock1=T.ti_sec+T.ti_hour*3600l+T.ti_min*60l;
TIMSAV=getvect(0x08);                      // сохранить старые вектора
setvect(0x08,PLTIME);                          // прерывания таймера и
KBSAV=getvect(0x9);                         // клавиатуры и установить
setvect(0x9,KEYB);                                      // собственные
keep(0,SIZE);                    // Завершиться в сохранением в памяти
}

Рейтинг@Mail.ru

вверх гостевая; E-mail