mirror of
git://git.psyc.eu/libpsyc
synced 2024-08-15 03:19:02 +00:00
Merge branch 'master' of supraverse.net:libpsyc
This commit is contained in:
commit
906f5debaa
2 changed files with 113 additions and 90 deletions
|
@ -69,44 +69,47 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
size_t cursor; /** current position in buffer */
|
||||
size_t startc; /** line start position */
|
||||
size_t cursor; ///< current position in buffer
|
||||
size_t startc; ///< line start position
|
||||
PSYC_Array buffer;
|
||||
uint8_t flags;
|
||||
char part; /** part of the packet being parsed currently, see PSYC_Parts */
|
||||
char part; ///< part of the packet being parsed currently, see PSYC_Parts
|
||||
|
||||
size_t contentParsed; /** number of bytes parsed from the content so far */
|
||||
size_t contentLength; /** expected length of the content */
|
||||
char contentLengthFound; /** is there a length given for this packet? */
|
||||
size_t valueParsed; /** number of bytes parsed from the value so far */
|
||||
size_t valueLength; /** expected length of the value */
|
||||
size_t contentParsed; ///< number of bytes parsed from the content so far
|
||||
size_t contentLength; ///< expected length of the content
|
||||
char contentLengthFound; ///< is there a length given for this packet?
|
||||
size_t valueParsed; ///< number of bytes parsed from the value so far
|
||||
size_t valueLength; ///< expected length of the value
|
||||
} PSYC_State;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t cursor; /** current position in buffer */
|
||||
size_t startc; /** line start position */
|
||||
size_t cursor; ///< current position in buffer
|
||||
size_t startc; ///< line start position
|
||||
PSYC_Array buffer;
|
||||
char type; /** list type, see PSYC_ListTypes */
|
||||
char type; ///< list type, see PSYC_ListTypes
|
||||
|
||||
size_t elemParsed; /** number of bytes parsed from the elem so far */
|
||||
size_t elemLength; /** expected length of the elem */
|
||||
size_t elemParsed; ///< number of bytes parsed from the elem so far
|
||||
size_t elemLength; ///< expected length of the elem
|
||||
} PSYC_ListState;
|
||||
|
||||
#ifndef PSYC_COMPILE_LIBRARY
|
||||
/* @brief Shortcut for creating an array.
|
||||
/**
|
||||
* Shortcut for creating an array.
|
||||
*
|
||||
* @param memory Pointer to the buffer.
|
||||
* @param length Length of that buffer.
|
||||
*
|
||||
* @return An instance of the PSYC_Array struct. */
|
||||
* @return An instance of the PSYC_Array struct.
|
||||
*/
|
||||
inline PSYC_Array PSYC_createArray (uint8_t* const memory, size_t length)
|
||||
{
|
||||
PSYC_Array arr = {length, memory};
|
||||
return arr;
|
||||
}
|
||||
|
||||
/* @brief Initiates the state struct with flags.
|
||||
/**
|
||||
* Initiates the state struct with flags.
|
||||
*
|
||||
* @param state Pointer to the state struct that should be initiated.
|
||||
* @param flags The flags that one ones to set, see PSYC_Flags.
|
||||
|
@ -117,7 +120,8 @@ inline void PSYC_initState2 (PSYC_State* state, uint8_t flags )
|
|||
state->flags = flags;
|
||||
}
|
||||
|
||||
/* @brief Initiates the state struct.
|
||||
/**
|
||||
* Initiates the state struct.
|
||||
*
|
||||
* @param state Pointer to the state struct that should be initiated.
|
||||
*/
|
||||
|
@ -126,7 +130,8 @@ inline void PSYC_initState (PSYC_State* state)
|
|||
memset(state, 0, sizeof(PSYC_State));
|
||||
}
|
||||
|
||||
/* @brief Initiates the list state struct.
|
||||
/**
|
||||
* Initiates the list state struct.
|
||||
*
|
||||
* @param state Pointer to the list state struct that should be initiated.
|
||||
*/
|
||||
|
|
162
src/parser.c
162
src/parser.c
|
@ -14,9 +14,9 @@
|
|||
return ret; \
|
||||
}
|
||||
|
||||
/** @brief isGlyph
|
||||
*
|
||||
* @todo: document this function
|
||||
/**
|
||||
* Determines if the argument is a glyph.
|
||||
* Glyphs are: : = + - ? !
|
||||
*/
|
||||
inline char isGlyph(uint8_t g)
|
||||
{
|
||||
|
@ -34,11 +34,17 @@ inline char isGlyph(uint8_t g)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the argument is numeric.
|
||||
*/
|
||||
inline char isNumeric(uint8_t c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the argument is alphanumeric.
|
||||
*/
|
||||
inline char isAlphaNumeric(uint8_t c)
|
||||
{
|
||||
return
|
||||
|
@ -47,14 +53,18 @@ inline char isAlphaNumeric(uint8_t c)
|
|||
isNumeric(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the argument is a keyword character.
|
||||
* Keyword characters are: alphanumeric and _
|
||||
*/
|
||||
inline char isKwChar(uint8_t c)
|
||||
{
|
||||
return isAlphaNumeric(c) || c == '_';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse variable name or method name.
|
||||
* @details It should contain one or more keyword characters.
|
||||
* Parse variable name or method name.
|
||||
* It should contain one or more keyword characters.
|
||||
* @return PSYC_ERROR or PSYC_SUCCESS
|
||||
*/
|
||||
inline int PSYC_parseName(PSYC_State* state, PSYC_Array* name)
|
||||
|
@ -64,7 +74,7 @@ inline int PSYC_parseName(PSYC_State* state, PSYC_Array* name)
|
|||
|
||||
while (isKwChar(state->buffer.ptr[state->cursor]))
|
||||
{
|
||||
name->length++; /* was a valid char, increase length */
|
||||
name->length++; // was a valid char, increase length
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_INSUFFICIENT);
|
||||
}
|
||||
|
||||
|
@ -72,8 +82,8 @@ inline int PSYC_parseName(PSYC_State* state, PSYC_Array* name)
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Parse binary data into value.
|
||||
* @details length is the expected length of the data, parsed is the number of bytes parsed so far
|
||||
* Parse binary data into value.
|
||||
* length is the expected length of the data, parsed is the number of bytes parsed so far
|
||||
* @return PSYC_COMPLETE or PSYC_INCOMPLETE
|
||||
*/
|
||||
inline int PSYC_parseBinaryValue(PSYC_State* state, PSYC_Array* value, size_t* length, size_t* parsed)
|
||||
|
@ -81,7 +91,7 @@ inline int PSYC_parseBinaryValue(PSYC_State* state, PSYC_Array* value, size_t* l
|
|||
size_t remaining = *length - *parsed;
|
||||
value->ptr = state->buffer.ptr + state->cursor;
|
||||
|
||||
if (state->cursor + remaining > state->buffer.length) /* is the length larger than this buffer? */
|
||||
if (state->cursor + remaining > state->buffer.length) // is the length larger than this buffer?
|
||||
{
|
||||
value->length = state->buffer.length - state->cursor;
|
||||
*parsed += value->length;
|
||||
|
@ -96,7 +106,7 @@ inline int PSYC_parseBinaryValue(PSYC_State* state, PSYC_Array* value, size_t* l
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Parse simple or binary variable
|
||||
* Parse simple or binary variable.
|
||||
* @return PSYC_ERROR or PSYC_SUCCESS
|
||||
*/
|
||||
inline int PSYC_parseVar(PSYC_State* state, uint8_t* modifier, PSYC_Array* name, PSYC_Array* value)
|
||||
|
@ -109,10 +119,10 @@ inline int PSYC_parseVar(PSYC_State* state, uint8_t* modifier, PSYC_Array* name,
|
|||
|
||||
value->length = 0;
|
||||
|
||||
/* Parse the value.
|
||||
* If we're in the content part check if it's a binary var */
|
||||
if (state->part == PSYC_PART_CONTENT && state->buffer.ptr[state->cursor] == ' ') /* binary arg */
|
||||
{ /* After SP the length follows. */
|
||||
// Parse the value.
|
||||
// If we're in the content part check if it's a binary var.
|
||||
if (state->part == PSYC_PART_CONTENT && state->buffer.ptr[state->cursor] == ' ') // binary arg
|
||||
{ // After SP the length follows.
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_INSUFFICIENT);
|
||||
state->valueLength = 0;
|
||||
state->valueParsed = 0;
|
||||
|
@ -129,11 +139,11 @@ inline int PSYC_parseVar(PSYC_State* state, uint8_t* modifier, PSYC_Array* name,
|
|||
else
|
||||
return PSYC_ERROR_VAR_LEN;
|
||||
|
||||
/* After the length a TAB follows. */
|
||||
// After the length a TAB follows.
|
||||
if (state->buffer.ptr[state->cursor] != '\t')
|
||||
return PSYC_ERROR_VAR_TAB;
|
||||
|
||||
if (state->buffer.length <= ++(state->cursor)) /* Incremented cursor inside length? */
|
||||
if (state->buffer.length <= ++(state->cursor)) // Incremented cursor inside length?
|
||||
return PSYC_ENTITY_INCOMPLETE;
|
||||
|
||||
if (PSYC_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed)) == PSYC_INCOMPLETE)
|
||||
|
@ -142,7 +152,7 @@ inline int PSYC_parseVar(PSYC_State* state, uint8_t* modifier, PSYC_Array* name,
|
|||
state->cursor++;
|
||||
return PSYC_SUCCESS;
|
||||
}
|
||||
else if (state->buffer.ptr[state->cursor] == '\t') /* simple arg */
|
||||
else if (state->buffer.ptr[state->cursor] == '\t') // simple arg
|
||||
{
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_INSUFFICIENT);
|
||||
value->ptr = state->buffer.ptr + state->cursor;
|
||||
|
@ -159,49 +169,52 @@ inline int PSYC_parseVar(PSYC_State* state, uint8_t* modifier, PSYC_Array* name,
|
|||
return PSYC_ERROR_VAR_TAB;
|
||||
}
|
||||
|
||||
/** @brief Generalized line-based parser. */
|
||||
/**
|
||||
* Parse PSYC packets.
|
||||
* Generalized line-based parser.
|
||||
* @return see PSYC_ReturnCodes
|
||||
*/
|
||||
int PSYC_parse(PSYC_State* state, uint8_t* modifier, PSYC_Array* name, PSYC_Array* value)
|
||||
{
|
||||
int ret; /* a return value */
|
||||
size_t pos; /* a cursor position */
|
||||
int ret; // a return value
|
||||
size_t pos; // a cursor position
|
||||
|
||||
/* Start position of the current line in the buffer
|
||||
* in case we return insufficent, we rewind to this position. */
|
||||
// Start position of the current line in the buffer
|
||||
// in case we return insufficent, we rewind to this position.
|
||||
state->startc = state->cursor;
|
||||
|
||||
/* First we test if we can access the first char. */
|
||||
if (state->cursor >= state->buffer.length) /* cursor is not inside the length */
|
||||
return PSYC_INSUFFICIENT; /* return insufficient data. */
|
||||
// First we test if we can access the first char.
|
||||
if (state->cursor >= state->buffer.length) // cursor is not inside the length
|
||||
return PSYC_INSUFFICIENT;
|
||||
|
||||
switch (state->part)
|
||||
{
|
||||
case PSYC_PART_RESET: /* New packet starts here, reset state. */
|
||||
case PSYC_PART_RESET: // New packet starts here, reset state.
|
||||
state->valueParsed = 0;
|
||||
state->valueLength = 0;
|
||||
state->contentParsed = 0;
|
||||
state->contentLength = 0;
|
||||
state->contentLengthFound = 0;
|
||||
state->part = PSYC_PART_HEADER;
|
||||
/* fall thru */
|
||||
// fall thru
|
||||
|
||||
case PSYC_PART_HEADER:
|
||||
/* Each line of the header starts with a glyph,
|
||||
* i.e. :_name, -_name +_name etc,
|
||||
* so just test if the first char is a glyph.
|
||||
*/
|
||||
if (isGlyph(state->buffer.ptr[state->cursor])) /* is the first char a glyph? */
|
||||
{ /* it is a glyph, so a variable starts here */
|
||||
// Each line of the header starts with a glyph,
|
||||
// i.e. :_name, -_name +_name etc,
|
||||
// so just test if the first char is a glyph.
|
||||
if (isGlyph(state->buffer.ptr[state->cursor])) // is the first char a glyph?
|
||||
{ // it is a glyph, so a variable starts here
|
||||
ret = PSYC_parseVar(state, modifier, name, value);
|
||||
return ret == PSYC_SUCCESS ? PSYC_ROUTING : ret;
|
||||
}
|
||||
else /* not a glyph */
|
||||
else // not a glyph
|
||||
{
|
||||
state->part = PSYC_PART_LENGTH;
|
||||
/* fall thru */
|
||||
// fall thru
|
||||
}
|
||||
|
||||
case PSYC_PART_LENGTH:
|
||||
/* End of header, content starts with an optional length then a NL */
|
||||
// End of header, content starts with an optional length then a NL
|
||||
if (isNumeric(state->buffer.ptr[state->cursor]))
|
||||
{
|
||||
state->contentLengthFound = 1;
|
||||
|
@ -214,17 +227,18 @@ int PSYC_parse(PSYC_State* state, uint8_t* modifier, PSYC_Array* name, PSYC_Arra
|
|||
while (isNumeric(state->buffer.ptr[state->cursor]));
|
||||
}
|
||||
|
||||
if (state->buffer.ptr[state->cursor] == '\n') /* start of content */
|
||||
if (state->buffer.ptr[state->cursor] == '\n') // start of content
|
||||
{
|
||||
/* If we need to parse the header only and we know the content length, then skip content parsing. */
|
||||
// If we need to parse the header only and we know the content length,
|
||||
// then skip content parsing.
|
||||
if (state->flags & PSYC_HEADER_ONLY && state->contentLengthFound)
|
||||
state->part = PSYC_PART_DATA;
|
||||
else
|
||||
state->part = PSYC_PART_CONTENT;
|
||||
}
|
||||
else /* Not start of content, this must be the end. */
|
||||
else // Not start of content, this must be the end.
|
||||
{
|
||||
/* If we have a length then it should've been followed by a \n */
|
||||
// If we have a length then it should've been followed by a \n
|
||||
if (state->contentLengthFound)
|
||||
return PSYC_ERROR_LENGTH;
|
||||
|
||||
|
@ -234,22 +248,21 @@ int PSYC_parse(PSYC_State* state, uint8_t* modifier, PSYC_Array* name, PSYC_Arra
|
|||
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_INSUFFICIENT);
|
||||
state->startc = state->cursor;
|
||||
/* fall thru */
|
||||
// fall thru
|
||||
|
||||
case PSYC_PART_CONTENT:
|
||||
/* In case of an incomplete binary variable resume parsing it. */
|
||||
// In case of an incomplete binary variable resume parsing it.
|
||||
if (state->valueParsed < state->valueLength) {
|
||||
ret = PSYC_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
|
||||
state->contentParsed += value->length;
|
||||
return ret == PSYC_COMPLETE ? PSYC_ENTITY : PSYC_ENTITY_INCOMPLETE;
|
||||
}
|
||||
|
||||
/* Each line of the header starts with a glyph,
|
||||
* i.e. :_name, -_name +_name etc.
|
||||
* So just test if the first char is a glyph.
|
||||
* In the body, the same applies, only that the
|
||||
* method does not start with a glyph.
|
||||
*/
|
||||
// Each line of the header starts with a glyph,
|
||||
// i.e. :_name, -_name +_name etc.
|
||||
// So just test if the first char is a glyph.
|
||||
// In the body, the same applies, only that the
|
||||
// method does not start with a glyph.
|
||||
if (isGlyph(state->buffer.ptr[state->cursor]))
|
||||
{
|
||||
pos = state->cursor;
|
||||
|
@ -261,13 +274,13 @@ int PSYC_parse(PSYC_State* state, uint8_t* modifier, PSYC_Array* name, PSYC_Arra
|
|||
{
|
||||
state->part = PSYC_PART_METHOD;
|
||||
state->startc = state->cursor;
|
||||
/* fall thru */
|
||||
// fall thru
|
||||
}
|
||||
|
||||
case PSYC_PART_METHOD:
|
||||
pos = state->cursor;
|
||||
if (PSYC_parseName(state, name) == PSYC_SUCCESS)
|
||||
{ /* the method ends with a \n then the data follows */
|
||||
{ // the method ends with a \n then the data follows
|
||||
if (state->buffer.ptr[state->cursor] != '\n')
|
||||
return PSYC_ERROR_METHOD;
|
||||
|
||||
|
@ -277,9 +290,9 @@ int PSYC_parse(PSYC_State* state, uint8_t* modifier, PSYC_Array* name, PSYC_Arra
|
|||
state->part = PSYC_PART_DATA;
|
||||
if (state->cursor >= state->buffer.length)
|
||||
return PSYC_INSUFFICIENT;
|
||||
/* fall thru */
|
||||
// fall thru
|
||||
}
|
||||
else /* No method, which means the packet should end now. */
|
||||
else // No method, which means the packet should end now.
|
||||
{
|
||||
state->part = PSYC_PART_END;
|
||||
state->startc = state->cursor;
|
||||
|
@ -290,7 +303,7 @@ int PSYC_parse(PSYC_State* state, uint8_t* modifier, PSYC_Array* name, PSYC_Arra
|
|||
value->ptr = state->buffer.ptr + state->cursor;
|
||||
value->length = 0;
|
||||
|
||||
if (state->contentLengthFound) /* We know the length of the packet. */
|
||||
if (state->contentLengthFound) // We know the length of the packet.
|
||||
{
|
||||
if (PSYC_parseBinaryValue(state, value, &(state->contentLength), &(state->contentParsed)) == PSYC_INCOMPLETE)
|
||||
return PSYC_BODY_INCOMPLETE;
|
||||
|
@ -299,20 +312,20 @@ int PSYC_parse(PSYC_State* state, uint8_t* modifier, PSYC_Array* name, PSYC_Arra
|
|||
state->part = PSYC_PART_END;
|
||||
return PSYC_BODY;
|
||||
}
|
||||
else /* Search for the terminator. */
|
||||
else // Search for the terminator.
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if (state->buffer.ptr[state->cursor] == '\n')
|
||||
{
|
||||
if (state->cursor+2 >= state->buffer.length) /* incremented cursor inside length? */
|
||||
if (state->cursor+2 >= state->buffer.length) // incremented cursor inside length?
|
||||
{
|
||||
state->cursor = state->startc;
|
||||
return PSYC_INSUFFICIENT;
|
||||
}
|
||||
|
||||
if (state->buffer.ptr[state->cursor+1] == '|' &&
|
||||
state->buffer.ptr[state->cursor+2] == '\n') /* packet ends here */
|
||||
state->buffer.ptr[state->cursor+2] == '\n') // packet ends here
|
||||
{
|
||||
state->cursor++;
|
||||
state->part = PSYC_PART_END;
|
||||
|
@ -326,28 +339,31 @@ int PSYC_parse(PSYC_State* state, uint8_t* modifier, PSYC_Array* name, PSYC_Arra
|
|||
|
||||
case PSYC_PART_END:
|
||||
PSYC_PART_END:
|
||||
/* End of packet, at this point we have already passed a \n
|
||||
and the cursor should point to | */
|
||||
if (state->cursor+1 >= state->buffer.length) /* incremented cursor inside length? */
|
||||
// End of packet, at this point we have already passed a \n
|
||||
// and the cursor should point to |
|
||||
if (state->cursor+1 >= state->buffer.length) // incremented cursor inside length?
|
||||
return PSYC_INSUFFICIENT;
|
||||
|
||||
if (state->buffer.ptr[state->cursor] == '|' &&
|
||||
state->buffer.ptr[state->cursor+1] == '\n') /* packet ends here */
|
||||
state->buffer.ptr[state->cursor+1] == '\n') // packet ends here
|
||||
{
|
||||
state->cursor += 2;
|
||||
state->part = PSYC_PART_RESET;
|
||||
return PSYC_COMPLETE;
|
||||
}
|
||||
else /* packet should've ended here, return error */
|
||||
else // packet should've ended here, return error
|
||||
{
|
||||
state->part = PSYC_PART_RESET;
|
||||
return PSYC_ERROR_END;
|
||||
}
|
||||
}
|
||||
return PSYC_ERROR; /* should not be reached */
|
||||
return PSYC_ERROR; // should not be reached
|
||||
}
|
||||
|
||||
/** @brief list parser */
|
||||
/**
|
||||
* List value parser.
|
||||
* @return see PSYC_ListReturnCodes.
|
||||
*/
|
||||
int PSYC_parseList(PSYC_ListState* state, PSYC_Array *name, PSYC_Array* value, PSYC_Array* elem)
|
||||
{
|
||||
if (state->cursor >= state->buffer.length)
|
||||
|
@ -355,13 +371,13 @@ int PSYC_parseList(PSYC_ListState* state, PSYC_Array *name, PSYC_Array* value, P
|
|||
|
||||
state->startc = state->cursor;
|
||||
|
||||
if (!state->type) /* If type is not set we're at the start */
|
||||
if (!state->type) // If type is not set we're at the start
|
||||
{
|
||||
if (name->length < 5 || memcmp(name->ptr, "_list", 5) != 0 ||
|
||||
(name->length > 5 && name->ptr[5] != '_')) /* name should be _list or should start with _list_ */
|
||||
(name->length > 5 && name->ptr[5] != '_')) // name should be _list or should start with _list_
|
||||
return PSYC_ERROR_LIST_NAME;
|
||||
|
||||
/* First character is either | for text lists, or a number for binary lists */
|
||||
// First character is either | for text lists, or a number for binary lists
|
||||
if (state->buffer.ptr[state->cursor] == '|')
|
||||
{
|
||||
state->type = PSYC_LIST_TEXT;
|
||||
|
@ -390,10 +406,11 @@ int PSYC_parseList(PSYC_ListState* state, PSYC_Array *name, PSYC_Array* value, P
|
|||
state->cursor++;
|
||||
return PSYC_LIST_ELEM;
|
||||
}
|
||||
else /* binary list */
|
||||
else // binary list
|
||||
{
|
||||
if (!(state->elemParsed < state->elemLength)) {
|
||||
/* Element starts with a number. */
|
||||
if (!(state->elemParsed < state->elemLength))
|
||||
{
|
||||
// Element starts with a number.
|
||||
if (isNumeric(state->buffer.ptr[state->cursor]))
|
||||
{
|
||||
do
|
||||
|
@ -415,8 +432,9 @@ int PSYC_parseList(PSYC_ListState* state, PSYC_Array *name, PSYC_Array* value, P
|
|||
state->elemParsed = 0;
|
||||
}
|
||||
|
||||
/* Start or resume parsing the binary data */
|
||||
if (state->elemParsed < state->elemLength) {
|
||||
// Start or resume parsing the binary data
|
||||
if (state->elemParsed < state->elemLength)
|
||||
{
|
||||
if (PSYC_parseBinaryValue((PSYC_State*)state, elem, &(state->elemLength), &(state->elemParsed)) == PSYC_INCOMPLETE)
|
||||
return PSYC_LIST_INCOMPLETE;
|
||||
|
||||
|
@ -433,5 +451,5 @@ int PSYC_parseList(PSYC_ListState* state, PSYC_Array *name, PSYC_Array* value, P
|
|||
}
|
||||
}
|
||||
|
||||
return PSYC_ERROR_LIST; /* should not be reached */
|
||||
return PSYC_ERROR_LIST; // should not be reached
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue