1
0
Fork 0
mirror of git://git.psyc.eu/libpsyc synced 2024-08-15 03:19:02 +00:00

Merge commit 'origin'

This commit is contained in:
psyc://psyced.org/~lynX 2011-06-11 09:00:56 +02:00
commit 96da1b7e6a
18 changed files with 401 additions and 119 deletions

View file

@ -338,7 +338,7 @@ EXTRACT_PRIVATE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
EXTRACT_STATIC = NO
EXTRACT_STATIC = YES
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
# defined locally in source files will be included in the documentation.

View file

@ -138,8 +138,7 @@ Parsing time of 1 000 000 packets, in milliseconds.
A simple strlen() scan of the respective message is provided for comparison.
These tests were performed on a 2.53 GHz Intel(R) Core(TM)2 Duo P9500 CPU.
| input: | PSYC | | JSON | | | XML | |
| parser: | strlen | libpsyc | json-c | json-glib | libxml sax | libxml | rapidxml |
| | strlen | libpsyc | json-c | json-glib | libxml sax | libxml | rapidxml |
|-----------------+--------+---------+--------+-----------+------------+--------+----------|
| user profile | 55 | 608 | 4715 | 16503 | 7350 | 12377 | 2477 |
| psyc-unfriendly | 70 | 286 | 2892 | 12567 | 5538 | 8659 | 1896 |
@ -151,21 +150,20 @@ These tests were performed on a 2.53 GHz Intel(R) Core(TM)2 Duo P9500 CPU.
Pure syntax comparisons above, protocol performance comparisons below:
| input: | | PSYC | | JSON | | | XMPP | |
| parser: | strlen | libpsyc | compact | json-c | json-glib | libxml sax | libxml | rapidxml |
|----------+--------+---------+---------+--------+-----------+------------+--------+----------|
| presence | 30 | 236 | 122 | 2463 | 10016 | 4997 | 7557 | 1719 |
| chat msg | 40 | 295 | 258 | 2147 | 9526 | 5911 | 8999 | 1850 |
| activity | 42 | 353 | 279 | 4666 | 16327 | 13357 | 28858 | 4356 |
|----------+--------+---------+---------+--------+-----------+------------+--------+----------|
| / | < | | > | < | > | < | | > |
| | strlen | libpsyc | libpsyc compact | json-c | json-glib | libxml sax | libxml | rapidxml |
|----------+--------+---------+-----------------+--------+-----------+------------+--------+----------|
| presence | 30 | 236 | 122 | 2463 | 10016 | 4997 | 7557 | 1719 |
| chat msg | 40 | 295 | 258 | 2147 | 9526 | 5911 | 8999 | 1850 |
| activity | 42 | 353 | 279 | 4666 | 16327 | 13357 | 28858 | 4356 |
|----------+--------+---------+-----------------+--------+-----------+------------+--------+----------|
| / | < | | > | < | > | < | | > |
| | | | <c> | | | | | |
Parsing large amounts of binary data. For JSON & XML base64 encoding was used.
Note that the results below include only the parsing time, base64 decoding was
not performed.
| input: | PSYC | | JSON | | | XML | |
| parser: | strlen | libpsyc | json-c | json-glib | libxml sax | libxml | rapidxml |
| | strlen | libpsyc | json-c | json-glib | libxml sax | libxml | rapidxml |
|---------+----------+---------+-----------+------------+------------+-----------+----------|
| 7K | 978 | 77 | 18609 | 98000 | 11445 | 19299 | 8701 |
| 70K | 9613 | 77 | 187540 | 1003900 | 96209 | 167738 | 74296 |

182
d/include/psyc/packet.d Normal file
View file

