doit( A_INT, 123, A_STR, " hello, ", A_INT, 456, A_STR, " world\n", A_NULL ); return 0; } 7.39. . - , : struct data { int b_key; /* */ char b_data[ DATALEN ]; /* */ }; : - - - ( ) - . (.. ). . fread, fwrite, fseek. n- : fseek( fp, (long) n * sizeof(struct data), 0 ); , , . , 1992-95 - 309 - UNIX char b_key[ KEYLEN ]; - KEYLEN , '\0', - KEYLEN '\0' ( d_name ). , - (hash - , . ). . struct record_header { int b_key ; /* */ long b_offset; /* */ int b_length; /* () */ }; . . b_offset . , fseek b_offset b_length . 7.40.  .  (). : - ( ), , ( , ), - , ( !). () ( ) , short. : ( - ) . . , , : . : 1 - , 0 - - . 7.41. match(,); - . : * - (0 ); ? - . : [] - . [!] - , . [h-z] - h z . : "" - . , , , (, "[]**"). , , . . , 1992-95 - 310 - UNIX #include <stdio.h> #include <string.h> #include <locale.h> #define U(c) ((c) & 0377) /* */ #define QUOT '\\' /* */ #ifndef MATCH_ERR # define MATCH_ERR printf(" ]\n") #endif /* s - * p - . \ . */ int match (register char *s, register char *p) { register int scc; /* */ int c, cc, lc; /* lc - [...] */ int ok, notflag; for (;;) { scc = U(*s++); /* */ switch (c = U (*p++)) { /* */ case QUOT: /* a*\*b */ c = U (*p++); if( c == 0 ) return(0); /* : pattern\ */ else goto def; case '[': /* */ ok = notflag = 0; lc = 077777; /* */ if(*p == '!'){ notflag=1; p++; } while (cc = U (*p++)) { if (cc == ']') { /* */ if (ok) break; /* */ return (0); /* */ } if (cc == '-') { /* */ if (notflag){ /* - OK */ if (!syinsy (lc, scc, U (*p++))) ok++; /* - */ else return (0); } else { /* - OK */ if (syinsy (lc, scc, U (*p++))) ok++; } } else { if (cc == QUOT){ /* [\[\]] */ cc = U(*p++); if(!cc) return(0);/* */ } if (notflag){ if (scc && scc != (lc = cc)) ok++; /* */ else return (0); } else { . , 1992-95 - 311 - UNIX if (scc == (lc = cc)) /* */ ok++; } } } if (cc == 0){ /* */ MATCH_ERR; return (0); /* */ } continue; case '*': /* */ if (!*p) return (1); for (s--; *s; s++) if (match (s, p)) return (1); return (0); case 0: return (scc == 0); default: def: if (c != scc) return (0); continue; case '?': /* */ if (scc == 0) return (0); continue; } } } /* , smy smax smin */ int syinsy (unsigned smin, unsigned smy, unsigned smax) { char left [2]; char right [2]; char middle [2]; left [0] = smin; left [1] = '\0'; right [0] = smax; right [1] = '\0'; middle[0] = smy; middle[1] = '\0'; return (strcoll(left, middle) <= 0 && strcoll(middle, right) <= 0); } , UNIX , *.c, ( MS DOS), - (shell: /bin/sh, /bin/csh, /bin/ksh). ( ) . 7.42. man regexp include- /usr/include/regexp.h, compile step ed, lex, grep: C \. \[ \* \$ \^ \\ ; . , 1992-95 - 312 - UNIX . \n; [abc] [a-b] ( ); [abc-] -; []abc] [] ] ; [^a-z] ^ , ..  ; [a-z^] ; [\*.] [] , ; C* (0 ) C; .* ; * (0 ) , [0-9]* ( ) .  ; \{n,m\} n m (), 255; \{n,\} n , [0-9]\{1,\} ; \{n\} n ; $ ,  , .*define.*\\$ ^ ,  ; \n ; \(.....\) . ; \N N . N- ( 1). matchReg, . , matchReg . : #include <stdio.h> #include <ctype.h> #define INIT register char *sp = instring; #define GETC() (*sp++) #define PEEKC() (*sp) #define UNGETC(c) (--sp) #define RETURN(ptr) return #define ERROR(code) \ {fprintf(stderr,"%s:ERR%d\n",instring,code);exit(177);} # include <regexp.h> #define EOL '\0' /* end of line */ #define ESIZE 512 int matchReg(char *str, char *pattern){ static char oldPattern[256]; static char compiledExpr[ESIZE]; if( strcmp(pattern, oldPattern)){ /* */ /* compile regular expression */ compile(pattern, compiledExpr, &compiledExpr[ESIZE], EOL); . , 1992-95 - 313 - UNIX strcpy(oldPattern, pattern); /* */ } return step(str, compiledExpr); /* */ } /* : reg '^int' 'int$' char | less */ /* reg 'putchar.*(.*)' < reg.c | more */ void main(int ac, char **av){ char inputline[BUFSIZ]; register i; while(gets(inputline)){ for(i=1; i < ac; i++) if(matchReg(inputline, av[i])){ char *p; extern char *loc1, *loc2; /*printf("%s\n", inputline);*/ /* , * */ for(p=inputline; p != loc1; p++) putchar(*p); for( ; p != loc2; p++) if(isspace((unsigned char) *p)) putchar(*p); else printf("%c\b%c", *p, *p); for( ; *p; p++) putchar(*p); putchar('\n'); break; } } } 7.43. <regexp.h> , . - . : $ regsub '\([0-9]\{1,\}\)' '(\1)' $ regsub 'f(\(.*\),\(.*\))' 'f(\2,\1)' < file f(a,b) f(b,a). , - \(...\), \N , N - , . \, : \\. . , 1992-95 - 314 - UNIX /* */ #include <stdio.h> #include <ctype.h> #define INIT register char *sp = instring; #define GETC() (*sp++) #define PEEKC() (*sp) #define UNGETC(c) (--sp) #define RETURN(ptr) return #define ERROR(code) regerr(code) void regerr(); # include <regexp.h> #define EOL '\0' /* end of line */ #define ESIZE 512 short all = 0; /* -a , (global, all): * regsub -a int INT * "aa int bbb int cccc" -> "aa INT bbb INT cccc" * * step() , , * regsub 'f(\(.*\),\(.*\))' 'f(\2,\1)' * "aa f(1,2) bb f(3,4) cc" -> "aa f(4,1,2) bb f(3) cc' * |___________|_| |_|___________| */ char compiled[ESIZE], line[512]; . , 1992-95 - 315 - UNIX void main(int ac, char *av[]){ register char *s, *p; register n; extern int nbra; extern char *braslist[], *braelist[], *loc1, *loc2; if( ac > 1 && !strcmp(av[1], "-a")){ ac--; av++; all++; } if(ac != 3){ fprintf(stderr, "Usage: %s [-a] pattern subst\n", av[0]); exit(1); } compile(av[1], compiled, compiled + sizeof compiled, EOL); while( gets(line) != NULL ){ if( !step(s = line, compiled)){ printf("%s\n", line); continue; } do{ /* */ for( ; s != loc1; s++) putchar(*s); /* */ for(s=av[2]; *s; s++) if(*s == '\\'){ if(isdigit(s[1])){ /* */ int num = *++s - '1'; if(num < 0 || num >= nbra){ fprintf(stderr, "Bad block number %d\n", num+1); exit(2); } for(p=braslist[num]; p != braelist[num]; ++p) putchar(*p); } else if(s[1] == '&'){ ++s; /* */ for(p=loc1; p != loc2; ++p) putchar(*p); } else putchar(*++s); } else putchar(*s); } while(all && step(s = loc2, compiled)); /* */ for(s=loc2; *s; s++) putchar(*s); putchar('\n'); } /* endwhile */ } . , 1992-95 - 316 - UNIX void regerr(int code){ char *msg; switch(code){ case 11: msg = "Range endpoint too large."; break; case 16: msg = "Bad number."; break; case 25: msg = "\\digit out of range."; break; case 36: msg = "Illegal or missing delimiter."; break; case 41: msg = "No remembered search string."; break; case 42: msg = "\\(~\\) imbalance."; break; case 43: msg = "Too many \\(."; break; case 44: msg = "More than 2 numbers given in \\{~\\\"}."; break; case 45: msg = "} expected after \\."; break; case 46: msg = "First number exceeds second in \\{~\\}."; break; case 49: msg = "[ ] imbalance."; break; case 50: msg = "Regular expression overflow."; break; default: msg = "Unknown error"; break; } fputs(msg, stderr); fputc('\n', stderr); exit(code); } void prfields(){ int i; for(i=0; i < nbra; i++) prfield(i); } void prfield(int n){ char *fbeg = braslist[n], *fend = braelist[n]; printf("\\%d='", n+1); for(; fbeg != fend; fbeg++) putchar(*fbeg); printf("'\n"); } 7.44. . , . ( ) , . main(). /* . * . , . , 1976 Texas * : Communications of the ACM 20, 10 (Oct., 1977), 762-772 * * * , - * strlen(str). * , * , . * slen/plen . */ char *pattern; /* ( ) */ static int plen; /* */ static int d[256]; /* ; ASCII - * 256 . */ /* i */ #define DISTANCE(i) ((plen-1) - (i)) . , 1992-95 - 317 - UNIX /* : * pattern str, * -1, */ int indexBM( str ) char *str; /* */ { int slen = strlen(str); /* */ register int pindx; /* */ register int cmppos; /* */ register int endpos; /* , "" * */ /* */ for( endpos = plen-1; endpos < slen ; ){ /* : pr(str, pattern, endpos - (plen-1), 0); /**/ /* */ for( cmppos = endpos, pindx = (plen - 1); pindx >= 0 ; cmppos--, pindx-- ) if( str[cmppos] != pattern[pindx] ){ /* , * str[endpos] endpos- * . * ( ), * endpos+1 * */ endpos += d[ str[endpos] & 0377 ]; break; /* & 0377 . */ } /* char -> unsigned char */ if( pindx < 0 ) return ( endpos - (plen-1)); /* : */ } return( -1 ); /* */ } . , 1992-95 - 318 - UNIX /* */ void compilePatternBM( ptrn ) char *ptrn; { register int c; pattern = ptrn; plen = strlen(ptrn); /* c - */ for(c = 0; c < 256; c++) d[c] = plen; /* */ /* c - */ for(c = 0; c < plen - 1; c++) d[ pattern[c] & 0377 ] = DISTANCE(c); /* * ( ) * . * , , * ( ) . */ } /* */ void pr(s, p, n, nl) char *s, *p; { register i; printf("%4d\t%s\n", nl, s ); printf(" \t"); for(i = 0; i < n; i++ ) putchar( s[i] == '\t' ? '\t' : ' ' ); printf( "%s\n", p ); } /* fgrep */ #include <stdio.h> char str[ 1024 ]; /* */ void main(ac, av) char **av; { int nline = 0; /* */ int ind; int retcode = 1; if(ac != 2){ fprintf(stderr, "Usage: %s 'pattern'\n", av[0] ); exit(33); } compilePatternBM( av[1] ); while( gets(str) != NULL ){ nline++; if((ind = indexBM(str)) >= 0 ){ retcode = 0; /* O'KAY */ pr(str, pattern, ind, nline); } } exit(retcode); } . , 1992-95 - 319 - UNIX /* : peter piper picked a peck of pickled peppers. peck peter piper picked a peck of pickled peppers. peck peter piper picked a peck of pickled peppers. peck peter piper picked a peck of pickled peppers. peck peter piper picked a peck of pickled peppers. peck peter piper picked a peck of pickled peppers. peck peter piper picked a peck of pickled peppers. peck peter piper picked a peck of pickled peppers. peck */ 7.45. , , - , main(). match, . grep UNIX ( , ). 7.46. expand(s1, s2), a-z s1 abcd...xyz s2. . a-b-c, a-z0-9 -a-g ( , "-", , - ). 7.47. , |<1 ><> |.pp |<> ( | , a <> - ). - - , nroff ( UNIX). : - , , \&<,   '> - , , .ip <> <> - \ \e. - .,;:!?) ( - , . - ,  ?). - , nroff : ....xxxx - => ....xxxx   yyyy...... yyyy................ . , 1992-95 - 320 - UNIX : $ prep ... | nroff -me > text.lp 7.48. , , (- ). . : <ctype.h>. : #include <ctype.h> #include <stdio.h> main(){ int c; while( (c = getchar()) != EOF ) putchar( isalpha( c ) ? (isupper( c ) ? tolower( c ) : c) : c); } ... putchar( isalpha(c) && isupper(c) ? tolower(c) : c ); putchar( isupper(c) ? tolower(c) : c ); isupper islower (, !). 7.49. , , : char ch; if( 0300 <= ch && ch < 0340 ) ...; ( -8 ), - : ch int ( char ). , ch (0200), ( ).  ! : char c = '\201'; /* = 129 */ printf( "%d\n", c ); -127. , , .. ch < 0. : if( 0300 <= (ch & 0377) && (ch & 0377) < 0340) ...; (0377 - 8 , 0xFF, ), unsigned char ch; , int . 7.50. : . , 1992-95 - 321 - UNIX main(){ char ch; /* 0377 - ASCII */ for (ch = 0100; ch <= 0377; ch++ ) printf( "%03o %s\n", ch & 0377, ch >= 0300 && ch < 0340 ? "yes" : "no" ); } ? - -, 0200 ch , ch -  (.. int ), "no". , unsigned char ch, ch (ch & 0377) ((unsigned) ch) - -, . ch =='\377'. ch <= 0377 . ch++. ch - , 0400 (0377 - , - ). ch 0. 0 < 0377 ! ; .. - . int ch; 0377+1 0400, 0 ( unsigned int, , 0377). 7.51. , , , . - , - . . . --> . . , , , . 7.52. , (spell check): ; - . - , - - . : - : =>; - (): =>; - : =>; - : =>; - : =>; - - , : 񎂎=>; . . : match: _ = ""; if(strlen(_) <= strlen(_)+1 && match(_, "****") ... /* */ *** ? ? *** ? *** ? : . , 1992-95 - 322 - UNIX #include <stdio.h> #include <ctype.h> #include <locale.h> typedef unsigned char uchar; #define ANYCHAR '*' /* , */ static uchar version[120]; /* */ static uchar vv; /* , ANYCHAR */ /* */ static uchar icase(uchar c){ return isupper(c) ? tolower(c) : c; } /* */ static int eqi(uchar *s1, uchar *s2 ) { while( *s1 && *s2 ){ if( icase( *s1 ) != icase( *s2 )) break; s1++; s2++; } return ( ! *s1 && ! *s2 ) ? 1 : 0 ; /* OK : FAIL */ } /* ANYCHAR */ static strok(register uchar *word, register uchar *pat) { while( *word && *pat ){ if( *word == ANYCHAR){ /* , *pat, */ vv= *pat; } else { if( icase(*pat) != icase(*word) ) break; } word++; pat++; } /* ... */ return ( !*word && !*pat) ? 1 : 0; /* OK : FAIL */ } . , 1992-95 - 323 - UNIX /* */ static int superfluous( uchar *word /* */ , uchar *s /* */ ){ register int i,j,k; int reply; register len = strlen(word); for(i=0 ; i < len ; i++){ /* , */ k=0; for(j=0 ; j < i ; j++) version[k++]=word[j]; for(j=i+1 ; j < len ; j++) version[k++]=word[j]; version[k]='\0'; if( eqi( version, s )) return 1; /* OK */ } return 0; /* FAIL */ } /* */ static int hole; /* , ANYCHAR */ static int lost(uchar *word, uchar *s) { register int i,j,k; register len = strlen(word); hole= (-1); for(i=0 ; i < len+1 ; i++){ k=0; for(j=0 ; j < i ; j++) version[k++]=word[j]; version[k++]=ANYCHAR; for(j=i ; j < len ; j++) version[k++]=word[j]; version[k]='\0'; if( strok( version, s )){ hole=i; return 1; /* OK */ } } return 0; /* FAIL */ } . , 1992-95 - 324 - UNIX /* ( ) */ static int changed(uchar *word, uchar *s) { register int i,j,k; register len = strlen(word); hole = (-1); for(i=0 ; i < len ; i++){ k=0; for( j=0 ; j < i ; j++) version[k++]=word[j]; version[k++]=ANYCHAR; for( j=i+1 ; j < len ; j++) version[k++]=word[j]; version[k]='\0'; if( strok( version,s)){ hole=i; return 1; /* OK */ } } return 0; /* FAIL */ } /* */ static int duplicates(uchar *word, uchar *s, int leng) { register int i,j,k; uchar tmp[80]; if( eqi( word, s )) return 1; /* OK */ for(i=0;i < leng - 1; i++) /* */ if( word[i]==word[i+1]){ k=0; for(j=0 ; j < i ; j++) tmp[k++]=word[j]; for(j=i+1 ; j < leng ; j++) tmp[k++]=word[j]; tmp[k]='\0'; if( duplicates( tmp, s, leng-1) == 1) return 1; /* OK */ } return 0; /* FAIL */ } . , 1992-95 - 325 - UNIX /* */ static int swapped(uchar *word, uchar *s) { register int i,j,k; register len = strlen(word); for(i=0;i < len-1;i++){ k=0; for(j=0 ; j < i ; j++) version[k++]=word[j]; version[k++]=word[i+1]; version[k++]=word[i]; for(j=i+2 ; j < len ; j++) version[k++]=word[j]; version[k]='\0'; if( eqi( version, s)) return 1; /* OK */ } return 0; /* FAIL */ } uchar *words[] = { (uchar *) "bag", (uchar *) "bags", (uchar *) "cook", (uchar *) "cool", (uchar *) "bug", (uchar *) "buy", (uchar *) "cock", NULL }; #define Bcase(x, operators) case x: { operators; } break; char *cname[5] = { " ", " ", " ", " ", " " }; . , 1992-95 - 326 - UNIX static int spellmatch( uchar *word /* IN */ , uchar *words[] /* IN */ , uchar **indx /* OUT */ ){ int i, code, total = (-1); uchar **ptr; if(!*word) return -1; for(ptr = words; *ptr; ++ptr) if(eqi(word, *ptr)){ if(indx) *indx = *ptr; return 0; } /* , */ for(ptr = words; *ptr; ++ptr){ uchar *s = *ptr; int max = 5; for(i=0; i < max; i++){ switch( i ){ Bcase(0,code = swapped(word, s) ) Bcase(1,code = duplicates(word, s, strlen(word)) ) Bcase(2,code = lost(word, s) ) Bcase(3,code = changed(word, s) ) Bcase(4,code = superfluous(word, s) ) } if(code){ total++; printf("?\t%s\t%s\n", cname[i], s); if(indx) *indx = s; /* * */ if(i==1) max = 4; } } } return total; } . , 1992-95 - 327 - UNIX void main(){ uchar inpbuf[BUFSIZ]; int n; uchar *reply, **ptr; setlocale(LC_ALL, ""); for(ptr = words; *ptr; ptr++) printf("#\t%s\n", *ptr); do{ printf("> "); fflush(stdout); if(gets((char *)inpbuf) == NULL) break; switch(spellmatch(inpbuf, words, &reply)){ case -1: printf(" \n"); break; case 0: printf(" '%s'\n", reply); break; default: printf("\n"); } } while(1); } 7.53. , , . , , . : - ? #include <stdio.h> char *strings[] = { " " " " " ", " ", NULL }; void main(){ char **p; for(p=strings;*p;++p) printf("%s\n", *p); } : , ANSI  : " " " " isspace, . strings