This is an old revision of the document!
Deadline: 4 Aprilie 2018, ora 23:55
Deadline hard: 11 Aprilie 2018, ora 23:55
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ă implementați funcționalitatea de buffering.
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
).
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.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 sens, puteți folosi funcția SetHandleInformation
.ReadFile
să întoarcă FALSE
, iar GetLastError
să întoarcă ERROR_BROKEN_PIPE
.