diff --git a/src/func_spec b/src/func_spec index 20e465c..e161b05 100644 --- a/src/func_spec +++ b/src/func_spec @@ -604,7 +604,7 @@ int send_erq(int, int*|string, null|closure default: F_CONST0); #endif #ifdef USE_PSYC -void psyc_parse(int* | string); +int psyc_parse(int* | string); string psyc_render(mixed*); #endif /* USE_PSYC */ diff --git a/src/pkg-psyc.c b/src/pkg-psyc.c index 28964ac..22ce658 100644 --- a/src/pkg-psyc.c +++ b/src/pkg-psyc.c @@ -4,35 +4,46 @@ * test LPC code: * +#define CHECK_PARSE_RET if (ret != 0) raise_error(sprintf("FAIL: psyc_parse returned %d\n", ret)) + string s, s2; create() { mixed p, r; + int ret; s = "=_context\ttest\n\n:_topic\ttesting\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"; - psyc_parse(s+s+s); + ret = psyc_parse(s+s+s); CHECK_PARSE_RET; - psyc_parse("=_context\ttest\n\n:_topic\ttest"); - psyc_parse("ing\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"); + ret = psyc_parse("=_context\ttest\n\n:_topic\ttest"); CHECK_PARSE_RET; + ret = psyc_parse("ing\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"); CHECK_PARSE_RET; p = ({ ([ "_context": "test"; '=' ]), ([ "_topic": "testing" ]), "_notice_test_libpsyc", "Just [_topic] libpsyc." }); r = psyc_render(p); - debug_message(sprintf(">> psyc_render returned:\n%s\n", r)); if (r != s) raise_error(sprintf(">> FAIL, expected:\n%s\n", s)); + s = "=_context\ttest\n\n:_amount\t4404\n:_list\t|4|4|0|4\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"; + s2 = "=_context\ttest\n\n:_list\t|4|4|0|4\n:_amount\t4404\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"; + p = ({ ([ "_context": "test"; '=' ]), ([ "_amount": 4404, "_list": ({4,4,0,4}) ]), + "_notice_test_libpsyc", "Just [_topic] libpsyc." }); + r = psyc_render(p); + + debug_message(sprintf(">> psyc_render returned:\n%s\n", r)); + if (r != s && r != s2) raise_error(sprintf(">> FAIL, expected:\n%s- or -\n%s\n", s, s2)); + s = "=_context\ttest\n\n:_time_foo\t59\n:_time_bar\t-41\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"; s2 = "=_context\ttest\n\n:_time_bar\t-41\n:_time_foo\t59\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"; - psyc_parse(s); + ret = psyc_parse(s); CHECK_PARSE_RET; s = "=_context\ttest\n\n:_date_foo\t59\n:_date_bar\t-41\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"; s2 = "=_context\ttest\n\n:_date_bar\t-41\n:_date_foo\t59\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"; - psyc_parse(s); + ret = psyc_parse(s); CHECK_PARSE_RET; s = "=_context\ttest\n\n:_list_foo\t|foo|bar|baz\n:_list_bar\t\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"; s2 = "=_context\ttest\n\n:_list_bar\t\n:_list_foo\t|foo|bar|baz\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"; - psyc_parse(s); + ret = psyc_parse(s); CHECK_PARSE_RET; p = ({ ([ "_context": "test"; '=' ]), ([ "_list_foo": ({ "foo", "bar", "baz" }), "_list_bar": ({}) ]), @@ -63,6 +74,7 @@ psyc_dispatch(mixed p) { #include "pkg-psyc.h" #include "simulate.h" #include "xalloc.h" +#include "efuns.h" #ifdef USE_PSYC @@ -79,13 +91,19 @@ psyc_dispatch(mixed p) { void fill_header_from_mapping (svalue_t *key, svalue_t *val, void *extra) { psyc_modifier_t *m = extra; - char oper; - char *name, *value, buf[32]; + char oper = 0; + char *name, *value; size_t namelen, valuelen, i; uint8_t type; + svalue_t vsp, *lval; - if (key->type != T_STRING) + psycList list; + psycString *elems = NULL; + + if (key->type != T_STRING) { errorf("fill_header_from_mapping: key type %d not supported\n", key->type); + return; // not reached + } name = get_txt(key->u.str); namelen = mstrsize(key->u.str); @@ -93,45 +111,86 @@ fill_header_from_mapping (svalue_t *key, svalue_t *val, void *extra) { if (m->num_values > 1) oper = val[1].u.number; - else + if (!oper) oper = C_GLYPH_OPERATOR_SET; - if (val->type == T_STRING) { - value = get_txt(val->u.str); - valuelen = mstrsize(val->u.str); - } else if (val->type == T_NUMBER) { - if (type == PSYC_TYPE_DATE) - snprintf(buf, 32, "%ld", val->u.number - PSYC_EPOCH); - else - snprintf(buf, 32, "%ld", val->u.number); - valuelen = strlen(buf); - value = pxalloc(valuelen); - if (!value) errorf("Out of memory in fill_header_from_mapping for number\n"); - memcpy(value, buf, valuelen); - } else if (val->type == T_POINTER) { - psycList list; - psycString *elems = NULL; + switch (val->type) { + case T_STRING: + value = get_txt(val->u.str); + valuelen = mstrsize(val->u.str); + break; - if (VEC_SIZE(val->u.vec)) { - elems = pxalloc(sizeof(psycString) * VEC_SIZE(val->u.vec)); - if (!elems) errorf("Out of memory in fill_header_from_mapping for elems\n"); - - for (i = 0; i < VEC_SIZE(val->u.vec); i++) { - if (val->u.vec->item[i].type == T_STRING) - elems[i] = (psycString){mstrsize(val->u.vec->item[i].u.str), get_txt(val->u.vec->item[i].u.str)}; - else - errorf("fill_header_from_mapping: list value type %d not supported\n", key->type); + case T_NUMBER: + case T_OBJECT: + vsp.type = val->type; + switch (val->type) { + case T_NUMBER: + if (type == PSYC_TYPE_DATE) + vsp.u.number = val->u.number - PSYC_EPOCH; + else + vsp.u.number = val->u.number; + break; + case T_OBJECT: + vsp.u.ob = val->u.ob; + break; } - } - list = psyc_newList(elems, VEC_SIZE(val->u.vec), PSYC_LIST_CHECK_LENGTH); - valuelen = list.length; - value = pxalloc(valuelen); - if (!value) errorf("Out of memory in fill_header_from_mapping for list value\n"); + f_to_string(&vsp); + value = get_txt(vsp.u.str); + valuelen = strlen(value); + break; - psyc_renderList(&list, value, valuelen); - } else - errorf("fill_header_from_mapping: value type %d not supported\n", key->type); + case T_POINTER: + if (VEC_SIZE(val->u.vec)) { + elems = pxalloc(sizeof(psycString) * VEC_SIZE(val->u.vec)); + if (!elems) { + errorf("Out of memory in fill_header_from_mapping for elems\n"); + return; // not reached + } + + for (i = 0; i < VEC_SIZE(val->u.vec); i++) { + lval = &(val->u.vec->item[i]); + switch (lval->type) { + case T_STRING: + elems[i] = (psycString){mstrsize(lval->u.str), get_txt(lval->u.str)}; + break; + case T_NUMBER: + case T_OBJECT: + vsp.type = lval->type; + switch (lval->type) { + case T_NUMBER: + vsp.u.number = lval->u.number; + break; + case T_OBJECT: + vsp.u.ob = lval->u.ob; + break; + } + + f_to_string(&vsp); + elems[i] = (psycString){strlen(get_txt(vsp.u.str)), get_txt(vsp.u.str)}; + break; + default: + errorf("fill_header_from_mapping: list value type %d not supported\n", lval->type); + return; // not reached + } + } + } + + list = psyc_newList(elems, VEC_SIZE(val->u.vec), PSYC_LIST_CHECK_LENGTH); + valuelen = list.length; + value = pxalloc(valuelen); + if (!value) { + errorf("Out of memory in fill_header_from_mapping for list value\n"); + return; // not reached + } + + psyc_renderList(&list, value, valuelen); + break; + + default: + errorf("fill_header_from_mapping: value type %d not supported\n", val->type); + return; // not reached + } m->header->modifiers[m->header->lines++] = psyc_newModifier2(oper, name, namelen, value, valuelen, m->flag); @@ -143,7 +202,7 @@ fill_header_from_mapping (svalue_t *key, svalue_t *val, void *extra) { svalue_t * f_psyc_render(svalue_t *sp) { - mp_int i; + uint8_t i; vector_t *v; string_t *out; char *meth, *body; @@ -155,41 +214,34 @@ f_psyc_render(svalue_t *sp) { // unless (sp->type == T_POINTER) return sp; v = sp->u.vec; - if ((i = (mp_int)VEC_SIZE(v)) != 1+PACKET_BODY) { - errorf("Wrong number of elements (%"PRIdMPINT") in array argument to psyc_render()\n", i); - /* NOTREACHED */ - return sp; - } - for (i = PACKET_ROUTING; i <= PACKET_ENTITY; i++) { - if (v->item[i].type == T_MAPPING) { - map = v->item[i].u.map; - headers[i].lines = 0; - headers[i].modifiers = malloc(sizeof(psycModifier) * MAP_SIZE(map)); - if (!headers[i].modifiers) errorf("Out of memory in psyc_render for header.\n"); + if (VEC_SIZE(v) == PACKET_BODY + 1) { + for (i = PACKET_ROUTING; i <= PACKET_ENTITY; i++) { + if (v->item[i].type == T_MAPPING) { + map = v->item[i].u.map; + if (!MAP_SIZE(map)) continue; + + headers[i].lines = 0; + headers[i].modifiers = malloc(sizeof(psycModifier) * MAP_SIZE(v->item[i].u.map)); + if (!headers[i].modifiers) { + errorf("Out of memory in psyc_render for entity header.\n"); + return sp; // not reached + } - if (i == PACKET_ROUTING) walk_mapping(map, &fill_header_from_mapping, - &(psyc_modifier_t) {&headers[i], map->num_values, - PSYC_MODIFIER_ROUTING}); - else - walk_mapping(map, &fill_header_from_mapping, - &(psyc_modifier_t) {&headers[i], map->num_values, - PSYC_MODIFIER_CHECK_LENGTH}); + &(psyc_modifier_t) { + &headers[i], map->num_values, + i == PACKET_ROUTING ? + PSYC_MODIFIER_ROUTING : + PSYC_MODIFIER_CHECK_LENGTH + }); + } } + } else { + errorf("Wrong number of elements (%" PRIdMPINT ") " + "in array argument to psyc_render()\n", VEC_SIZE(v)); + return sp; // not reached } -#if 0 - if (v->item[PACKET_METHOD].type != T_STRING) { - errorf("Wrong type for PACKET_METHOD element in PSYC packet.\n"); - /* NOTREACHED */ - return sp; - } - if (v->item[PACKET_BODY].type != T_STRING) { - errorf("Wrong type for PACKET_BODY element in PSYC packet.\n"); - /* NOTREACHED */ - return sp; - } -#else if (v->item[PACKET_METHOD].type == T_STRING) { meth = get_txt(v->item[PACKET_METHOD].u.str); mlen = mstrsize(v->item[PACKET_METHOD].u.str); @@ -197,6 +249,7 @@ f_psyc_render(svalue_t *sp) { meth = NULL; mlen = 0; } + if (v->item[PACKET_BODY].type == T_STRING) { body = get_txt(v->item[PACKET_BODY].u.str); blen = mstrsize(v->item[PACKET_BODY].u.str); @@ -204,14 +257,17 @@ f_psyc_render(svalue_t *sp) { body = NULL; blen = 0; } -#endif - // TODO: handle _lists - packet = psyc_newPacket2(headers[PACKET_ROUTING].modifiers, headers[PACKET_ROUTING].lines, - headers[PACKET_ENTITY].modifiers, headers[PACKET_ENTITY].lines, - meth, mlen, body, blen, - PSYC_PACKET_CHECK_LENGTH); + packet = psyc_newPacket2(headers[PACKET_ROUTING].modifiers, + headers[PACKET_ROUTING].lines, + headers[PACKET_ENTITY].modifiers, + headers[PACKET_ENTITY].lines, + meth, mlen, body, blen, + PSYC_PACKET_CHECK_LENGTH); + +#ifdef DEBUG printf("rendering... packet.length = %ld\n", packet.length); +#endif // 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); @@ -224,9 +280,10 @@ f_psyc_render(svalue_t *sp) { } /* f_psyc_render */ /*-------------------------------------------------------------------------*/ -// void psyc_parse(int* | string); +// int psyc_parse(int* | string); static string_t *psyc_dispatch_callback = NULL; +static string_t *psyc_error_callback = NULL; svalue_t * f_psyc_parse (svalue_t *sp) { @@ -237,82 +294,116 @@ f_psyc_parse (svalue_t *sp) { char oper = 0; psycString name = {0,0}, value = {0,0}, elems[MAX_LIST_SIZE], elem; psycParseListState listState; - int ret, retl, type = -1; + int ret, retl, type = -1, error = 0; size_t size, i; time_t t; if (!psyc_dispatch_callback) psyc_dispatch_callback = new_tabled("psyc_dispatch"); + if (!psyc_error_callback) + psyc_error_callback = new_tabled("psyc_error"); + 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"); + if (!state) { + errorf("Out of memory for psyc state struct.\n"); + return sp; // not reached + } O_GET_PSYC_STATE(current_object) = state; memset(state, 0, sizeof(psyc_state_t)); state->parser = pxalloc(sizeof(psycParseState)); - if (!state->parser) errorf("Out of memory for psyc parse state struct.\n"); + if (!state->parser) { + errorf("Out of memory for psyc parse state struct.\n"); + return sp; // not reached + } psyc_initParseState(state->parser); } v = state->packet; if (sp->type == T_POINTER) { - errorf("\npsyc_parse got %ld int* bytes... not supported yet\n", VEC_SIZE(sp->u.vec)); + errorf("\npsyc_parse got %ld int* bytes... not supported yet\n", + VEC_SIZE(sp->u.vec)); + return sp; // not reached } else if (sp->type == T_STRING) { +#ifdef DEBUG printf("\npsyc_parse got a %ld bytes long string...\n", mstrsize(sp->u.str)); - +#endif if (state->remaining) { // there are remaining bytes from the previous call to psyc_parse, // copy them together with the newly arrived data buffer = pxalloc(state->remaining_len + mstrsize(sp->u.str)); - if (!buffer) errorf("Out of memory for psyc_parse buffer.\n"); + if (!buffer) { + errorf("Out of memory for psyc_parse buffer.\n"); + return sp; // not reached + } memcpy(buffer, state->remaining, state->remaining_len); - memcpy(buffer + state->remaining_len, get_txt(sp->u.str), mstrsize(sp->u.str)); - psyc_setParseBuffer2(state->parser, buffer, state->remaining_len + mstrsize(sp->u.str)); + memcpy(buffer + state->remaining_len, get_txt(sp->u.str), + mstrsize(sp->u.str)); + psyc_setParseBuffer2(state->parser, buffer, + state->remaining_len + mstrsize(sp->u.str)); pfree(state->remaining); state->remaining = NULL; state->remaining_len = 0; } else { - psyc_setParseBuffer2(state->parser, get_txt(sp->u.str), mstrsize(sp->u.str)); + psyc_setParseBuffer2(state->parser, get_txt(sp->u.str), + mstrsize(sp->u.str)); } } else { errorf("\npsyc_parse got type %d, not supported\n", sp->type); + return sp; // not reached } do { ret = psyc_parse(state->parser, &oper, &name, &value); - - printf("#%2d %c%.*s = %.*s\n", ret, oper ? oper : ' ', (int)name.length, name.ptr, (int)value.length, value.ptr); - +#ifdef DEBUG + printf("#%2d %c%.*s = %.*s\n", ret, oper ? oper : ' ', + (int)name.length, name.ptr, (int)value.length, value.ptr); +#endif if (!state->packet) { state->packet = allocate_array(4); - if (!state->packet) errorf("Out of memory for psyc_parse array.\n"); + if (!state->packet) { + errorf("Out of memory for psyc_parse array.\n"); + return sp; // not reached + } v = state->packet; map = allocate_mapping(0, 2); // empty mapping - if (!map) errorf("Out of memory for psyc_parse routing header.\n"); + if (!map) { + errorf("Out of memory for psyc_parse routing header.\n"); + return sp; // not reached + } put_mapping(&v->item[PACKET_ROUTING], map); map = allocate_mapping(0, 2); // empty mapping - if (!map) errorf("Out of memory for psyc_parse entity header.\n"); + if (!map) { + errorf("Out of memory for psyc_parse entity header.\n"); + return sp; // not reached + } put_mapping(&v->item[PACKET_ENTITY], map); } 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 + // save oper, name & value in state at the start of + // incomplete entity or body state->oper = oper; state->name = mstring_alloc_string(name.length); memcpy(get_txt(state->name), name.ptr, name.length); - if (!state->name) + if (!state->name) { errorf("Out of memory for name.\n"); + return sp; // not reached + } // allocate memory for the total length of the value state->value_len = 0; state->value = mstring_alloc_string(psyc_getParseValueLength(state->parser)); - if (!state->value) + if (!state->value) { errorf("Out of memory for value.\n"); + return sp; // not reached + } // fall thru case PSYC_PARSE_ENTITY_CONT: case PSYC_PARSE_BODY_CONT: @@ -323,7 +414,8 @@ f_psyc_parse (svalue_t *sp) { } 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 + // incomplete entity or body parsing done, + // set oper/name/value to the ones saved in state oper = state->oper; name.ptr = get_txt(state->name); name.length = mstrsize(state->name); @@ -363,36 +455,37 @@ f_psyc_parse (svalue_t *sp) { put_number(&sv[1], oper); type = psyc_getVarType(&name); + switch (type) { case PSYC_TYPE_DATE: // number + PSYC_EPOCH if (psyc_parseDate(&value, &t)) put_number(sv, t); else - errorf("Error while parsing _date value\n"); // TODO: _error_invalid_value? + error = PSYC_PARSE_ERROR_DATE; break; case PSYC_TYPE_TIME: // number if (psyc_parseTime(&value, &t)) put_number(sv, t); else - errorf("Error while parsing _time value\n"); + error = PSYC_PARSE_ERROR_TIME; break; case PSYC_TYPE_AMOUNT: // number if (psyc_parseNumber(&value, &t)) put_number(sv, t); else - errorf("Error while parsing _amount value\n"); + error = PSYC_PARSE_ERROR_AMOUNT; break; case PSYC_TYPE_DEGREE: // first digit if (value.length && value.ptr[0] >= '0' && value.ptr[0] <= '9') put_number(sv, value.ptr[0] - '0'); else - errorf("Error while parsing _degree value\n"); + error = PSYC_PARSE_ERROR_DEGREE; break; case PSYC_TYPE_FLAG: // 0 or 1 if (value.length && value.ptr[0] >= '0' && value.ptr[0] <= '1') put_number(sv, value.ptr[0] - '0'); else - errorf("Error while parsing _flag value\n"); + error = PSYC_PARSE_ERROR_FLAG; break; case PSYC_TYPE_LIST: // array size = 0; @@ -407,23 +500,22 @@ f_psyc_parse (svalue_t *sp) { retl = 0; case PSYC_PARSE_LIST_ELEM: if (size >= MAX_LIST_SIZE) { - errorf("Error while parsing PSYC list: max list size reached\n"); - /* NOTREACHED */ - return sp; + error = PSYC_PARSE_ERROR_LIST_TOO_LARGE; + break; } elems[size++] = elem; break; default: - errorf("Error while parsing PSYC list: %i\n", retl); - /* NOTREACHED */ - return sp; + error = PSYC_PARSE_ERROR_LIST; } - } while (retl > 0); + } while (retl > 0 && !error); } + if (error) break; list = allocate_array(size); for (i = 0; i < size; i++) - put_string(&list->item[i], new_n_tabled(elems[i].ptr, elems[i].length)); + put_string(&list->item[i], new_n_tabled(elems[i].ptr, + elems[i].length)); put_array(sv, list); break; @@ -478,26 +570,26 @@ f_psyc_parse (svalue_t *sp) { break; default: - errorf("Error while parsing PSYC: %i\n", ret); - /* NOTREACHED */ - return sp; + error = ret; } switch (ret) { case PSYC_PARSE_BODY_END: case PSYC_PARSE_ENTITY_END: - // reset tmp buffers in state when incomplete entity or body parsing is done + // reset tmp buffers in state when incomplete + // entity or body parsing is finished state->oper = 0; state->name = NULL; state->value = NULL; } - } while (ret); + } while (ret && !error); if (buffer) pfree(buffer); - free_svalue(sp); // f_remove_interactive does it the same way... - return --sp; + free_svalue(sp); + put_number(sp, error); + return sp; } /* f_psyc_parse */ #endif /* USE_PSYC */ diff --git a/src/pkg-psyc.h b/src/pkg-psyc.h index 0cd4545..97a979f 100644 --- a/src/pkg-psyc.h +++ b/src/pkg-psyc.h @@ -19,6 +19,14 @@ # define MAX_LIST_SIZE 1024 +# define PSYC_PARSE_ERROR_AMOUNT 1 +# define PSYC_PARSE_ERROR_DEGREE 2 +# define PSYC_PARSE_ERROR_DATE 3 +# define PSYC_PARSE_ERROR_TIME 4 +# define PSYC_PARSE_ERROR_FLAG 5 +# define PSYC_PARSE_ERROR_LIST 6 +# define PSYC_PARSE_ERROR_LIST_TOO_LARGE 7 + typedef struct psyc_state_s { psycParseState *parser; vector_t *packet;