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); // Завершиться в сохранением в памяти }
гостевая; E-mail |