et, rset; /* */ struct timeval timeout, rtimeout; FD_ZERO(&set); nopen = 0; /* */ FD_SET (PP.pfd, &set); nopen++; /* */ FD_SET (STDIN, &set); nopen++; maxfd = max(PP.pfd, STDIN); timeout.tv_sec = 3600; /* */ timeout.tv_usec = 0; /* */ . , 1992-95 - 270 - UNIX nfds = maxfd + 1; while( nopen ){ rset = set; rtimeout = timeout; /* */ if((nready = select( nfds, &rset, NULL, NULL, &rtimeout )) <= 0) continue; for(f=0; f < nfds; f++ ) if( FD_ISSET(f, &rset)){ /* f */ int n; if((n = read(f, buf, sizeof buf)) <= 0 ){ FD_CLR(f, &set); nopen--; /* */ close(f); } else { int fdout; /* */ if( f == PP.pfd ){ fdout = STDOUT; PP.out_bytes += n; if( fpscript ) fwrite(buf, 1, n, fpscript); } else if( f == STDIN ) { fdout = PP.pfd; PP.in_bytes += n; if( halfflag && fpscript ) fwrite(buf, 1, n, fpscript); if( autoecho ) write(STDOUT, buf, n); } write(fdout, buf, n); } } } } . , 1992-95 - 271 - UNIX int main(ac, av) char **av; { while( ac > 1 && *av[1] == '-' ){ switch(av[1][1]){ case 's': scriptflg++; break; case 'f': av++; ac--; protocol = av[1]; scriptflg++; break; case 'h': halfflag++; break; case 'a': autoecho++; break; default: fprintf(stderr, "Bad key %s\n", av[1]); break; } ac--; av++; } if( scriptflg ){ fpscript = fopen( protocol, "w" ); } ac--; av++; wm_init(); PP = wm_ptypair(); if( PP.pfd < 0 ){ fprintf(stderr, "Cannot get pty. Please wait and try again.\n"); return 1; } wm_fixtty(); wm_startshell(ac, av); go++; wm_select(); wm_done(0); /* NOTREACHED */ return 0; } 6.12. . . match " ". . , 1992-95 - 272 - UNIX /* . * : CMD ARG1 ... ARGn <FILE >FILE >>FILE >&FILE >>&FILE * : cc -U42 -DCWDONLY sh.c match.c pwd.c -o sh */ #include <sys/types.h>/* , */ #include <stdio.h> /* / */ #include <signal.h> /* */ #include <fcntl.h> /* O_RDONLY */ #include <errno.h> /* */ #include <ctype.h> /* */ #include <dirent.h> /* BSD 4.2 */ #include <pwd.h> /* /etc/passwd */ #include <sys/wait.h> /* wait() */ char cmd[256]; /* */ #define MAXARGS 256 /* . */ char *arg[MAXARGS]; /* */ char *fin, *fout; /* / */ int rout; /* */ char *firstfound; /* , */ #define LIM ':' /* path */ extern char *malloc(), *getenv(), *strcpy(), *getwd(); extern char *strchr(), *execat(); extern void callshell(), printenv(), setenv(), dowait(), setcwd(); extern struct passwd *getpwuid(); /* */ extern char **environ; /* : * , ev main() */ extern int errno; /* */ char *strdup(s)char *s; { char *p; return(p=malloc(strlen(s)+1), strcpy(p,s)); } /* strcpy() */ char *str3spl(s, p, q) char *s, *p, *q; { char *n = malloc(strlen(s)+strlen(p)+strlen(q)+1); strcpy(n, s); strcat(n, p); strcat(n, q); return n; } int cmps(s1, s2) char **s1, **s2; { return strcmp(*s1, *s2); } . , 1992-95 - 273 - UNIX /* */ #define APPEND 0x01 #define ERRTOO 0x02 int output (name, append, err_too, created) char *name; int *created; { int fd; *created = 0; /* ? */ if( append ){ /* >>file */ /* name ? */ if((fd = open (name, O_WRONLY)) < 0) { if (errno == ENOENT) /* */ goto CREATE; else return 0; /* */ } /* fd == , *created == 0 */ }else{ CREATE: /* ( ) "name" */ if((fd = creat (name, 0666)) < 0 ) return 0; /* */ else *created = 1; /* */ } if (append) lseek (fd, 0l, 2); /* */ /* */ dup2(fd, 1); if( err_too ) dup2(fd, 2); /* err_too=1 >& */ close(fd); return 1; } /* */ int input (name) char *name; { int fd; if((fd = open (name, O_RDONLY)) < 0 ) return 0;/* */ /* */ dup2(fd, 0); close(fd); return 1; } . , 1992-95 - 274 - UNIX /* */ int cmdExec(progr, av, envp, inp, outp, outflg) char *progr; /* */ char **av; /* */ char **envp; /* */ char *inp, *outp; /* - () */ int outflg; /* */ { void (*del)(), (*quit)(); int pid; int cr = 0; del = signal(SIGINT, SIG_IGN); quit = signal(SIGQUIT, SIG_IGN); if( ! (pid = fork())){ /* */ /* () */ signal(SIGINT, SIG_DFL); /* */ signal(SIGQUIT,SIG_DFL); /* */ /* getpid() () */ printf( " pid=%d \n", pid = getpid()); /* - */ if( inp ) if(!input( inp )){ fprintf(stderr, " <%s\n", inp ); goto Err; } if( outp ) if(!output (outp, outflg & APPEND, outflg & ERRTOO, &cr)){ fprintf(stderr, " >%s\n", outp ); goto Err; } /* : * , * main(ac, av, envp) , progr. * ac . */ execvpe(progr, av, envp); Err: /* */ perror(firstfound ? firstfound: progr); /* free(firstfound),firstfound = NULL * ( * ) : */ if( cr && outp ) /* */ unlink(outp); /* */ exit(errno); } /* - */ /* , wait * */ dowait(); /* */ /* */ signal(SIGINT, del); signal(SIGQUIT, quit); return pid; /* */ } . , 1992-95 - 275 - UNIX /* PATH */ int execvpe(progr, av, envp) char *progr, **av, **envp; { char *path, *cp; int try = 1; register eacces = 0; char fullpath[256]; /* */ firstfound = NULL; if((path = getenv("PATH")) == NULL ) path = ".:/bin:/usr/bin:/etc"; /* : ? */ cp = strchr(progr, '/') ? "" : path; do{ /* */ cp = execat(cp, progr, fullpath); retry: fprintf(stderr, " \"%s\"\n", fullpath ); execve(fullpath, av, envp); /* , * . - . */ switch( errno ){ /* ? */ case ENOEXEC: /* */ callshell(fullpath, av, envp); return (-1); case ETXTBSY: /* */ if( ++try > 5 ) return (-1); sleep(try); goto retry; case EACCES: /* */ if(firstfound == NULL) firstfound = strdup(fullpath); eacces++; break; case ENOMEM: /* */ case E2BIG: return (-1); } }while( cp ); if( eacces ) errno = EACCES; return (-1); } /* path name */ static char *execat(path, name, buf) register char *path, *name; char *buf; /* */ { register char *s = buf; while(*path && *path != LIM ) *s++ = *path++; /* */ if( s != buf ) *s++ = '/'; while( *name ) *s++ = *name++; /* */ *s = '\0'; return ( *path ? ++path /* LIM */ : NULL ); } . , 1992-95 - 276 - UNIX /* */ void callshell(progr, av, envp) char *progr, **av, **envp; { register i; char *sh; char *newav[MAXARGS+2]; int fd; char first = 0; if((fd = open(progr, O_RDONLY)) < 0 ) sh = "/bin/sh"; else{ read(fd, &first, 1); close(fd); sh = (first == '#') ? "/bin/csh" : "/bin/sh"; } newav[0] = "Shellscript"; newav[1] = progr; for(i=1; av[i]; i++) newav[i+1] = av[i]; newav[i+1] = NULL; printf( " %s\n", sh ); execve(sh, newav, envp); } /* , . */ void dowait(){ int ws; int pid; while((pid = wait( &ws)) > 0 ){ if( WIFEXITED(ws)){ printf( " %d %d\n", pid, WEXITSTATUS(ws)); }else if( WIFSIGNALED(ws)){ printf( " %d %d\n", pid, WTERMSIG(ws)); if(WCOREDUMP(ws)) printf( " core\n" ); /* core - adb */ }else if( WIFSTOPPED(ws)){ printf( " %d %d\n", pid, WSTOPSIG(ws)); } } } . , 1992-95 - 277 - UNIX /* . , * . */ void glob(dir, args, indx, str /* */, quote ) char *args[], *dir; int *indx; char *str; char quote; /* , str */ { static char globchars[] = "*?["; char *p; char **start = &args[ *indx ]; short nglobbed = 0; register struct dirent *dirbuf; DIR *fd; extern DIR *opendir(); /* : */ if( *str == '\\' ){ str++; goto noGlob; } /* $NAME */ if( *str == '$' && quote != '\'' ){ char *s = getenv(str+1); if( s ) str = s; } /* : */ if( quote ) goto noGlob; for( p=str; *p; p++ ) /* ? */ if( strchr(globchars, *p)) goto doGlobbing; noGlob: args[ (*indx)++ ] = strdup(str); return; doGlobbing: if((fd = opendir (dir)) == NULL){ fprintf(stderr, "Can't read %s\n", dir); return; } while ((dirbuf = readdir (fd)) != NULL ) { if (dirbuf->d_ino == 0) continue; if (strcmp (dirbuf->d_name, ".") == 0 || strcmp (dirbuf->d_name, "..") == 0) continue; if( match( dirbuf->d_name, str)){ args[ (*indx)++ ] = strdup(dirbuf->d_name); nglobbed++; } } closedir(fd); if( !nglobbed){ printf( "%s: no match\n", str); goto noGlob; }else{ /* */ qsort(start, nglobbed, sizeof (char *), cmps); } } . , 1992-95 - 278 - UNIX /* */ int parse(s) register char *s; { int i; register char *p; char tmp[80]; /* */ char c; /* */ for(i=0; arg[i]; i++) free(arg[i]), arg[i] = NULL; if( fin ) free(fin ), fin = NULL; if( fout ) free(fout), fout = NULL; rout = 0; /* */ for( i=0 ;; ){ char quote = '\0'; /* - */ while((c = *s) && isspace(c)) s++; if( !c ) break; /* */ p = tmp; if(*s == '\'' || *s == '"' ){ /* */ quote = *s++; /* */ while((c = *s) != '\0' && c != quote){ if( c == '\\' ){ /* */ c = *++s; if( !c ) break; } *p++ = c; ++s; } if(c == '\0') fprintf(stderr, " %c\n", quote); else s++; /* */ . , 1992-95 - 279 - UNIX } else while((c = *s) && !isspace(c)){ if(c == '\\') /* */ if( !(c = *++s)) break /* while */; *p++ = c; s++; } *p = '\0'; /* , * /. sh csh * > < * >< . */ p = tmp; /* */ if( *p == '>'){ /* */ p++; if( fout ) free(fout), rout = 0; /* */ if( *p == '>' ){ rout |= APPEND; p++; } if( *p == '&' ){ rout |= ERRTOO; p++; } if( !*p ){ fprintf(stderr, " >\n"); fout = NULL; rout = 0; } else fout = strdup(p); } else if( *p == '<' ){ /* */ p++; if( fin ) free(fin); /* */ if( !*p ){ fprintf(stderr, " <\n"); fin = NULL; } else fin = strdup(p); } else /* */ glob( ".", arg, &i, p, quote ); } arg[i] = NULL; return i; } /* */ void setuser(){ int uid = getuid(); /* , */ char *user = "mr. Nobody"; /* */ char *home = "/tmp"; /* */ struct passwd *pp = getpwuid( uid ); if( pp != NULL ){ if(pp->pw_name && *pp->pw_name ) user = pp->pw_name; if( *pp->pw_dir ) home = pp->pw_dir; } setenv("USER", user); setenv("HOME", home); } void setcwd(){ /* */ char cwd[512]; getwd(cwd); setenv( "CWD", cwd ); } . , 1992-95 - 280 - UNIX void main(ac, av, ev) char *av[], *ev[]; { int argc; /* */ char *prompt; /* */ setuser(); setcwd(); signal(SIGINT, SIG_IGN); setbuf(stdout, NULL); /* */ for(;;){ prompt = getenv( "prompt" ); /* setenv prompt -->\ */ printf( prompt ? prompt : "@ ");/* */ if( gets(cmd) == NULL /* at EOF */ ) exit(0); argc = parse(cmd); if( !argc) continue; if( !strcmp(arg[0], "exit" )) exit(0); if( !strcmp(arg[0], "cd" )){ char *d = (argc==1) ? getenv("HOME"):arg[1]; if(chdir(d) < 0) printf( " %s\n", d ); else setcwd(); continue; } if( !strcmp(arg[0], "echo" )){ register i; FILE *fp; if( fout ){ if((fp = fopen(fout, rout & APPEND ? "a":"w")) == NULL) continue; } else fp = stdout; for(i=1; i < argc; i++ ) fprintf( fp, "%s%s", arg[i], i == argc-1 ? "\n":" "); if( fp != stdout ) fclose(fp); continue; } if( !strcmp(arg[0], "setenv" )){ if( argc == 1 ) printenv(); else if( argc == 2 ) setenv( arg[1], "" ); else setenv( arg[1], arg[2]); continue; } cmdExec(arg[0], (char **) arg, environ, fin, fout, rout); } } . , 1992-95 - 281 - UNIX /* -----------------------------------------------------------*/ /* */ void printenv(){ char *e[40]; register i = 0; char *p, **q = e; do{ p = e[i] = environ[i]; i++; } while( p ); #ifdef SORT qsort( e, --i /* */, sizeof(char *), cmps); #endif while( *q ) printf( "%s\n", *q++ ); } /* name */ static char *envcmp(name, evstr) char *name, *evstr; { char *p; int code; if((p = strchr(evstr, '=')) == NULL ) return NULL; /* error ! */ *p = '\0'; /* */ code = strcmp(name, evstr); *p = '='; /* */ return code==0 ? p+1 : NULL; } /* */ void setenv( name, value ) char *name, *value; { static malloced = 0; /* 1, environ */ char *s, **p, **newenv; int len, change_at = (-1), i; /* name environ- ? */ for(p = environ; *p; p++ ) if(s = envcmp(name, *p)){ /* */ if((len = strlen(s)) >= strlen(value)){ /* */ strcpy(s, value); return; } /* environ ... */ if( malloced ){ free( *p ); *p = str3spl(name, "=", value); return; } /* environ- */ change_at = p - environ; /* */ break; } . , 1992-95 - 282 - UNIX /* environ-. change_at == (-1), * */ for(p=environ, len=0; *p; p++, len++ ); /* */ if( change_at < 0 ) len++; if((newenv = (char **) malloc( sizeof(char *) * (len+1))) == (char **) NULL) return; for(i=0; i < len+1; i++ ) newenv[i] = NULL; /* */ /* environ */ if( !malloced ) /* environ ( ) */ for(i=0; environ[i]; i++ ) newenv[i] = strdup(environ[i]); else for(i=0; environ[i]; i++ ) newenv[i] = environ[i]; /* , */ /* , : */ if( change_at >= 0 ){ free( newenv[change_at] ); newenv[change_at] = str3spl(name, "=", value); } else { /* */ newenv[len-1] = str3spl(name, "=", value); } /* environ */ if( malloced ) free( environ ); environ = newenv; malloced++; qsort( environ, len, sizeof(char *), cmps); } /* : unsetenv _ - ; exit N - N ( ); */ . , 1992-95 - 283 - UNIX 7. . " " ( " ") - , - , , , , - , , , ... 7.1. , "" . "", . , list.txt 7.2. , . 7.3. , , - /  . . 7.4. . - , , . "- " , , : #include <ctype.h> #include <stdio.h> const int YES=1, NO=0; main(){ register int inWord = NO; /* */ int words = 0, c; while((c = getchar()) != EOF) if(isspace(c) || c == '\n') inWord = NO; else if(inWord == NO){ inWord = YES; ++words; } printf("%d \n", words); } const. . - #define YES 1 - , ..  ; - ; - . main(){ /* cc 00.c -o 00 -lm */ double sqrt(double); const double sq12 = sqrt(12.0); #define SQRT2 sqrt(2.0) double x; x = sq12 * sq12 * SQRT2 * SQRT2; /* @1 */ sq12 = 3.4641; /* @2 */ printf("%g %g\n", sq12, x); } #define @1 x = sq12 * sq12 * sqrt(2.0) * sqrt(2.0); sqrt. const . . , 1992-95 - 284 - UNIX , @2 - . , - isWord, . - ( ): #include <ctype.h> #include <stdio.h> int wordLength, inWord, words; /* = 0 */ char aWord[128], *wrd; void space (c){} void letter (c){ wordLength++; *wrd++ = c; } void begWord(c){ wordLength=0; inWord=1; wrd=aWord; words++; letter(c); } void endWord(c){ inWord=0; *wrd = '\0'; printf(" '%s' %d\n", aWord, wordLength); } void (*sw[2][2])() = { /* !isWord */ { space, endWord }, /* isWord */ { begWord, letter } /* !inWord inWord */ }; #define isWord(c) (isalnum(c) || c=='-' || c=='_') main(){ register c; while((c = getchar()) != EOF) (*sw[isWord(c)][inWord])(c); printf("%d \n", words); } 7.5. , (.. : 0 -, 1 - -, ..., ). 7.6. , in out. 7.7. , , . 7.8. , . 7.9. , - , . : (malloc) ; - . : . : ; . 7.10. , , - . . 7.11. , . . , 1992-95 - 285 - UNIX 7.12. , . uniq UNIX. : #include <stdio.h> /* char *gets(); */ char buf1[4096], buf2[4096]; char *this = buf1, *prev = buf2; main(){ long nline =0L; char *tmp; while( gets(this)){ if(nline){ /* */ if( strcmp(this, prev)) /* ? */ puts(prev); } /* : */ tmp=prev; prev=this; this=tmp; nline++; /* */ }/* endwhile */ if( nline ) puts(prev); /* */ } 7.13. , ( ) , , . 7.14. , . ( - , !), , : /* */ void untab(s) register char *s; { char newstr[256]; /* */ char *src = s; int n; /* */ register dstx; /* x */ for(dstx = 0; *s != '\0'; s++) if( *s == '\t'){ for(n = 8 - dstx % 8 ; n > 0 ; n--) newstr[dstx++] = ' '; }else newstr[dstx++] = *s; newstr[dstx] = '\0'; strcpy(src, newstr); /* */ } 7.15. , . . , 1992-95 - 286 - UNIX void tabify(){ int chr; int icol, ocol; /* input/output columns */ for(icol = ocol = 0; ; ){ if((chr = getchar()) == EOF) break; switch(chr){ case ' ': icol++; break; case '\n': case '\r': ocol = icol = 0; putchar(chr); break; case '\t': icol += 8; icol &= ~07; /* icol -= icol % 8; */ break; default: while(((ocol + 8) & ~07) <= icol){ #ifdef NOTDEF if(ocol + 1 == icol) break; /* ' ' '\t' */ #endif putchar('\t'); ocol += 8; ocol &= ~07; } while(ocol < icol){ putchar(' '); ocol++; } putchar(chr); icol++; ocol++; break; } } } 7.16. , . , - ! 7.17. , 60 . . . , 1992-95 - 287 - UNIX 7.18. , - , 60 . 7.19. , . ( ). 60. 7.20. , , .. , 40- (, 80 ). 7.21. , n ( n ). , n ( ). #include <stdio.h> /* ... untab(); ... */ void process(char name[], int n, int spacesOnly){ char line[256]; int length, shift, nline = 0; char newname[128]; FILE *fpin, *fpout; if((fpin = fopen(name, "r")) == NULL){ fprintf(stderr, " %s\n", name); return; } sprintf(newname, "_%s", name); /* */ if((fpout = fopen(newname, "w")) == NULL){ fprintf(stderr, " %s\n", newname); fclose(fpin); return; } while(fgets(line, sizeof line, fpin)){ ++nline; if((length = strlen(line)) && line[length-1] == '\n') line[--length] = '\0'; /* '\n' */ untab(line); /* */ for(shift=0; line[shift] != '\0' && shift < n ; ++shift) if(spacesOnly && line[shift] != ' ') break; if(*line && shift != n ) /* */ fprintf(stderr, " #%d \n", nline); fprintf(fpout, "%s\n", line+shift); /* fputs(line+n, fpout); * .. */ } fclose(fpin); fclose(fpout); } void main(int argc, char **argv){ if( argc != 3 ) exit(1); process(argv[2], atoi(argv[1]) /* 8 */, 1); exit(0); } 7.22. , : - , - . main(). - 40 . 7.23. . , strcmp() , . , , ! . , 1992-95 - 288 - UNIX , , strcmp(). 7.24. , . 7.25. ( ). /* : dihotomia */ #include <stdio.h> struct elem { char *name; /* */ int value; } table[] = { /* */ { "andrew", 17 }, { "bill", 23 }, { "george", 55 }, { "jack", 54 }, { "jaw", 43 }, { "john", 33 }, { "mike", 99 }, { "paul", 21 }, { "sue", 66 }, /* SIZE - 2 */ { NULL, -1 }, /* SIZE - 1 */ /* NULL */ }; #define SIZE (sizeof(table) / sizeof(struct elem)) /* */ struct elem *find(s, table, size) char *s; /* ? */ struct elem table[]; /* ? */ int size; /* size */ { register top, bottom, middle; register code; top = 0; /* */ bottom = size - 1; /* : "sue" */ while( top <= bottom ){ middle = (top + bottom) / 2; /* */ /* */ code = strcmp( s, table[middle].name ) ; if( code > 0 ){ top = middle + 1; }else if( code < 0 ){ bottom = middle - 1; }else return &table[ middle ]; } return (struct elem *) NULL; /* */ } . , 1992-95 - 289 - UNIX /* */ void printtable(tbl) register struct elem *tbl; { for( ; tbl->name != NULL ; tbl++ ){