Cod sursa(job #1356613)

Utilizator alexandru.eliseiAlexandru Elisei alexandru.elisei Data 23 februarie 2015 15:08:45
Problema Convertor Scor 100
Compilator c Status done
Runda rosedu_cdl_2015 Marime 5.02 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 in stringul pentru valori, respectiv pentru chei. Scriu cheile
 * in fisier o singura data, apoi scriu valorile in fisier dupa ce depasesc o 
 * limita de spatiu ocupat in memorie (FLUSH_LIMIT).
 *
 * NOTA: Am folosit vim cu: set shiftwidth = 8; set tabstop = 8;
 */

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

#define FLUSH_LIMIT	8192		/* octeti */
#define LG_MAX     	1025	
#define START_CHEIE	'"'     	/* inceput cheie */
#define STOP_CHEIE	'"'     	/* inceput cheie */
#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)

#undef ADAUGA
#define ADAUGA(s, l, m, c) do {							\
			if ((l) == (m)) {					\
				(m) <<= 1;					\
				(s) =(char *)realloc((s), (m) * sizeof(char));	\
			}							\
			(s)[(l)++] = (c);					\
} while(0)

#undef RESET
#define RESET(s, l)	do {							\
			(s)[0] = '\0';						\
			(l) = 0;						\
} while(0)

struct flag {
	unsigned short citit_chei;
	unsigned short in_hash;
	unsigned short in_date;
	unsigned short in_valoare;
	unsigned short in_cheie;
	unsigned short este_string;
	unsigned short citit_valoare;
};

int main(void)
{
	FILE *in, *out;
	char buflin[LG_MAX];

	char *chei;			/* cheiul cu cheile */
	int maloc_chei;
	int len_chei;
	char *valori;	  		/* valorile de scris */
	int maloc_val;
	int len_val;

	struct flag flags = {0};
	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");

	maloc_chei = LG_MAX;
	chei = (char *)malloc(maloc_chei * sizeof(char));
	RESET(chei, len_chei);

	maloc_val = LG_MAX;
	valori = (char *)malloc(maloc_val * sizeof(char));
	RESET(valori, len_val);

	while (fgets(buflin, LG_MAX, in) != NULL)  {

		/* Caut inceputul datelor de citit */
		if (flags.in_date == 0) {
			for (i = 0; buflin[i] != START_DATE &&
					buflin[i] != '\0' &&
					buflin[i] != EOF; i++)
				;

			if (buflin[i] == '\0' ||
					buflin[i] == EOF)
				continue;
			else {
				flags.in_date = 1;
				i++;
			}
		} else {
			i = 0;
		}

		for (; !END_OF_LINE(buflin[i]); i++) {

			if (buflin[i] == STOP_DATE) {
				fputs(valori, out);

				fclose(out);
				fclose(in);

				return 0;
			}

			if (flags.in_hash) {

				if (buflin[i] == STOP_HASH) {

					/* Printez cheiul */
					if (flags.citit_chei == 0) {
						ADAUGA(chei, len_chei,
							maloc_chei, '\n');
						fputs(chei, out);
						flags.citit_chei = 1;
					}

					/* Adaug ultima valoare */
					if (flags.citit_valoare == 0) {
						ADAUGA(valori, len_val,
							maloc_val, ',');
						flags.in_valoare = 0;
					}

					ADAUGA(valori, len_val,
							maloc_val, '\n');

					/* Scriu in fisier */
					if (len_val >= FLUSH_LIMIT) {
						ADAUGA(valori, len_val,
							maloc_val, '\0');

						fputs(valori, out);

						RESET(valori, len_val);
					}

					flags.in_hash = 0;

				/* Sunt in interiorul unei valori */
				} else if (flags.in_valoare) {

					if (!(buflin[i] == SEP_EL || 
					(flags.este_string && buflin[i] == '"'))) {

						if (flags.este_string == 0) {
							if (isblank(buflin[i]))
								continue;

							if (buflin[i] == '"') {
								flags.este_string = 1;
								continue;
							}
						}
						
						ADAUGA(valori, len_val,
							maloc_val, buflin[i]);
					} else {
						ADAUGA(valori, len_val,
							maloc_val, ',');

						flags.citit_valoare = 1;
						flags.in_valoare = 0;
						flags.este_string = 0;
					}

				/* Am terminat de citit cheia */
				} else if (buflin[i] == SEP_CV) {

					flags.citit_valoare = 0;
					flags.in_valoare = 1;

				/* Citesc o cheie */
				} else if (flags.citit_chei == 0) {

					/* Caut inceputul cheii */
					if (flags.in_cheie == 0 &&
					buflin[i] == START_CHEIE) {

						flags.in_cheie = 1;
						continue;
					}

					/*
					 * Adaug caractere numai daca am gasit
					 * inceputul cheii
					 */
					if (flags.in_cheie == 1) {

						if (buflin[i] == STOP_CHEIE) {
							ADAUGA(chei, len_chei,
								maloc_chei, ',');
							flags.in_cheie = 0;
						} else {
							ADAUGA(chei, len_chei,
								maloc_chei, buflin[i]);

						}
					}
				}

			} else if (buflin[i] == START_HASH) {
				flags.in_hash = 1;
			}
		}
	}

	fclose(out);
	fclose(in);

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