Cod sursa(job #1346816)

Utilizator alexandru.eliseiAlexandru Elisei alexandru.elisei Data 18 februarie 2015 17:12:53
Problema Convertor Scor 70
Compilator c Status done
Runda rosedu_cdl_2015 Marime 4.77 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 <ctype.h>
#include <string.h>

#define LG_MAX		99999
#define MAX_LINII	99999		/* 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 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[LG_MAX];		/* buffer citire linia curenta */
	char antet[LG_MAX] = "";	/* antetul cu cheile */
	char valori[LG_MAX] = "";	/* valorile de scris */
	char bufcuv[LG_MAX];		/* cuvintul curent parsat */
	unsigned short nr_linii;	/* numarul de linii citite */
	struct flag flags = {0};
	int ibuf;			/* iterator pentru buffer cuvinte */
	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;

				} else 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)
							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) {
						bufcuv[ibuf++] = buflin[i]; 
					}

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

					flags.in_hash = 1;
				}

			} else if (buflin[i] == START_DATE) {
				flags.in_date = 1;
			}
		}
	}

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

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

	if (s == NULL)
		return NULL;

	s[len] = '\0';

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

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

	return s;
}

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

	if (s == NULL)
		return NULL;

	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]))
		s[j++] = s[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 (s == NULL)
		return 0;

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

	return 1;
}

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