@ -0,0 +1,182 @@
/*
* Packet data structures and functions for creating them are defined here.
*/
module psyc.packet;
import psyc.common;
import psyc.syntax;
/** Modifier flags. */
enum ModifierFlag
{
/// Modifier needs to be checked if it needs length.
CHECK_LENGTH = 0,
/// Modifier needs length.
NEED_LENGTH = 1,
/// Modifier doesn't need length.
NO_LENGTH = 2,
/// Routing modifier, which implies that it doesn't need length.
ROUTING = 3,
};
/** List flags. */
enum ListFlag
{
/// List needs to be checked if it needs length.
CHECK_LENGTH = 0,
/// List needs length.
NEED_LENGTH = 1,
/// List doesn't need length.
NO_LENGTH = 2,
} ;
/** Packet flags. */
enum PacketFlag
{
/// Packet needs to be checked if it needs content length.
CHECK_LENGTH = 0,
/// Packet needs content length.
NEED_LENGTH = 1,
/// Packet doesn't need content length.
NO_LENGTH = 2,
} ;
/** Structure for a modifier. */
struct Modifier
{
char oper;
String name;
String value;
ModifierFlag flag;
} ;
/** Structure for an entity or routing header. */
struct Header
{
size_t lines;
Modifier *modifiers;
} ;
/** Structure for a list. */
struct List
{
size_t num_elems;
String *elems;
size_t length;
ListFlag flag;
} ;
/** intermediate struct for a PSYC packet */
struct Packet
{
Header routing; ///< Routing header.
Header entity; ///< Entity header.
String method; ///< Contains the method.
String data; ///< Contains the data.
String content; ///< Contains the whole content.
size_t routingLength; ///< Length of routing part.
size_t contentLength; ///< Length of content part.
size_t length; ///< Total length of packet.
PacketFlag flag; ///< Packet flag.
} ;
/**
* \internal
* Check if a modifier needs length.
*/
ModifierFlag psyc_checkModifierLength (Modifier *m)
{
ModifierFlag flag;
if (m->value.length > PSYC_MODIFIER_SIZE_THRESHOLD)
flag = ModifierFlag.NEED_LENGTH;
else if (memchr(m->value.ptr, (int)'\n', m->value.length))
flag = ModifierFlag.NEED_LENGTH;
else
flag = ModifierFlag.NO_LENGTH;
return flag;
}
/** Create new modifier. */
Modifier psyc_newModifier (char oper, String *name, String *value,
ModifierFlag flag)
{
Modifier m = {oper, *name, *value, flag};
if (flag == ModifierFlag.CHECK_LENGTH) // find out if it needs a length
m.flag = psyc_checkModifierLength(&m);
return m;
}
/** Create new modifier */
Modifier psyc_newModifier2 (char oper,
char *name, size_t namelen,
char *value, size_t valuelen,
ModifierFlag flag)
{
String n = {namelen, name};
String v = {valuelen, value};
return psyc_newModifier(oper, &n, &v, flag);
}
/**
* \internal
* Get the total length of a modifier when rendered.
*/
size_t psyc_getModifierLength (Modifier *m);
/**
* \internal
* Check if a list needs length.
*/
ListFlag psyc_checkListLength (List *list);
/**
* \internal
* Get the total length of a list when rendered.
*/
ListFlag psyc_getListLength (List *list);
/**
* \internal
* Check if a packet needs length.
*/
PacketFlag psyc_checkPacketLength (Packet *p);
/**
* Calculate and set the rendered length of packet parts and total packet length.
*/
size_t psyc_setPacketLength (Packet *p);
/** Create new list. */
List psyc_newList (String *elems, size_t num_elems, ListFlag flag);
/** Create new packet. */
Packet psyc_newPacket (Header *routing,
Header *entity,
String *method, String *data,
PacketFlag flag);
/** Create new packet. */
Packet psyc_newPacket2 (Modifier *routing, size_t routinglen,
Modifier *entity, size_t entitylen,
char *method, size_t methodlen,
char *data, size_t datalen,
PacketFlag flag);
/** Create new packet with raw content. */
Packet psyc_newRawPacket (Header *routing, String *content,
PacketFlag flag);
/** Create new packet with raw content. */
Packet psyc_newRawPacket2 (Modifier *routing, size_t routinglen,
char *content, size_t contentlen,
PacketFlag flag);

View file

