Хостинг портала RFpro.ru: Московский хостер Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64 РАССЫЛКИ ПОРТАЛА RFPRO.RU Чемпионы рейтинга экспертов в этой рассылке Номер выпуска: | 1343 | Дата выхода: | 25.05.2010, 21:30 | Администратор рассылки: | Лысков Игорь Витальевич, Модератор | Подписчиков / экспертов: | 266 / 63 | Вопросов / ответов: | 2 / 2 | IRC-канал по теме: | #assembler | Вопрос № 178504: Доброго времени суток, уважаемые эксперты! Прошу помочь с такой задачей: необходимо написать резидентную программу, которая через каждую минуту выводит сообщение "Привет" и не мешает работе пользователя. DOS, TASM. ... Вопрос № 178509: Доброго времени суток, уважаемые эксперты! Прошу помочь с такой задачей: необходима программа текстового редактора.Дополнительные условия не обозначены. DOS, TASM.Заранее спасибо.... Вопрос № 178504: Доброго времени суток, уважаемые эксперты! Прошу помочь с такой задачей: необходимо написать резидентную программу, которая через каждую минуту выводит сообщение "Привет" и не мешает работе пользователя. DOS, TASM.
Отправлен: 19.05.2010, 21:05 Вопрос задал: Виктор Никанорович, Посетитель Всего ответов: 1 Страница вопроса » Отвечает Зенченко Константин Николаевич, Модератор : Здравствуйте, Виктор Никанорович.
Смотрите приложение. Код TASM 2.00. Запускал дополнительно ещё и редактор EDIT, т.к. в только в CMD - ХР, результата нет.

