Пример 16



/*#!/bin/cc -DUSG wins.c -o wins -lncurses -lx

	Просмотр двух файлов в перекрывающихся окнах.

	Редактирование содержимого окон.

*/

/* _______________________ файл wcur.h __________________________ */

#include "curses.h"

	/* Макросы, зависимые от реализации curses */

/* число колонок и строк в окне: */

#  define wcols(w)  ((w)-> _maxx+1 )

#  define wlines(w) ((w)-> _maxy+1 )

/* верхний левый угол окна: */

#  define wbegx(w)  ((w)-> _begx )

#  define wbegy(w)  ((w)-> _begy )

/* координаты курсора в окне: */

#  define wcurx(w)  ((w)-> _curx )

#  define wcury(w)  ((w)-> _cury )

/* доступ к памяти строк окна: */

#  define wtext(w)  ((w)-> _line)  /* chtype **_line; */

/* в других реализациях: ((w)-> _y) */

/* Псевдографика:    Для  curses   Для IBM PC MS DOS */

#define HOR_LINE        '\200'     /* 196 */

#define VER_LINE        '\201'     /* 179 */

#define UPPER_LEFT      '\210'     /* 218 */

#define LOWER_LEFT      '\202'     /* 192 */

#define UPPER_RIGHT     '\212'     /* 191 */

#define LOWER_RIGHT     '\204'     /* 217 */

#define LEFT_JOIN       '\205'     /* 195 */

#define RIGHT_JOIN      '\207'     /* 180 */

#define TOP_JOIN        '\211'     /* 194 */

#define BOTTOM_JOIN     '\203'     /* 193 */

#define MIDDLE_CROSS    '\206'     /* 197 */

#define BOX             '\272'     /* 219 */

#define BOX_HATCHED     '\273'     /* 177 */

#define LABEL           '\274'     /*   3 */

#define RIGHT_TRIANG    '\234'     /*  16 */

#define LEFT_TRIANG     '\235'     /*  17 */

#define YES                 1

#define NO                  0

#define MIN(a,b)        (((a) < (b)) ? (a):(b))

#define MAX(a,b)        (((a) > (b)) ? (a):(b))

#define A_ITALICS  A_ALTCHARSET  /* в этой версии curses-а - курсив */

#ifndef  ESC

# define ESC '\033'     /* escape */

#endif

#define  ctrl(c)  (c & 037)

/* перерисовка экрана */

#define RedrawScreen() { vidattr(curscr->_attrs = A_NORMAL); \

			 wrefresh(curscr); }

/* curscr - служебное окно - копия текущего состояния экрана дисплея

 * для сравнения со сформированным НОВЫМ образом  экрана - newscr.

 * Поле _attrs в структуре окна содержит текущие атрибуты окна,

 * именно это поле изменяется wattrset(), wattron(), wattroff();

 */

/* _______________________ файл wins.c __________________________ */

#include "wcur.h"

#include <signal.h>

WINDOW *wbase1, *wbase2;        /* окна рамки (фоновые окна) */

WINDOW *w1,     *w2;            /* окна для текста */

/* Размеры и расположение окон */

/* COLS - предопределенная переменная: число колонок */

/* LINES     - // -                  : число строк на экране */

#define W1ysize (LINES/2)       /* высота */

#define W1xsize (COLS/3*2)      /* ширина */

#define W1y     5               /* y верхнего левого угла на экране */

#define W1x     20              /* x верхнего левого угла на экране */

#define W2ysize (LINES/2)

#define W2xsize (COLS/3*2)

#define W2y     10

#define W2x     5

FILE *fp1, *fp2;         /* просматриваемые файлы */

/* Завершить работу */

void die(sig){                /* аргумент - номер сигнала */

	/* Восстановление режимов терминала */

	echo();         /* эхо-отображение вводимых букв */

	nocbreak();     /* ввод с системным редактированием строки */

	mvcur( -1, -1, LINES-1, 0 ); /* курсор в нижн. левый угол  */

	endwin();       /* окончание  работы с curses-ом */

	putchar('\n');

	exit(sig);      /* завершение работы с кодом sig. 0 - успешно */

}

int run;

void stop(nsig){ signal(SIGINT, SIG_IGN); run = 0; beep(); }

