#pragma inline

/* Для всех функций, осуществляющих прямые
   обращения к видеопамяти, отсчет координат
   интересующей текстовой клетки экрана ведется
   от единицы (т.е. левая верхняя символьная
   клетка имеет координаты 1,1); все
   соответствующие параметры функций должны
   удовлетворять этому соглашению. */

/* адрес вектора прерывания 0x1b (Ctrl-Break)
   в таблице прерываний (смещение и сегмент) */
#define BreakOffsetPtr 0x1b*4
#define BreakSegmentPtr 0x1b*4+2

/* Отключить обработку прерывания 0x1b (Ctrl-Break) 
   Функция возвращает значение старого вектора
   прерывания 0x1b. Сегментный адрес содержится в
   старшем слове, смещение - в младшем */
unsigned long break_off(void){
 asm	xor	ax,ax;
 asm	mov	es,ax;    /* 0 сегмент в ES */

 asm	cli;  /* запретить обработку прерываний */

 /* сохранить старый вектор в DX:AX */
 /* смещение */
 asm	mov	ax,es:BreakOffsetPtr;
 /* сегмент */
 asm	mov	dx,es:BreakSegmentPtr;

 /* установить новый вектор, указывающий на
    инструкцию IRET */
 /* смещение */
 asm	mov	word ptr es:BreakOffsetPtr,offset nobreak;
 /* сегмент */
 asm	mov	es:BreakSegmentPtr,cs;

 asm	sti;  /* разрешить обработку прерываний */
 asm	jmp short quit;  /* переход на возврат */

 /* подпрограмма обработки прерывания,
    возвращающая управление по адресу вызова */
asm nobreak:
 asm	iret;

quit:;       /* возврат из функции */
} /* break_off() */

/* Установить программу обработки прерывания 0x1b (Ctrl-Break) 
   Функция устанавливает новый вектор обработки
   прерывания 0x1b (либо восстанавливает старый),
   переданный ей через параметр oldbreakvector,
   где сегментный адрес содержится в старшем слове,
   а смещение - в младшем */
void break_on(unsigned long oldbreakvector){
 asm	xor	ax,ax;
 asm	mov	es,ax;    /* 0 сегмент в ES */

 asm	cli;  /* запретить обработку прерываний */

 /* записать вектор в таблицу прерываний */
 /* смещение */
 asm	mov	ax,oldbreakvector;
 asm	mov	es:BreakOffsetPtr,ax;
 /* сегмент */
 asm	mov	ax,oldbreakvector[2];
 asm	mov	es:BreakSegmentPtr,ax;

 asm	sti;  /* разрешить обработку прерываний */
} /* break_on() */

/* Прочитать текущий видеорежим 
   Функция возвращает значение текущего
   видеорежима в регистре AX */
int get_video_mode(void){
 asm	xor	ax,ax;
 asm	mov	es,ax;	    /* 0 сегмент в ES */
 /* поместить байт текущего видеорежима
    (0:449h) в AX */
 asm	mov	al,es:[449h];    /* AH = 0 */
} /* get_video_mode() */

/* Переключить бит мигания/интенсивности 
   Функция производит переключение в соответствии
   со значением параметра blinking_status:
   1 - включить мигание;
   0 - включить интенсивность.
   Функция работает только с видеоадаптерами
   EGA/VGA
*/
void toggle_intensity_blinking(int blinking_status)
{
 asm	push	sp;   /* сохранить значения */
 asm	push	bp;   /* изменяемых регистров */
 asm	push	si;
 asm	push	di;
 /* вызов прерывания 10h, 1003h "Toggle
    intensity/blinking" */
 asm	mov	ax,1003h;
 asm	mov	bl,byte ptr blinking_status;
 asm	int	10h;

 asm	pop	di;   /* восстановить значения */
 asm	pop	si;   /* регистров */
 asm	pop	bp;
 asm	pop	sp;
} /* toggle_intensity_blinking() */

/* Прочитать код с клавиатуры 
   Функция возвращает код клавиши, полученный по
   прерыванию 16h, 00h и преобразованный
   следующим образом. Если ASCII-код клавиши не
   равен 0, то возвращается ASCII-код в младшем
   байте слова, старший же байт равен 0. Если
   ASCII-код клавиши равен 0, то в младшем байте
   возвращается скан-код этой клавиши, а старший
   байт устанавливается равным 01h. */
