trafi

Transducteurs finis
git clone git://git.asteride.xyz/trafi.git
Journaux | Fichiers | Références

json.c (4361B)


      1 #include <assert.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <unistd.h>
      5 
      6 #include <stdio.h>
      7 
      8 #include "json.h"
      9 #include "tampex.h"
     10 
     11 /* c est un espace? */
     12 #define ESPACE(c) ((c) == ' ' || \
     13                    (c) == '\t' || \
     14                    (c) == '\n' || \
     15                    (c) == '\r')
     16 
     17 /* c peut être dans un nombre? */
     18 #define DANSNOMB(c) ((c) == '-' || \
     19                      (c) == '+' || \
     20                      (c) == '.' || \
     21                     ((c) >= '0' && (c) <= '9') || \
     22                      (c) == 'e' || \
     23                      (c) == 'E')
     24 
     25 /* Lire dans le tampex *jeton une chaîne de caractères commençant à *texte et
     26  * devant se terminer avant fin.
     27  * Renvoie le nombre de caractères écrits dans *jeton, ou -1 en cas
     28  * d’erreur. */
     29 static ssize_t lire_ccar(char **texte, char *fin, char **jeton);
     30 
     31 /* Lire dans le tampex *jeton un nombre en commençant à *texte et devant se
     32  * terminer avant fin.
     33  * Renvoie le nombre de caractères écrits dans *jeton, ou -1 en cas
     34  * d’erreur. */
     35 static ssize_t lire_nomb(char **texte, char *fin, char **jeton);
     36 
     37 /* Échapper dans *jeton le ou les caractères dans *texte et devant se terminer
     38  * avant fin. Augmente cecr du nombre de caractères échappés.
     39  * Renvoie 0, ou -1 en cas d’erreur. */
     40 static int echapper(char **texte, char *fin, char **jeton, size_t *cecr);
     41 
     42 ssize_t
     43 json_segmenter(char **json, size_t *reste, char **jeton, int *type)
     44 {
     45 	char *pos; /* Position dans *json. */
     46 	char *fin; /* Fin de *json. */
     47 	size_t vr; /* Valeur de renvoi. */
     48 
     49 	assert(json);
     50 	assert(*json);
     51 	assert(reste);
     52 	assert(jeton);
     53 	assert(*jeton);
     54 
     55 	fin = *json + *reste;
     56 
     57 	/* Manger les espaces. */
     58 	for (pos = *json; ESPACE(*pos) && pos != fin; pos++) ;
     59 
     60 	if (pos == fin) return 0;
     61 	assert(pos < fin);
     62 
     63 	vr = 1;
     64 
     65 	/* Détecter le type du jeton selon le premier caractère. */
     66 	switch (*pos++) {
     67 	case '[':
     68 		*type = JSON_T_CRCH_GCH; break;
     69 	case ']':
     70 		*type = JSON_T_CRCH_DRT; break;
     71 	case '{':
     72 		*type = JSON_T_ACCO_GCH; break;
     73 	case '}':
     74 		*type = JSON_T_ACCO_DRT; break;
     75 	case ':':
     76 		*type = JSON_T_DPTS; break;
     77 	case ',':
     78 		*type = JSON_T_VIRG; break;
     79 	case '"':
     80 		*type = JSON_T_CCAR;
     81 		vr = lire_ccar(&pos, fin, jeton);
     82 		break;
     83 	case '-': case '.': case '0': case '1': case '2': case '3': case '4':
     84 	case '5': case '6': case '7': case '8': case '9':
     85 		pos--;
     86 		*type = JSON_T_NOMB;
     87 		vr = lire_nomb(&pos, fin, jeton);
     88 		break;
     89 	case 't':
     90 		*type = JSON_T_VRAI;
     91 		if (fin - pos < 3) return -1;
     92 		pos += 3;
     93 		break;
     94 	case 'f':
     95 		*type = JSON_T_FAUX;
     96 		if (fin - pos < 3) return -1;
     97 		pos += 4;
     98 		break;
     99 	case 'n':
    100 		*type = JSON_T_NULL;
    101 		if (fin - pos < 3) return -1;
    102 		pos += 3;
    103 		break;
    104 	default:
    105 		return -1;
    106 	}
    107 
    108 	*reste = fin - pos;
    109 	*json = pos;
    110 
    111 	return vr;
    112 }
    113 
    114 static ssize_t
    115 lire_ccar(char **texte, char *fin, char **jeton)
    116 {
    117 	size_t cecr; /* Nombre de caractères écrits. */
    118 	char *pos; /* Position dans texte. */
    119 
    120 	assert(texte);
    121 	assert(*texte);
    122 	assert(fin),
    123 	assert(jeton);
    124 	assert(*jeton);
    125 
    126 	cecr = 0;
    127 	pos = *texte;
    128 
    129 	while (*pos != '"') {
    130 		if (pos >= fin) return -1;
    131 		if (*pos == '\\') {
    132 		    pos++;
    133 		    if (echapper(&pos, fin, jeton, &cecr) < 0) return -1;
    134 		    continue;
    135 		}
    136 		if (tampex_minim((void **)jeton, cecr) < 0) return -1;
    137 		(*jeton)[cecr++] = *pos++;
    138 	}
    139 
    140 	*texte = pos + 1;
    141 	return cecr;
    142 }
    143 
    144 static int
    145 echapper(char **texte, char *fin, char **jeton, size_t *cecr)
    146 {
    147 	char *pos;
    148 	char c;
    149 
    150 	assert(texte);
    151 	assert(*texte);
    152 	assert(fin),
    153 	assert(jeton);
    154 	assert(*jeton);
    155 
    156 	pos = *texte;
    157 
    158 	if (pos >= fin)
    159 		return -1;
    160 
    161 	switch (*pos) {
    162 	case 'u': return -1; /* À implémenter. */
    163 	case 'b': c = '\b'; break;
    164 	case 'f': c = '\f'; break;
    165 	case 'n': c = '\n'; break;
    166 	case 'r': c = '\r'; break;
    167 	case 't': c = '\t'; break;
    168 	default:  c = *pos; /* Les autres caractères restent. */
    169 	}
    170 
    171 	if (tampex_minim((void **)jeton, *cecr) < 0) return -1;
    172 	(*jeton)[(*cecr)++] = c;
    173 
    174 	*texte = pos + 1;
    175 
    176 	return 0;
    177 }
    178 
    179 static ssize_t
    180 lire_nomb(char **texte, char *fin, char **jeton)
    181 {
    182 	size_t cecr; /* Nombre de caractères écrits. */
    183 	char *pos; /* Position dans texte. */
    184 
    185 	assert(texte);
    186 	assert(*texte);
    187 	assert(fin),
    188 	assert(jeton);
    189 	assert(*jeton);
    190 
    191 
    192 	cecr = 0;
    193 	pos = *texte;
    194 
    195 	while (DANSNOMB(*pos)) {
    196 		if (pos >= fin) return -1;
    197 		if (tampex_minim((void **)jeton, cecr) < 0) return -1;
    198 		(*jeton)[cecr++] = *pos++;
    199 	}
    200 
    201 	*texte = pos;
    202 	return cecr;
    203 }