Tiny programs (C, C++, C#, ...)
File detail
Source code
/*
* Soubor: proj4_io.c
* Datum: 15.12.2004
* Autor: Kamil Dudka, xdudka00@stud.fit.vutbr.cz
* Projekt: IZP c. 4 - Ceske razeni
* Popis: Rozhrani I/O
*
* Prosím, neodevzdávejte zdrojové kódy, které jsou zde k dispozici,
* jako Vaše školní projekty. Děkuji :-)
*/
/*
* Tento modul jako jedinny vyuziva stdio.h
*/
#include <stdio.h>
#include "proj4_io.h"
/*
* Poradi nazvu souboru v poli parametru predane funkci main()
*/
#define ARGNUM_READFILE 2
#define ARGNUM_WRITEFILE 3
/*
* Maximalni delka radku, ktery je mozno nacist cely
* Skutecna maximalni delka radku je 49 znaku vcetne " " a "\n"
*/
#define MAXLINE_LENGTH 80
/*
* Makro udava pro kolik osob se bude nejprve alokovat pamet
* (velikost se bude pri nedostatku zvetsovat vzdy 2x)
*/
#define ALLOC_FIRST 16
/*
* Nazev programu - bude se vypisovat v chybovych hlaskach
*/
const char ProgramName[] = "proj4";
/*
* Chybove hlasky
*/
const char ErrOpenSrc[] = "Nelze otevrit zdrojovy soubor!";
const char ErrOpenDest[] = "Nelze vytvorit vystupni soubor!";
const char ErrLongLine[] = "Prekrocena maximalni delka radku!";
const char ErrReadIO[] = "Chyba I/O behem cteni ze souboru!";
const char ErrWriteIO[] = "Chyba I/O behem zapisu do souboru!";
const char ErrBadInput[] = "Chyba ve strukture vstupnich dat!";
const char ErrBadSex[] = "Neurcite pohlavi!";
/*
* Funkce vypise chybovou hlasku danou prvnim parametrem na stderr
* Pred tuto hlasku vlozi ProgramName: a nakonec \n
* @param errorMessage - text chybove hlasky ktera se ma vypsat
*/
void printErrMsg (const char *errorMessage)
{
fprintf (stderr,ProgramName);
fprintf (stderr,": ");
fprintf (stderr,errorMessage);
fprintf (stderr,"\n");
}
/*
* Funkce vypise napovedu na stdout
* Ukonci program s kodem EXIT_SUCCESS
*/
void printHelpExit (void)
{
printf (
"Program Ceske razeni\n"
"Autor: Kamil Dudka\n"
"Program nacte data ze vstupniho souboru, seradi polozky podle zadaneho\n"
"slozeneho klice a ulozi do vystupniho souboru.\n"
"Pouziti: proj4 -h\n"
" proj4 KEY FILE1 FILE2\n"
"Popis parametru:\n"
" -h Vypise tuto obrazovku s napovedou.\n"
" KEY Slozeny klic (slozeny s cislic 1,2,3,4)\n"
" FILE1 Soubor obsahujici vstupni data\n"
" FILE2 Soubor, do ktereho se ulozi vysledek\n"
"Format vstupnich dat:\n"
" Prijmeni Jmeno Pohlavi Rok (jedna osoba na jeden radek)\n"
);
exit (EXIT_SUCCESS);
}
/*
* Tato funkce predstavuje rozhrani souboroveho IO
* @param operation - urcuje provadenou operaci:
* FIO_INIT - Otevreni souboru danych parametry fce main()
* FIO_READLINE - Nacteni radky souboru jako retezce ukonceneho nulou
* FIO_WRITELINE - Zapis informaci o jedne osobe do souboru (1 radek)
* FIO_CLOSESRC - Zavre zdrojovy soubor
* FIO_CLOSEDEST - Zavre vystupni soubor
* @param arg - ukazatel na vstupni data:
* pro FIO_INIT - ukazatel argv z funkce main()
* pro FIO_READLINE - ukazatel na radkovy buffer o velikosti MAXLINE_LENGTH
* pro FIO_WRITELINE - ukazatel na strukturu typu TPerson
* jinak se nepouziva
*/
int fileIO (EFileIO operation, void *arg)
{
/*
* Ukazatele na otevrene soubory
* Pokud soubor neni otevreny, ukazatel je NULL
*/
static FILE *fReadFile = NULL;
static FILE *fWriteFile = NULL;
char *string;
PTPerson pPerson;
int c;
switch (operation)
{
case FIO_INIT:
// Otevre zdrojovy soubor
string = ((char**)arg)[ARGNUM_READFILE];
if (NULL==(fReadFile=fopen (string, "r") ))
printErrMsg (ErrOpenSrc);
// Otevre vystupni soubor
string = ((char**)arg)[ARGNUM_WRITEFILE];
if (NULL==(fWriteFile=fopen(string, "w") ))
printErrMsg (ErrOpenDest);
// Zhodnoti celkovou uspesnost
if (NULL==fReadFile || NULL==fWriteFile)
return EXIT_FAILURE;
else
return EXIT_SUCCESS;
case FIO_READLINE:
assert (NULL!=fReadFile);
assert (NULL!=arg);
string = (char*) arg; // Ukazatel na lineBuffer
for (int i=0; i<MAXLINE_LENGTH; i++)
{
c = fgetc (fReadFile); // Nacteni jednoho znaku
switch (c)
{
case EOF:
if (!feof(fReadFile))
{ // Chyba behem cteni
printErrMsg (ErrReadIO);
return EXIT_FAILURE;
}
if (i==0)
// Nelze nacist znak
return EXIT_FAILURE;
case '\n':
// Konec radky
string[i] = 0;
return EXIT_SUCCESS;
default:
string[i] = c;
}
}
// Radka je delsi nez buffer
printErrMsg (ErrLongLine);
return EXIT_FAILURE;
case FIO_WRITELINE:
assert (NULL!=fWriteFile);
assert (NULL!=arg);
pPerson = (PTPerson) arg; // ukazatel na TPerson
assert ((pPerson->sex==0)||(pPerson->sex==1));
fprintf (fWriteFile, "%s %s %c %i\n",
pPerson->surname,
pPerson->name,
pPerson->sex ? 'Ž' : 'M',
pPerson->birth );
if (ferror(fWriteFile))
{ // Chyba behem zapisu do souboru
printErrMsg (ErrWriteIO);
return EXIT_FAILURE;
}
else
return EXIT_SUCCESS;
case FIO_CLOSESRC:
if (NULL==fReadFile)
// Soubor neni otevreny
return EXIT_FAILURE;
else
{
fclose (fReadFile);
return EXIT_SUCCESS;
}
case FIO_CLOSEDEST:
if (NULL==fWriteFile)
// Soubor neni otevreny
return EXIT_FAILURE;
{
fclose (fWriteFile);
return EXIT_SUCCESS;
}
default:// Neplatna operace
return EXIT_FAILURE;
}
}
/*
* Nacte vstupni data do bufferu, ktery si sama alokuje.
* Alokoje a inicializuje mapovaci tabulku, ve ktere se bude tridit.
* Funkce si sama osetruje chybove stavy, zpusobene strukturou vstupnich dat.
* Je-li uspesna vraci EXIT_SUCCESS.
* Neni-li uspesna neni alokovana zadna pamet.
* @param pData - ukazatel na strukturu popisujici nactena data
*/
int readData (PTData pData)
{
char lineBuffer [MAXLINE_LENGTH]; // radkovy buffer
char sex, tmpChar; // vyuziva se pri volani sscanf()
PTPerson pPerson; // ukazatel na data o jedinne osobe
void *tmp; // ukazatel na cokoliv
unsigned long capacity = ALLOC_FIRST; // aktualni velikost bloku
// Inicializace zatim nevyuzitych ukazatelu
pData->pData = NULL;
pData->mapTable = NULL;
// Pocatecni alokace pameti pro ALLOC_FIRST osob
if (NULL==( pData->pData = malloc (capacity * sizeof(TPerson)) ))
return EXIT_FAILURE;
// Na zacatku neni nactena ani jedna osoba
pData->count = 0;
// Cyklus nacitani jednotlivych osob ze souboru
while (EXIT_SUCCESS==fileIO (FIO_READLINE, lineBuffer))
{
if (pData->count >= capacity)
{ // Nedostatek pameti pro nacteni dalsi osoby
// pamet se realokuje (velikost se zvetsi 2x)
capacity <<=1;
tmp = realloc (pData->pData, capacity *sizeof(TPerson));
if (NULL==tmp)
{ // Pamet se nepodarilo realokovat
free (pData->pData);
return EXIT_FAILURE;
}
pData->pData = tmp;
}
// Ukazatel do bufferu na prave nacitanou osobu
pPerson = pData->pData + pData->count;
if (4!=sscanf (lineBuffer, "%20s %20s %c %i %c",
pPerson->surname,
pPerson->name,
&sex,
&pPerson->birth,
&tmpChar // Detekce chybne struktury
) )
{ // Chybna struktura vstupnich dat
printErrMsg (ErrBadInput);
free (pData->pData);
pData->pData = NULL;
return EXIT_FAILURE;
}
if (sex=='M')
pPerson->sex = 0;
else if (sex=='Ž')
pPerson->sex = 1;
else
{ // Neurcite pohlavi
printErrMsg (ErrBadSex);
free (pData->pData);
pData -> pData = NULL;
return EXIT_FAILURE;
}
// Inkrementace pocitadla nactenych osob
pData->count ++;
}
if (0==pData->count)
{ // Nebyla nactena ani jedna osoba
free (pData->pData);
pData->pData = NULL;
return EXIT_FAILURE;
}
// Uvolneni prebytecne pameti
pData->pData = realloc (pData->pData,
pData->count * sizeof(TPerson) );
// Alokace pameti pro mapovaci tabulku
if (NULL==( pData->mapTable = malloc (
pData->count * sizeof(unsigned)) ))
{
free (pData->pData);
pData->pData = NULL;
return EXIT_FAILURE;
}
// Inicializace mapovaci tabulky
for (unsigned int i=0; i< pData->count; i++)
pData->mapTable[i] = i;
return EXIT_SUCCESS;
}
/*
* Zapise data z bufferu do souboru podle mapovaci tabulky a
* uvolni pamet bez ohledu na uspesnost zapisu (nezapsana data se zahodi)
* Je-li uspesna vraci EXIT_SUCCESS.
* Neni-li uspesna, data jsou nenavratne ztracena (nemelo by nastat)
* @param pData - ukazatel na strukturu popisujici data v bufferu
*/
int writeData (PTData pData)
{
unsigned int i;
assert(NULL!= pData->pData);
assert(NULL!= pData->mapTable);
for (i=0; i< pData->count; i++)
if (EXIT_SUCCESS!=fileIO (FIO_WRITELINE, pData->pData +
pData->mapTable[i] ))
break;
// Uvolni pamet bufferu
free (pData->pData);
pData->pData = NULL;
// Uvolni mapovaci tabulku
free (pData->mapTable);
pData->mapTable = NULL;
// Zhodnoti uspesnost zapisu
if (i == pData->count)
return EXIT_SUCCESS;
else
return EXIT_FAILURE;
}
/*
* Nouzove ukonceni aplikace volane vyhradne z funkce main()
* Funkce vypise chybovou hlasku
* Zavre otevrene soubory, uvolni alokovanou pamet
* Ukonci program s kodem EXIT_FAILURE
* @param pData - ukazatel na nactena data; pokud nejsou nactena tak NULL
* @param errorMessage - text chybove hlasky
*/
void errorHandle (PTData pData, const char *errorMessage)
{
// Vypis chybove hlasky
printErrMsg (errorMessage);
// Zavreni otevrenych souboru
fileIO (FIO_CLOSESRC, NULL);
fileIO (FIO_CLOSEDEST, NULL);
if (NULL!= pData)
{ // Uvolneni alokovane pameti
if (NULL!= pData->pData)
free (pData->pData);
if (NULL!= pData->mapTable)
free (pData->mapTable);
}
// Ukonceni aplikace
exit (EXIT_FAILURE);
}