int getkey(void){
 /* вызов прерывания 16h, 00h "Keyboard Read" */
 /* После возврата AL содержит ASCII-код клавиши,
    AH - скан-код клавиши */
 asm	xor	ah,ah;
 asm	int	16h;

 asm	and	al,al;      /* проверить AL = 0 */
 /* если ASCII = 0, то переход на обработку скан
    кода */
 asm	jz	scancode;
 asm	xor	ah,ah; /* очистить старший байт */
 asm	jmp short quit;   /* переход на возврат */
scancode:
 /* передать скан-код в младший байт */
 asm	mov	al,ah;
 /* установить старший байт равным 01h */
 asm	mov	ah,01h;
quit:;                      /* возврат */
} /* getkey() */

/* Определить форму аппаратного курсора 
   Функция возвращает номера начальной и конечной
   скан-линиий аппаратного курсора:
   начальная скан-линия - в старшем байте слова;
   конечная скан-линия - в младшем байте слова. */
int get_cursor_size(void){
 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* конечная и начальная скан-линии курсора
    (0:460h) */
 asm	mov	ax,es:[460h];
} /* get_cursor_size() */

/* Задать форму аппаратного курсора 
   Функция устанавливает форму аппаратного курсора
   в соответствии со значением переданного
   параметра cursor_shape:
   старший байт слова содержит номер начальной
   скан-линии курсора;
   младший байт слова содержит номер конечной
   скан-линии курсора. */
void set_cursor_size(int cursor_shape){
 /* передать параметры курсора в CX и вызвать
    прерывание 10h, 01h "Set cursor size/shape" */
 asm	mov	cx,cursor_shape;
 asm	mov	ah,01h;
 asm	int	10h;
} /* set_cursor_size() */

/* Установить курсор в заданную позицию 
   Функция устанавливает аппаратный курсор в
   позицию, определяемую параметрами column и row
   (считая от единицы):
   column - горизонтальная позиция курсора;
   row - вертикальная позиция курсора; */
void set_cursor_position(int column, int row){
 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* передать номер текущей страницы дисплея
    (0:462h) в BH */
 asm	mov	bh,es:[462h];
 /* номера столбца и строки в DX */
 asm	mov	dl,byte ptr column;
 asm	mov	dh,byte ptr row;
 /* подстроить под базу 0 */
 asm	sub	dx,0101h;
 /* прерывание 10h, 02h "Set cursor position" */
 asm	mov	ah,02h;
 asm	int	10h;
} /* set_cursor_position() */

/* Определить текущую позицию и 
   форму аппаратного курсора 
   Функция возвращает длинное целое, содержащее
   следующие значения:
   0 байт - конечная скан-линия курсора;
   1 байт - начальная скан-линия курсора;
   2 байт - горизонтальная позиция курсора;
   3 байт - вертикальная позиция курсора.
*/
unsigned long get_cursor_position_size(void){
 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* номер текущей страницы (0:462h) в AL */
 asm	mov	al,es:[462h];
 /* умножить на 2 для адресации слов */
 asm	shl	ax,1;
 /* стартовый адрес таблицы позиций курсора
    (0:450h) в BX */
 asm	mov	bx,450h;
 /* прибавить смещение для текущей страницы */
 asm	add	bx,ax;
 /* горизонтальная и вертикальная позиции
    курсора в DX */
 asm	mov	dx,es:[bx];
 /* конечная и начальная скан-линии курсора в AX */
 asm	mov	ax,es:[460h];
} /* get_cursor_position_size() */

/* Задать позицию и форму аппаратного курсора 
   Функция устанавливает курсор на экране в
   указанную позицию и задает его форму в
   соответствии с переданным параметром
   cursorparms, в котором:
   0 байт - конечная скан-линия курсора;
   1 байт - начальная скан-линия курсора;
   2 байт - горизонтальная позиция курсора;
   3 байт - вертикальная позиция курсора.
*/
void set_cursor_position_size(unsigned long cursorparms){
 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* номер текущей страницы дисплея (0:462h) в BH */
 asm	mov	bh,es:[462h];
 /* передать горизонтальную и вертикальную позиции
    курсора в DX */
 asm	mov	dx,cursorparms[2];
 /* вызов прерывания 10h,02h "Set cursor position" */
 asm	mov	ah,02h;
 asm	int	10h;
 /* конечная и начальная скан-линии курсора в CX */
 asm	mov	cx,cursorparms;
 /* прерывание 10h,01h "Set cursor size/shape" */
 asm	mov	ah,01h;
 asm	int	10h;
} /* set_cursor_position_size() */

