/*
* 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 1024 /* 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) { \
fprintf(stderr, "\nEROARE - %s\n\n", (s)); \
return (c); \
}
#undef ADAUGA
#define ADAUGA(s, l, m, c){ \
if (l == m) { \
m <<= 1; \
s =(char *)realloc(s, m * sizeof(char));\
} \
s[l++] = c; \
}
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 citit_valoare;
};
/* 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;
int len_antet;
char *valori; /* valorile de scris */
int maloc_val;
int len_val;
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_antet = LG_MAX;
antet = (char *)malloc(maloc_antet * sizeof(char));
len_antet = 0;
maloc_val = LG_MAX;
valori = (char *)malloc(maloc_val * sizeof(char));
len_val = 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) {
/* POATE FPUTS? */
fprintf(out, "%s\n", antet);
flags.citit_antet = 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');
/* POATE FPUTS? */
fprintf(out, "%s", valori);
valori[0] = '\0';
len_val = 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;
}
}
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_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) {
ADAUGA(antet, len_antet,
maloc_antet, ',');
flags.in_cheie = 0;
} else {
ADAUGA(antet, len_antet,
maloc_antet, buflin[i]);
}
}
}
} else if (buflin[i] == START_HASH) {
flags.in_hash = 1;
}
}
}
fclose(out);
fclose(in);
EROARE(5, "Date JSON incomplete sau inexistente");
}