Pers.narod.ru. Алгоритмы. Упражнения на резидентные программы под 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); // Завершиться в сохранением в памяти
}
|
|