/*
* 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 64 /* 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;
int counter;
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';
counter = 0;
while (fgets(buflin, LG_MAX, in) != NULL || 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) {
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) {
//printf("maloc_valori = %d, counter = %d\n", maloc_valori,
//counter);
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';
/*
printf("SEP_EL\n");
printf("bufcuv = |%s|\n\n", bufcuv);
*/
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';
/*
printf("STOP_CHEIE\n");
printf("bufcuv = |%s|\n\n", bufcuv);
*/
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;
}