k() * otkazyvaetsya vypolnyat'sya, esli * fajl dst uzhe sushchestvuet (errno==EEXIST). */ if( link( src, dst ) < 0 ) return FAILED; unlinkd( src, typefrom ); /* udalyaem staryj fajl */ return OK; } } /* Esli ne poluchilos' svyazat' fajl pri pomoshchi link() - sleduet * skopirovat' fajl v ukazannoe mesto, a zatem unichtozhit' staryj fajl. */ int mcopy(char *src, char *dst, unsigned typefrom, unsigned typeto) { if( typefrom == S_IFDIR ) return FAILED; /* katalog ne kopiruem, poskol'ku neposredstvennaya zapis' * v katalog (kak celevoj fajl) razreshena tol'ko yadru OS. */ return docopy( src, dst, typefrom, typeto ); } /* Pereimenovanie fajla */ int domove(char *src, char *dst, unsigned typefrom, unsigned typeto) { switch( typefrom ){ default: if( ! mlink( src, dst, typefrom, typeto)){ if( ! mcopy( src, dst, typefrom, typeto)){ printf( "Can't move %s\n", src ); return FAILED; } else unlinkd( src, typefrom ); /* steret' staryj */ } break; case S_IFDIR: /* katalog pereimenovyvaem v katalog */ if( ! strcmp( ".", basename(src))){ printf( "impossible to move directory \".\"\n" ); return FAILED; } if( ! mlink( src, dst, typefrom, typeto )){ if( errno == EXDEV ) printf( "No cross device directory links\n" ); return FAILED; } break; case ECANTSTAT: printf( "%s does not exist\n", src ); return FAILED; } return OK; /* okay */ } int docpmv( char *src, /* fajl-istochnik */ char *dst, /* fajl-poluchatel' */ struct ftype typeto, /* tip fajla-poluchatelya */ int cp, /* 0 - pereimenovanie, 1 - kopirovanie */ int *confirm /* zaprashivat' podtverzhdenie na perezapis' ? */ ){ struct ftype typefrom; /* tip istochnika */ char namebuf[BUFSIZ]; /* novoe imya poluchatelya (esli nado) */ typefrom = filetype(src); if(typefrom.type == ECANTSTAT){ /* ne sushchestvuet */ printf("%s does not exist.\n", src); return FAILED; } if( typefrom.type != S_IFDIR && typeto.type == S_IFDIR ){ /* fajl v kataloge dst */ sprintf(namebuf, "%s/%s", dst, basename(src)); typeto = filetype(dst = namebuf); } if(typefrom.dev == typeto.dev && typefrom.ino == typeto.ino){ /* Nel'zya kopirovat' fajl sam v sebya */ printf("%s and %s are identical.\n", src, dst); return OK; /* tak kak fajl uzhe est' - schitaem eto udachej */ } /* esli poluchatel' uzhe sushchestvuet, to * zaprosit' podtverzhdenie na perezapis' */ if(*confirm && typeto.type == S_IFREG){ char answer[40]; printf("%s already exists. Overwrite (y/n/all) ? ", dst); fflush(stdout); switch( *gets(answer)){ case 'n': default: return OK; /* nichego ne delat' */ case 'y': break; case 'a': *confirm = NO; /* dal'she - bez zaprosov */ break; } } return cp ? docopy(src, dst, typefrom.type, typeto.type) : domove(src, dst, typefrom.type, typeto.type) ; } void main(int argc, char *argv[]) { char *cmd; int cp, i, err, confirm = YES; struct ftype typeto; /* tip fajla-poluchatelya */ if( argc < 3 ) { printf( "Usage: %s source... destination\n", argv[0] ); exit(1); /* nenulevoj kod vozvrata signaliziruet ob oshibke */ } /* vydelyaem bazovoe imya programmy. */ cmd = basename( argv[0] ); if ( !strcmp( cmd, CP )) cp = 1; else if( !strcmp( cmd, MV )) cp = 0; else{ printf( "%s - wrong program name.\n", cmd ); exit(2); } typeto = filetype( argv[argc-1] ); if(cp && typeto.type != S_IFDIR && typeto.type != S_IFBLK && typeto.type != S_IFCHR && argc > 3){ printf("Group of files can be copied " "to the directory or device only.\n"); exit(3); } if(!cp && typeto.type != S_IFDIR && argc > 3){ printf("Group of files can be moved " "to the directory only.\n"); exit(4); } for(err=0, i=1; i < argc-1; i++) err += ! docpmv(argv[i], argv[argc-1], typeto, cp, &confirm); exit(err); /* 0, esli ne bylo oshibok */ } /* Primer 13 */ /* Obhod dereva katalogov v MS DOS pri pomoshchi smeny tekushchego kataloga. * Analog ls -R v UNIX. Po analogichnomu algoritmu rabotaet programma * find . -print (napishite komandu find, ispol'zuya match()) */ #define STYLE2 #include <stdio.h> #include <stdlib.h> #include <dir.h> #include <dos.h> #include <alloc.h> /* dlya malloc() */ #include <string.h> /* strchr(), strrchr(), strcpy(), ... */ /* prototipy */ char *strend(char *s); char *strdup(const char *s); void action(int, char **); void main(int, char **); int listdir(char *); void printdir(int n); #ifdef STYLE2 void lookdir(char *s, int ac, char **av, register int level); #else void lookdir(char *s, int ac, char **av); #endif char root[256]; /* imya startovogo kataloga */ char cwd[256]; /* polnoe imya tekushchego kataloga */ char *strend(register char *s){ while(*s)s++; return s; } char *strdup(const char *s){ /* prototip malloc v <stdlib.h> */ char *p = (char *) malloc(strlen(s) + 1); if(p) strcpy(p, s); return p; } stop(){ /* Reakciya na control/break */ chdir( root ); /* |to neobhodimo potomu, chto MS DOS imeet (v otlichie ot UNIX) ponyatie "tekushchij katalog" kak global'noe dlya vsej sistemy. Esli my prervem programmu, to okazhemsya ne v tom kataloge, otkuda nachinali. */ printf( "\nInterrupted by ctrl-break\n"); return 0; /* exit */ } void main(int argc, char **argv){ /* poluchit' imya tekushchego kataloga */ (void) getcwd(root, sizeof root); ctrlbrk( stop ); /* ustanovit' reakciyu na ctrl/break */ #ifndef STYLE2 lookdir( "." /* koren' dereva */, argc, argv ); #else /* dlya primera: derevo ot "\\" a ne ot "." */ lookdir( "\\", argc, argv, 0 /* nachal'nyj uroven' */ ); #endif /*STYLE2*/ chdir(root); /* vernut'sya v ish. katalog */ } # ifndef STYLE2 void lookdir(char *s, int ac, char **av){ static int level = 0; /* uroven' rekursii */ # else void lookdir(char *s, int ac, char **av, register int level){ # endif /*STYLE2*/ struct ffblk dblk, *psd = &dblk; register done; if( chdir(s) < 0 ){ /* vojti v katalog */ printf( "Cannot cd %s\n", s ); return; } else if (level == 0){ /* verhnij uroven' */ (void) getcwd(cwd, sizeof cwd); /* poluchit' polnoe imya kornya poddereva */ } action(ac, av); /* iskat' imena katalogov, udovletvoryayushchie shablonu "*" */ /* (ne v alfavitnom poryadke !) */ done = findfirst("*.", psd, FA_DIREC); while( !done ){ if((psd->ff_attrib & FA_DIREC) && psd->ff_name[0] != '.' ){ /* Vidim katalog: vojti v nego! */ char *tail = strend(cwd); char *addplace; if( tail[-1] == '\\' ){ addplace = tail; }else{ *tail = '\\'; addplace = tail+1; } strcpy(addplace, psd->ff_name); #ifndef STYLE2 level++; lookdir( psd->ff_name, ac, av ); level--; #else lookdir( psd->ff_name, ac, av, level+1 ); #endif *tail = '\0'; } /* Iskat' sleduyushchee imya. Informaciya o tochke, gde byl * prervan poisk, hranitsya v dblk */ done = findnext(psd); } if( level ) chdir( ".." ); /* vyjti vverh */ } /* Vypolnit' dejstviya v kataloge */ void action(int ac, char **av){ extern int busy; busy = 0; if( ac == 1 ) listdir( "*.*" ); else{ av++; while( *av ) listdir( *av++ ); } printdir( busy ); } #define MAXF 400 struct fst{ char *name; long size; short attr; } files[MAXF]; int busy; /* skol'ko imen sobrano */ /* Sobrat' imena, udovletvoryayushchie shablonu. */ int listdir( char *picture ){ int done, n; struct ffblk dentry; for(n=0, done=findfirst(picture, &dentry,0xFF /* vse tipy */); busy < MAXF && !done ; done = findnext( &dentry )){ files[busy].name = strdup(dentry.ff_name); files[busy].size = dentry.ff_fsize; files[busy].attr = dentry.ff_attrib; n++; busy++; } return n; } /* int cmp(struct fst *a, struct fst *b) */ /* novye veyaniya v Si trebuyut takogo prototipa: */ int cmp(const void *a, const void *b){ return strcmp(((struct fst *) a) -> name, ((struct fst *) b) -> name ); } /* otsortirovat' i napechatat' */ void printdir(int n){ register i; struct fst *f; qsort( files, n, sizeof files[0], cmp ); printf( "Directory %s\n", cwd ); for( i=0, f = files; i < n; i++, f++ ) printf("\t%-16s\t%10ld\t%c%c%c%c%c%c\n", f->name, f->size, f->attr & FA_DIREC ? 'd':'-', /* directory */ f->attr & FA_RDONLY ? 'r':'-', /* read only */ f->attr & FA_HIDDEN ? 'h':'-', /* hidden */ f->attr & FA_SYSTEM ? 's':'-', /* system */ f->attr & FA_LABEL ? 'l':'-', /* volume label */ f->attr & FA_ARCH ? 'a':'-' /* archive */ ), free(f->name); putchar('\n'); } /* Primer 14 */ /* Demonstraciya raboty s longjmp/setjmp i signalami */ /* Po motivam knigi M.Dansmura i G.Dejvisa. */ #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <setjmp.h> /*#define IGN*/ /* potom otkommentirujte etu stroku */ jmp_buf cs_stack; /* control point */ int in_cs; /* flag, chto my v kriticheskoj sekcii */ int sig_recd; /* flag signal received */ /* aktivnaya zaderzhka */ Delay(){ int i; for( i=0; i < 10000; i++ ){ i += 200; i -= 200; } } interrupt( code ){ fprintf( stderr, "\n\n***\n" ); fprintf( stderr, "*** Obrabatyvaem signal (%s)\n", code == 1 ? "razreshennyj" : "otlozhennyj" ); fprintf( stderr, "***\n\n" ); } /* argument reakcii na signal - nomer signala (podstavlyaetsya sistemoj) */ void mexit( nsig ){ fprintf( stderr, "\nUbili signalom #%d...\n\n", nsig ); exit(0); } void main(){ extern void sig_vec(); int code; int killable = 1; signal( SIGINT, mexit ); signal( SIGQUIT, mexit ); fprintf( stderr, "Dannaya programma perezapuskaetsya po signalu INTR\n" ); fprintf( stderr, "Vyhod iz programmy po signalu QUIT\n\n\n" ); fprintf( stderr, "Sejchas vy eshche mozhete uspet' ubit' etu programmu...\n\n" ); Delay(); Delay(); Delay(); for(;;){ if( code = setjmp( cs_stack )){ /* Vozvrashchaet ne 0, esli vozvrat v etu tochku proizoshel * po longjmp( cs_stack, code ); gde code != 0 */ interrupt( code ); /* prishlo preryvanie */ } /* else setjmp() vozvrashchaet 0, * esli eto USTANOVKA kontrol'noj tochki (to est' * sohranenie registrov SP, PC i drugih v bufer cs_stack), * a ne pryzhok na nee. */ signal( SIGINT, sig_vec ); /* vyzyvat' po preryvaniyu */ if( killable ){ killable = 0; fprintf( stderr, "\7Teper' signaly INTR obrabatyvayutsya osobym obrazom\n\n\n" ); } body(); /* osnovnaya programma */ } } body(){ static int n = 0; int i; fprintf( stderr, "\tVoshli v telo %d-yj raz\n", ++n ); ecs(); for( i=0; i < 10 ; i++ ){ fprintf( stderr, "- %d\n",i); Delay(); } lcs(); for( i=0; i < 10 ; i++ ){ fprintf( stderr, "+ %d\n",i); Delay(); } } /* zapominanie poluchennyh signalov */ void sig_vec(nsig){ if( in_cs ){ /* we're in critical section */ #ifdef IGN signal( SIGINT, SIG_IGN ); /* ignorirovat' */ fprintf( stderr, "Dal'nejshie preryvaniya budut ignorirovat'sya\n" ); #else signal( SIGINT, sig_vec ); fprintf( stderr, "Dal'nejshie preryvaniya budut podschityvat'sya\n" ); #endif fprintf( stderr, "Poluchen signal i otlozhen\n" ); sig_recd++ ; /* signal received */ /* pometit', chto signal prishel */ }else{ signal( SIGINT, sig_vec ); fprintf( stderr, "Poluchen razreshennyj signal: prygaem na restart\n" ); longjmp( cs_stack, 1); } } ecs(){ /* enter critical section */ fprintf( stderr, "Otkladyvaem preryvaniya\n" ); sig_recd = 0; in_cs = 1; } lcs(){ /* leave critical section */ fprintf( stderr, "Razreshaem preryvaniya\n" ); in_cs = 0; if( sig_recd ){ fprintf( stderr, "Prygaem na restart, t.k. est' otlozhennyj signal (%d raz)\n", sig_recd ); sig_recd = 0; signal( SIGINT, sig_vec ); longjmp( cs_stack, 2); } } /* Primer 15 */ /* Komanda dlya izmeneniya skorosti obmena v linii (baud).*/ /* Primer vyzova v XENIX: baud /dev/tty1a 9600 */ /* /dev/tty1a - eto kommunikacionnyj posledov. port #1 */ /* Pro upravlenie modami terminala smotri man termio */ #include <fcntl.h> #include <termio.h> struct termio old, new; int fd = 2; /* stderr */ struct baudrate{ int speed; char *name;} br[] = { { B0, "HANGUP" }, { B1200, "1200" }, { B9600, "9600" }, { B600, "600" }, { B2400, "2400" }, { EXTA, "19200" }, }; #define RATES (sizeof br/sizeof br[0]) main(ac, av) char *av[]; { register i; char *newbaud; if( ac == 3 ){ if((fd = open(av[1], O_RDWR)) < 0 ){ printf("Ne mogu otkryt' %s\n", av[1]); exit(1); } newbaud = av[2]; } else newbaud = av[1]; if( ioctl(fd, TCGETA, &old) < 0 ){ printf("Popytka upravlyat' ne terminalom i ne portom.\n"); exit(2); } if(newbaud == (char*)0) newbaud = "<ne zadano>"; new=old; for(i=0; i < RATES; i++) if((old.c_cflag & CBAUD) == br[i].speed) goto ok; printf("Neizvestnaya skorost'\n"); exit(3); ok: printf("Bylo %s bod\n", br[i].name); for(i=0; i < RATES; i++) if( !strcmp(newbaud, br[i].name)){ new.c_cflag &= ~CBAUD; /* pobitnoe "ili" vseh masok B... */ new.c_cflag |= br[i].speed; if( ioctl(fd, TCSETA, &new) < 0) perror("ioctl"); /* Skorost' obmena mozhet ne izmenit'sya, esli terminal * ne otkryt ni odnim processom (drajver ne inicializirovan). */ exit(0); } printf("Nevernaya skorost' %s\n", newbaud); exit(4); } /* Primer 16 */ /*#!/bin/cc -DUSG wins.c -o wins -lncurses -lx Prosmotr dvuh fajlov v perekryvayushchihsya oknah. Redaktirovanie soderzhimogo okon. */ /* _______________________ fajl wcur.h __________________________ */ #include "curses.h" /* Makrosy, zavisimye ot realizacii curses */ /* chislo kolonok i strok v okne: */ # define wcols(w) ((w)-> _maxx+1 ) # define wlines(w) ((w)-> _maxy+1 ) /* verhnij levyj ugol okna: */ # define wbegx(w) ((w)-> _begx ) # define wbegy(w) ((w)-> _begy ) /* koordinaty kursora v okne: */ # define wcurx(w) ((w)-> _curx ) # define wcury(w) ((w)-> _cury ) /* dostup k pamyati strok okna: */ # define wtext(w) ((w)-> _line) /* chtype **_line; */ /* v drugih realizaciyah: ((w)-> _y) */ /* Psevdografika: Dlya curses Dlya IBM PC MS DOS */ #define HOR_LINE '\200' /* 196 */ #define VER_LINE '\201' /* 179 */ #define UPPER_LEFT '\210' /* 218 */ #define LOWER_LEFT '\202' /* 192 */ #define UPPER_RIGHT '\212' /* 191 */ #define LOWER_RIGHT '\204' /* 217 */ #define LEFT_JOIN '\205' /* 195 */ #define RIGHT_JOIN '\207' /* 180 */ #define TOP_JOIN '\211' /* 194 */ #define BOTTOM_JOIN '\203' /* 193 */ #define MIDDLE_CROSS '\206' /* 197 */ #define BOX '\272' /* 219 */ #define BOX_HATCHED '\273' /* 177 */ #define LABEL '\274' /* 3 */ #define RIGHT_TRIANG '\234' /* 16 */ #define LEFT_TRIANG '\235' /* 17 */ #define YES 1 #define NO 0 #define MIN(a,b) (((a) < (b)) ? (a):(b)) #define MAX(a,b) (((a) > (b)) ? (a):(b)) #define A_ITALICS A_ALTCHARSET /* v etoj versii curses-a - kursiv */ #ifndef ESC # define ESC '\033' /* escape */ #endif #define ctrl(c) (c & 037) /* pererisovka ekrana */ #define RedrawScreen() { vidattr(curscr->_attrs = A_NORMAL); \ wrefresh(curscr); } /* curscr - sluzhebnoe okno - kopiya tekushchego sostoyaniya ekrana displeya * dlya sravneniya so sformirovannym NOVYM obrazom ekrana - newscr. * Pole _attrs v strukture okna soderzhit tekushchie atributy okna, * imenno eto pole izmenyaetsya wattrset(), wattron(), wattroff(); */ /* _______________________ fajl wins.c __________________________ */ #include "wcur.h" #include <signal.h> WINDOW *wbase1, *wbase2; /* okna ramki (fonovye okna) */ WINDOW *w1, *w2; /* okna dlya teksta */ /* Razmery i raspolozhenie okon */ /* COLS - predopredelennaya peremennaya: chislo kolonok */ /* LINES - // - : chislo strok na ekrane */ #define W1ysize (LINES/2) /* vysota */ #define W1xsize (COLS/3*2) /* shirina */ #define W1y 5 /* y verhnego levogo ugla na ekrane */ #define W1x 20 /* x verhnego levogo ugla na ekrane */ #define W2ysize (LINES/2) #define W2xsize (COLS/3*2) #define W2y 10 #define W2x 5 FILE *fp1, *fp2; /* prosmatrivaemye fajly */ /* Zavershit' rabotu */ void die(sig){ /* argument - nomer signala */ /* Vosstanovlenie rezhimov terminala */ echo(); /* eho-otobrazhenie vvodimyh bukv */ nocbreak(); /* vvod s sistemnym redaktirovaniem stroki */ mvcur( -1, -1, LINES-1, 0 ); /* kursor v nizhn. levyj ugol */ endwin(); /* okonchanie raboty s curses-om */ putchar('\n'); exit(sig); /* zavershenie raboty s kodom sig. 0 - uspeshno */ } int run; void stop(nsig){ signal(SIGINT, SIG_IGN); run = 0; beep(); } char label[3][5] = { /* Demonstraciya psevdografiki */ { UPPER_LEFT, TOP_JOIN, UPPER_RIGHT, HOR_LINE, '\0' }, { LEFT_JOIN, MIDDLE_CROSS, RIGHT_JOIN, VER_LINE, '\0' }, { LOWER_LEFT, BOTTOM_JOIN, LOWER_RIGHT, BOX, '\0' } }; /* Narisovat' ramku, nazvanie i fon okna */ wborder( w, name ) WINDOW *w; char *name; { register i, j; for(i=1; i < wlines(w)-1; i++ ){ /* postavit' kursor i vydat' simvol */ mvwaddch(w, i, 0, VER_LINE ); /* mvwaddch(w,y,x,c) = wmove(w,y,x); waddch(w,c); */ /* wmove(w,y,x) - logich. kursor v poziciyu (y,x) */ /* waddch(w,c) - vydat' simvol v pozicii kursora, prodvinut' kursor. Analog putchar */ mvwaddch(w, i, wcols(w)-1, VER_LINE ); } for(j=1; j < wcols(w)-1; j++ ){ mvwaddch(w, 0, j, HOR_LINE ); mvwaddch(w, wlines(w)-1, j, HOR_LINE ); } /* Ugly */ mvwaddch(w, 0, 0, UPPER_LEFT); mvwaddch(w, wlines(w)-1, 0, LOWER_LEFT); mvwaddch(w, wlines(w)-1, wcols(w)-1, LOWER_RIGHT); mvwaddch(w, 0, wcols(w)-1, UPPER_RIGHT); /* Risuem zagolovki vverhu i vnizu na ramke. * Zagolovki vydaem v centre ramki. */ if( (j = (wcols(w) - strlen(name))/2 ) > 0 ){ /* logicheskij kursor - v 0 stroku, poziciyu j */ wmove(w, 0, j); /* zadat' rezhimy vydelenij */ wattrset( w, A_BOLD | A_BLINK | A_REVERSE ); waddstr( w, name ); /* vydat' stroku v okno */ wmove( w, wlines(w)-1, j); wattrset( w, A_ITALICS | A_STANDOUT ); waddstr ( w, name ); wattrset( w, A_NORMAL ); /* normal'nye atributy */ } } /* rezhim redaktirovaniya teksta v oknah */ int mode = 0; /* 0 - zamena, 1 - vstavka */ main( ac, av ) char **av; { char buffer[512]; int need1, need2; int c; void (*save)(); WINDOW *w; /* aktivnoe okno */ if( ac < 3 ){ fprintf( stderr, "Vyzov: %s file1 file2\n", av[0] ); exit( 1 ); } if((fp1 = fopen( av[1], "r" )) == NULL ){ fprintf( stderr, "Ne mogu chitat' %s\n", av[1] ); exit( 2 ); } if((fp2 = fopen( av[2], "r" )) == NULL ){ fprintf( stderr, "Ne mogu chitat' %s\n", av[2] ); exit( 2 ); } /* Inicializirovat' curses */ initscr(); signal( SIGINT, die ); /* po ctrl/C - umeret' */ signal( SIGQUIT,die ); /* Sozdat' okna */ /* vysota shirina Y i X verh.levogo ugla */ wbase1 = newwin( W1ysize, W1xsize, W1y, W1x); if( wbase1 == NULL ){ fprintf( stderr, "Ne mogu sozdat' wbase1\n" ); goto bad; } wbase2 = newwin( W2ysize, W2xsize, W2y, W2x); if( wbase2 == NULL ){ fprintf( stderr, "Ne mogu sozdat' wbase2\n" ); goto bad; } /* Sozdat' podokna dlya teksta */ /* baza vysota shirina Y ugla X ugla */ w1 = subwin( wbase1, W1ysize - 2, W1xsize - 2, W1y+1, W1x+1); w2 = subwin( wbase2, W2ysize - 2, W2xsize - 2, W2y+1, W2x+1); scrollok( w1, TRUE ); /* razreshit' rollirovanie okon */ scrollok( w2, TRUE ); wattrset( w2, A_REVERSE ); /*ustanovit' atributy teksta v oknah*/ wattrset( stdscr, A_STANDOUT ); wborder( wbase1, av[1] ); wborder( wbase2, av[2] ); /* ramki */ werase( w1 ); werase( w2 ); /* ochistit' okna */ /* fon ekrana */ werase( stdscr ); /* funkcii bez bukvy w... rabotayut s oknom stdscr (ves' ekran) */ for(c=0; c < 3; c++) mvwaddstr(stdscr, c, COLS-5, &label[c][0]); move( 1, 10 ); addstr( "F1 - pereklyuchit' okna" ); mvaddstr( 2, 10, "F5 - pereklyuchit' rezhim vstavki/zameny" ); move( 3, 10 ); printw( "F%d - udalit' stroku, F%c - vstavit' stroku", 7, '8' ); mvwprintw(stdscr, 4,10, "ESC - vyhod, CTRL/C - prervat' prosmotr"); /* wprintw(w, fmt, ...) - analog printf dlya okon */ /* V nizhnij pravyj ugol ekrana nichego ne vyvodit': * na nekotoryh terminalah eto rolliruet ekran i tem samym * portit nam kartinku. */ wattrset( stdscr, A_NORMAL ); wmove( stdscr, LINES-1, COLS-1 ); waddch( stdscr, ' ' ); wnoutrefresh( stdscr ); /* virtual'noe proyavlenie okna. */ run = need1 = need2 = 1; /* oba fajla ne dostigli konca */ /* preryvat' prosmotr po CTRL/C */ save = signal(SIGINT, stop); while( run && (need1 || need2)){ if( need1 ){ /* prochest' stroku iz pervogo fajla */ if( fgets( buffer, sizeof buffer, fp1 ) == NULL ) need1 = 0; /* konec fajla */ else{ /* vydat' stroku v okno */ waddstr( w1, buffer ); } } if( need2 ){ /* prochest' stroku iz vtorogo fajla */ if( fgets( buffer, sizeof buffer, fp2 ) == NULL ) need2 = 0; /* konec fajla */ else{ waddstr( w2, buffer ); /* wnoutrefresh( w2 ); */ } } /* Proyavit' w1 poverh w2 */ touchwin( wbase2 ); wnoutrefresh( wbase2 ); touchwin( w2 ); wnoutrefresh( w2 ); touchwin( wbase1 ); wnoutrefresh( wbase1 ); touchwin( w1 ); wnoutrefresh( w1 ); /* touchwin - pometit' okno kak celikom izmenennoe. * wnoutrefresh - perepisat' izmeneniya v novyj obraz * ekrana v pamyati. */ /* Proyavit' izobrazhenie na ekrane terminala * (vyvesti novyj obraz ekrana). Pri etom vyvodyatsya * lish' OTLICHIYA ot tekushchego soderzhimogo ekrana * (s cel'yu optimizacii). */ doupdate(); } fclose(fp1); fclose(fp2); /* vosstanovit' spasennuyu reakciyu na signal */ signal(SIGINT, save); /* Redaktirovanie v oknah */ noecho(); /* vykl. eho-otobrazhenie */ cbreak(); /* nemedlennyj vvod nabrannyh klavish * (bez nazhatiya knopki \n) */ keypad( w1, TRUE ); /* raspoznavat' funkc. knopki */ keypad( w2, TRUE ); scrollok( w1, FALSE ); /* zapretit' rollirovanie okna */ w = w1; /* tekushchee aktivnoe okno */ for( ;; ){ int y, x; /* koordinaty kursora v okne */ wrefresh( w ); /* obnovit' okno. Primerno sootvetstvuet * wnoutrefresh(w);doupdate(); */ c = wgetch( w ); /* vvesti simvol s klaviatury */ /* zametim, chto v rezhime noecho() simvol ne * otobrazitsya v okne bez nashej pomoshchi ! */ getyx( w, y, x ); /* uznat' koordinaty kursora v okne */ /* ne nado &y &x, t.k. eto makros, prevrashchayushchijsya v paru prisvaivanij */ switch( c ){ case KEY_LEFT: /* shag vlevo */ waddch( w, '\b' ); break; case KEY_RIGHT: /* shag vpravo */ wmove( w, y, x+1 ); break; case KEY_UP: /* shag vverh */ wmove( w, y-1, x ); break; case KEY_DOWN: /* shag vniz */ wmove( w, y+1, x ); break; case KEY_HOME: /* v nachalo stroki */ case KEY_LL: /* KEY_END v konec stroki */ { int xbeg, xend; wbegend(w, &xbeg, &xend); wmove(w, y, c==KEY_HOME ? xbeg : xend); break; } case '\t': /* tabulyaciya */ x += 8 - (x % 8); if( x >= wcols( w )) x = wcols(w)-1; wmove(w, y, x); break; case KEY_BACKTAB: /* obratnaya tabulyaciya */ x -= 8 - (x % 8); if( x < 0 ) x = 0; wmove( w, y, x ); break; case '\b': /* zaboj */ case KEY_BACKSPACE: case '\177': if( !x ) break; /* nichego */ wmove( w, y, x-1 ); /* and fall to ... (i provalit'sya v) */ case KEY_DC: /* udalenie nad kursorom */ wdelch( w ); break; case KEY_IC: /* vstavka probela nad kursorom */ winsch( w, ' ' ); break; case KEY_IL: case KEY_F(8): /* vstavka stroki */ winsertln( w ); break; case KEY_DL: /* udalenie stroki */ case KEY_F(7): wdeleteln( w ); break; case ESC: /* ESC - vyhod */ goto out; case KEY_F(1): /* pereklyuchenie aktivnogo okna */ if( w == w1 ){ touchwin( wbase2 ); wnoutrefresh( wbase2 ); touchwin( w2 ); wnoutrefresh( w2 ); w = w2; } else { touchwin( wbase1 ); wnoutrefresh( wbase1 ); touchwin( w1 ); wnoutrefresh( w1 ); w = w1; } break; case KEY_F(5): /* pereklyuchenie rezhima redaktirovaniya */ mode = ! mode; break; case ctrl('A'): /* pererisovka ekrana */ RedrawScreen(); break; case '\n': case '\r': waddch( w, '\n' ); break; default: /* dobavlenie simvola v okno */ if( c >= 0400 ){ beep(); /* gudok */ break; /* funkc. knopka - ne bukva */ } if( mode ){ winsch( w, ' ' ); /* razdvin' stroku */ } waddch( w, c ); /* vydat' simvol v okno */ break; } } out: wrefresh( w ); wsave(w); bad: die(0); /* vyzov bez vozvrata */ } /* Sohranit' soderzhimoe okna v fajl, obrezaya koncevye probely */ wsave(w) WINDOW *w; { FILE *fp = fopen("win.out", "w"); register int x,y, lastnospace; int xs, ys; getyx(w, ys, xs); for( y=0; y < wlines(w); y++ ){ /* poisk poslednego neprobela */ for( lastnospace = (-1), x=0; x < wcols(w); x++ ) /* chitaem simvol iz koordinat (x,y) okna */ if((mvwinch(w,y,x) & A_CHARTEXT) != ' ' ) lastnospace = x; /* zapis' v fajl */ for( x=0 ; x <= lastnospace; x++ ){ wmove(w,y,x); putc( winch(w) & A_CHARTEXT, fp ); } putc( '\n', fp ); } fclose(fp); wmove(w, ys, xs ); /* vernut' kursor na prezhnee mesto */ } /* Na samom dele * winch(w) = wtext(w)[ wcury(w) ][ wcurx(w) ]; * Predlozhim eshche odin, bolee bystryj sposob chteniya pamyati okna * (dlya ZAPISI v okno on neprigoden, t.k. curses eshche * special'nym obrazom pomechaet IZMENENNYE oblasti okon). */ /* Najti nachalo i konec stroki */ int wbegend(w, xbeg, xend) WINDOW *w; int *xbeg, *xend; { /* Tip chtype: 0xFF - kod simvola; 0xFF00 - atributy */ chtype ch, *thisline = wtext(w)[ wcury(w) ]; register x, notset = TRUE; *xbeg = *xend = 0; for(x=0; x < wcols(w); x++) /* & A_CHARTEXT ignoriruet atributy simvola */ if(((ch=thisline[x]) & A_CHARTEXT) != ' '){ if((*xend = x+1) >= wcols(w)) *xend = wcols(w) - 1; if(notset){ notset = FALSE; *xbeg=x; } } return (*xend - *xbeg); } /* Primer 17 */ /* Window management: "stopka" okon * cc -DTEST -DUSG w.c -lncurses -lx * *____ Fajl w.h dlya Primer 17, Primer 19, Primer 21, Primer 23 _____ */ #include "wcur.h" /* Tot zhe, chto v Primer 16 */ extern int botw, topw; extern struct WindowList { /* |lement spiska okon */ WINDOW *w; /* okno */ int next; /* sleduyushchee okno v spiske */ char busy; /* 0:slot svoboden, 1:okno vidimo, -1:okno spryatano */ } wins[]; /* znacheniya polya busy: */ #define W_VISIBLE 1 /* okno vidimo */ #define W_FREE 0 /* slot tablicy svoboden */ #define W_HIDDEN (-1) /* okno spryatano */ #define EOW (-1) #define WIN(n) wins[n].w /* esli sovsem net vidimyh okon... */ #define TOPW (topw != EOW ? WIN(topw) : stdscr) #define BOTW (botw == EOW ? stdscr : WIN(botw)) #define MAXW 15 #define iswindow(n) wins[n].busy int RaiseWin (WINDOW *w); void PopWin (); void DestroyWin(WINDOW *w, int destroy); int HideWin (WINDOW *w); #define KillWin(w) DestroyWin(w, TRUE) #define DropWin(w) DestroyWin(w, FALSE) #define PushWin(w) RaiseWin(w) #define BAR_HOR 01 /* okno imeet gorizontal'nyj scroll bar */ #define BAR_VER 02 /* okno imeet vertikal'nyj scroll bar */ #define DX 2 /* otstup ot kraev okna */ #define BARWIDTH 2 /* shirina scroll bar-a */ #define BARHEIGHT 1 /* vysota */ /* Vychislenie koordinat stroki vybora v okne */ #define WY(title, y) ((y) + (title ? 3 : 1)) #define WX(x) ((x) + 1 + DX) #define XEND(w,scrollok) (wcols(w)-((scrollok & BAR_VER) ? BARWIDTH+2 : 1)) void whorline (WINDOW *w, int y, int x1, int x2); void wverline (WINDOW *w, int x, int y1, int y2); void wbox (WINDOW *w, int x1, int y1, int x2, int y2); void wborder (WINDOW *w); void wboxerase (WINDOW *w, int x1, int y1, int x2, int y2); void WinBorder (WINDOW *w, int bgattrib, int titleattrib, char *title, int scrollok, int clear); void WinScrollBar(WINDOW *w, int whichbar, int n, int among, char *title, int bgattrib); /* Spasenie/vosstanovlenie pozicii kursora */ typedef struct { int x, y; } Point; #define SetPoint(p, yy, xx) { (p).x = (xx); (p).y = (yy);} #define GetBack(p, w) wmove((w), (p).y, (p).x) /* _______________________ fajl w.c _____________________________ */ /* UPRAVLENIE PORYADKOM OKON NA |KRANE */ /* ______________________________________________________________ */ #include "w.h" int botw = EOW, topw = EOW; /* nizhnee i verhnee okna */ struct WindowList wins[MAXW]; /* spisok upravlyaemyh okon */ /* Prochest' simvol iz okna, proyaviv okno (esli ono ne spryatano) */ int WinGetch (WINDOW *win) { register n, dorefr = YES; if(botw != EOW) for(n=botw; n != EOW; n=wins[n].next) if(wins[n].w == win){ if(wins[n].busy == W_HIDDEN) dorefr = NO; /* spryatano */ break; } if( dorefr ) wrefresh (win); /* proyavka */ else doupdate (); for(;;){ n = wgetch (win); /* sobstvenno chtenie */ if( n == ctrl('A')){ RedrawScreen(); continue; } return n; } } /* Vychislit' novoe verhnee okno */ static void ComputeTopWin(){ register n; if(botw == EOW) topw = EOW; /* spisok stal pust */ else{ /* ishchem samoe verhnee vidimoe okno */ for(topw = EOW, n=botw; n != EOW; n=wins[n].next) /* spryatannoe okno ne mozhet byt' verhnim */ if( wins[n].busy == W_VISIBLE) topw = n; /* Mozhet sovsem ne okazat'sya vidimyh okon; togda * topw == EOW, hotya botw != EOW. Makros TOPW predlozhit * v kachestve verhnego okna okno stdscr */ } } /* Virtual'no pererisovat' okna v spiske v poryadke snizu vverh */ static void WinRefresh(){ register nw; /* chistyj fon ekrana */ touchwin(stdscr); wnoutrefresh(stdscr); if(botw != EOW) for(nw=botw; nw != EOW; nw=wins[nw].next) if(wins[nw].busy == W_VISIBLE){ touchwin(wins[nw].w); wnoutrefresh(wins[nw].w); } } /* Isklyuchit' okno iz spiska ne unichtozhaya yachejku */ static int WinDelList(WINDOW *w){ register nw, prev; if(botw == EOW) return EOW; /* spisok pust */ for(prev=EOW, nw=botw; nw != EOW; prev=nw, nw=wins[nw].next) if(wins[nw].w == w){ if(prev == EOW) botw = wins[nw].next; /* bylo dno stopki */ else wins[prev].next = wins[nw].next; return nw; /* nomer yachejki v tablice okon */ } return EOW; /* okna ne bylo v spiske */ } /* Sdelat' okno verhnim, esli ego eshche ne bylo v tablice - zanesti */ int RaiseWin(WINDOW *w){ int nw, n; if((nw = WinDelList(w)) == EOW){ /* ne bylo v spiske */ for(nw=0; nw < MAXW; nw++) /* zanesti v tablicu */ if( !iswindow(nw)){ wins[nw].w = w; break; } if(nw == MAXW){ beep(); return EOW; } /* slishkom mnogo okon */ } /* pomestit' okno nw na vershinu spiska */ if(botw == EOW) botw = nw; else{ for(n = botw; wins[n].next != EOW; n=wins[n].next); wins[n].next = nw; } wins[nw].busy = W_VISIBLE; /* okno vidimo, slot zanyat */ wins[topw = nw].next = EOW; WinRefresh(); return nw; } /* Udalit' okno iz spiska i (vozmozhno) unichtozhit' */ /* Okno pri etom ischeznet s ekrana */ void DestroyWin(WINDOW *w, int destroy){ int nw; if((nw = WinDelList(w)) != EOW){ /* okno bylo v spiske */ ComputeTopWin(); wins[nw].busy = W_FREE; /* yachejka svobodna */ wins[nw].w = NULL; } if(destroy) delwin(w); /* unichtozhit' curses-noe okno */ WinRefresh(); } void PopWin(){ KillWin(TOPW); } /* Spryatat' okno, i pri etom sdelat' ego samym nizhnim. */ int HideWin(WINDOW *w){ register nw, prev; if(botw == EOW) return EOW; /* spisok pust */ for(prev = EOW, nw = botw; nw != EOW; prev = nw, nw = wins[nw].next ) if(wins[nw].w == w){ wnoutrefresh(w); /* vmesto untouchwin(w); */ wins[nw].busy = W_HIDDEN; /* spryatano */ if( nw != botw ){ wins[prev].next = wins[nw].next; /* udalit' iz spiska */ wins[nw].next = botw; botw = nw; /* na dno stopki */ } WinRefresh(); ComputeTopWin(); return nw; } return EOW; /* net v spiske */ } /* _______________ OFORMITELXSKIE RABOTY _____________________ */ /* Narisovat' gorizontal'nuyu liniyu */ void whorline(WINDOW *w, int y, int x1, int x2){ for( ; x1 <= x2; x1++) mvwaddch(w, y, x1, HOR_LINE); } /* Narisovat' vertikal'nuyu liniyu */ void wverline(WINDOW *w, int x, int y1, int y2){ for( ; y1 <= y2; y1++) mvwaddch(w, y1, x, VER_LINE); } /* Narisovat' pryamougol'nuyu ramku */ void wbox(WINDOW *w, int x1, int y1, int x2, int y2){ whorline(w, y1, x1+1, x2-1); whorline(w, y2, x1+1, x2-1); wverline(w, x1, y1+1, y2-1); wverline(w, x2, y1+1, y2-1); /* Ugly */ mvwaddch (w, y1, x1, UPPER_LEFT); mvwaddch (w, y1, x2, UPPER_RIGHT); mvwaddch (w, y2, x1, LOWER_LEFT); /* Nizhnij pravyj ugol nel'zya zanimat' ! */ if(! (wbegx(w) + x2 == COLS-1 && wbegy(w) + y2 == LINES-1)) mvwaddch (w, y2, x2, LOWER_RIGHT); } /* Narisovat' ramku vokrug okna */ void wborder(WINDOW *w){ wbox(w, 0, 0, wcols(w)-1, wlines(w)-1); } /* Ochistit' pryamougol'nuyu oblast' v okne */ void wboxerase(WINDOW *w, int x1, int y1, int x2, int y2){ int x, y; register i, j; getyx(w, y, x); for(i=y1; i <= y2; ++i) for(j=x1; j <= x2; j++) mvwaddch(w, i, j, ' '); wmove(w, y, x); } /* Narisovat' ramku i zagolovok u okna */ void WinBorder (WINDOW *w, int bgattrib, int titleattrib, char *title, int scrollok, int clear){ register x, y; wattrset (w, bgattrib); /* zadat' cvet okna */ if(clear) werase(w); /* zapolnit' okno cvetnymi probelami */ wborder (w); /* narisovat' ramku vokrug okna */ if (title) { /* esli est' zagolovok ... */ for (x = 1; x < wcols (w) - 1; x++){ wattrset(w, bgattrib); mvwaddch (w, 2, x, HOR_LINE); /* ochistka polya zagolovka */ wattrset(w, titleattrib); mvwaddch (w, 1, x, ' '); } wattrset(w, bgattrib); mvwaddch (w, 2, 0, LEFT_JOIN); mvwaddch (w, 2, wcols (w) - 1, RIGHT_JOIN); wattrset (w, A_BOLD | titleattrib); mvwaddstr(w, 1, (wcols(w)-strlen(title))/2, title); wattrset (w, bgattrib); } if (scrollok & BAR_VER) { /* vydelit' stolbec pod scroll bar. */ int ystart = WY(title, 0), xend = XEND(w, scrollok); for (y = ystart; y < wlines (w) - 1; y++) mvwaddch (w, y, xend, VER_LINE); mvwaddch (w, wlines (w)-1, xend, BOTTOM_JOIN); mvwaddch (w, ystart-1, xend, TOP_JOIN); } /* zatychka */ if(wcols(w)==COLS && wlines(w)==LINES){ wattrset(w, A_NORMAL); mvwaddch(w, LINES-1, COLS-1, ' '); } wattrset (w, bgattrib); } /* Narisovat' vertikal'nyj scroll bar (gorizontal'nyj ne sdelan) */ /* Napisano ne ochen' akkuratno */ void WinScrollBar(WINDOW *w, int whichbar, int n, int among, char *title, int bgattrib){ register y, i; int starty = WY(title, 0); int endy = wlines (w) - 1; int x = XEND(w, whichbar) + 1; int height = endy - starty ; if(whichbar & BAR_VER){ /* vertikal'nyj */ wattrset (w, A_NORMAL); for (y = starty; y < endy; y++) for (i = 0; i < BARWIDTH; i++) mvwaddch (w, y, x + i, ' '); y = starty; if(among > 1) y += ((long) (height - BARHEIGHT) * n / (among - 1)); wattron(w, A_BOLD); for (i = 0; i < BARWIDTH; i++) mvwaddch (w, y, x + i, BOX); wattrset(w, bgattrib | A_BOLD ); if( wcols(w) >= 10 ) mvwprintw(w, 0, wcols(w)-9, "%03d/%03d", n+1, among); } wattrset (w, bgattrib); } #ifdef TEST main(){ WINDOW *w[5]; register i, y; initscr(); /* zapustit' curses */ w[0] = newwin(16, 20, 4, 43); /* sozdat' 5 okon */ w[1] = newwin(12, 20, 7, 34); w[2] = newwin(6, 30, 3, 40); w[3] = newwin(7, 35, 12, 38); w[4] = newwin(6, 20, 11, 54); for(i=0; i < 5; i++){ keypad (w[i], TRUE); wattrset(w[i], A_REVERSE); werase(w[i]); wborder (w[i]); mvwprintw(w[i], 1, 2, "Window %d", i); RaiseWin(w[i]); /* sdelat' verhnim oknom */ } noecho(); cbreak(); /* prozrachnyj vvod */ for(;botw != EOW;){ int c; /* narisovat' poryadok okon */ for(i=botw, y=0; y < 5; y++, i=(i==EOW ? EOW : wins[i].next)) mvprintw(8 - y, 5, i==EOW ? "~": "%d%c", i, wins[i].busy == W_HIDDEN ? 'h':' '); mvprintw(9, 5, "topw=%3d botw=%3d", topw, botw); wnoutrefresh(stdscr); /* virt. proyavka etih cifr */ c = WinGetch(TOPW); /* zdes' proishodit doupdate(); * i tol'ko v etot moment kartinka proyavlyaetsya */ switch(c){ case KEY_DC: PopWin(); break; case KEY_IC: KillWin(BOTW); break; case '0': case '1': case '2': case '3': case '4': case '5': c -= '0'; if( !iswindow(c)){ beep(); break; } RaiseWin(WIN(c)); break; case 'D': KillWin(w[2]); break; case 'h': HideWin(BOTW); break; case 'H': HideWin(TOPW); break; case ESC: goto out; default: waddch(TOPW, c & 0377); break; } } mvaddstr(LINES-2, 0, "Bol'she net okon"); refresh(); out: echo(); nocbreak(); endwin(); } #endif /* Primer 18 */ /* _______________________ fajl glob.h ___________________________*/ /* PODDERZHKA SPISKA IMEN FAJLOV ZADANNOGO KATALOGA */ /* ______________________________________________________________ */ #define FILF #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> # define DIR_SIZE 14 extern char *malloc(unsigned); char *strdup(const char *str); extern char *getenv(); extern char *strchr(char *, char), *strrchr(char *, char); #define ISDIR(mode) ((mode & S_IFMT) == S_IFDIR) #define ISDEV(mode) ((mode & S_IFMT) & (S_IFCHR|S_IFBLK)) #define ISREG(mode) ((mode & S_IFMT) == S_IFREG) #define ISEXE(mode) ((mode & S_IFMT) == S_IFREG && (mode & 0111)) #define isdir(st) ISDIR(st.st_mode) #define isdev(st) ISDEV(st.st_mode) #define isreg(st) ISREG(st.st_mode) #define isexe(st) ISEXE(st.st_mode) #define YES 1 #define NO 0 #define I_DIR 0x01 /* eto imya kataloga */ #define I_EXE 0x02 /* eto vypolnyaemyj fajl */ #define I_NOSEL 0x04 /* stroku nel'zya vybrat' */ #define I_SYS (I_DIR | I_EXE | I_NOSEL) /* Skopirovano iz treemk.c * Luchshe prosto napisat' #include "glob.h" v fajle treemk.c */ #define FAILURE (-1) /* kod neudachi */ #define SUCCESS 1 /* kod uspeha */ #define WARNING 0 /* nefatal'naya oshibka */ typedef struct _info { /* struktura elementa kataloga */ char *s; /* imya fajla */ short fl; /* flag */ union _any{ int (*act)(); /* vozmozhno svyazannoe dejstvie */ char *note; /* ili kommentarij */ unsigned i; /* ili eshche kakoj-to parametr */ struct _info *inf; } any; /* vspomogatel'noe pole */ #ifdef FILF /* dopolnitel'nye neobyazatel'nye parametry, poluchaemye iz stat(); */ long size; int uid, gid; unsigned short mode; #endif } Info; typedef union _any Any; extern Info NullInfo; #define MAX_ARGV 256 /* Maksimal'noe chislo imen v kataloge */ typedef struct { /* Soderzhimoe kataloga name */ time_t lastRead; /* vremya poslednego chteniya kataloga */ Info *files; /* soderzhimoe kataloga */ char *name; /* imya kataloga */ ino_t ino; dev_t dev; /* I-uzel i ustrojstvo */ char valid; /* sushchestvuet li etot katalog voobshche */ short readErrors; /* != 0, esli katalog ne chitaetsya */ } DirContents; /* Vidy sortirovki imen v kataloge */ typedef enum { SORT_ASC, SORT_DESC, SORT_SUFX, SORT_NOSORT, SORT_SIZE } Sort; extern Sort sorttype; extern int in_the_root; int gcmps (const void *p1, const void *p2); Info *blkcpy(Info *v); void blkfree(Info *v); Info *glob(char **patvec, char *dirname); Info *glb(char *pattern, char *dirname); int ReadDir(char *dirname, DirContents *d); struct savech{ char *s, c; }; #define SAVE(sv, str) (sv).s = (str); (sv).c = *(str) #define RESTORE(sv) if((sv).s) *(sv).s =