This is an old revision of the document!


Tema 2 Bibliotecă stdio

Dată publicare: 15 Martie 2018

Deadline: 4 Aprilie 2018, ora 23:55

Deadline hard: 11 Aprilie 2018, ora 23:55

Obiectivele temei

  • TODO

Enunț

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.

SO_FILE

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șier
  • mode 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 0
    • w+ - deschide fișierul pentru citire și scriere. Dacă fișierul nu există, este creat. Dacă fișierul există, este trunchiat la dimensiune 0
    • a - 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.

Citirea și scrierea

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.

Poziționarea cursorului în fișier

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:

  • SEEK_SET - noua poziție este offset bytes față de începutul fișierului
  • SEEK_CUR - noua poziție este offset bytes față de poziția curentă
  • SEEK_END - noua poziție este 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.

Buffering

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:

  • Operațiile de citire (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)
  • Operațiile de scriere (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.

Alte funcții

/* 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.

Rularea de procese

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:

  • “r” - fișierul întors este read-only. Operațiile so_fgetc/so_fread executate pe fișier vor citi de la ieșirea standard a procesului creat.
  • “w” - fișierul întors este write-only. Operațiile 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).

Precizări/recomandări pentru implementare

  • Pentru simplitate, sugerăm să începeți implementarea cu so_fgetc/so_fputc. Apoi so_fread/so_fwrite pot fi implementate pe baza lor.
  • Pentru fișierele deschise în unul din modurile “r”, “r+”, “w”, “w+”, cursorul va fi poziționat inițial la începutul fișierului.
  • Operațiile de scriere pe un fișier deschis în modul “a” se fac ca și cum fiecare operație ar fi precedată de un seek la sfârșitul fișierului.
  • Pentru fișierele deschise în modul “a+”, scrierile se fac la fel ca mai sus. În schimb, citirea se face inițial de la începutul fișierului.
  • Conform standardului C, pentru fișierele deschise în modul update (i.e. toate modurile care conțin caracterul '+' la final: “r+”, “w+”, “a+”) trebuie respectate următoarele (de asemenea vor fi respectate în teste):
    • Între o operație de citire și o operație de scriere trebuie intercalată o operație de fseek.
    • Între o operație de scriere și o operație de citire trebuie intercalată o operație de fflush sau fseek.
  • La o operație de so_fseek trebuie avute în vedere următoarele:
    • Dacă ultima operație făcută pe fișier a fost una de citire, tot bufferul trebuie invalidat.
    • Dacă ultima operație făcută pe fișier a fost una de scriere, conținutul bufferului trebuie scris în fișier.

Precizări Linux

  • Tema se va realiza folosind funcții POSIX. Astfel so_fopen se va implementa folosind open, so_fgetc/so_fread folosind read, so_fputc/so_write folosind write, etc.
  • În implementarea popen trebuie să închideți capetele de pipe nefolosite atât în procesul părinte cât și în procesul copil.

Precizări Windows

  • Tema se va realiza folosind funcții Win32. Astfel so_fopen se va implementa folosind CreateFile, so_fgetc/so_fread folosind ReadFile, so_fputc/so_write folosind WriteFile, etc.
  • În implementarea 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.
  • Pentru a detecta EOF la citirea dintr-un pipe trebuie ca ReadFile să întoarcă FALSE, iar GetLastError să întoarcă ERROR_BROKEN_PIPE.
so/teme-new/tema-2.1552420741.txt.gz · Last modified: 2019/03/12 21:59 by adrian.sendroiu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0