/* zadatak 13, Milan Ruzic 394/2000 */ /* u zadatku se koriste dve dvostruko povezane liste - jedna pocinje od pocetka, a druga od kraja. Ako je predhodna/sled stranica vec prikazana, ona se nalazi u nekoj listi i pocetak ne mora da se racuna. Medjutim, ako se na pr pritisne End, pocetak pred strane mora da se racuna iduci unazad. Pri tome se posebno mora voditi racuna o mogucem zasebnom pojavljivanju CR znaka, i njegovim razlicitim interpretacijama zavisno od opcije (b/t). U textualnom rezimu nije najbolje definisano sta raditi kada se naleti na EOF znak. DOSov type jednostavno stane, ali u programu sa PgUp,PgDn,.. opcijama to nije resenje. */ #include #include #include #include /* scan codovi */ #define HomeSc 0x47 #define EndSc 0x4F #define PgdnSc 0x51 #define PgupSc 0x49 #define EscSc 0x1B /*ovo je ASCII kod za escape kojim se izlazi iz prog */ int _imode; /* koriste se iste konstante kao za _fmode O_BINARY za binarnu interpretaciju i O_TEXT za textualnu */ typedef struct {long int st_pos; int *prev,*next;} listElem; typedef listElem *listpok; /* u obe liste prev pokazuje na stranu blizu pocetku file-a; potrebne su razlicite f-je za dodavanje elementa i brisanje cele liste, ali zato setnja kroz strane u main f-ji ne zavisi od aktivne liste */ int appendTopList(long pos,listpok lastEl) { listpok newEl=malloc(sizeof(listElem)); newEl->prev=lastEl; newEl->next=NULL; newEl->st_pos=pos; lastEl->next=newEl; return newEl; } int appendBottList(long pos,listpok lastEl) { listpok newEl=malloc(sizeof(listElem)); newEl->next=lastEl; newEl->prev=NULL; newEl->st_pos=pos; lastEl->prev=newEl; return newEl; } void disposeTopList(listpok firstEl) { while (firstEl->next!=NULL) { firstEl=firstEl->next; free(firstEl->prev); } free(firstEl); } void disposeBottList(listpok firstEl) { while (firstEl->prev!=NULL) { firstEl=firstEl->prev; free(firstEl->next); } free(firstEl); } /************************************************************************/ long displayPage(FILE *fp) /*vraca poziciju pocetka sled strane */ {char c; clrscr(); if (_imode==O_BINARY) { while (wherey()<25 && fread(&c,1,1,fp)) {if (c!='\n') putch(c); else putchar('\n'); /* putch ne radi CR+LF vec samo LF */ fseek(fp,0,SEEK_CUR); /* ovo je bug TC-a */ } /*u poslednjoj liniji treba paziti da se nepotrebno ne odstampa '\n' */ while ( fread(&c,1,1,fp) && c!='\n'&& wherex()<80) { putch(c); fseek(fp,0,SEEK_CUR); } } else { while (wherey()<25 && (c=fgetc(fp))!=EOF) putchar(c); while ((c=fgetc(fp))!=EOF && c!='\n'&& wherex()<80) putchar(c); if (c==EOF) fseek(fp,0,SEEK_END); } if (c!='\n' && c!=EOF) fseek(fp,-1L,SEEK_CUR); return ftell(fp); } /*************************************************************************/ /* sled f-ja nalazi pocetak predhodne stranice; posto u textualnom reximu ima problema sa translacijom karaktera kad se cita po jedan byte, u oba slucaja se na nizem nivou radi u O_BINARY modu, s time sto se u /t opciji ignorise CR znak (posto se to se desava u O_TEXT modu); na izlazu se vraca u originalni mod. Bilo bi efikasnije u ovoj proceduri iskljuciti ili smanjiti buffer stream-a (posto se cita unazad), ali onda TC ne radi najbolje */ long findPrevPos(FILE *fp) { long fpos=ftell(fp)-1; int chars_left=80*25, /*broj mesta na raspolaganju */ chars_tren; char c; fseek(fp,fpos,SEEK_SET); setmode(fileno(fp),O_BINARY); fread(&c,1,1,fp); /*posled '\n' se nece stampati pa ga treba ignore */ if (c=='\n') chars_left+=80; fseek(fp,fpos,SEEK_SET); /*mora opet zbog jos jednog buga TC-a */ if (_imode==O_BINARY) while (chars_left>0) { chars_tren=0; while (fpos && fread(&c,1,1,fp) && c!='\n' && c!='\r' && chars_tren0) {chars_tren=0; while (fpos && fread(&c,1,1,fp) && c!='\n' && chars_trenst_pos=0; /* sledi inicijalizacija lista */ topdown->prev=NULL; topdown->next=NULL; fseek(infile,0,SEEK_END); bottup->st_pos=findPrevPos(infile); bottup->prev=NULL; bottup->next=NULL; fseek(infile,0,SEEK_SET); trenpok=topdown; /* trenutna pozicija je 1. stranica */ /* kod gornje liste se uvek dodaje pozicija sledece strane, posto je ona poznata posle prikazivanja trenutne */ fpos=displayPage(infile); if (fpos>bottup->st_pos) fpos=bottup->st_pos; appendTopList(fpos,topdown); while ((inkey=getch())!=EscSc) if (inkey==0) { inkey=getch(); if (trenpok->st_pos==0) { trenpok=topdown; if (inkey==HomeSc || inkey==PgupSc ) continue; } else if (trenpok->st_pos==bottup->st_pos) { trenpok=bottup; if (inkey==EndSc || inkey==PgdnSc ) continue; } switch (inkey) { case HomeSc : trenpok=topdown; fseek(infile,0,SEEK_SET); displayPage(infile); break; case EndSc : trenpok=bottup; fseek(infile,bottup->st_pos,SEEK_SET); displayPage(infile); break; case PgupSc : if (trenpok->prev!=NULL) trenpok=trenpok->prev; else {fseek(infile,trenpok->st_pos,SEEK_SET); trenpok=appendBottList(findPrevPos(infile),trenpok); } fseek(infile,trenpok->st_pos,SEEK_SET); displayPage(infile); break; case PgdnSc : /* nikad nije (trenpok->next==NULL) */ trenpok=trenpok->next; fseek(infile,trenpok->st_pos,SEEK_SET); fpos=displayPage(infile); if (fpos>bottup->st_pos) fpos=bottup->st_pos; if (trenpok->next==NULL) appendTopList(fpos,trenpok); break; } /* end switch */ } /*end if special key */ fclose(infile); disposeTopList(topdown); disposeBottList(bottup); return 0; }