char label[3][5] = {  /* Демонстрация псевдографики */

 { UPPER_LEFT,  TOP_JOIN,     UPPER_RIGHT,    HOR_LINE, '\0' },

 { LEFT_JOIN,   MIDDLE_CROSS, RIGHT_JOIN,     VER_LINE, '\0' },

 { LOWER_LEFT,  BOTTOM_JOIN,  LOWER_RIGHT,    BOX,      '\0' }

};

/* Нарисовать рамку, название и фон окна */

wborder( w, name ) WINDOW *w;  char *name;

{       register i, j;

	for(i=1; i < wlines(w)-1; i++ ){

		/* поставить курсор и выдать символ */

		mvwaddch(w, i, 0,          VER_LINE );

		/* mvwaddch(w,y,x,c) = wmove(w,y,x); waddch(w,c); */

		/* wmove(w,y,x) - логич. курсор в позицию (y,x)   */

		/* waddch(w,c)  - выдать символ в позиции курсора,

		   продвинуть курсор. Аналог putchar              */

		mvwaddch(w, i, wcols(w)-1, VER_LINE );

	}

	for(j=1; j < wcols(w)-1; j++ ){

		mvwaddch(w, 0,           j, HOR_LINE );

		mvwaddch(w, wlines(w)-1, j, HOR_LINE );

	}               /* Углы */

	mvwaddch(w, 0,            0,          UPPER_LEFT);

	mvwaddch(w, wlines(w)-1,  0,          LOWER_LEFT);

	mvwaddch(w, wlines(w)-1,  wcols(w)-1, LOWER_RIGHT);

	mvwaddch(w, 0,            wcols(w)-1, UPPER_RIGHT);

	/* Рисуем заголовки вверху и внизу на рамке.

	 * Заголовки выдаем в центре рамки.

	 */

	if( (j = (wcols(w) - strlen(name))/2 ) > 0 ){

	     /* логический курсор - в 0 строку, позицию j */

	     wmove(w, 0, j);

	     /* задать режимы выделений */

	     wattrset( w, A_BOLD | A_BLINK | A_REVERSE );

	     waddstr( w, name );     /* выдать строку в окно */

	     wmove( w, wlines(w)-1, j);

	     wattrset( w, A_ITALICS | A_STANDOUT );

	     waddstr ( w, name );

	     wattrset( w, A_NORMAL ); /* нормальные атрибуты */

	}

}

/* режим редактирования текста в окнах     */

int mode = 0;   /* 0 - замена, 1 - вставка */

main( ac, av ) char **av;

