Cod sursa(job #1346383)

Utilizator alexandru.eliseiAlexandru Elisei alexandru.elisei Data 18 februarie 2015 11:01:43
Problema Convertor Scor 60
Compilator c Status done
Runda rosedu_cdl_2015 Marime 4.4 kb
/*
 * Fisierul in format JSON este un vector cu elemente hash-uri.
 * Fiecare hash este format din perechi cheie:valoare.
 *
 * Parsez fiecare linie caracter cu caracter si stochez caracterele pe care le
 * intalnesc fie in stringul cu chei, fie in cel cu valori in functie de
 * caracterele delimitatoare intalnite pana atunci.
 *
 * La sfarsitul fiecarui hash scriu cele doua stringuri in fisier.
 */

#include <stdio.h>
#include <ctype.h>

#define LG_MAX		9025		/* lungime maxima linie; 1024 + '\0' */
#define MAX_LINII	20128		/* numarul maxim de linii in fisier */
#define SEP_CV		':'		/* separa cheia de valoare */
#define SEP_EL		','		/* separa elementele hash-ului */
#define START_DATE	'['		/* inceputul datelor de citit */
#define STOP_DATE	']'		/* sfarsitul datelor de citit */
#define START_HASH	'{'		/* semnaleaza inceputul unui hash */
#define STOP_HASH	'}'		/* semnaleaza sfarsitul unui hash */

/* Masturbare intelectuala */
#undef END_OF_LINE
#define END_OF_LINE(a)	(((a) == EOF || (a) == '\n' || (a) == '\0') ? 1 : 0)

#undef EROARE
#define EROARE(c, s)	do {						  \
				fprintf(stderr, "\nEROARE - %s\n\n", (s));\
				return (c);				  \
			} while(0)

/* Sterge blankurile dintre valori si ghilimele */
char *jstrip(char *s);

/* Scrie datele in fisier, returneaza 0 in caz de eroare */
int flush_data(FILE *f, char *s);

/* Initializeaza stringurile folosite la citirea datelor */ 
void init_data(char *s, int *length);

struct flag {
	unsigned short citit_antet;
	unsigned short in_hash;
	unsigned short in_date;
	unsigned short in_valoare;
};

int main(void)
{
	FILE *in, *out;
	char buflin[LG_MAX];		/* buffer citire linia curenta */
	char antet[LG_MAX];		/* antetul cu cheile */
	char valori[LG_MAX];		/* valorile de scris */
	unsigned short nr_linii;	/* numarul de linii citite */
	struct flag flags = {0};
	int i_antet, i_valori;		/* index antet si valori */
	int i;

	if ((in = fopen("convertor.in", "r")) == NULL)
		EROARE(1, "Fisierul convertor.in nu a putut fi deschis");

	if ((out = fopen("convertor.out", "w")) == NULL)
		EROARE(2, "Fisierul convertor.out nu a putut fi scris");

	nr_linii = 0;

	while (fgets(buflin, LG_MAX, in) != NULL) {
		if (++nr_linii > MAX_LINII)
			EROARE(3, "S-a depasit numarul maxim de linii");

		for (i = 0; !(END_OF_LINE(buflin[i])); i++) {
			if (flags.in_date) {
				if (buflin[i] == STOP_DATE) {
					return 0;
					flags.in_date = 0;

				} else if (flags.in_hash) {
					if (buflin[i] == STOP_HASH) {

						if (flags.citit_antet == 0) {
							antet[i_antet] = '\0';
							jstrip(antet);
							flush_data(out, antet);
							flags.citit_antet = 1;
						}

						valori[i_valori++] = ',';
						valori[i_valori] = '\0';
						jstrip(valori);

						flush_data(out, valori);

						flags.in_hash = 0;
						flags.in_valoare = 0;

					/* Sunt in interiorul unei valori */
					} else if (flags.in_valoare) {
						if (buflin[i] != SEP_EL)
							valori[i_valori++] = buflin[i];
						else {
							valori[i_valori++] = ',';
							flags.in_valoare = 0;
						}

					/* Am terminat de citit cheia */
					} else if (buflin[i] == SEP_CV) {
						if (flags.citit_antet == 0)
							antet[i_antet++] = ',';
						flags.in_valoare = 1;

					/* Citesc o cheie */
					} else if (flags.citit_antet == 0) {
						antet[i_antet++] = buflin[i]; 
					}

				/* Iterez pana gasesc un nou hash */
				} else if (buflin[i] == START_HASH) {
					init_data(antet, &i_antet);
					init_data(valori, &i_valori);
					flags.in_hash = 1;
				}

			/* Iterez pana gasesc inceputul unui hash */
			} else if (buflin[i] == START_DATE) {
				flags.in_date = 1;
			}
		}
	}

	EROARE(5, "Date JSON incomplete sau inexistente");
}

/* Sterge blankurile dintre valori si ghilimele */
char *jstrip(char *s)
{
	int i, j;

	if (s == NULL)
		return NULL;

	j = 0;
	i = 0;
	while (s[i] != '\0') {

		/* Sterg blankurile de inceput */
		for (; isblank(s[i]); i++)
			;

		if (s[i] == '"') {
			++i;
			while (s[i] != '"')
				s[j++] = s[i++];

			/* Sterg blankurile dupa ghilimele */
			for (; s[i] != ','; i++)
				;
		} else {
			while (s[i] != ',')
				s[j++] = s[i++];
		}

		/* Copiez si virgula */
		s[j++] = s[i++];
	}

	s[j] = '\0';

	return s;
}

/* Scrie datele in fisier, returneaza 0 in caz de eroare */
int flush_data(FILE *f, char *s)
{
	if (s == NULL)
		return 0;

	if (fprintf(f, "%s\n", s) == 0)
		return 0;

	return 1;
}

/* Initializeaza stringurile folosite la citirea datelor */ 
void init_data(char *s, int *length)
{
	s[0] = 0;
	*length = 0;
}