/* Построить на экране горизонтальный 
   брусок с указанными атрибутами 
   Параметры:
   row - координата строки на экране;
   start_col - координата начального (левого)
	       столбца на экране;
   width     - ширина бруска;
   sourcestring - указатель на строку новых
		  атрибутов бруска (длиной width);
   deststring   - указатель на буфер для старых
		  атрибутов бруска (длиной width).
*/
void make_hbar(int row, int start_col, int width,
	       unsigned char far *sourcestring,
         unsigned char far *deststring){
 asm	push	ds;    /* сохранить значение DS */

 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* стартовый (сегментный) адрес видеопамяти для
    цветного текстового режима */
 asm	mov	dx,0b800h;
 /* проверить текущий видеорежим */
 asm	cmp	byte ptr es:[449h],7;
 /* если не монохромный режим, то переход на
    skip_mono, иначе задать соответствующий
    стартовый адрес видеопамяти для монохромного
    режима */
 asm	jne	skip_mono;
 asm	mov	dx,0b000h;
skip_mono:
 /* передать сегментный адрес видеопамяти в DS */
 asm	mov	ds,dx;

 /* вычислить смещение бруска в видеопамяти */
 /* передать вертикальную координату бруска в CX
    и подстроить под базу 0 */
 asm	mov	cx,row;
 asm	dec	cx;
 /* длина экранной строки (в байтах) в AL */
 asm	mov	al,160;
 /* вычислить смещение строки от начала страницы
    в AX (умножив на 160) */
 asm	mul	cl;
 /* передать горизонтальную позицию начала бруска
    в CX и подстроить под базу 0 */
 asm	mov	cx,start_col;
 asm	dec	cx;
 /* умножить на 2 для доступа к словам */
 asm	shl	cx,1;
 /* вычислить смещение начала бруска от текущей
    страницы в AX */
 asm	add	ax,cx;

 /* вычислить смещение начала бруска в сегменте
    видеопамяти, прибавив смещение текущей
    страницы (0:44eh) */
 asm	add	ax,es:[44eh];

 asm	mov	si,ax; /* передать смещение в SI */

 /* загрузить far-указатель на строку-приемник */
 asm	les	di,deststring;
 asm	mov	cx,width; /* ширина бруска в CX */
 /* временно сохранить ширину в BX */
 asm	mov	bx,cx;
 /* очистить direction-флаг для обработки строки в
    сторону увеличения адреса */
 asm	cld;
 /* сохранить старые атрибуты бруска в буфере */
video2memory:
 /* увеличить адрес на 1 для доступа к атрибутам
    символа */
 asm	inc	si;
 asm	movsb;    /* передать атрибут в буфер */
 asm	loop	video2memory; /* возврат в цикл */

 /* передать адрес видеосегмента в ES */
 asm	mov	es,dx;
 asm	mov	di,ax;	/* смещение бруска в DI */
 /* загрузить far-указатель на строку-источник */
 asm	lds	si,sourcestring;
 asm	mov	cx,bx;	/* ширина бруска в CX */
 /* переслать новые атрибуты бруска в видеопамять */
memory2video:
 /* увеличить адрес на 1 для доступа к атрибутам
    символа */
 asm	inc	di;
 asm	movsb;  /* переслать байт в видеопамять */
 asm	loop	memory2video; /* возврат в цикл */

 asm	pop	ds; /* восстановить значение DS */
} /* make_hbar() */





