hipack-parser.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. /*
  2. * hipack-parser.c
  3. * Copyright (C) 2015 Adrian Perez <aperez@igalia.com>
  4. *
  5. * Distributed under terms of the MIT license.
  6. */
  7. #include "hipack.h"
  8. #include <assert.h>
  9. #include <string.h>
  10. #include <stdbool.h>
  11. #include <stdlib.h>
  12. #include <ctype.h>
  13. #include <errno.h>
  14. const char* HIPACK_READ_ERROR = "Error reading from input";
  15. enum status {
  16. kStatusOk = 0,
  17. kStatusEof,
  18. kStatusError,
  19. kStatusIoError,
  20. };
  21. typedef enum status status_t;
  22. struct parser {
  23. int (*getchar) (void*);
  24. void *getchar_data;
  25. int look;
  26. unsigned line;
  27. unsigned column;
  28. const char *error;
  29. };
  30. #define P struct parser* p
  31. #define S status_t *status
  32. #define CHECK_OK status); \
  33. if (*status != kStatusOk) goto error; \
  34. ((void) 0
  35. #define DUMMY ) /* Makes autoindentation work. */
  36. #undef DUMMY
  37. #define DUMMY_VALUE ((hipack_value_t) { .type = HIPACK_BOOL, .annot = NULL })
  38. static hipack_value_t parse_value (P, S);
  39. static void parse_keyval_items (P, hipack_dict_t *result, int eos, S);
  40. static inline bool
  41. string_to_intrinsic_annot (const hipack_string_t *hstr, hipack_type_t *type)
  42. {
  43. assert (type);
  44. static const struct {
  45. const char * const str;
  46. int type;
  47. } annots[] = {
  48. { ".int", HIPACK_INTEGER },
  49. { ".float", HIPACK_FLOAT },
  50. { ".bool", HIPACK_BOOL },
  51. { ".string", HIPACK_STRING },
  52. { ".list", HIPACK_LIST },
  53. { ".dict", HIPACK_DICT },
  54. };
  55. if (hstr->size < 4)
  56. return false;
  57. for (uint8_t i = 0; i < sizeof (annots) / sizeof (annots[0]); i++) {
  58. if (strncmp (annots[i].str, (const char*) hstr->data, hstr->size) == 0) {
  59. *type = annots[i].type;
  60. return true;
  61. }
  62. }
  63. return false;
  64. }
  65. static inline bool
  66. is_hipack_whitespace (int ch)
  67. {
  68. switch (ch) {
  69. case 0x09: /* Horizontal tab. */
  70. case 0x0A: /* New line. */
  71. case 0x0D: /* Carriage return. */
  72. case 0x20: /* Space. */
  73. return true;
  74. default:
  75. return false;
  76. }
  77. }
  78. static inline bool
  79. is_hipack_key_character (int ch)
  80. {
  81. switch (ch) {
  82. /* Keys do not contain whitespace */
  83. case 0x09: /* Horizontal tab. */
  84. case 0x0A: /* New line. */
  85. case 0x0D: /* Carriage return. */
  86. case 0x20: /* Space. */
  87. /* Characters are forbidden in keys by the spec. */
  88. case '[':
  89. case ']':
  90. case '{':
  91. case '}':
  92. case ':':
  93. case ',':
  94. return false;
  95. default:
  96. return true;
  97. }
  98. }
  99. static inline bool
  100. is_number_char (int ch)
  101. {
  102. switch (ch) {
  103. case '.': return true;
  104. case '+': return true;
  105. case '-': return true;
  106. case '0': return true;
  107. case '1': return true;
  108. case '2': return true;
  109. case '3': return true;
  110. case '4': return true;
  111. case '5': return true;
  112. case '6': return true;
  113. case '7': return true;
  114. case '8': return true;
  115. case '9': return true;
  116. case 'a': case 'A': return true;
  117. case 'b': case 'B': return true;
  118. case 'c': case 'C': return true;
  119. case 'd': case 'D': return true;
  120. case 'e': case 'E': return true;
  121. case 'f': case 'F': return true;
  122. default:
  123. return false;
  124. }
  125. }
  126. static inline bool
  127. is_octal_nonzero_digit (int ch)
  128. {
  129. return (ch > '0') && (ch < '8');
  130. }
  131. static inline int
  132. xdigit_to_int (int xdigit)
  133. {
  134. assert ((xdigit >= '0' && xdigit <= '9') ||
  135. (xdigit >= 'A' && xdigit <= 'F') ||
  136. (xdigit >= 'a' && xdigit <= 'f'));
  137. switch (xdigit) {
  138. case '0': return 0;
  139. case '1': return 1;
  140. case '2': return 2;
  141. case '3': return 3;
  142. case '4': return 4;
  143. case '5': return 5;
  144. case '6': return 6;
  145. case '7': return 7;
  146. case '8': return 8;
  147. case '9': return 9;
  148. case 'a': case 'A': return 0xA;
  149. case 'b': case 'B': return 0xB;
  150. case 'c': case 'C': return 0xC;
  151. case 'd': case 'D': return 0xD;
  152. case 'e': case 'E': return 0xE;
  153. case 'f': case 'F': return 0xF;
  154. default: abort ();
  155. }
  156. }
  157. static inline int
  158. nextchar_raw (P, S)
  159. {
  160. int ch = (*p->getchar) (p->getchar_data);
  161. switch (ch) {
  162. case HIPACK_IO_ERROR:
  163. *status = kStatusIoError;
  164. /* fall-through */
  165. case HIPACK_IO_EOF:
  166. break;
  167. case '\n':
  168. p->column = 0;
  169. p->line++;
  170. /* fall-through */
  171. default:
  172. p->column++;
  173. }
  174. return ch;
  175. }
  176. static inline void
  177. nextchar (P, S)
  178. {
  179. do {
  180. p->look = nextchar_raw (p, CHECK_OK);
  181. if (p->look == '#') {
  182. while (p->look != '\n' && p->look != HIPACK_IO_EOF) {
  183. p->look = nextchar_raw (p, CHECK_OK);
  184. }
  185. }
  186. } while (p->look != HIPACK_IO_EOF && p->look == '#');
  187. error:
  188. /* noop */;
  189. }
  190. static inline void
  191. skipwhite (P, S)
  192. {
  193. while (p->look != HIPACK_IO_EOF && is_hipack_whitespace (p->look))
  194. nextchar (p, status);
  195. }
  196. static inline void
  197. matchchar (P, int ch, const char *errmsg, S)
  198. {
  199. if (p->look == ch) {
  200. nextchar (p, CHECK_OK);
  201. return;
  202. }
  203. p->error = errmsg ? errmsg : "unexpected input";
  204. *status = kStatusError;
  205. error:
  206. return;
  207. }
  208. #ifndef HIPACK_STRING_CHUNK_SIZE
  209. #define HIPACK_STRING_CHUNK_SIZE 32
  210. #endif /* !HIPACK_STRING_CHUNK_SIZE */
  211. #ifndef HIPACK_STRING_POW_SIZE
  212. #define HIPACK_STRING_POW_SIZE 512
  213. #endif /* !HIPACK_STRING_POW_SIZE */
  214. #ifndef HIPACK_LIST_CHUNK_SIZE
  215. #define HIPACK_LIST_CHUNK_SIZE HIPACK_STRING_CHUNK_SIZE
  216. #endif /* !HIPACK_LIST_CHUNK_SIZE */
  217. #ifndef HIPACK_LIST_POW_SIZE
  218. #define HIPACK_LIST_POW_SIZE HIPACK_STRING_POW_SIZE
  219. #endif /* !HIPACK_LIST_POW_SIZE */
  220. static hipack_string_t*
  221. string_resize (hipack_string_t *hstr, uint32_t *alloc, uint32_t size)
  222. {
  223. /* TODO: Use HIPACK_STRING_POW_SIZE. */
  224. if (size) {
  225. uint32_t new_size = HIPACK_STRING_CHUNK_SIZE *
  226. ((size / HIPACK_STRING_CHUNK_SIZE) + 1);
  227. if (new_size < size) {
  228. new_size = size;
  229. }
  230. if (new_size != *alloc) {
  231. *alloc = new_size;
  232. new_size = sizeof (hipack_string_t) + new_size * sizeof (uint8_t);
  233. hstr = hipack_alloc_array_extra (hstr, new_size,
  234. sizeof (uint8_t),
  235. sizeof (hipack_string_t));
  236. }
  237. hstr->size = size;
  238. } else {
  239. hipack_alloc_free (hstr);
  240. hstr = NULL;
  241. *alloc = 0;
  242. }
  243. return hstr;
  244. }
  245. static hipack_list_t*
  246. list_resize (hipack_list_t *list, uint32_t *alloc, uint32_t size)
  247. {
  248. /* TODO: Use HIPACK_LIST_POW_SIZE. */
  249. if (size) {
  250. uint32_t new_size = HIPACK_LIST_CHUNK_SIZE *
  251. ((size / HIPACK_LIST_CHUNK_SIZE) + 1);
  252. if (new_size < size) {
  253. new_size = size;
  254. }
  255. if (new_size != *alloc) {
  256. *alloc = new_size;
  257. list = hipack_alloc_array_extra (list, new_size,
  258. sizeof (hipack_value_t),
  259. sizeof (hipack_list_t));
  260. }
  261. list->size = size;
  262. } else {
  263. hipack_alloc_free (list);
  264. list = NULL;
  265. *alloc = 0;
  266. }
  267. return list;
  268. }
  269. /* On empty (missing) keys, NULL is returned. */
  270. static hipack_string_t*
  271. parse_key (P, S)
  272. {
  273. hipack_string_t *hstr = NULL;
  274. uint32_t alloc_size = 0;
  275. uint32_t size = 0;
  276. while (p->look != HIPACK_IO_EOF && is_hipack_key_character (p->look)) {
  277. hstr = string_resize (hstr, &alloc_size, size + 1);
  278. hstr->data[size++] = p->look;
  279. nextchar (p, CHECK_OK);
  280. }
  281. return hstr;
  282. error:
  283. hipack_string_free (hstr);
  284. return NULL;
  285. }
  286. static void
  287. parse_string (P, hipack_value_t *result, S)
  288. {
  289. hipack_string_t *hstr = NULL;
  290. uint32_t alloc_size = 0;
  291. uint32_t size = 0;
  292. matchchar (p, '"', NULL, CHECK_OK);
  293. while (p->look != '"' && p->look != HIPACK_IO_EOF) {
  294. /* Handle escapes. */
  295. if (p->look == '\\') {
  296. int extra;
  297. p->look = nextchar_raw (p, CHECK_OK);
  298. switch (p->look) {
  299. case '"' : p->look = '"' ; break;
  300. case 'n' : p->look = '\n'; break;
  301. case 'r' : p->look = '\r'; break;
  302. case 't' : p->look = '\t'; break;
  303. case '\\': p->look = '\\'; break;
  304. default:
  305. /* Hex number. */
  306. extra = nextchar_raw (p, CHECK_OK);
  307. if (!isxdigit (extra) || !isxdigit (p->look)) {
  308. p->error = "invalid escape sequence";
  309. *status = kStatusError;
  310. goto error;
  311. }
  312. p->look = (xdigit_to_int (p->look) * 16) +
  313. xdigit_to_int (extra);
  314. break;
  315. }
  316. }
  317. hstr = string_resize (hstr, &alloc_size, size + 1);
  318. hstr->data[size++] = p->look;
  319. /* Read next character from the string. */
  320. p->look = nextchar_raw (p, CHECK_OK);
  321. }
  322. matchchar (p, '"', "unterminated string value", CHECK_OK);
  323. result->type = HIPACK_STRING;
  324. result->v_string = hstr ? hstr : hipack_string_new_from_lstring ("", 0);
  325. return;
  326. error:
  327. hipack_string_free (hstr);
  328. return;
  329. }
  330. static void
  331. parse_list (P, hipack_value_t *result, S)
  332. {
  333. hipack_list_t *list = NULL;
  334. uint32_t alloc_size = 0;
  335. uint32_t size = 0;
  336. matchchar (p, '[', NULL, CHECK_OK);
  337. skipwhite (p, CHECK_OK);
  338. while (p->look != ']') {
  339. hipack_value_t value = parse_value (p, CHECK_OK);
  340. list = list_resize (list, &alloc_size, size + 1);
  341. list->data[size++] = value;
  342. bool got_whitespace = is_hipack_whitespace (p->look);
  343. skipwhite (p, CHECK_OK);
  344. /* There must either a comma or whitespace after the value. */
  345. if (p->look == ',') {
  346. nextchar (p, CHECK_OK);
  347. } else if (!got_whitespace && !is_hipack_whitespace (p->look)) {
  348. break;
  349. }
  350. skipwhite (p, CHECK_OK);
  351. }
  352. matchchar (p, ']', "unterminated list value", CHECK_OK);
  353. result->type = HIPACK_LIST;
  354. result->v_list = list ? list : hipack_list_new (0);
  355. return;
  356. error:
  357. hipack_list_free (list);
  358. return;
  359. }
  360. static void
  361. parse_dict (P, hipack_value_t *result, S)
  362. {
  363. hipack_dict_t *dict = hipack_dict_new ();
  364. matchchar (p, '{', NULL, CHECK_OK);
  365. skipwhite (p, CHECK_OK);
  366. parse_keyval_items (p, dict, '}', CHECK_OK);
  367. matchchar (p, '}', "unterminated dict value", CHECK_OK);
  368. result->type = HIPACK_DICT;
  369. result->v_dict = dict;
  370. return;
  371. error:
  372. hipack_dict_free (dict);
  373. return;
  374. }
  375. static void
  376. parse_bool (P, hipack_value_t *result, S)
  377. {
  378. result->type = HIPACK_BOOL;
  379. if (p->look == 'T' || p->look == 't') {
  380. nextchar (p, CHECK_OK);
  381. matchchar (p, 'r', NULL, CHECK_OK);
  382. matchchar (p, 'u', NULL, CHECK_OK);
  383. matchchar (p, 'e', NULL, CHECK_OK);
  384. result->v_bool = true;
  385. } else if (p->look == 'F' || p->look == 'f') {
  386. nextchar (p, CHECK_OK);
  387. matchchar (p, 'a', NULL, CHECK_OK);
  388. matchchar (p, 'l', NULL, CHECK_OK);
  389. matchchar (p, 's', NULL, CHECK_OK);
  390. matchchar (p, 'e', NULL, CHECK_OK);
  391. result->v_bool = false;
  392. }
  393. return;
  394. error:
  395. p->error = "invalid boolean value";
  396. }
  397. static void
  398. parse_number (P, hipack_value_t *result, S)
  399. {
  400. hipack_string_t *hstr = NULL;
  401. uint32_t alloc_size = 0;
  402. uint32_t size = 0;
  403. #define SAVE_LOOK( ) \
  404. hstr = string_resize (hstr, &alloc_size, size + 1); \
  405. hstr->data[size++] = p->look
  406. /* Optional sign. */
  407. bool has_sign = false;
  408. if (p->look == '-' || p->look == '+') {
  409. SAVE_LOOK ();
  410. has_sign = true;
  411. nextchar (p, CHECK_OK);
  412. }
  413. /* Octal/hexadecimal numbers. */
  414. bool is_octal = false;
  415. bool is_hex = false;
  416. if (p->look == '0') {
  417. SAVE_LOOK ();
  418. nextchar (p, CHECK_OK);
  419. if (p->look == 'x' || p->look == 'X') {
  420. SAVE_LOOK ();
  421. nextchar (p, CHECK_OK);
  422. is_hex = true;
  423. } else if (is_octal_nonzero_digit (p->look)) {
  424. is_octal = true;
  425. }
  426. }
  427. /* Read the rest of the number. */
  428. bool dot_seen = false;
  429. bool exp_seen = false;
  430. while (p->look != HIPACK_IO_EOF && is_number_char (p->look)) {
  431. if (!is_hex && (p->look == 'e' || p->look == 'E')) {
  432. if (exp_seen || is_octal) {
  433. *status = kStatusError;
  434. goto error;
  435. }
  436. exp_seen = true;
  437. /* Handle the optional sign of the exponent. */
  438. SAVE_LOOK ();
  439. nextchar (p, CHECK_OK);
  440. if (p->look == '-' || p->look == '+') {
  441. SAVE_LOOK ();
  442. nextchar (p, CHECK_OK);
  443. }
  444. } else {
  445. if (p->look == '.') {
  446. if (dot_seen || is_hex || is_octal) {
  447. *status = kStatusError;
  448. goto error;
  449. }
  450. dot_seen = true;
  451. }
  452. if (p->look == '-' || p->look == '+') {
  453. *status = kStatusError;
  454. goto error;
  455. }
  456. SAVE_LOOK ();
  457. nextchar (p, CHECK_OK);
  458. }
  459. }
  460. if (!size) {
  461. *status = kStatusError;
  462. goto error;
  463. }
  464. /* Zero-terminate, to use with the libc conversion functions. */
  465. hstr = string_resize (hstr, &alloc_size, size + 1);
  466. hstr->data[size++] = '\0';
  467. char *endptr = NULL;
  468. if (is_hex) {
  469. assert (!is_octal);
  470. assert (!exp_seen);
  471. assert (!dot_seen);
  472. char *endptr = NULL;
  473. long v = strtol ((const char*) hstr->data, &endptr, 16);
  474. /* TODO: Check for overflow. */
  475. result->type = HIPACK_INTEGER;
  476. result->v_integer = (int32_t) v;
  477. } else if (is_octal) {
  478. assert (!is_hex);
  479. assert (!exp_seen);
  480. assert (!dot_seen);
  481. long v = strtol ((const char*) hstr->data, &endptr, 8);
  482. /* TODO: Check for overflow. */
  483. result->type = HIPACK_INTEGER;
  484. result->v_integer = (int32_t) v;
  485. } else if (dot_seen || exp_seen) {
  486. assert (!is_hex);
  487. assert (!is_octal);
  488. result->type = HIPACK_FLOAT;
  489. result->v_float = strtod ((const char*) hstr->data, &endptr);
  490. } else {
  491. assert (!is_hex);
  492. assert (!is_octal);
  493. assert (!exp_seen);
  494. assert (!dot_seen);
  495. long v = strtol ((const char*) hstr->data, &endptr, 10);
  496. /* TODO: Check for overflow. */
  497. result->type = HIPACK_INTEGER;
  498. result->v_integer = (int32_t) v;
  499. }
  500. if (endptr && *endptr != '\0') {
  501. *status = kStatusError;
  502. goto error;
  503. }
  504. hipack_string_free (hstr);
  505. return;
  506. error:
  507. p->error = "invalid numeric value";
  508. hipack_string_free (hstr);
  509. }
  510. static bool
  511. parse_annotations (P, hipack_value_t *result, S)
  512. {
  513. hipack_string_t *key = NULL;
  514. bool type_annot = false;
  515. while (p->look == ':') {
  516. p->look = nextchar_raw (p, CHECK_OK);
  517. key = parse_key (p, CHECK_OK);
  518. skipwhite (p, CHECK_OK); /* TODO: Move after checking duplicates. */
  519. /* Check for intrinsic type annotations. */
  520. assert (key->size > 0);
  521. if (key->data[0] == '.') {
  522. hipack_type_t annot_type;
  523. bool found = string_to_intrinsic_annot (key, &annot_type);
  524. if (found) {
  525. if (type_annot && annot_type != result->type) {
  526. p->error = "multiple intrinsic type annotations";
  527. goto error;
  528. }
  529. result->type = annot_type;
  530. type_annot = true;
  531. } else {
  532. p->error = "invalid intrinsic annotation";
  533. goto error;
  534. }
  535. } else {
  536. /* Check if the annotation is already in the set. */
  537. if (result->annot && hipack_dict_get (result->annot, key)) {
  538. p->error = "duplicate annotation";
  539. goto error;
  540. }
  541. /* Add the annotation to the set. */
  542. if (!result->annot)
  543. result->annot = hipack_dict_new ();
  544. static const hipack_value_t annot_present = {
  545. .type = HIPACK_BOOL,
  546. .v_bool = true,
  547. };
  548. hipack_dict_set_adopt_key (result->annot, &key, &annot_present);
  549. }
  550. }
  551. return type_annot;
  552. error:
  553. if (key)
  554. hipack_string_free (key);
  555. *status = kStatusError;
  556. return false;
  557. }
  558. static hipack_value_t
  559. parse_value (P, S)
  560. {
  561. hipack_value_t result = DUMMY_VALUE;
  562. bool type_annot = parse_annotations (p, &result, CHECK_OK);
  563. const hipack_type_t expected_type = result.type;
  564. switch (p->look) {
  565. case '"': /* String */
  566. parse_string (p, &result, CHECK_OK);
  567. break;
  568. case '[': /* List */
  569. parse_list (p, &result, CHECK_OK);
  570. break;
  571. case '{': /* Dict */
  572. parse_dict (p, &result, CHECK_OK);
  573. break;
  574. case 'T': /* Bool */
  575. case 't':
  576. case 'F':
  577. case 'f':
  578. parse_bool (p, &result, CHECK_OK);
  579. break;
  580. default: /* Integer or Float */
  581. parse_number (p, &result, CHECK_OK);
  582. break;
  583. }
  584. if (type_annot && expected_type != result.type) {
  585. p->error = "annotated type does not match value type";
  586. *status = kStatusError;
  587. goto error;
  588. }
  589. return result;
  590. error:
  591. hipack_value_free (&result);
  592. return DUMMY_VALUE;
  593. }
  594. static void
  595. parse_keyval_items (P, hipack_dict_t *result, int eos, S)
  596. {
  597. hipack_value_t value = DUMMY_VALUE;
  598. hipack_string_t *key = NULL;
  599. while (p->look != eos) {
  600. key = parse_key (p, CHECK_OK);
  601. if (!key) {
  602. p->error = "missing dictionary key";
  603. *status = kStatusError;
  604. goto error;
  605. }
  606. bool got_separator = false;
  607. if (is_hipack_whitespace (p->look)) {
  608. got_separator = true;
  609. skipwhite (p, CHECK_OK);
  610. } else switch (p->look) {
  611. case ':':
  612. nextchar (p, CHECK_OK);
  613. skipwhite (p, CHECK_OK);
  614. /* fall-through */
  615. case '{':
  616. case '[':
  617. got_separator = true;
  618. break;
  619. }
  620. if (!got_separator) {
  621. p->error = "missing separator";
  622. *status = kStatusError;
  623. goto error;
  624. }
  625. value = parse_value (p, CHECK_OK);
  626. hipack_dict_set_adopt_key (result, &key, &value);
  627. /*
  628. * There must be either a comma or a whitespace after the value,
  629. * or the end-of-sequence character.
  630. */
  631. if (p->look == ',') {
  632. nextchar (p, CHECK_OK);
  633. } else if (p->look != eos && !is_hipack_whitespace (p->look)) {
  634. break;
  635. }
  636. skipwhite (p, CHECK_OK);
  637. }
  638. return;
  639. error:
  640. hipack_string_free (key);
  641. hipack_value_free (&value);
  642. }
  643. static hipack_dict_t*
  644. parse_message (P, S)
  645. {
  646. hipack_dict_t *result = hipack_dict_new ();
  647. nextchar (p, CHECK_OK);
  648. skipwhite (p, CHECK_OK);
  649. if (p->look == HIPACK_IO_ERROR) {
  650. *status = kStatusIoError;
  651. } else if (p->look == '{') {
  652. /* Input starts with a Dict marker. */
  653. nextchar (p, CHECK_OK);
  654. skipwhite (p, CHECK_OK);
  655. parse_keyval_items (p, result, '}', CHECK_OK);
  656. matchchar (p, '}', "unterminated message", CHECK_OK);
  657. } else {
  658. parse_keyval_items (p, result, HIPACK_IO_EOF, CHECK_OK);
  659. }
  660. return result;
  661. error:
  662. hipack_dict_free (result);
  663. return NULL;
  664. }
  665. hipack_dict_t*
  666. hipack_read (hipack_reader_t *reader)
  667. {
  668. assert (reader);
  669. /*
  670. * Copy the reader function (and its data pointer) into the parser
  671. * structure. The rest of the fields are used as results, so the
  672. * reader structure can be cleaned up right after.
  673. */
  674. struct parser p = {
  675. .getchar = reader->getchar,
  676. .getchar_data = reader->getchar_data,
  677. .line = 1,
  678. 0,
  679. };
  680. memset (reader, 0x00, sizeof (hipack_reader_t));
  681. status_t status = kStatusOk;
  682. hipack_dict_t *result = parse_message (&p, &status);
  683. switch (status) {
  684. case kStatusOk:
  685. assert (result);
  686. break;
  687. case kStatusError:
  688. assert (!result);
  689. assert (p.error);
  690. break;
  691. case kStatusIoError:
  692. p.error = HIPACK_READ_ERROR;
  693. hipack_dict_free (result);
  694. result = NULL;
  695. break;
  696. case kStatusEof:
  697. break;
  698. }
  699. reader->error = p.error;
  700. reader->error_line = p.line;
  701. reader->error_column = p.column;
  702. return result;
  703. }
  704. int
  705. hipack_stdio_getchar (void *fp)
  706. {
  707. assert (fp);
  708. int ch = fgetc ((FILE*) fp);
  709. if (ch == EOF) {
  710. return ferror ((FILE*) fp) ? HIPACK_IO_ERROR : HIPACK_IO_EOF;
  711. }
  712. return ch;
  713. }