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

437 lines
12 KiB
C
Raw Normal View History

2010-02-20 16:40:09 +00:00
#include <stdint.h>
2010-02-20 19:31:22 +00:00
#include <stdlib.h>
2010-02-20 16:40:09 +00:00
#ifdef DEBUG
#include <stdio.h>
#endif
#include <psyc/parser.h>
2010-02-20 19:31:22 +00:00
2010-02-20 16:40:09 +00:00
/** @brief isGlyph
*
* @todo: document this function
*/
inline char isGlyph(uint8_t g)
{
switch(g)
{
case ':':
case '-':
case '+':
case '=':
return 1;
default:
return 0;
}
}
2010-02-20 19:31:22 +00:00
inline char isNumeric(uint8_t c)
{
return c >= '0' && c <= '9' ;
}
2010-02-20 16:40:09 +00:00
inline char isAlphaNumeric(uint8_t c)
{
return
(( c >= 'a' && c <= 'z' )||
( c >= 'A' && c <= 'Z' )||
2010-02-20 19:31:22 +00:00
isNumeric(c))
2010-02-20 16:40:09 +00:00
;
}
2010-02-20 19:31:22 +00:00
2010-02-20 16:40:09 +00:00
/** @brief generalized linebased parser */
2011-04-15 23:42:36 +00:00
inline int PSYC_parse(
PSYC_State* state,
2011-04-18 08:09:35 +00:00
uint8_t* modifier, PSYC_Array* name, PSYC_Array* value)
2010-02-20 16:40:09 +00:00
{
2011-04-17 10:56:24 +00:00
start:
2011-04-18 08:09:35 +00:00
if (state->valueRemaining != 0)
goto binaryArg;
2010-02-20 16:40:09 +00:00
/* first we test if we can access the first char */
2011-04-15 23:42:36 +00:00
if(state->buffer.length<=state->cursor) // cursor is not inside the length
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT; // return insufficient data.
2010-02-20 16:40:09 +00:00
// in case we return insufficent, we rewind to the start.
2011-04-15 23:42:36 +00:00
unsigned int startc=state->cursor;
2010-02-20 16:40:09 +00:00
2011-04-18 08:09:35 +00:00
/******************************************
* * * * * * * Inspect Header * * * * * * *
*******************************************/
2010-02-20 16:40:09 +00:00
/* each line of the header starts with a glyph.
* iE :_name, -_name +_name etc, so just test if
* the first char is a glyph. */
2011-04-18 08:09:35 +00:00
if(0==state->inContent)
2010-02-20 16:40:09 +00:00
{
2011-04-15 23:42:36 +00:00
if(!isGlyph(state->buffer.ptr[state->cursor])) // is the first char not a glyph?
2011-04-18 08:09:35 +00:00
{ // parse length of content here
2011-04-17 10:05:14 +00:00
if(isNumeric(state->buffer.ptr[state->cursor]))
{
2011-04-18 08:09:35 +00:00
if(state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
2011-04-17 10:05:14 +00:00
{
state->cursor=startc; // set to start value
return PSYC_INSUFFICIENT; // return insufficient
}
while(isNumeric(state->buffer.ptr[state->cursor]));
{
2011-04-18 08:09:35 +00:00
state->contentLength = 10 * state->contentLength + state->buffer.ptr[state->cursor] - '0';
2011-04-17 10:05:14 +00:00
2011-04-18 08:09:35 +00:00
if(state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
2011-04-17 10:05:14 +00:00
{
state->cursor=startc; // set to start value
return PSYC_INSUFFICIENT; // return insufficient
}
}
2011-04-18 08:09:35 +00:00
}
// header ends with a NL
if (state->buffer.ptr[state->cursor] != '\n')
{
return -10;
}
2011-04-17 10:05:14 +00:00
2011-04-18 08:09:35 +00:00
if (state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
{
state->cursor=startc; // set to start value
return PSYC_INSUFFICIENT; // return insufficient
2011-04-17 10:05:14 +00:00
}
2010-02-20 16:40:09 +00:00
// the only other possibility now is that the packet
// is complete(empty packet) or that the method started.
2011-04-18 08:09:35 +00:00
if (isAlphaNumeric(state->buffer.ptr[state->cursor]))
2011-04-15 23:42:36 +00:00
{
2011-04-18 08:09:35 +00:00
state->inContent = 1;
2011-04-17 10:56:24 +00:00
if (state->flags & PSYC_HEADER_ONLY)
return PSYC_HEADER_COMPLETE; // return header finished
else
goto start;
2011-04-15 23:42:36 +00:00
}
2010-02-20 16:40:09 +00:00
2011-04-18 08:09:35 +00:00
if (state->buffer.ptr[state->cursor] == '|')
2010-02-20 16:40:09 +00:00
{
2011-04-18 08:09:35 +00:00
if (state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
2010-02-20 16:40:09 +00:00
{
2011-04-15 23:42:36 +00:00
state->cursor=startc; // set to start value
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT; // return insufficient
2010-02-20 16:40:09 +00:00
}
2011-04-18 08:09:35 +00:00
if (state->buffer.ptr[state->cursor]=='\n')
2010-02-20 16:40:09 +00:00
{
2011-04-15 23:42:36 +00:00
++(state->cursor);
2011-04-18 08:09:35 +00:00
state->inContent = 0;
2011-04-17 10:56:24 +00:00
return PSYC_COMPLETE; // return packet finished
2010-02-20 16:40:09 +00:00
}
}
return -6; // report error
2011-04-17 10:05:14 +00:00
}
else // it is a glyph, so a variable name starts here
2010-02-20 16:40:09 +00:00
{
2011-04-18 08:09:35 +00:00
/***************************************************
* * * * * * * Routing Variable Start * * * * * * *
**************************************************/
*modifier = *(state->buffer.ptr+state->cursor);
if (state->buffer.length <= ++(state->cursor))
{
state->cursor = startc; // rewind to start of line
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT; // return insufficient
}
name->ptr = state->buffer.ptr + state->cursor;
2011-04-17 11:59:07 +00:00
name->length = 1;
2010-02-20 16:40:09 +00:00
}
2011-04-18 08:09:35 +00:00
} // endif inContent=0
2011-04-15 23:42:36 +00:00
2010-02-20 16:40:09 +00:00
char method=0;
2011-04-17 11:59:07 +00:00
/* each line of the header starts with a glyph.
* iE :_name, -_name +_name etc, so just test if
* the first char is a glyph. */
2010-02-20 16:40:09 +00:00
/* in the body, the same applies, only that the
* method does not start with a glyph.*/
2011-04-18 08:09:35 +00:00
if(1==state->inContent)
2010-02-20 16:40:09 +00:00
{
2011-04-17 11:59:07 +00:00
if(!isGlyph(state->buffer.ptr[state->cursor]))
2010-02-20 16:40:09 +00:00
{
2011-04-17 11:59:07 +00:00
if(!isAlphaNumeric(state->buffer.ptr[state->cursor]) && state->buffer.ptr[state->cursor] != '_')
2010-02-20 16:40:09 +00:00
{
2011-04-17 11:59:07 +00:00
// the body rule is optional, which means
// that now also just |\n can follow.
if(state->buffer.ptr[state->cursor] == '|')
2010-02-20 16:40:09 +00:00
{
2011-04-18 08:09:35 +00:00
if(state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
2011-04-17 11:59:07 +00:00
{
state->cursor=startc; // set to start value
return PSYC_INSUFFICIENT; // return insufficient
}
2010-02-20 16:40:09 +00:00
2011-04-17 11:59:07 +00:00
if(state->buffer.ptr[state->cursor]=='\n')
{
++(state->cursor);
2011-04-18 08:09:35 +00:00
state->inContent = 0;
2011-04-17 11:59:07 +00:00
return PSYC_COMPLETE; // return packet finished
}
2010-02-20 16:40:09 +00:00
}
2011-04-17 11:59:07 +00:00
return -5; // report error
}
else
{
name->ptr = state->buffer.ptr+state->cursor;
name->length=1;
method=1;
2010-02-20 16:40:09 +00:00
}
}
else
{
2011-04-17 11:59:07 +00:00
*modifier = *(state->buffer.ptr+state->cursor);
if (state->buffer.length <= ++(state->cursor))
{
state->cursor = startc; // rewind
return PSYC_INSUFFICIENT; // return insufficient
}
2011-04-15 23:42:36 +00:00
name->ptr = state->buffer.ptr+state->cursor;
name->length=1;
}
2010-02-20 16:40:09 +00:00
}
/* validate the incremented cursor */
2011-04-15 23:42:36 +00:00
if(state->buffer.length <= ++(state->cursor))
2010-02-20 16:40:09 +00:00
{
2011-04-15 23:42:36 +00:00
state->cursor=startc;
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT;
2010-02-20 16:40:09 +00:00
}
/* what follows is the name. At least one char.
* allowed is alphanumeric and _ */
// first char must exist.
2011-04-15 23:42:36 +00:00
if(!isAlphaNumeric(state->buffer.ptr[state->cursor]) // is it not alphanum
&& state->buffer.ptr[state->cursor] != '_') // AND not '_'. must be invalid then
2010-02-20 16:40:09 +00:00
return -1; // return parser error.
2011-04-15 23:42:36 +00:00
name->length+=1;
2010-02-20 16:40:09 +00:00
/* now checking how long the name of the variable is. */
unsigned int i=0;
while(1)
{
2011-04-18 08:09:35 +00:00
if(state->buffer.length<= ++(state->cursor)) // incremented cursor inside length?
2010-02-20 16:40:09 +00:00
{
2011-04-15 23:42:36 +00:00
state->cursor=startc; // set to start value
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT; // return insufficient
2010-02-20 16:40:09 +00:00
}
// same as bevore
2011-04-15 23:42:36 +00:00
if(!isAlphaNumeric(state->buffer.ptr[state->cursor]) &&
state->buffer.ptr[state->cursor] != '_')
2010-02-20 16:40:09 +00:00
break; // not valid? then stop the loop right here
2011-04-15 23:42:36 +00:00
++(name->length); // was a valid char, increase length
2010-02-20 16:40:09 +00:00
}
/* we now parsed the variable name successfully
* after the name either a \n or a \t follows.
*
2011-04-17 10:05:14 +00:00
* for the method, the data starts after an \n
2010-02-20 16:40:09 +00:00
* so checking for \n too here
* We dont check if cursor inside length, because
2010-02-20 18:50:10 +00:00
* the last loop iteration did that already.
*/
2011-04-15 23:42:36 +00:00
if(state->buffer.ptr[state->cursor] == '\t' || state->buffer.ptr[state->cursor] == '\n') // && method==1))
2010-02-20 16:40:09 +00:00
{
2011-04-17 10:05:14 +00:00
/* after the \t the data follows, which is
* anything but \n. data can be of length 0
2010-02-20 16:40:09 +00:00
*
2011-04-17 10:05:14 +00:00
* for the method: after the \n data follows,
2010-02-20 16:40:09 +00:00
* which is anything but \n|\n
*
2011-04-17 10:05:14 +00:00
* but data is optional, so we first check
* here if data follows at all.
2010-02-20 22:06:33 +00:00
*
2011-04-17 10:05:14 +00:00
* arg-data=value. we set value here so it
2010-02-20 16:40:09 +00:00
* points to a valid range and so we point
2011-04-17 10:05:14 +00:00
* to the first potential arg-data byte.
* If there is no arg-data, we still have
2010-02-20 16:40:09 +00:00
* the length attribute on 0. */
2011-04-15 23:42:36 +00:00
if((method == 0 && state->buffer.ptr[state->cursor] == '\n') /* emptyvar */ ||
(method == 1 && state->cursor+2 < state->buffer.length &&
state->buffer.ptr[state->cursor+1] == '|' &&
2011-04-17 10:05:14 +00:00
state->buffer.ptr[state->cursor+2] == '\n') /*no data */ )
2010-02-20 16:40:09 +00:00
{
2011-04-15 23:42:36 +00:00
value->ptr=state->buffer.ptr+state->cursor;
value->length=0;
2010-02-20 22:06:33 +00:00
}
else
2010-02-20 18:50:10 +00:00
{
2011-04-15 23:42:36 +00:00
value->ptr=state->buffer.ptr+state->cursor+1;
2011-04-18 08:09:35 +00:00
if (0 != state->contentLength) // we know the length of the packet
{
2011-04-17 10:05:14 +00:00
// is the packet in the buffer?
2011-04-18 08:09:35 +00:00
if (value->ptr + state->contentLength + 3 > state->buffer.ptr + state->buffer.length)
2011-04-17 10:05:14 +00:00
{ // no
value->length = state->buffer.length - state->cursor;
2011-04-18 11:27:48 +00:00
//*expectedBytes = state->contentLength - value->length;
2011-04-17 10:05:14 +00:00
}
else // yes, the packet is complete in the buffer.
{
value->length= state->buffer.length - state->cursor -3;
2011-04-18 11:27:48 +00:00
//*expectedBytes = 0;
2011-04-17 10:05:14 +00:00
}
2011-04-15 23:42:36 +00:00
}
else // else search for the terminator
{
2011-04-15 23:42:36 +00:00
value->length=0;
while (1)
2010-02-20 18:50:10 +00:00
{
2011-04-18 08:09:35 +00:00
if(state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
2010-02-20 18:50:10 +00:00
{
2011-04-15 23:42:36 +00:00
state->cursor=startc; // set to start value
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT ; // return insufficient
2010-02-20 18:50:10 +00:00
}
2011-04-15 23:42:36 +00:00
if(0 == method && state->buffer.ptr[state->cursor] == '\n')
2010-02-20 21:18:39 +00:00
break;
2011-04-15 23:42:36 +00:00
if(1 == method && state->buffer.ptr[state->cursor] == '\n')
2010-02-20 21:18:39 +00:00
{
2011-04-18 08:09:35 +00:00
if(state->buffer.length<=(state->cursor)+2) // incremented cursor inside length?
2010-02-20 21:18:39 +00:00
{
2011-04-15 23:42:36 +00:00
state->cursor=startc; // set to start value
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT; // return insufficient
2010-02-20 21:18:39 +00:00
}
2011-04-15 23:42:36 +00:00
if(state->buffer.ptr[state->cursor+1] == '|')
if(state->buffer.ptr[state->cursor+2] == '\n')
2010-02-20 22:06:33 +00:00
{
/* packet finishes here */
2011-04-15 23:42:36 +00:00
state->cursor+=3;
2011-04-18 08:09:35 +00:00
state->inContent = 0;
2011-04-17 10:56:24 +00:00
return PSYC_COMPLETE;
2010-02-20 22:06:33 +00:00
}
2010-02-20 18:50:10 +00:00
}
2011-04-15 23:42:36 +00:00
++(value->length);
2010-02-20 22:06:33 +00:00
}
}
2010-02-20 16:40:09 +00:00
}
2011-04-17 10:05:14 +00:00
}
2011-04-18 08:09:35 +00:00
else if(state->inContent == 1 && method==0 && state->buffer.ptr[state->cursor] == ' ') // oi, its a binary var!
2010-02-20 19:31:22 +00:00
{ // after SP the length follows.
2011-04-18 08:09:35 +00:00
if(state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
{
state->cursor=startc; // set to start value
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT; // return insufficient
}
2011-04-17 12:22:01 +00:00
while(isNumeric(state->buffer.ptr[state->cursor]))
2010-02-20 19:31:22 +00:00
{
2011-04-18 08:09:35 +00:00
value->length = 10 * value->length + state->buffer.ptr[state->cursor] - '0';
2011-04-18 08:09:35 +00:00
if(state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
2010-02-20 19:31:22 +00:00
{
2011-04-15 23:42:36 +00:00
state->cursor=startc; // set to start value
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT; // return insufficient
2010-02-20 19:31:22 +00:00
}
2011-04-15 23:42:36 +00:00
}
// after the length a TAB follows
2011-04-15 23:42:36 +00:00
if (state->buffer.ptr[state->cursor] != '\t')
2011-04-18 08:09:35 +00:00
return PSYC_ERROR_EXPECTED_TAB;
binaryArg:
if(state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
{
state->valueRemaining = value->length - state->cursor;
state->cursor=0;
value->length = 0;
value->ptr = state->buffer.ptr;
return PSYC_ENTITY_INCOMPLETE;
}
2010-02-20 21:18:39 +00:00
// is the length still in this buffer?
2011-04-18 08:09:35 +00:00
if(state->buffer.length <= state->cursor+value->length+1 )
2010-02-20 19:31:22 +00:00
{
2011-04-18 08:09:35 +00:00
state->valueRemaining = value->length - state->cursor;
state->cursor=0;
value->ptr = state->buffer.ptr + state->cursor;
value->length = state->buffer.length - state->cursor;
return PSYC_ENTITY_INCOMPLETE;
2010-02-20 19:31:22 +00:00
}
2011-04-18 08:09:35 +00:00
value->ptr = state->buffer.ptr + state->cursor;
state->cursor += value->length;
state->valueRemaining = 0;
}
else
2010-02-20 19:31:22 +00:00
return -8;
2010-02-20 16:40:09 +00:00
/* if there was a \t, then we parsed up until the
2011-04-17 11:59:07 +00:00
* \n char from the simple-arg rule ( \t arg-data \n )
2010-02-20 16:40:09 +00:00
*
* Now, if there would be no \t, we still would be at
* the point where a \n must follow.
*
* So, just checking \n here will cover both cases of
* the alternative ( simple-arg / \n ) from rule
* routing-modifier
*
* again, the loop has already validated the cursors
* position*/
2011-04-15 23:42:36 +00:00
if(state->buffer.ptr[state->cursor] != '\n')
2010-02-20 16:40:09 +00:00
return -2; // return parser error.
/* if a \n follows now, the an body is attached.
* if not, a |\n must follow */
2011-04-18 08:09:35 +00:00
if(state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
2010-02-20 16:40:09 +00:00
{
2011-04-15 23:42:36 +00:00
state->cursor=startc; // set to start value
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT; // return insufficient
2010-02-20 16:40:09 +00:00
}
2011-04-18 08:09:35 +00:00
if(0 == state->inContent && state->buffer.ptr[state->cursor] == '\n')
2010-02-20 16:40:09 +00:00
{
2011-04-15 23:42:36 +00:00
state->cursor+=1;
2011-04-18 08:09:35 +00:00
state->inContent = 1;
2011-04-17 11:59:07 +00:00
2011-04-17 12:22:01 +00:00
return PSYC_ROUTING; // return header finished
2010-02-20 16:40:09 +00:00
}
2011-04-15 23:42:36 +00:00
if(state->buffer.ptr[state->cursor] != '|') // no pipe, then only line complete, not the packet.
2011-04-17 10:05:14 +00:00
{
2011-04-18 08:09:35 +00:00
if (state->inContent == 0)
2011-04-17 10:05:14 +00:00
return PSYC_ROUTING;
else
return PSYC_ENTITY;
}
2011-04-18 08:09:35 +00:00
if(state->buffer.length<=++(state->cursor)) // incremented cursor inside length?
2010-02-20 16:40:09 +00:00
{
2011-04-15 23:42:36 +00:00
state->cursor=startc; // set to start value
2011-04-17 10:05:14 +00:00
return PSYC_INSUFFICIENT; // return insufficient
2010-02-20 16:40:09 +00:00
}
2011-04-15 23:42:36 +00:00
if(state->buffer.ptr[state->cursor] != '\n')
2010-02-20 16:40:09 +00:00
return -4;
2011-04-15 23:42:36 +00:00
state->cursor+=1;
2011-04-18 08:09:35 +00:00
state->inContent = 0;
2011-04-17 10:56:24 +00:00
return PSYC_COMPLETE; // packet is complete
2010-02-20 16:40:09 +00:00
}