Вопросы задавайте в мини-форум. Удачи! Приложение: ----- Итерация от человека. Рекурсия — от Бога. — Л. Питер Дойч Ответ отправил: Зенченко Константин Николаевич, Модератор Ответ отправлен: 20.05.2010, 16:44 Номер ответа: 261524 Украина, Киев Тел.: +38-097-953-66-19 Адрес: Украина, Киев
Оценка ответа: 5 Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 261524 на номер 1151 (Россия) | Еще номера » | Вопрос № 178509: Доброго времени суток, уважаемые эксперты! Прошу помочь с такой задачей: необходима программа текстового редактора.Дополнительные условия не обозначены. DOS, TASM.Заранее спасибо. Отправлен: 19.05.2010, 21:17 Вопрос задал: Виктор Никанорович, Посетитель Всего ответов: 1 Страница вопроса » Отвечает Лысков Игорь Витальевич, Модератор : Здравствуйте, Виктор Никанорович. Вот Вам текстовый редактор
Код: ;Текстовый редактор ;Распределение сегментов: DS=SS=сегмент данных, ES=видеобуфер
.model small, C ;модель памяти + соглашение о передаче параметров .286 ;чтобы можно было посылать в стек числа .code ;сегмент кода .startup ;точка входа call init ;инициализация call PrWin, 0, 0, XSize, YSize, DOUBLE, MainColor ;рисуем окно с рамкой call PrHelpMess ;выводим строку "F1 - помощь"
call SetCursor ;установим курсор в позицию (1,1) call GetFile ;читаем файл, если имя файла задано параметром
Redraw: ;сюда приходим, когда надо перерисовать содержимое буфера call SetName ;пишем имя файла
mov ax, XSize ;выводим содержимое буфера на экран dec ax mov cx, YSize dec cx mov dx, UpLine push ds mov ds, FileSeg call PrText, 1, 1, ax, cx, dx pop ds
NewCursor: ;сюда приходим, когда надо только поменять позицию курсора call SetCursor KeyLoop: ;цикл ожидания нажатия на клавишу mov ah,0 ;al=кон, ah=скан-код int 16h
lea di, KeyTable ;адрес таблицы отрабатываемых кодов mov cx, KeyTableLen ;длина SearchKey_loop: cmp ah, [di] ;сравниваем скан-код je KeyFound ;нашли код inc di loop SearchKey_loop ;по всей таблице ;дальше нас интересуют только символьные коды cmp al, ' ' ;управляющие игнорируем jae KeyInsert ;вставляем код jmp KeyLoop KeyFound: ;отработка кода sub di, offset KeyTable shl di, 1 ;di - смещение в таблице PrgTable jmp PrgTable[di] ;на отработку
KeyInsert: ;вставка символа cmp FileLen, 0ffffh ;проверка на длину (макс = 0ffffh) je KeyLoop< br> mov fChange, 1 ;содержимое поменялось ;освободим места для нового символа, для этого сдвинем на 1 байт mov si, FileLen ;смещение конца lea di, [si+1] ;на 1 дальше xor bx, bx mov bl, XFile ;позиция в текущей строке add bx, CurLine ;+смещение строки в файле (смещение, куда надо вставить) mov cx, di sub cx, bx ;количество копируемых байт push ds es mov es, FileSeg mov ds, FileSeg ;в рабочем буфере std ;в обратном порядке rep movsb ;копируем cld ;воостановим прямой порядок цепочечных команд mov [bx], al ;вставляем введенный код на его место pop es ds inc FileLen ;инкремент длины файла call PressedKeyRight ;перемещаем курсор вправо jmp Redraw ;не перерисовку KeyEnter: ;вставка перевода строки, а точнее двух кодов 0dh и 0ah cmp FileLen, 0fffeh ;проверка на длину (макс = 0fffeh) jae KeyLoop mov fChange, 1 ;содержимое поменялось ;освободим места для двух символов, для э того сдвинем на 2 байта mov si, FileLen ;смещение конца lea di, [si+2] ;на 2 дальше xor bx, bx mov bl, XFile ;позиция в текущей строке add bx, CurLine ;+смещение строки в файле (смещение, куда надо вставить) mov cx, di sub cx, bx ;количество копируемых байт push ds es mov es, FileSeg mov ds, FileSeg ;в рабочем буфере std ;в обратном порядке rep movsb ;копируем cld ;воостановим прямой порядок цепочечных команд mov word ptr [bx], 0a0dh ;вставляем введенные коды на их место pop es ds add FileLen, 2 ;увеличиваем длину файлу call PressedKeyRight ;перемещаем курсор вправо to_Redraw: ;промежуточная метка, чтобы достать до метки < 128 jmp Redraw ;не перерисовку to_KeyLoop: ;промежуточная метка, чтобы достать до метки < 128 jmp KeyLoop finish: ;выход call exit KeyUp: call PressedKeyUp ;стрелка вверх jc to_KeyLoop ;ничего дополнительного не делать jz to_Redraw ;п ерерисовать jmp NewCursor ;поменять позицию курсора KeyLeft: call PressedKeyLeft ;стрелка влево jc to_KeyLoop jz to_ Redraw jmp NewCursor KeyRight: call PressedKeyRight ;стрелка вправо jc to_KeyLoop jz to_Redraw jmp NewCursor Keydown: call PressedKeyDown ;стрелка вниз jc to_KeyLoop jz to_Redraw jmp NewCursor KeyHelp: call Help ;F1 to_NewCursor: jmp NewCursor KeyRead: call ReadFile ;F3 jc to_NewCursor jmp Redraw KeyWrite: call WriteFile ;F2 jc to_NewCursor jmp Redraw KeyBack: call BackSpace ;BackSpace jc to_KeyLoop jmp Redraw
;расчет позиции курсора для строки текста, учитывается табуляция ;bx - до какой позиции смотрим CalcXtab proc push ds xor cx, cx ;счетчик позиции на экране mov si, CurLine ;текущая строка mov ds, FileSeg dec bx ;адрес предыдущего байта CX_loop: cmp si, bx ;дошли до bx jge CX_ret ;на выход, в CX искомая позиция курсора lodsb ;очередной байт inc cx ;посчитаем cmp al, 9 ;табуляция? jne CX_loop ;для обычн ого символа просто идем на следующий mov ax, cx ;табуляцию расширяем до 8-й позиции and ax, 7 ;ax = x mod 8 sub ax, 8 neg ax ;ax = 8 - (x mod 8) add cx, ax ;ax - число пробелов, чтобы табуляция встала на позиции, кратной 8 jmp CX_loop ;продолжаем CX_ret: mov ax, cx pop ds mov XScreen, al ;сохраним новую позицию курсора ret CalcXtab endp
;расчет позиции курсора для строки текста, учитывается табуляция ;отличие от предыдузей в том, что здесь проверяем на старую позицию курсора ;используется в переходе на строку вниз/вверх CalcXXtab proc push ds mov dl, XScreen ;старая позиция курсора mov si, CurLine ;текущая строка mov ds, FileSeg xor bx, bx ;индекс в текущей строке xor cx, cx ;сl-текущая позиция в строке, ch-промежуточное значение позиции CXX_loop: cmp ch, dl ;дошли до старой позиции ja CXX_ret1 mov cl, ch ;нет, сохраним, как текущую mov al, [bx+si] ;читаем байт< br> cmp al, 0dh ;конец строки? je CXX_ret ;да, это и будет новая позиция на экране cmp al, 9 ;табуляция? jne CXX_next ;нет - на следующий mov al, cl ;расширяем табуляцию пробелами and al, 7 sub al, 7 sub ch, al CXX_next: inc ch ;инкремент позиции на экране inc bx ;инкремент позиции в файле jmp CXX_loop CXX_ret1: dec bl ;в случае, когда табуляция перескакивает, то на 1 меньше CXX_ret: pop ds mov XFile, bl ;сохраним позицию в файле mov XScreen, cl ;и на экране ret CalcXXtab endp
;отработка клавиши "влево" PressedKeyLeft proc mov ax, CurLine ;в первой позиции ничего не делаем or ax, UpLine or al, XFile jnz KL_Change KL_NoChange: stc ret KL_Change: xor ax, ax mov al, XFile add ax, CurLine ;ax - позиция текущего символа в файле push ds mov ds, FileSeg mov bx, ax mov dl, [bx-1] ;предыдущий символ pop ds
cmp dl, 0a h ;мы в начале строки? je KL_eol ;становимся в конец предыдущей dec XFile ;уменьшаем на 1 позицию в строке cmp dl, 9 ;предыдущий символ - табуляция? je KL_tab ;отрабатываем dec XScreen ;для обычного символа просто уменьшаем позицию на экране KL_NewCursor: or al, 1 ;Z=0 для установки курсора clc ;для отработки ret KL_tab: call CalcXtab ;посчитаем новую позицию курсора на экране jmp KL_NewCursor KL_eol: ;переходим в конец строки выше push ds mov ds, FileSeg dec bx ;bx - позиция в файле символа 0ah
lea di, [bx-1] ;di - позиция 0dh KL_eol_loop: ;ищем начало строки dec bx ;на предыдущий символ test bx, bx ;для первой строки дойдем до 0 jz KL_set_CurLine ;начало первой строки mov al, [bx] ;читаем символ cmp al, 0ah ;0ah? jne KL_eol_loop inc bx ;нашли 0ah, следующий - начало строки KL_set_CurLine: pop ds
mov CurLine, bx ;сохраним адрес, как адрес тек ущей строки
mov bx, di ;посчитаем позицию на экране sub bx, CurLine ;bx - длина строки mov XFile, bl ;запомним, как позиц ию в строке файла lea bx, [di+1] ;адрес конца строки call CalcXtab ;считаем позицию на экране
KL_scroll: ;если есть необходимость, делаем скроллинг на одну строку dec YFile ;уменьшим номер строки в файле sub YScreen, 1 ;уменьшим номер строки на экране ;(отнимаем 1, а не dec - чтобы отработался флаг С) jge KL_NewCursor ;если нет необходимости скроллировать, то выходим
mov ax, CurLine ;устанавливаем новый адрес начала прорисовки mov UpLine, ax mov YScreen, 0 ;номер строки на экране = 0
mov ax, 0701h ;скролинг на одну строку вниз mov cx, 0101h ;с позиции (1,1) mov dl, byte ptr XSize ;и все, что внутри рамки mov dh, byte ptr YSize sub dx, cx mov bh, byte ptr MainColor ;цвет фона int 10h mov ax, XSize ;выводим в первую строку экрана текущую строку файла dec ax mov dx, UpLine push ds mov ds, FileSeg call PrText, 1, 1, ax, 1, dx pop ds jmp KL_NewCursor PressedKeyL eft endp
;строка вверх PressedKeyUp proc mov ax, CurLine ;для первой строки ничего не делаем or ax, UpLine jnz KU_Change KU_NoChange: stc ret KU_Change: mov bx, CurLine ;начало текущей строки в файле push ds mov ds, FileSeg dec bx ;адрес 0ah предыдущей строки ;ищем начало предыдущей строки KU_eol_loop: dec bx test bx, bx ;для первой строки начало - bx=0 jz KU_set_CurLine mov al, [bx] ;ищем начало строки, как адрес байта, cmp al, 0ah ; следующего за 0ah (строки, которая выше) jne KU_eol_loop inc bx ;начало строки KU_set_CurLine: pop ds mov CurLine, bx ;сохраним
call CalcXXtab ;вычислим текущую позицию на экране
jmp KL_scroll ;проскроллируем, если необходимо
PressedKeyUp endp
;отработка клавиши "вправо" PressedKeyRight proc xor ax, ax ;если в позиции последнего символа, mov al, XFile ; то ничего не делаем add ax , CurLine cmp ax, FileLen jb KR_Change KR_NoChange: stc ret KR_Change: push ds mov ds, FileSeg mov bx, ax mov dl, [bx] ;символ в текущей позиции pop ds
cmp dl, 0dh ;конец строки? je KR_eol ;да, переходим на следующую inc XFile ;нет, инкремент позиции в строке файла cmp dl, 9 ;если табуляция, je KR_tab ;то посчитать позицию на экране inc XScreen ;нет, просто инкремент позиции на экране KR_NewCursor: or al, 1 ;смена позиции курсора clc ;отработать ret KR_tab: ;табуляция xor ax, ax mov al, XScreen and ax, 7 sub ax, 8 ;ax = (XScreen mod 8) - 8 < 0 sub XScreen, al ;выравнять до позиции, кратной 8 jmp KR_NewCursor KR_eol: ;переходим на следующую строку xor ax, ax mov al, XFile add ax, CurLine inc ax ;обойдем 0dh, 0ah inc ax
mov CurLine, ax ;сохраним адрес, как начало новой строки
mov XFile,0 ;начало строки в фай ле mov XScreen, 0 ;начало строки на экране
KR_scroll: ;скроллинг на одну строку вниз, если необходимо inc YFile ;инкремент строки в файле inc YScreen ;инкрмент строки на экране xor ax, ax mov al, YScreen ;номер строки на экране mov cx, YSize dec cx ;максимальный номер строки + 1 cmp ax, cx ;если меньше то скроллировать не надо jb KR_NewCursor dec YScreen ;вернем на номер последней строки ;найдем адрес второй строки для отображения mov bx, UpLine ;адрес первой строки на экране push ds mov ds, FileSeg KR_eol_loop: ;ищем 0ah в конце строки mov al, [bx] inc bx cmp al, 0ah jne KR_eol_loop pop ds mov UpLine, bx ;сохраним следующий адрес, как адрес верхней строки
mov ax, 0601h ;скроллируем на одну строку вверх mov cx, 0101h mov dl, byte ptr XSize mov dh, byte ptr YSize sub dx, cx mov bh, byte ptr MainColor int 10h mov ax, XSize dec ax mo v cx, YSize dec cx mov dx, CurLine push ds mov ds, FileSeg ;выводим одну текущую строку в конце экрана call PrText, 1, cx, ax, 1, dx pop ds jmp KR_NewCursor PressedKeyRight endp
;строка вниз PressedKeyDown proc mov bx, CurLine ;пробуем найти 0ah, если не находим, то KD_eol_loop: ; то ничего не делаем cmp bx, FileLen jae KD_NoChange push ds mov ds, FileSeg mov al, [bx] pop ds inc bx cmp al, 0ah jne KD_eol_loop jmp KD_Change KD_NoChange: stc ret KD_Change: mov CurLine, bx ;сохраняем адрес байта за 0ah, ; как адрес текущей строки call CalcXXtab ;посчитаем позицию на экране для новой строки
jmp KR_scroll ;на скроллирование, если надо
PressedKeyDown endp
;отработка BackSpace BackSpace proc mov ax, CurLine ;для первого символа ничего не делаем or ax, UpLine or al, XFile jnz BS_Change BS_NoChange: stc ret BS_Change: mov fChange, 1 ;содержимое изменено call PressedKeyLeft ;курсор влево xor bx, bx mov bl, XFile add bx, CurLine ;текущая позиция в файле push ds ;копируем на 1 или на 2 позиции, затирая текущий символ push es mov es, FileSeg mov ds, FileSeg mov di, bx mov bx, 1 ;для обычного символа mov al, [di] cmp al, 0dh jne copy_back inc bx ;для конца строки bx = 2 copy_back: lea si, [di+bx] ;адрес, откуда пишем mov cx, ss:Filelen sub cx, si inc cx ;число копируемых байт (вместе с завершающим 0) rep movsb ;копируем pop es pop ds dec di mov FileLen, di ;новая длина файла clc ;для прорисовки ret BackSpace endp
;рисуем окно (x1,y1)-(x2,y2) с двойной/одинарной рамкой и указанным цветом PrWin proc x1:word, y1:word, x2:word, y2:word, TableType:word, color:word local rows:word, cols:word
mov ax, 0600h ;очищаем окно mov ch, byte ptr y1 mov cl, byte ptr x1 mov dh, byte ptr y2 mov dl, byte ptr x2 mov bh, byte ptr color int 10h
mov si, TableType ;тип рамки ( 0,1) shl si, 1 mov si, Borders[si] ;адрес таблицы псевдографики
mov ax, Xsize ;вычисляем адрес начала вывода inc ax mul y1 add ax, x1 shl ax, 1 mov di, ax ;адрес вывода в видеобуфер
mov ax, y2 ;число строк sub ax, y1 inc ax mov rows, ax
mov ax, x2 ;число колонок sub ax, x1 inc ax mov cols, ax
mov bx, XSize inc bx shl bx, 1 ;длина строки для перехода на следующую строку
mov ah, byte ptr color+1 ;цвет рамки push di mov al, LU[si] ;левый верхний уголок stosw mov cx, cols ;горизонталь dec cx dec cx mov dx, cx ;сохраним "внутренюю" длину колонок mov al, HH[si] rep stosw mov al, RU[si] ;правый верхний уголок stosw pop di add di, bx mov cx, rows dec cx dec cx ;число "средних" строк PW_RLoop: ;окаймим "средние" строки вертикалями push di mov al, VV[si] stosw add di, dx add di, dx stosw pop di add di, bx loop PW_RLoop mov al, LD[si] ;нижняя часть, левый нижний уголок stosw mov cx, dx mov al, HH[si] ;горизонталь rep stosw mov al, RD[si] ;правый нижний уголок stosw
ret PrWin endp
;Установка курсора SetCursor proc push ax mov ah, 2 mov dx, word ptr ss:XScreen ;x+y add dx, 0101h ;поправка на позицию (1,1) mov bh, 0 int 10h pop ax ret SetCursor endp
;начальная инициализация init proc call GetParm ;вводим имя файла из строки параметров
;узнаем размер экрана по горизонтали mov ah, 0fh int 10h mov al, ah ;в ah - число текстовых колонок mov ah, 0 dec ax mov Xsize, ax ;сохраним индекс последнего символа в строке экрана
;определим высоту экрана mov ax, 1130h int 10h mov al, dl ;в dl число строк - 1 mov ah, 0 mov Ysize, ax ;сохраним индекс последней строки экрана
;обнулим некоторые переменные mov fChange, 0 mov CurLine, 0 mov UpLine, 0 mov XScreen, 0 mov YScreen, 0 mov XFile, 0 mov YFile, 0
;зададим адрес сегмента для содержимого файла, как DS+1000h xor bx, bx mov ax, ds add ax, 1000h mov FileSeg, ax mov FileLen, bx ;длины 0 push ds mov ds, ax mov [bx], bl ;первый символ - 0 pop ds
;запомним позицию курсора mov ah, 3 mov bh, 0 int 10h mov PosOld, dx
;сохраним содержимое видеостраницы, чтобы потом восстановить mov ax, XSize mov cx, YSize inc ax inc cx mul cx mov cx, ax push ds push ds pop es mov ax, 0b800h mov ds, ax lea di, SaveScr xor si, si rep movsw pop ds
;настраиваем сегментный регистр es на видеобуфер mov ax, 0b800h mov es, ax ret init endp
;рассматриваем строку параметров, как имя файла GetParm proc mov si, 81h ;начало строки, длину по адресу 80h игнорируем, ; будем искать конец по 0dh lea di, FName ;сюда запишем имя файла GPSpaceLoop: ;сначала пропуст им разделители перед параметром mov al,es:[si] ;es адресует PSP inc si cmp al, 0dh je GPRet ;параметра нет cmp al, ' ' je GPSpaceLoop cmp al, 9 je GPSpaceLoop GPName: ;что-то нашли mov [di], al ;сохраняем inc di mov al,es:[si] inc si cmp al, 0dh ;продолжаем до 0dh je GPRet cmp al, ' ' ; или до разделителя je GPRet cmp al, 9 jne GPName GPret: mov byte ptr [di], 0;закрываем строку нулем ret GetParm endp
;пишем имя файла вверху экрана SetName proc mov cx, XSize sub cx, 4 ;на всякий случай, ограничим длину lea si, FName ;имя файла cmp byte ptr [si],0 ;задано ли? jne SNPrName lea si, Default ;нет - считаем именем Default.txt SNPrName: mov di, 2 ;с позиции 1 mov ah, byte ptr MainColor+1 ;цвет mov al, ' ' ;отделим пробелом stosw SNPrLoop: lodsb cmp al, 0 je SNPrTail stosw loop SNPrLoop ;выведем строку имени SNPrTail: mov al, ' ' stosw ;пробел dec cx mov al, BorderDouble + HH stosw dec cx cmp fChange, 0 je SNFlagChange mov al, '*' ;признак изменения содержимого (* или черточка) SNFlagChange: stosw dec cx ;до конца, чтобы вытереть возможное старое, выведем черточки jcxz SNRet mov al, BorderDouble + HH SN_clear_loop: stosb inc di loop SN_clear_loop SNRet: ret SetName endp
;краткая помощь ;внутри 11 строк Help proc call MessageBox, offset sHelp, 11 ret Help endp
;читаем файл по F3 ReadFile proc cmp fChange, 0 ;было ли изменение? je RFContinue ;1 строку сообщения call MessageBox, offset sChanged, 1 ;возвращается скан-код нажатой клавиши cmp ah, 15h ;Y jne RFRet ;не Y - не сохраняем RFContinue: ;запрос имени файла call NameBox,offset sReadFile, offset sFileName, offset FName jc RFRet ; Esc - отказ от чтения call GetFile ;читаем файл с именем FName mov fChange, 0 ;все обнуляем mov CurLine, 0 mov UpLine, 0 mov XScreen, 0 mov YScreen, 0 mov XFile, 0 mov YFile, 0 clc ;перерисовываем ret RFRet: stc ret ReadFile endp
;пишем файл по F2 WriteFile proc ;запрос имени файла call NameBox,offset sWriteFile, offset sFileName, offset FName jc WFRet ;отказ по Esc call SetFile ;сохраняем файл mov fChange, 0 ;сброс флага изменения clc ;перерисуем WFRet: ret WriteFile endp
;читаем файл GetFile proc lea dx, FName cmp FName, 0 jnz GFOpen lea dx, default GFOpen: mov si, dx ;сохраняем адрес имени (для сообщений) mov ax, 3d00h int 21h ;открываем на чтение jc GFOpenError ;ошибка открытия mov bx, ax ;описатель файла push ds mov ds, FileSeg xor dx, dx mov cx,0ffffh mov ah, 3fh int 21h ;читаем в сегмент да нный файла jc GFReadError ;ошибка чтения cmp ax, cx ;проверим размер файла (еще есть что читать, значит больше, чем надо) jz GFSizeError ;выведем ошибку mov si, ax ;длина как индекс конца mov byte ptr [si],0 ;запишем в конце нолик pop ds mov FileLen, ax ;сохраним длину файла
mov fChange, 0 ;сбросим флаг изменения FNCloseFile: mov ah, 3eh int 21h ;закрываем файл ret ;сообщения об ошибках GFOpenError: cmp si, offset default je GFRet ;ошибку открытия файла default.txt не выводим call ErrorBox, offset sOpenError, si GFRet: ret GFReadError: pop ds call ErrorBox, offset sReadError, si jmp FNCloseFile GFSizeError: ;поместим в начало байт 0 и сбросим длину в 0 mov byte ptr ds:[0],0 pop ds mov FileLen, 0 call ErrorBox, offset sSizeError, si jmp FNCloseFile GetFile endp
;запись файла SetFile proc lea dx, FName cmp FName, 0 jnz SFOpen lea dx, default SFOpen: mov si, dx ;сохраним имя (для сообщений) mov ah, 3ch ;создаем файл (если был с таким именем, то тот потер яется) xor cx, cx int 21h jc SFCreateError mov bx, ax ;описатель файла mov cx, FileLen ;длина файла push ds mov ds, FileSeg xor dx, dx mov ah, 40h ;пишем в файл с адреса ds:dx int 21h pop ds jc SFWriteError
mov fChange, 0 ;сбросим флаг изменения SFCloseFile: mov ah, 3eh int 21h ;закрываем файл ret ;сообщения об ошибках SFCreateError: call ErrorBox, offset sCreateError, si SFRet: ret SFWriteError: call ErrorBox, offset sWriteError, si jmp SFCloseFile SetFile endp
;сообщение об ошибке (всегда две внутренние строки) ;sFormat - форматная строка, параметром можно указать %, в то место вставится sStr ;sStr - имя файла, вставляемое, как параметр в сообщение ;во второй строке всегда пишем: "Нажмите на любую клавишу" ErrorBox proc sFormat:word, sStr:word local sTextBuffer:byte:76, \ ;буфер для формирования строки wSave:word:80*4, \ ;для сохран ения старого содержимого экрана MB_x1:word, MB_y1:word, MB_x2:word, MB_y2:word ;координаты окна (псевдографики)
;посчитаем размеры окна, для этого найдем максимальную длину строки xor dx, dx ;максимальная длина mov si, sFormat ;форматная строка lea di, sTextBuffer ;где формируем данные для вывода xor cx, cx ;длина первой строки EBForm: lodsb cmp al, 0 je EBSecond ;добавляем вторую строку cmp al, '%' je EBParm ;добавляем параметр mov [di], al ;сохраняем inc di cmp al, ' ' ;0dh,0ah не считаем jb EBForm inc cx ;считаем символы jmp EBForm EBParm: ;копируем параметр push si mov si, sStr EBParmLoop: lodsb cmp al, 0 je EBParmEnd inc cx ;считаем длину строки mov [di], al inc di jmp EBParmLoop EBParmEnd: pop si jmp EBForm ;продолжаем проссматривать форматную строку EBSecond: cmp cx, dx ;сравниваем с максимумом jbe EBAnyKe y mov dx, cx EBAnyKey: ;добавляем строку sAnyKey xor cx, cx lea si, sAnyKey EBAnyLoop: lodsb cmp al, 0 je EBCalcSize ;конец mov [di], al inc di cmp al, ' ' jb EBAnyLoop inc cx ;считаем jmp EBAnyLoop EBCalcSize: cmp cx, dx ;ищем максимум ja EBCalcMiddle mov cx, dx EBCalcMiddle: add cx, 4 ;+ по пробелу и чертечке слева и справа mov ax, XSize ;сделаем, чтобы окно было посередине экрана sub ax, cx shr ax, 1 mov MB_x1, ax ;Х левого верхнего угла add ax, cx dec ax mov MB_x2, ax ;Х правого нижнего угла mov ax, YSize sub ax, 4 shr ax, 1 mov MB_y1, ax ;Y левого верхнего угла add ax, 3 ;внутри 2 строки mov MB_y2, ax ;Y правого нижнего угла
lea di, wSave ;сохраняем старое содержимое экрана mov cx, XSize ; причем для простоты сохраняем строки от начала до конца mov ax, MB_y1 mul cx shl ax, 1 mov si, ax shl cx, 2 push ds push es push ds push es pop ds pop es rep movsw pop es pop ds
;рисуем окно с рамкой с цвет ом ошибок call PrWin, MB_x1, MB_y1, MB_x2, MB_y2, SINGLE, ErrorColor ;и выводим текст из 2-х строк в позицию (1,1) mov ax, MB_x1 inc ax inc ax mov cx, MB_y1 inc cx mov dx, MB_x2 sub dx, ax lea bx, sTextBuffer call PrText, ax, cx, dx, 2, bx push word ptr XScreen ;сохраняем позицию курсора mov ax, MB_x2 ;установим курсор в конец второй строки sub al, 2 mov XScreen, al mov ax, MB_y2 sub al, 2 mov YScreen, al call SetCursor
mov ah, 0 ;ждем нажатие на клавишу int 16h
lea si, wSave ;востановим экран mov cx, XSize mov ax, MB_y1 mul cx shl ax, 1 mov di, ax shl cx, 2 rep movsw
pop word ptr XScreen ;восстановим курсор call SetCursor ret ErrorBox endp
;вывод сообщения с получением кода нажатой клавиши ;sStr - выводимое сообщение ;nRows - число информационных строк MessageBox proc sStr:word, nRows:word local wSave:word:8 0*14, \;для сохранения старого содержимого (максимум 12 инфо строк) MB_x1:word, MB_y1:word, MB_x2:word, MB_y2:word ;координаты окна
;найдем максимальную длину строки mov si, sStr xor cx, cx ;текущая mov dx, cx ;максимальная MBStrLen: lodsb cmp al, 0ah je MB_EOL cmp al, 0 je MBCmpLastPart cmp al, ' ' jb MBStrLen inc cx jmp MBStrLen MB_EOL: cmp cx, dx jbe to_MBStrLen mov dx, cx to_MBStrLen: xor cx, cx jmp MBStrLen MBCmpLastPart: cmp cx, dx ja MBCalcMiddle mov cx, dx MBCalcMiddle: ;посчитаем Xи Y, чтобы было в центре экрана add cx, 4 ;добавим два пробела и две черточки mov ax, XSize sub ax, cx shr ax, 1 mov MB_x1, ax ;Х левого верхнего угла add ax, cx dec ax mov MB_x2, ax ;Х правого нижнего угла mov ax, YSize sub ax, nRows ;инфо строки sub ax, 2 ;верхняя и нижняя shr ax, 1 mov MB_y1, ax ;Y левого верхнего уг ла add ax, nRows inc ax mov MB_y2, ax ;Y правого нижнего угла
lea di, wSave ;сохраним экран mov cx, XSize inc cx mov ax, MB_y1 mul cx shl ax, 1 mov si, ax mov ax, nRows add ax, 2 mul cx mov cx, ax push ds push es push ds push es pop ds pop es rep movsw pop es pop ds
;нарисуем окно с рамкой call PrWin, MB_x1, MB_y1, MB_x2, MB_y2, SINGLE, MessageColor ;выведем текст в позицию (2,1) mov ax, MB_x1 inc ax inc ax mov cx, MB_y1 inc cx mov dx, MB_x2 sub dx, ax call PrText, ax, cx, dx, nRows, sStr push word ptr XScreen ;сохраним курсор mov ax, MB_x2 ;курсор в конец последней инфо строки sub al, 2 mov XScreen, al mov ax, MB_y2 sub al, 2 mov YScreen, al call SetCursor
mov ah, 0 int 16h ;ждем
push ax ;сохраним код! lea si, wSave ;востановим старое содержимое экрана mov cx, XSiz e inc cx mov ax, MB_y1 mul cx shl ax, 1 mov di, ax mov ax, nRows add ax, 2 mul cx mov cx, ax rep movsw pop ax ;восстановим и вернем код нажатой клавиши!
pop word ptr XScreen ;восстановим позицию курсора ret ;установится в сновном цикле! MessageBox endp
;вывод сообщения и запрос имени файла ;sTitle - первая строка сообщения ;sName - строка "Имя файла:" ;sOldName - адрес строки со старым именем и куда будет это имя потом записано NameBox proc sTitle:word, sName:word, sOldName:word local sTextBuffer:byte:76, \;для формирования строки для вывода wSave:word:80*4, \;для сохранения экрана MB_x1:word, MB_y1:word, MB_x2:word, MB_y2:word ;позиция окна local offName:word, \;смещение вводимого имени в строке sTextBuffer lenName:word, \;длина собственно имени файла lenStr:word ;длина строки sName
xor dx, dx ;ищем максимальную длину строки mov si, sTitle ; начинаем с первой lea di, sTextBuffer ;и формируем строку в sTextBuffer xor cx, cx NBForm: lodsb cmp al, 0 je NBAdd Name mov [di], al inc di cmp al, ' ' jb NBForm inc cx jmp NBForm NBAddName: ;добавляем sName mov dx, cx xor cx, cx mov lenStr, cx ;считаем ее длину mov si, sName NBNameLoop: lodsb cmp al, 0 je NBOldName mov [di], al inc di cmp al, ' ' jb NBNameLoop inc cx inc lenStr jmp NBNameLoop NBOldName: add cx, 12 ;12 позиций на имя 8.3 !
mov offName, di ;начало имени файла mov lenName, 0 ;длина имени
mov si, sOldName ;перенесем старое имя cmp byte ptr [si], 0 jne NBCopyName lea si, Default NBCopyName: lodsb cmp al, 0 je NBCalcSize mov [di], al inc di inc lenName jmp NBCopyName NBCalcSize: mov [di], al ;закрываем нулем
cmp cx, dx ja NBCalcMiddle mov cx, dx ;максимальная длина NBCalcMiddle: add cx, 4 ;+ 2 пробела и 2 черточки mov ax, XSize ;посреди экрана sub ax, cx shr ax, 1 mov MB_x1, ax add ax, cx dec ax mov MB_x2, ax mov ax, YSize sub ax, 4 shr ax, 1 mov MB_y1, ax add ax, 3 mov MB_y2, ax
lea di, wSave ;сохраняем старый экран mov cx, XSize inc cx mov ax, MB_y1 mul cx shl ax, 1 mov si, ax shl cx, 2 push ds push es push ds push es pop ds pop es rep movsw pop es pop ds
push word ptr XScreen;сохраняем курсор
mov ax, MB_x1 ;курсор на конец имени файла add ax, lenStr add ax, lenName inc al mov XScreen, al mov ax, MB_y2 sub al, 2 mov YScreen, al ;во второй строке
;нарисуем окно с рамкой call PrWin, MB_x1, MB_y1, MB_x2, MB_y2, SINGLE, MessageColor
mov si, offName ;адрес имени mov bx, lenName ;длина имени, одновременно индекс конца введенной строки
NBPrName: ;цикл ввода строки имени файла push si bx ;сохраним используемые регистры ;выводим текст вместе с вв одимым именем mov ax, MB_x1 inc ax inc ax mov cx, MB_y1 inc cx mov dx, MB_x2 sub dx, ax lea di, sTextBuffer call PrText, ax, cx, dx, 2, di call SetCursor ;установка курсора pop bx si
NBKeyLoop: ;цикл ожидания нажатия на клавишу mov ah, 0 int 16h cmp ah, 1 je NBEscape ;Escape - выходим без сохранения cmp al, 0dh je NBEnter ;Enter - сохраняем имя cmp al, 8 je NBBackSpace ;BackSpace - удаляем последний символ cmp al, ' ' jbe NBKeyLoop ;управляющие игнорируем cmp bx, 12 jae NBKeyLoop ;максимум 12 символов mov [bx+si], al ;сохраняем inc bx ;инкремент mov byte ptr[bx+si], 0 ;закрываем нулем inc XScreen ;инкремент позиции на экране jmp NBPrName ;заново отрисовываем
NBBackSpace: ;BackSpace test bx, bx jz NBKeyLoop ;в начале - игнорируем dec bx ;уменьшаем индекс mov byte ptr[bx+si], 0 ;признак конца dec XScreen ;декре мент позиции на экране jmp NBPrName ;заново отрисовываем NBEscape: ;Escape - выходим без сохранения mov di, 1 ;чтобы в бите D0 была единица jmp NBReturn NBEnter: mov di, sOldName ;копируем имя по указанному адресу mov cx, bx ;длина inc cx ;+ 0 push es push ds pop es rep movsb pop es xor di, di ;D0 = 0 NBReturn: push di ;сохраним признак lea si, wSave ;восстановим экран mov cx, XSize inc cx mov ax, MB_y1 mul cx shl ax, 1 mov di, ax shl cx, 2 rep movsw pop di
pop word ptr XScreen ;востановим позицию курсора call SetCursor
shr di, 1 ;бит D0 в бит С - признак, как вышли! ret NameBox endp
;вывод текста ;PT_x1, PT_y1 - координаты начала вывода ;PT_xcount - мах число символов по Х ;PT_ycount - число инфо строк ;PT_str - адрес строки, заканчивающейся 0, для перехода на другую строку 0dh,0ah PrText proc uses di, PT_x1:word, PT_ y1:word, PT_xcount:word, PT_ycount:word, PT_str:word ;вычисляем смещение в сегменте видеоданных mov ax, ss:XSize inc ax mul PT_y1 add ax, PT_x1 shl ax, 1 mov di, ax
mov si, PT_str ;адрес строки mov dx, di ;начало строки на экране, для подсчета адреса следующей строки mov cx, PT_xcount ;число колонок mov bx, PT_ycount ;число строк PTRLoop: test bx, bx ;кончилось? jz to_PrRet PTCLoop: jcxz PrNextRow ;дошли до конца строки - переход на следующую строку lodsb cmp al, 0 ;дошли до конца строки? jnz PTCmp0d ;нет, на проверку 0dh jcxz to_PrRet ;заполним до конца пробелами mov al, ' ' PTEndRow_loop: stosb inc di loop PTEndRow_loop ;также заполним пробелами всю следующую строку cmp PT_ycount, 23 ;но только для всего экрана, для сообщений - игнорируем jbe PrRet cmp si, 2 ;для пустого файла - игнорируем jb PrRet cmp byte ptr [si-2], 0ah ;если последний символ 0ah - игнорируем, je PrRet ; для него уже очищено до конца! mov di, dx ;адрес следующей строки add di, ss:XSize a dd di, ss:XSize inc di inc di mov dx, di dec bx mov cx, PT_xcount ;"опробелим" PTEndRow_loop_2: stosb inc di loop PTEndRow_loop_2 to_PrRet: jmp PrRet PTCmp0d: ;анализируем дальше cmp al, 0dh jz PTCLoop ;0dh игнорируем cmp al, 0ah jz PrNextRow ;по 0ah переходим на новую строку cmp al, 9 jne PTstosb ;обычный символ проосто выводим mov ax, di ;табуляцию расширяем до позиции, кратной 8 sub ax, dx shr ax, 1 and ax, 7 sub ax, 7 neg ax mov ah, al ;ah - число дополнительных пробелов mov al, ' ' PTExpandTabLoop: jcxz PrNextRow ;дошли ли до края строки на экране cmp ah, 0 je PTstosb ;на вывод еще одного пробела stosb inc di dec cx ;счетчик символов, которые еще можно вывести dec ah ;счетчик дополнительных пробелов для расширения табуляции jnz PTExpandTabLoop PTstosb: stosb ;вывод символа inc di ;обойдем атрибут dec cx ;декремент счетчика jmp PTCLoop ;на следующий PrNextRow: ;переход на следующую строку jcxz PrNextRow_1 ;сначала дополним до конца пробелами mov al, ' ' PrEndRow_loop: stosb inc di loop PrEndRow_loop PrNextRow_1: mov di, dx ;адрес следующей строки add di, ss:XSize add di, ss:XSize inc di inc di mov dx, di dec bx ;счетчик строк mov cx, PT_xcount ;заново счетчик колонок ;PTSearchLineEndLoop: ; cmp al, 0ah ; je PTRLoop ; lodsb ; cmp al, 0 ; je PrRet ; jmp PTSearchLineEndLoop jmp PTRLoop ;на повтор PrRet: ret ;все выведено! PrText endp
;вывод в последней строке "F1 - помощь" PrHelpMess proc mov ax, YSize inc ax mov di, XSize inc di mul di sub ax, sMessHelpLen ;длина строки shl ax, 1 mov di, ax ;адрес, куда выводим lea si, sMessHelp ;строка PrHelp_loop: lodsb cmp al, 0 je PrHelRet stosb inc di loop PrHelp_loop PrHelRet: ret PrHelpMess endp
;выход exit proc cmp fChange, 0 ;было ли изменение? je EContinue ;1 строку сообщения call MessageBox, offset sChanged, 1 ;возвращается скан-код нажатой клавиши cmp ah, 15h ;Y? je EContinue ;Y - выходим jmp NewCursor ;восстановим курсор и продолжаем работать EContinue: lea si, SaveScr ;восстановим эвесь экран xor di, di mov ax, XSize mov cx, YSize inc ax inc cx mul cx inc ax mov cx, ax rep movsw
mov ah, 2 ;восстановим курсор mov bh, 0 mov dx, PosOld int 10h mov ax, 4c00h ;выход в ДОС int 21h exit endp
;индексы в массиве псевдографики LU equ 0 RU equ 1 RD equ 2 LD equ 3 HH equ 4 VV equ 5
;индексы в массиве адресов псевдографики SINGLE equ 0 DOUBLE equ 1
;сегмент данных .data ;краткая помощь по F1 sHelp db 'F1 - эта помощь' ;, 0dh, 0ah db 'F2 - запись файла', 0dh, 0ah db 'F3 - чтение файла', 0dh, 0ah db 1ah,' - курсор вправо ', 0dh, 0ah db 1bh,' - курсор влево', 0dh, 0ah db 18h,' - курсор вверх', 0dh, 0ah db 19h,' - курсор вниз', 0dh, 0ah db 'BSp- удалить символ слева', 0dh, 0ah db 'Tab- вставить табуляцию', 0dh, 0ah db 'Ent- перейти на новую строку', 0dh, 0ah db 'Esc- выход', 0 ;подсказка о помощи в последней строке sMessHelp db ' F1-помощь ',0 ;длина подсказки sMessHelpLen equ $-sMessHelp ;сообщение, добавляемое в сообщения об ошибках sAnyKey db 0dh,0ah,'Нажмите на любую клавишу',0 ;сообщения об ошибках sOpenError db 'Файл % не найден',0 sReadError db 'Ошибка чтения файла %',0 sSizeError db 'Длина файла % >= 65535',0 sCreateError db 'Ошибка создания файла %',0 sWriteError db 'Ошибка записи файла %',0 ;для запроса имени файла sFileName db 'Имя файла: ',0 sReadFile db 'Чтение файла' ;, 0dh, 0ah, 0 sWriteFile db 'Запись файла', 0dh, 0ah, 0 ;для подтверждения продолжения при изменении файла sChanged db 'Файл изменен, продолжать? (Y,N)',0 ;таблицы псевдографики Borders dw BorderSingle, BorderDouble BorderSingle db 0dah,0bfh,0d9h,0c0h,0c4h,0b3h BorderDouble db 0c9h,0bbh,0bch,0c8h,0cdh,0bah ;имя файла по-умолчанию Default db 'Noname.txt',0 ;цвета (атрибуты) окон в виде: ст байт - текст внутри, мл байт - рамка ;цвет основного окна MainColor dw 1f17h ;цвет сообщения об ошибке ErrorColor dw 4f47h ;цвет сообщения, например, ввода имени файла MessageColor dw 3f37h ;таблица отрабатываемых кодов (скан-кодов) KeyTable db 01h,48h,4bh,4dh,50h,3bh,3dh,3ch,0eh,0fh,1ch ;длина KeyTable KeyTablelen equ $-KeyTable ;соответствующая таблица подпрограмм отработки PrgTable dw Exit,KeyUp,KeyLeft,KeyRight dw KeyDown,KeyHelp,KeyRead,KeyWrite dw KeyBack,KeyInsert,KeyEnter
. data? Xsize dw ? ;размер экрана в колонках-1, т.е. индекс последней колонки на экране Ysize dw ? ;размер экрана в строках-1, т.е. индекс последней строки на экране FileSeg dw ? ;сегмент данных файла FileLen dw ? ;длина данных файла UpLine dw ? ;смещение в сегменте данных файла первой строки отображения на экране CurLine dw ? ;смещение в сегменте данных файла текущей строки PosOld dw ? ;сохраненная позиция курсора XScreen db ? ;текущая позиция по Х на экране YScreen db ? ;текущая позиция по Y на экране XFile db ? ;текущая позиция по Х в текущей строке в файле YFile db ? ;текущая позиция по Y в текущей строке в файле fChange db ? ;флаг изменеия содержимого файла FName db 128 dup (?) ;буфер для имени файла SaveScr label word ;буфер для сохранения содержимого экрана текущей страницы
end В ASCII-кодировке текст можно взять здесь ----- Удачи! Ответ отправил: Лысков Игорь Витальевич, Модератор Ответ отправлен: 20.05.2010, 00:59 Номер ответа: 261516 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov
Оценка ответа: 5 Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 261516 на номер 1151 (Россия) | Еще номера » | Оценить выпуск » Нам очень важно Ваше мнение об этом выпуске рассылки! Скажите "спасибо" эксперту, который помог Вам! Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА на короткий номер 1151 (Россия) Номер ответа и конкретный текст СМС указан внизу каждого ответа. Полный список номеров » * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов) ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются. *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании. |
Комментариев нет:
Отправить комментарий