(sv).c /* _______________________ glob.c __________________________ */ #include "glob.h" int in_the_root = NO; /* ? */ Sort sorttype = SORT_SUFX; /* */ Info NullInfo = { NULL, 0 }; /* = 0 ( ) */ char *strdup(const char *s){ char *p = malloc(strlen(s)+1); if(p)strcpy(p, s); return p; } /* ? */ int any(register char *s, register char *p){ while( *s ){ if( strchr(p, *s)) return YES; s++; } return NO; } /* */ static char *lastpoint (char *s) { register char *last; static char no[] = ""; if((last = strchr(s, '.')) == NULL) return no; /* - */ return( last == s ? no : last ); } /* */ 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; /* */ /* : . */ c1 = *p1; c2 = *p2; *p1 = '\0'; *p2 = '\0'; /* */ code = strcmp (s1, s2); *p1 = c1; *p2 = c2; return code; } /* */ 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 } } /* */ 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; } /* */ int blklen(Info *v){ int i = 0; while( v->s ) i++, v++; return i; } /* () */ void blkfree(Info *v){ Info *all = v; while( v->s ) free((char *) v->s ), v++; free((char *) all ); } /* */ 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; /* */ return 1; /* */ } char globchars [] = "*?["; Info gargv[MAX_ARGV]; int gargc; static short readErrors; void greset() { gargc = 0; readErrors = 0; } /* */ 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; /* ".." */ if( in_the_root && !strcmp(d->d_name, "..")) continue; /* */ if( gargc == MAX_ARGV - 1){ free(gargv[gargc-1].s); gargv[gargc-1].s = strdup(" !!!"); 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; } /* */ 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); } /* , : * : 0 - ; * 1 - ; * 1000 - (chdir); * -1 - ; */ int ReadDir(char *dirname, DirContents *d){ struct stat st; Info *newFiles; int save = YES; /* ? */ int dirchanged = NO; /* chdir() ? */ /* , */ if( stat(dirname, &st) < 0 ){ d->valid = NO; d->lastRead = 0L; if(d->files) blkfree(d->files); d->files = blkcpy( &NullInfo ); return (-1); /* */ } else d->valid = YES; /* , *d ? */ if(d->ino != st.st_ino || d->dev != st.st_dev){ /* */ d->ino = st.st_ino; d->dev = st.st_dev; save = NO; d->lastRead = 0L; dirchanged = YES; } /* ? */ if( !d->name || strcmp(d->name, dirname)){ if(d->name) free(d->name); d->name = strdup(dirname); /* save=NO; d->lastRead = 0; */ } /* , ? */ if( save==YES && d->files && st.st_mtime == d->lastRead ) return 0; /* */ d->lastRead = st.st_mtime; newFiles = glb("*", d->name); /* */ if(save == YES && d->files){ register Info *p, *q; if( !blkcmp(newFiles, d->files)){ blkfree(newFiles); return 0; /* */ } /* */ 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); /* */ } /* 19 */ /* ________________________ menu.h __________________________ */ /* */ /* _______________________________________________________________*/ #include <ctype.h> #include <sys/param.h> #define M_HOT '\\' /* */ #define M_CTRL '\1' /* */ #define MXEND(m) XEND((m)->win,(m)->scrollok) #define NOKEY (-33) /* */ #define MAXLEN MAXPATHLEN /* . */ typedef enum { /* , handler- (HandlerReply *reply) */ HANDLER_OUT = 0, /* */ HANDLER_CONTINUE = 1, /* */ HANDLER_NEWCHAR = 2, /* handler-. */ HANDLER_SWITCH = 3, /* switch() */ HANDLER_AGAIN = 4 /* */ } HandlerReply; typedef struct _Menu { /* */ int nitems; /* */ Info *items; /* */ int *hotkeys; /* "" */ int key; /* , */ int current; /* */ int shift; /* */ int scrollok; /* ? */ WINDOW *win; /* */ int left, top, height, width; /* win */ int textwidth, textheight; /* */ int bg_attrib; /* */ int sel_attrib; /* */ char *title; /* */ Point savep; void (*showMe) (struct _Menu *m); void (*scrollBar) (struct _Menu *m, int n, int among); int *hitkeys; /* , */ int (*handler) (struct _Menu *m, int c, HandlerReply *reply); } Menu; /* : *--------------* +0 | | +1 *-----------*--* +2 |+ 1 | | +3 | 2 |##| <- scroll bar BARWIDTH | 3 | | *___________|__* |DX| len |DX|BS| */ /* */ #define M_BOLD I_DIR /* */ #define M_HATCH 0x08 /* */ #define M_LFT 0x10 /* pulldown menu */ #define M_RGT 0x20 /* pulldown menu */ #define M_LABEL 0x40 /* */ #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) /* */ 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 /* _______________________ menu.c __________________________ */ #include "w.h" #include "glob.h" #include "menu.h" #include <signal.h> /* ---------------- implementation module ------------------------- */ /* ? (-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 ]; /* */ /* "" . */ 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; } /* */ static void MnuWin (Menu *m) { WinBorder(m->win, m->bg_attrib, m->sel_attrib, m->title, m->scrollok, YES); } /* scroll bar */ static void MnuWinBar (Menu *m) { WINDOW *w = m -> win; /* */ WinScrollBar(m->win, m->scrollok, m->current, m->nitems, m->title, m->bg_attrib); if(m->scrollBar) /* - */ m->scrollBar(m, m->current, m->nitems); } /* */ /* +---+----->+---+<-----+ | n| |;;;;;;;;;| | shift cur| | |;;;;;;;;;| | | | =============<---------| | | I ;;;;;;;;; I | y 0..n-1 | | I ;;;;;;;;; I | | +------>I###:::::::::###I<--+ |h | I ;;;;;;;;; I | | =================<---------+ | |;;;;;;;;;| +----->|_________| */ static void MnuRoll (Menu *ptr, int aid, /* (0..n-1) */ int *cur, int *shift, int h, /* () */ int n, /* items[] () */ void (*go) (Menu *p, int y, int eraseOld), void (*draw) (Menu *p), int DY ) { int y = *cur - *shift; /* */ int newshift; /* */ 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) { /* , */ (*go) (ptr, aid - *shift, YES); *cur = aid; /* (*go)() !!! */ return; } scroll: if (aid > *cur) newshift = aid - AID_DN; /* up */ else if (aid < *cur) newshift = aid - AID_UP; /* down */ else newshift = *shift; if (newshift + h > n) newshift = n - h; if (newshift < 0) newshift = 0; *shift = newshift; *cur = aid; (*draw) (ptr); /* */ (*go) (ptr, aid - newshift, NO); /* */ } /* . : m->items . m->title . m->top (y). m->left (x). m->handler NULL. m->hitkeys [] NULL. m->bg_attrib . m->sel_attrib . */ int MnuInit (Menu *m) { int len, pos; char *s; register i; m -> current = m -> shift = 0; m -> scrollok = m -> key = 0; if (m -> hotkeys) { /* "" */ free ((char *) m -> hotkeys); m -> hotkeys = (int *) NULL; } /* */ for (i = 0; M_ITEM (m, i) != (char *) NULL; i++); m -> nitems = i; /* "" */ if (m -> hotkeys = (int *) malloc (sizeof (int) * m -> nitems)) { for (i = 0; i < m -> nitems; i++) m -> hotkeys[i] = NOKEY; } /* */ 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; } /* */ #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) { /* */ m -> scrollok = BAR_VER; /* */ 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; /* */ 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 ){ /* */ KillWin( m->win ); m->win = NULL; } if( m->win == NULL ){ /* */ if((m->win = newwin(m->height, m->width, m->top, m->left)) == NULL) return 0; keypad(m->win, TRUE); MnuWin(m); MnuDraw(m); /* */ } return ( m->win != NULL ); } /* */ void MnuDeinit (Menu *m) { if( m->win ){ KillWin (m->win); m->win = NULL; } if( m->hotkeys ){ free ((char *) m -> hotkeys); m -> hotkeys = (int *) NULL; } } /* */ void MnuHide (Menu *m){ if( m->win ) HideWin(m->win); } /* line- */ 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, ' '); /* M_CTRL- */ wattrset (w, m->bg_attrib); mvwaddch (w, line, 0, VER_LINE); mvwaddch (w, line, xend, VER_LINE); wattrset (w, m->bg_attrib); } /* y- */ 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 { /* */ s = "~"; label = hatch = bold = NO; } if (*s == M_CTRL) { /* */ 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) { /* */ 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){ /* */ 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); /* */ } /* */ 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); } /* */ void MnuDraw (Menu *m) { register i, j; for (i = 0; i < m -> textheight; i++) MnuDrawItem (m, i, NO, m -> scrollok ? YES : NO); } /* line- . */ void MnuPoint(Menu *m, int line, int eraseOld /* ? */){ int curline = m->current - m->shift; /* */ if (line < 0 || line >= m -> textheight) return; /* */ if (eraseOld && curline != line) /* */ MnuDrawItem (m, curline, NO, YES); MnuDrawItem (m, line, YES, YES); /* */ } /* y- , */ void MnuPointAt (Menu *m, int y) { char *s; if (y < 0 || y >= m->nitems) return; /* ! */ 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); /* scroll bar */ GetBack(m->savep, m->win); /* , * MnuWinBar- */ } /* "". */ 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; /* */ RaiseWin (m->win); /* */ MnuPointAt (m, sel); /* */ if(m->showMe) m->showMe(m); /* ? */ 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); /* 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: /* / */ if (M_TST (m, sel, M_LABEL)) M_CLR (m, sel, M_LABEL); else M_SET (m, sel, M_LABEL); MnuPointAt (m, sel); /* goto next; * break; * * 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; } /* HOT KEY ( ) */ done++; goto mv; } continue; mv: MnuPointAt (m, sel = snew); if(done){ wrefresh(m->win); /* */ break; } } out: wnoutrefresh(m->win); return((m->key = c) == ESC ? -1 : sel); /* : - * MnuHide(m); MnuUsualSelect(); */ } /* 20 */ /* ______________________________________________________________ */ /* PULL_DOWN (-) */ /* _______________________ pull.h __________________________ */ typedef struct { Info info; /* */ Menu *menu; /* */ char *note; /* */ } PullInfo; typedef struct _Pull { /* */ int nitems; /* */ PullInfo *items;/* */ int *hotkeys; /* */ int key; /* , */ int current; /* */ int space; /* */ int bg_attrib; /* */ int sel_attrib; /* */ Point savep; void (*scrollBar) (struct _Pull *m, int n, int among); } PullMenu; #define PYBEG 0 /* , */ #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 ) /* _______________________ 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; } /* . : p->items M_HOT- . p->bg_attrib . p->sel_attrib . stdscr (PullWin). */ int PullInit(PullMenu *m){ /* , * .. */ int total, pos; char *s; register i; m->key = m->current = 0; if(m->hotkeys){ free((char *) m->hotkeys); m->hotkeys = (int *) NULL; } /* */ 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)){ /* */ err: beep(); return 0; } m->space = (wcols(PullWin) - total - 2) / (m->nitems + 1); if( m->space <= 0 ) goto err; /* */ 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; } /* pull-down */ 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); } /* pull-down . , */ 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); } /* */ 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); } /* 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); } } /* */ 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); /* */ for(;;){ if( autogo ){ /* */ 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; } /* */ if( code == TOTAL_NOSEL) goto ask; /* MnuUsualSelect * */ 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; /* , PM_MENU(m, m->current) */ } /* 21 */ /* */ /* _______________________ hist.h __________________________ */ /* . . */ /* ______________________________________________________________ */ typedef struct { /* */ Info *list; /* */ int sz; /* (.) */ int len; /* */ Menu mnu; /* */ } Hist; void HistInit(Hist *h, int n); void HistAdd (Hist *h, char *s, int fl); Info *HistSelect(Hist *h, int x, int y); /* _______________________ hist.c __________________________ */ #include "w.h" #include "glob.h" #include "menu.h" #include "hist.h" /* "" n */ 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; } /* s fl */ void HistAdd (Hist *h, char *s, int fl){ register i, j; Info tmp; if( h->sz == 0 ) return; /* ? */ for( i=0; i < h->len; i++ ) if( !strcmp(s, h->list[i].s )){ /* ! */ if( i == 0 ) return; /* */ /* */ 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{ /* */ 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; } /* */ 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 ]; } /* _______________________ line.h __________________________ */ /* ( ) */ /* ______________________________________________________________ */ typedef struct _LineEdit { /* */ WINDOW *win; /* */ int width; /* */ int left, top; /* */ int pos; /* */ int shift; /* */ char *line; /* */ int maxlen; /* */ int len; /* */ int insert; /* 1 - ; 0 - */ int nc; /* 1 - */ int cursorOn; /* ( ) */ int bg_attrib; /* */ int fr_attrib; /* */ int wl_attrib; /* */ int sel_attrib; /* */ Hist *histIn; /* */ Hist *histOut; /* */ int key; /* , */ Point savep; /* ( ) */ int (*showMe)(struct _LineEdit *le); /* 1 */ void (*hideMe)(struct _LineEdit *le); void (*posMe) (struct _LineEdit *le); /* */ /* scroll bar- ( ) */ void (*scrollBar)(struct _LineEdit *le, int whichbar, int n, int among); /* ( ) */ 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 ) /* _______________________ line.c __________________________ */ /* . * * , CURSES- */ #include "w.h" #include "glob.h" #include "menu.h" #include "hist.h" #include "line.h" /* */ 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; } /* */ static void insert(char *s, int at, int c){ register char *p; s += at; p = s; while(*p) p++; /* */ p[1] = '\0'; /* */ for( ; p != s; p-- ) p[0] = p[-1]; *s = c; } /* from */ static void LeDrawLine( LineEdit *le, int from ){ LeCursorHide( le ); for( ; from < le->width; from++ ) LePutChar(le, from); /* */ } /* at */ void LePutChar( LineEdit *le, int at){ int off = le->shift + at; int bgcolor = le->bg_attrib, wall; wall = /* ? */ ( 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): /* */ 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); } /* . x 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; } /* */ 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); } /* */ static void LeRoll( LineEdit *ptr, int aid, int *cur, int *shift, int width, /* */ int len, int maxlen, void (*go) (LineEdit *p, int x, int eraseOld), void (*draw)(LineEdit *p), /* */ int LDX ){ int x = *cur - *shift, oldshift = *shift, newshift = oldshift; int AID_LFT, AID_RGT, drawn = NO; if( aid < 0 || aid > len )