Česky
Kamil Dudka

Tiny programs (C, C++, C#, ...)

File detail

Name:Downloadproj4_io.c [Download]
Detected charset:ISO-8859-2 - [Download as UTF-8]
Location: tiny > IZP > proj4
Size:9.3 KB
Last modification:2009-12-21 17:54

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);
}