@ -159,25 +159,6 @@ struct ParseState
return psyc_parse(this, &oper, cast(String*) &name, cast(String*) &value);
}
/**
* Change parse flags in state
*
* Params:
* state = Pointer to the state struct that should be initialized.
* flags = Flags to be set for the parser, see psycParseFlag.
*
* See_Also: psyc_initParseState psycParseFlag
*/
void setParseFlags (ParseFlag flags)
{
this.flags = flags;
if (flags & ParseFlag.START_AT_CONTENT)
this.part = Part.CONTENT;
else
this.part = Part.ROUTING;
}
/**
* Sets a new buffer in the parser state struct with data to be parsed.
*
@ -265,6 +246,7 @@ struct ParseState
void getRemainingBuffer ( ref ubyte[] buf )
{
buf = this.buffer.ptr[cursor .. cursor + getRemainingLength()];
}

57
d/include/psyc/render.d Normal file
View file

@ -0,0 +1,57 @@
module psyc.render;
import psyc.packet;
/*
* All rendering functions and the definitions they use are defined here.
*/
/**
* Return codes for psyc_render.
*/
enum RenderRC
{
/// Error, method is missing, but data is present.
ERROR_METHOD_MISSING = -3,
/// Error, a modifier name is missing.
ERROR_MODIFIER_NAME_MISSING = -2,
/// Error, buffer is too small to render the packet.
ERROR = -1,
/// Packet is rendered successfully in the buffer.
SUCCESS = 0,
} ;
/**
* Return codes for psyc_renderList.
*/
enum RenderListRC
{
/// Error, buffer is too small to render the list.
ERROR = -1,
/// List is rendered successfully in the buffer.
SUCCESS = 0,
};
/**
* Render a PSYC packet into a buffer.
*
* The packet structure should contain the packet parts, either routing, entity,
* method & data, or routing & content when rendering raw content.
* It should also contain the contentLength & total length of the packet,
* you can use psyc_setPacketLength() for calculating & setting these values.
* This function renders packet->length bytes to the buffer,
* if buflen is less than that an error is returned.
*
* @see psyc_newPacket
* @see psyc_newPacket2
* @see psyc_newRawPacket
* @see psyc_newRawPacket2
* @see psyc_setPacketLength
*/
RenderRC psyc_render (Packet *packet, char *buffer, size_t buflen);
/**
* Render a PSYC list into a buffer.
*/
RenderListRC psyc_renderList (List *list, char *buffer, size_t buflen);

36
d/include/psyc/syntax.d Normal file
View file

@ -0,0 +1,36 @@
module psyc.syntax;
const PSYC_LIST_SIZE_LIMIT = 404;
/* beyond this a content length must be provided */
const = PSYC_CONTENT_SIZE_THRESHOLD = 444;
/* beyond this a modifier value length must be provided */
const PSYC_MODIFIER_SIZE_THRESHOLD = 404;
const C_GLYPH_PACKET_DELIMITER = '|';
const S_GLYPH_PACKET_DELIMITER = "|";
const PSYC_PACKET_DELIMITER = "\n|\n";
const C_GLYPH_SEPARATOR_KEYWORD = '_';
const S_GLYPH_SEPARATOR_KEYWORD = "_";
const C_GLYPH_OPERATOR_SET = ':';
const S_GLYPH_OPERATOR_SET = ":";
const C_GLYPH_OPERATOR_ASSIGN = '=';
const S_GLYPH_OPERATOR_ASSIGN = "=";
const C_GLYPH_OPERATOR_AUGMENT = '+';
const S_GLYPH_OPERATOR_AUGMENT = "+";
const C_GLYPH_OPERATOR_DIMINISH = '-';
const S_GLYPH_OPERATOR_DIMINISH = "-";
const C_GLYPH_OPERATOR_QUERY = '?';
const S_GLYPH_OPERATOR_QUERY = "?";
/* might move into routing.h or something */
const PSYC_ROUTING = 1;
const PSYC_ROUTING_MERGE = 2;
const PSYC_ROUTING_RENDER = 4;

View file

@ -88,9 +88,9 @@ typedef enum
typedef struct
{
/// Length of the data pointed to by ptr
size_t length;
size_t length;
/// pointer to the data
const char *ptr;
const char *ptr;
} psycString;
typedef struct

View file

