Cod sursa(job #1349954)

Utilizator alexandru.eliseiAlexandru Elisei alexandru.elisei Data 20 februarie 2015 16:21:50
Problema Convertor Scor 70
Compilator c Status done
Runda rosedu_cdl_2015 Marime 5.41 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 intr-un buffer pentru cuvinte. Cand intalnesc un caracter
 * delimitator sterg simbolurile specifice JSON si adaug cuvantul curent fie in
 * stringul de valori, fie in cel de chei.
 *
 * La sfarsitul fiecarui hash scriu cele doua stringuri in fisier.
 */

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

#define LG_MAX     	9999
#define START_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)

/* Sterge caracterele nevalide */
char *strip_key(char *s, int len);
char *strip_val(char *s, int len);

/* Adauga cuvantul curent */
char *add_word(char *dest, char *cuv);

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

/* Initializeaza bufferul */
void init_buf(char *s, int *len);

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 = NULL;   		/* buffer citire linia curenta */
	char antet[LG_MAX];		/* antetul cu cheile */
	char valori[LG_MAX];  		/* valorile de scris */
	char *bufcuv;		       	/* cuvintul curent parsat */
	int maloc_cuv;
	struct flag flags = {0};
	int ibuf;       		/* iterator pentru buffer cuvinte */
	size_t nbuf = 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_cuv = LG_MAX;
	bufcuv = (char *)malloc(maloc_cuv * sizeof(char));

	while (getline(&buflin, &nbuf, in) != -1 || buflin[0] == EOF)  {

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

			if (!END_OF_LINE(buflin[i])) {
				flags.in_date = 1;
				i++;
			}
		} else {
			i = 0;
		}

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

			if (buflin[i] == STOP_DATE)
				return 0;

			if (flags.in_hash) {

				if (buflin[i] == STOP_HASH) {

					if (flags.citit_antet == 0) {
						flush_data(out, antet);
						flags.citit_antet = 1;
					}

					strip_val(bufcuv, ibuf);
					add_word(valori, bufcuv);
					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) {

						if (maloc_cuv < ibuf - 1) {
							for (; maloc_cuv < (ibuf -1);
								       maloc_cuv <<= 1)
							;	
							bufcuv = (char *)realloc(bufcuv,
								maloc_cuv * sizeof(char));
						}

						bufcuv[ibuf++] = buflin[i];
					} else {
						strip_val(bufcuv, ibuf);
						add_word(valori, bufcuv);
						init_buf(bufcuv, &ibuf);

						flags.in_valoare = 0;
					}

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

					if (flags.citit_antet == 0) {
						strip_key(bufcuv, ibuf);
						add_word(antet, bufcuv);   
					}
					init_buf(bufcuv, &ibuf);

					flags.in_valoare = 1;

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

					if (maloc_cuv < ibuf - 1) {
						for (; maloc_cuv < (ibuf -1);
								maloc_cuv <<= 1)
							;	
						bufcuv = (char *)realloc(bufcuv,
								maloc_cuv * sizeof(char));
					}

					bufcuv[ibuf++] = buflin[i];
				}

			} else if (buflin[i] == START_HASH) {
				init_buf(bufcuv, &ibuf);
				antet[0] = '\0';
				valori[0] = '\0';

				flags.in_hash = 1;
			}
		}

		/* Fortez getline sa imi realoce memorie pentru buffer */
		free(buflin);
		buflin = NULL;
		nbuf = 0;
	}

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

/* Sterge caracterele nevalide din cheie */
char *strip_key(char *s, int len)
{
	int i, j;

	s[len] = '\0';

	for (i = 0; s[i] != '"'; i++)
		;
	i++;

	j = 0;
	while (s[i] != '"')
		if (isprint(s[i]))
			s[j++] = s[i++];
		else
			i++;
	s[j] = '\0';

	return s;
}

/* Sterge caracterele nevalide din valoare */
char *strip_val(char *s, int len)
{
	int i, j;

	s[len] = '\0';

	for (i = 0; isblank(s[i]) || (!isprint(s[i])); i++)
		;

	if (s[i] == '"')
		return strip_key(s, len);

	j = 0;
	/* Blankurile apar numai intre ghilimele */
	while (s[i] != '\0' && !isblank(s[i]))
		if (isprint(s[i]))
			s[j++] = s[i++];
		else
			i++;
	s[j] = '\0';

	return s;
}

/* Adauga cuvantul curent */
char *add_word(char *dest, char *cuv)
{
	strcat(dest, cuv);
	strcat(dest, ",");

	return dest;
}


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

	fflush(f);
	return 1;
}

/* Initializeaza stringurile folosite la citirea datelor */
void init_buf(char *s, int *len)
{
	s[0] = '\0';
	*len = 0;
}