opredelennoj fajlovoj sistemy. |to oznachaet, chto odin odnorodnyj interfejs upravlyaet vsemi svya- zyami mezhdu programmoj i periferijnymi ustrojstvami. V naibolee obshchem sluchae pered chteniem iz fajla ili za- pis'yu v fajl neobhodimo soobshchit' sisteme o vashem namerenii; etot process nazyvaetsya "otkrytiem" fajla. Sistema vyyasnya- et,imeete li vy pravo postupat' takim obrazom (sushchestvuet li etot fajl? imeetsya li u vas razreshenie na obrashchenie k ne- mu?), i esli vse v poryadke, vozvrashchaet v programmu nebol'shoe polozhitel'noe celoe chislo, nazyvaemoe deskriptorom fajla. vsyakij raz, kogda etot fajl ispol'zuetsya dlya vvoda ili vyvo- da, dlya identifikacii fajla upotreblyaetsya deskriptor fajla, a ne ego imya. (Zdes' sushchestvuet primernaya analogiya s ispol'- zovaniem READ (5,...) i WRITE (6,...) v fortrane). Vsya in- formaciya ob otkrytom fajle soderzhitsya v sisteme; programma pol'zovatelya obrashchaetsya k fajlu tol'ko cherez deskriptor faj- la. Dlya udobstva vypolneniya obychnyh operacij vvoda i vyvoda s pomoshch'yu terminala pol'zovatelya sushchestvuyut special'nye sog- lasheniya. Kogda interpretator komand ("SHELL") progonyaet programmu, on otkryvaet tri fajla, nazyvaemye standartnym vvodom, standartnym vyvodom i standartnym vyvodom oshibok, kotorye imeyut sootvetstvenno chisla 0, 1 i 2 v kachestve desk- riptorov etih fajlov. V normal'nom sostoyanii vse oni svyazany s terminalom, tak chto esli programma chitaet s deskriptorom fajla 0 i pishet s deskriptorami fajlov 1 i 2, to ona mozhet osushchestvlyat' vvod i vyvod s pomoshch'yu terminala, ne zabotyas' ob otkrytii sootvetstvuyushchih fajlov. Pol'zovatel' programmy mozhet perenapravlyat' vvod i vyvod na fajly, ispol'zuya operacii komandnogo interpretatora SHELL "<" i ">" : PROG <INFILE>OUTFILE V etom sluchae interpretator komand SHELL izmenit prisvaiva- nie po umolchaniyu deskriptorov fajlov 0 i 1 s terminala na ukazannye fajly. Normal'no deskriptor fajla 2 ostaetsya svya- zannym s terminalom, tak chto soobshcheniya ob oshibkah mogut pos- tupat' tuda. Podobnye zamechaniya spravedlivy i togda, kogda vvod i vyvod svyazan s kanalom. Sleduet otmetit', chto vo vseh sluchayah prikrepleniya fajlov izmenyayutsya interpretatorom SHELL, a ne programmoj. Sama programma, poka ona ispol'zuet fajl 0 dlya vvoda i fajly 1 i 2 dlya vyvoda, ne znaet ni otku- da prihodit ee vvod, ni kuda postupaet ee vydacha. 8.2. Nizkourovnevyj vvod/vyvod - operatory READ i WRITE Samyj nizkij uroven' vvoda/vyvoda v sisteme UNIX ne pre- dusmatrivaet ni kakoj-libo buferizacii, ni kakogo-libo dru- gogo servisa; on po sushchestvu yavlyaetsya neposredstvennym vho- dom v operacionnuyu sistemu. Ves' vvod i vyvod osushchestvlyaetsya dvumya funkciyami: READ i WRITE. Pervym argumentom obeih funk- cij yavlyaetsya deskriptor fajla. Vtorym argumentom yavlyaetsya bufer v vashej programme, otkuda ili kuda dolzhny postupat' dannye. Tretij argument - eto chislo podlezhashchih peresylke bajtov. Obrashcheniya k etim funkciyam imeyut vid: N_READ=READ(FD,BUF,N); N_WRITTEN=WRITE(FD,BUF,N); Pri kazhdom obrashchenii vozvrashchaetsya schetchik bajtov, ukazyvayu- shchij fakticheskoe chislo peredannyh bajtov. Pri chtenii vozvra- shchennoe chislo bajtov mozhet okazat'sya men'she, chem zaproshennoe chislo. Vozvrashchennoe nulevoe chislo bajtov oznachaet konec faj- la, a "-1" ukazyvaet na nalichie kakoj-libo oshibki. Pri zapi- si vozvrashchennoe znachenie ravno chislu fakticheski zapisannyh bajtov; nesovpadenie etogo chisla s chislom bajtov, kotoroe predpolagalos' zapisat', obychno svidetel'stvuet ob oshibke. Kolichestvo bajtov, podlezhashchih chteniyu ili zapisi, mozhet byt' sovershenno proizvol'nym. Dvumya samymi rasprostranennymi velichinami yavlyayutsya "1", kotoraya oznachaet peredachu odnogo simvola za obrashchenie (t.e. Bez ispol'zovaniya bufera), i "512", kotoraya sootvetstvuet fizicheskomu razmeru bloka na mnogih periferijnyh ustrojstvah. |tot poslednij razmer budet naibolee effektivnym, no dazhe vvod ili vyvod po odnomu sim- volu za obrashchenie ne budet neobyknovenno dorogim. Ob容diniv vse eti fakty, my napisali prostuyu programmu dlya kopirovaniya vvoda na vyvod, ekvivalentnuyu programme ko- pirovki fajlov, napisannoj v glave 1. Na sisteme UNIX eta programma budet kopirovat' chto ugodno kuda ugodno, potomu chto vvod i vyvod mogut byt' perenapravleny na lyuboj fajl ili ustrojstvo. #DEFINE BUFSIZE 512 /*BEST SIZE FOR PDP-11 UNIX*/ MAIN() /*COPY INPUT TO OUTPUT*/ \( CHAR BUF[BUFSIZE]; INT N; WHILE((N=READ(0,BUF,BUFSIZE))>0) WRITE(1,BUF,N); \) Esli razmer fajla ne budet kraten BUFSIZE, to pri nekotorom obrashchenii k READ budet vozvrashcheno men'shee chislo bajtov, ko- torye zatem zapisyvayutsya s pomoshch'yu WRITE; pri sleduyushchem pos- le etogo obrashchenii k READ budet vozvrashchen nul'. Pouchitel'no razobrat'sya, kak mozhno ispol'zovat' funkcii READ i WRITE dlya postroeniya procedur bolee vysokogo urovnya, takih kak GETCHAR, PUTCHAR i t.d. Vot, naprimer, variant funkcii GETCHAR, osushchestvlyayushchij vvod bez ispol'zovaniya bufe- ra. #DEFINE CMASK 0377 /*FOR MAKING CHAR'S > 0*/ GETCHAR() /*UNBUFFERED SINGLE CHARACTER INPUT*/ \( CHAR C; RETURN((READ(0,&C,1)>0 7 & CMASK : EOF); \) Peremennaya "C" dolzhna byt' opisana kak CHAR, potomu chto fun- kciya READ prinimaet ukazatel' na simvoly. Vozvrashchaemyj sim- vol dolzhen byt' maskirovan chislom 0377 dlya garantii ego po- lozhitel'nosti; v protivnom sluchae znakovyj razryad mozhet sde- lat' ego znachenie otricatel'nym. (Konstanta 0377 podhodit dlya evm PDP-11, no ne obyazatel'no dlya drugih mashin). Vtoroj variant funkcii GETCHAR osushchestvlyaet vvod bol'shi- mi porciyami, a vydaet simvoly po odnomu za obrashchenie. #DEFINE CMASK 0377 /*FOR MAKING CHAR'S>0*/ #DEFINE BUFSIZE 512 GETCHAR() /*BUFFERED VERSION*/ \( STATIC CHAR BUF[BUFSIZE]; STATIC CHAR *BUFP = BUF; STATIC INT N = 0; IF (N==0) \( /*BUFFER IS EMPTY*/ N=READ(0,BUF,BUFSIZE); BUFP = BUF; \) RETURN((--N>=0) ? *BUFP++ & CMASK : EOF); \) 8.3. Otkrytie, sozdanie, zakrytie i rasceplenie (UNLINK) Krome sluchaya, kogda po umolchaniyu opredeleny standartnye fajly vvoda, vyvoda i oshibok, vy dolzhny yavno otkryvat' faj- ly, chtoby zatem chitat' iz nih ili pisat' v nih. Dlya etoj ce- li sushchestvuyut dve tochki vhoda: OPEN i CREAT. Funkciya OPEN ves'ma shodna s funkciej FOPEN, rassmotren- noj v glave 7, za isklyucheniem togo, chto vmesto vozvrashcheniya ukazatelya fajla ona vozvrashchaet deskriptor fajla, kotoryj yav- lyaetsya prosto celym tipa INT. INT FD; FD=OPEN(NAME,RWMODE); Kak i v sluchae FOPEN, argument NAME yavlyaetsya simvol'noj strokoj, sootvetstvuyushchej vneshnemu imeni fajla. Odnako argu- ment, opredelyayushchij rezhim dostupa, otlichen: RWMODE ravno: 0 - dlya chteniya, 1 - dlya zapisi, 2 - dlya chteniya i zapisi. Esli proishodit kakaya-to oshibka, funkciya OPEN vozvrashchaet "-1"; v protivnom sluchae ona vozvrashchaet dejstvitel'nyj deskriptor fajla. Popytka otkryt' fajl, kotoryj ne sushchestvuet, yavlyaetsya oshibkoj. Tochka vhoda CREAT predostavlyaet vozmozhnost' sozda- niya novyh fajlov ili perezapisi staryh. V rezul'tate obrashche- niya FD=CREAT(NAME,PMODE); vozvrashchaet deskriptor fajla, esli okazalos' vozmozhnym soz- dat' fajl s imenem NAME, i "-1" v protivnom sluchae. Esli fajl s takim imenem uzhe sushchestvuet, CREAT usechet ego do nu- levoj dliny; sozdanie fajla, kotoryj uzhe sushchestvuet, ne yav- lyaetsya oshibkoj. Esli fajl yavlyaetsya sovershenno novym, to CREAT sozdaet ego s opredelennym rezhimom zashchity, specificiruemym argumen- tom PMODE. V sisteme fajlov na UNIX s fajlom svyazyvayutsya de- vyat' bitov zashchity informacii, kotorye upravlyayut razresheniem na chtenie, zapis' i vypolnenie dlya vladel'ca fajla, dlya gruppy vladel'cev i dlya vseh ostal'nyh pol'zovatelej. Takim obrazom, trehznachnoe vos'merichnoe chislo naibolee udobno dlya specifikacii razreshenij. Naprimer, chislo 0755 svidetel'stvu- et o razreshenii na chtenie, zapis' i vypolnenie dlya vladel'ca i o razreshenii na chtenie i vypolnenie dlya gruppy i vseh os- tal'nyh. Dlya illyustracii nizhe privoditsya programma kopirovaniya odnogo fajla v drugoj, yavlyayushchayasya uproshchennym variantom uti- lity CP sistemy UNIX. (Osnovnoe uproshchenie zaklyuchaetsya v tom, chto nash variant kopiruet tol'ko odin fajl i chto vtoroj argu- ment ne dolzhen byt' spravochnikom). #DEFINE NULL 0 #DEFINE BUFSIZE 512 #DEFINE PMODE 0644/*RW FOR OWNER,R FOR GROUP,OTHERS*/ MAIN(ARGC,ARGV) /*CP: COPY F1 TO F2*/ INT ARGC; CHAR *ARGV[]; \( INT F1, F2, N; CHAR BUF[BUFSIZE]; IF (ARGC ! = 3) ERROR("USAGE:CP FROM TO", NULL); IF ((F1=OPEN(ARGV[1],0))== -1) ERROR("CP:CAN'T OPEN %S", ARGV[1]); IF ((F2=CREAT(ARGV[2],PMODE))== -1) ERROR("CP: CAN'T CREATE %S", ARGV[2]); WHILE ((N=READ(F1,BUF,BUFSIZE))>0) IF (WRITE(F2,BUF,N) !=N) ERROR("CP: WRITE ERROR", NULL); EXIT(0); \) ERROR(S1,S2) /*PRINT ERROR MESSAGE AND DIE*/ CHAR *S1, S2; \( PRINTF(S1,S2); PRINTF("\N"); EXIT(1); \) Sushchestvuet ogranichenie (obychno 15 - 25) na kolichestvo fajlov, kotorye programma mozhet imet' otkrytymi odnovremen- no. V sootvetstvii s etim lyubaya programma, sobirayushchayasya ra- botat' so mnogimi fajlami, dolzhna byt' podgotovlena k pov- tornomu ispol'zovaniyu deskriptorov fajlov. Procedura CLOSE preryvaet svyaz' mezhdu deskriptorom fajla i otkrytym fajlom i osvobozhdaet deskriptor fajla dlya ispol'zovaniya s nekotorym drugim fajlom. Zavershenie vypolneniya programmy cherez EXIT ili v rezul'tate vozvrata iz vedushchej programmy privodit k zakrytiyu vseh otkrytyh fajlov. Funkciya rascepleniya UNLINK (FILENAME) udalyaet iz sistemy fajlov fajl s imenem FILENAME ( iz dannogo spravochnogo faj- la. Fajl mozhet byt' sceplen s drugim spravochnikom, vozmozhno, pod drugim imenem - primech.perevodchika). Uprazhnenie 8-1 -------------- Perepishite programmu CAT iz glavy 7, ispol'zuya funkcii READ, WRITE, OPEN i CLOSE vmesto ih ekvivalentov iz standar- tnoj biblioteki. Provedite eksperimenty dlya opredeleniya ot- nositel'noj skorosti raboty etih dvuh variantov. 8.4. Proizvol'nyj dostup - SEEK i LSEEK Normal'no pri rabote s fajlami vvod i vyvod osushchestvlya- etsya posledovatel'no: pri kazhdom obrashchenii k funkciyam READ i WRITE chtenie ili zapis' nachinayutsya s pozicii, neposredstven- no sleduyushchej za predydushchej obrabotannoj. No pri neobhodimos- ti fajl mozhet chitat'sya ili zapisyvat'sya v lyubom proizvol'nom poryadke. Obrashchenie k sisteme s pomoshch'yu funkcii LSEEK pozvo- lyaet peredvigat'sya po fajlu, ne proizvodya fakticheskogo chte- niya ili zapisi. V rezul'tate obrashcheniya LSEEK(FD,OFFSET,ORIGIN); tekushchaya poziciya v fajle s deskriptorom FD peredvigaetsya na poziciyu OFFSET (smeshchenie), kotoraya otschityvaetsya ot mesta, ukazyvaemogo argumentom ORIGIN (nachalo otscheta). Posleduyushchee chtenie ili zapis' budut teper' nachinat'sya s etoj pozicii. Argument OFFSET imeet tip LONG; FD i ORIGIN imeyut tip INT. Argument ORIGIN mozhet prinimat' znacheniya 0,1 ili 2, ukazyvaya na to, chto velichina OFFSET dolzhna otschityvat'sya sootvetst- venno ot nachala fajla, ot tekushchej pozicii ili ot konca faj- la. Naprimer, chtoby dopolnit' fajl, sleduet pered zapis'yu najti ego konec: LSEEK(FD,0L,2); chtoby vernut'sya k nachalu ("peremotat' obratno"), mozhno napi- sat': LSEEK(FD,0L,0); obratite vnimanie na argument 0L; ego mozhno bylo by zapisat' i v vide (LONG) 0. Funkciya LSEEK pozvolyaet obrashchat'sya s fajlami primerno tak zhe, kak s bol'shimi massivami, pravda cenoj bolee medlen- nogo dostupa. sleduyushchaya prostaya funkciya, naprimer, schityvaet lyuboe kolichestvo bajtov, nachinaya s proizvol'nogo mesta v fajle. GET(FD,POS,BUF,N) /*READ N BYTES FROM POSITION POS*/ INT FD, N; LONG POS; CHAR *BUF; \( LSEEK(FD,POS,0); /*GET TO POS*/ RETURN(READ(FD,BUF,N)); \) V bolee rannih redakciyah, chem redakciya 7 sistemy UNIX, osnovnaya tochka vhoda v sistemu vvoda-vyvoda nazyvaetsya SEEK. Funkciya SEEK identichna funkcii LSEEK, za isklyucheniem togo, chto argument OFFSET imeet tip INT, a ne LONG. v sootvetstvii s etim, poskol'ku na PDP-11 celye imeyut tol'ko 16 bitov, ar- gument OFFSET, ukazyvaemyj funkcii SEEK, ogranichen velichinoj 65535; po etoj prichine argument ORIGIN mozhet imet' znacheniya 3, 4, 5, kotorye zastavlyayut funkciyu SEEK umnozhit' zadannoe znachenie OFFSET na 512 (kolichestvo bajtov v odnom fizicheskom bloke) i zatem interpretirovat' ORIGIN, kak esli eto 0, 1 ili 2 sootvetstvenno. Sledovatel'no, chtoby dostich' proiz- vol'nogo mesta v bol'shom fajle, nuzhno dva obrashcheniya k SEEK: snachala odno, kotoroe vydelyaet nuzhnyj blok, a zatem vtoroe, gde ORIGIN imeet znachenie 1 i kotoroe osushchestvlyaet peredvi- zhenie na zhelaemyj bajt vnutri bloka. Uprazhnenie 8-2 --------------- Ochevidno, chto SEEK mozhet byt' napisana v terminalah LSEEK i naoborot. napishite kazhduyu funkciyu cherez druguyu. 8.5. Primer - realizaciya funkcij FOPEN i GETC Davajte teper' na primere realizacii funkcij FOPEN i GETC iz standartnoj biblioteki podprogramm prodemonstriruem, kak nekotorye iz opisannyh elementov ob容dinyayutsya vmeste. Napomnim, chto v standartnoj biblioteke fajly opisyvatsya posredstvom ukazatelej fajlov, a ne deskriptorov. Ukazatel' fajla yavlyaetsya ukazatelem na strukturu, kotoraya soderzhit neskol'ko elementov informacii o fajle: ukazatel' bufera, chtoby fajl mog chitat'sya bol'shimi porciyami; schetchik chisla simvolov, ostavshihsya v bufere; ukazatel' sleduyushchej pozicii simvola v bufere; nekotorye priznaki, ukazyvayushchie rezhim chte- niya ili zapisi i t.d.; deskriptor fajla. Opisyvayushchaya fajl struktura dannyh soderzhitsya v fajle STDIO.H, kotoryj dolzhen vklyuchat'sya (posredstvom #INCLUDE) v lyuboj ishodnyj fajl, v kotorom ispol'zuyutsya funkcii iz stan- dartnoj biblioteki. On takzhe vklyuchaetsya funkciyami etoj bib- lioteki. V privodimoj nizhe vyderzhke iz fajla STDIO.H imena, prednaznachaemye tol'ko dlya ispol'zovaniya funkciyami bibliote- ki, nachinayutsya s podcherkivaniya, s tem chtoby umen'shit' vero- yatnost' sovpadeniya s imenami v programme pol'zovatelya. DEFINE _BUFSIZE 512 DEFINE _NFILE 20 /*FILES THAT CAN BE HANDLED*/ TYPEDEF STRUCT _IOBUF \( CHAR *_PTR; /*NEXT CHARACTER POSITION*/ INT _CNT; /*NUMBER OF CHARACTERS LEFT*/ CHAR *_BASE; /*LOCATION OF BUFFER*/ INT _FLAG; /*MODE OF FILE ACCESS*/ INT _FD; /*FILE DESCRIPTOR*/ ) FILE; XTERN FILE _IOB[_NFILE]; DEFINE STDIN (&_IOB[0]) DEFINE STDOUT (&_IOB[1]) DEFINE STDERR (&_IOB[2]) DEFINE _READ 01 /* FILE OPEN FOR READING */ DEFINE _WRITE 02 /* FILE OPEN FOR WRITING */ DEFINE _UNBUF 04 /* FILE IS UNBUFFERED */ DEFINE _BIGBUF 010 /* BIG BUFFER ALLOCATED */ DEFINE _EOF 020 /* EOF HAS OCCURRED ON THIS FILE */ DEFINE _ERR 040 /* ERROR HAS OCCURRED ON THIS FILE */ DEFINE NULL 0 DEFINE EOF (-1) DEFINE GETC(P) (--(P)->_CNT >= 0 \ ? *(P)->_PTR++ & 0377 : _FILEBUF(P)) DEFINE GETCHAR() GETC(STDIN) DEFINE PUTC(X,P) (--(P)->_CNT >= 0 \ ? *(P)->_PTR++ = (X) : _FLUSHBUF((X),P)) DEFINE PUTCHAR(X) PUTC(X,STDOUT) V normal'nom sostoyanii makros GETC prosto umen'shaet schetchik, peredvigaet ukazatel' i vozvrashchaet simvol. (Esli opredelenie #DEFINE slishkom dlinnoe, to ono prodolzhaetsya s pomoshch'yu obratnoj kosoj cherty). Esli odnako schetchik stanovit- sya otricatel'nym, to GETC vyzyvaet funkciyu _FILEBUF, kotoraya snova zapolnyaet bufer, reinicializiruet soderzhimoe struktury i vozvrashchaet simvol. Funkciya mozhet predostavlyat' perenosimyj interfejs i v to zhe vremya soderzhat' neperenosimye konstruk- cii: GETC maskiruet simvol chislom 0377, kotoroe podavlyaet znakovoe rasshirenie, osushchestvlyaemoe na PDP-11, i tem samym garantiruet polozhitel'nost' vseh simvolov. Hotya my ne sobiraemsya obsuzhdat' kakie-libo detali, my vse zhe vklyuchili syuda opredelenie makrosa PUTC, dlya togo chto- by pokazat', chto ona rabotaet v osnovnom tochno takzhe, kak i GETC, obrashchayas' pri zapolnenii bufera k funkcii _FLUSHBUF. Teper' mozhet byt' napisana funkciya FOPEN. Bol'shaya chast' programmy funkcii FOPEN svyazana s otkryvaniem fajla i raspo- lozheniem ego v nuzhnom meste, a takzhe s ustanovleniem bitov priznakov takim obrazom, chtoby oni ukazyvali nuzhnoe sostoya- nie. Funkciya FOPEN ne vydelyaet kakoj-libo bufernoj pamyati; eto delaetsya funkciej _FILEBUF pri pervom chtenii iz fajla. #INCLUDE <STDIO.H> #DEFINE PMODE 0644 /*R/W FOR OWNER;R FOR OTHERS*/ FILE *FOPEN(NAME,MODE) /*OPEN FILE,RETURN FILE PTR*/ REGISTER CHAR *NAME, *MODE; \( REGISTER INT FD; REGISTER FILE *FP; IF(*MODE !='R'&&*MODE !='W'&&*MODE !='A') \( FPRINTF(STDERR,"ILLEGAL MODE %S OPENING %S\N", MODE,NAME); EXIT(1); \) FOR (FP=_IOB;FP<_IOB+_NFILE;FP++) IF((FP->_FLAG & (_READ \! _WRITE))==0) BREAK; /*FOUND FREE SLOT*/ IF(FP>=_IOB+_NFILE) /*NO FREE SLOTS*/ RETURN(NULL); IF(*MODE=='W') /*ACCESS FILE*/ FD=CREAT(NAME,PMODE); ELSE IF(*MODE=='A') \( IF((FD=OPEN(NAME,1))==-1) FD=CREAT(NAME,PMODE); LSEEK(FD,OL,2); \) ELSE FD=OPEN(NAME,0); IF(FD==-1) /*COULDN'T ACCESS NAME*/ RETURN(NULL); FP->_FD=FD; FP->_CNT=0; FP->_BASE=NULL; FP->_FLAG &=(_READ \! _WRITE); FP->_FLAG \!=(*MODE=='R') ? _READ : _WRITE; RETURN(FP); \) Funkciya _FILEBUF neskol'ko bolee slozhnaya. Osnovnaya trud- nost' zaklyuchaetsya v tom, chto _FILEBUF stremitsya razreshit' dostup k fajlu i v tom sluchae, kogda mozhet ne okazat'sya dos- tatochno mesta v pamyati dlya buferizacii vvoda ili vyvoda. es- li prostranstvo dlya novogo bufera mozhet byt' polucheno obra- shcheniem k funkcii CALLOC, to vse otlichno; esli zhe net, to _FILEBUF osushchestvlyaet nebuferizovannyj vvod/ vyvod, ispol'- zuya otdel'nyj simvol, pomeshchennyj v lokal'nom massive. #INCLUDE <STDIO.H> _FILLBUF(FP) /*ALLOCATE AND FILL INPUT BUFFER*/ REGISTER FILE *FP; ( STATIC CHAR SMALLBUF(NFILE);/*FOR UNBUFFERED 1/0*/ CHAR *CALLOC(); IF((FR->_FLAG&_READ)==0\!\!(FP->_FLAG&(EOF\!_ERR))\!=0 RETURN(EOF); WHILE(FP->_BASE==NULL) /*FIND BUFFER SPACE*/ IF(FP->_FLAG & _UNBUF) /*UNBUFFERED*/ FP->_BASE=&SMALLBUF[FP->_FD]; ELSE IF((FP->_BASE=CALLOC(_BUFSIZE,1))==NULL) FP->_FLAG \!=_UNBUF; /*CAN'T GET BIG BUF*/ ELSE FP->_FLAG \!=_BIGBUF; /*GOT BIG ONE*/ FP->_PTR=FP->_BASE; FP->_CNT=READ(FP->_FD, FP->_PTR, FP->_FLAG & _UNBUF ? 1 : _BUFSIZE); FF(--FP->_CNT<0) \( IF(FP->_CNT== -1) FP->_FLAG \! = _EOF; ELSE FP->_FLAG \! = _ ERR; FP->_CNT = 0; RETURN(EOF); \) RETURN(*FP->_PTR++ & 0377); /*MAKE CHAR POSITIVE*/ ) Pri pervom obrashchenii k GETC dlya konkretnogo fajla schetchik okazyvaetsya ravnym nulyu, chto privodit k obrashcheniyu k _FILEBUF. Esli funkciya _FILEBUF najdet, chto etot fajl ne ot- kryt dlya chteniya, ona nemedlenno vozvrashchaet EOF. V protivnom sluchae ona pytaetsya vydelit' bol'shoj bufer, a esli ej eto ne udaetsya, to bufer iz odnogo simvola. Pri etom ona zanosit v _FLAG sootvetstvuyushchuyu informaciyu o buferizacii. Raz bufer uzhe sozdan, funkciya _FILEBUF prosto vyzyvaet funkciyu READ dlya ego zapolneniya, ustanavlivaet schetchik i ukazateli i vozvrashchaet simvol iz nachala bufera. Edinstvennyj ostavshijsya nevyyasnennym vopros sostoit v tom, kak vse nachinaetsya. Massiv _IOB dolzhen byt' opredelen i inicializirovan dlya STDIN, STDOUT i STDERR: FILE _IOB[NFILE] = \( (NULL,0,_READ,0), /*STDIN*/ (NULL,0,NULL,1), /*STDOUT*/ (NULL,0,NULL,_WRITE \! _UNBUF,2) /*STDERR*/ ); Iz inicializacii chasti _FLAG etogo massiva struktur vidno, chto fajl STDIN prednaznachen dlya chteniya, fajl STDOUT - dlya zapisi i fajl STDERR - dlya zapisi bez ispol'zovaniya bufera. Uprazhnenie 8-3 -------------- Perepishite funkcii FOPEN i _FILEBUF, ispol'zuya polya vmesto yavnyh pobitovyh operacij. Uprazhnenie 8-4 --------------- Razrabotajte i napishite funkcii _FLUSHBUF i FCLOSE. Uprazhnenie 8-5 --------------- Standartnaya biblioteka soderzhit funkciyu FSEEK(FP, OFFSET, ORIGIN) kotoraya identichna funkcii LSEEK, isklyuchaya to, chto FP yavlyaet- sya ukazatelem fajla, a ne deskriptorom fajla. Napishite FSEEK. Ubedites', chto vasha FSEEK pravil'no soglasuetsya s bu- ferizaciej, sdelannoj dlya drugih funkcij biblioteki. 8.6. Primer - raspechatka spravochnikov Inogda trebuetsya drugoj vid vzaimodejstviya s sistemoj fajlov - opredelenie informacii o fajle, a ne togo, chto v nem soderzhitsya. Primerom mozhet sluzhit' komanda LS ("spisok spravochnika") sistemy UNIX. Po etoj komande raspechatyvayutsya imena fajlov iz spravochnika i, neobyazatel'no, drugaya infor- maciya, takaya kak razmery, razresheniya i t.d. Poskol'ku, po krajnej mere, na sisteme UNIX spravochnik yavlyaetsya prosto fajlom, to v takoj komande, kak LS net niche- go osobennogo; ona chitaet fajl i vydelyaet nuzhnye chasti iz nahodyashchejsya tam informacii. Odnako format informacii oprede- lyaetsya sistemoj, tak chto LS dolzhna znat', v kakom vide vse predstavlyaetsya v sisteme. My eto chastichno proillyustriruem pri napisanii programmy FSIZE. Programma FSIZE predstavlyaet soboj special'nuyu formu LS, kotoraya pechataet razmery vseh fajlov, ukazannyh v spiske ee argumentov. Esli odin iz fajlov yavlyaetsya spravochnikom, to dlya obrabotki etogo spravochnika programma FSIZE obrashchaetsya sama k sebe rekursivno. esli zhe argumenty voobshche otsutstvu- yut, to obrabatyvaetsya tekushchij spravochnik. Dlya nachala dadim kratkij obzor struktury sistemy fajlov. Spravochnik - eto fajl, kotoryj soderzhit spisok imen fajlov i nekotoroe ukazanie o tom, gde oni razmeshchayutsya. Fakticheski eto ukazanie yavlyaetsya indeksom dlya drugoj tablicy, kotoruyu nazyvayut "I - uzlovoj tablicej". Dlya fajla I-uzel - eto to, gde soderzhitsya vsya informaciya o fajle, za isklyucheniem ego imeni. Zapis' v spravochnike sostoit tol'ko iz dvuh elemen- tov: nomera I-uzla i imeni fajla. Tochnaya specifikaciya postu- paet pri vklyuchenii fajla SYS/DIR.H, kotoryj soderzhit #DEFINE DIRSIZ 14 /*MAX LENGTH OF FILE NAME*/ STRUCT DIRECT /*STRUCTURE OF DIRECTORY ENTRY*/ \( INO_T&_INO; /*INODE NUMBER*/ CHAR &_NAME[DIRSIZ]; /*FILE NAME*/ \); "Tip" INO_T - eto opredelyaemyj posredstvom TYPEDEF tip, kotoryj opisyvaet indeks I-uzlovoj tablicy. Na PDP-11 UNIX etim tipom okazyvaetsya UNSIGNED, no eto ne tot sort informa- cii, kotoryj pomeshchayut vnutr' programmy: na raznyh sistemah etot tip mozhet byt' razlichnym. Poetomu i sleduet ispol'zo- vat' TYPEDEF. Polnyj nabor "sistemnyh" tipov nahoditsya v fajle SYS/TUPES.H. Funkciya STAT beret imya fajla i vozvrashchaet vsyu soderzhashchu- yusya v I-om uzle informaciyu ob etom fajle (ili -1, esli ime- etsya oshibka). Takim obrazom, v rezul'tate STRUCT STAT STBUF; CHAR *NAME; STAT(NAME,&STBUF); struktura STBUF napolnyaetsya informaciej iz I-go uzla o fajle s imenem NAME. Struktura, opisyvayushchaya vozvrashchaemuyu funkciej STAT informaciyu, nahoditsya v fajle SYS/STAT.H i vyglyadit sleduyushchim obrazom: STRUCT STAT /*STRUCTURE RETURNED BY STAT*/ \( DEV_T ST_DEV; /* DEVICE OF INODE */ INO_T ST_INO; /* INODE NUMBER */ SHORT ST_MODE /* MODE BITS */ SHORT ST_NLINK; / *NUMBER OF LINKS TO FILE */ SHORT ST_UID; /* OWNER'S USER ID */ SHORT ST_GID; /* OWNER'S GROUP ID */ DEV_T ST_RDEV; /* FOR SPECIAL FILES */ OFF_T ST_SIZE; /* FILE SIZE IN CHARACTERS */ TIME_T ST_ATIME; /* TIME LAST ACCESSED */ TIME_T ST_MTIME; /* TIME LAST MODIFIED */ TIME_T ST_CTIME; /* TIME ORIGINALLY CREATED */ \) Bol'shaya chast' etoj informacii ob座asnyaetsya v kommentariyah. |lement ST.MODE soderzhit nabor flagov, opisyvayushchih fajl; dlya udobstva opredeleniya flagov takzhe nahodyatsya v fajle SYS/STAT.H. #DEFINE S_IFMT 0160000 /* TYPE OF FILE */ #DEFINE S_IFDIR 0040000 /* DIRECTORY */ #DEFINE S_IFCHR 0020000 /* CHARACTER SPECIAL */ #DEFINE S_IFBLK 0060000 /* BLOCK SPECIAL */ #DEFINE S_IFREG 0100000 /* REGULAR */ #DEFINE S_ISUID 04000 /* SET USER ID ON EXECUTION */ #DEFINE S_ISGID 02000 /* SET GROUP ID ON EXECUTION */ #DEFINE S_ISVTX 01000 /*SAVE SWAPPED TEXT AFTER USE*/ #DEFINE S_IREAD 0400 /* READ PERMISSION */ #DEFINE S_IWRITE 0200 /* WRITE PERMISSION */ #DEFINE S_IEXEC 0100 /* EXECUTE PERMISSION */ Teper' my v sostoyanii napisat' programmu FSIZE. Esli po- luchennyj ot funkcii STAT rezhim ukazyvaet, chto fajl ne yavlya- etsya spravochnikom, to ego razmer uzhe pod rukoj i mozhet byt' napechatan neposredstvenno. Esli zhe on okazyvaetsya spravochni- kom, to my dolzhny obrabatyvat' etot spravochnik otdel'no dlya kazhdogo fajla; tak kak spravochnik mozhet v svoyu ochered' so- derzhat' podspravochniki, etot process obrabotki yavlyaetsya re- kursivnym. Kak obychno, vedushchaya programma glavnym obrazom imeet delo s komandnoj strokoj argumentov; ona peredaet kazhdyj argument funkcii FSIZE v bol'shoj bufer. #INCLUDE <STDIO.H.> #INCLUDE <SYS/TYPES.H> /*TYPEDEFS*/ #INCLUDE <SYS/DIR.H> /*DIRECTORY ENTRY STRUCTURE*/ #INCLUDE <SYS/STAT.H> /*STRUCTURE RETURNED BY STAT*/ #DEFINE BUFSIZE 256 MAIN(ARGC,ARGV) /*FSIZE:PRINT FILE SIZES*/ CHAR *ARGV[]; \( CHAR BUF[BUFSIZE]; IF(ARGC==1) \( /*DEFAULT:CURRENT DIRECTORY*/ ATRCPY(BUF,"."); FSIZE(BUF); \) ELSE WHILE(--ARGC>0) \( STRCPY(BUF,*++ARGV); FSIZE(BUF); \) \) Funkciya FSIZE pechataet razmer fajla. Esli odnako fajl okazyvaetsya spravochnikom, to FSIZE snachala vyzyvaet funkciyu DIRECTORY dlya obrabotki vseh ukazannyh v nem fajlov. Obrati- te vnimanie na ispol'zovanie imen flagov S_IFMT i _IFDIR iz fajla STAT.H. FSIZE(NAME) /*PRINT SIZE FOR NAME*/ CHAR *NAME; \( STRUCT STAT STBUF; IF(STAT(NAME,&STBUF)== -1) \( FPRINTF(STDERR,"FSIZE:CAN'T FIND %S\N",NAME); RETURN; \) IF((STBUF.ST_MODE & S_IFMT)==S_IFDIR) DIRECTORY(NAME); PRINTF("%8LD %S\N",STBUF.ST_SIZE,NAME); \) Funkciya DIRECTORY yavlyaetsya samoj slozhnoj. Odnako znachi- tel'naya ee chast' svyazana s sozdaniem dlya obrabatyvaemogo v dannyj moment fajla ego polnogo imeni, po kotoromu mozhno vosstanovit' put' v dereve. DIRECTORY(NAME) /*FSIZE FOR ALL FILES IN NAME*/ CHAR *NAME; ( STRUCT DIRECT DIRBUF; CHAR *NBP, *NEP; INT I, FD; NBP=NAME+STRLEN(NAME); *NBP++='/'; /*ADD SLASH TO DIRECTORY NAME*/ IF(NBP+DIRSIZ+2>=NAME+BUFSIZE) /*NAME TOO LONG*/ RETURN; IF((FD=OPEN(NAME,0))== -1) RETURN; WHILE(READ(FD,(CHAR *)&DIRBUF,SIZEOF(DIRBUF))>0) \( IF(DIRBUF.D_INO==0) /*SLOT NOT IN USE*/ CONTINUE; IF(STRCMP (DIRBUF.D_NAME,".")==0 \!\! STRCMP(DIRBUF.D_NAME,"..")==0 CONTINUE; /*SKIP SELF AND PARENT*/ FOR (I=0,NEP=NBP;I<DIRSIZ;I++) *NEP++=DIRBUF.D_NAME[I]; *NEP++='\0'; FSIZE(NAME); \) CLOSE(FD); *--NBP='\0'; /*RESTORE NAME*/ ) Esli nekotoraya dyra v spravochnike v nastoyashchee vremya ne ispol'zuetsya (potomu chto fajl byl udalen), to v sootvetstvu- yushchee I-uzlovoe chislo ravno nulyu, i eta poziciya propuskaetsya. Kazhdyj spravochnik takzhe soderzhit zapis' v samom sebe, nazy- vaemuyu ".", i o svoem roditele, ".."; oni, ochevidno, takzhe dolzhny byt' propushcheny, a to programma budet rabotat' ves'ma i ves'ma dolgo. Hotya programma FSIZE dovol'no specializirovanna, ona vse zhe demonstriruet paru vazhnyh idej. vo-pervyh, mnogie prog- rammy ne yavlyayutsya "sistemnymi programmami"; oni tol'ko is- pol'zuyut informaciyu, forma ili soderzhanie kotoroj opredelya- etsya operacionnoj sistemoj. Vo-vtoryh, dlya takih programm sushchestvenno, chto predstavlenie etoj informacii vhodit tol'ko v standartnye "zagolovochnye fajly", takie kak STAT.H i DIR.H, i chto programmy vklyuchayut eti fajly, a ne pomeshchayut fakticheskie opisaniya vnutr' samih programm. 8.7. Primer - raspredelitel' pamyati V glave 5 my napisali beshitrostnyj variant funkcii ALLOC. Variant, kotoryj my napishem teper', ne soderzhit ogra- nichenij: obrashcheniya k funkciyam ALLOC i FREE mogut peremezhat'- sya v lyubom poryadke; kogda eto neobhodimo, funkciya ALLOC ob- rashchaetsya k operacionnoj sisteme za dopolnitel'noj pamyat'yu. Krome togo, chto eti procedury polezny sami po sebe, oni tak- zhe illyustriruyut nekotorye soobrazheniya, svyazannye s napisani- em mashinno-zavisimyh programm otnositel'no mashinno-nezavisi- mym obrazom, i pokazyvayut prakticheskoe primenenie struktur, ob容dinenij i konstrukcij TYPEDEF. Vmesto togo, chtoby vydelyat' pamyat' iz skompilirovannogo vnutri massiva fiksirovannogo razmera, funkciya ALLOC budet po mere neobhodimosti obrashchat'sya za pamyat'yu k operacionnoj sisteme. Poskol'ku razlichnye sobytiya v programme mogut tre- bovat' asinhronnogo vydeleniya pamyati, to pamyat', upravlyaemaya ALLOC, ne mozhet byt' nepreryvnoj. V silu etogo svobodnaya pa- myat' hranitsya v vide cepochki svobodnyh blokov. Kazhdyj blok vklyuchaet razmer, ukazatel' sleduyushchego bloka i samu svobodnuyu pamyat'. Bloki uporyadochivayutsya v poryadke vozrastaniya adresov pamyati, prichem poslednij blok (s naibol'shim adresom) ukazy- vaet na pervyj, tak chto cepochka fakticheski okazyvaetsya kol'- com. Pri postuplenii zaprosa spisok svobodnyh blokov prosmat- rivaetsya do teh por, poka ne budet najden dostatochno bol'shoj blok. Esli etot blok imeet v tochnosti trebuemyj razmer, to on otceplyaetsya ot spiska i peredaetsya pol'zovatelyu. Esli zhe etot blok slishkom velik, to on razdelyaetsya, nuzhnoe kolichest- vo peredaetsya pol'zovatelyu, a ostatok vozvrashchaetsya v svobod- nyj spisok. Esli dostatochno bol'shogo bloka najti ne udaetsya, to operacionnoj sistemoj vydelyaetsya novyj blok, kotoryj vklyuchaetsya v spisok svobodnyh blokov; zatem poisk vozobnov- lyaetsya. Osvobozhdenie pamyati takzhe vlechet za soboj prosmotr svo- bodnogo spiska v poiske podhodyashchego mesta dlya vvedeniya osvo- bozhdennogo bloka. Esli etot osvobodivshijsya blok s kakoj-libo storony primykaet k bloku iz spiska svobodnyh blokov, to oni ob容dinyayutsya v odin blok bol'shego razmera, tak chto pamyat' ne stanovitsya slishkom razdroblennoj. Obnaruzhit' smezhnye bloki prosto, potomu chto svobodnyj spisok soderzhitsya v poryadke vozrastaniya adresov. Odna iz problem, o kotoroj my upominali v glave 5, zak- lyuchaetsya v obespechenii togo, chtoby vozvrashchaemaya funkciej ALLOC pamyat' byla vyrovnena podhodyashchim obrazom dlya teh ob容ktov, kotorye budut v nej hranit'sya. Hotya mashiny i raz- lichayutsya, dlya kazhdoj mashiny sushchestvuet tip, trebuyushchij nai- bol'shih ogranichenij po razmeshcheniyu pamyati, esli dannye samogo ogranichitel'nogo tipa mozhno pomestit' v nekotoryj opredelen- nyj adres, to eto zhe vozmozhno i dlya vseh ostal'nyh tipov. Naprimer, na IBM 360/370,HONEYWELL 6000 i mnogih drugih ma- shinah lyuboj ob容kt mozhet hranit'sya v granicah, sootvetstvuyu- shchim peremennym tipa DOUBLE; na PDP-11 budut dostatochny pere- mennye tipa INT. Svobodnyj blok soderzhit ukazatel' sleduyushchego bloka v ce- pochke, zapis' o razmere bloka i samo svobodnoe prostranstvo; upravlyayushchaya informaciya v nachale nazyvaetsya zagolovkom. Dlya uproshcheniya vyravnivaniya vse bloki kratny razmeru zagolovka, a sam zagolovok vyrovnen nadlezhashchim obrazom. |to dostigaetsya s pomoshch'yu ob容dineniya, kotoroe soderzhit zhelaemuyu strukturu za- golovka i obrazec naibolee ogranichitel'nogo po vyravnivaniyu tipa: TYPEDEF INT ALIGN; /*FORCES ALIGNMENT ON PDP-11*/ UNION HEADER \( /*FREE BLOCK HEADER*/ STRUCT \( UNION HEADER *PTR; /*NEXT FREE BLOCK*/ UNSIGNED SIZE; /*SIZE OF THIS FREE BLOCK*/ \) S; ALIGN X; /*FORCE ALIGNMENT OF BLOCKS*/ \); TYPEDEF UNION HEADER HEADER; Funkciya ALLOC okruglyaet trebuemyj razmer v simvolah do nuzhnogo chisla edinic razmera zagolovka; fakticheskij blok, kotoryj budet vydelen, soderzhit na odnu edinicu bol'she, prednaznachaemuyu dlya samogo zagolovka, i eto i est' znachenie, kotoroe zapisyvaetsya v pole SIZE zagolovka. Ukazatel', vozv- rashchaemyj funkciej ALLOC, ukazyvaet na svobodnoe prostranst- vo, a ne na sam zagolovok. STATIC HEADER BASE; /*EMPTY LIST TO GET STARTED*/ STATIC HEADER *ALLOCP=NULL; /*LAST ALLOCATED BLOCK*/ CHAR *ALLOC(NBYTES)/*GENERAL-PURPOSE STORAGE ALLOCATOR*/ UNSIGNED NBYTES; \( HEADER *MORECORE(); REGISTER HEADER *P, *G; REGISTER INT NUNITS; NUNITS=1+(NBYTES+SIZEOF(HEADER)-1)/SIZEOF(HEADER); IF ((G=ALLOCP)==NULL) \( /*NO FREE LIST YET*/ BASE.S PTR=ALLOCP=G=&BASE; BASE.S.SIZE=0; \) FOR (P=G>S.PTR; ; G=P, P=P->S.PTR) \( IF (P->S.SIZE>=NUNITS) \( /*BIG ENOUGH*/ IF (P->S.SIZE==NUNITS) /*EXACTLY*/ G->S.PTR=P->S.PTR; ELSE \( /*ALLOCATE TAIL END*/ P->S.SIZE-=NUNITS; P+=P->S.SIZE; P->S.SIZE=NUNITS; \) ALLOCP=G; RETURN((CHAR *)(P+1)); \) IF(P==ALLOCP) /*WRAPPED AROUND FREE LIST*/ IF((P=MORECORE(NUNITS))==NULL) RETURN(NULL); /*NONE LEFT*/ \) \) Peremennaya BASE ispol'zuetsya dlya nachala raboty. Esli ALLOCP imeet znachenie NULL, kak v sluchae pervogo obrashcheniya k ALLOC, to sozdaetsya vyrozhdennyj svobodnyj spisok: on sostoit iz svobodnogo bloka razmera nul' i ukazatelya na samogo sebya. V lyubom sluchae zatem issleduetsya svobodnyj spisok. Poisk svobodnogo bloka podhodyashchego razmera nachinaetsya s togo mesta (ALLOCP), gde byl najden poslednij blok; takaya strategiya po- mogaet sohranit' odnorodnost' diska. Esli najden slishkom bol'shoj blok, to pol'zovatelyu predlagaetsya ego hvostovaya chast'; eto privodit k tomu, chto v zagolovke ishodnogo bloka nuzhno izmenit' tol'ko ego razmer. Vo vseh sluchayah vozvrashchae- myj pol'zovatelyu ukazatel' ukazyvaet na dejstvitel'no svo- bodnuyu oblast', lezhashchuyu na edinicu dal'she zagolovka. Obrati- te vnimanie na to, chto funkciya ALLOC pered vozvrashcheniem "P" preobrazuet ego v ukazatel' na simvoly. Funkciya MORECORE poluchaet pamyat' ot operacionnoj siste- my. Detali togo, kak eto osushchestvlyaetsya, menyayutsya, konechno, ot sistemy k sisteme. Na sisteme UNIX tochka vhoda SBRK(N) vozvrashchaet ukazatel' na "N" dopolnitel'nyh bajtov pamya- ti.(ukazatel' udvoletvoryaet vsem ogranicheniyam na vyravniva- nie). Tak kak zapros k sisteme na vydelenie pamyati yavlyaetsya sravnitel'no dorogoj operaciej, my ne hotim delat' eto pri kazhdom obrashchenii k funkcii ALLOC. Poetomu funkciya MORECORE okruglyaet zatrebovannoe chislo edinic do bol'shego znacheniya; etot bol'shij blok budet zatem razdelen tak, kak neobhodimo. Masshtabiruyushchaya velichina yavlyaetsya parametrom, kotoryj mozhet byt' podobran v sootvetstvii s neobhodimost'yu. #DEFINE NALLOC 128 /*#UNITS TO ALLOCATE AT ONCE*/ STATIC HEADER *MORECORE(NU) /*ASK SYSTEM FOR MEMORY*/ UNSIGNED NU; \( CHAR *SBRK(); REGISTER CHAR *CP; REGISTER HEADER *UP; REGISTER INT RNU; RNU=NALLOC*((NU+NALLOC-1)/NALLOC); CP=SBRK(RNU*SIZEOF(HEADER)); IF ((INT)CP==-1) /*NO SPACE AT ALL*/ RETURN(NULL); UP=(HEADER *)CP; UP->S.SIZE=RNU; FREE((CHAR *)(UP+1)); RETURN(ALLOCP); \) Esli bol'she ne ostalos' svobodnogo prostranstva, to fun- kciya SBRK vozvrashchaet "-1", hotya NULL byl by luchshim vyborom. Dlya nadezhnosti sravneniya "-1" dolzhna byt' preobrazovana k tipu INT. Snova prihoditsya mnogokratno ispol'zovat' yavnye preobrazovaniya (perevod) tipov, chtoby obespechit' opredelen- nuyu nezavisimost' funkcij ot detalej predstavleniya ukazate- lej na razlichnyh mashinah. I poslednee - sama funkciya FREE. Nachinaya s ALLOCP, ona prosto prosmatrivaet svobodnyj spisok v poiske mesta dlya vvedeniya svobodnogo bloka. |to mesto nahoditsya libo mezhdu dvumya sushchestvuyushchimi blokami, libo v odnom iz koncov spiska. V lyubom sluchae, esli osvobodivshijsya blok primykaet k odnomu iz sosednih, smezhnye bloki ob容dinyayutsya. Sledit' nuzhno tol'- ko zatem, chtoby ukazateli ukazyvali na to, chto nuzhno, i chto- by razmery byli ustanovleny pravil'no. FREE(AP) /*PUT BLOCKE AP IN FREE LIST*/ CHAR *AP; \( REGISTER HEADER *P, *G; P=(HEADER*)AP-1; /*POINT TO HEADER*/ FOR (G=ALLOCP; !(P>G && P>G->S.PTR);G=G->S.PTR) IF (G>=G->S.PTR && (P>G \!\! P<G->S.PTR)) BREAK; /*AT ONE END OR OTHER*/ IF (P+P->S.SIZE==G->S.PTR)\(/*JOIN TO UPPER NBR*/ P->S.SIZE += G->S.PTR->S.SIZE; P->S.PTR = G->S.PTR->S.PTR; \) ELSE P->S.PTR = G->S.PTR; IF (G+G->S.SIZE==P) \( /*JOIN TO LOWER NBR*/ G->S.SIZE+=P->S.SIZE; G->S.PTR=P->S.PTR; \) ELSE G->S.PTR=P; ALLOCP = G; \) Hotya raspredelenie pamyati po svoej suti zavisit ot is- pol'zuemoj mashiny, privedennaya vyshe programma pokazyvaet, kak etu zavisimost' mozhno regulirovat' i ogranichit' ves'ma nebol'shoj chast'yu programmy. Ispol'zovanie TYPEDEF i UNION pozvolyaet spravit'sya s vyravnivaniem (pri uslovii, chto funk- ciya SBRK obespechivaet podhodyashchij ukazatel'). Perevody tipov organizuyut vypolnenie yavnogo preobrazovaniya tipov i dazhe spravlyayutsya s neudachno razrabotannym sistemnym interfejsom. I hotya rassmotrennye zdes' podrobnosti svyazany s raspredele- niem pamyati, obshchij podhod ravnym obrazom primenim i k drugim situaciyam. Uprazhnenie 8-6 -------------- Funkciya iz standartnoj biblioteki CALLOC(N,SIZE) vozvra- shchaet ukazatel' na "N" ob容ktov razmera SIZE, prichem sootvet- stvuyushchaya pamyat' inicializiruetsya na nul'. napishite programmu dlya CALLOC, ispol'zuya funkciyu ALLOC libo v kachestve obrazca, libo kak funkciyu, k kotoroj proishodit obrashchenie. Uprazhnenie 8-7 --------------- Funkciya ALLOC prinimaet zatrebovannyj razmer, ne prove- ryaya ego pravdopodobnosti; funkciya FREE polagaet, chto tot blok, kotoryj ona dolzhna osvobodit', soderzhit pravil'noe znachenie v pole razmera. Usovershenstvujte eti procedury, zatrativ bol'she usilij na proverku oshibok. Uprazhnenie 8-8 --------------- Napishite funkciyu BFREE(P,N), kotoraya vklyuchaet proizvol'- nyj blok "P" iz "N" simvolov v spisok svobodnyh blokov, up- ravlyaemyj funkciyami ALLOC i FREE. S pomoshch'yu funkcii BFREE pol'zovatel' mozhet v lyuboe vremya dobavlyat' v svobodnyj spi- sok staticheskij ili vneshnij massiv.  * 9. Prilozhenie A: spravochnoe rukovodstvo po yazyku 'C' *  9.1. Vvedenie |to rukovodstvo opisyvaet yazyk 's' dlya komp'yuterov DEC PDP-11, HONEYWELL 6000, IBM sistema/370 i INTERDATA 8/32. tam, gde est' rashozhdeniya, my sosredotachivaemsya na versii dlya PDP-11, stremyas' v to zhe vremya ukazat' detali, kotorye zavisyat ot realizacii. Za malym isklyucheniem, eti rashozhdeniya neposredstvenno obuslovleny osnovnymi svojstvami ispol'zue- mogo apparatnogo oborudovaniya; razlichnye kompilyatory obychno vpolne sovmestimy. 10. Leksicheskie soglasheniya Imeetsya shest' klassov leksem: identifikatory, klyuchevye slova, konstanty, stroki, operacii i drugie razdeliteli. Probely, tabulyacii , novye stroki i kommentarii (sovmestno, "pustye promezhutki"), kak opisano nizhe, ignoriruyutsya, za is- klyucheniem teh sluchaev, kogda oni sluzhat razdelitelyami lek- sem. Neobhodim kakoj-to pustoj promezhutok dlya razdeleniya identifikatorov, klyuchevyh slov i konstant, kotorye v protiv- nom sluchae sol'yutsya. Esli sdelan razbor vhodnogo potoka na leksemy vplot' do dannogo simvola, to v kachestve sleduyushchej leksemy beretsya sa- maya dlinnaya stroka simvolov, kotoraya eshche mozhet predstavlyat' soboj leksemu. 10.1. Kommentarii Kommentarij otkryvaetsya simvolami /* i zakanchivaetsya simvolami /*. Kommentarii ne vkladyvayutsya drug v druga. 10.2. Identifikatory (imena) Identifikator - eto posledovatel'nost' bukv i cifr; per- vyj simvol dolzhen byt' bukvoj. Podcherkivanie _ schitaetsya bukvoj. Bukvy nizhnego i verhnego registrov razlichayutsya. zna- chashchimi yavlyayutsya ne bolee, chem pervye vosem' simvolov, hotya mozhno ispol'zovat' i bol'she. Na vneshnie identifikatory, ko- torye ispol'zuyutsya razlichnymi assemblerami i zagruzchikami, nakladyvatsya bolee zhestkie ogranicheniya: DEC PDP-11 7 simvolov, 2 registra HONEYWELL 6000 6 simvolov, 1 registr IBM 360/370 7 simvolov, 1 registr INTERDATA 8/32 8 simvolov, 2 registra 10.3. Klyuchevye slova Sleduyushchie identifikatory zarezervirovany dlya ispol'zova- niya v kachestve klyuchevyh slov i ne mogut ispol'zovat'sya inym obrazom: INT EXTERN ELSE CHAR REGISTER FOR FLOAT TYPEDEF DO DOUBLE STATIC WHILE STRUCT GOTO SWITCH UNION RETURN CASE LONG SIZEOF DEFAULT SHORT BREAK ENTRY UNSIGNED CONTINUE *AUTO IF Klyuchevoe slovo ENTRY v nastoyashchee vremya ne ispol'zuetsya ka- kim-libo kompilyatorom; ono zarezervirovano dlya ispol'zovaniya v budushchem. V nekotoryh realizaciyah rezerviruetsya takzhe slova FORTRAN i ASM 10.4. Konstanty Imeetsya neskol'ko vidov konstant, kotorye perechisleny nizhe. V punkte 10.6 rezyumiruyutsya harakteristiki apparatnyh sred- stv, kotorye vliyayut na razmery. 10.4.1. Celye konstanty Celaya konstanta, sostoyashchaya iz posledovatel'nosti cifr, schitaetsya vos'merichnoj, esli ona nachinaetsya s 0 (cifra nul'), i desyatichnoj v protivnom sluchae. Cifry 8 i 9 imeyut vos'merichnye znacheniya 10 i 11 sootvetstvenno. Posledovatel'- nost' cifr, kotoroj predshestvuyut simvoly 0h (nul', h-malen'- koe) ili 0h (nul' h-bol'shoe), rassmatrivaetsya kak shestnadca- tirichnoe celoe. SHestnadcatirichnye cifry vklyuchayut bukvy ot a (malen'koe) ili a (bol'shoe) do F (malen'koe) ili F (bol'shoe) so znacheniyami ot 10 do 15. Desyatichnaya konstanta, velichina kotoroj prevyshaet naibol'shee mashinnoe celoe so znakom, schi- taetsya dlinnoj; vosmerichnaya ili shestnadcatirichnaya konstanta, kotoroe prevyshaet naibol'shee mashinnoe celoe bez znaka, takzhe schitaetsya dlinnoj. 10.4.2. YAvnye dlinnye konstanty Desyatichnaya, vosmerichnaya ili shestnadcatirichnaya konstanta, za kotoroj neposredstvenno sleduet L (el'-malen'koe) ili L (el'-bol'shoe), yavlyaetsya dlinnoj konstantoj. Kak obsuzhdaetsya nizhe, na nekotoryh mashinah celye i dlinnye znacheniya mogut rassmatrivat'sya kak identichnye. 10.4.3. Simvol'nye konstanty Simvol'naya konstanta - eto simvol, zaklyuchennyj v odinoch- nye kavychki, kak, naprimer, 'X'. Znacheniem simvol'noj kons- tanty yavlyaetsya chislennoe znachenie etogo simvola v mashinnom predstavlen