bproto_functions.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. <?php
  2. function tokenize ($str, &$out) {
  3. $out = array();
  4. while (strlen($str) > 0) {
  5. if (preg_match('/^\\/\\/.*/', $str, $matches)) {
  6. $str = substr($str, strlen($matches[0]));
  7. }
  8. else if (preg_match('/^\\s+/', $str, $matches)) {
  9. $str = substr($str, strlen($matches[0]));
  10. }
  11. else if (preg_match('/^include/', $str, $matches)) {
  12. $out[] = array('include', null);
  13. $str = substr($str, strlen($matches[0]));
  14. }
  15. else if (preg_match('/^message/', $str, $matches)) {
  16. $out[] = array('message', null);
  17. $str = substr($str, strlen($matches[0]));
  18. }
  19. else if (preg_match('/^repeated/', $str, $matches)) {
  20. $out[] = array('repeated', null);
  21. $str = substr($str, strlen($matches[0]));
  22. }
  23. else if (preg_match('/^required/', $str, $matches)) {
  24. $out[] = array('required', null);
  25. $str = substr($str, strlen($matches[0]));
  26. }
  27. else if (preg_match('/^optional/', $str, $matches)) {
  28. $out[] = array('optional', null);
  29. $str = substr($str, strlen($matches[0]));
  30. }
  31. else if (preg_match('/^{/', $str, $matches)) {
  32. $out[] = array('spar', null);
  33. $str = substr($str, strlen($matches[0]));
  34. }
  35. else if (preg_match('/^}/', $str, $matches)) {
  36. $out[] = array('epar', null);
  37. $str = substr($str, strlen($matches[0]));
  38. }
  39. else if (preg_match('/^\(/', $str, $matches)) {
  40. $out[] = array('srpar', null);
  41. $str = substr($str, strlen($matches[0]));
  42. }
  43. else if (preg_match('/^\)/', $str, $matches)) {
  44. $out[] = array('erpar', null);
  45. $str = substr($str, strlen($matches[0]));
  46. }
  47. else if (preg_match('/^=/', $str, $matches)) {
  48. $out[] = array('equals', null);
  49. $str = substr($str, strlen($matches[0]));
  50. }
  51. else if (preg_match('/^;/', $str, $matches)) {
  52. $out[] = array('semicolon', null);
  53. $str = substr($str, strlen($matches[0]));
  54. }
  55. else if (preg_match('/^uint(8|16|32|64)/', $str, $matches)) {
  56. $out[] = array('uint', $matches[1]);
  57. $str = substr($str, strlen($matches[0]));
  58. }
  59. else if (preg_match('/^data/', $str, $matches)) {
  60. $out[] = array('data', null);
  61. $str = substr($str, strlen($matches[0]));
  62. }
  63. else if (preg_match('/^[0-9]+/', $str, $matches)) {
  64. $out[] = array('number', $matches[0]);
  65. $str = substr($str, strlen($matches[0]));
  66. }
  67. else if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*/', $str, $matches)) {
  68. $out[] = array('name', $matches[0]);
  69. $str = substr($str, strlen($matches[0]));
  70. }
  71. else if (preg_match('/^"([^"]*)"/', $str, $matches)) {
  72. $out[] = array('string', $matches[1]);
  73. $str = substr($str, strlen($matches[0]));
  74. }
  75. else {
  76. return FALSE;
  77. }
  78. }
  79. return TRUE;
  80. }
  81. function fatal_error ($message)
  82. {
  83. fwrite(STDERR, "Fatal error: $message\n");
  84. ob_get_clean();
  85. exit(1);
  86. }
  87. function make_writer_decl ($msg, $entry)
  88. {
  89. switch ($entry["type"]["type"]) {
  90. case "uint":
  91. return "void {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o, uint{$entry["type"]["size"]}_t v)";
  92. case "data":
  93. return "uint8_t * {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o, int len)";
  94. case "constdata":
  95. return "uint8_t * {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o)";
  96. default:
  97. assert(0);
  98. }
  99. }
  100. function make_parser_decl ($msg, $entry)
  101. {
  102. switch ($entry["type"]["type"]) {
  103. case "uint":
  104. return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint{$entry["type"]["size"]}_t *v)";
  105. case "data":
  106. return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint8_t **data, int *data_len)";
  107. case "constdata":
  108. return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint8_t **data)";
  109. default:
  110. assert(0);
  111. }
  112. }
  113. function make_parser_reset_decl ($msg, $entry)
  114. {
  115. return "void {$msg["name"]}Parser_Reset{$entry["name"]} ({$msg["name"]}Parser *o)";
  116. }
  117. function make_parser_forward_decl ($msg, $entry)
  118. {
  119. return "void {$msg["name"]}Parser_Forward{$entry["name"]} ({$msg["name"]}Parser *o)";
  120. }
  121. function make_type_name ($msg, $entry)
  122. {
  123. switch ($entry["type"]["type"]) {
  124. case "uint":
  125. return "BPROTO_TYPE_UINT{$entry["type"]["size"]}";
  126. case "data":
  127. return "BPROTO_TYPE_DATA";
  128. case "constdata":
  129. return "BPROTO_TYPE_CONSTDATA";
  130. default:
  131. assert(0);
  132. }
  133. }
  134. function make_finish_assert ($msg, $entry)
  135. {
  136. switch ($entry["cardinality"]) {
  137. case "repeated":
  138. return "ASSERT(o->{$entry["name"]}_count >= 0)";
  139. case "required repeated":
  140. return "ASSERT(o->{$entry["name"]}_count >= 1)";
  141. case "optional":
  142. return "ASSERT(o->{$entry["name"]}_count >= 0 && o->{$entry["name"]}_count <= 1)";
  143. case "required":
  144. return "ASSERT(o->{$entry["name"]}_count == 1)";
  145. default:
  146. assert(0);
  147. }
  148. }
  149. function make_add_count_assert ($msg, $entry)
  150. {
  151. if (in_array($entry["cardinality"], array("optional", "required"))) {
  152. return "ASSERT(o->{$entry["name"]}_count == 0)";
  153. }
  154. return "";
  155. }
  156. function make_add_length_assert ($msg, $entry)
  157. {
  158. if ($entry["type"]["type"] == "data") {
  159. return "ASSERT(len >= 0 && len <= UINT32_MAX)";
  160. }
  161. return "";
  162. }
  163. function make_size_define ($msg, $entry)
  164. {
  165. switch ($entry["type"]["type"]) {
  166. case "uint":
  167. return "#define {$msg["name"]}_SIZE{$entry["name"]} (sizeof(struct BProto_header_s) + sizeof(struct BProto_uint{$entry["type"]["size"]}_s))";
  168. case "data":
  169. return "#define {$msg["name"]}_SIZE{$entry["name"]}(_len) (sizeof(struct BProto_header_s) + sizeof(struct BProto_data_header_s) + (_len))";
  170. case "constdata":
  171. return "#define {$msg["name"]}_SIZE{$entry["name"]} (sizeof(struct BProto_header_s) + sizeof(struct BProto_data_header_s) + ({$entry["type"]["size"]}))";
  172. default:
  173. assert(0);
  174. }
  175. }
  176. function generate_header ($name, $directives, $messages) {
  177. ob_start();
  178. echo <<<EOD
  179. /*
  180. DO NOT EDIT THIS FILE!
  181. This file was automatically generated by the bproto generator.
  182. */
  183. #include <stdint.h>
  184. #include <string.h>
  185. #include <misc/debug.h>
  186. #include <misc/byteorder.h>
  187. #include <bproto/BProto.h>
  188. EOD;
  189. foreach ($directives as $directive) {
  190. if ($directive["type"] == "include") {
  191. echo <<<EOD
  192. #include "{$directive["file"]}"
  193. EOD;
  194. }
  195. }
  196. echo <<<EOD
  197. EOD;
  198. foreach ($messages as $msg) {
  199. foreach ($msg["entries"] as $entry) {
  200. $def = make_size_define($msg, $entry);
  201. echo <<<EOD
  202. {$def}
  203. EOD;
  204. }
  205. echo <<<EOD
  206. typedef struct {
  207. uint8_t *out;
  208. int used;
  209. EOD;
  210. foreach ($msg["entries"] as $entry) {
  211. echo <<<EOD
  212. int {$entry["name"]}_count;
  213. EOD;
  214. }
  215. echo <<<EOD
  216. } {$msg["name"]}Writer;
  217. static void {$msg["name"]}Writer_Init ({$msg["name"]}Writer *o, uint8_t *out);
  218. static int {$msg["name"]}Writer_Finish ({$msg["name"]}Writer *o);
  219. EOD;
  220. foreach ($msg["entries"] as $entry) {
  221. $decl = make_writer_decl($msg, $entry);
  222. echo <<<EOD
  223. static {$decl};
  224. EOD;
  225. }
  226. echo <<<EOD
  227. typedef struct {
  228. uint8_t *buf;
  229. int buf_len;
  230. EOD;
  231. foreach ($msg["entries"] as $entry) {
  232. echo <<<EOD
  233. int {$entry["name"]}_start;
  234. int {$entry["name"]}_span;
  235. int {$entry["name"]}_pos;
  236. EOD;
  237. }
  238. echo <<<EOD
  239. } {$msg["name"]}Parser;
  240. static int {$msg["name"]}Parser_Init ({$msg["name"]}Parser *o, uint8_t *buf, int buf_len);
  241. static int {$msg["name"]}Parser_GotEverything ({$msg["name"]}Parser *o);
  242. EOD;
  243. foreach ($msg["entries"] as $entry) {
  244. $decl = make_parser_decl($msg, $entry);
  245. $reset_decl = make_parser_reset_decl($msg, $entry);
  246. $forward_decl = make_parser_forward_decl($msg, $entry);
  247. echo <<<EOD
  248. static {$decl};
  249. static {$reset_decl};
  250. static {$forward_decl};
  251. EOD;
  252. }
  253. echo <<<EOD
  254. void {$msg["name"]}Writer_Init ({$msg["name"]}Writer *o, uint8_t *out)
  255. {
  256. o->out = out;
  257. o->used = 0;
  258. EOD;
  259. foreach ($msg["entries"] as $entry) {
  260. echo <<<EOD
  261. o->{$entry["name"]}_count = 0;
  262. EOD;
  263. }
  264. echo <<<EOD
  265. }
  266. int {$msg["name"]}Writer_Finish ({$msg["name"]}Writer *o)
  267. {
  268. ASSERT(o->used >= 0)
  269. EOD;
  270. foreach ($msg["entries"] as $entry) {
  271. $ass = make_finish_assert($msg, $entry);
  272. echo <<<EOD
  273. {$ass}
  274. EOD;
  275. }
  276. echo <<<EOD
  277. return o->used;
  278. }
  279. EOD;
  280. foreach ($msg["entries"] as $entry) {
  281. $decl = make_writer_decl($msg, $entry);
  282. $type = make_type_name($msg, $entry);
  283. $add_count_assert = make_add_count_assert($msg, $entry);
  284. $add_length_assert = make_add_length_assert($msg, $entry);
  285. echo <<<EOD
  286. {$decl}
  287. {
  288. ASSERT(o->used >= 0)
  289. {$add_count_assert}
  290. {$add_length_assert}
  291. struct BProto_header_s header;
  292. header.id = htol16({$entry["id"]});
  293. header.type = htol16({$type});
  294. memcpy(o->out + o->used, &header, sizeof(header));
  295. o->used += sizeof(struct BProto_header_s);
  296. EOD;
  297. switch ($entry["type"]["type"]) {
  298. case "uint":
  299. echo <<<EOD
  300. struct BProto_uint{$entry["type"]["size"]}_s data;
  301. data.v = htol{$entry["type"]["size"]}(v);
  302. memcpy(o->out + o->used, &data, sizeof(data));
  303. o->used += sizeof(struct BProto_uint{$entry["type"]["size"]}_s);
  304. EOD;
  305. break;
  306. case "data":
  307. echo <<<EOD
  308. struct BProto_data_header_s data;
  309. data.len = htol32(len);
  310. memcpy(o->out + o->used, &data, sizeof(data));
  311. o->used += sizeof(struct BProto_data_header_s);
  312. uint8_t *dest = (o->out + o->used);
  313. o->used += len;
  314. EOD;
  315. break;
  316. case "constdata":
  317. echo <<<EOD
  318. struct BProto_data_header_s data;
  319. data.len = htol32({$entry["type"]["size"]});
  320. memcpy(o->out + o->used, &data, sizeof(data));
  321. o->used += sizeof(struct BProto_data_header_s);
  322. uint8_t *dest = (o->out + o->used);
  323. o->used += ({$entry["type"]["size"]});
  324. EOD;
  325. break;
  326. default:
  327. assert(0);
  328. }
  329. echo <<<EOD
  330. o->{$entry["name"]}_count++;
  331. EOD;
  332. if (in_array($entry["type"]["type"], array("data", "constdata"))) {
  333. echo <<<EOD
  334. return dest;
  335. EOD;
  336. }
  337. echo <<<EOD
  338. }
  339. EOD;
  340. }
  341. echo <<<EOD
  342. int {$msg["name"]}Parser_Init ({$msg["name"]}Parser *o, uint8_t *buf, int buf_len)
  343. {
  344. ASSERT(buf_len >= 0)
  345. o->buf = buf;
  346. o->buf_len = buf_len;
  347. EOD;
  348. foreach ($msg["entries"] as $entry) {
  349. echo <<<EOD
  350. o->{$entry["name"]}_start = o->buf_len;
  351. o->{$entry["name"]}_span = 0;
  352. o->{$entry["name"]}_pos = 0;
  353. EOD;
  354. }
  355. echo <<<EOD
  356. EOD;
  357. foreach ($msg["entries"] as $entry) {
  358. echo <<<EOD
  359. int {$entry["name"]}_count = 0;
  360. EOD;
  361. }
  362. echo <<<EOD
  363. int pos = 0;
  364. int left = o->buf_len;
  365. while (left > 0) {
  366. int entry_pos = pos;
  367. if (!(left >= sizeof(struct BProto_header_s))) {
  368. return 0;
  369. }
  370. struct BProto_header_s header;
  371. memcpy(&header, o->buf + pos, sizeof(header));
  372. pos += sizeof(struct BProto_header_s);
  373. left -= sizeof(struct BProto_header_s);
  374. uint16_t type = ltoh16(header.type);
  375. uint16_t id = ltoh16(header.id);
  376. switch (type) {
  377. EOD;
  378. foreach (array(8, 16, 32, 64) as $bits) {
  379. echo <<<EOD
  380. case BPROTO_TYPE_UINT{$bits}: {
  381. if (!(left >= sizeof(struct BProto_uint{$bits}_s))) {
  382. return 0;
  383. }
  384. pos += sizeof(struct BProto_uint{$bits}_s);
  385. left -= sizeof(struct BProto_uint{$bits}_s);
  386. switch (id) {
  387. EOD;
  388. foreach ($msg["entries"] as $entry) {
  389. if (!($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits)) {
  390. continue;
  391. }
  392. $type = make_type_name($msg, $entry);
  393. echo <<<EOD
  394. case {$entry["id"]}:
  395. if (o->{$entry["name"]}_start == o->buf_len) {
  396. o->{$entry["name"]}_start = entry_pos;
  397. }
  398. o->{$entry["name"]}_span = pos - o->{$entry["name"]}_start;
  399. {$entry["name"]}_count++;
  400. break;
  401. EOD;
  402. }
  403. echo <<<EOD
  404. default:
  405. return 0;
  406. }
  407. } break;
  408. EOD;
  409. }
  410. echo <<<EOD
  411. case BPROTO_TYPE_DATA:
  412. case BPROTO_TYPE_CONSTDATA:
  413. {
  414. if (!(left >= sizeof(struct BProto_data_header_s))) {
  415. return 0;
  416. }
  417. struct BProto_data_header_s val;
  418. memcpy(&val, o->buf + pos, sizeof(val));
  419. pos += sizeof(struct BProto_data_header_s);
  420. left -= sizeof(struct BProto_data_header_s);
  421. uint32_t payload_len = ltoh32(val.len);
  422. if (!(left >= payload_len)) {
  423. return 0;
  424. }
  425. pos += payload_len;
  426. left -= payload_len;
  427. switch (id) {
  428. EOD;
  429. foreach ($msg["entries"] as $entry) {
  430. if (!in_array($entry["type"]["type"], array("data", "constdata"))) {
  431. continue;
  432. }
  433. $type = make_type_name($msg, $entry);
  434. echo <<<EOD
  435. case {$entry["id"]}:
  436. if (!(type == {$type})) {
  437. return 0;
  438. }
  439. EOD;
  440. if ($entry["type"]["type"] == "constdata") {
  441. echo <<<EOD
  442. if (!(payload_len == ({$entry["type"]["size"]}))) {
  443. return 0;
  444. }
  445. EOD;
  446. }
  447. echo <<<EOD
  448. if (o->{$entry["name"]}_start == o->buf_len) {
  449. o->{$entry["name"]}_start = entry_pos;
  450. }
  451. o->{$entry["name"]}_span = pos - o->{$entry["name"]}_start;
  452. {$entry["name"]}_count++;
  453. break;
  454. EOD;
  455. }
  456. echo <<<EOD
  457. default:
  458. return 0;
  459. }
  460. } break;
  461. default:
  462. return 0;
  463. }
  464. }
  465. EOD;
  466. foreach ($msg["entries"] as $entry) {
  467. $cond = "";
  468. switch ($entry["cardinality"]) {
  469. case "repeated":
  470. break;
  471. case "required repeated":
  472. $cond = "{$entry["name"]}_count >= 1";
  473. break;
  474. case "optional":
  475. $cond = "{$entry["name"]}_count <= 1";
  476. break;
  477. case "required":
  478. $cond = "{$entry["name"]}_count == 1";
  479. break;
  480. default:
  481. assert(0);
  482. }
  483. if ($cond) {
  484. echo <<<EOD
  485. if (!({$cond})) {
  486. return 0;
  487. }
  488. EOD;
  489. }
  490. }
  491. echo <<<EOD
  492. return 1;
  493. }
  494. int {$msg["name"]}Parser_GotEverything ({$msg["name"]}Parser *o)
  495. {
  496. return (
  497. EOD;
  498. $first = 1;
  499. foreach ($msg["entries"] as $entry) {
  500. if ($first) {
  501. $first = 0;
  502. } else {
  503. echo <<<EOD
  504. &&
  505. EOD;
  506. }
  507. echo <<<EOD
  508. o->{$entry["name"]}_pos == o->{$entry["name"]}_span
  509. EOD;
  510. }
  511. echo <<<EOD
  512. );
  513. }
  514. EOD;
  515. foreach ($msg["entries"] as $entry) {
  516. $decl = make_parser_decl($msg, $entry);
  517. $reset_decl = make_parser_reset_decl($msg, $entry);
  518. $forward_decl = make_parser_forward_decl($msg, $entry);
  519. $type = make_type_name($msg, $entry);
  520. echo <<<EOD
  521. {$decl}
  522. {
  523. ASSERT(o->{$entry["name"]}_pos >= 0)
  524. ASSERT(o->{$entry["name"]}_pos <= o->{$entry["name"]}_span)
  525. int left = o->{$entry["name"]}_span - o->{$entry["name"]}_pos;
  526. while (left > 0) {
  527. ASSERT(left >= sizeof(struct BProto_header_s))
  528. struct BProto_header_s header;
  529. memcpy(&header, o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos, sizeof(header));
  530. o->{$entry["name"]}_pos += sizeof(struct BProto_header_s);
  531. left -= sizeof(struct BProto_header_s);
  532. uint16_t type = ltoh16(header.type);
  533. uint16_t id = ltoh16(header.id);
  534. switch (type) {
  535. EOD;
  536. foreach (array(8, 16, 32, 64) as $bits) {
  537. echo <<<EOD
  538. case BPROTO_TYPE_UINT{$bits}: {
  539. ASSERT(left >= sizeof(struct BProto_uint{$bits}_s))
  540. EOD;
  541. if ($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits) {
  542. echo <<<EOD
  543. struct BProto_uint{$bits}_s val;
  544. memcpy(&val, o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos, sizeof(val));
  545. EOD;
  546. }
  547. echo <<<EOD
  548. o->{$entry["name"]}_pos += sizeof(struct BProto_uint{$bits}_s);
  549. left -= sizeof(struct BProto_uint{$bits}_s);
  550. EOD;
  551. if ($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits) {
  552. echo <<<EOD
  553. if (id == {$entry["id"]}) {
  554. *v = ltoh{$bits}(val.v);
  555. return 1;
  556. }
  557. EOD;
  558. }
  559. echo <<<EOD
  560. } break;
  561. EOD;
  562. }
  563. echo <<<EOD
  564. case BPROTO_TYPE_DATA:
  565. case BPROTO_TYPE_CONSTDATA:
  566. {
  567. ASSERT(left >= sizeof(struct BProto_data_header_s))
  568. struct BProto_data_header_s val;
  569. memcpy(&val, o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos, sizeof(val));
  570. o->{$entry["name"]}_pos += sizeof(struct BProto_data_header_s);
  571. left -= sizeof(struct BProto_data_header_s);
  572. uint32_t payload_len = ltoh32(val.len);
  573. ASSERT(left >= payload_len)
  574. EOD;
  575. if ($entry["type"]["type"] == "data" || $entry["type"]["type"] == "constdata") {
  576. echo <<<EOD
  577. uint8_t *payload = o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos;
  578. EOD;
  579. }
  580. echo <<<EOD
  581. o->{$entry["name"]}_pos += payload_len;
  582. left -= payload_len;
  583. EOD;
  584. if ($entry["type"]["type"] == "data") {
  585. echo <<<EOD
  586. if (type == BPROTO_TYPE_DATA && id == {$entry["id"]}) {
  587. *data = payload;
  588. *data_len = payload_len;
  589. return 1;
  590. }
  591. EOD;
  592. }
  593. else if ($entry["type"]["type"] == "constdata") {
  594. echo <<<EOD
  595. if (type == BPROTO_TYPE_CONSTDATA && id == {$entry["id"]}) {
  596. *data = payload;
  597. return 1;
  598. }
  599. EOD;
  600. }
  601. echo <<<EOD
  602. } break;
  603. default:
  604. ASSERT(0);
  605. }
  606. }
  607. return 0;
  608. }
  609. {$reset_decl}
  610. {
  611. o->{$entry["name"]}_pos = 0;
  612. }
  613. {$forward_decl}
  614. {
  615. o->{$entry["name"]}_pos = o->{$entry["name"]}_span;
  616. }
  617. EOD;
  618. }
  619. }
  620. return ob_get_clean();
  621. }