pkg-psyc: incomplete packet handling

This commit is contained in:
Gabor Adam Toth 2011-05-09 21:33:45 +02:00
parent 14944d8484
commit a27331f703
6 changed files with 131 additions and 80 deletions

View File

@ -1220,7 +1220,7 @@ lp_cv_has_psyc_lib="no"
AC_CHECK_LIB(psyc,main, lp_cv_has_psyc_lib="yes")
if test $lp_cv_has_psyc_lib = yes; then
LIBS="-lpsyc"
LIBS="-lpsyc -lm"
AC_CACHE_CHECK(for libpsyc usability,lp_cv_has_psyc,
AC_TRY_RUN([
#include <psyc.h>
@ -1237,7 +1237,7 @@ int main(void) {
if test $lp_cv_has_psyc = yes; then
AC_DEFINE(HAS_PSYC, 1, [Does the machine offer libpsyc?])
PKGLIBS="$PKGLIBS -lpsyc"
PKGLIBS="$PKGLIBS -lpsyc -lm"
echo "Congrats! libpsyc is available on this system."
else
echo "libpsyc not available on this system yet."

View File

@ -32,7 +32,7 @@
# include <fcntl.h>
# include <psyc.h>
# include <psyc/parser.h>
# include <psyc/parse.h>
# include <psyc/render.h>
/*-------------------------------------------------------------------------*/
@ -95,7 +95,7 @@ f_psyc_render(svalue_t *sp) {
meth, mlen, body, blen,
PSYC_PACKET_CHECK_LENGTH);
printf("rendering... packet.length = %d\n", packet.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);
@ -117,15 +117,14 @@ f_psyc_parse (svalue_t *sp) {
mapping_t *map;
mp_int i;
char oper = 0;
psycString name = {0,0}, value = {0,0}, elem = {0,0};
psycString name = {0,0}, value = {0,0}, elem;
psycParseListState listState;
int ret;
size_t len;
assert_shadow_sent(current_object);
psycState *state = O_GET_PSYC_STATE(current_object);
psyc_state_t *state = O_GET_PSYC_STATE(current_object);
if (!state) {
state = pxalloc(sizeof(psycState));
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));
@ -138,7 +137,7 @@ f_psyc_parse (svalue_t *sp) {
errorf("\npsyc_parse got %ld int* bytes... not supported yet\n", i);
}
else if (sp->type == T_STRING) {
printf("\npsyc_parse got a %d bytes long string...\n", mstrsize(sp->u.str));
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)));
}
@ -160,21 +159,50 @@ f_psyc_parse (svalue_t *sp) {
svalue_t *sv;
ret = psyc_parse(state->parser, &oper, &name, &value);
switch (ret) {
case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_BODY_START:
if ((len = psyc_getParseValueLength(state->parser)))
state->tmp = pxalloc(len);
case PSYC_PARSE_ENTITY_CONT: case PSYC_PARSE_BODY_CONT:
case PSYC_PARSE_ENTITY_END: case PSYC_PARSE_BODY_END:
memcpy(state->tmp + state->tmplen, value.ptr, value.length);
state->tmplen += value.length;
if (state->remaining) {
pfree(state->remaining);
state->remaining_len = 0;
}
switch (ret) {
case PSYC_PARSE_ROUTING:
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;
puts("_failure_unsupported_state");
continue;
}
sv = pxalloc(sizeof(svalue_t));
// new_n_tabled fetches a reference of a probably existing
@ -186,20 +214,16 @@ f_psyc_parse (svalue_t *sp) {
// 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_START:
case PSYC_PARSE_ENTITY_CONT:
case PSYC_PARSE_ENTITY_END:
case PSYC_PARSE_ENTITY:
if (oper && oper != ':') {
puts("_failure_unsupported_state");
continue;
case PSYC_PARSE_ENTITY_END:
case PSYC_PARSE_ENTITY:
if (oper != ':') {
puts("_failure_unsupported_state");
continue;
}
if (name.length) {
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);
} else
errorf("sv needs to point to the current map_lvalue .. FIXME!\n");
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
@ -207,61 +231,76 @@ f_psyc_parse (svalue_t *sp) {
put_string(sv, new_n_tabled(value.ptr, value.length));
// list parsing not supported yet.. TODO
if (name.length >= 5 && memcmp(name.ptr, "_list", 5) == 0)
{
write(1, ">>> LIST START\n", 15);
psyc_initParseListState(&listState);
psyc_setParseListBuffer(&listState, value);
while ((ret = psyc_parseList(&listState, &name, &value, &elem)))
if (psyc_isListVar(&name)) {
psyc_initParseListState(&listState);
psyc_setParseListBuffer(&listState, value);
elem = (psycString){0, 0};
while ((ret = psyc_parseList(&listState, &value, &elem))) {
switch (ret)
{
switch (ret)
{
case PSYC_PARSE_LIST_END:
case PSYC_PARSE_LIST_ELEM:
write(1, "|", 1);
write(1, elem.ptr, elem.length);
write(1, "\n", 1);
break;
default:
errorf("Error while parsing PSYC list: %i\n", ret);
/* NOTREACHED */
return sp;
}
if (ret == PSYC_PARSE_LIST_END)
{
write(1, ">>> LIST END\n", 13);
break;
}
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_START:
case PSYC_PARSE_BODY_CONT:
case PSYC_PARSE_BODY_END:
case PSYC_PARSE_BODY:
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));
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:
case PSYC_PARSE_COMPLETE:
ret = 0;
break;
case PSYC_PARSE_INSUFFICIENT:
errorf("Insufficient PSYC data.\n");
/* NOTREACHED */
return sp;
default:
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);

View File

@ -11,28 +11,40 @@
# define PSYC_METHOD 2
# define PSYC_BODY 3
# include <psyc/parser.h>
# include <psyc/parse.h>
# include "array.h"
# include "xalloc.h"
typedef struct {
typedef struct psyc_state_s {
psycParseState *parser;
vector_t *packet;
char *tmp;
size_t tmplen;
} psycState;
// tmp storage for incomplete modifier/body
char oper;
char *name;
size_t name_len;
char *value;
size_t value_len;
// tmp storage for remaining unparsed bytes at the end of the buffer
char *remaining;
size_t remaining_len;
} psyc_state_t;
static inline void
psyc_free_parser (psycState *ps) {
psyc_free_state (psyc_state_t *ps) {
if (!ps)
return;
if (ps->tmp)
pfree((void *) ps->tmp);
if (ps->name)
pfree((void *) ps->name);
if (ps->value)
pfree((void *) ps->value);
if (ps->remaining)
pfree((void *) ps->remaining);
if (ps->parser)
pfree((void *) ps->parser);
if (ps->packet)
free_array(ps->packet);
ps->oper = ps->name_len = ps->value_len = ps->remaining_len = 0;
}
# define PKG_PSYC_H

View File

@ -132,7 +132,7 @@ struct shadow_s
#endif
interactive_t *ip; /* the information for interactive objects */
#ifdef USE_PSYC
psycState *psyc_state; /* in case this objects parses PSYC data */
psyc_state_t *psyc_state; /* in case this objects parses PSYC data */
#endif
};

View File

@ -2703,7 +2703,7 @@ destruct (object_t *ob)
#ifdef USE_PSYC
if (shadow_sent->psyc_state)
psyc_free_parser(shadow_sent->psyc_state);
psyc_free_state(shadow_sent->psyc_state);
#endif
#ifdef USE_SHADOWING

View File

@ -17,7 +17,7 @@ version_longtype="stable"
# A timestamp, to be used by bumpversion and other scripts.
# It can be used, for example, to 'touch' this file on every build, thus
# forcing revision control systems to add it on every checkin automatically.
version_stamp="Sun May 8 22:11:18 CEST 2011"
version_stamp="Mon May 9 21:22:33 CEST 2011"
# Okay, LDMUD is using 3.x.x so to avoid conflicts let's just use 4.x.x
version_major=4