Dezvoltarea trebuie făcută exclusiv pe mașinile virtuale SO.
git
. Indicați în README link-ul către repository dacă ați folosit git.
Asigurați-vă că responsabilii de teme au drepturi de citire asupra repo-ului vostru.
Ca să vă creați un repo de gitlab în instanța facultății: în repository-ul so-assignments de pe Github se află un script Bash care vă ajută să vă creați un repository privat pe instanța de Gitlab a facultății, unde aveți la dispoziție 5 repository-uri private utile pentru teme. Urmăriți indicațiile din README și de pe wiki-ul SO.
Motivul pentru care încurajăm acest lucru este că responsabilii de teme se pot uita mai rapid pe Gitlab la temele voastre pentru a vă ajuta în cazul în care întâmpinați probleme/bug-uri. Este mai ușor să primiți suport în rezolvarea problemelor implementării voastre dacă le oferiți responsabililor de teme acces la codul sursă pe Gitlab.
Crash-course practic de git puteți găsi aici: git-immersion
student@so:~$ git clone https://github.com/systems-cs-pub-ro/so-assignments.git student@so:~$ cd so-assignments/2-stdio
În repository-ul de pe Github se vor găsi și scheletele pentru temele viitoare, care vor fi actualizate și se vor putea descărca pe viitor folosind comanda:
student@so:~$ git pull
Tot prin comanda de mai sus se pot obține toate actualizările făcute în cadrul temei 2.
Să se realizeze o implementare minimală a bibliotecii stdio, care să permită lucrul cu fișiere. Biblioteca va trebui să implementeze structura SO_FILE (similar cu FILE din biblioteca standard C), împreună cu funcțiile de citire/scriere. De asemenea, va trebui să ofere funcționalitatea de buffering.
Rezolvarea temei va trebui să genereze o bibliotecă dinamică numită libso_stdio.so
/so_stdio.dll
care implementează header-ul
so_stdio.h. În acest header găsiți semnăturile functiilor exportate de biblioteca generată de voi.
Este tipul de date care descrie un fișier deschis și este folosit de toate celelalte funcții. Un pointer la o astfel de structură este obținut la deschiderea unui fișier, folosind funcția so_fopen
.
SO_FILE *so_fopen(const char *pathname, const char *mode);
Argumentele funcției sunt similare cu cele pentru fopen
:
pathname
reprezintă calea către un fișiermode
este un string care determină modul în care va fi deschis fișierul. Poate fi unul din următoarele:r
- deschide fișierul pentru citire. Dacă fișierul nu există, funcția eșuează.r+
- deschide fișierul pentru citire și scriere. Dacă fișierul nu există, funcția eșuează.w
- deschide fișierul pentru scriere. Dacă fișierul nu există, este creat. Dacă fișierul există, este trunchiat la dimensiune 0w+
- deschide fișierul pentru citire și scriere. Dacă fișierul nu există, este creat. Dacă fișierul există, este trunchiat la dimensiune 0a
- deschide fișierul în modul append
- scriere la sfârșitul fișierului. Dacă fișierul nu există, este creat.a+
- deschide fișierul în modul append+read
. Dacă fișierul nu există, este creat.
Funcția so_fopen
alocă o structură SO_FILE
pe care o întoarce. În caz de eroare, funcția întoarce NULL
.
Închiderea unui fișier se face cu so_fclose
.
int so_fclose(SO_FILE *stream);
Închide fișierul primit ca parametru și eliberează memoria folosită de structura SO_FILE
. Întoarce 0 în caz de succes sau SO_EOF
în caz de eroare.
Aceste operații se realizează cu ajutorul funcțiilor so_fgetc
, so_fputc
, so_fread
și so_fwrite
.
int so_fgetc(SO_FILE *stream);
Citește un caracter din fișier. Întoarce caracterul respectiv sau SO_EOF
în caz de eroare.
int so_fputc(int c, SO_FILE *stream);
Scrie un caracter în fișier. Întoarce caracterul scris sau SO_EOF
în caz de eroare.
size_t so_fread(void *ptr, size_t size, size_t nmemb, SO_FILE *stream);
Citește nmemb
elemente, fiecare de dimensiune size
. Datele citite sunt stocate la adresa de memorie specificată prin ptr
. Întoarce numărul de elemente citite. În caz de eroare sau dacă s-a ajuns la sfârșitul fișierului, funcția întoarce 0.
size_t so_fwrite(const void *ptr, size_t size, size_t nmemb, SO_FILE *stream);
Scrie nmemb
elemente, fiecare de dimensiune size
. Datele ce urmează a fi scrise sunt luate de la adresa de memorie specificată prin ptr
. Întoarce numărul de elemente scrise, sau 0 în caz de eroare.
int so_fseek(SO_FILE *stream, long offset, int whence);
Mută cursorul fișierului. Noua poziție este obținută prin adunarea valorii offset
la poziția specificată de whence
, astfel:
offset
bytes față de începutul fișieruluioffset
bytes față de poziția curentăoffset
bytes față de sfârșitul fișieruluiÎntoarce 0 în caz de succes și -1 în caz de eroare.
long so_ftell(SO_FILE *stream);
Întoarce poziția curentă din fișier. În caz de eroare funcția întoarce -1.
Proprietatea esențială a bibliotecii stdio este că aceasta face buffering
. O structură SO_FILE
are un buffer asociat, iar operațiile de citire/scriere se folosesc de acest buffer:
so_fgetc
, so_fread
) întorc datele direct din buffer. Atunci când bufferul este gol sau nu există date suficiente, acesta este populat cu date din fișier, folosind API-ul pus la dispoziție de sistemul de operare (read
/ReadFile
)so_fputc
, so_fwrite
) scriu datele în buffer. În situația când bufferul este plin (sau când se apelează so_fflush
), datele se scriu în fișier, folosind API-ul pus la dispoziție de sistemul de operare(write
/WriteFile
).int so_fflush(SO_FILE *stream);
Are sens doar pentru fișierele pentru care ultima operație a fost una de scriere. În urma apelului acestei funcții, datele din buffer sunt scrise în fișier. Întoarce 0 în caz de succes sau SO_EOF
în caz de eroare.
/* Linux */ int so_fileno(SO_FILE *stream); /* Windows */ HANDLE so_fileno(SO_FILE *stream);
Întoarce file descriptorul/HANDLE-ul asociat structurii SO_FILE
.
int so_feof(SO_FILE *stream);
Întoarce o valoarea diferită de 0 dacă s-a ajuns la sfârșitul fișierului sau 0 în caz contrar.
int so_ferror(SO_FILE *stream);
Întoarce o valoarea diferită de 0 dacă s-a întâlnit vreo eroare în urma unei operații cu fișierul sau 0 în caz contrar.
SO_FILE *so_popen(const char *command, const char *type);
Lansează un proces nou, care va executa comanda specificată de parametrul command
. Ca implementare, se va executa sh -c command
, respectiv cmd /C command
, folosind un pipe pentru a redirecta intrarea standard/ieșirea standard a noului proces. Funcția întoarce o structură SO_FILE
pe care apoi se pot face operațiile uzuale de citire/scriere, ca și cum ar fi un fișier obișnuit.
Valorile parametrului type
pot fi:
so_fgetc
/so_fread
executate pe fișier vor citi de la ieșirea standard a procesului creat.so_fputc
/so_fwrite
executate pe fișier vor scrie la intrarea standard a procesului creat.int so_pclose(SO_FILE *stream);
Se apelează doar pentru fișierele deschise cu so_popen
. Așteaptă terminarea procesului lansat de so_popen
și eliberează memoria ocupată de structura SO_FILE
. Întoarce codul de ieșire al procesului (cel obținut în urma apelului waitpid
/GetExitCodeProcess
).
DEFAULT_BUF_SIZE
.so_fgetc
/so_fputc
. Apoi so_fread
/so_fwrite
pot fi implementate pe baza lor.fseek
.fflush
sau fseek
.so_fseek
trebuie avute în vedere următoarele:so_fopen
se va implementa folosind open
, so_fgetc
/so_fread
folosind read
, so_fputc
/so_write
folosind write
, etc.popen
trebuie să închideți capetele de pipe nefolosite atât în procesul părinte cât și în procesul copil.system()
so_fopen
se va implementa folosind CreateFile
, so_fgetc
/so_fread
folosind ReadFile
, so_fputc
/so_write
folosind WriteFile
, etc.popen
, înainte de a apela CreateProcess
, trebuie să marcați ca nemoștenibil capătul de pipe nefolosit de către procesul copil. În acest scop, puteți folosi funcția SetHandleInformation
.ReadFile
să întoarcă FALSE
, iar GetLastError
să întoarcă ERROR_BROKEN_PIPE
.
DO_CLEANUP=no
în scriptul run_test.sh.
Cursuri utile:
Laboratoare utile:
Resurse:
so_stdio
.Pagina de Upload:
În plus, responsabilii de teme se pot uita mai rapid pe Gitlab la temele voastre pentru a vă ajuta în cazul în care întâmpinați probleme/bug-uri. Este mai ușor să primiți suport în rezolvarea problemelor implementării voastre dacă le oferiți responsabililor de teme acces la codul sursă pe Gitlab.
Dacă ați folosit Gitlab pentru realizarea temei, indicați în README link-ul către repository. Asigurați-vă că responsabilii de teme au drepturi de citire asupra repo-ului vostru.
Pentru întrebări sau nelămuriri legate de temă folosiți lista de discuții sau canalul de IRC.
[Tema2][Platforma] Titlul problemei
. Exemple de așa da:
Exemple de așa nu:
Revedeți și secțiunea de guidelines pentru lista de discuții SO