Cod sursa(job #1356124)

Utilizator alexandru.eliseiAlexandru Elisei alexandru.elisei Data 23 februarie 2015 10:54:07
Problema Convertor Scor 70
Compilator c Status done
Runda rosedu_cdl_2015 Marime 7.07 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 FLUSH_LIMIT	96		/* 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)

struct flag {
	unsigned short citit_antet;
	unsigned short in_hash;
	unsigned short in_date;
	unsigned short in_valoare;
	unsigned short in_cheie;
	unsigned short este_string;
	unsigned short scrie_fisier;
};

/* 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, int *maloc, struct flag *flags);

/* 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);

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

	char *antet;			/* antetul cu cheile */
	int maloc_antet;
	char *valori;	  		/* valorile de scris */
	int maloc_valori;
	char *bufcuv;		       	/* cuvintul curent parsat */
	int maloc_cuv;

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

	maloc_cuv = LG_MAX;
	bufcuv = (char *)malloc(maloc_cuv * sizeof(char));

	maloc_antet = LG_MAX;
	antet = (char *)malloc(maloc_antet * sizeof(char));

	maloc_valori = LG_MAX;
	valori = (char *)malloc(maloc_antet * sizeof(char));

	bufcuv[0] = '\0';
	ibuf = 0;

	antet[0] = '\0';
	valori[0] = '\0';

	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) {
				fprintf(out, "%s", valori);

				fclose(out);
				fclose(in);

				return 0;
			}

			if (flags.in_hash) {

				if (buflin[i] == STOP_HASH) {

					/* Printez antetul */
					if (flags.citit_antet == 0) {
						fprintf(out, "%s\n", antet);
						flags.citit_antet = 1;
					}

					/* Adaug ultima valoare */
					if (ibuf != 0) {
						bufcuv[ibuf] = '\0';

						add_word(&valori, bufcuv, &maloc_valori, &flags);

						bufcuv[0] = '\0';
						ibuf = 0;

						flags.in_valoare = 0;
					}
					strcat(valori, "\n");

					/* Scriu in fisier */
					if (flags.scrie_fisier) {
						
						fprintf(out, "%s", valori);

						maloc_valori = FLUSH_LIMIT;
						valori = (char *)malloc(maloc_valori * sizeof(char));
						valori[0] = '\0';

						flags.scrie_fisier = 0;
					}

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

						/* Realoc memoria pentru bufcuv */
						if (maloc_cuv < ibuf - 3) {
							for (; maloc_cuv < (ibuf - 3);
								       maloc_cuv <<= 1)
								;	
							bufcuv = (char *)realloc(bufcuv,
								maloc_cuv * sizeof(char));
						}

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

					} else {

						bufcuv[ibuf] = '\0';

						add_word(&valori, bufcuv, &maloc_valori, &flags);

						bufcuv[0] = '\0';
						ibuf = 0;

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

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

					flags.in_valoare = 1;

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

					if (flags.in_cheie == 0 &&
					buflin[i] == START_CHEIE) {

						flags.in_cheie = 1;
						continue;
					}

					if (flags.in_cheie == 1) {

						if (buflin[i] == STOP_CHEIE) {

							bufcuv[ibuf] = '\0';

							add_word(&antet, bufcuv, &maloc_antet, &flags);   

							bufcuv[0] = '\0';
							ibuf = 0;

							flags.in_cheie = 0;
						} else {

							/* Realoc memoria pentru bufcuv */
							if (maloc_cuv < ibuf - 3) {
								for (; maloc_cuv < (ibuf - 3);
										maloc_cuv <<= 1)
									;	
								bufcuv = (char *)realloc(bufcuv,
										maloc_cuv * sizeof(char));
							}

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

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

	fclose(out);
	fclose(in);

	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 (isalnum(s[i]))
			s[j++] = s[i++];
		else
			i++;
	s[j] = '\0';

	return s;
}

/* Adauga cuvantul curent */
char *add_word(char **dest, char *cuv, int *maloc, struct flag *flags)
{
	int len;

	/* Adaug , si newline */
	len = strlen(*dest) + strlen(cuv) + 3;

	/* Realocam daca este cazul */
	if (*maloc < len) {
		flags->scrie_fisier = 1;
		*maloc += FLUSH_LIMIT;
		*dest = (char *)realloc(*dest, *maloc * sizeof(char));
	}

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