/* Обновить строку в окне влево
   Функция обновляет в окне на экране левую часть
   редактируемой строки от текущей позиции курсора,
   устанавливая одновременно маркеры, указывающие
   на продолжение строки за рамки окна (маркеры
   устанавливаются за границами строки).
   Параметры:
   row - вертикальная координата строки;
   startcolumn, endcolumn - левая и правая
	 горизонтальные координаты границ строки
	 на экране;
   beg_status, end_status - ключи состояний левого
	 и правого маркеров:
	 1 - установить маркер,
	 0 - сбросить маркер;
   cursorpos_w - позиция курсора в окне
	 (абсолютная горизонтальная координата на
	  экране)
   cursorpos_s - указатель на текущую позицию
		 курсора в строке.
*/
void update_left(int row, int startcolumn,
    int endcolumn, int beg_status, int end_status,
    int cursorpos_w, char far *cursorpos_s){
 asm	push	ds;    /* сохранить значение DS */

 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* стартовый адрес видеопамяти для цветного
    текстового режима */
 asm	mov	cx,0b800h;
 /* проверить текущий видеорежим */
 asm	cmp	byte ptr es:[449h],7;
 /* если не монохромный режим, то переход на
    skip_mono, иначе задать соответствующий
    стартовый адрес видеопамяти для монохромного
    режима */
 asm	jne	skip_mono;
 asm	mov	cx,0b000h;
skip_mono:
 /* подстроить номер строки под базу 0 */
 asm	mov	dx,row;
 asm	dec	dx;
 /* вычислить смещение строки на странице */
 asm	mov	al,160;
 asm	mul	dl;

 /* прибавить смещение текущей страницы */
 asm	add	ax,es:[44eh];
 /* адрес видеосегмента в ES */
 asm	mov	es,cx;

 /* позиция правого маркера в DI */
 asm	mov	di,endcolumn;
 asm	shl	di,1;        /* умножить на 2 */
 /* прибавить смещение страницы и строки */
 asm	add	di,ax;
 /* очистить правый маркер на экране */
 asm	mov	byte ptr es:[di],0;
 /* если end_status = 0, то переход */
 asm	cmp	byte ptr end_status,0;
 asm	je	skip_endsign;
 /* иначе установить правый маркер */
 asm	mov	byte ptr es:[di],16;
skip_endsign:
 /* позиция курсора на экране в CX */
 asm	mov	cx,cursorpos_w;
 asm	mov	di,cx;     /* скопировать в DI */
 asm	dec	di;   /* подстроить под базу 0 */
 asm	shl	di,1;      /* умножить на 2 */
 /* прибавить смещение страницы и строки */
 asm	add	di,ax;

 /* загрузить far-указатель на позицию курсора в
    строке */
 asm	lds	si,cursorpos_s;
 /* установить direction-флаг для обработки строки
    в сторону уменьшения адреса */
 asm	std;
 /* вычислить длину выводимой строки */
 asm	sub	cx,word ptr startcolumn;
 asm	inc	cx;
memory2video:               /* выводить строку */
 asm	movsb;      /* вывести символ на экран */
 asm	dec	di;      /* пропустить атрибут */
 asm	loop	memory2video; /* возврат в цикл */

 /* очистить левый маркер */
 asm	mov	byte ptr es:[di],0;
 /* если beg_status = 0, то переход */
 asm	cmp	byte ptr beg_status,0;
 asm	je	skip_begsign;
 /* иначе установить левый маркер */
 asm	mov	byte ptr es:[di],17;
skip_begsign:
 asm	pop	ds; /* восстановить значение DS */
} /* update_left() */

