Table of Contents

Tema 2 Bibliotecă stdio

  • Dată publicare: 14.03.2019
  • Deadline: 03.04.2019, ora 23:55
  • Deadline hard: 10.04.2019, ora 23:55

Obiectivele temei

Dezvoltarea temei

Dezvoltarea trebuie făcută exclusiv pe mașinile virtuale SO.

Nu rulați testele “local” (pe calculatoarele voastre sau în mașinile voastre virtuale). Veți avea diferențe față de vmchecker, iar echipa de SO nu va depana testele care merg “local”, dar pe vmchecker nu merg. Pe vmchecker sunt aceleași mașinile virtuale ca cele de pe wiki.

Este încurajat ca lucrul la tema să se desfășoare folosind 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

Atât semnătura pentru funcția de comparare (veți vedea mai jos pentru ce vă trebuie), cât și testele publice care se rulează pe vmchecker se găsesc pe repo-ul so-assignments de pe Github:

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.

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ă 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.

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:

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:

Î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:

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:

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

Precizări Linux

Precizări Windows

Testare

Înainte de a uploada tema, asigurați-vă că implementarea voastră trece testele pe mașinile virtuale. Dacă apar probleme în rezultatele testelor, acestea se vor reproduce și pe vmchecker.

Pentru a inspecta diferențele între output-ul bibliotecii voastre și fișierele de referință ale checker-ului setați DO_CLEANUP=no în scriptul run_test.sh.

Materiale ajutătoare

Cursuri utile:

Laboratoare utile:

Resurse:

Pagina de Upload:

Repo-ul de pe Github conține și 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.

Î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.

Suport, întrebări și clarificări

Pentru întrebări sau nelămuriri legate de temă folosiți lista de discuții sau canalul de IRC.

Orice intrebare pe mailing list e recomandat să aibă subiectul de forma [Tema2][Platforma] Titlul problemei. Exemple de așa da:

  • [Tema2][Linux] Biblioteca nu se generează
  • [Tema2][Windows] No makefile found
  • [Tema2][General] Neclaritate enunt: Dimensiune buffer

Exemple de așa nu:

  • Problema la tema 2
  • eroare tema 2
  • eroare la dimensiuni

Revedeți și secțiunea de guidelines pentru lista de discuții SO