{

	char buffer[512];

	int need1, need2;

	int c; void (*save)();

	WINDOW *w;  /* активное окно */

	if( ac < 3 ){

		fprintf( stderr, "Вызов: %s file1 file2\n", av[0] );

		exit( 1 );

	}

	if((fp1 = fopen( av[1], "r" )) == NULL ){

		fprintf( stderr, "Не могу читать %s\n", av[1] );

		exit( 2 );

	}

	if((fp2 = fopen( av[2], "r" )) == NULL ){

		fprintf( stderr, "Не могу читать %s\n", av[2] );

		exit( 2 );

	}

	/* Инициализировать curses */

	initscr();

	signal( SIGINT, die );        /* по ctrl/C - умереть */

	signal( SIGQUIT,die );

	/* Создать окна                                            */

	/*               высота   ширина   Y  и X верх.левого угла */

	wbase1 = newwin( W1ysize, W1xsize, W1y, W1x);

	if( wbase1 == NULL ){

		fprintf( stderr, "Не могу создать wbase1\n" );

		goto bad;

	}

	wbase2 = newwin( W2ysize, W2xsize, W2y, W2x);

	if( wbase2 == NULL ){

		fprintf( stderr, "Не могу создать wbase2\n" );

		goto bad;

	}

	/* Создать подокна для текста                                */

	/*           база    высота       ширина       Y угла X угла */

	w1 = subwin( wbase1, W1ysize - 2, W1xsize - 2, W1y+1, W1x+1);

	w2 = subwin( wbase2, W2ysize - 2, W2xsize - 2, W2y+1, W2x+1);

	scrollok( w1, TRUE );   /* разрешить роллирование окон */

	scrollok( w2, TRUE );

	wattrset( w2, A_REVERSE  ); /*установить атрибуты текста в окнах*/

	wattrset( stdscr, A_STANDOUT );

	wborder( wbase1, av[1] );

	wborder( wbase2, av[2] );   /* рамки */

	werase( w1 ); werase( w2 );        /* очистить окна */

	/* фон экрана */

	werase( stdscr );

	/* функции без буквы w... работают с окном stdscr (весь экран) */

	for(c=0; c < 3; c++)

	    mvwaddstr(stdscr, c, COLS-5, &label[c][0]);

	move( 1, 10 ); addstr( "F1 - переключить окна" );

	mvaddstr( 2, 10,       "F5 - переключить режим вставки/замены" );

	move( 3, 10 ); printw( "F%d - удалить строку, F%c - вставить строку",

				 7,                    '8'             );

	mvwprintw(stdscr, 4,10, "ESC - выход, CTRL/C - прервать просмотр");

	/* wprintw(w, fmt, ...) - аналог printf для окон */

	   /* В нижний правый угол экрана ничего не выводить:

	    * на некоторых терминалах это роллирует экран и тем самым

	    * портит нам картинку.

	    */

	   wattrset( stdscr, A_NORMAL );

	   wmove(    stdscr, LINES-1, COLS-1 );

	   waddch(   stdscr, ' ' );

	wnoutrefresh( stdscr );

	/* виртуальное проявление окна. */

	run = need1 = need2 = 1; /* оба файла не достигли конца */

	/* прерывать просмотр по CTRL/C */

	save = signal(SIGINT, stop);

	while( run && (need1 || need2)){

		if( need1 ){

		    /* прочесть строку из первого файла */

		    if( fgets( buffer, sizeof buffer, fp1 ) == NULL )

			need1 = 0;      /* конец файла */

		    else{

			/* выдать строку в окно */

			waddstr( w1, buffer );

		    }

		}

		if( need2 ){

		    /* прочесть строку из второго файла */

		    if( fgets( buffer, sizeof buffer, fp2 ) == NULL )

			need2 = 0;      /* конец файла */

		    else{

			waddstr( w2, buffer );

			/* wnoutrefresh( w2 ); */

		    }

		}

		/* Проявить w1 поверх w2 */

		touchwin( wbase2 ); wnoutrefresh( wbase2 );

		touchwin( w2 );     wnoutrefresh( w2 );

		touchwin( wbase1 ); wnoutrefresh( wbase1 );

		touchwin( w1 );     wnoutrefresh( w1 );

		/* touchwin - пометить окно как целиком измененное.

		 * wnoutrefresh - переписать изменения в новый образ

		 * экрана в памяти. */

		/* Проявить изображение на экране терминала

		 * (вывести новый образ экрана). При этом выводятся

		 * лишь ОТЛИЧИЯ от текущего содержимого экрана

		 * (с целью оптимизации).

		 */

		doupdate();

	}

	fclose(fp1); fclose(fp2);

	/* восстановить спасенную реакцию на сигнал */

	signal(SIGINT, save);

	/* Редактирование в окнах                */

	noecho();       /* выкл. эхо-отображение */

	cbreak();       /* немедленный ввод набранных клавиш

			 * (без нажатия кнопки \n) */

	keypad( w1, TRUE );     /* распознавать функц. кнопки */

	keypad( w2, TRUE );

	scrollok( w1, FALSE );  /* запретить роллирование окна */

	w = w1;                 /* текущее активное окно */

	for( ;; ){

		int y, x;       /* координаты курсора в окне */

		wrefresh( w ); /* обновить окно. Примерно соответствует

				* wnoutrefresh(w);doupdate(); */

		c = wgetch( w );  /* ввести символ с клавиатуры */

		/* заметим, что в режиме noecho() символ не

		 * отобразится в окне без нашей помощи !

		 */

		getyx( w, y, x );  /* узнать координаты курсора в окне */

 /* не надо &y &x, т.к. это макрос, превращающийся в пару присваиваний */

		switch( c ){

		case KEY_LEFT:              /* шаг влево */

			waddch( w, '\b' );

			break;

		case KEY_RIGHT:             /* шаг вправо */

			wmove( w, y, x+1 );

			break;

		case KEY_UP:                /* шаг вверх */

			wmove( w, y-1, x );

			break;

		case KEY_DOWN:              /* шаг вниз */

		       wmove( w, y+1, x );

			break;

		case KEY_HOME:              /* в начало строки */

		case KEY_LL:   /* KEY_END      в конец строки  */

		{       int xbeg, xend;

			wbegend(w, &xbeg, &xend);

			wmove(w, y, c==KEY_HOME ? xbeg : xend);

			break;

		}

		case '\t':                  /* табуляция */

			x += 8 - (x % 8);

			if( x >= wcols( w ))

				x = wcols(w)-1;

			wmove(w, y, x);

			break;

		case KEY_BACKTAB:           /* обратная табуляция */

			x -= 8 - (x % 8);

			if( x < 0 ) x = 0;

			wmove( w, y, x );

			break;

		case '\b':                  /* забой */

		case KEY_BACKSPACE:

		case '\177':

			if( !x ) break;     /* ничего */

			wmove( w, y, x-1 );

			/* and fall to ... (и провалиться в) */

		case KEY_DC:                /* удаление над курсором */

			wdelch( w );

			break;

		case KEY_IC:         /* вставка пробела над курсором */

			winsch( w, ' ' );

			break;

		case KEY_IL:

		case KEY_F(8):              /* вставка строки */

			winsertln( w );

			break;

		case KEY_DL:                /* удаление строки */

		case KEY_F(7):

			wdeleteln( w );

			break;

		case ESC:                   /* ESC - выход */

			goto out;

		case KEY_F(1):       /* переключение активного окна */

			if( w == w1 ){

				touchwin( wbase2 ); wnoutrefresh( wbase2 );

				touchwin( w2 );     wnoutrefresh( w2 );

				w = w2;

			} else {

				touchwin( wbase1 ); wnoutrefresh( wbase1 );

				touchwin( w1 );     wnoutrefresh( w1 );

				w = w1;

			}

			break;

		case KEY_F(5):    /* переключение режима редактирования */

			mode = ! mode;

			break;

		case ctrl('A'):   /* перерисовка экрана */

			RedrawScreen(); break;

		case '\n': case '\r':

			waddch( w, '\n' );

			break;

		default:          /* добавление символа в окно */

			if( c >= 0400 ){

				beep();     /* гудок */

				break;      /* функц. кнопка - не буква */

			}

			if( mode ){

				winsch( w, ' ' );  /* раздвинь строку */

			}

			waddch( w, c );     /* выдать символ в окно */

			break;

		}

	}

out:

	wrefresh( w ); wsave(w);

bad:

	die(0); /* вызов без возврата */

}