/* Обновить строку в окне вправо
   Функция обновляет в окне на экране правую часть
   редактируемой строки от текущей позиции курсора,
   устанавливая одновременно маркеры, указывающие
   на продолжение строки за рамки окна (маркеры
   устанавливаются за границами строки).
   Параметры:
   row - вертикальная координата строки;
   startcolumn, endcolumn - левая и правая
	 горизонтальные координаты границ строки
	 на экране;
   beg_status, end_status - ключи состояний левого
	 и правого маркеров:
	 1 - установить маркер,
	 0 - сбросить маркер;
   cursorpos_w - позиция курсора в окне
	 (абсолютная горизонтальная координата на
	  экране)
   cursorpos_s - указатель на текущую позицию
		 курсора в строке.
*/
void update_right(int row, int startcolumn,
    int endcolumn, int beg_status, int end_status,
    int cursorpos_w, char far *cursorpos_s){
 asm	push	ds;    /* сохранить значение DS */

 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* стартовый адрес видеопамяти для цветного
    текстового режима */
 asm	mov	cx,0b800h;
 /* проверить текущий видеорежим */
 asm	cmp	byte ptr es:[449h],7;
 /* если не монохромный режим, то переход на
    skip_mono, иначе задать соответствующий
    стартовый адрес видеопамяти для монохромного
    режима */
 asm	jne	skip_mono;
 asm	mov	cx,0b000h;
skip_mono:
 /* подстроить номер строки под базу 0 */
 asm	mov	dx,row;
 asm	dec	dx;
 /* вычислить смещение строки на странице */
 asm	mov	al,160;
 asm	mul	dl;

 /* прибавить смещение текущей страницы */
 asm	add	ax,es:[44eh];
 asm	mov	es,cx;   /* видеосегмент в ES */

 /* левая координата строки */
 asm	mov	di,startcolumn;
 /* подстроить под позицию левого маркера */
 asm	dec	di;
 asm	dec	di;  /* подстроить под базу 0 */
 /* умножить на 2 для доступа к словам */
 asm	shl	di,1;
 /* прибавить смещение страницы и строки */
 asm	add	di,ax;
 /* очистить левый маркер */
 asm	mov	byte ptr es:[di],0;
 /* если beg_status = 0, то переход */
 asm	cmp	byte ptr beg_status,0;
 asm	je	skip_begsign;
 /* иначе установить левый маркер */
 asm	mov	byte ptr es:[di],17;
skip_begsign:
 /* правая граница строки */
 asm	mov	cx,endcolumn;
 /* позиция курсора на экране */
 asm	mov	di,cursorpos_w;
 /* вычислить количество обновляемых символов */
 asm	sub	cx,di;
 asm	inc	cx;
 /* подстроить координату под базу 0 */
 asm	dec	di;
 asm	shl	di,1;        /* умножить на 2 */
 /* прибавить смещение страницы и строки */
 asm	add	di,ax;
 /* временно сохранить смещение в BX */
 asm	mov	bx,ax;

 /* загрузить far-указатель на текущую позицию в
    строке */
 asm	lds	si,cursorpos_s;
 /* очистить direction-флаг для движения в
    сторону увеличения адреса */
 asm	cld;
 /* выводить символы до конца строки */
memory2video:
 asm	lodsb;       /* загрузить символ в AL */
 asm	stosb;     /* вывести символ на экран */
 /* если конец строки, то выход из цикла */
 asm	and	al,al;
 asm	jz	endofstring;
 asm	inc	di;     /* пропустить атрибут */
 asm	loop	memory2video; /* возврат в цикл */
endofstring:
 /* координата правого маркера */
 asm	mov	di,endcolumn;
 asm	shl	di,1;
 /* прибавить смещение страницы и строки */
 asm	add	di,bx;
 /* очистить правый маркер */
 asm	mov	byte ptr es:[di],0;
 /* если end_status = 0, то переход */
 asm	cmp	byte ptr end_status,0;
 asm	je	skip_endsign;
 /* иначе установить правый маркер */
 asm	mov	byte ptr es:[di],16;
skip_endsign:
 asm	pop	ds; /* восстановить значение DS */
} /* update_right() */

/* Восстановить текст на экране
   Функция заполняет окно с указанными координатами
   на экране текстом из указанной строки. Строка
   содержит коды символов, чередующиеся с их
   атрибутами. Параметры:
   left, top, right, bottom - левая, верхняя,
       правая и нижняя координаты окна на экране;
   sourcetext - указатель на строку кодов символов
		и их атрибутов.
*/
void restore_text(int left, int top, int right,
        int bottom, char far *sourcetext){
 asm	push	ds;    /* сохранить значение DS */

 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* стартовый адрес видеопамяти для цветного
    текстового режима */
 asm	mov	cx,0b800h;
 /* проверить текущий видеорежим */
 asm	cmp	byte ptr es:[449h],7;
 /* если не монохромный режим, то переход на
    skip_mono, иначе задать соответствующий
    стартовый адрес видеопамяти для монохромного
    режима */
 asm	jne	skip_mono;
 asm	mov	cx,0b000h;
skip_mono:
 /* подстроить верхнюю координату под базу 0 */
 asm	mov	dx,top;
 asm	dec	dx;
 /* вычислить смещение строки на странице, умножив
    на 160 */
 asm	mov	al,160;
 asm	mul	dl;
 /* подстроить левую координату под базу 0 */
 asm	mov	di,left;
 asm	dec	di;
 /* вычислить смещение окна на странице */
 asm	shl	di,1;
 asm	add	di,ax;

 /* прибавить смещение текущей страницы */
 asm	add	di,es:[44eh];
 /* временно сохранить смещение в AX */
 asm	mov	ax,di;

 asm	mov	es,cx; /* адрес видеосегмента в ES */

 /* загрузить far-указатель на строку-источник */
 asm	lds	si,sourcetext;

 /* вычислить высоту окна в BX */
 asm	mov	bx,bottom;
 asm	sub	bx,top;
 asm	inc	bx;
 /* вычислить ширину окна в DX */
 asm	mov	dx,right;
 asm	sub	dx,left;
 asm	inc	dx;
 /* очистить direction-флаг для движения в
    сторону увеличения адреса */
 asm	cld;
 asm	jmp short skip_addition;

mem2video_row:   /* цикл пересылки строк окна */
 /* вычислить смещение следующей строки окна и
    передать в DI */
 asm	add	ax,160;
 asm	mov	di,ax;
skip_addition:
 asm	mov	cx,dx;    /* ширина окна в CX */
 /* пересылать символы с атрибутами на экран */
 asm	rep	movsw;
 /* уменьшить счетчик строк окна на 1 */
 asm	dec	bx;
 /* если счетчик не равен 0, то возврат в цикл */
 asm	jne	mem2video_row;

 asm	pop	ds; /* восстановить значение DS */
} /* restore_text() */

