/*------------------------------------------------------------------ * Glue for libpsyc. *------------------------------------------------------------------ * test LPC code: * // doesn't work with (int *) yet mixed* x = psyc_parse(":_context\ttest\n\n:_topic\ttesting\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"); mixed y = psyc_render(x); mixed z = ({ ([ "_context": "test" ]), ([ "_topic": "testing" ]), "_notice_test_libpsyc", "Just [_topic] libpsyc." }); z = psyc_render(z); // psyc_render currently having some memory corruption problems debug_message(sprintf("libpsyc returned %O, %O and %O (%s)\n", x, y, z, y == z? "success": "FAIL!")); * */ #include "array.h" #include "interpret.h" #include "mapping.h" #include "mstrings.h" #include "object.h" #include "pkg-psyc.h" #include "simulate.h" #include "xalloc.h" #ifdef USE_PSYC # include "pkg-psyc.h" # include # include # include # include # include # include /*-------------------------------------------------------------------------*/ // old: string psyc_render(mapping, mapping, string, int* | string); // new: string psyc_render(mixed*); svalue_t * f_psyc_render(svalue_t *sp) { mp_int i; vector_t *v; psycPacket packet; string_t *out; char *meth, *body; size_t mlen, blen; mapping_t *map; // unless (sp->type == T_POINTER) return sp; v = sp->u.vec; if ((i = (mp_int)VEC_SIZE(v)) != 1+PSYC_BODY) { errorf("Wrong number of elements (%"PRIdMPINT") in array argument to psyc_render()\n", i); /* NOTREACHED */ return sp; } if (v->item[PSYC_ROUTING].type == T_MAPPING) { map = v->item[PSYC_ROUTING].u.map; } else { map = NULL; } #if 0 if (v->item[PSYC_METHOD].type != T_STRING) { errorf("Wrong type for PSYC_METHOD element in PSYC packet.\n"); /* NOTREACHED */ return sp; } if (v->item[PSYC_BODY].type != T_STRING) { errorf("Wrong type for PSYC_BODY element in PSYC packet.\n"); /* NOTREACHED */ return sp; } #else if (v->item[PSYC_METHOD].type == T_STRING) { meth = get_txt(v->item[PSYC_METHOD].u.str); mlen = mstrsize(v->item[PSYC_METHOD].u.str); } else { meth = NULL; mlen = 0; } if (v->item[PSYC_BODY].type == T_STRING) { body = get_txt(v->item[PSYC_BODY].u.str); blen = mstrsize(v->item[PSYC_BODY].u.str); } else { body = NULL; blen = 0; } #endif // TODO: handle _lists // FIXME: handle mappings packet = psyc_newPacket2(NULL, 0, NULL, 0, meth, mlen, body, blen, PSYC_PACKET_CHECK_LENGTH); printf("rendering... packet.length = %ld\n", packet.length); // alloc_mstring creates an *untabled* string suitable for tmp data memsafe(out = alloc_mstring(packet.length), packet.length, "f_psyc_render"); psyc_render(&packet, get_txt(out), packet.length); free_svalue(sp); put_string(sp, out); // stack should take care of freeing the string after use return sp; } /* f_psyc_render */ /*-------------------------------------------------------------------------*/ // mixed psyc_parse(int* | string); svalue_t * f_psyc_parse (svalue_t *sp) { string_t *str = NULL; vector_t *v; mapping_t *map; mp_int i; char oper = 0; psycString name = {0,0}, value = {0,0}, elem; psycParseListState listState; int ret; assert_shadow_sent(current_object); psyc_state_t *state = O_GET_PSYC_STATE(current_object); if (!state) { state = pxalloc(sizeof(psyc_state_t)); if (!state) errorf("Out of memory for psyc state struct.\n"); O_GET_PSYC_STATE(current_object) = state; state->parser = pxalloc(sizeof(psycParseState)); if (!state->parser) errorf("Out of memory for psyc parse state struct.\n"); psyc_initParseState(state->parser); } i = 0; if (sp->type == T_POINTER) { errorf("\npsyc_parse got %ld int* bytes... not supported yet\n", i); } else if (sp->type == T_STRING) { printf("\npsyc_parse got a %ld bytes long string...\n", mstrsize(sp->u.str)); psyc_setParseBuffer(state->parser, psyc_newString(get_txt(sp->u.str), mstrsize(sp->u.str))); } if (!state->packet) { state->packet = allocate_array(4); if (!state->packet) errorf("Out of memory for psyc_parse array.\n"); } v = state->packet; map = allocate_mapping( 0, 1 ); // empty mapping if (!map) errorf("Out of memory for psyc_parse routing header.\n"); put_mapping(&v->item[PSYC_ROUTING], map); map = allocate_mapping( 0, 1 ); // empty mapping if (!map) errorf("Out of memory for psyc_parse entity header.\n"); put_mapping(&v->item[PSYC_ENTITY], map); do { svalue_t *sv; ret = psyc_parse(state->parser, &oper, &name, &value); if (state->remaining) { pfree(state->remaining); state->remaining_len = 0; } switch (ret) { case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_BODY_START: // save oper, name & value in state at the start of incomplete entity or body state->oper = oper; state->name_len = name.length; state->name = pxalloc(name.length); memcpy(state->name, name.ptr, name.length); if (!state->name) errorf("Out of memory for name.\n"); state->value_len = 0; // allocate memory for the total length of the value state->value = pxalloc(psyc_getParseValueLength(state->parser)); if (!state->value) errorf("Out of memory for value.\n"); // fall thru case PSYC_PARSE_ENTITY_CONT: case PSYC_PARSE_BODY_CONT: case PSYC_PARSE_ENTITY_END: case PSYC_PARSE_BODY_END: // append value to tmp buffer in state memcpy(state->value + state->value_len, value.ptr, value.length); state->value_len += value.length; } if (ret == PSYC_PARSE_ENTITY_END || ret == PSYC_PARSE_BODY_END) { // incomplete entity or body parsing done, set oper/name/value to the ones saved in state oper = state->oper; name.ptr = state->name; name.length = state->name_len; value.ptr = state->value; value.length = state->value_len; } switch (ret) { case PSYC_PARSE_ROUTING: if (oper != ':') { puts("_failure_unsupported_state"); continue; } sv = pxalloc(sizeof(svalue_t)); // new_n_tabled fetches a reference of a probably existing // shared string put_string(sv, new_n_tabled(name.ptr, name.length)); sv = get_map_lvalue(v->item[PSYC_ROUTING].u.map, sv); // strings are capable of containing 0 so we can do this // for binary data too. let's use a tabled string even // for values of routing variables as they repeat a lot put_string(sv, new_n_tabled(value.ptr, value.length)); break; case PSYC_PARSE_ENTITY_END: case PSYC_PARSE_ENTITY: if (oper != ':') { puts("_failure_unsupported_state"); continue; } sv = pxalloc(sizeof(svalue_t)); put_string(sv, new_n_tabled(name.ptr, name.length)); sv = get_map_lvalue(v->item[PSYC_ENTITY].u.map, sv); // is it good to put entity variable values into the // shared string table? probably yes.. but it's a guess //t_string(sv, new_n_mstring(value.ptr, value.length)); put_string(sv, new_n_tabled(value.ptr, value.length)); // list parsing not supported yet.. TODO if (psyc_isListVar(&name)) { psyc_initParseListState(&listState); psyc_setParseListBuffer(&listState, value); elem = (psycString){0, 0}; while ((ret = psyc_parseList(&listState, &value, &elem))) { switch (ret) { case PSYC_PARSE_LIST_END: case PSYC_PARSE_LIST_ELEM: // TODO: store elem //write(1, elem.ptr, elem.length); break; default: errorf("Error while parsing PSYC list: %i\n", ret); /* NOTREACHED */ return sp; } if (ret == PSYC_PARSE_LIST_END) break; } } break; case PSYC_PARSE_BODY_END: case PSYC_PARSE_BODY: if (str) errorf("Got two PSYC methods in the same packet!?\n"); // new_n_tabled gets the shared string for the method put_string(&v->item[PSYC_METHOD], new_n_tabled(name.ptr, name.length)); // allocate an untabled string for the packet body put_string(&v->item[PSYC_BODY], new_n_mstring(value.ptr, value.length)); break; case PSYC_PARSE_COMPLETE: ret = 0; break; case PSYC_PARSE_INSUFFICIENT: // insufficient data, save remaining bytes state->remaining_len = psyc_getParseRemainingLength(state->parser); if (state->remaining_len) { state->remaining = pxalloc(state->remaining_len); memcpy(state->remaining, psyc_getParseRemainingBuffer(state->parser), state->remaining_len); } else state->remaining = NULL; //TODO: psyc_setRemainingBuffer2(state->parser, state->remaining, state->remaining_len); break; default: errorf("Error while parsing PSYC: %i\n", ret); /* NOTREACHED */ return sp; } // free tmp buffers in state when incomplete entity or body parsing is done if (ret == PSYC_PARSE_ENTITY_END || ret == PSYC_PARSE_BODY_END) { oper = 0; if (state->name) pfree(state->name); state->name = NULL; state->name_len = 0; if (value.ptr) pfree((void*)value.ptr); state->value = NULL; state->value_len = 0; } } while (ret); free_svalue(sp); put_array(sp, v); state->packet = 0; return sp; } /* f_psyc_parse */ #endif /* USE_PSYC */