Хрестоматия по программированию на Си в Unix
/* УПРАВЛЕНИЕ ПОРЯДКОМ ОКОН НА ЭКРАНЕ */
/* ______________________________________________________________ */
#include "w.h"
int botw = EOW, topw = EOW; /* нижнее и верхнее окна */
struct WindowList wins[MAXW]; /* список управляемых окон */
/* Прочесть символ из окна, проявив окно (если оно не спрятано) */
int WinGetch (WINDOW *win) { register n, dorefr = YES;
if(botw != EOW) for(n=botw; n != EOW; n=wins[n].next)
if(wins[n].w == win){
if(wins[n].busy == W_HIDDEN) dorefr = NO; /* спрятано */
break;
}
if( dorefr ) wrefresh (win); /* проявка */
else doupdate ();
for(;;){ n = wgetch (win); /* собственно чтение */
if( n == ctrl('A')){ RedrawScreen(); continue; }
return n;
}
}
/* Вычислить новое верхнее окно */
static void ComputeTopWin(){ register n;
if(botw == EOW) topw = EOW; /* список стал пуст */
else{ /* ищем самое верхнее видимое окно */
for(topw = EOW, n=botw; n != EOW; n=wins[n].next)
/* спрятанное окно не может быть верхним */
if( wins[n].busy == W_VISIBLE) topw = n;
/* Может совсем не оказаться видимых окон; тогда
* topw == EOW, хотя botw != EOW. Макрос TOPW предложит
* в качестве верхнего окна окно stdscr */
}
}
/* Виртуально перерисовать окна в списке в порядке снизу вверх */
static void WinRefresh(){ register nw;
/* чистый фон экрана */
touchwin(stdscr); wnoutrefresh(stdscr);
if(botw != EOW) for(nw=botw; nw != EOW; nw=wins[nw].next)
if(wins[nw].busy == W_VISIBLE){
touchwin(wins[nw].w); wnoutrefresh(wins[nw].w);
}
}
/* Исключить окно из списка не уничтожая ячейку */
static int WinDelList(WINDOW *w){ register nw, prev;
if(botw == EOW) return EOW; /* список пуст */
for(prev=EOW, nw=botw; nw != EOW; prev=nw, nw=wins[nw].next)
if(wins[nw].w == w){
if(prev == EOW) botw = wins[nw].next; /* было дно стопки */
else wins[prev].next = wins[nw].next;
return nw; /* номер ячейки в таблице окон */
}
return EOW; /* окна не было в списке */
}
/* Сделать окно верхним, если его еще не было в таблице - занести */
int RaiseWin(WINDOW *w){ int nw, n;
if((nw = WinDelList(w)) == EOW){ /* не было в списке */
for(nw=0; nw < MAXW; nw++) /* занести в таблицу */
if( !iswindow(nw)){ wins[nw].w = w; break; }
if(nw == MAXW){ beep(); return EOW; } /* слишком много окон */
}
/* поместить окно nw на вершину списка */
if(botw == EOW) botw = nw;
else{ for(n = botw; wins[n].next != EOW; n=wins[n].next);
wins[n].next = nw;
}
wins[nw].busy = W_VISIBLE; /* окно видимо, слот занят */
wins[topw = nw].next = EOW; WinRefresh(); return nw;
}
/* Удалить окно из списка и (возможно) уничтожить */
/* Окно при этом исчезнет с экрана */
void DestroyWin(WINDOW *w, int destroy){ int nw;
if((nw = WinDelList(w)) != EOW){ /* окно было в списке */
ComputeTopWin();
wins[nw].busy = W_FREE; /* ячейка свободна */
wins[nw].w = NULL;
}
if(destroy) delwin(w); /* уничтожить curses-ное окно */
WinRefresh();
}
void PopWin(){ KillWin(TOPW); }
/* Спрятать окно, и при этом сделать его самым нижним. */
int HideWin(WINDOW *w){ register nw, prev;
if(botw == EOW) return EOW; /* список пуст */
for(prev = EOW, nw = botw; nw != EOW; prev = nw, nw = wins[nw].next )
if(wins[nw].w == w){
wnoutrefresh(w); /* вместо untouchwin(w); */
wins[nw].busy = W_HIDDEN; /* спрятано */
if( nw != botw ){
wins[prev].next = wins[nw].next; /* удалить из списка */
wins[nw].next = botw; botw = nw; /* на дно стопки */
}
WinRefresh();
ComputeTopWin();
return nw;
}
return EOW; /* нет в списке */
}
/* _______________ ОФОРМИТЕЛЬСКИЕ РАБОТЫ _____________________ */
/* Нарисовать горизонтальную линию */
void whorline(WINDOW *w, int y, int x1, int x2){
for( ; x1 <= x2; x1++) mvwaddch(w, y, x1, HOR_LINE);
}
/* Нарисовать вертикальную линию */
void wverline(WINDOW *w, int x, int y1, int y2){
for( ; y1 <= y2; y1++) mvwaddch(w, y1, x, VER_LINE);
}
/* Нарисовать прямоугольную рамку */
void wbox(WINDOW *w, int x1, int y1, int x2, int y2){
whorline(w, y1, x1+1, x2-1);
whorline(w, y2, x1+1, x2-1);
wverline(w, x1, y1+1, y2-1);
wverline(w, x2, y1+1, y2-1);
/* Углы */
mvwaddch (w, y1, x1, UPPER_LEFT);
mvwaddch (w, y1, x2, UPPER_RIGHT);
mvwaddch (w, y2, x1, LOWER_LEFT);
/* Нижний правый угол нельзя занимать ! */
if(! (wbegx(w) + x2 == COLS-1 && wbegy(w) + y2 == LINES-1))
mvwaddch (w, y2, x2, LOWER_RIGHT);
}
/* Нарисовать рамку вокруг окна */
void wborder(WINDOW *w){ wbox(w, 0, 0, wcols(w)-1, wlines(w)-1); }
/* Очистить прямоугольную область в окне */
void wboxerase(WINDOW *w, int x1, int y1, int x2, int y2){
int x, y; register i, j; getyx(w, y, x);
for(i=y1; i <= y2; ++i) for(j=x1; j <= x2; j++)
mvwaddch(w, i, j, ' ');
wmove(w, y, x);
}
/* Нарисовать рамку и заголовок у окна */
void WinBorder (WINDOW *w, int bgattrib, int titleattrib, char *title,
int scrollok, int clear){
register x, y;
wattrset (w, bgattrib); /* задать цвет окна */
if(clear) werase(w); /* заполнить окно цветными пробелами */
wborder (w); /* нарисовать рамку вокруг окна */
if (title) { /* если есть заголовок ... */
for (x = 1; x < wcols (w) - 1; x++){
wattrset(w, bgattrib); mvwaddch (w, 2, x, HOR_LINE);
/* очистка поля заголовка */
wattrset(w, titleattrib); mvwaddch (w, 1, x, ' ');
}
wattrset(w, bgattrib);
mvwaddch (w, 2, 0, LEFT_JOIN);
mvwaddch (w, 2, wcols (w) - 1, RIGHT_JOIN);
wattrset (w, A_BOLD | titleattrib);
mvwaddstr(w, 1, (wcols(w)-strlen(title))/2, title);
wattrset (w, bgattrib);
}
if (scrollok & BAR_VER) { /* выделить столбец под scroll bar. */
int ystart = WY(title, 0), xend = XEND(w, scrollok);
for (y = ystart; y < wlines (w) - 1; y++)
mvwaddch (w, y, xend, VER_LINE);
mvwaddch (w, wlines (w)-1, xend, BOTTOM_JOIN);
mvwaddch (w, ystart-1, xend, TOP_JOIN);
}
/* затычка */
if(wcols(w)==COLS && wlines(w)==LINES){ wattrset(w, A_NORMAL);
mvwaddch(w, LINES-1, COLS-1, ' ');
}
wattrset (w, bgattrib);
}
/* Нарисовать вертикальный scroll bar (горизонтальный не сделан) */
/* Написано не очень аккуратно */
void WinScrollBar(WINDOW *w, int whichbar, int n, int among,
char *title, int bgattrib){
register y, i;
int starty = WY(title, 0);
int endy = wlines (w) - 1;
int x = XEND(w, whichbar) + 1;
int height = endy - starty ;
if(whichbar & BAR_VER){ /* вертикальный */
wattrset (w, A_NORMAL);
for (y = starty; y < endy; y++)
for (i = 0; i < BARWIDTH; i++)
mvwaddch (w, y, x + i, ' ');
y = starty;
if(among > 1) y += ((long) (height - BARHEIGHT) * n / (among - 1));
wattron(w, A_BOLD);
for (i = 0; i < BARWIDTH; i++)
mvwaddch (w, y, x + i, BOX);
wattrset(w, bgattrib | A_BOLD );
if( wcols(w) >= 10 )
mvwprintw(w, 0, wcols(w)-9, "%03d/%03d", n+1, among);
}
wattrset (w, bgattrib);
}
#ifdef TEST
main(){ WINDOW *w[5]; register i, y;
initscr(); /* запустить curses */
w[0] = newwin(16, 20, 4, 43); /* создать 5 окон */
w[1] = newwin(12, 20, 7, 34);
w[2] = newwin(6, 30, 3, 40);
w[3] = newwin(7, 35, 12, 38);
w[4] = newwin(6, 20, 11, 54);
for(i=0; i < 5; i++){
keypad (w[i], TRUE);
wattrset(w[i], A_REVERSE); werase(w[i]);
wborder (w[i]); mvwprintw(w[i], 1, 2, "Window %d", i);
RaiseWin(w[i]); /* сделать верхним окном */
}
noecho(); cbreak(); /* прозрачный ввод */
for(;botw != EOW;){ int c;
/* нарисовать порядок окон */
for(i=botw, y=0; y < 5; y++, i=(i==EOW ? EOW : wins[i].next))
mvprintw(8 - y, 5, i==EOW ? "~": "%d%c", i,
wins[i].busy == W_HIDDEN ? 'h':' ');
mvprintw(9, 5, "topw=%3d botw=%3d", topw, botw);
wnoutrefresh(stdscr); /* вирт. проявка этих цифр */
c = WinGetch(TOPW);
/* здесь происходит doupdate();
* и только в этот момент картинка проявляется */
switch(c){
case KEY_DC: PopWin(); break;
case KEY_IC: KillWin(BOTW); break;
case '0': case '1': case '2': case '3': case '4': case '5':
c -= '0'; if( !iswindow(c)){ beep(); break; }
RaiseWin(WIN(c)); break;
case 'D': KillWin(w[2]); break;
case 'h': HideWin(BOTW); break;
case 'H': HideWin(TOPW); break;
case ESC: goto out;
default: waddch(TOPW, c & 0377); break;
}
}
mvaddstr(LINES-2, 0, "Больше нет окон"); refresh();
out: echo(); nocbreak(); endwin();
}
#endif
/* Пример 18 */
/* _______________________ файл glob.h ___________________________*/
/* ПОДДЕРЖКА СПИСКА ИМЕН ФАЙЛОВ ЗАДАННОГО КАТАЛОГА */
/* ______________________________________________________________ */
#define FILF
#include
#include
#include
# define DIR_SIZE 14
extern char *malloc(unsigned); char *strdup(const char *str);
extern char *getenv();
extern char *strchr(char *, char), *strrchr(char *, char);
#define ISDIR(mode) ((mode & S_IFMT) == S_IFDIR)
#define ISDEV(mode) ((mode & S_IFMT) & (S_IFCHR|S_IFBLK))
#define ISREG(mode) ((mode & S_IFMT) == S_IFREG)
#define ISEXE(mode) ((mode & S_IFMT) == S_IFREG && (mode & 0111))
#define isdir(st) ISDIR(st.st_mode)
#define isdev(st) ISDEV(st.st_mode)
#define isreg(st) ISREG(st.st_mode)
#define isexe(st) ISEXE(st.st_mode)
#define YES 1
#define NO 0
#define I_DIR 0x01 /* это имя каталога */
#define I_EXE 0x02 /* это выполняемый файл */
#define I_NOSEL 0x04 /* строку нельзя выбрать */
#define I_SYS (I_DIR | I_EXE | I_NOSEL)
/* Скопировано из treemk.c
* Лучше просто написать #include "glob.h" в файле treemk.c
*/
#define FAILURE (-1) /* код неудачи */
#define SUCCESS 1 /* код успеха */
#define WARNING 0 /* нефатальная ошибка */
typedef struct _info { /* структура элемента каталога */
char *s; /* имя файла */
short fl; /* флаг */
union _any{
int (*act)(); /* возможно связанное действие */
char *note; /* или комментарий */
unsigned i; /* или еще какой-то параметр */
struct _info *inf;
} any; /* вспомогательное поле */
#ifdef FILF
/* дополнительные необязательные параметры, получаемые из stat(); */
long size;
int uid, gid;
unsigned short mode;
#endif
} Info;
typedef union _any Any;
extern Info NullInfo;
#define MAX_ARGV 256 /* Максимальное число имен в каталоге */
typedef struct { /* Содержимое каталога name */
time_t lastRead; /* время последнего чтения каталога */
Info *files; /* содержимое каталога */
char *name; /* имя каталога */
ino_t ino; dev_t dev; /* I-узел и устройство */