"avarijnuyu" kartinku v paneli */ if( ReadDir(tpane1.d.name, &tpane1.d) || NON_VALID(&tpane1.d)) InitTblFromDir(&tpane1, NO, NULL); if( tpane1.t.exposed == NO ) TblDraw(&tpane1.t); if( ReadDir(tpane2.d.name, &tpane2.d) || NON_VALID(&tpane2.d)) InitTblFromDir(&tpane2, NO, NULL); if( tpane2.t.exposed == NO ) TblDraw(&tpane2.t); } /*-----------------------------------------------------------------* * Vvod komand i vydacha podskazki. * *-----------------------------------------------------------------*/ /* Osobaya obrabotka otdel'nyh klavish v redaktore stroki */ char e_move = NO; /* knopki so strelkami <- -> dvigayut kursor po stroke/po tablice */ int e_hit[] = { KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_F(0), KEY_IC, ctrl('G'), ctrl('E'), ctrl('L'), ctrl('F'), ctrl('X'), ctrl('Y'), -1 }; int e_handler (LineEdit *le, int c, HandlerReply *reply){ *reply = HANDLER_CONTINUE; switch(c){ /* Peremeshchenie po tablice bez vyhoda iz redaktora stroki */ case KEY_LEFT: if( !SEL_PANE || !e_move){ *reply=HANDLER_SWITCH; return c; } TblPointAt(A_tbl, A_tbl->current - A_tbl->height); break; case KEY_RIGHT: if( !SEL_PANE || !e_move){ *reply=HANDLER_SWITCH; return c; } TblPointAt(A_tbl, A_tbl->current + A_tbl->height); break; case KEY_DOWN: if( !SEL_PANE){ *reply=HANDLER_SWITCH; return c; } TblPointAt(A_tbl, A_tbl->current + 1); break; case KEY_UP: if( !SEL_PANE){ *reply=HANDLER_SWITCH; return c; } TblPointAt(A_tbl, A_tbl->current - 1); break; case KEY_F(0): /* F10 */ e_move = !e_move; break; case KEY_IC: if( !SEL_PANE){ *reply=HANDLER_SWITCH; return c; } TblRetag(A_tbl, A_tbl->current, T_LABEL); TblPointAt(A_tbl, A_tbl->current+1); break; /* Podstanovki */ case ctrl('G'): /* podstavit' polnoe imya domashnego kataloga */ LeInsStr(le, getenv("HOME")); LeInsStr(le, " "); break; case ctrl('E'): /* podstavit' imya vybrannogo fajla */ if( A_tbl->nitems ) LeInsStr(le, T_ITEMF(A_tbl, A_tbl->current, 0)); LeInsStr(le, " "); break; case ctrl('L'): /* podstavit' imya vybrannogo fajla iz drugoj paneli */ LeInsStr(le, T_ITEMF(B_tbl, B_tbl->current, 0)); LeInsStr(le, " "); break; case ctrl('X'): case ctrl('Y'): /* podstanovka imen pomechennyh fajlov */ { int label = (c == ctrl('X') ? T_LABEL : T_HATCH); register i; for(i=0; i < A_tbl->nitems && le->len < le->maxlen; ++i ) if( T_TST(A_tbl, i, label)){ LeInsStr(le, " "); LeInsStr(le, T_ITEMF(A_tbl, i, 0)); } } break; case ctrl('F'): /* podstavit' imya tekushchego kataloga */ LeInsStr(le, CWD); LeInsStr(le, " "); break; } return c; } /* Pri nachale redaktirovaniya stav' kursor v konec stroki */ void e_pos (LineEdit *le){ le->pos = le->len; } /* Oboznachit', chto my pokinuli redaktor stroki */ void e_hide(LineEdit *le){ le->sel_attrib = le->fr_attrib = le->bg_attrib = A_ITALICS; LeDraw(le); } /* Otredaktirovat' stroku v predposlednej stroke okna */ char *Edit(WINDOW *w, char *src, RunType dorun){ static char CMD[MAXLEN]; /* bufer dlya stroki komandy */ int c; if(w != TOPW){ beep(); return NULL; }/* eto dolzhno byt' verhnee okno */ keypad(w, TRUE); /* Proinicializirovat' redaktor stroki */ switch(dorun){ case NORUN: edit.histIn = edit.histOut = NULL; break; case RUNCMD: edit.histIn = edit.histOut = &hedit; break; case FIND: case TAG: edit.histIn = edit.histOut = &hpat; break; case CHDIR: edit.histIn = &hcwd; edit.histOut = NULL; break; } edit.line = CMD; edit.maxlen = sizeof(CMD)-1; edit.top = wlines(w)-2; edit.left = 2; edit.width = wcols (w)-4 - (1+BARWIDTH); edit.insert = YES; edit.nc = YES; edit.win = w; edit.wl_attrib = edit.bg_attrib=A_REVERSE; edit.fr_attrib=A_STANDOUT; edit.sel_attrib = A_NORMAL|A_BLINK; edit.posMe = e_pos; edit.hitkeys = (SEL_PANE ? e_hit : e_hit+5); edit.handler = e_handler; /* edit.hideMe = e_hide; vyzyvaetsya YAVNO */ /* ostal'nye polya ravny 0, t.k. edit - staticheskoe dannoe */ for(;;){ strcpy(CMD, src); if(*src){ strcat(CMD, " "); } c = LeEdit( &edit ); if( LE_REFUSED(&edit) || dorun != RUNCMD || !*CMD || c != '\n' ) break; /* kursor v nizhnyuyu stroku ekrana */ attrset(A_NORMAL); move(LINES-1, 0); refresh(); resetterm(); /* priostanovit' rabotu curses-a */ putchar('\n'); /* promotat' ekran na stroku */ system(CMD); /* vypolnit' komandu vneshnim SHellom */ fprintf(stderr,"Nazhmi ENTER chtoby prodolzhit' --- ");gets(CMD); fixterm(); /* vozobnovit' rabotu curses-a */ RedrawScreen(); /* pererisovat' ekran */ if(w == panewin){ checkBothPanes(); if(A_tbl->nitems) TblPoint(A_tbl, A_tbl->current, NO); } src = ""; /* vo vtoroj raz nichego ne podstavlyat' */ } wattrset(w, A_NORMAL); /* ? */ e_hide ( &edit ); return ( *CMD && !LE_REFUSED(&edit)) ? CMD : NULL; } /* Vydacha podskazki a takzhe soobshchenij ob oshibkah. */ /* V etom zhe okne mozhno nabirat' komandy (dorun==RUNCMD). */ char *help(char *msg, RunType dorun){ register i; char *s; static char *helptext[] = { "ESC - vyhod v glavnoe menyu", "F1 - podskazka", "INS - pometit' fajl", "ctrl/E - podstavit' imya vybrannogo fajla", "ctrl/L - podstavit' imya iz drugoj paneli", "ctrl/X - podstavit' pomechennye fajly", "ctrl/Y - podstavit' pomechennye kursivom", "ctrl/G - podstavit' imya domashnego kataloga", "ctrl/F - podstavit' imya tekushchego kataloga", "F4 - istoriya", "F7 - pereklyuchit' rezhim vstavki/zameny", "F10 - pereklyuchit' peremeshcheniya po stroke/po paneli", }; #define HELPLINES (sizeof(helptext)/sizeof helptext[0]) Sel save_current_menu = current_menu; /* "vyskakivayushchee" POP-UP window */ WINDOW *w = newwin(2+1+HELPLINES+1, 70, 2, (COLS-70)/2); if( w == NULL ) return NULL; current_menu = SEL_HELP; wattrset(w, A_REVERSE); /* eto budet inversnoe okno */ werase (w); /* zapolnit' inversnym fonom */ wborder(w); RaiseWin(w); /* okno poyavlyaetsya */ if(*msg){ wattron (w, A_BOLD); mvwaddstr(w, 1+HELPLINES, 2, msg); wattroff(w, A_BOLD); } for(i=0; i < HELPLINES; i++) mvwaddstr(w, 1+i, 2, helptext[i]); s = Edit(w, "", dorun); PopWin(); /* okno ischezaet */ current_menu = save_current_menu; return s; } /*-----------------------------------------------------------------* * Upravlyayushchee menyu. * *-----------------------------------------------------------------*/ int f_left(), f_right(), f_pull(), f_help(), f_sort(), f_dir(), f_bye(), f_redraw(),f_cdroot(); /* Obratite vnimanie, chto mozhno ukazyvat' ne vse polya struktury, * a tol'ko pervye. Ostal'nye ravny 0 */ #ifndef __GNUC__ Info mwrk_info[] = { /* stroki dlya glavnogo menyu */ { "\\Current directory", 0 , f_left }, /* 0 */ { "\\Root directory", M_HATCH , f_right }, /* 1 */ { "\\Menus", 0 , f_pull }, /* 2 */ { "\1", /* goriz. cherta */ 0 }, /* 3 */ { "\\Help", 0 , f_help }, /* 4 */ { "Un\\implemented", I_NOSEL }, /* 5 */ { "Change \\sorttype", 0 , f_sort }, /* 6 */ { "Look directory \\history", 0 , f_dir }, /* 7 */ { "\1", /* goriz. cherta */ 0 }, /* 8 */ { "\\Quit", M_BOLD , f_bye }, /* 9 */ { "\1", /* goriz. cherta */ 0 }, /* 10 */ { "\\Redraw screen", M_HATCH , f_redraw}, /* 11 */ { "Chdir both panels to /", M_HATCH , f_cdroot}, /* 12 */ { NULL, 0 } }; #else /* GNU C-kompilyator 1.37 ne mozhet inicializirovat' polya-union-y */ static char _gnu_[] = "Compiled with GNU C-compiler"; Info mwrk_info[] = { /* stroki dlya glavnogo menyu */ { "\\Current directory", 0 }, { "\\Root directory", M_HATCH }, { "\\Menus", 0 }, { "\1", /* goriz. cherta */ 0 }, { "\\Help", 0 }, { "Un\\implemented", I_NOSEL }, { "Change \\sorttype", 0 }, { "Look directory \\history", 0 }, { "\1", /* goriz. cherta */ 0 }, { "\\Quit", M_BOLD }, { "\1", /* goriz. cherta */ 0 }, { "\\Redraw screen", M_HATCH }, { "Chdir both panels to /", M_HATCH }, { NULL, 0 } }; void mwrk_init(){ mwrk_info [0].any.act = f_left; mwrk_info [1].any.act = f_right; mwrk_info [2].any.act = f_pull; mwrk_info [4].any.act = f_help; mwrk_info [6].any.act = f_sort; mwrk_info [7].any.act = f_dir; mwrk_info [9].any.act = f_bye; mwrk_info[11].any.act = f_redraw; mwrk_info[12].any.act = f_cdroot; } #endif char *mwrk_help[] = { "Perejti v levuyu panel'", "Perejti v pravuyu panel'", "Perejti v strochnoe menyu", "", "Vydat' podskazku", "Ne realizovano", "Izmenit' tip sortirovki imen", "Istoriya puteshestvij", "", "Vyhod", "", "Pererisovka ekrana", "Obe paneli postavit' v kornevoj katalog", NULL }; void m_help(Menu *m, int n, int among){ Message(mwrk_help[n]); } /* Vybor v rabochem (komandnom) menyu */ void SelectWorkingMenu(int sel){ if(sel == NOSELECTED) sel = MnuUsualSelect( & mwrk, NO); if( M_REFUSED(&mwrk)) help("Vyberi Quit", NORUN); else if(mwrk.items[sel].any.act) (*mwrk.items[sel].any.act)(); if( !done) MnuHide( & mwrk ); } f_left () { current_menu = SEL_PANE1; return 0; } f_right() { current_menu = SEL_PANE2; return 0; } f_pull () { current_menu = SEL_PULL; return 0; } f_help () { help("Nazhmi ENTER ili naberi komandu:", RUNCMD); return 0; } f_sort () { SelectSortType(NOSELECTED); return 0; } f_dir () { Info *idir; if(idir = HistSelect(&hcwd, 20, 3)) cd(idir->s, &tpane2, CWD); current_menu = SEL_PANE2; return 0; } f_bye () { done++; return 0; } f_redraw() { RedrawScreen(); return 0; } f_cdroot() { cd("/", &tpane1, CWD); cd("/", &tpane2, CWD); checkBothPanes(); return 0; } /*-----------------------------------------------------------------* * Vydacha informacii pro fajl, redaktirovanie kodov dostupa. * *-----------------------------------------------------------------*/ void MYwaddstr(WINDOW *w, int y, int x, int maxwidth, char *s){ register pos; for(pos=0; *s && *s != '\n' && pos < maxwidth; ++s){ wmove(w, y, x+pos); if( *s == '\t') pos += 8 - (pos & 7); else if( *s == '\b'){ if(pos) --pos; } else if( *s == '\r') pos = 0; else { ++pos; waddch(w, isprint(*s) ? *s : '?'); } } } /* Prosmotr nachala fajla v protivopolozhnoj paneli. */ void fastView( char *name, /* imya fajla */ unsigned mode, /* nekotorye tipy fajlov ne prosmatrivat' */ Table *otbl /* protivopolozhnaya panel' */ ){ FILE *fp; register int x, y; char buf[512]; TblClear(otbl); Message("Nazhmi ENTER dlya okonchaniya. " "PROBEL - izmenyaet kod dostupa. " "ESC - otkatka."); if( !ISREG(mode)) goto out; if((fp = fopen(name, "r")) == NULL){ Message("Ne mogu chitat' %s", name); return; } for(y=0; y < otbl->height && fgets(buf, sizeof buf, fp); y++) MYwaddstr(panewin, otbl->top+y, otbl->left+1, otbl->width-2, buf); fclose(fp); out: wrefresh(otbl->win); /* proyavit' */ } static struct attrNames{ unsigned mode; char name; char acc; int off; } modes[] = { { S_IREAD, 'r', 'u', 0 }, { S_IWRITE, 'w', 'u', 1 }, { S_IEXEC, 'x', 'u', 2 }, { S_IREAD >> 3, 'r', 'g', 3 }, { S_IWRITE >> 3, 'w', 'g', 4 }, { S_IEXEC >> 3, 'x', 'g', 5 }, { S_IREAD >> 6, 'r', 'o', 6 }, { S_IWRITE >> 6, 'w', 'o', 7 }, { S_IEXEC >> 6, 'x', 'o', 8 }, }; #define NMODES (sizeof(modes)/sizeof(modes[0])) /* Poziciya v kotoroj izobrazhat' i-yj bit kodov dostupa */ #define MODE_X_POS(tbl, i) (tbl->left + DIR_SIZE + 12 + modes[i].off) #define MODE_Y_POS(tbl) (tbl->top + tbl->height + 1) #ifdef FILF /* Izobrazit' informaciyu o tekushchem vybrannom fajle */ void showMode(Table *tbl, int attr){ Info *inf = & tbl->items[tbl->current]; /* fajl */ register i; unsigned mode = inf->mode; /* kody */ int uid = inf->uid, gid = inf->gid; /* hozyain */ /* identifikatory hozyaina i gruppy processa-kommandera */ static char first = YES; static int myuid, mygid; WINDOW *win = tbl->win; int xleft = tbl->left + 1, y = MODE_Y_POS(tbl); if( first ){ first = NO; myuid = getuid(); mygid = getgid(); } wattron (win, attr); mvwprintw(win, y, xleft, " %*.*s %8ld ", /* imya fajla */ -DIR_SIZE, DIR_SIZE, inf->s ? (!strcmp(inf->s, "..") ? "<UP-DIR>": inf->s) : "(EMPTY)", inf->size); /* tip fajla (obychnyj|katalog|ustrojstvo) */ wattron (win, A_ITALICS|A_BOLD); waddch (win, ISDIR(mode) ? 'd': ISDEV(mode) ? '@' : '-'); wattroff(win, A_ITALICS|A_BOLD); /* kody dostupa */ for(i=0; i < NMODES; i++){ if((modes[i].acc == 'u' && myuid == uid) || (modes[i].acc == 'g' && mygid == gid) || (modes[i].acc == 'o' && myuid != uid && mygid != gid)) ; else wattron(win, A_ITALICS); mvwaddch(win, y, MODE_X_POS(tbl, i), mode & modes[i].mode ? modes[i].name : '-'); wattroff(win, A_ITALICS); } waddch(win, ' '); wattroff(win, attr); } #define newmode (tbl->items[tbl->current].mode) /* Redaktirovanie kodov dostupa k fajlam. */ int editAccessModes(FileWidget *wd){ Table *tbl = &wd->t; Table *otbl = &(Other_pane(wd)->t); /* ili Other_tbl(tbl); */ unsigned prevmode, oldmode; /* staryj kod dostupa */ char *name; /* imya tekushchego fajla */ WINDOW *win = tbl->win; int position = 0, c; for(;;){ /* Cikl vybora fajlov v tablice */ name = T_ITEMF(tbl, tbl->current, 0); oldmode = newmode; /* zapomnit' */ fastView(name, newmode, otbl); /* pokazat' pervye stroki fajla */ for(;;){ /* Cikl obrabotki vybrannogo fajla */ wmove(win, MODE_Y_POS(tbl), MODE_X_POS(tbl, position)); switch(c = WinGetch(win)){ /* Nekotorye klavishi vyzyvayut peremeshchenie po tablice */ case KEY_BACKTAB: TblPointAt(tbl, tbl->current - tbl->height); goto mv; case '\t': TblPointAt(tbl, tbl->current + tbl->height); goto mv; case KEY_UP: TblPointAt(tbl, tbl->current - 1); goto mv; case KEY_DOWN: TblPointAt(tbl, tbl->current + 1); goto mv; case KEY_HOME: TblPointAt(tbl, 0); goto mv; case KEY_END: TblPointAt(tbl, tbl->nitems-1); goto mv; /* Prochie klavishi prednaznacheny dlya redaktirovaniya kodov dostupa */ case KEY_LEFT: if(position) --position; break; case KEY_RIGHT: if(position < NMODES-1) position++; break; default: goto out; case ESC: /* Vosstanovit' starye kody */ prevmode = newmode = oldmode; goto change; case ' ': /* Invertirovat' kod dostupa */ prevmode = newmode; /* zapomnit' */ newmode ^= modes[position].mode; /* invertirovat' */ change: if( chmod(name, newmode) < 0){ beep(); Message("Ne mogu izmenit' dostup k %s", name); newmode = prevmode; /* vosstanovit' */ } else /* dostup izmenen, pokazat' eto */ showMode(tbl, A_REVERSE); break; } } /* Konec cikla obrabotki vybrannogo fajla */ mv: ; } /* Konec cikla vybora fajlov v tablice */ out: /* Ochistit' protivopolozhnuyu panel' posle fastView(); */ Message(""); TblClear(otbl); return c; } #undef newmode #else void editAccessModes(FileWidget *wd){} #endif long diskFree(){ struct ustat ust; struct stat st; long freespace; if(stat(".", &st) < 0) return 0; ustat(st.st_dev, &ust); freespace = ust.f_tfree * 512L; freespace /= 1024; Message("V %*.*s svobodno %ld Kb.", -sizeof(ust.f_fname), sizeof(ust.f_fname), *ust.f_fname ? ust.f_fname : ".", freespace); doupdate(); /* proyavit' okno dlya Message() */ return freespace; } /*-----------------------------------------------------------------* * Special'nye komandy, ispol'zuyushchie obhod dereva *-----------------------------------------------------------------*/ /* Vydacha soobshchenij ob oshibkah (smotri Makefile) */ int tree_err_cant_read(char *name){ Message("Ne mogu chitat' \"%s\"", name); return WARNING; } int tree_name_too_long(){ Message("Slishkom dlinnoe polnoe imya"); return WARNING; } char canRun; /* prodolzhat' li poisk */ /* Preryvanie obhoda po SIGINT */ void onintr_f(nsig){ canRun = NO; Message("Interrupted"); } /* ==== mesto, zanimaemoe podderevom ==== */ long tu(int *count){ struct stat st; register i; long sum = 0L; *count = 0; for(i=0; i < A_tbl->nitems ;++i ) if( T_TST(A_tbl, i, T_LABEL)){ stat(T_ITEMF(A_tbl, i, 0), &st); #define KB(s) (((s) + 1024L - 1) / 1024L) sum += KB(st.st_size); (*count)++; } return sum; } void diskUsage(){ long du(), size, sizetagged; int n; char msg[512]; Message("Izmeryaem ob®em fajlov..."); doupdate(); size = du("."); diskFree(); sizetagged = tu(&n); sprintf(msg, "%ld kilobajt v %s, %ld kb v %d pomechennyh fajlah", size, CWD, sizetagged, n); help(msg, NORUN); } /* ==== poisk fajla ===================== */ extern char *find_PATTERN; /* imported from treemk.c */ extern Info gargv[]; extern int gargc; /* imported from glob.c */ /* Proverit' ocherednoe imya i zapomnit' ego, esli podhodit */ static int findCheck(char *fullname, int level, struct stat *st){ char *basename = strrchr(fullname, '/'); if(basename) basename++; else basename = fullname; if( canRun == NO ) return FAILURE; /* poisk prervan */ if( match(basename, find_PATTERN)){ /* imported from match.c */ gargv[gargc] = NullInfo; /* zachistka */ gargv[gargc].s = strdup(fullname); gargv[gargc++].fl= ISDIR(st->st_mode) ? I_DIR : 0; gargv[gargc] = NullInfo; Message("%s", fullname); doupdate(); } /* Strahovka ot perepolneniya gargv[] */ if ( gargc < MAX_ARGV - 1 ) return SUCCESS; else { Message("Najdeno slishkom mnogo imen."); return FAILURE; } } /* Sobrat' imena fajlov, udovletvoryayushchie shablonu */ static Info *findAndCollect(char *pattern){ void (*old)() = signal(SIGINT, onintr_f); Sort saveSort; find_PATTERN = pattern; canRun = YES; Message("Ishchem %s ot %s", pattern, CWD); doupdate(); greset(); /* smotri glob.c, gargc=0; */ walktree(CWD, findCheck, NULL, findCheck); signal(SIGINT, old); saveSort = sorttype; sorttype = SORT_ASC; if(gargc) qsort( gargv, gargc, sizeof(Info), gcmps); sorttype = saveSort; return gargc ? blkcpy(gargv) : NULL; } /* Obrabotat' sobrannye imena pri pomoshchi pred®yavleniya menyu s nimi */ void findFile(FileWidget *wd){ static Info *found; static Menu mfind; int c; Table *tbl = & wd->t; char *pattern = help("Vvedi obrazec dlya poiska, vrode *.c, " "ili ENTER dlya prezhnego spiska", FIND); if( LE_REFUSED( &edit)) return; /* otkazalis' ot poiska */ /* Esli nabrana pustaya stroka, help() vydaet NULL */ if( pattern ){ /* zadan novyj obrazec - ishchem */ /* Unichtozhit' staryj spisok fajlov i menyu */ if( found ) blkfree( found ); MnuDeinit( &mfind ); found = findAndCollect(pattern); /* poisk */ HistAdd( &hpat, pattern, 0); /* Obrazuem menyu iz najdennyh fajlov */ if( found ){ /* esli chto-nibud' nashli */ mfind.items = found; mfind.title = pattern ? pattern : "Najdennye fajly"; mfind.top = 3; mfind.left = COLS/6; mfind.bg_attrib = A_STANDOUT; mfind.sel_attrib = A_REVERSE; MnuInit (&mfind); } } /* else nabrana pustaya stroka - prosto vyzyvaem spisok * najdennyh ranee fajlov. */ if( found == NULL ){ Message("Nichego ne najdeno"); beep(); return; } c = MnuUsualSelect(&mfind, NO); /* Vybor fajla v etom menyu vyzovet perehod v katalog, * v kotorom soderzhitsya etot fajl */ if( !M_REFUSED( &mfind )){ char *s = M_ITEM(&mfind, mfind.current); /* pometit' vybrannyj element */ M_SET(&mfind, mfind.current, M_LABEL); /* esli eto katalog - vojti v nego */ if( M_TST(&mfind, mfind.current, I_DIR)) cd(s, wd, CWD); /* inache vojti v katalog, soderzhashchij etot fajl */ else { char *p; struct savech svch; /* smotri glob.h */ SAVE( svch, strrchr(s, '/')); *svch.s = '\0'; p = strdup(s); RESTORE(svch); if( !strcmp(CWD, p)) /* my uzhe zdes' */ TblPlaceByName(tbl, svch.s+1); /* ukazat' kursorom */ else /* izmenit' katalog i ukazat' kursorom na fajl s */ cd(p, wd, s); free(p); } } MnuHide(&mfind); /* spryatat' menyu, ne unichtozhaya ego */ } /*-----------------------------------------------------------------* * Rabota s panelyami, soderzhashchimi imena fajlov dvuh katalogov. * *-----------------------------------------------------------------*/ /* Vosstanovit' elementy, zatertye ramkoj WinBorder */ void t_restore_corners(){ mvwaddch(panewin, LINES-3, 0, LEFT_JOIN); mvwaddch(panewin, LINES-3, COLS-2-BARWIDTH, RIGHT_JOIN); mvwaddch(panewin, LINES-5, 0, LEFT_JOIN); mvwaddch(panewin, LINES-5, COLS-2-BARWIDTH, RIGHT_JOIN); mvwaddch(panewin, 2, CENTER, TOP_JOIN); wattron (panewin, A_BOLD); mvwaddch(panewin, LINES-3, CENTER, BOTTOM_JOIN); mvwaddch(panewin, LINES-5, CENTER, MIDDLE_CROSS); wattroff(panewin, A_BOLD); } /* Narisovat' nechto pri vhode v panel'. Zdes' izmenyaetsya * zagolovok okna: on stanovitsya ravnym imeni kataloga, * prosmatrivaemogo v paneli */ void t_enter(Table *tbl){ WinBorder(tbl->win, tbl->bg_attrib, tbl->sel_attrib, CWD, BAR_VER|BAR_HOR, NO); t_restore_corners(); } /* Steret' podsvetku pri vyhode iz paneli */ void t_leave(Table *tbl){ TblDrawItem( tbl, tbl->current, NO, YES ); } /* Risuet nedostayushchuyu chast' ramki, kotoraya ne izmenyaetsya vposledstvii */ void t_border_common(){ WinBorder(panewin, A_tbl->bg_attrib, A_tbl->sel_attrib, A_dir->name, BAR_VER|BAR_HOR, NO); wattron (panewin, A_BOLD); whorline(panewin, LINES-3, 1, COLS-1-BARWIDTH-1); whorline(panewin, LINES-5, 1, COLS-1-BARWIDTH-1); wverline(panewin, CENTER, A_tbl->top, A_tbl->top + A_tbl->height+2); wattroff(panewin, A_BOLD); t_restore_corners(); } /* Funkciya, izobrazhayushchaya nedostayushchie chasti paneli pri vhode v nee */ int t_show(Table *tbl){ #ifdef FILF showMode(A_tbl, A_STANDOUT); showMode(B_tbl, A_STANDOUT); #endif return 1; } void t_scrollbar(Table *tbl, int whichbar, int n, int among){ WinScrollBar(tbl->win, BAR_VER|BAR_HOR, n, among, "Yes", tbl->bg_attrib); #ifdef FILF showMode(tbl, A_REVERSE); #endif } /* Osobaya obrabotka klavish pri vybore v tablice */ int t_hit[] = { '\t', KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(8), ' ', '+', '-', ctrl('R'), ctrl('L'), ctrl('F'), -1 }; Info t_info[] = { { "TAB Perejti v druguyu panel'", 0}, { "F1 Vydat' podskazku", 0}, { "F2 Vvesti komandu", 0}, { "F3 Perejti v roditel'skij katalog", 0}, { "F4 Perejti v katalog po imeni", 0}, { "F8 Udalit' pomechennye fajly", 0}, { "PROBEL Redaktirovat' kody dostupa", 0}, { "+ Pometit' fajly", 0}, { "- Snyat' pometki", 0}, { "ctrl/R Perechitat' katalog", 0}, { "ctrl/L Vydat' razmer fajlov v kataloge",0}, { "ctrl/F Poisk fajla", 0}, { NULL, 0} }; int t_help(){ static Menu mth; int c = 0; if( mth.items == NULL ){ mth.items = t_info; mth.title = "Komandy v paneli"; mth.top = 3; mth.left = COLS/6; mth.bg_attrib = A_STANDOUT; mth.sel_attrib = A_REVERSE; MnuInit (&mth); mth.hotkeys = t_hit; } c = MnuUsualSelect(&mth, 0); /* Spryatat' menyu, ne unichtozhaya ego. Unichtozhenie vyglyadelo by tak: * mth.hotkeys = NULL; (t.k. oni ne vydelyalis' malloc()-om) * MnuDeinit(&mth); */ MnuHide(&mth); if( M_REFUSED(&mth)) return 0; /* nichego ne delat' */ return t_hit[c]; /* klavisha, sootvetstvuyushchaya vybrannoj stroke */ } int t_handler (Table *tbl, int c, HandlerReply *reply){ int i, cnt=0; extern int unlink(), rmdir(); char *answer; FileWidget *wd = TblFW (tbl); switch(c){ case '\t': /* perejti v sosednyuyu panel' */ ExchangePanes(); *reply = HANDLER_OUT; return LEAVE_KEY; /* pokinut' etu panel' */ case KEY_F(1): *reply = HANDLER_NEWCHAR; return t_help(); case KEY_F(2): (void) Edit(tbl->win, T_ITEMF(tbl, tbl->current, 0), RUNCMD); break; case KEY_F(3): cd(".." , wd, CWD); break; case KEY_F(4): if(answer = help("Vvedi imya kataloga, v kotoryj nado perejti",CHDIR)) cd(answer , wd, CWD); break; case ctrl('R'): break; case KEY_F(8): for(i=0; i < tbl->nitems; i++) if(T_TST(tbl, i, M_LABEL)){ int code; cnt++; if((code = (T_TST(tbl, i, I_DIR) ? rmdir : unlink) (T_ITEMF(tbl, i,0))) < 0) T_SET(tbl, i, M_HATCH); } if(cnt==0) help("Net pomechennyh fajlov", NORUN); break; case '+': if(answer = help("SHablon dlya pometki", TAG)) TblTagAll(tbl, answer, T_LABEL); break; case '-': if(answer = help("SHablon dlya snyatiya pometok", TAG)) TblUntagAll(tbl, answer, T_LABEL); break; case ctrl('L'): /* komanda "disk usage" */ diskUsage(); break; case ctrl('F'): /* poisk fajla */ findFile(wd); break; case ' ': /* redaktirovanie kodov dostupa */ editAccessModes(wd); break; } *reply = HANDLER_OUT; return REPEAT_KEY; /* vernut'sya v etu zhe panel' */ } /* Vybor v odnoj iz panelej. */ int SelectPane(FileWidget *wd){ Table *tbl = & wd->t; DirContents *d = & wd->d; int sel, retcode = 0; RaiseWin( tbl->win ); /* vojti v ukazannyj katalog, popravit' CWD */ if(mychdir( d->name ) < 0) checkBothPanes(); /* t_enter( tbl ); /* vojti v ukazannuyu panel', popravit' ramku */ for(;;){ /* Proverit', ne ustarelo li soderzhimoe tablic */ checkBothPanes(); if((sel = TblUsualSelect( tbl )) == TOTAL_NOSEL ){ current_menu = SEL_PULL; goto out; } if( T_REFUSED(tbl)) break; /* nazhat ESC */ if( tbl->key == LEAVE_KEY ){ retcode=1; break; } strcpy(SELECTION, T_ITEMF(tbl, sel, 0)); if( tbl->key == REPEAT_KEY ) continue; if(T_TST(tbl, sel, I_DIR)){ /* eto katalog */ /* popytat'sya perejti v etot katalog */ cd(SELECTION, wd, CWD); } else if(T_TST(tbl, sel, I_EXE)){ /* vypolnyaemyj fajl */ (void) Edit(tbl->win, SELECTION, RUNCMD); } else { editAccessModes(wd); /* Na samom dele nado proizvodit' podbor komandy po * tipu fajla (nabor sootvetstvij dolzhen programmirovat'sya * vami v special'nom fajle, schityvaemom pri zapuske kommandera). * runCommand( classify(SELECTION)); * gde klassifikaciya v prostejshem sluchae - po imeni i suffiksu, * a v bolee razvitom - eshche i po kodam dostupa (vklyuchaya tip fajla) * i po pervoj stroke fajla (ili "magicheskomu chislu"). */ } } /* end for */ t_leave( tbl ); out: if( !retcode ) current_menu = SEL_PULL; /* vyhod po ESC */ return retcode; } /*-----------------------------------------------------------------* * Gorizontal'noe komandnoe menyu (vyzyvaetsya po ESC). * *-----------------------------------------------------------------*/ PullInfo pm_items [] = { /* podskazka */ {{ " \\Left ", 0 }, NULL, "Left pane" }, /* 0 */ {{ " \\Commands ", 0 }, &mwrk, "Do some commands"}, /* 1 */ {{ " \\Tools ", PM_NOSEL }, NULL, "" }, /* 2 */ {{ " \\Sorttype ", 0 }, &msort, "Change sort type"}, /* 3 */ {{ " \\Right ", 0 }, NULL, "Right pane" }, /* 4 */ {{ NULL, 0 }, NULL, NULL } }; void p_help(PullMenu *p, int n, int among){ Message( PM_NOTE(p, n)); } /* Vybor v menyu-stroke */ void SelectPullMenu(){ int c, sel; Menu *m; for(;current_menu == SEL_PULL;){ c = PullUsualSelect(&pull); sel = pull.current; if( PM_REFUSED(&pull)){ current_menu = previous_menu; return;} switch(sel){ case 0: current_menu = SEL_PANE1; return; case 1: SelectWorkingMenu(c); return; case 2: return; /* ne byvaet */ case 3: SelectSortType(c); return; case 4: current_menu = SEL_PANE2; return; } } } /*-----------------------------------------------------------------* * Inicializaciya i zavershenie. * *-----------------------------------------------------------------*/ void die(int sig){ echo(); nocbreak(); mvcur(-1,-1,LINES-1,0); refresh(); endwin (); putchar('\n'); if(sig) printf("Signal %d\n", sig); if(sig == SIGSEGV) abort(); else exit(sig); } void main (void) { setlocale(LC_ALL, ""); /* poluchit' informaciyu o yazyke diagnostik */ initscr (); /* vklyuchit' curses */ signal(SIGINT, die); /* po signalu vyzyvat' die(); */ signal(SIGBUS, die); /* po narusheniyu zashchity pamyati */ signal(SIGSEGV,die); refresh(); /* obnovit' ekran: eto ochistit ego */ noecho(); cbreak(); /* vyklyuchit' eho, vklyuchit' prozrachnyj vvod */ /* Proinicializirovat' istorii */ HistInit(&hcwd, 20); hcwd. mnu.title = "Istoriya puti"; HistInit(&hedit, 20); hedit.mnu.title = "Istoriya komand"; HistInit(&hpat, 8); hpat. mnu.title = "SHablony imen"; /* Razmetit' menyu sortirovki */ msort.items = sort_info; msort.title = "Vid sortirovki kataloga"; msort.top = 1; msort.left = 2; msort.showMe = sort_show; msort.bg_attrib = A_NORMAL; msort.sel_attrib = A_STANDOUT; /* MnuInit (&msort); inicializiruetsya v pull-menu */ /* Razmetit' rabochee menyu */ mwrk.items = mwrk_info; mwrk.title = "Glavnoe menyu"; mwrk.top = 1; mwrk.left = COLS/3; mwrk.handler = NULL; mwrk.hitkeys = NULL; mwrk.bg_attrib = A_STANDOUT; mwrk.sel_attrib = A_REVERSE; mwrk.scrollBar = m_help; #ifdef __GNUC__ mwrk_init(); #endif /* MnuInit (&mwrk); inicializiruetsya v pull-menu */ /* Razmetit' levuyu i pravuyu paneli */ tpane1.t.width = CENTER - 1; tpane2.t.width = COLS - tpane1.t.width - 2 - (2 + BARWIDTH); tpane1.t.height = tpane2.t.height = (LINES - 8); tpane1.t.win = tpane2.t.win = panewin = stdscr; tpane1.t.left = 1; tpane2.t.left = CENTER+1; tpane1.t.top = tpane2.t.top = 3; tpane1.t.bg_attrib = tpane2.t.bg_attrib = A_NORMAL; tpane1.t.sel_attrib = tpane2.t.sel_attrib = A_STANDOUT; tpane1.t.scrollBar = tpane2.t.scrollBar = t_scrollbar; tpane1.t.hitkeys = tpane2.t.hitkeys = t_hit; tpane1.t.handler = tpane2.t.handler = t_handler; tpane1.t.showMe = tpane2.t.showMe = t_show; tpane1.t.hideMe = tpane2.t.hideMe = NULL; /* Razmetit' imena dlya fajlovyh ob®ektov */ tpane1.d.name = strdup("Tekushchij katalog"); tpane2.d.name = strdup("Kornevoj katalog"); /* Izobrazit' ramki (no poka ne proyavlyat' ih) * |to nado sdelat' do pervogo cd(), t.k. inache pri neudache budet vydano * soobshchenie, kotoroe proyavit NEZAVERSHENNUYU kartinku */ t_border_common(); t_restore_corners(); /* Dorazmetit' levuyu panel' */ mychdir("."); /* uznat' polnoe imya tekushchego kataloga v CWD[] */ /* prochitat' soderzhimoe kataloga CWD v tpane1.d */ cd( CWD , &tpane1, CWD); tpane1.t.fmt = "directory"; InitTblFromDir(&tpane1, NO, NULL); /* Dorazmetit' pravuyu panel' */ tpane2.t.fmt = NULL; /* prochitat' soderzhimoe kataloga "/" v tpane2.d */ cd( "/", &tpane2, CWD); /* teper' stoim v korne */ /* Vernut'sya v rabochij katalog */ cd( tpane1.d.name, &tpane1, CWD); /* Narisovat' obe paneli */ TblDraw(A_tbl); TblDraw(B_tbl); /* Razmetit' pulldown menyu */ pull.bg_attrib = A_REVERSE; pull.sel_attrib = A_NORMAL; pull.items = pm_items; pull.scrollBar = p_help; PullInit(&pull); /* Osnovnoj cikl */ for(done=NO, current_menu=SEL_PANE1, A_pane= &tpane1, B_pane= &tpane2; done == NO; ){ Message(""); if(SEL_PANE) previous_menu = current_menu; switch(current_menu){ case SEL_WRK : SelectWorkingMenu(NOSELECTED); break; case SEL_PULL: SelectPullMenu(); break; case SEL_PANE1: if( SelectPane(&tpane1) < 0) M_SET(&mwrk, 0, I_NOSEL); break; case SEL_PANE2: if( SelectPane(&tpane2) < 0) M_SET(&mwrk, 0, I_NOSEL); break; } } die(0); /* Zavershit' rabotu */ } /* Primer 24 */ /* Primer kommunikacii processov pri pomoshchi programmnyh kanalov * (truby, pipes). * Dannaya programma prevrashchaetsya v dve programmy, * soedinennye trubami v takom poryadke: * * stdout stdin * /------------ PIP1 -----------> cmd2 * cmd1 <----------PIP2---------------/ * stdin stdout */ /* fajl LOOP_strt.c */ #include <stdio.h> #define eq(s1,s2) ( strcmp(s1,s2) == 0 ) /* istina, esli stroki ravny */ #define SEP "---" /* razdelitel' komand pri nabore */ main( c, v ) char **v; { char **p, **q; int pid; int PIP1[2]; /* truba cmd1-->cmd2 */ int PIP2[2]; /* truba cmd2-->cmd1 */ if( c==1 ){ printf( "Call: strt cmd1... %s cmd2...\n", SEP ); exit(1); } /* razbor argumentov */ v++; /* v p - argumenty pervoj komandy */ p = v; while( *v && !eq( *v, SEP )) v++; *v = NULL; v++; /* v q - argumenty vtoroj komandy */ q = v; pipe( PIP1 ); /* sozdaem dve truby */ pipe( PIP2 ); /* PIP[0] - otkryt na chtenie, PIP[1] - na zapis' */ if( pid = fork()){ /* razvilka: porozhdaem process */ /* POROZHDENNYJ PROCESS */ fprintf( stderr, "syn=%s pid=%d\n", p[0], getpid()); /* perenapravlyaem stdout novogo processa v PIP1 */ dup2( PIP1[1], 1 ); close( PIP1[1] ); /* kanal chteniya my ne budem ispol'zovat' */ close( PIP1[0] ); /* perenapravlyaem stdin iz PIP2 */ dup2( PIP2[0], 0 ); close( PIP2[0] ); /* kanal zapisi my ne budem ispol'zovat' */ close( PIP2[1] ); /* nachinaem vypolnyat' programmu, soderzhashchuyusya v * fajle p[0] s argumentami p (t.e. cmd1) */ execvp( p[0], p ); /* vozvrata iz sisvyzova exec ne byvaet */ }else{ /* PROCESS-RODITELX */ fprintf( stderr, "otec=%s pid=%d\n", q[0], getpid()); /* perenapravlyaem stdout v PIP2 */ dup2( PIP2[1], 1 ); close( PIP2[1] ); close( PIP2[0] ); /* perenapravlyaem stdin iz PIP1 */ dup2( PIP1[0], 0 ); close( PIP1[0] ); close( PIP1[1] ); /* zapuskaem cmd2 */ execvp( q[0], q ); } } /* Nizhe privodyatsya teksty dvuh programm, kotorye mozhno zapustit' * kak test. Server kompiliruetsya v programmu cmd2, * klient - v programmu cmd1. Esli zapuskayushchaya programma * skompilirovana v strt, to naberite komandu * strt cmd1 --- cmd2 * libo strt cmd2 --- cmd1 */ /* fajl LOOP_p.c --------------------------------------------- * Process-klient (cmd1) */ #include <stdio.h> int trace = 1; /* vesti trassirovku svoih dejstvij */ main(c , v) char **v; { FILE *fp; int pid; char buf[128]; fprintf( stderr, "P: process pid=%d\n", getpid()); fp = fopen( "LOOP_p.c", "r" ); /* otkryvaem fajl s tekstom etoj komandy */ /* chitaem ego postrochno */ while( fgets( buf, sizeof buf, fp ) != NULL ){ if( trace ) fprintf( stderr, "P posylaet: %s", buf ); /* posylaem ego v standartnyj vyvod: trubu PIP1 */ printf( "%s", buf ); fflush( stdout ); /* ozhidat' otveta iz truby PIP2 */ fgets( buf, sizeof buf, stdin ); if( trace ) fprintf( stderr, "P poluchil: %s", buf ); } fclose( stdout ); /* otklyuchit'sya ot truby PIP1. Esli etogo ne sdelat', server * ne prochitaet iz nee EOF */ while((pid = wait(NULL)) > 0 ) fprintf( stderr, "P: %d umer\n", pid ); } /* fajl LOOP_q.c ------------------------------------------------ * process-server (cmd2) */ #include <stdio.h> int trace = 1; main(c , v) char **v; { char buf[128]; int pid; fprintf( stderr, "Q: process pid=%d\n", getpid()); /* chitat' postupayushchie iz truby PIP1 stroki */ while( fgets( buf, sizeof(buf), stdin ) != NULL ){ /* napechatat' poluchennoe soobshchenie */ if( trace ) fprintf( stderr, "Q prochel: %s", buf ); if( trace ) fprintf( stderr, "Q otvechaet: OK=%s", buf ); /* otvetit' v trubu PIP2 */ printf( "OK=%s", buf ); fflush( stdout ); } fclose( stdout ); /* otklyuchit'sya ot truby PIP2 */ while((pid = wait(NULL)) > 0 ) fprintf( stderr, "Q: %d umer\n", pid ); } /* Primer 25 */ /* Primer ispol'zovaniya imenovannyh "trub" (pipes) FIFO-fajlov * dlya kommunikacii nezavisimyh processov * (FIFO - first in, first out : pervym prishel - pervym ushel). * Po motivam knigi M.Dansmura i G.Dejvisa. */ /* fajl P_packet.h --------------------------------------------*/ #include <sys/types.h> #include <sys/stat.h> /* S_IFIFO */ /* struktura paketa-zaprosa */ struct packet { int pk_pid; /* identifikator processa-otpravitelya */ int pk_blk; /* nomer bloka, kotoryj nado prochitat' */ int pk_code; /* kod zaprosa */ }; /* request codes (kody zaprosov) */ #define RQ_READ 0 /* zapros na chtenie */ #define CONNECT 1 /* zapros na soedinenie */ #define SENDPID 2 /* otvet na zapros soedineniya */ #define DISCONNECT 3 /* razryv svyazi */ #define BYE 4 /* zavershit' server */ /* imena FIFO-kanalov svyazi */ #define DNAME "datapipe" #define CNAME "ctrlpipe" /* razmer bloka informacii */ #define PBUFSIZE 512 /* P_client.c --------------------------------------------------------- */ /* * Process-klient, posylayushchij zaprosy k serveru. */ #include <stdio.h> #include <signal.h> #include <fcntl.h> #include "P_packet.h" int datapipe, ctrlpipe; int got_sig; int mypid; /* identifikator processa-klienta */ int spid; /* identifikator processa-servera */ /* waiting for signal */ #define WAITSIG while( !got_sig ) void handler(nsig){ signal( SIGUSR1, handler ); got_sig ++; } void init(){ extern void die(); /* Ozhidat' sozdaniya kanalov svyazi */ while( (datapipe = open( DNAME, O_RDONLY | O_NDELAY )) < 0 ); while( (ctrlpipe = open( CNAME, O_WRONLY | O_NDELAY )) < 0 ); mypid = getpid(); /* my process identifier */ printf( "Client pid=%d started\n", mypid ); signal( SIGINT, die); signal( SIGQUIT, die); signal( SIGTERM, die); handler(0); } int canRun = 1; void die(nsig){ canRun = 0; } /* podklyuchit'sya k serveru, zaprosiv ego pid */ connect(){ struct packet pk; pk.pk_pid = mypid; pk.pk_code = CONNECT; pk.pk_blk = (-1); got_sig = 0; write( ctrlpipe, &pk, sizeof pk ); /* poslat' zapros */ /* ozhidat' signala-"tolchka" */ WAITSIG; /* prochitat' otvet iz kanala dannyh */ read( datapipe, &pk, sizeof pk ); /* poslat' signal-podtverzhdenie */ kill( pk.pk_pid, SIGUSR1 ); return pk.pk_pid; } void disconnect(){ struct packet pk; pk.pk_pid = mypid; pk.pk_code = DISCONNECT; pk.pk_blk = (-1); got_sig = 0; write( ctrlpipe, &pk, sizeof pk ); /* send request */ /* wait for reply */ WAITSIG; /* receive reply */ read( datapipe, &pk, sizeof pk ); /* confirm */ kill( pk.pk_pid, SIGUSR1 ); printf( "Disconnected.\n" ); } request( ptr, blk, spid ) char *ptr; int blk; int spid; { struct packet pk; pk.pk_pid = mypid; pk.pk_blk = blk; pk.pk_code = RQ_READ; got_sig = 0; write( ctrlpipe, &pk, sizeof pk ); WAITSIG; read( datapipe, ptr, PBUFSIZE ); kill( spid, SIGUSR1 ); } bye(){ struct packet pk; pk.pk_pid = mypid; pk.pk_code = BYE; pk.pk_blk = (-1); got_sig = 0; write( ctrlpipe, &pk, sizeof pk ); /* send request */ exit(0); } /* client [nomer_bloka] */ main(argc, argv) char *argv[]; { int blk; char buffer[ PBUFSIZE ]; setbuf( stdout, NULL ); /* make unbuffered */ blk = (argv[1] ? atoi( argv[1] ) : 0); init(); spid = connect(); printf( "Client pid=%d connected to server pid=%d\n", mypid, spid ); /* zapros bloka nomer -33 sootvetstvuet zaprosu "zavershit' * rabotu servera" */ if( blk == -33 ) bye(); /* v cikle posylat' zaprosy na chtenie bloka blk */ while( canRun ){ request( buffer, blk, spid ); printf( "\nBEG-------------------------------------\n" ); fwrite( buffer, PBUFSIZE, 1, stdout );