(sv).c /* _______________________ fajl glob.c __________________________ */ #include "glob.h" int in_the_root = NO; /* chitaem kornevoj katalog ? */ Sort sorttype = SORT_SUFX; /* sortirovka imen po suffiksu */ Info NullInfo = { NULL, 0 }; /* i prochie polya = 0 (esli est') */ char *strdup(const char *s){ char *p = malloc(strlen(s)+1); if(p)strcpy(p, s); return p; } /* Soderzhitsya li lyuboj iz simvolov v stroke ? */ int any(register char *s, register char *p){ while( *s ){ if( strchr(p, *s)) return YES; s++; } return NO; } /* Najti poslednyuyu tochku v imeni */ static char *lastpoint (char *s) { register char *last; static char no[] = ""; if((last = strchr(s, '.')) == NULL) return no; /* esli imya nachinaetsya s tochki - ne schitat' ee */ return( last == s ? no : last ); } /* Sravnenie strok s uchetom ih suffiksov */ int strsfxcmp (register char *s1, register char *s2){ char *p1, *p2, c1, c2; int code; p1 = lastpoint (s1); p2 = lastpoint (s2); if (code = strcmp (p1, p2)) return code; /* suffiksy raznye */ /* inache: suffiksy ravny. Sortiruem po golovam */ c1 = *p1; c2 = *p2; *p1 = '\0'; *p2 = '\0'; /* vremenno */ code = strcmp (s1, s2); *p1 = c1; *p2 = c2; return code; } /* Funkciya sortirovki */ int gcmps(const void *p1, const void *p2){ Info *s1 = (Info *) p1, *s2 = (Info *) p2; switch( sorttype ){ default: case SORT_ASC: return strcmp(s1->s, s2->s); case SORT_DESC: return -strcmp(s1->s, s2->s); case SORT_SUFX: return strsfxcmp(s1->s, s2->s); case SORT_NOSORT: return (-1); #ifdef FILF case SORT_SIZE: return (s1->size < s2->size ? -1 : s1->size == s2->size ? 0 : 1 ); #endif } } /* Kopirovanie bloka */ Info *blkcpy(Info *v){ register i, len; Info *vect = (Info *) malloc(((len=blklen(v)) + 1) * sizeof(Info)); for(i=0; i < len; i++ ) vect[i] = v[i]; vect[len] = NullInfo; return vect; } /* Izmerenie dliny bloka */ int blklen(Info *v){ int i = 0; while( v->s ) i++, v++; return i; } /* Ochistka bloka (unichtozhenie) */ void blkfree(Info *v){ Info *all = v; while( v->s ) free((char *) v->s ), v++; free((char *) all ); } /* Sravnenie dvuh blokov */ int blkcmp( register Info *p, register Info *q ){ while( p->s && q->s && !strcmp(p->s, q->s) && (p->fl & I_SYS) == (q->fl & I_SYS)){ p++; q++; } if( p->s == NULL && q->s == NULL ) return 0; /* sovpadayut */ return 1; /* razlichayutsya */ } char globchars [] = "*?["; Info gargv[MAX_ARGV]; int gargc; static short readErrors; void greset() { gargc = 0; readErrors = 0; } /* Rasshirit' shablon imen fajlov v sami imena */ static void globone(char *pattern, char dirname[]){ extern char *strdup(); struct stat st; DIR *dirf; struct dirent *d; if( any(pattern, globchars) == NO ){ /* no glob */ gargv[gargc] = NullInfo; gargv[gargc].s = strdup(pattern); gargc++; gargv[gargc] = NullInfo; return; } if((dirf = opendir(dirname)) == NULL){ readErrors++; goto out; } while(d = readdir(dirf)){ if(match(d->d_name, pattern)){ char fullname[512]; if( sorttype != SORT_NOSORT && !strcmp(d->d_name, ".")) continue; /* V kornevom kataloge imya ".." sleduet propuskat' */ if( in_the_root && !strcmp(d->d_name, "..")) continue; /* Proverka na perepolnenie */ if( gargc == MAX_ARGV - 1){ free(gargv[gargc-1].s); gargv[gargc-1].s = strdup(" Slishkom mnogo fajlov!!!"); gargv[gargc-1].fl = I_SYS; break; } gargv[gargc] = NullInfo; gargv[gargc].s = strdup(d->d_name); sprintf(fullname, "%s/%s", dirname, d->d_name); if(stat(fullname, &st) < 0) gargv[gargc].fl |= I_NOSEL; else if(isdir(st)) gargv[gargc].fl |= I_DIR; else if(isexe(st)) gargv[gargc].fl |= I_EXE; #ifdef FILF gargv[gargc].size = st.st_size; gargv[gargc].uid = st.st_uid; gargv[gargc].gid = st.st_gid; gargv[gargc].mode = st.st_mode; #endif gargc++; } } closedir(dirf); out: gargv[ gargc ] = NullInfo; } /* Rasshirit' neskol'ko shablonov */ Info *glob(char **patvec, char *dirname){ greset(); while(*patvec){ globone(*patvec, dirname); patvec++; } qsort(gargv, gargc, sizeof(Info), gcmps); return blkcpy(gargv); } Info *glb(char *pattern, char *dirname){ char *pv[2]; pv[0] = pattern; pv[1] = NULL; return glob(pv, dirname); } /* Prochest' soderzhimoe kataloga, esli ono izmenilos': * Vernut': 0 - katalog ne menyalsya; * 1 - izmenilsya; * 1000 - izmenilsya rabochij katalog (chdir); * -1 - katalog ne sushchestvuet; */ int ReadDir(char *dirname, DirContents *d){ struct stat st; Info *newFiles; int save = YES; /* sohranyat' metki u fajlov ? */ int dirchanged = NO; /* sdelan chdir() ? */ /* katalog mog byt' udalen, a my ob etom ne izveshcheny */ if( stat(dirname, &st) < 0 ){ d->valid = NO; d->lastRead = 0L; if(d->files) blkfree(d->files); d->files = blkcpy( &NullInfo ); return (-1); /* ne sushchestvuet */ } else d->valid = YES; /* ne izmenilsya li adres kataloga, hranimogo v *d ? */ if(d->ino != st.st_ino || d->dev != st.st_dev){ /* izmenilsya */ d->ino = st.st_ino; d->dev = st.st_dev; save = NO; d->lastRead = 0L; dirchanged = YES; } /* ne izmenilos' li imya kataloga ? */ if( !d->name || strcmp(d->name, dirname)){ if(d->name) free(d->name); d->name = strdup(dirname); /* save=NO; d->lastRead = 0; */ } /* proverim, byl li modificirovan katalog ? */ if( save==YES && d->files && st.st_mtime == d->lastRead ) return 0; /* soderzhimoe kataloga ne menyalos' */ d->lastRead = st.st_mtime; newFiles = glb("*", d->name); /* prochest' soderzhimoe kataloga */ if(save == YES && d->files){ register Info *p, *q; if( !blkcmp(newFiles, d->files)){ blkfree(newFiles); return 0; /* ne izmenilos' */ } /* inache sohranit' pometki */ for(p= d->files; p->s; p++) for(q= newFiles; q->s; ++q) if( !strcmp(p->s, q->s)){ q->fl |= p->fl & ~I_SYS; break; } } if(d->files) blkfree(d->files); d->files = newFiles; d->readErrors = readErrors; return 1 + (dirchanged ? 999:0); /* katalog izmenilsya */ } /* Primer 19 */ /* ________________________fajl menu.h __________________________ */ /* ROLLIRUEMOE MENYU */ /* _______________________________________________________________*/ #include <ctype.h> #include <sys/param.h> #define M_HOT '\\' /* goryachij klyuch */ #define M_CTRL '\1' /* priznak gorizontal'noj cherty */ #define MXEND(m) XEND((m)->win,(m)->scrollok) #define NOKEY (-33) /* goryachego klyucha net */ #define MAXLEN MAXPATHLEN /* maks. dlina imen fajlov */ typedef enum { /* Kody, vozvrashchaemye handler-om (HandlerReply *reply) */ HANDLER_OUT = 0, /* vyjti iz funkcii vybora */ HANDLER_CONTINUE = 1, /* chitat' ocherednuyu bukvu */ HANDLER_NEWCHAR = 2, /* pojti na analiz koda handler-om. */ HANDLER_SWITCH = 3, /* pojti na switch() */ HANDLER_AGAIN = 4 /* perezapustit' vsyu funkciyu vybora */ } HandlerReply; typedef struct _Menu { /* pasport menyu */ int nitems; /* chislo elementov menyu */ Info *items; /* sam massiv elementov */ int *hotkeys; /* "goryachie" klavishi */ int key; /* klavisha, zavershivshaya vybor */ int current; /* tekushchaya stroka spiska */ int shift; /* sdvig okna ot nachala menyu */ int scrollok; /* okno rolliruemoe ? */ WINDOW *win; /* okno dlya menyu */ int left, top, height, width; /* koordinaty menyu na ekrane i razmer okna win */ int textwidth, textheight; /* razmer podokna vybora */ int bg_attrib; /* atribut fona okna */ int sel_attrib; /* atribut vybrannoj stroki */ char *title; /* zagolovok menyu */ Point savep; void (*showMe) (struct _Menu *m); void (*scrollBar) (struct _Menu *m, int n, int among); int *hitkeys; /* klavishi, obrabatyvaemye osobo */ int (*handler) (struct _Menu *m, int c, HandlerReply *reply); } Menu; /* Struktura okna s menyu: *--------------* +0 | ZAGOLOVOK | +1 *-----------*--* +2 |+ str1aaa | | +3 | str2bbb |##| <- scroll bar shirinoj BARWIDTH | str3vvv | | *___________|__* |DX| len |DX|BS| */ /* Metki u elementov menyu */ #define M_BOLD I_DIR /* yarkaya stroka */ #define M_HATCH 0x08 /* stroka tusklaya */ #define M_LFT 0x10 /* dlya ispol'zovaniya v pulldown menu */ #define M_RGT 0x20 /* dlya ispol'zovaniya v pulldown menu */ #define M_LABEL 0x40 /* stroka imeet metku */ #define M_LEFT (-111) #define M_RIGHT (-112) #define TOTAL_NOSEL (-I_NOSEL) #define M_SET(m, i, flg) (((m)->items)[i]). fl |= (flg) #define M_CLR(m, i, flg) (((m)->items)[i]). fl &= ~(flg) #define M_TST(m, i, flg) ((((m)->items)[i]).fl & (flg)) #define M_ITEM(m, i) ((((m)->items)[i]).s) /* Prototipy */ int MnuInit (Menu *m); void MnuDeinit (Menu *m); void MnuDrawItem (Menu * m, int y, int reverse, int selection); int MnuNext (Menu *m); int MnuPrev (Menu *m); int MnuFirst(Menu *m); int MnuLast (Menu *m); int MnuPgUp (Menu *m); int MnuPgDn (Menu *m); int MnuThis (Menu *m); int MnuHot (Menu *m, unsigned c); int MnuName (Menu *m, char *name); void MnuDraw (Menu *m); void MnuHide(Menu *m); void MnuPointAt (Menu *m, int y); void MnuPoint (Menu *m, int line, int eraseOld); int MnuUsualSelect (Menu *m, int block); int is_in(register int c, register int s[]); char *MnuConvert (char *s, int *pos); #define M_REFUSED(m) ((m)->key < 0 || (m)->key == ESC ) #define MNU_DY 1 /* _______________________ fajl menu.c __________________________ */ #include "w.h" #include "glob.h" #include "menu.h" #include <signal.h> /* ---------------- implementation module ------------------------- */ /* Ne vhodit li simvol v special'nyj nabor? Massiv zavershaetsya (-1) */ int is_in(register int c, register int s[]){ while (*s >= 0) { if(*s == c) return YES; s++; } return NO; } char STRING_BUFFER[ MAXLEN ]; /* vremennyj bufer */ /* Snyat' pometku s "goryachej" klavishi. */ char *MnuConvert (char *s, int *pos){ int i = 0; *pos = (-1); while (*s) { if (*s == M_HOT) { *pos = i; s++; } else STRING_BUFFER[i++] = *s++; } STRING_BUFFER[i] = '\0'; return STRING_BUFFER; } /* Ramka vokrug okna s menyu */ static void MnuWin (Menu *m) { WinBorder(m->win, m->bg_attrib, m->sel_attrib, m->title, m->scrollok, YES); } /* Narisovat' scroll bar v nuzhnoj pozicii */ static void MnuWinBar (Menu *m) { WINDOW *w = m -> win; /* okno */ WinScrollBar(m->win, m->scrollok, m->current, m->nitems, m->title, m->bg_attrib); if(m->scrollBar) /* mozhet byt' eshche kakie-to nashi dejstviya */ m->scrollBar(m, m->current, m->nitems); } /* Rollirovanie menyu */ /* +---+----->+-MASSIV--+<-----+ | n|vsego |;;;;;;;;;| | shift sdvig do okna cur| | |;;;;;;;;;| | tekushchij| | =OKNO============<---------| element| | I ;;;;;;;;; I | y stroka okna 0..n-1 | | I ;;;;;;;;; I | | +------>I###:::::::::###I<--+ |h vysota okna | I ;;;;;;;;; I | | =================<---------+ | |;;;;;;;;;| +----->|_________| */ static void MnuRoll (Menu *ptr, int aid, /* kakoj novyj element vybrat' (0..n-1) */ int *cur, int *shift, int h, /* vysota okna (strok) */ int n, /* vysota items[] (elementov) */ void (*go) (Menu *p, int y, int eraseOld), void (*draw) (Menu *p), int DY ) { int y = *cur - *shift; /* tekushchaya stroka okna */ int newshift; /* novyj sdvig */ int AID_UP, AID_DN; if (aid < 0 || aid >= n) return; /* incorrect */ if (y < 0 || y >= h) return; /* incorrect */ AID_UP = MIN (DY, n); AID_DN = MAX (0, MIN (n, h - 1 - DY)); if (aid < *cur && y <= AID_UP && *shift > 0) goto scroll; /* down */ if (aid > *cur && y >= AID_DN && *shift + h < n) goto scroll; /* up */ if (*shift <= aid && aid < *shift + h) { /* rollirovat' ne nado, a prosto pojti v nuzhnuyu stroku okna */ (*go) (ptr, aid - *shift, YES); *cur = aid; /* eto nado izmenyat' POSLE (*go)() !!! */ return; } scroll: if (aid > *cur) newshift = aid - AID_DN; /* vverh up */ else if (aid < *cur) newshift = aid - AID_UP; /* vniz down */ else newshift = *shift; if (newshift + h > n) newshift = n - h; if (newshift < 0) newshift = 0; *shift = newshift; *cur = aid; (*draw) (ptr); /* pererisovat' okno */ (*go) (ptr, aid - newshift, NO); /* vstat' v nuzhnuyu stroku okna */ } /* Inicializaciya i razmetka menyu. Na vhode: m->items Massiv strok. m->title Zagolovok menyu. m->top Verhnyaya stroka okna (y). m->left Levyj kraj (x). m->handler Obrabotchik nazhatiya klavish ili NULL. m->hitkeys Special'nye klavishi [] ili NULL. m->bg_attrib Cvet fona okna. m->sel_attrib Cvet selekcii. */ int MnuInit (Menu *m) { int len, pos; char *s; register i; m -> current = m -> shift = 0; m -> scrollok = m -> key = 0; if (m -> hotkeys) { /* unichtozhit' starye "goryachie" klyuchi */ free ((char *) m -> hotkeys); m -> hotkeys = (int *) NULL; } /* podschet elementov menyu */ for (i = 0; M_ITEM (m, i) != (char *) NULL; i++); m -> nitems = i; /* otvesti massiv dlya "goryachih" klavish */ if (m -> hotkeys = (int *) malloc (sizeof (int) * m -> nitems)) { for (i = 0; i < m -> nitems; i++) m -> hotkeys[i] = NOKEY; } /* podschitat' shirinu teksta */ len = m -> title ? strlen (m -> title) : 0; for (i = 0; i < m -> nitems; i++) { if (*(s = M_ITEM (m, i)) == M_CTRL) continue; s = MnuConvert (s, &pos); if (m -> hotkeys && pos >= 0) m -> hotkeys[i] = isupper (s[pos]) ? tolower (s[pos]) : s[pos]; if ((pos = strlen (s)) > len) len = pos; } /* sformirovat' okno */ #define BORDERS_HEIGHT (2 + (m -> title ? 2 : 0)) #define BORDERS_WIDTH (2 + 2*DX + (m -> scrollok ? BARWIDTH + 1 : 0)) m -> height = m->nitems + BORDERS_HEIGHT; if (m -> height > LINES * 2 / 3) { /* slishkom vysokoe menyu */ m -> scrollok = BAR_VER; /* budet rollirovat'sya */ m -> height = LINES * 2 / 3; } if((m -> width = len + BORDERS_WIDTH) > COLS ) m->width = COLS; m -> textheight = m->height - BORDERS_HEIGHT; m -> textwidth = m->width - BORDERS_WIDTH; /* okno dolzhno lezhat' v predelah ekrana */ if( m->top + m->height > LINES ) m->top = LINES - m->height; if( m->left + m->width > COLS ) m->left = COLS - m->width; if( m->top < 0 ) m->top = 0; if( m->left < 0 ) m->left = 0; if( m->win ){ /* unichtozhit' staroe okno */ KillWin( m->win ); m->win = NULL; } if( m->win == NULL ){ /* sozdat' okno i narisovat' osnovu */ if((m->win = newwin(m->height, m->width, m->top, m->left)) == NULL) return 0; keypad(m->win, TRUE); MnuWin(m); MnuDraw(m); /* no okno poka ne vstavleno v spisok aktivnyh okon */ } return ( m->win != NULL ); } /* Deinicializirovat' menyu */ void MnuDeinit (Menu *m) { if( m->win ){ KillWin (m->win); m->win = NULL; } if( m->hotkeys ){ free ((char *) m -> hotkeys); m -> hotkeys = (int *) NULL; } } /* Spryatat' menyu */ void MnuHide (Menu *m){ if( m->win ) HideWin(m->win); } /* Zachistit' mesto dlya line-toj stroki okna menyu */ static void MnuBox (Menu *m, int line, int attr) { register WINDOW *w = m -> win; register i, xend = MXEND(m); wattrset (w, attr); for (i = 1; i < xend; i++) mvwaddch (w, line, i, ' '); /* likvidirovat' posledstviya M_CTRL-linii */ wattrset (w, m->bg_attrib); mvwaddch (w, line, 0, VER_LINE); mvwaddch (w, line, xend, VER_LINE); wattrset (w, m->bg_attrib); } /* Narisovat' stroku menyu v y-oj stroke okna vybora */ void MnuDrawItem (Menu *m, int y, int reverse, int selection) { register WINDOW *w = m -> win; int pos, l, attr; int ay = WY (m->title, y), ax = WX (0); char *s, c; int hatch, bold, label, cont = NO, under; if (y + m -> shift >= 0 && y + m -> shift < m -> nitems) { s = M_ITEM (m, y + m -> shift); hatch = M_TST (m, y + m -> shift, I_NOSEL) || M_TST (m, y + m -> shift, M_HATCH); bold = M_TST (m, y + m -> shift, M_BOLD); label = M_TST (m, y + m -> shift, M_LABEL); under = M_TST (m, y + m -> shift, I_EXE); } else { /* stroka vne dopustimogo diapazona */ s = "~"; label = hatch = bold = NO; } if (*s == M_CTRL) { /* narisovat' gorizontal'nuyu chertu */ int x, xend = MXEND(m); wattrset(w, m->bg_attrib); for(x=1; x < xend; x++) mvwaddch(w, ay, x, HOR_LINE); mvwaddch (w, ay, 0, LEFT_JOIN); mvwaddch (w, ay, xend, RIGHT_JOIN); wattrset (w, m->bg_attrib); return; } l = strlen(s = MnuConvert (s, &pos)); c = '\0'; if (l > m -> textwidth) { /* slishkom dlinnaya stroka */ c = s[m -> textwidth]; s[m -> textwidth] = '\0'; cont = YES; if (pos > m -> textwidth) pos = (-1); } if (selection) MnuBox (m, ay, reverse ? m->sel_attrib : m->bg_attrib); wattrset (w, attr = (bold ? A_BOLD : 0) | (hatch ? A_ITALICS : 0) | (under ? A_UNDERLINE : 0) | (reverse ? m->sel_attrib : m->bg_attrib)); mvwaddstr (w, ay, ax, s); if( cont ) mvwaddch(w, ay, ax+m->textwidth, RIGHT_TRIANG); /* Hot key letter */ if (pos >= 0) { wattron (w, bold ? A_ITALICS : A_BOLD); mvwaddch (w, ay, WX(pos), s[pos]); } if (label){ /* stroka pomechena */ wattrset (w, attr | A_BOLD); mvwaddch (w, ay, 1, LABEL); } if (under){ wattrset (w, A_BOLD); mvwaddch (w, ay, ax-1, BOX_HATCHED); } if (c) s[m->textwidth] = c; wattrset (w, m->bg_attrib); SetPoint (m->savep, ay, ax-1); /* kursor postavit' pered slovom */ } /* Vybor v menyu podhodyashchego elementa */ int MnuNext (Menu *m) { char *s; register y = m -> current; for (++y; y < m -> nitems; y++) if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL)) return y; return (-1); } int MnuPrev (Menu *m) { char *s; register y = m -> current; for (--y; y >= 0; --y) if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL)) return y; return (-1); } int MnuPgUp (Menu *m) { char *s; register n, y = m -> current; for (--y, n = 0; y >= 0; --y) { if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL)) n++; if (n == m -> textheight) return y; } return MnuFirst (m); } int MnuPgDn (Menu *m) { char *s; register n, y = m -> current; for (++y, n = 0; y < m -> nitems; y++) { if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL)) n++; if (n == m -> textheight) return y; } return MnuLast (m); } int MnuFirst (Menu *m) { char *s; register y; for (y = 0; y < m -> nitems; y++) if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL)) return y; return (-1); } int MnuLast (Menu *m) { char *s; register y; for (y = m -> nitems - 1; y >= 0; --y) if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL)) return y; return (-1); } int MnuThis (Menu *m) { char *s; if (m -> current < 0 || m -> current >= m -> nitems) return (-1); /* error */ if ((s = M_ITEM (m, m -> current)) && *s != M_CTRL && !M_TST (m, m -> current, I_NOSEL)) return m -> current; return (-1); } int MnuName (Menu *m, char *name) { char *s; register y; int pos; for(y = 0; y < m -> nitems; ++y) if ((s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL) && strcmp(name, MnuConvert(s, &pos)) == 0 ) return y; return (-1); } int MnuHot (Menu *m, unsigned c) { register y; char *s; if (m -> hotkeys == (int *) NULL) return (-1); if (c < 0400 && isupper (c)) c = tolower (c); for (y = 0; y < m -> nitems; y++) if (c == m -> hotkeys[y] && (s = M_ITEM (m, y)) && *s != M_CTRL && !M_TST (m, y, I_NOSEL)) return y; return (-1); } /* Narisovat' soderzhimoe menyu dlya vybora */ void MnuDraw (Menu *m) { register i, j; for (i = 0; i < m -> textheight; i++) MnuDrawItem (m, i, NO, m -> scrollok ? YES : NO); } /* Postavit' kursor v line-tuyu stroku okna. */ void MnuPoint(Menu *m, int line, int eraseOld /* stirat' staruyu selekciyu? */){ int curline = m->current - m->shift; /* tekushchaya stroka okna */ if (line < 0 || line >= m -> textheight) return; /* oshibka */ if (eraseOld && curline != line) /* steret' staryj vybor */ MnuDrawItem (m, curline, NO, YES); MnuDrawItem (m, line, YES, YES); /* podsvetit' novuyu stroku */ } /* Perejti k y-toj stroke massiva elementov, izmenit' kartinku */ void MnuPointAt (Menu *m, int y) { char *s; if (y < 0 || y >= m->nitems) return; /* oshibka! */ if ((s = M_ITEM (m, y)) == NULL || *s == M_CTRL) return; MnuRoll (m, y, &m -> current, &m -> shift, m -> textheight, m -> nitems, MnuPoint, MnuDraw, MNU_DY); if (m -> scrollok) MnuWinBar(m); /* sdvinut' scroll bar */ GetBack(m->savep, m->win); /* vernut' kursor v nachalo stroki selekcii, * otkuda on byl sbit MnuWinBar-om */ } /* Vybor v menyu bez uchastiya "myshi". */ int MnuUsualSelect (Menu *m, int block) { int sel, snew, c, done = 0; m -> key = (-1); if( ! m->win ) return TOTAL_NOSEL; if((sel = MnuThis (m)) < 0) if((sel = MnuFirst (m)) < 0) return TOTAL_NOSEL; /* v menyu nel'zya nichego vybrat' */ RaiseWin (m->win); /* sdelat' okno verhnim */ MnuPointAt (m, sel); /* proyavit' */ if(m->showMe) m->showMe(m); /* mozhet byt' izmenit' poziciyu ? */ for (;;) { c = WinGetch (m->win); INP: if (m -> hitkeys && m -> handler) { HandlerReply reply; if (is_in (c, m -> hitkeys)) { c = (*m -> handler) (m, c, &reply); /* vosstanovit' scroll bar */ MnuPointAt (m, m -> current); switch (reply) { case HANDLER_CONTINUE: continue; case HANDLER_NEWCHAR: goto INP; case HANDLER_OUT: goto out; case HANDLER_SWITCH: default: break; /* goto switch(c) */ } } } switch (c) { case KEY_UP: if ((snew = MnuPrev (m)) < 0) break; goto mv; case KEY_DOWN: next: if ((snew = MnuNext (m)) < 0) break; goto mv; case KEY_HOME: if ((snew = MnuFirst (m)) < 0) break; goto mv; case KEY_END: if ((snew = MnuLast (m)) < 0) break; goto mv; case KEY_NPAGE: if ((snew = MnuPgDn (m)) < 0) break; goto mv; case KEY_PPAGE: if ((snew = MnuPgUp (m)) < 0) break; goto mv; case KEY_IC: /* postavit'/snyat' pometku */ if (M_TST (m, sel, M_LABEL)) M_CLR (m, sel, M_LABEL); else M_SET (m, sel, M_LABEL); MnuPointAt (m, sel); /* Esli vy vycherknete goto next; * i ostavite prosto break; * to vstav'te v eto mesto * MnuPoint( m, m->current - m->shift, NO ); */ goto next; case KEY_DC: if (M_TST (m, sel, M_HATCH)) M_CLR (m, sel, M_HATCH); else M_SET (m, sel, M_HATCH); MnuPointAt (m, sel); goto next; case KEY_LEFT: if (block & M_LFT) { sel = M_LEFT; goto out; } break; case KEY_RIGHT: if (block & M_RGT) { sel = M_RIGHT; goto out; } break; case 0: break; default: if (c == '\n' || c == '\r' || c == ESC) goto out; if ((snew = MnuHot (m, c)) < 0) { beep(); break; } /* inache najden HOT KEY (goryachaya klavisha) */ done++; goto mv; } continue; mv: MnuPointAt (m, sel = snew); if(done){ wrefresh(m->win); /* proyavit' novuyu poziciyu */ break; } } out: wnoutrefresh(m->win); return((m->key = c) == ESC ? -1 : sel); /* Menyu avtomaticheski NE ISCHEZAET: esli nado - * yavno delajte MnuHide(m); posle MnuUsualSelect(); */ } /* Primer 20 */ /* ______________________________________________________________ */ /* PULL_DOWN menyu (menyu-stroka) */ /* _______________________ fajl pull.h __________________________ */ typedef struct { Info info; /* stroka v menyu */ Menu *menu; /* svyazannoe s nej vertikal'noe menyu */ char *note; /* podskazka */ } PullInfo; typedef struct _Pull { /* Pasport menyu */ int nitems; /* kolichestvo elementov v menyu */ PullInfo *items;/* elementy menyu */ int *hotkeys; /* goryachie klyuchi */ int key; /* klavisha, zavershivshaya vybor */ int current; /* vybrannyj element */ int space; /* interval mezhdu elementami menyu */ int bg_attrib; /* cvet fona stroki */ int sel_attrib; /* cvet vybrannogo elementa */ Point savep; void (*scrollBar) (struct _Pull *m, int n, int among); } PullMenu; #define PYBEG 0 /* stroka, v kotoroj razmeshchaetsya menyu */ #define PM_BOLD I_DIR #define PM_NOSEL I_NOSEL #define PM_LFT M_LFT #define PM_RGT M_RGT #define PM_SET(m, i, flg) (m)->items[i].info.fl |= (flg) #define PM_CLR(m, i, flg) (m)->items[i].info.fl &= ~(flg) #define PM_TST(m, i, flg) ((m)->items[i].info.fl & (flg)) #define PM_ITEM(m, i) ((m)->items[i].info.s) #define PM_MENU(m, i) ((m)->items[i].menu) #define PM_NOTE(m, i) ((m)->items[i].note) #define COORD(m, i) ((m)->space * (i+1) + PullSum(m, i)) int PullInit(PullMenu *m); int PullSum(PullMenu *m, int n); void PullDraw(PullMenu *m); int PullShow(PullMenu *m); void PullHide(PullMenu *m); void PullDrawItem(PullMenu *m, int i, int reverse, int selection); void PullPointAt(PullMenu *m, int y); int PullHot(PullMenu *m, unsigned c); int PullPrev(PullMenu *m); int PullNext(PullMenu *m); int PullFirst(PullMenu *m); int PullThis(PullMenu *m); int PullUsualSelect(PullMenu *m); #define PullWin stdscr #define PM_REFUSED(m) ((m)->key < 0 || (m)->key == ESC ) /* _______________________ fajl pull.c __________________________ */ #include "glob.h" #include "w.h" #include "menu.h" #include "pull.h" int PullSum(PullMenu *m, int n){ register i, total; int pos; for(i=0, total = 0; i < n; i++ ) total += strlen( MnuConvert(PM_ITEM(m, i), &pos )); return total; } /* Razmetka menyu. Na vhode: p->items massiv elementov s M_HOT-metkami i svyazannyh menyu. p->bg_attrib cvet fona stroki. p->sel_attrib cvet vybrannogo elementa. Menyu vsegda razmeshchaetsya v okne stdscr (PullWin). */ int PullInit(PullMenu *m){ /* podmenyu ne dolzhny byt' inicializirovany, * t.k. vse ravno budut sdvinuty v drugoe mesto */ int total, pos; char *s; register i; m->key = m->current = 0; if(m->hotkeys){ free((char *) m->hotkeys); m->hotkeys = (int *) NULL; } /* podschitat' elementy menyu */ m->nitems = 0; for( i=0, total = 0; PM_ITEM(m, i) != NULL; i++ ){ total += strlen(s = MnuConvert(PM_ITEM(m, i), &pos)); m->nitems++; } if( total > wcols(PullWin)){ /* menyu slishkom shirokoe */ err: beep(); return 0; } m->space = (wcols(PullWin) - total - 2) / (m->nitems + 1); if( m->space <= 0 ) goto err; /* razmetit' goryachie klavishi */ if( m-> hotkeys = (int *) malloc( sizeof(int) * m->nitems )){ for(i=0; i < m->nitems; i++ ) m->hotkeys[i] = NOKEY; } for( i=0; i < m->nitems; i++ ){ if( PM_MENU(m,i)){ PM_MENU(m,i)->left = COORD(m, i) - 1; PM_MENU(m,i)->top = PYBEG + 1; PM_MENU(m,i)->bg_attrib = m-> bg_attrib; PM_MENU(m,i)->sel_attrib = m-> sel_attrib; if( PM_MENU(m,i)->win ) MnuDeinit( PM_MENU(m,i)); MnuInit( PM_MENU(m,i)); } if( m->hotkeys ){ s = MnuConvert(PM_ITEM(m, i), &pos); if( pos >= 0 ) m->hotkeys[i] = isupper(s[pos]) ? tolower(s[pos]) : s[pos]; } } keypad(PullWin, TRUE); return 1; } /* Proyavit' pull-down menyu */ int PullShow(PullMenu *m){ register i; int first, last; first = last = (-1); for(i=0; i < m->nitems; i++ ){ PM_SET(m, i, PM_LFT | PM_RGT ); if( !PM_TST(m, i, PM_NOSEL)){ if( first < 0 ) first = i; last = i; } } if( first < 0 ) return (TOTAL_NOSEL); if(first == last ){ PM_CLR(m, first, PM_LFT | PM_RGT ); }else{ PM_CLR(m, first, PM_LFT); PM_CLR(m, last, PM_RGT); } wmove(PullWin, PYBEG, 0); wattrset(PullWin, m->bg_attrib); wclrtoeol(PullWin); PullDraw(m); return 1; } void PullDraw(PullMenu *m){ register i; for(i=0; i < m->nitems; i++ ) PullDrawItem(m, i, NO, NO); } /* Spryatat' pull-down menyu. Sama stroka ostaetsya, podmenyu ischezayut */ void PullHide(PullMenu *m){ register i; for(i=0; i < m->nitems; i++ ) if( PM_MENU(m, i)) MnuHide( PM_MENU(m, i)); PullDraw(m); } /* Narisovat' element menyu */ void PullDrawItem(PullMenu *m, int i, int reverse, int selection){ int x, pos, hatch = PM_TST(m, i, PM_NOSEL ); char *s; x = COORD(m, i); s = MnuConvert( PM_ITEM(m, i), &pos ); wattrset(PullWin, (reverse ? m->sel_attrib : m->bg_attrib) | (hatch ? A_ITALICS : 0 )); /*mvwaddch(PullWin, PYBEG, x-1, reverse ? LEFT_TRIANG : ' ');*/ mvwaddstr(PullWin, PYBEG, x, s); /*waddch(PullWin, reverse ? RIGHT_TRIANG : ' ');*/ if( pos >= 0 ){ /* Hot key letter */ wattron(PullWin, A_BOLD); mvwaddch(PullWin, PYBEG, x + pos, s[pos]); } wmove (PullWin, PYBEG, x-1); SetPoint(m->savep, PYBEG, x-1); wattrset(PullWin, m->bg_attrib); } int PullPrev(PullMenu *m){ register y; for( y = m->current - 1; y >= 0; y-- ) if( !PM_TST(m, y, PM_NOSEL )) return y; return (-1); } int PullNext(PullMenu *m){ register y; for( y = m->current+1; y < m->nitems; y++ ) if( !PM_TST(m, y, PM_NOSEL)) return y; return (-1); } int PullFirst(PullMenu *m){ register y; for( y = 0; y < m->nitems; y++ ) if( !PM_TST(m, y, PM_NOSEL)) return y; return (-1); } int PullThis(PullMenu *m){ register y; if( m->current < 0 || m->current >= m->nitems ) return (-1); if( PM_TST(m, m->current, PM_NOSEL)) return (-1); return m->current; } int PullHot(PullMenu *m, unsigned c){ register y; if( m-> hotkeys == (int *) NULL ) return (-1); if( c < 0400 && isupper(c)) c = tolower(c); for( y=0; y < m->nitems; y++ ) if( c == m->hotkeys[y] && !PM_TST(m, y, PM_NOSEL)) return y; return (-1); } /* Ukazat' na element n */ void PullPointAt( PullMenu *m, int n){ if( n < 0 || n >= m->nitems ) return ; /* error */ if( n != m->current ){ if( PM_MENU(m, m->current)) MnuHide( PM_MENU(m, m->current)); PullDrawItem( m, m->current, NO, YES ); } m -> current = n; PullDrawItem( m, n, YES, YES ); if( m->scrollBar ){ m->scrollBar( m, n, m->nitems ); GetBack(m->savep, PullWin); } } /* Vybor v menyu */ int PullUsualSelect(PullMenu *m){ int autogo = NO, c, code, done = 0, snew, sel, reply = (-1); m->key = (-1); if((sel = PullThis(m)) < 0 ) if((sel = PullFirst(m)) < 0 ) return TOTAL_NOSEL; if( PullShow(m) < 0 ) return TOTAL_NOSEL; PullPointAt(m, sel); /* nachal'naya poziciya */ for(;;){ if( autogo ){ /* Avtomaticheskaya proyavka podmenyu */ if( PM_MENU(m, m->current) == NULL) goto ask; code = MnuUsualSelect(PM_MENU(m, m->current), PM_TST(m, m->current, PM_LFT) | PM_TST(m, m->current, PM_RGT)); MnuHide(PM_MENU(m, m->current)); c = PM_MENU(m, m->current)->key; if(code == (-1)){ reply = (-1); goto out; } /* v podmenyu nichego nel'zya vybrat' */ if( code == TOTAL_NOSEL) goto ask; /* MnuUsualSelect vydaet special'nye kody dlya * sdvigov vlevo i vpravo */ if( code == M_LEFT ) goto left; if( code == M_RIGHT ) goto right; reply = code; goto out; } else ask: c = WinGetch(PullWin); switch(c){ case KEY_LEFT: left: if((snew = PullPrev(m)) < 0 ) goto ask; goto mv; case KEY_RIGHT: right: if((snew = PullNext(m)) < 0 ) goto ask; goto mv; case ESC: reply = (-1); goto out; case '\r': case '\n': if( PM_MENU(m, m->current) == NULL){ reply = 0; goto out; } autogo = YES; break; default: if((snew = PullHot(m, c)) < 0 ) break; if( PM_MENU(m, snew) == NULL){ reply=0; done++; } autogo = YES; goto mv; } continue; mv: PullPointAt(m, sel = snew); if( done ) break; } out: wnoutrefresh(PullWin); PullHide(m); m->key = c; wattrset(PullWin, A_NORMAL); /* NOT bg_attrib */ return reply; /* nomer elementa, vybrannogo v menyu PM_MENU(m, m->current) */ } /* Primer 21 */ /* REDAKTOR STROKI I ISTORIYA REDAKTIRUEMYH STROK */ /* _______________________ fajl hist.h __________________________ */ /* ISTORIYA. ZAPOMINANIE STROK I VYDACHA IH NAZAD PO TREBOVANIYU. */ /* ______________________________________________________________ */ typedef struct { /* Pasport istorii */ Info *list; /* zapomnennye stroki */ int sz; /* razmer istorii (maks.) */ int len; /* tekushchee chislo strok */ Menu mnu; /* menyu dlya vyborki iz istorii */ } Hist; void HistInit(Hist *h, int n); void HistAdd (Hist *h, char *s, int fl); Info *HistSelect(Hist *h, int x, int y); /* _______________________ fajl hist.c __________________________ */ #include "w.h" #include "glob.h" #include "menu.h" #include "hist.h" /* Proinicializirovat' novuyu "istoriyu" emkost'yu n strok */ void HistInit(Hist *h, int n){ register i; if( h->list ){ blkfree( h->list ); h->list = NULL; } h->len = 0; h->mnu.title = "History"; h->mnu.bg_attrib = A_NORMAL; h->mnu.sel_attrib = A_REVERSE; h->list = (Info *) malloc( (n+1) * sizeof(Info)); if( ! h->list ){ h->sz = 0; return; }else h->sz = n; for( i=0; i < n+1 ; i++ ) h->list[i] = NullInfo; } /* Dobavit' stroku s s metkoj fl v istoriyu */ void HistAdd (Hist *h, char *s, int fl){ register i, j; Info tmp; if( h->sz == 0 ) return; /* A net li uzhe takoj stroki ? */ for( i=0; i < h->len; i++ ) if( !strcmp(s, h->list[i].s )){ /* est' ! */ if( i == 0 ) return; /* pervaya */ /* sdelat' ee pervoj strokoj */ tmp = h->list[i]; for( j=i-1; j >= 0; --j ) h->list[j+1] = h->list[j]; h->list[0] = tmp; return; } if( h->len < h->sz ){ for( i=h->len-1; i>= 0; i-- ) h->list[i+1] = h->list[i]; h->len ++ ; }else{ /* vykinut' samuyu staruyu stroku iz istorii */ free( h->list[ h->sz - 1 ].s ); for( i=h->sz - 2; i >= 0; i-- ) h->list[i+1] = h->list[i]; } (h->list)[0].s = strdup(s); (h->list)[0].fl = fl; } /* Vyborka stroki iz istorii */ Info *HistSelect(Hist *h, int x, int y){ if( h->len == 0 ) return (Info *) NULL; h->mnu.top = y; h->mnu.left = x; h->mnu.items = h->list; MnuInit( & h->mnu ); if( h->mnu.hotkeys ){ register i; for(i=0 ; i < h->mnu.nitems; i++ ) h->mnu.hotkeys[i] = h->list[i].s[0] & 0377; } MnuUsualSelect( & h->mnu, 0 ); MnuDeinit ( & h->mnu ); if( M_REFUSED ( & h->mnu )) return (Info *) NULL; return & h->list[ h->mnu.current ]; } /* _______________________ fajl line.h __________________________ */ /* REDAKTOR DLINNYH STROK (VOZMOZHNO SHIRE |KRANA) */ /* ______________________________________________________________ */ typedef struct _LineEdit { /* Pasport redaktora stroki */ WINDOW *win; /* okno dlya redaktirovaniya */ int width; /* shirina polya redaktirovaniya */ int left, top; /* koordinaty polya redaktirovaniya v okne */ int pos; /* poziciya v stroke */ int shift; /* chislo simvolov skrytyh levee polya */ char *line; /* stroka kotoraya redaktiruetsya */ int maxlen; /* maksimal'naya dlina stroki */ int len; /* tekushchaya dlina stroki */ int insert; /* 1 - rezhim vstavki; 0 - zameny */ int nc; /* 1 - stirat' stroku po pervomu nazhatiyu */ int cursorOn; /* kursor vklyuchen (dlya grafiki) */ int bg_attrib; /* cvet teksta */ int fr_attrib; /* cvet pustogo mesta v pole */ int wl_attrib; /* cvet kraev stroki */ int sel_attrib; /* cvet simvola pod kursorom */ Hist *histIn; /* istoriya dlya vyborki strok */ Hist *histOut; /* istoriya dlya zapominaniya strok */ int key; /* knopka, zavershivshaya redaktirovanie */ Point savep; /* funkcii proyavki i ubiraniya okna (esli nado) */ int (*showMe)(struct _LineEdit *le); /* 1 pri uspehe */ void (*hideMe)(struct _LineEdit *le); void (*posMe) (struct _LineEdit *le); /* ustanovka pozicii */ /* Funkciya risovaniya scroll bar-a (esli nado) */ void (*scrollBar)(struct _LineEdit *le, int whichbar, int n, int among); /* Special'naya obrabotka klavish (esli nado) */ int *hitkeys; int (*handler)(struct _LineEdit *le, int c, HandlerReply *reply); } LineEdit; void LePutChar( LineEdit *le, int at); void LeCursorHide( LineEdit *le ); void LeCursorShow( LineEdit *le ); void LePointAt( LineEdit *le, int at ); void LePoint( LineEdit *le, int x, int eraseOld ); void LeDraw( LineEdit *le ); void LeReport( LineEdit *le ); void LeDelCh ( LineEdit *le ); void LeInsCh ( LineEdit *le, int c ); void LeRepCh ( LineEdit *le, int c ); int LeInsStr( LineEdit *le, char *s); int LeWerase( LineEdit *le, char *to ); int LeEdit( LineEdit *le ); #define LINE_DX 1 #define LE_REFUSED(m) ((m)->key < 0 || (m)->key == ESC ) /* _______________________ fajl line.c __________________________ */ /* Redaktor stroki. |ta versiya byla iznachal'no napisana * * dlya grafiki, poetomu zdes' ne sovsem CURSES-nye algoritmy */ #include "w.h" #include "glob.h" #include "menu.h" #include "hist.h" #include "line.h" /* Udalit' bukvu iz stroki */ static char cdelete(register char *s, int at) { char c; s += at; if((c = *s) == '\0') return c; while( s[0] = s[1] ) s++; return c; } /* Vstavit' bukvu v stroku */ static void insert(char *s, int at, int c){ register char *p; s += at; p = s; while(*p) p++; /* najti konec stroki */ p[1] = '\0'; /* zakryt' stroku */ for( ; p != s; p-- ) p[0] = p[-1]; *s = c; } /* Narisovat' vidimuyu chast' stroki s pozicii from */ static void LeDrawLine( LineEdit *le, int from ){ LeCursorHide( le ); for( ; from < le->width; from++ ) LePutChar(le, from); /* kursor ostaetsya spryatannym */ } /* Vydat' simvol stroki v pozicii at */ void LePutChar( LineEdit *le, int at){ int off = le->shift + at; int bgcolor = le->bg_attrib, wall; wall = /* simvol na krayu polya i stroka vyhodit za etot kraj ? */ ( at == 0 && le->shift || ( at >= le->width - 1 && le->shift + le->width < le->len )); bgcolor = ( off < le->len ) ? le->bg_attrib : ( at >= le->width || off >= le->maxlen ) ? (le->bg_attrib | A_ITALICS): /* chistoe mesto v pole */ le->fr_attrib ; wattrset( le->win, wall? le->wl_attrib|A_BOLD|A_ITALICS: bgcolor); mvwaddch( le->win, le->top, le->left + at, off < le->len ? le->line[off] : ' ' ); wattrset( le->win, le->bg_attrib); } /* Spryatat' kursor. x v intervale 0..le->width */ void LeCursorHide( LineEdit *le ){ int x = le->pos - le->shift; if( x < 0 || x > le->width || le->cursorOn == NO ) return; LePutChar( le, x ); le->cursorOn = NO; } /* Proyavit' kursor */ void LeCursorShow( LineEdit *le ){ int x = le->pos - le->shift, saveattr = le->bg_attrib; if( x < 0 || x > le->width || le->cursorOn == YES ) return; le->bg_attrib = le->sel_attrib | (le->insert==NO ? A_BOLD : 0); LePutChar(le, x); le->bg_attrib = saveattr; wmove(le->win, le->top, le->left + x); le->cursorOn = YES; SetPoint(le->savep, le->top, le->left+x); } /* Funkciya prokrutki dlinnoj stroki cherez okoshko */ static void LeRoll( LineEdit *ptr, int aid, int *cur, int *shift, int width, /* shirina okna */ int len, int maxlen, void (*go) (LineEdit *p, int x, int eraseOld), void (*draw)(LineEdit *p), /* pererisovshchik polya */ int LDX ){ int x = *cur - *shift, oldshift = *shift, newshift = oldshift; int AID_LFT, AID_RGT, drawn = NO; if( aid < 0 || aid > len )