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
e9664de2ad
53 changed files with 670 additions and 150 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -6,7 +6,9 @@ src/match
|
|||
test/testMatch
|
||||
test/testParser
|
||||
test/testRender
|
||||
test/testServer
|
||||
test/isRoutingVar
|
||||
test/getVarType
|
||||
|
||||
.config
|
||||
~$*
|
||||
|
|
2
Doxyfile
2
Doxyfile
|
@ -875,7 +875,7 @@ HTML_FOOTER =
|
|||
# the style sheet file to the HTML output directory, so don't put your own
|
||||
# stylesheet in the HTML output directory as well, or it will be erased!
|
||||
|
||||
HTML_STYLESHEET = doc/psyc.css
|
||||
#HTML_STYLESHEET = doc/psyc.css
|
||||
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
|
||||
# Doxygen will adjust the colors in the stylesheet and background images
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#projectlogo img {
|
||||
height: 50px;
|
||||
}
|
|
@ -8,13 +8,13 @@
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg4025"
|
||||
version="1.1"
|
||||
width="715.59717"
|
||||
height="145.17674"
|
||||
width="234"
|
||||
height="50"
|
||||
xml:space="preserve"><g
|
||||
id="g4035"
|
||||
transform="matrix(1.25,0,0,-1.25,-0.93316256,156.86281)"><g
|
||||
transform="matrix(1,0,0,-1,2,52)"><g
|
||||
id="g4037"
|
||||
transform="scale(0.1,0.1)"><path
|
||||
transform="scale(0.04,0.04)"><path
|
||||
d="m 223.621,1244.61 5292.459,0 c 113.7,0 205.87,-92.17 205.87,-205.86 l 0,-729.109 c 0,-113.696 -92.17,-205.86 -205.87,-205.86 l -5292.459,0 c -113.695,0 -205.8632,92.164 -205.8632,205.86 l 0,729.109 c 0,113.69 92.1682,205.86 205.8632,205.86"
|
||||
style="fill:#e45e3b;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path4039" /><path
|
||||
|
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
@ -107,6 +107,12 @@ typedef struct
|
|||
const char *ptr;
|
||||
} psycString;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
psycString name;
|
||||
int value;
|
||||
} psycMatchVar;
|
||||
|
||||
/**
|
||||
* Shortcut for creating a psycString.
|
||||
*
|
||||
|
@ -146,13 +152,13 @@ typedef struct
|
|||
/* intermediate struct for a PSYC packet */
|
||||
typedef struct
|
||||
{
|
||||
psycHeader routing; ///< Routing header.
|
||||
psycHeader entity; ///< Entitiy header.
|
||||
psycHeader routing; ///< Routing header.
|
||||
psycHeader entity; ///< Entity header.
|
||||
psycString method;
|
||||
psycString data;
|
||||
size_t routingLength; ///< Length of routing part.
|
||||
size_t contentLength; ///< Length of content part.
|
||||
size_t length; ///< Total length of packet.
|
||||
size_t routingLength; ///< Length of routing part.
|
||||
size_t contentLength; ///< Length of content part.
|
||||
size_t length; ///< Total length of packet.
|
||||
psycPacketFlag flag;
|
||||
} psycPacket;
|
||||
|
||||
|
@ -204,8 +210,7 @@ inline psycPacket psyc_newPacket2(psycModifier *routing, size_t routinglen,
|
|||
|
||||
/// Routing vars in alphabetical order.
|
||||
extern const psycString PSYC_routingVars[];
|
||||
/// Number of routing vars.
|
||||
extern const size_t PSYC_routingVarsNum;
|
||||
extern const psycMatchVar PSYC_varTypes[];
|
||||
|
||||
/**
|
||||
* Get the type of variable name.
|
||||
|
@ -215,7 +220,7 @@ psycBool psyc_isRoutingVar(const char *name, size_t len);
|
|||
/**
|
||||
* Get the type of variable name.
|
||||
*/
|
||||
psycType psyc_getVarType(char *name, size_t len);
|
||||
psycType psyc_getVarType(const char *name, size_t len);
|
||||
|
||||
/**
|
||||
* Checks if long keyword string inherits from short keyword string.
|
||||
|
@ -238,8 +243,8 @@ int psyc_matches(char *sho, size_t slen,
|
|||
* number of bytes written. 0 is a legal return value. Should the
|
||||
* callback return -1, psyc_text leaves the original template text as is.
|
||||
*/
|
||||
typedef int (*psyctextCB)(uint8_t *match, size_t mlen,
|
||||
uint8_t **buffer, size_t *blen);
|
||||
typedef int (*psyctextCB)(char *match, size_t mlen,
|
||||
char **buffer, size_t *blen);
|
||||
|
||||
/**
|
||||
* Fills out text templates by asking a callback for content.
|
||||
|
@ -254,8 +259,8 @@ typedef int (*psyctextCB)(uint8_t *match, size_t mlen,
|
|||
*
|
||||
* See also http://about.psyc.eu/psyctext
|
||||
*/
|
||||
int psyc_text(uint8_t *template, size_t tlen,
|
||||
uint8_t **buffer, size_t *blen,
|
||||
int psyc_text(char *template, size_t tlen,
|
||||
char **buffer, size_t *blen,
|
||||
psyctextCB lookupValue,
|
||||
char *braceOpen, char *braceClose);
|
||||
|
||||
|
|
|
@ -30,11 +30,13 @@ typedef enum
|
|||
*/
|
||||
typedef enum
|
||||
{
|
||||
PSYC_PARSE_ERROR_END = -7,
|
||||
PSYC_PARSE_ERROR_METHOD = -6,
|
||||
PSYC_PARSE_ERROR_VAR_LEN = -5,
|
||||
PSYC_PARSE_ERROR_VAR_TAB = -4,
|
||||
PSYC_PARSE_ERROR_VAR_NAME = -3,
|
||||
PSYC_PARSE_ERROR_END = -9,
|
||||
PSYC_PARSE_ERROR_BODY = -8,
|
||||
PSYC_PARSE_ERROR_METHOD = -7,
|
||||
PSYC_PARSE_ERROR_MOD_NL = -6,
|
||||
PSYC_PARSE_ERROR_MOD_LEN = -5,
|
||||
PSYC_PARSE_ERROR_MOD_TAB = -4,
|
||||
PSYC_PARSE_ERROR_MOD_NAME = -3,
|
||||
PSYC_PARSE_ERROR_LENGTH = -2,
|
||||
PSYC_PARSE_ERROR = -1,
|
||||
PSYC_PARSE_SUCCESS = 0,
|
||||
|
@ -42,13 +44,13 @@ typedef enum
|
|||
/// Fill another buffer and concatenate it with the end of the current buffer,
|
||||
/// from the cursor position to the end.
|
||||
PSYC_PARSE_INSUFFICIENT = 1,
|
||||
/// Routing variable parsing done.
|
||||
/// Routing modifier parsing done.
|
||||
/// Operator, name & value contains the respective parts.
|
||||
PSYC_PARSE_ROUTING = 2,
|
||||
/// Entity variable parsing done.
|
||||
/// Entity modifier parsing done.
|
||||
/// Operator, name & value contains the respective parts.
|
||||
PSYC_PARSE_ENTITY = 3,
|
||||
/// Entity variable parsing is incomplete.
|
||||
/// Entity modifier parsing is incomplete.
|
||||
/// Operator & name are complete, value is incomplete.
|
||||
PSYC_PARSE_ENTITY_INCOMPLETE = 4,
|
||||
/// Body parsing done, name contains method, value contains body.
|
||||
|
@ -91,6 +93,7 @@ typedef struct
|
|||
uint8_t flags; ///< flags for the parser, see psycParseFlag
|
||||
psycPart part; ///< part of the packet being parsed currently
|
||||
|
||||
size_t routingLength; ///< length of routing part parsed so far
|
||||
size_t contentParsed; ///< number of bytes parsed from the content so far
|
||||
size_t contentLength; ///< expected length of the content
|
||||
psycBool contentLengthFound; ///< is there a length given for this packet?
|
||||
|
|
|
@ -7,8 +7,9 @@ int psyc_inherits(char* sho, size_t slen,
|
|||
// the length.. but we would be faster here if we expected the callee
|
||||
// to always use the PSYC_C2ARG() macro instead. additionally, the
|
||||
// empty string would then be fully supported (in case you want that)
|
||||
if (!slen) slen = strlen(sho);
|
||||
if (!llen) llen = strlen(lon);
|
||||
// Disabled this, let's use that macro rather.
|
||||
//if (!slen) slen = strlen(sho);
|
||||
//if (!llen) llen = strlen(lon);
|
||||
|
||||
if (slen == 0 || *sho != '_' ||
|
||||
llen == 0 || *lon != '_') {
|
||||
|
@ -45,8 +46,8 @@ int psyc_matches(char* sho, size_t slen,
|
|||
char* lon, size_t llen) {
|
||||
char *s, *l, *se, *le;
|
||||
|
||||
if (!slen) slen = strlen(sho);
|
||||
if (!llen) llen = strlen(lon);
|
||||
//if (!slen) slen = strlen(sho);
|
||||
//if (!llen) llen = strlen(lon);
|
||||
|
||||
if (slen == 0 || *sho != '_' ||
|
||||
llen == 0 || *lon != '_') {
|
||||
|
|
11
src/packet.c
11
src/packet.c
|
@ -146,9 +146,14 @@ inline size_t psyc_setPacketLength(psycPacket *p)
|
|||
p->contentLength += p->data.length + 1; // data\n
|
||||
|
||||
// set total length: routing-header \n content |\n
|
||||
p->length = p->routingLength + 1 + p->contentLength + sizeof(PSYC_PACKET_DELIMITER) - 2;
|
||||
if (p->flag == PSYC_PACKET_NEED_LENGTH) // add length of length if needed
|
||||
p->length += log10((double)p->data.length) + 1;
|
||||
p->length = p->routingLength + p->contentLength + sizeof(PSYC_PACKET_DELIMITER) - 2;
|
||||
if (p->contentLength > 0)
|
||||
{
|
||||
p->contentLength--; // subtract the \n from the delimiter, as that doesn't belong to the content part
|
||||
p->length++; // add \n at the start of the content part
|
||||
if (p->flag == PSYC_PACKET_NEED_LENGTH) // add length of length if needed
|
||||
p->length += log10((double)p->data.length) + 1;
|
||||
}
|
||||
|
||||
return p->length;
|
||||
}
|
||||
|
|
116
src/parser.c
116
src/parser.c
|
@ -133,13 +133,15 @@ inline psycParseRC psyc_parseBinaryValue(psycParseState* state, psycString* valu
|
|||
if (state->cursor + remaining > state->buffer.length) // is the length larger than this buffer?
|
||||
{
|
||||
value->length = state->buffer.length - state->cursor;
|
||||
state->cursor += value->length;
|
||||
*parsed += value->length;
|
||||
return PSYC_PARSE_INCOMPLETE;
|
||||
}
|
||||
|
||||
value->length += remaining;
|
||||
value->length = remaining;
|
||||
state->cursor += remaining;
|
||||
*parsed += value->length;
|
||||
*parsed += remaining;
|
||||
assert(*parsed == *length);
|
||||
|
||||
return PSYC_PARSE_COMPLETE;
|
||||
}
|
||||
|
@ -153,9 +155,13 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
|||
*oper = *(state->buffer.ptr + state->cursor);
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
|
||||
if (psyc_parseName(state, name) != PSYC_PARSE_SUCCESS)
|
||||
return PSYC_PARSE_ERROR_VAR_NAME;
|
||||
psycParseRC ret = psyc_parseName(state, name);
|
||||
if (ret == PSYC_PARSE_ERROR)
|
||||
return PSYC_PARSE_ERROR_MOD_NAME;
|
||||
else if (ret != PSYC_PARSE_SUCCESS)
|
||||
return ret;
|
||||
|
||||
size_t length = 0;
|
||||
value->length = 0;
|
||||
state->valueLength = 0;
|
||||
state->valueParsed = 0;
|
||||
|
@ -170,25 +176,26 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
|||
{
|
||||
do
|
||||
{
|
||||
state->valueLength = 10 * state->valueLength + state->buffer.ptr[state->cursor] - '0';
|
||||
length = 10 * length + state->buffer.ptr[state->cursor] - '0';
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
}
|
||||
while (isNumeric(state->buffer.ptr[state->cursor]));
|
||||
state->valueLength = length;
|
||||
}
|
||||
else
|
||||
return PSYC_PARSE_ERROR_VAR_LEN;
|
||||
return PSYC_PARSE_ERROR_MOD_LEN;
|
||||
|
||||
// After the length a TAB follows.
|
||||
if (state->buffer.ptr[state->cursor] != '\t')
|
||||
return PSYC_PARSE_ERROR_VAR_TAB;
|
||||
return PSYC_PARSE_ERROR_MOD_TAB;
|
||||
|
||||
if (state->buffer.length <= ++(state->cursor)) // Incremented cursor inside length?
|
||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
if (++(state->cursor) >= state->buffer.length)
|
||||
return PSYC_PARSE_INCOMPLETE;
|
||||
|
||||
if (psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed)) == PSYC_PARSE_INCOMPLETE)
|
||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
|
||||
if (ret == PSYC_PARSE_INCOMPLETE)
|
||||
return ret;
|
||||
|
||||
state->cursor++;
|
||||
return PSYC_PARSE_SUCCESS;
|
||||
}
|
||||
else if (state->buffer.ptr[state->cursor] == '\t') // simple arg
|
||||
|
@ -201,11 +208,11 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
|||
value->length++;
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
}
|
||||
state->cursor++;
|
||||
|
||||
return PSYC_PARSE_SUCCESS;
|
||||
}
|
||||
else
|
||||
return PSYC_PARSE_ERROR_VAR_TAB;
|
||||
return PSYC_PARSE_ERROR_MOD_TAB;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,7 +221,7 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
|
|||
*/
|
||||
psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psycString* value)
|
||||
{
|
||||
int ret; // a return value
|
||||
psycParseRC ret; // a return value
|
||||
size_t pos; // a cursor position
|
||||
|
||||
// Start position of the current line in the buffer
|
||||
|
@ -230,6 +237,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
case PSYC_PART_RESET: // New packet starts here, reset state.
|
||||
state->valueParsed = 0;
|
||||
state->valueLength = 0;
|
||||
state->routingLength = 0;
|
||||
state->contentParsed = 0;
|
||||
state->contentLength = 0;
|
||||
state->contentLengthFound = 0;
|
||||
|
@ -237,17 +245,27 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
// fall thru
|
||||
|
||||
case PSYC_PART_ROUTING:
|
||||
pos = state->cursor;
|
||||
if (state->routingLength > 0)
|
||||
{
|
||||
if (state->buffer.ptr[state->cursor] != '\n')
|
||||
return PSYC_PARSE_ERROR_MOD_NL;
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
}
|
||||
|
||||
// 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_parseModifier(state, oper, name, value);
|
||||
state->routingLength += state->cursor - pos;
|
||||
return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ROUTING : ret;
|
||||
}
|
||||
else // not a glyph
|
||||
{
|
||||
state->part = PSYC_PART_LENGTH;
|
||||
state->startc = state->cursor;
|
||||
// fall thru
|
||||
}
|
||||
|
||||
|
@ -284,8 +302,8 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
goto PSYC_PART_END;
|
||||
}
|
||||
|
||||
state->startc = state->cursor + 1;
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
state->startc = state->cursor;
|
||||
// fall thru
|
||||
|
||||
case PSYC_PART_CONTENT:
|
||||
|
@ -293,7 +311,20 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
if (state->valueParsed < state->valueLength) {
|
||||
ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
|
||||
state->contentParsed += value->length;
|
||||
return ret == PSYC_PARSE_COMPLETE ? PSYC_PARSE_ENTITY : PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
|
||||
if (ret == PSYC_PARSE_INCOMPLETE)
|
||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
|
||||
return PSYC_PARSE_ENTITY;
|
||||
}
|
||||
|
||||
pos = state->cursor;
|
||||
|
||||
if (state->contentParsed > 0)
|
||||
{
|
||||
if (state->buffer.ptr[state->cursor] != '\n')
|
||||
return PSYC_PARSE_ERROR_MOD_NL;
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
}
|
||||
|
||||
// Each line of the header starts with a glyph,
|
||||
|
@ -303,31 +334,45 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
// method does not start with a glyph.
|
||||
if (isGlyph(state->buffer.ptr[state->cursor]))
|
||||
{
|
||||
pos = state->cursor;
|
||||
ret = psyc_parseModifier(state, oper, name, value);
|
||||
state->contentParsed += state->cursor - pos;
|
||||
return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ENTITY : ret;
|
||||
|
||||
if (ret == PSYC_PARSE_INCOMPLETE)
|
||||
return PSYC_PARSE_ENTITY_INCOMPLETE;
|
||||
else if (ret == PSYC_PARSE_SUCCESS)
|
||||
return PSYC_PARSE_ENTITY;
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->part = PSYC_PART_METHOD;
|
||||
state->contentParsed += state->cursor - pos;
|
||||
state->startc = state->cursor;
|
||||
state->part = PSYC_PART_METHOD;
|
||||
// fall thru
|
||||
}
|
||||
|
||||
case PSYC_PART_METHOD:
|
||||
pos = state->cursor;
|
||||
if (psyc_parseName(state, name) == PSYC_PARSE_SUCCESS)
|
||||
ret = psyc_parseName(state, name);
|
||||
|
||||
if (ret == PSYC_PARSE_INSUFFICIENT)
|
||||
return ret;
|
||||
else if (ret == PSYC_PARSE_SUCCESS)
|
||||
{ // the method ends with a \n then the data follows
|
||||
if (state->buffer.ptr[state->cursor] != '\n')
|
||||
return PSYC_PARSE_ERROR_METHOD;
|
||||
|
||||
state->cursor++;
|
||||
state->startc = state->cursor;
|
||||
state->contentParsed += state->cursor - pos;
|
||||
state->part = PSYC_PART_DATA;
|
||||
if (state->cursor >= state->buffer.length)
|
||||
return PSYC_PARSE_INSUFFICIENT;
|
||||
if (state->contentLengthFound)
|
||||
{ // if length was found set start position to the beginning of data
|
||||
state->cursor++;
|
||||
state->startc = state->cursor;
|
||||
state->contentParsed += state->cursor - pos;
|
||||
state->part = PSYC_PART_DATA;
|
||||
}
|
||||
else // otherwise keep it at the beginning of method
|
||||
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
|
||||
|
||||
// fall thru
|
||||
}
|
||||
else // No method, which means the packet should end now.
|
||||
|
@ -343,20 +388,28 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
|
||||
if (state->contentLengthFound) // We know the length of the packet.
|
||||
{
|
||||
if (psyc_parseBinaryValue(state, value, &(state->contentLength), &(state->contentParsed)) == PSYC_PARSE_INCOMPLETE)
|
||||
if (state->contentParsed < state->contentLength &&
|
||||
psyc_parseBinaryValue(state, value, &(state->contentLength), &(state->contentParsed)) == PSYC_PARSE_INCOMPLETE)
|
||||
return PSYC_PARSE_BODY_INCOMPLETE;
|
||||
|
||||
if (state->cursor >= state->buffer.length)
|
||||
return PSYC_PARSE_BODY;
|
||||
|
||||
if (state->buffer.ptr[state->cursor] != '\n')
|
||||
return PSYC_PARSE_ERROR_BODY;
|
||||
|
||||
state->cursor++;
|
||||
state->part = PSYC_PART_END;
|
||||
return PSYC_PARSE_BODY;
|
||||
}
|
||||
else // Search for the terminator.
|
||||
{
|
||||
size_t datac = state->cursor; // start of data
|
||||
while (1)
|
||||
{
|
||||
uint8_t nl = state->buffer.ptr[state->cursor] == '\n';
|
||||
// check for |\n if we're at the start of data or we have found a \n
|
||||
if (state->cursor == state->startc || nl)
|
||||
if (state->cursor == datac || nl)
|
||||
{
|
||||
if (state->cursor+1+nl >= state->buffer.length) // incremented cursor inside length?
|
||||
{
|
||||
|
@ -367,6 +420,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
if (state->buffer.ptr[state->cursor+nl] == '|' &&
|
||||
state->buffer.ptr[state->cursor+1+nl] == '\n') // packet ends here
|
||||
{
|
||||
state->contentParsed += state->cursor - pos;
|
||||
state->cursor += nl;
|
||||
state->part = PSYC_PART_END;
|
||||
return PSYC_PARSE_BODY;
|
||||
|
@ -385,7 +439,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
|
|||
return PSYC_PARSE_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;
|
||||
|
@ -414,7 +468,7 @@ psycParseListRC psyc_parseList(psycParseListState* state, psycString *name, psyc
|
|||
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_PARSE_LIST_ERROR_NAME;
|
||||
|
||||
// First character is either | for text lists, or a number for binary lists
|
||||
|
|
|
@ -76,7 +76,8 @@ psycRenderRC psyc_render(psycPacket *packet, char *buffer, size_t buflen)
|
|||
cur += itoa(packet->contentLength, buffer + cur, 10);
|
||||
}
|
||||
|
||||
buffer[cur++] = '\n'; // start of content part
|
||||
if (packet->entity.lines || packet->method.length || packet->data.length)
|
||||
buffer[cur++] = '\n'; // start of content part if there's content
|
||||
|
||||
// render entity modifiers
|
||||
for (i = 0; i < packet->entity.lines; i++)
|
||||
|
|
|
@ -1,62 +1,83 @@
|
|||
#include <psyc.h>
|
||||
#include <psyc/lib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/// Routing variables in alphabetical order.
|
||||
const psycString PSYC_routingVars[] =
|
||||
|
||||
const psycString psyc_routingVars[] =
|
||||
{
|
||||
PSYC_C2STR("_amount_fragments"),
|
||||
PSYC_C2STR("_context"),
|
||||
//PSYC_C2STR("_count"), // older PSYC
|
||||
PSYC_C2STR("_counter"), // the name for this is supposed to be _count, not _counter
|
||||
PSYC_C2STR("_counter"), // the name for this is supposed to be _count, not _counter
|
||||
PSYC_C2STR("_fragment"),
|
||||
//PSYC_C2STR("_length"), // older PSYC
|
||||
PSYC_C2STR("_source"),
|
||||
PSYC_C2STR("_source_identification"),
|
||||
//PSYC_C2STR("_source_identification"), // older PSYC
|
||||
PSYC_C2STR("_source_identity"),
|
||||
PSYC_C2STR("_source_relay"),
|
||||
PSYC_C2STR("_source_relay_relay"), // until you have a better idea.. is this really in use?
|
||||
PSYC_C2STR("_source_relay_relay"), // until you have a better idea.. is this really in use?
|
||||
PSYC_C2STR("_tag"),
|
||||
PSYC_C2STR("_tag_relay"),
|
||||
//PSYC_C2STR("_tag_reply"), // older PSYC
|
||||
PSYC_C2STR("_target"),
|
||||
PSYC_C2STR("_target_forward"),
|
||||
PSYC_C2STR("_target_relay"),
|
||||
//PSYC_C2STR(19, "_understand_modules"), // older PSYC
|
||||
//PSYC_C2STR(14, "_using_modules"), // older PSYC
|
||||
//PSYC_C2STR("_understand_modules"), // older PSYC
|
||||
//PSYC_C2STR("_using_modules"), // older PSYC
|
||||
};
|
||||
|
||||
const size_t PSYC_routingVarsNum = sizeof(PSYC_routingVars) / sizeof(*PSYC_routingVars);
|
||||
const psycMatchVar psyc_varTypes[] =
|
||||
{
|
||||
{PSYC_C2STR("_amount"), PSYC_TYPE_AMOUNT},
|
||||
{PSYC_C2STR("_color"), PSYC_TYPE_COLOR},
|
||||
{PSYC_C2STR("_date"), PSYC_TYPE_DATE},
|
||||
{PSYC_C2STR("_degree"), PSYC_TYPE_DEGREE},
|
||||
{PSYC_C2STR("_entity"), PSYC_TYPE_ENTITY},
|
||||
{PSYC_C2STR("_flag"), PSYC_TYPE_FLAG},
|
||||
{PSYC_C2STR("_language"), PSYC_TYPE_LANGUAGE},
|
||||
{PSYC_C2STR("_list"), PSYC_TYPE_LIST},
|
||||
{PSYC_C2STR("_nick"), PSYC_TYPE_NICK},
|
||||
{PSYC_C2STR("_page"), PSYC_TYPE_PAGE},
|
||||
{PSYC_C2STR("_uniform"), PSYC_TYPE_UNIFORM},
|
||||
{PSYC_C2STR("_time"), PSYC_TYPE_TIME},
|
||||
};
|
||||
|
||||
const size_t psyc_routingVarsNum = PSYC_NUM_ELEM(psyc_routingVars);
|
||||
const size_t psyc_varTypesNum = PSYC_NUM_ELEM(psyc_varTypes);
|
||||
|
||||
/**
|
||||
* Get the type of variable name.
|
||||
*/
|
||||
psycBool psyc_isRoutingVar(const char *name, size_t len)
|
||||
{
|
||||
//return psyc_matchArray(psyc_routingVars, PSYC_NUM_ELEM(psyc_routingVars), name, len, 0);
|
||||
size_t cursor = 1;
|
||||
int8_t matching[PSYC_routingVarsNum]; // indexes of matching vars
|
||||
memset(&matching, -1, sizeof(matching));
|
||||
uint8_t i, m = 0;
|
||||
int8_t matching[psyc_routingVarsNum]; // indexes of matching vars
|
||||
|
||||
if (len < 2 || name[0] != '_')
|
||||
return PSYC_FALSE;
|
||||
|
||||
// first find the vars with matching length
|
||||
for (i=0; i<PSYC_routingVarsNum; i++)
|
||||
if (len == PSYC_routingVars[i].length)
|
||||
for (i=0; i<psyc_routingVarsNum; i++)
|
||||
if (len == psyc_routingVars[i].length)
|
||||
matching[m++] = i;
|
||||
|
||||
matching[m] = -1; // mark the end of matching indexes
|
||||
|
||||
while (cursor < len && matching[0] >= 0)
|
||||
{
|
||||
for (i = m = 0; i < PSYC_routingVarsNum; i++)
|
||||
for (i = m = 0; i < psyc_routingVarsNum; i++)
|
||||
{
|
||||
if (matching[i] < 0)
|
||||
break;
|
||||
if (PSYC_routingVars[matching[i]].ptr[cursor] == name[cursor])
|
||||
break; // reached the end of possible matches
|
||||
if (psyc_routingVars[matching[i]].ptr[cursor] == name[cursor])
|
||||
matching[m++] = matching[i]; // found a match, update matching indexes
|
||||
else if (PSYC_routingVars[matching[i]].ptr[cursor] > name[cursor])
|
||||
break; // passed the possible matches in alphabetical order
|
||||
else if (psyc_routingVars[matching[i]].ptr[cursor] > name[cursor])
|
||||
break; // passed the possible matches in alphabetical order in the array
|
||||
}
|
||||
|
||||
if (m < PSYC_routingVarsNum)
|
||||
if (m < psyc_routingVarsNum)
|
||||
matching[m] = -1; // mark the end of matching indexes
|
||||
|
||||
cursor++;
|
||||
|
@ -68,7 +89,43 @@ psycBool psyc_isRoutingVar(const char *name, size_t len)
|
|||
/**
|
||||
* Get the type of variable name.
|
||||
*/
|
||||
psycType psyc_getVarType(char *name, size_t len)
|
||||
psycType psyc_getVarType(const char *name, size_t len)
|
||||
{
|
||||
return PSYC_TYPE_UNKNOWN;
|
||||
//return psyc_matchArray(psyc_varTypes, PSYC_NUM_ELEM(psyc_varTypes), name, len, 1);
|
||||
size_t cursor = 1;
|
||||
uint8_t i, m = 0;
|
||||
int8_t matching[psyc_varTypesNum]; // indexes of matching vars
|
||||
|
||||
if (len < 2 || name[0] != '_')
|
||||
return 0;
|
||||
|
||||
// first find the vars with matching length
|
||||
for (i=0; i<psyc_varTypesNum; i++)
|
||||
if (len == psyc_varTypes[i].name.length || (len > psyc_varTypes[i].name.length && name[psyc_varTypes[i].name.length] == '_'))
|
||||
matching[m++] = i;
|
||||
|
||||
matching[m] = -1; // mark the end of matching indexes
|
||||
|
||||
while (cursor < len && matching[0] >= 0)
|
||||
{
|
||||
for (i = m = 0; i < psyc_varTypesNum; i++)
|
||||
{
|
||||
if (matching[i] < 0)
|
||||
break; // reached the end of possible matches
|
||||
if (cursor < psyc_varTypes[matching[i]].name.length && psyc_varTypes[matching[i]].name.ptr[cursor] == name[cursor])
|
||||
matching[m++] = matching[i]; // found a match, update matching indexes
|
||||
else if (cursor == psyc_varTypes[matching[i]].name.length && name[cursor] == '_')
|
||||
return psyc_varTypes[matching[0]].value; // _ after the end of a matching prefix
|
||||
else if (psyc_varTypes[matching[i]].name.ptr[cursor] > name[cursor])
|
||||
break; // passed the possible matches in alphabetical order in the array
|
||||
}
|
||||
|
||||
if (m < psyc_varTypesNum)
|
||||
matching[m] = -1; // mark the end of matching indexes
|
||||
|
||||
cursor++;
|
||||
}
|
||||
|
||||
// return first match if found
|
||||
return matching[0] >= 0 ? psyc_varTypes[matching[0]].value : 0;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,38 @@
|
|||
CFLAGS=-I../include -DDEBUG -g -O0 -Wall
|
||||
LDFLAGS=-L../src
|
||||
LOADLIBES=-lpsyc -lm
|
||||
TARGETS=testParser testMatch testRender isRoutingVar
|
||||
TARGETS=testServer testParser testMatch testRender isRoutingVar getVarType
|
||||
PORT=4440
|
||||
|
||||
all: $(TARGETS)
|
||||
./testRender
|
||||
./testMatch
|
||||
./isRoutingVar
|
||||
./getVarType
|
||||
|
||||
test: $(TARGETS)
|
||||
for f in packets/*; do echo ">> $$f"; ./testParser $$f; done
|
||||
for f in packets/full-* packets/error-*; do echo ">> $$f"; ./testParser $$f; done
|
||||
|
||||
netstart:
|
||||
./testServer $(PORT)
|
||||
|
||||
netstartv:
|
||||
./testServer $(PORT) -v
|
||||
|
||||
nettest:
|
||||
for f in packets/full-*; do echo ">> $$f"; cat $$f | nc localhost $(PORT) | diff -u $$f -; done
|
||||
|
||||
nettesterr:
|
||||
for f in packets/error-*; do echo ">> $$f"; cat $$f | nc localhost $(PORT); done
|
||||
|
||||
splittest:
|
||||
for f in packets/full-*; do echo ">> $$f"; ./splittest.pl $$f $(PORT) | diff -u $$f -; done
|
||||
|
||||
nettestp1:
|
||||
(for f in packets/part-1-p*; do cat $$f; done) | nc localhost $(PORT) | diff -u packets/full-1 -
|
||||
|
||||
nettestp2:
|
||||
(for f in packets/part-1-length-p*; do cat $$f; done) | nc localhost $(PORT) | diff -u packets/full-1-length -
|
||||
|
||||
clean:
|
||||
rm -f $(TARGETS)
|
||||
|
|
21
test/getVarType.c
Normal file
21
test/getVarType.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include <psyc.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include "../include/psyc/lib.h"
|
||||
|
||||
int main() {
|
||||
unless (psyc_getVarType(PSYC_C2ARG("_list"))) return 1;
|
||||
unless (psyc_getVarType(PSYC_C2ARG("_list_foo"))) return 2;
|
||||
unless (psyc_getVarType(PSYC_C2ARG("_color_red"))) return 3;
|
||||
if (psyc_getVarType(PSYC_C2ARG("_last"))) return 4;
|
||||
if (psyc_getVarType(PSYC_C2ARG("_lost_foo"))) return 5;
|
||||
if (psyc_getVarType(PSYC_C2ARG("_colorful"))) return 6;
|
||||
if (psyc_getVarType(PSYC_C2ARG("_foo"))) return 7;
|
||||
if (psyc_getVarType(PSYC_C2ARG("bar"))) return 8;
|
||||
if (psyc_getVarType(PSYC_C2ARG("______"))) return 9;
|
||||
if (psyc_getVarType(PSYC_C2ARG("_"))) return 10;
|
||||
|
||||
puts("psyc_getVarType passed all tests.");
|
||||
return 0; // passed all tests
|
||||
}
|
|
@ -24,14 +24,14 @@ int main() {
|
|||
printf("%s: %d\n", vars[i], psyc_isRoutingVar(vars[i], strlen(vars[i])));
|
||||
}
|
||||
#else
|
||||
unless (psyc_isRoutingVar(PSYC_C2ARG("_source"))) return -1;
|
||||
unless (psyc_isRoutingVar(PSYC_C2ARG("_source_relay"))) return -2;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_source_foo"))) return -3;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_sourcherry"))) return -4;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_sour"))) return -5;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_foo"))) return -6;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("bar"))) return -7;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_"))) return -8;
|
||||
unless (psyc_isRoutingVar(PSYC_C2ARG("_source"))) return 1;
|
||||
unless (psyc_isRoutingVar(PSYC_C2ARG("_source_relay"))) return 2;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_source_foo"))) return 3;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_sourcherry"))) return 4;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_sour"))) return 5;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_foo"))) return 6;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("bar"))) return 7;
|
||||
if (psyc_isRoutingVar(PSYC_C2ARG("_"))) return 8;
|
||||
|
||||
puts("psyc_isRoutingVar passed all tests.");
|
||||
#endif
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
:_source some_source
|
||||
:_length
|
||||
|
||||
_method
|
||||
1234567
|
||||
|
|
||||
|
|
@ -10,4 +10,3 @@ _message_foo_bar
|
|||
ohai there!
|
||||
\o/
|
||||
|
|
||||
|
|
|
@ -17,9 +17,3 @@ _message_foo_bar
|
|||
ohai there!
|
||||
\o/
|
||||
|
|
||||
:_target psyc://foo.bar/~baz
|
||||
|
||||
:_test 123
|
||||
_message_test
|
||||
ohai!
|
||||
|
|
|
@ -10,4 +10,3 @@ _message_foo_bar
|
|||
ohai there!
|
||||
\o/
|
||||
|
|
||||
|
|
|
@ -10,4 +10,3 @@ _message_foo_bar
|
|||
ohai there!
|
||||
\o/
|
||||
|
|
||||
|
|
|
@ -10,4 +10,3 @@ _message_foo_bar
|
|||
ohai there!
|
||||
\o/
|
||||
|
|
||||
|
|
|
@ -16,9 +16,3 @@ _message_foo_bar
|
|||
ohai there!
|
||||
\o/
|
||||
|
|
||||
:_target psyc://foo.bar/~baz
|
||||
|
||||
:_test 123
|
||||
_message_test
|
||||
ohai!
|
||||
|
|
|
@ -18,16 +18,3 @@ _message_foo_bar
|
|||
ohai there!
|
||||
\o/
|
||||
|
|
||||
:_target psyc://foo.bar/~baz
|
||||
|
||||
:_test 123
|
||||
_message_test
|
||||
ohai!
|
||||
|
|
||||
:_target psyc://foo.bar/~baz
|
||||
|
||||
+_list_foo yay
|
||||
-_amount_x 2
|
||||
_notice_test
|
||||
test!
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
|
||||
_request_some_things
|
||||
|
|
||||
|
5
test/packets/full-8-context-enter
Normal file
5
test/packets/full-8-context-enter
Normal file
|
@ -0,0 +1,5 @@
|
|||
:_target psyc://p5B084547.dip.t-dialin.net/@test
|
||||
:_source something
|
||||
|
||||
_request_context_enter
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
:_target psyc://p5B084547.dip.t-dialin.net/@test
|
||||
:_source something
|
||||
|
||||
_request_context_enter
|
||||
|
|
||||
:_target psyc://p5B084547.dip.t-dialin.net/@test
|
||||
|
||||
:_more vars
|
||||
:_bin 6 "1
|
1
test/packets/part-1-length-p1
Symbolic link
1
test/packets/part-1-length-p1
Symbolic link
|
@ -0,0 +1 @@
|
|||
part-1-p1
|
1
test/packets/part-1-length-p2
Symbolic link
1
test/packets/part-1-length-p2
Symbolic link
|
@ -0,0 +1 @@
|
|||
part-1-p2
|
3
test/packets/part-1-length-p3
Normal file
3
test/packets/part-1-length-p3
Normal file
|
@ -0,0 +1,3 @@
|
|||
hu3r2cm
|
||||
85
|
||||
:_foo bar baz
|
1
test/packets/part-1-length-p4
Symbolic link
1
test/packets/part-1-length-p4
Symbolic link
|
@ -0,0 +1 @@
|
|||
part-1-p4
|
1
test/packets/part-1-length-p5
Symbolic link
1
test/packets/part-1-length-p5
Symbolic link
|
@ -0,0 +1 @@
|
|||
part-1-p5
|
1
test/packets/part-1-length-p6
Symbolic link
1
test/packets/part-1-length-p6
Symbolic link
|
@ -0,0 +1 @@
|
|||
part-1-p6
|
1
test/packets/part-1-length-p7
Symbolic link
1
test/packets/part-1-length-p7
Symbolic link
|
@ -0,0 +1 @@
|
|||
part-1-p7
|
1
test/packets/part-1-length-p8
Symbolic link
1
test/packets/part-1-length-p8
Symbolic link
|
@ -0,0 +1 @@
|
|||
part-1-p8
|
1
test/packets/part-1-length-p9
Symbolic link
1
test/packets/part-1-length-p9
Symbolic link
|
@ -0,0 +1 @@
|
|||
part-1-p9
|
2
test/packets/part-1-p1
Normal file
2
test/packets/part-1-p1
Normal file
|
@ -0,0 +1,2 @@
|
|||
:_source psyc://foo/~bar
|
||||
:_tar
|
2
test/packets/part-1-p2
Normal file
2
test/packets/part-1-p2
Normal file
|
@ -0,0 +1,2 @@
|
|||
get psyc://bar/~baz
|
||||
:_tag sch1828
|
3
test/packets/part-1-p3
Normal file
3
test/packets/part-1-p3
Normal file
|
@ -0,0 +1,3 @@
|
|||
hu3r2cm
|
||||
|
||||
:_foo bar baz
|
2
test/packets/part-1-p4
Normal file
2
test/packets/part-1-p4
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
:_abc_def 1
|
1
test/packets/part-1-p5
Normal file
1
test/packets/part-1-p5
Normal file
|
@ -0,0 +1 @@
|
|||
1 foo
|
4
test/packets/part-1-p6
Normal file
4
test/packets/part-1-p6
Normal file
|
@ -0,0 +1,4 @@
|
|||
bar
|
||||
baz
|
||||
:_foo_bar yay
|
||||
_message
|
2
test/packets/part-1-p7
Normal file
2
test/packets/part-1-p7
Normal file
|
@ -0,0 +1,2 @@
|
|||
_foo_bar
|
||||
ohai
|
2
test/packets/part-1-p8
Normal file
2
test/packets/part-1-p8
Normal file
|
@ -0,0 +1,2 @@
|
|||
there!
|
||||
\o/
|
1
test/packets/part-1-p9
Normal file
1
test/packets/part-1-p9
Normal file
|
@ -0,0 +1 @@
|
|||
|
|
28
test/splittest.pl
Executable file
28
test/splittest.pl
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use IO::Socket;
|
||||
$| = 1;
|
||||
|
||||
print "Usage: splittest.pl <packet file> [<port> [<chunk length> [-v]]]\n" and exit unless @ARGV;
|
||||
my $port = $ARGV[1] || 4440;
|
||||
my $length = int($ARGV[2] || 1); $length = 1 if $length < 1;
|
||||
my $verbose = $ARGV[3];
|
||||
|
||||
open FILE, '<', $ARGV[0] or die "$ARGV[0]: $!\n";
|
||||
my $file = ''; $file .= $_ while <FILE>;
|
||||
close FILE;
|
||||
|
||||
my $s = IO::Socket::INET->new(Proto => "tcp", PeerAddr => "localhost", PeerPort => $port) or die "localhost:$port: $!\n";
|
||||
$s->autoflush(1);
|
||||
|
||||
my $c = 0;
|
||||
while ($c < length $file) {
|
||||
my $chunk = substr $file, $c, $length;
|
||||
print "[$chunk]" if $verbose;
|
||||
print $s $chunk;
|
||||
$c += $length;
|
||||
}
|
||||
|
||||
print while <$s>;
|
||||
close $s;
|
|
@ -2,17 +2,17 @@
|
|||
#include "../include/psyc/lib.h"
|
||||
|
||||
int main() {
|
||||
if (psyc_matches("_failure_delivery", 0, "_failure_unsuccessful_delivery_death", 0)) return -1;
|
||||
if (psyc_matches("_failure_trash", 8, "_failure_unsuccessful_delivery_death", 0)) return -2;
|
||||
if (psyc_matches("_unsuccessful", 0, "_failure_unsuccessful_delivery_death", 0)) return -3;
|
||||
unless (psyc_matches("_fail", 0, "_failure_unsuccessful_delivery_death", 0)) return -4;
|
||||
unless (psyc_matches("_truthahn", 0, "_failure_unsuccessful_delivery_death", 0)) return -5;
|
||||
if (psyc_matches(PSYC_C2ARG("_failure_delivery"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 1;
|
||||
if (psyc_matches(PSYC_C2ARG("_failure"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 2;
|
||||
if (psyc_matches(PSYC_C2ARG("_unsuccessful"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 3;
|
||||
unless (psyc_matches(PSYC_C2ARG("_fail"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 4;
|
||||
unless (psyc_matches(PSYC_C2ARG("_truthahn"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 5;
|
||||
|
||||
puts("psyc_matches passed all tests.");
|
||||
|
||||
unless (psyc_inherits("_failure_delivery", 0, "_failure_unsuccessful_delivery_death", 0)) return -11;
|
||||
if (psyc_inherits("_failure_unsuccessful", 0, "_failure_unsuccessful_delivery_death", 0)) return -12;
|
||||
unless (psyc_inherits("_fail", 0, "_failure_unsuccessful_delivery_death", 0)) return -13;
|
||||
unless (psyc_inherits(PSYC_C2ARG("_failure_delivery"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 11;
|
||||
if (psyc_inherits(PSYC_C2ARG("_failure_unsuccessful"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 12;
|
||||
unless (psyc_inherits(PSYC_C2ARG("_fail"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 13;
|
||||
|
||||
puts("psyc_inherits passed all tests.");
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ int main(int argc, char **argv)
|
|||
continue;
|
||||
case PSYC_PARSE_INSUFFICIENT:
|
||||
printf("Insufficient data.\n");
|
||||
return -1;
|
||||
return 1;
|
||||
default:
|
||||
printf("Error while parsing: %i\n", ret);
|
||||
return 1;
|
||||
|
|
|
@ -94,7 +94,7 @@ int main(int argc, char **argv) {
|
|||
=_description_presence\tI'm omnipresent right now\n\
|
||||
_notice_presence\n\
|
||||
|\n", verbose))
|
||||
return -1;
|
||||
return 1;
|
||||
|
||||
if (testList("\
|
||||
:_source psyc://10.100.1000/~ludwig\n\
|
||||
|
@ -106,7 +106,7 @@ qux\n\
|
|||
_test_list\n\
|
||||
list test\n\
|
||||
|\n", verbose))
|
||||
return -2;
|
||||
return 2;
|
||||
|
||||
puts("psyc_render passed all tests.");
|
||||
|
||||
|
|
330
test/testServer.c
Normal file
330
test/testServer.c
Normal file
|
@ -0,0 +1,330 @@
|
|||
/**
|
||||
* libpsyc test server for packet parsing & rendering
|
||||
*
|
||||
* based on selectserver.c from http://beej.us/guide/bgnet/
|
||||
* "The C source code presented in this document is hereby granted to the public domain, and is completely free of any license restriction."
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <psyc/lib.h>
|
||||
#include <psyc/parser.h>
|
||||
#include <psyc/render.h>
|
||||
#include <psyc/syntax.h>
|
||||
|
||||
const size_t RECV_BUF_SIZE = 256;
|
||||
const size_t CONT_BUF_SIZE = 512;
|
||||
const size_t SEND_BUF_SIZE = 1024;
|
||||
const size_t NUM_PARSERS = 100;
|
||||
// max size for routing & entity header
|
||||
const size_t ROUTING_LINES = 16;
|
||||
const size_t ENTITY_LINES = 32;
|
||||
|
||||
// get sockaddr, IPv4 or IPv6:
|
||||
void *get_in_addr(struct sockaddr *sa)
|
||||
{
|
||||
if (sa->sa_family == AF_INET) {
|
||||
return &(((struct sockaddr_in*)sa)->sin_addr);
|
||||
}
|
||||
|
||||
return &(((struct sockaddr_in6*)sa)->sin6_addr);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *port = argc > 1 ? argv[1] : "4440";
|
||||
uint8_t verbose = argc > 2;
|
||||
|
||||
fd_set master; // master file descriptor list
|
||||
fd_set read_fds; // temp file descriptor list for select()
|
||||
int fdmax; // maximum file descriptor number
|
||||
|
||||
int listener; // listening socket descriptor
|
||||
int newfd; // newly accept()ed socket descriptor
|
||||
struct sockaddr_storage remoteaddr; // client address
|
||||
socklen_t addrlen;
|
||||
|
||||
char buf[CONT_BUF_SIZE + RECV_BUF_SIZE]; // cont buf + recv buf: [ ccrrrr]
|
||||
char *recvbuf = buf + CONT_BUF_SIZE; // recv buf: ^^^^
|
||||
char *parsebuf; // parse buf: ^^^^^^
|
||||
char sendbuf[SEND_BUF_SIZE];
|
||||
size_t nbytes, contbytes = 0;
|
||||
|
||||
char remoteIP[INET6_ADDRSTRLEN];
|
||||
|
||||
int yes = 1; // for setsockopt() SO_REUSEADDR, below
|
||||
int i, rv;
|
||||
|
||||
struct addrinfo hints, *ai, *p;
|
||||
|
||||
psycParseState parsers[NUM_PARSERS];
|
||||
psycPacket packets[NUM_PARSERS];
|
||||
psycModifier routing[NUM_PARSERS][ROUTING_LINES];
|
||||
psycModifier entity[NUM_PARSERS][ENTITY_LINES];
|
||||
psycModifier *mod;
|
||||
|
||||
int ret, retl;
|
||||
char oper;
|
||||
psycString name, value, elem;
|
||||
psycString *pname, *pvalue;
|
||||
psycParseListState listState;
|
||||
|
||||
FD_ZERO(&master); // clear the master and temp sets
|
||||
FD_ZERO(&read_fds);
|
||||
|
||||
// get us a socket and bind it
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
if ((rv = getaddrinfo(NULL, port, &hints, &ai)) != 0) {
|
||||
fprintf(stderr, "error: %s\n", gai_strerror(rv));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (p = ai; p != NULL; p = p->ai_next) {
|
||||
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||
if (listener < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// lose the pesky "address already in use" error message
|
||||
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
|
||||
|
||||
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
|
||||
close(listener);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// if we got here, it means we didn't get bound
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "failed to bind\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
freeaddrinfo(ai); // all done with this
|
||||
|
||||
// listen
|
||||
if (listen(listener, 10) == -1) {
|
||||
perror("listen");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
// add the listener to the master set
|
||||
FD_SET(listener, &master);
|
||||
|
||||
// keep track of the biggest file descriptor
|
||||
fdmax = listener; // so far, it's this one
|
||||
|
||||
// main loop
|
||||
for (;;) {
|
||||
read_fds = master; // copy it
|
||||
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
|
||||
perror("select");
|
||||
exit(4);
|
||||
}
|
||||
|
||||
// run through the existing connections looking for data to read
|
||||
for (i = 0; i <= fdmax; i++) {
|
||||
if (FD_ISSET(i, &read_fds)) { // we got one!!
|
||||
if (i == listener) {
|
||||
// handle new connections
|
||||
if (fdmax == NUM_PARSERS - 1)
|
||||
continue; // ignore if there's too many
|
||||
|
||||
addrlen = sizeof remoteaddr;
|
||||
newfd = accept(listener, (struct sockaddr *)&remoteaddr, &addrlen);
|
||||
|
||||
if (newfd == -1) {
|
||||
perror("accept");
|
||||
} else {
|
||||
FD_SET(newfd, &master); // add to master set
|
||||
if (newfd > fdmax) { // keep track of the max
|
||||
fdmax = newfd;
|
||||
}
|
||||
|
||||
// reset parser state & packet
|
||||
psyc_initParseState(&parsers[newfd]);
|
||||
memset(&packets[newfd], 0, sizeof(psycPacket));
|
||||
memset(&routing[newfd], 0, sizeof(psycModifier) * ROUTING_LINES);
|
||||
memset(&entity[newfd], 0, sizeof(psycModifier) * ENTITY_LINES);
|
||||
packets[newfd].routing.modifiers = routing[newfd];
|
||||
packets[newfd].entity.modifiers = entity[newfd];
|
||||
|
||||
printf("# New connection from %s on socket %d\n",
|
||||
inet_ntop(remoteaddr.ss_family,
|
||||
get_in_addr((struct sockaddr*)&remoteaddr),
|
||||
remoteIP, INET6_ADDRSTRLEN),
|
||||
newfd);
|
||||
}
|
||||
} else {
|
||||
// handle data from a client
|
||||
if ((nbytes = recv(i, recvbuf, RECV_BUF_SIZE, 0)) <= 0) {
|
||||
// got error or connection closed by client
|
||||
if (nbytes == 0) {
|
||||
// connection closed
|
||||
printf("socket %d hung up\n", i);
|
||||
} else {
|
||||
perror("recv");
|
||||
}
|
||||
close(i); // bye!
|
||||
FD_CLR(i, &master); // remove from master set
|
||||
} else {
|
||||
// we got some data from a client
|
||||
parsebuf = recvbuf - contbytes;
|
||||
psyc_nextParseBuffer(&parsers[i], psyc_newString(parsebuf, contbytes + nbytes));
|
||||
contbytes = 0;
|
||||
oper = 0;
|
||||
name.length = 0;
|
||||
value.length = 0;
|
||||
|
||||
do {
|
||||
ret = psyc_parse(&parsers[i], &oper, &name, &value);
|
||||
switch (ret) {
|
||||
case PSYC_PARSE_ROUTING:
|
||||
assert(packets[i].routing.lines < ROUTING_LINES);
|
||||
mod = &(packets[i].routing.modifiers[packets[i].routing.lines]);
|
||||
pname = &mod->name;
|
||||
pvalue = &mod->value;
|
||||
mod->flag = PSYC_MODIFIER_ROUTING;
|
||||
packets[i].routing.lines++;
|
||||
break;
|
||||
case PSYC_PARSE_ENTITY_INCOMPLETE:
|
||||
case PSYC_PARSE_ENTITY:
|
||||
assert(packets[i].entity.lines < ENTITY_LINES);
|
||||
mod = &(packets[i].entity.modifiers[packets[i].entity.lines]);
|
||||
pname = &mod->name;
|
||||
pvalue = &mod->value;
|
||||
if (ret == PSYC_PARSE_ENTITY) {
|
||||
packets[i].entity.lines++;
|
||||
mod->flag = parsers[i].valueLength ? PSYC_MODIFIER_NEED_LENGTH : PSYC_MODIFIER_NO_LENGTH;
|
||||
}
|
||||
break;
|
||||
case PSYC_PARSE_BODY_INCOMPLETE:
|
||||
case PSYC_PARSE_BODY:
|
||||
pname = &(packets[i].method);
|
||||
pvalue = &(packets[i].data);
|
||||
break;
|
||||
case PSYC_PARSE_COMPLETE:
|
||||
printf("# Done parsing.\n");
|
||||
packets[i].flag = parsers[i].contentLengthFound ? PSYC_PACKET_NEED_LENGTH : PSYC_PACKET_NO_LENGTH;
|
||||
psyc_setPacketLength(&packets[i]);
|
||||
psyc_render(&packets[i], sendbuf, SEND_BUF_SIZE);
|
||||
if (send(i, sendbuf, packets[i].length, 0) == -1) {
|
||||
perror("send");
|
||||
}
|
||||
ret = -1;
|
||||
break;
|
||||
case PSYC_PARSE_INSUFFICIENT:
|
||||
if (verbose)
|
||||
printf("# Insufficient data.\n");
|
||||
contbytes = parsers[i].buffer.length - parsers[i].cursor;
|
||||
if (contbytes > 0) { // copy end of parsebuf before start of recvbuf
|
||||
assert(recvbuf - contbytes >= buf); // make sure it's still in the buffer
|
||||
memcpy(recvbuf - contbytes, parsebuf + parsers[i].cursor, contbytes);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
printf("# Error while parsing: %i\n", ret);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case PSYC_PARSE_ENTITY_INCOMPLETE:
|
||||
case PSYC_PARSE_BODY_INCOMPLETE:
|
||||
ret = 0;
|
||||
case PSYC_PARSE_ENTITY:
|
||||
case PSYC_PARSE_ROUTING:
|
||||
case PSYC_PARSE_BODY:
|
||||
if (oper) {
|
||||
mod->oper = oper;
|
||||
if (verbose)
|
||||
printf("%c", oper);
|
||||
}
|
||||
|
||||
if (name.length) {
|
||||
pname->ptr = malloc(name.length);
|
||||
pname->length = name.length;
|
||||
assert(pname->ptr != NULL);
|
||||
memcpy((void*)pname->ptr, name.ptr, name.length);
|
||||
name.length = 0;
|
||||
if (verbose) {
|
||||
printf("%.*s = ", (int)pname->length, pname->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (value.length) {
|
||||
if (!pvalue->ptr)
|
||||
pvalue->ptr = malloc(parsers[i].valueLength ? parsers[i].valueLength : value.length);
|
||||
assert(pvalue->ptr != NULL);
|
||||
memcpy((void*)pvalue->ptr + pvalue->length, value.ptr, value.length);
|
||||
pvalue->length += value.length;
|
||||
value.length = 0;
|
||||
if (verbose) {
|
||||
printf("%.*s", (int)pvalue->length, pvalue->ptr);
|
||||
if (parsers[i].valueLength > pvalue->length)
|
||||
printf("...");
|
||||
printf("\n");
|
||||
}
|
||||
} else if (verbose) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("\t\t\t\t\t\t\t\t# n:%ld v:%ld c:%ld r:%ld\n", pname->length, pvalue->length, parsers[i].contentParsed, parsers[i].routingLength);
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case PSYC_PARSE_ROUTING:
|
||||
case PSYC_PARSE_ENTITY:
|
||||
if (pname->length >= 5 && memcmp(pname->ptr, "_list", 5) == 0) {
|
||||
if (verbose)
|
||||
printf("## LIST START\n");
|
||||
psyc_initParseListState(&listState);
|
||||
psyc_nextParseListBuffer(&listState, *pvalue);
|
||||
do {
|
||||
retl = psyc_parseList(&listState, pname, pvalue, &elem);
|
||||
switch (retl) {
|
||||
case PSYC_PARSE_LIST_END:
|
||||
retl = 0;
|
||||
case PSYC_PARSE_LIST_ELEM:
|
||||
if (verbose) {
|
||||
printf("|%.*s\n", (int)elem.length, elem.ptr);
|
||||
if (ret == PSYC_PARSE_LIST_END)
|
||||
printf("## LIST END");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("# Error while parsing list: %i\n", ret);
|
||||
ret = retl = -1;
|
||||
}
|
||||
} while (retl > 0);
|
||||
}
|
||||
}
|
||||
} while (ret > 0);
|
||||
if (ret < 0) {
|
||||
printf("# Closing connection: %i\n", i);
|
||||
close(i); // bye!
|
||||
FD_CLR(i, &master); // remove from master set
|
||||
}
|
||||
}
|
||||
} // END handle data from client
|
||||
} // END got new incoming connection
|
||||
} // END looping through file descriptors
|
||||
} // END for(;;)--and you thought it would never end!
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue