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