/* Вставить символ в строку
   Функция вставляет переданный символ в
   указанную строку, сдвигая остальные символы
   строки вправо. Параметры:
   sourcestring - указатель на ту позицию в строке,
	    в которую должен быть вставлен символ;
   stringlength - длина строки, считая от
		  указанной позиции;
   character - код вставляемого символа.
*/
void insert_char(char far *sourcestring,
     int stringlength, int character){
 asm	push	ds;    /* сохранить значение DS */

 /* загрузить far-указатель на строку */
 asm	lds	si,sourcestring;
 /* вычислить указатель на конец строки (0) */
 asm	add	si,word ptr stringlength;
 asm	push	ds;    /* скопировать DS в ES */
 asm	pop	es;
 /* вычислить новое смещение для конца строки
    в DI */
 asm	mov	di,si;
 asm	inc	di;
 /* вычислить количество сдвигаемых символов */
 asm	mov	cx,stringlength;
 asm	inc	cx;
 /* установить direction-флаг для движения в
    сторону уменьшения адреса */
 asm	std;
 asm	rep	movsb;  /* перемещать символы */
 /* загрузить в AL код вставляемого символа */
 asm	mov	al,byte ptr character;
 asm	stosb; /* вставить символ в строку */

 asm	pop	ds; /* восстановить значение DS */
} /* insert_char() */

/* Удалить символ из строки
   Функция удаляет символ из строки, сдвигая
   оставшиеся символы строки влево. Параметры:
   sourcestring - указатель на тот символ строки,
		  который необходимо удалить;
   stringlength - длина строки, считая от
		  указанного символа.
*/
void delete_char(char far *sourcestring,
         int stringlength){
 asm	push	ds;    /* сохранить значение DS */

 /* загрузить far-указатель на строку */
 asm	lds	si,sourcestring;
 asm	push	ds;    /* скопировать DS в ES */
 asm	pop	es;

 asm	mov	di,si; /* скопировать смещение в DI */
 /* смещение следующего символа в SI */
 asm	inc	si;
 /* счетчик сдвигаемых символов */
 asm	mov	cx,stringlength;
 /* очистить direction-флаг для движения в
    сторону увеличения адреса */
 asm	cld;
 asm	rep	movsb;  /* перемещать символы */

 asm	pop	ds; /* восстановить значение DS */
} /* delete_char() */

/* Скопировать строку
   Функция копирует строку-источник в строку-
   приемник, возвращая при этом число
   скопированных символов (длину строки).
   Параметры:
   deststring - указатель на строку-приемник;
   sourcestring - указатель на строку-источник.
*/
int string_copy(char far *deststring,
    char far *sourcestring){
 asm	push	ds;    /* сохранить значение DS */
 /* загрузить far-указатель на строку-источник */
 asm	lds	si,sourcestring;
 /* загрузить far-указатель на строку-приемник */
 asm	les	di,deststring;
 asm	xor	dx,dx;	/* счетчик в DX равен 0 */
 /* очистить direction-флаг для движения в
    сторону увеличения адреса */
 asm	cld;
nextchar:          /* цикл пересылки символов */
 asm	lodsb;     /* загрузить символ в AL */
 /* записать символ в строку-приемник */
 asm	stosb;
 /* увеличить счетчик символов на 1 */
 asm	inc	dx;
 /* если не конец строки (0), то возврат в цикл */
 asm	and	al,al;
 asm	jne	nextchar;

 /* уменьшить счетчик символов на 1, т.к. был
    сосчитан конец строки, и передать в AX */
 asm	dec	dx;
 asm	mov	ax,dx;
 asm	pop	ds; /* восстановить значение DS */
} /* string_copy() */
/* Очистить на экране строку указанной длины
   Функция очищает на экране строку указанной
   длины, начиная с указанной позиции.
   Параметры:
   row, start_col - вертикальная и горизонтальная
      координаты первого символа строки на экране;
   nn_chars - количество удаляемых символов. */