@ -92,7 +92,10 @@ typedef struct
psycPacketFlag flag; ///< Packet flag.
} psycPacket;
/** Check if a modifier needs length. */
/**
* \internal
* Check if a modifier needs length.
*/
static inline
psycModifierFlag psyc_checkModifierLength (psycModifier *m)
{
@ -134,19 +137,33 @@ psycModifier psyc_newModifier2 (char oper,
return psyc_newModifier(oper, &n, &v, flag);
}
/** Get the total length of a modifier when rendered. */
/**
* \internal
* Get the total length of a modifier when rendered.
*/
size_t psyc_getModifierLength (psycModifier *m);
/** Check if a list needs length. */
/**
* \internal
* Check if a list needs length.
*/
psycListFlag psyc_checkListLength (psycList *list);
/** Get the total length of a list when rendered. */
/**
* \internal
* Get the total length of a list when rendered.
*/
psycListFlag psyc_getListLength (psycList *list);
/** Check if a packet needs length. */
/**
* \internal
* Check if a packet needs length.
*/
psycPacketFlag psyc_checkPacketLength (psycPacket *p);
/** Calculate and set the rendered length of packet parts and total packet length. */
/**
* Calculate and set the rendered length of packet parts and total packet length.
*/
size_t psyc_setPacketLength (psycPacket *p);
/** Create new list. */

View file

@ -40,9 +40,7 @@
* char* raw_data; // points to our (possibly incomplete) packet
* size_t raw_len; // how many bytes of data
*
* psyc_setParseBuffer(&state, // our initialized state from before
* raw_data,
* raw_len);
* psyc_setParseBuffer(&state, raw_data, raw_len); // state is our initialized state from before
* @endcode
*
* Now the the variables that will save the output of the parser need to be
@ -179,10 +177,10 @@ typedef enum
/// Start of an incomplete content, value contains part of content.
/// Used when PSYC_PARSE_ROUTING_ONLY is set.
PSYC_PARSE_CONTENT_START = 7,
/// Continuation of an incomplete body.
/// Continuation of an incomplete content.
/// Used when PSYC_PARSE_ROUTING_ONLY is set.
PSYC_PARSE_CONTENT_CONT = 8,
/// End of an incomplete body.
/// End of an incomplete content.
/// Used when PSYC_PARSE_ROUTING_ONLY is set.
PSYC_PARSE_CONTENT_END = 9,
/// Content parsing done in one go, value contains the whole content.
@ -274,27 +272,6 @@ void psyc_initParseState2 (psycParseState *state, uint8_t flags)
state->part = PSYC_PART_CONTENT;
}
/**
* Change parse flags in state
*
* @param state Pointer to the state struct that should be initialized.
* @param flags Flags to be set for the parser, see psycParseFlag.
* @see psyc_initParseState
* @see psycParseFlag
*/
static inline
void psyc_setParseFlags (psycParseState *state, uint8_t flags)
{
state->flags = flags;
if (flags & PSYC_PARSE_START_AT_CONTENT)
state->part = PSYC_PART_CONTENT;
else
state->part = 0;
}
/**
* Sets a new buffer in the parser state struct with data to be parsed.
*
@ -330,7 +307,7 @@ void psyc_setParseBuffer (psycParseState *state, psycString buffer)
* @see psycString
*/
static inline
void psyc_setParseBuffer2 (psycParseState *state, char *buffer, size_t length)
void psyc_setParseBuffer2 (psycParseState *state, const char *buffer, size_t length)
{
psycString buf = {length, buffer};
psyc_setParseBuffer(state, buf);
@ -358,7 +335,7 @@ void psyc_setParseListBuffer (psycParseListState *state, psycString buffer)
}
static inline
void psyc_setParseListBuffer2 (psycParseListState *state, char *buffer, size_t length)
void psyc_setParseListBuffer2 (psycParseListState *state, const char *buffer, size_t length)
{
psycString buf = {length, buffer};
psyc_setParseListBuffer(state, buf);

View file

@ -26,7 +26,7 @@ typedef enum
/// Text template parsing & rendering complete.
PSYC_TEXT_COMPLETE = 0,
/// Text template parsing & rendering is incomplete, because the buffer was too small.
/// Another call is required to this function with a new buffer.
/// Another call is required to this function after setting a new buffer.
PSYC_TEXT_INCOMPLETE = 1,
} psycTextRC;
@ -48,8 +48,8 @@ typedef struct
{
size_t cursor; ///< current position in the template
size_t written; ///< number of bytes written to buffer
psycString template; ///< template to parse
psycString buffer; ///< buffer for writing to
psycString tmpl; ///< input buffer with text template to parse
psycString buffer; ///< output buffer for rendered text
psycString open;
psycString close;
} psycTextState;
@ -70,32 +70,32 @@ typedef psycTextValueRC (*psycTextCB)(const char *name, size_t len, psycString *
* Initializes the PSYC text state struct.
*
* @param state Pointer to the PSYC text state struct that should be initialized.
* @param template Text template to be parsed.
* @param tlen Length of template.
* @param buffer Buffer where the rendered text is going to be written.
* @param blen Length of buffer.
* @param tmpl Input buffer with text template to be parsed.
* @param tmplen Length of input buffer.
* @param buffer Output buffer where the rendered text is going to be written.
* @param buflen Length of output buffer.
*/
static inline
void psyc_initTextState (psycTextState *state,
char *template, size_t tlen,
char *buffer, size_t blen)
const char *tmpl, size_t tmplen,
char *buffer, size_t buflen)
{
state->cursor = 0;
state->written = 0;
state->template = (psycString) {tlen, template};
state->buffer = (psycString) {blen, buffer};
state->open = (psycString) {1, "["};
state->close = (psycString) {1, "]"};
state->cursor = 0;
state->written = 0;
state->tmpl = (psycString) {tmplen, tmpl};
state->buffer = (psycString) {buflen, buffer};
state->open = (psycString) {1, "["};
state->close = (psycString) {1, "]"};
}
/**
* Initializes the PSYC text state struct with custom open & closing braces.
* Initializes the PSYC text state struct with custom opening & closing braces.
*
* @param state Pointer to the PSYC text state struct that should be initialized.
* @param template Text template to be parsed.
* @param tlen Length of template.
* @param buffer Buffer where the rendered text is going to be written.
* @param blen Length of buffer.
* @param tmpl Input buffer with text template to be parsed.
* @param tmplen Length of input buffer.
* @param buffer Output buffer where the rendered text is going to be written.
* @param buflen Length of output buffer.
* @param open Opening brace.
* @param openlen Length of opening brace.
* @param close Closing brace.
@ -103,19 +103,21 @@ void psyc_initTextState (psycTextState *state,
*/
static inline
void psyc_initTextState2 (psycTextState *state,
char *template, size_t tlen,
char *buffer, size_t blen,
char *open, size_t openlen,
char *close, size_t closelen)
const char *tmpl, size_t tmplen,
char *buffer, size_t buflen,
const char *open, size_t openlen,
const char *close, size_t closelen)
{
state->template = (psycString) {tlen, template};
state->buffer = (psycString) {blen, buffer};
state->open = (psycString) {openlen, open};
state->close = (psycString) {closelen, close};
state->cursor = 0;
state->written = 0;
state->tmpl = (psycString) {tmplen, tmpl};
state->buffer = (psycString) {buflen, buffer};
state->open = (psycString) {openlen, open};
state->close = (psycString) {closelen, close};
}
/**
* Sets a new buffer in the PSYC text state struct.
* Sets a new output buffer in the PSYC text state struct.
*/
static inline
void psyc_setTextBuffer (psycTextState *state, psycString buffer)
@ -149,10 +151,10 @@ size_t psyc_getTextBytesWritten (psycTextState *state)
* string between these braces. Should the callback return
* PSYC_TEXT_VALUE_NOT_FOUND, the original template text is copied as is.
*
* Before calling this function psyc_initTextState or psyc_initTextState should
* be called to initialze the state struct. By default PSYC's "[" and "]" are
* used but you can provide any other brace strings such as "${" and "}" or
* "<!--" and "-->".
* Before calling this function psyc_initTextState should be called to initialize
* the state struct. By default PSYC's "[" and "]" are used but you can provide
* any other brace strings such as "${" and "}" or "<!--" and "-->" if you use
* the psyc_initTextState2 variant.
*
* @see http://about.psyc.eu/psyctext
**/

