Пример 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);
}

© Copyright А. Богатырев, 1992-95 www.abyss-group.narod.ru
Си в UNIX

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

Hosted by uCoz