/* Сохранить содержимое окна в файл, обрезая концевые пробелы */

wsave(w) WINDOW *w;

{

	FILE *fp = fopen("win.out", "w");

	register int x,y, lastnospace; int xs, ys;

	getyx(w, ys, xs);

	for( y=0; y < wlines(w); y++ ){

		/* поиск последнего непробела */

		for( lastnospace = (-1), x=0; x < wcols(w); x++ )

			/* читаем символ из координат (x,y) окна */

			if((mvwinch(w,y,x) & A_CHARTEXT) != ' ' )

				    lastnospace = x;

		/* запись в файл */

		for( x=0 ; x <= lastnospace; x++ ){

			wmove(w,y,x);

			putc( winch(w) & A_CHARTEXT, fp );

		}

		putc( '\n', fp );

	}

	fclose(fp);

	wmove(w, ys, xs ); /* вернуть курсор на прежнее место */

}

/* На самом деле

 * winch(w) = wtext(w)[ wcury(w) ][ wcurx(w) ];

 * Предложим еще один, более быстрый способ чтения памяти окна

 * (для ЗАПИСИ в окно он непригоден, т.к.  curses еще

 * специальным образом помечает ИЗМЕНЕННЫЕ области окон).

 */

/* Найти начало и конец строки */

int wbegend(w, xbeg, xend) WINDOW *w; int *xbeg, *xend;

{

/* Тип chtype: 0xFF - код символа; 0xFF00 - атрибуты */

	chtype ch, *thisline = wtext(w)[ wcury(w) ];

	register x, notset = TRUE;

	*xbeg = *xend = 0;

	for(x=0; x < wcols(w); x++)

		/* & A_CHARTEXT игнорирует атрибуты символа */

		if(((ch=thisline[x]) & A_CHARTEXT) != ' '){

			if((*xend = x+1) >= wcols(w))

			    *xend = wcols(w) - 1;

			if(notset){ notset = FALSE; *xbeg=x; }

		}

	return (*xend - *xbeg);

}

[Назад][Содержание][Вперед]

Используются технологии uCoz