View file

@ -1,12 +1,15 @@
OPT = -O2
DEBUG = 2
CFLAGS = -I../include -Wall -std=c99 ${OPT}
CFLAGS = -I../include -Wall -std=c99 -fPIC ${OPT}
DIET = diet
S = packet.c parse.c match.c render.c memmem.c itoa.c variable.c text.c
O = packet.o parse.o match.o render.o memmem.o itoa.o variable.o text.o
P = match itoa
A = ../lib/libpsyc.a
SO = ../lib/libpsyc.so
all: CC := ${WRAPPER} ${CC}
all: lib
@ -18,9 +21,15 @@ diet: WRAPPER = ${DIET}
diet: CC := ${WRAPPER} ${CC}
diet: lib
lib: $O
lib: $O $A ${SO}
${SO}:
@mkdir -p ../lib
${WRAPPER} ${AR} rcs ../lib/libpsyc.a $O
${CC} ${CFLAGS} -shared -lm -o $@ $O
$A:
@mkdir -p ../lib
${WRAPPER} ${AR} rcs $@ $O
match: match.c
${CC} -o $@ -DDEBUG=4 -DCMDTOOL -DTEST $<

View file

@ -3,29 +3,29 @@
psycTextRC psyc_text (psycTextState *state, psycTextCB getValue)
{
const char *start = state->template.ptr, *end; // start & end of variable name
const char *prev = state->template.ptr + state->cursor;
const char *start = state->tmpl.ptr, *end; // start & end of variable name
const char *prev = state->tmpl.ptr + state->cursor;
psycString value;
int ret;
size_t len;
uint8_t no_subst = (state->cursor == 0); // whether we can return NO_SUBST
while (state->cursor < state->template.length)
while (state->cursor < state->tmpl.length)
{
start = memmem(state->template.ptr + state->cursor,
state->template.length - state->cursor,
start = memmem(state->tmpl.ptr + state->cursor,
state->tmpl.length - state->cursor,
state->open.ptr, state->open.length);
if (!start)
break;
state->cursor = (start - state->template.ptr) + state->open.length;
if (state->cursor >= state->template.length)
state->cursor = (start - state->tmpl.ptr) + state->open.length;
if (state->cursor >= state->tmpl.length)
break; // [ at the end
end = memmem(state->template.ptr + state->cursor,
state->template.length - state->cursor,
end = memmem(state->tmpl.ptr + state->cursor,
state->tmpl.length - state->cursor,
state->close.ptr, state->close.length);
state->cursor = (end - state->template.ptr) + state->close.length;
state->cursor = (end - state->tmpl.ptr) + state->close.length;
if (!end)
break; // ] not found
@ -40,12 +40,12 @@ psycTextRC psyc_text (psycTextState *state, psycTextCB getValue)
if (ret < 0)
continue; // value not found, no substitution
// first copy the part in the template from the previous subst. to the current one
// first copy the part in the input from the previous subst. to the current one
// if there's enough buffer space for that
len = start - prev;
if (state->written + len > state->buffer.length)
{
state->cursor = prev - state->template.ptr;
state->cursor = prev - state->tmpl.ptr;
return PSYC_TEXT_INCOMPLETE;
}
@ -55,7 +55,7 @@ psycTextRC psyc_text (psycTextState *state, psycTextCB getValue)
// now substitute the value if there's enough buffer space
if (state->written + value.length > state->buffer.length)
{
state->cursor = start - state->template.ptr;
state->cursor = start - state->tmpl.ptr;
return PSYC_TEXT_INCOMPLETE;
}
@ -63,7 +63,7 @@ psycTextRC psyc_text (psycTextState *state, psycTextCB getValue)
state->written += value.length;
// mark the start of the next chunk of text in the template
prev = state->template.ptr + state->cursor;
prev = state->tmpl.ptr + state->cursor;
no_subst = 0;
}
@ -71,7 +71,7 @@ psycTextRC psyc_text (psycTextState *state, psycTextCB getValue)
return PSYC_TEXT_NO_SUBST;
// copy the rest of the template after the last var
len = state->template.length - (prev - state->template.ptr);
len = state->tmpl.length - (prev - state->tmpl.ptr);
if (state->written + len > state->buffer.length)
return PSYC_TEXT_INCOMPLETE;

View file

@ -0,0 +1,4 @@
_message_private
OHAI
|

1
test/packets/00-empty Normal file
View file

@ -0,0 +1 @@
|

View file

@ -0,0 +1,4 @@
22
_message_private
OHAI
|

View file

@ -0,0 +1,6 @@
:_source psyc://foo.example.com/
:_target psyc://bar.example.com/
22
_message_private
OHAI
|

View file

@ -0,0 +1,3 @@
_
|

View file

@ -80,6 +80,8 @@ int test_input (int i, char *recvbuf, size_t nbytes) {
value.length = 0;
do {
if (verbose >= 3)
printf("\n# buffer = [%.*s]\n# part = %d\n", (int)parsers[i].buffer.length, parsers[i].buffer.ptr, parsers[i].part);
// Parse the next part of the packet (a routing/entity modifier or the body)
ret = exit_code = psyc_parse(&parsers[i], &oper, &name, &value);
if (verbose >= 2)
@ -188,6 +190,8 @@ int test_input (int i, char *recvbuf, size_t nbytes) {
contbytes = psyc_getParseRemainingLength(&parsers[i]);
if (contbytes > 0) { // copy end of parsebuf before start of recvbuf
if (verbose >= 3)
printf("# remaining = [%.*s]\n", (int)contbytes, psyc_getParseRemainingBuffer(&parsers[i]));
assert(contbytes <= CONT_BUF_SIZE); // make sure it's still in the buffer
memmove(recvbuf - contbytes, psyc_getParseRemainingBuffer(&parsers[i]), contbytes);
}