void clear_nchars(int row, int start_col,
                  int nn_chars){
 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* стартовый адрес видеопамяти для цветного
    текстового режима */
 asm	mov	cx,0b800h;
 /* проверить текущий видеорежим */
 asm	cmp	byte ptr es:[449h],7;
 /* если не монохромный режим, то переход на
    skip_mono, иначе задать соответствующий
    стартовый адрес видеопамяти для монохромного
    режима */
 asm	jne	skip_mono;
 asm	mov	cx,0b000h;
skip_mono:
 /* подстроить вертикальную координату под базу 0 */
 asm	mov	dx,row;
 asm	dec	dx;
 /* вычислить смещение строки */
 asm	mov	al,160;
 asm	mul	dl;
 /* подстроить горизонтальную координату под
    базу 0 */
 asm	mov	di,start_col;
 asm	dec	di;
 /* умножить на 2 для доступа к словам */
 asm	shl	di,1;
 /* прибавить смещение столбца */
 asm	add	di,ax;

 /* прибавить смещение текущей страницы в
    видеосегменте */
 asm	add	di,es:[44eh];
 /* передать стартовый адрес видеосегмента в ES */
 asm	mov	es,cx;

 asm	xor	ax,ax;    /* установить AL = 0 */
 /* установить счетчик символов */
 asm	mov	cx,nn_chars;
 /* очистить direction-флаг для движения в сторону
    увеличения адреса */
 asm	cld;
 /* очистить строку на экране */
clear_char:
 asm	stosb           /* вывести 0 на экран */
 /* пропустить атрибут символа */
 asm	inc	di;
 asm	loop	clear_char; /* возврат в цикл */
} /* clear_nchars() */
/* Вывести строку на экран
   Функция выводит на экран ASCIIZ-строку (строка,
   заканчивающаяся нулем), начиная с указанной
   позиции. Параметры:
   row, start_col - вертикальная и горизонтальная
      координаты первого символа строки на экране;
   sourcestring - указатель на выводимую строку.
*/
void put_string(int row, int start_col,
                char far *sourcestring){
 asm	push	ds;    /* сохранить значение DS */

 asm	xor	ax,ax;
 asm	mov	es,ax;      /* 0 сегмент в ES */

 /* стартовый адрес видеопамяти для цветного
    текстового режима */
 asm	mov	cx,0b800h;
 /* проверить текущий видеорежим */
 asm	cmp	byte ptr es:[449h],7;
 /* если не монохромный режим, то переход на
    skip_mono, иначе задать соответствующий
    стартовый адрес видеопамяти для монохромного
    режима */
 asm	jne	skip_mono;
 asm	mov	cx,0b000h;
skip_mono:
 /* подстроить вертикальную координату под базу 0 */
 asm	mov	dx,row;
 asm	dec	dx;
 /* вычислить смещение строки */
 asm	mov	al,160;
 asm	mul	dl;
 /* подстроить горизонтальную координату под
    базу 0 */
 asm	mov	di,start_col;
 asm	dec	di;
 /* умножить на 2 для доступа к словам */
 asm	shl	di,1;
 /* прибавить смещение столбца */
 asm	add	di,ax;

 /* прибавить смещение текущей страницы в
    видеосегменте */
 asm	add	di,es:[44eh];
 /* передать стартовый адрес видеосегмента в ES */
 asm	mov	es,cx;

 /* загрузить far-указатель на строку-источник */
 asm	lds	si,sourcestring;
 /* очистить direction-флаг для движения в
    сторону увеличения адреса */
 asm	cld;
 /* выдать строку на экран */
memory2video:
 asm	lodsb;       /* загрузить символ в AL */
 asm	and	al,al;            /* AL = 0 ? */
 /* если конец строки, то переход на возврат */
 asm	je	quit;
 asm	stosb;      /* вывести символ на экран */
 /* пропустить атрибут символа */
 asm	inc	di;
 /* возврат в цикл */
 asm	jmp short memory2video;
quit:
 asm	pop	ds; /* восстановить значение DS */
} /* put_string() */
