1
0
Fork 0
mirror of git://git.psyc.eu/libpsyc synced 2024-08-15 03:19:02 +00:00
This commit is contained in:
tg(x) 2011-11-11 22:18:24 +01:00
parent aee9203df6
commit 1cc58abd0e
31 changed files with 2797 additions and 2759 deletions

View file

@ -1,6 +1,9 @@
.PHONY: doc test bench .PHONY: doc test bench
.NOTPARALLEL: clean .NOTPARALLEL: clean
indent_args = -nbad -bap -bbo -nbc -br -brs -ncdb -cdw -ce -ci4 -cli0 -cs -d0 -di1 \
-nfc1 -nfca -hnl -i4 -ip0 -l80 -lp -npcs -nprs -npsl -saf -sai -saw -nsc -nsob -nss
all: all:
${MAKE} -C src ${MAKE} -C src

View file

@ -15,13 +15,14 @@
// * @subsection step1 Step 1: Opening the box // * @subsection step1 Step 1: Opening the box
#ifndef PSYC_H #ifndef PSYC_H
#define PSYC_H
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#define PSYC_VERSION 1 #define PSYC_VERSION 1
#define PSYC_EPOCH 1440444041 // 2015-08-24 21:20:41 CET (Monday) #define PSYC_EPOCH 1440444041 // 2015-08-24 21:20:41 CET (Monday)
#define PSYC_C2STR(str) (PsycString) {sizeof(str)-1, str} #define PSYC_C2STR(str) (PsycString) {sizeof(str)-1, str}
#define PSYC_C2STRI(str) {sizeof(str)-1, str} #define PSYC_C2STRI(str) {sizeof(str)-1, str}
@ -33,31 +34,28 @@
#define PSYC_NUM_ELEM(a) (sizeof(a) / sizeof(*(a))) #define PSYC_NUM_ELEM(a) (sizeof(a) / sizeof(*(a)))
/// Boolean: true/false, yes/no. /// Boolean: true/false, yes/no.
typedef enum typedef enum {
{ PSYC_FALSE = 0,
PSYC_FALSE = 0, PSYC_TRUE = 1,
PSYC_TRUE = 1, PSYC_NO = 0,
PSYC_NO = 0, PSYC_YES = 1,
PSYC_YES = 1,
} PsycBool; } PsycBool;
/// Return code: OK/error. /// Return code: OK/error.
typedef enum typedef enum {
{ PSYC_OK = 1,
PSYC_OK = 1, PSYC_ERROR = -1,
PSYC_ERROR = -1,
} PsycRC; } PsycRC;
/// PSYC packet parts. /// PSYC packet parts.
typedef enum typedef enum {
{ PSYC_PART_RESET = -1,
PSYC_PART_RESET = -1, PSYC_PART_ROUTING = 0,
PSYC_PART_ROUTING = 0, PSYC_PART_LENGTH = 1,
PSYC_PART_LENGTH = 1, PSYC_PART_CONTENT = 2,
PSYC_PART_CONTENT = 2, PSYC_PART_METHOD = 3,
PSYC_PART_METHOD = 3, PSYC_PART_DATA = 4,
PSYC_PART_DATA = 4, PSYC_PART_END = 5,
PSYC_PART_END = 5,
} PsycPart; } PsycPart;
/** /**
@ -68,31 +66,29 @@ typedef enum
* validity. Other variable types are treated * validity. Other variable types are treated
* as opaque data. * as opaque data.
*/ */
typedef enum typedef enum {
{ PSYC_TYPE_UNKNOWN,
PSYC_TYPE_UNKNOWN, PSYC_TYPE_AMOUNT,
PSYC_TYPE_AMOUNT, PSYC_TYPE_COLOR,
PSYC_TYPE_COLOR, PSYC_TYPE_DATE,
PSYC_TYPE_DATE, PSYC_TYPE_DEGREE,
PSYC_TYPE_DEGREE, PSYC_TYPE_ENTITY,
PSYC_TYPE_ENTITY, PSYC_TYPE_FLAG,
PSYC_TYPE_FLAG, PSYC_TYPE_LANGUAGE,
PSYC_TYPE_LANGUAGE, PSYC_TYPE_LIST,
PSYC_TYPE_LIST, PSYC_TYPE_NICK,
PSYC_TYPE_NICK, PSYC_TYPE_PAGE,
PSYC_TYPE_PAGE, PSYC_TYPE_UNIFORM,
PSYC_TYPE_UNIFORM, PSYC_TYPE_TIME,
PSYC_TYPE_TIME,
} PsycType; } PsycType;
/** /**
* List types. * List types.
* Possible types are text and binary. * Possible types are text and binary.
*/ */
typedef enum typedef enum {
{ PSYC_LIST_TEXT = 1,
PSYC_LIST_TEXT = 1, PSYC_LIST_BINARY = 2,
PSYC_LIST_BINARY = 2,
} PsycListType; } PsycListType;
/** /**
@ -100,37 +96,34 @@ typedef enum
* *
* Contains pointer and length for a buffer. * Contains pointer and length for a buffer.
*/ */
typedef struct typedef struct {
{ /// Length of the data pointed to by ptr
/// Length of the data pointed to by ptr size_t length;
size_t length; /// pointer to the data
/// pointer to the data char *data;
char *data;
} PsycString; } PsycString;
typedef struct typedef struct {
{ PsycString key;
PsycString key; void *value;
void *value;
} PsycDict; } PsycDict;
typedef struct typedef struct {
{ PsycString key;
PsycString key; intptr_t value;
intptr_t value;
} PsycDictInt; } PsycDictInt;
/** /**
* Checks if long keyword string inherits from short keyword string. * Checks if long keyword string inherits from short keyword string.
*/ */
int psyc_inherits (char *sho, size_t slen, int
char *lon, size_t llen); psyc_inherits (char *sho, size_t slen, char *lon, size_t llen);
/** /**
* Checks if short keyword string matches long keyword string. * Checks if short keyword string matches long keyword string.
*/ */
int psyc_matches (char *sho, size_t slen, int
char *lon, size_t llen); psyc_matches (char *sho, size_t slen, char *lon, size_t llen);
/** /**
* Look up value associated with a key in a dictionary. * Look up value associated with a key in a dictionary.
@ -147,25 +140,24 @@ int psyc_matches (char *sho, size_t slen,
* @return The value of the entry if found, or NULL if not found. * @return The value of the entry if found, or NULL if not found.
*/ */
void * psyc_dict_lookup (const PsycDict *dict, size_t size, void *
const char *key, size_t keylen, psyc_dict_lookup (const PsycDict *dict, size_t size,
PsycBool inherit, int8_t *tmp); const char *key, size_t keylen,
PsycBool inherit, int8_t *tmp);
/** /**
* Look up value associated with a key in a dictionary of integers. * Look up value associated with a key in a dictionary of integers.
* @see psyc_dict_lookup * @see psyc_dict_lookup
*/ */
static inline static inline intptr_t
intptr_t psyc_dict_lookup_int (const PsycDictInt *dict, size_t size, psyc_dict_lookup_int (const PsycDictInt * dict, size_t size,
const char *key, size_t keylen, const char *key, size_t keylen,
PsycBool inherit, int8_t *tmp) PsycBool inherit, int8_t *tmp)
{ {
return (intptr_t) psyc_dict_lookup((PsycDict *)dict, size, key, keylen, inherit, tmp); return (intptr_t) psyc_dict_lookup((PsycDict *) dict, size, key, keylen,
inherit, tmp);
} }
#include "psyc/variable.h" #include "psyc/variable.h"
#define PSYC_H
#endif #endif

View file

@ -1,4 +1,5 @@
#ifndef PSYC_PACKET_H #ifndef PSYC_PACKET_H
#define PSYC_PACKET_H
/** /**
* @file psyc/packet.h * @file psyc/packet.h
@ -20,185 +21,182 @@
#include <math.h> #include <math.h>
/** Modifier flags. */ /** Modifier flags. */
typedef enum typedef enum {
{ /// Modifier needs to be checked if it needs length.
/// Modifier needs to be checked if it needs length. PSYC_MODIFIER_CHECK_LENGTH = 0,
PSYC_MODIFIER_CHECK_LENGTH = 0, /// Modifier needs length.
/// Modifier needs length. PSYC_MODIFIER_NEED_LENGTH = 1,
PSYC_MODIFIER_NEED_LENGTH = 1, /// Modifier doesn't need length.
/// Modifier doesn't need length. PSYC_MODIFIER_NO_LENGTH = 2,
PSYC_MODIFIER_NO_LENGTH = 2, /// Routing modifier, which implies that it doesn't need length.
/// Routing modifier, which implies that it doesn't need length. PSYC_MODIFIER_ROUTING = 3,
PSYC_MODIFIER_ROUTING = 3,
} PsycModifierFlag; } PsycModifierFlag;
/** List flags. */ /** List flags. */
typedef enum typedef enum {
{ /// List needs to be checked if it needs length.
/// List needs to be checked if it needs length. PSYC_LIST_CHECK_LENGTH = 0,
PSYC_LIST_CHECK_LENGTH = 0, /// List needs length.
/// List needs length. PSYC_LIST_NEED_LENGTH = 1,
PSYC_LIST_NEED_LENGTH = 1, /// List doesn't need length.
/// List doesn't need length. PSYC_LIST_NO_LENGTH = 2,
PSYC_LIST_NO_LENGTH = 2,
} PsycListFlag; } PsycListFlag;
/** Packet flags. */ /** Packet flags. */
typedef enum typedef enum {
{ /// Packet needs to be checked if it needs content length.
/// Packet needs to be checked if it needs content length. PSYC_PACKET_CHECK_LENGTH = 0,
PSYC_PACKET_CHECK_LENGTH = 0, /// Packet needs content length.
/// Packet needs content length. PSYC_PACKET_NEED_LENGTH = 1,
PSYC_PACKET_NEED_LENGTH = 1, /// Packet doesn't need content length.
/// Packet doesn't need content length. PSYC_PACKET_NO_LENGTH = 2,
PSYC_PACKET_NO_LENGTH = 2,
} PsycPacketFlag; } PsycPacketFlag;
typedef enum typedef enum {
{ PSYC_OPERATOR_SET = ':',
PSYC_OPERATOR_SET = ':', PSYC_OPERATOR_ASSIGN = '=',
PSYC_OPERATOR_ASSIGN = '=', PSYC_OPERATOR_AUGMENT = '+',
PSYC_OPERATOR_AUGMENT = '+', PSYC_OPERATOR_DIMINISH = '-',
PSYC_OPERATOR_DIMINISH = '-', PSYC_OPERATOR_QUERY = '?',
PSYC_OPERATOR_QUERY = '?',
} PsycOperator; } PsycOperator;
typedef enum typedef enum {
{ PSYC_STATE_NOOP = 0,
PSYC_STATE_NOOP = 0, PSYC_STATE_RESET = '=',
PSYC_STATE_RESET = '=', PSYC_STATE_RESYNC = '?',
PSYC_STATE_RESYNC = '?',
} PsycStateOp; } PsycStateOp;
/** Structure for a modifier. */ /** Structure for a modifier. */
typedef struct typedef struct {
{ char oper;
char oper; PsycString name;
PsycString name; PsycString value;
PsycString value; PsycModifierFlag flag;
PsycModifierFlag flag;
} PsycModifier; } PsycModifier;
/** Structure for an entity or routing header. */ /** Structure for an entity or routing header. */
typedef struct typedef struct {
{ size_t lines;
size_t lines; PsycModifier *modifiers;
PsycModifier *modifiers;
} PsycHeader; } PsycHeader;
/** Structure for a list. */ /** Structure for a list. */
typedef struct typedef struct {
{ size_t num_elems;
size_t num_elems; PsycString *elems;
PsycString *elems; size_t length;
size_t length; PsycListFlag flag;
PsycListFlag flag;
} PsycList; } PsycList;
/** Intermediate struct for a PSYC packet */ /** Intermediate struct for a PSYC packet */
typedef struct typedef struct {
{ PsycHeader routing; ///< Routing header.
PsycHeader routing; ///< Routing header. PsycHeader entity; ///< Entity header.
PsycHeader entity; ///< Entity header. char stateop; ///< State operation. @see PsycStateOp
char stateop; ///< State operation. @see PsycStateOp PsycString method; ///< Contains the method.
PsycString method; ///< Contains the method. PsycString data; ///< Contains the data.
PsycString data; ///< Contains the data. PsycString content; ///< Contains the whole content.
PsycString content; ///< Contains the whole content. size_t routingLength; ///< Length of routing part.
size_t routingLength; ///< Length of routing part. size_t contentLength; ///< Length of content part.
size_t contentLength; ///< Length of content part. size_t length; ///< Total length of packet.
size_t length; ///< Total length of packet. PsycPacketFlag flag; ///< Packet flag.
PsycPacketFlag flag; ///< Packet flag.
} PsycPacket; } PsycPacket;
/** /**
* Return the number of digits a number has in its base 10 representation. * Return the number of digits a number has in its base 10 representation.
*/ */
static inline static inline size_t
size_t psyc_num_length (size_t n) psyc_num_length (size_t n)
{ {
return n < 10 ? 1 : log10(n) + 1; return n < 10 ? 1 : log10(n) + 1;
} }
/** /**
* \internal * \internal
* Check if a modifier needs length. * Check if a modifier needs length.
*/ */
static inline static inline PsycModifierFlag
PsycModifierFlag psyc_modifier_length_check (PsycModifier *m) psyc_modifier_length_check (PsycModifier *m)
{ {
PsycModifierFlag flag; PsycModifierFlag flag;
if (m->value.length > PSYC_MODIFIER_SIZE_THRESHOLD) if (m->value.length > PSYC_MODIFIER_SIZE_THRESHOLD)
flag = PSYC_MODIFIER_NEED_LENGTH; flag = PSYC_MODIFIER_NEED_LENGTH;
else if (memchr(m->value.data, (int)'\n', m->value.length)) else if (memchr(m->value.data, (int) '\n', m->value.length))
flag = PSYC_MODIFIER_NEED_LENGTH; flag = PSYC_MODIFIER_NEED_LENGTH;
else else
flag = PSYC_MODIFIER_NO_LENGTH; flag = PSYC_MODIFIER_NO_LENGTH;
return flag; return flag;
} }
/** Initialize modifier */ /** Initialize modifier */
static inline static inline void
void psyc_modifier_init (PsycModifier *m, char oper, psyc_modifier_init (PsycModifier *m, char oper,
char *name, size_t namelen, char *name, size_t namelen,
char *value, size_t valuelen, char *value, size_t valuelen, PsycModifierFlag flag)
PsycModifierFlag flag)
{ {
*m = (PsycModifier) {oper, {namelen, name}, {valuelen, value}, flag}; *m = (PsycModifier) {oper, {namelen, name}, {valuelen, value}, flag};
if (flag == PSYC_MODIFIER_CHECK_LENGTH) // find out if it needs a length if (flag == PSYC_MODIFIER_CHECK_LENGTH) // find out if it needs a length
m->flag = psyc_modifier_length_check(m); m->flag = psyc_modifier_length_check(m);
} }
/** /**
* \internal * \internal
* Get the total length of a modifier when rendered. * Get the total length of a modifier when rendered.
*/ */
size_t psyc_modifier_length (PsycModifier *m); size_t
psyc_modifier_length (PsycModifier *m);
/** /**
* \internal * \internal
* Check if a list needs length. * Check if a list needs length.
*/ */
PsycListFlag psyc_list_length_check (PsycList *list); PsycListFlag
psyc_list_length_check (PsycList *list);
/** /**
* \internal * \internal
* Get the total length of a list when rendered. * Get the total length of a list when rendered.
*/ */
PsycListFlag psyc_list_length (PsycList *list); PsycListFlag
psyc_list_length (PsycList *list);
/** /**
* \internal * \internal
* Check if a packet needs length. * Check if a packet needs length.
*/ */
PsycPacketFlag psyc_packet_length_check (PsycPacket *p); PsycPacketFlag
psyc_packet_length_check (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_packet_length_set (PsycPacket *p); size_t
psyc_packet_length_set (PsycPacket *p);
/** Initialize list. */ /** Initialize list. */
void psyc_list_init (PsycList *list, PsycString *elems, size_t num_elems, void
PsycListFlag flag); psyc_list_init (PsycList *list, PsycString *elems, size_t num_elems,
PsycListFlag flag);
/** Initialize packet. */ /** Initialize packet. */
void psyc_packet_init (PsycPacket *packet, void
PsycModifier *routing, size_t routinglen, psyc_packet_init (PsycPacket *packet,
PsycModifier *entity, size_t entitylen, PsycModifier *routing, size_t routinglen,
char *method, size_t methodlen, PsycModifier *entity, size_t entitylen,
char *data, size_t datalen, char *method, size_t methodlen,
char stateop, PsycPacketFlag flag); char *data, size_t datalen,
char stateop, PsycPacketFlag flag);
/** Initialize packet with raw content. */ /** Initialize packet with raw content. */
void psyc_packet_init_raw (PsycPacket *packet, void
PsycModifier *routing, size_t routinglen, psyc_packet_init_raw (PsycPacket *packet,
char *content, size_t contentlen, PsycModifier *routing, size_t routinglen,
PsycPacketFlag flag); char *content, size_t contentlen,
PsycPacketFlag flag);
/** @} */ // end of packet group /** @} */ // end of packet group
#define PSYC_PACKET_H
#endif #endif

View file

@ -1,4 +1,5 @@
#ifndef PSYC_PARSE_H #ifndef PSYC_PARSE_H
#define PSYC_PARSE_H
/** /**
* @file psyc/parse.h * @file psyc/parse.h
@ -115,13 +116,13 @@
#include <psyc.h> #include <psyc.h>
typedef enum { typedef enum {
/// Default Flag. Parse everything. /// Default Flag. Parse everything.
PSYC_PARSE_ALL = 0, PSYC_PARSE_ALL = 0,
/// Parse only the header /// Parse only the header
PSYC_PARSE_ROUTING_ONLY = 1, PSYC_PARSE_ROUTING_ONLY = 1,
/// Parse only the content. /// Parse only the content.
/// Parsing starts at the content and the content must be complete. /// Parsing starts at the content and the content must be complete.
PSYC_PARSE_START_AT_CONTENT = 2, PSYC_PARSE_START_AT_CONTENT = 2,
} PsycParseFlag; } PsycParseFlag;
/** /**
@ -129,69 +130,69 @@ typedef enum {
* @see psyc_parse() * @see psyc_parse()
*/ */
typedef enum { typedef enum {
/// Error, packet is not ending with a valid delimiter. /// Error, packet is not ending with a valid delimiter.
PSYC_PARSE_ERROR_END = -8, PSYC_PARSE_ERROR_END = -8,
/// Error, expected NL after the method. /// Error, expected NL after the method.
PSYC_PARSE_ERROR_METHOD = -7, PSYC_PARSE_ERROR_METHOD = -7,
/// Error, expected NL after a modifier. /// Error, expected NL after a modifier.
PSYC_PARSE_ERROR_MOD_NL = -6, PSYC_PARSE_ERROR_MOD_NL = -6,
/// Error, modifier length is not numeric. /// Error, modifier length is not numeric.
PSYC_PARSE_ERROR_MOD_LEN = -5, PSYC_PARSE_ERROR_MOD_LEN = -5,
/// Error, expected TAB before modifier value. /// Error, expected TAB before modifier value.
PSYC_PARSE_ERROR_MOD_TAB = -4, PSYC_PARSE_ERROR_MOD_TAB = -4,
/// Error, modifier name is missing. /// Error, modifier name is missing.
PSYC_PARSE_ERROR_MOD_NAME = -3, PSYC_PARSE_ERROR_MOD_NAME = -3,
/// Error, expected NL after the content length. /// Error, expected NL after the content length.
PSYC_PARSE_ERROR_LENGTH = -2, PSYC_PARSE_ERROR_LENGTH = -2,
/// Error in packet. /// Error in packet.
PSYC_PARSE_ERROR = -1, PSYC_PARSE_ERROR = -1,
/// Buffer contains insufficient amount of data. /// Buffer contains insufficient amount of data.
/// Fill another buffer and concatenate it with the end of the current buffer, /// Fill another buffer and concatenate it with the end of the current buffer,
/// from the cursor position to the end. /// from the cursor position to the end.
PSYC_PARSE_INSUFFICIENT = 1, PSYC_PARSE_INSUFFICIENT = 1,
/// Routing modifier parsing done. /// Routing modifier parsing done.
/// Operator, name & value contains the respective parts. /// Operator, name & value contains the respective parts.
PSYC_PARSE_ROUTING = 2, PSYC_PARSE_ROUTING = 2,
/// State sync operation. /// State sync operation.
PSYC_PARSE_STATE_RESYNC = 3, PSYC_PARSE_STATE_RESYNC = 3,
/// State reset operation. /// State reset operation.
PSYC_PARSE_STATE_RESET = 4, PSYC_PARSE_STATE_RESET = 4,
/// Start of an incomplete entity modifier. /// Start of an incomplete entity modifier.
/// Operator & name are complete, value is incomplete. /// Operator & name are complete, value is incomplete.
PSYC_PARSE_ENTITY_START = 5, PSYC_PARSE_ENTITY_START = 5,
/// Continuation of an incomplete entity modifier. /// Continuation of an incomplete entity modifier.
PSYC_PARSE_ENTITY_CONT = 6, PSYC_PARSE_ENTITY_CONT = 6,
/// End of an incomplete entity modifier. /// End of an incomplete entity modifier.
PSYC_PARSE_ENTITY_END = 7, PSYC_PARSE_ENTITY_END = 7,
/// Entity modifier parsing done in one go. /// Entity modifier parsing done in one go.
/// Operator, name & value contains the respective parts. /// Operator, name & value contains the respective parts.
PSYC_PARSE_ENTITY = 8, PSYC_PARSE_ENTITY = 8,
/// Start of an incomplete body. /// Start of an incomplete body.
/// Name contains method, value contains part of the body. /// Name contains method, value contains part of the body.
/// Used when packet length is given /// Used when packet length is given
PSYC_PARSE_BODY_START = 9, PSYC_PARSE_BODY_START = 9,
/// Continuation of an incomplete body. /// Continuation of an incomplete body.
/// Used when packet length is given /// Used when packet length is given
PSYC_PARSE_BODY_CONT = 10, PSYC_PARSE_BODY_CONT = 10,
/// End of an incomplete body. /// End of an incomplete body.
/// Used when packet length is given /// Used when packet length is given
PSYC_PARSE_BODY_END = 11, PSYC_PARSE_BODY_END = 11,
/// Body parsing done in one go, name contains method, value contains body. /// Body parsing done in one go, name contains method, value contains body.
PSYC_PARSE_BODY = 12, PSYC_PARSE_BODY = 12,
/// Start of an incomplete content, value contains part of content. /// Start of an incomplete content, value contains part of content.
/// Used when PSYC_PARSE_ROUTING_ONLY is set. /// Used when PSYC_PARSE_ROUTING_ONLY is set.
PSYC_PARSE_CONTENT_START = 9, PSYC_PARSE_CONTENT_START = 9,
/// Continuation of an incomplete content. /// Continuation of an incomplete content.
/// Used when PSYC_PARSE_ROUTING_ONLY is set. /// Used when PSYC_PARSE_ROUTING_ONLY is set.
PSYC_PARSE_CONTENT_CONT = 10, PSYC_PARSE_CONTENT_CONT = 10,
/// End of an incomplete content. /// End of an incomplete content.
/// Used when PSYC_PARSE_ROUTING_ONLY is set. /// Used when PSYC_PARSE_ROUTING_ONLY is set.
PSYC_PARSE_CONTENT_END = 11, PSYC_PARSE_CONTENT_END = 11,
/// Content parsing done in one go, value contains the whole content. /// Content parsing done in one go, value contains the whole content.
/// Used when PSYC_PARSE_ROUTING_ONLY is set. /// Used when PSYC_PARSE_ROUTING_ONLY is set.
PSYC_PARSE_CONTENT = 12, PSYC_PARSE_CONTENT = 12,
/// Finished parsing packet. /// Finished parsing packet.
PSYC_PARSE_COMPLETE = 13, PSYC_PARSE_COMPLETE = 13,
} PsycParseRC; } PsycParseRC;
/** /**
@ -199,48 +200,48 @@ typedef enum {
* @see psyc_parse_list() * @see psyc_parse_list()
*/ */
typedef enum { typedef enum {
PSYC_PARSE_LIST_ERROR_DELIM = -4, PSYC_PARSE_LIST_ERROR_DELIM = -4,
PSYC_PARSE_LIST_ERROR_LEN = -3, PSYC_PARSE_LIST_ERROR_LEN = -3,
PSYC_PARSE_LIST_ERROR_TYPE = -2, PSYC_PARSE_LIST_ERROR_TYPE = -2,
PSYC_PARSE_LIST_ERROR = -1, PSYC_PARSE_LIST_ERROR = -1,
/// Completed parsing a list element. /// Completed parsing a list element.
PSYC_PARSE_LIST_ELEM = 1, PSYC_PARSE_LIST_ELEM = 1,
/// Reached end of buffer. /// Reached end of buffer.
PSYC_PARSE_LIST_END = 2, PSYC_PARSE_LIST_END = 2,
/// Binary list is incomplete. /// Binary list is incomplete.
PSYC_PARSE_LIST_INCOMPLETE = 3, PSYC_PARSE_LIST_INCOMPLETE = 3,
} PsycParseListRC; } PsycParseListRC;
/** /**
* Struct for keeping parser state. * Struct for keeping parser state.
*/ */
typedef struct { typedef struct {
size_t cursor; ///< Current position in buffer. size_t cursor; ///< Current position in buffer.
size_t startc; ///< Position where the parsing would be resumed. size_t startc; ///< Position where the parsing would be resumed.
PsycString buffer; ///< Buffer with data to be parsed. PsycString buffer; ///< Buffer with data to be parsed.
uint8_t flags; ///< Flags for the parser, see PsycParseFlag. uint8_t flags; ///< Flags for the parser, see PsycParseFlag.
PsycPart part; ///< Part of the packet being parsed currently. PsycPart part; ///< Part of the packet being parsed currently.
size_t routingLength; ///< Length of routing part parsed so far. size_t routingLength; ///< Length of routing part parsed so far.
size_t contentParsed; ///< Number of bytes parsed from the content so far. size_t contentParsed; ///< Number of bytes parsed from the content so far.
size_t contentLength; ///< Expected length of the content. size_t contentLength; ///< Expected length of the content.
PsycBool contentLengthFound; ///< Is there a length given for this packet? PsycBool contentLengthFound;///< Is there a length given for this packet?
size_t valueParsed; ///< Number of bytes parsed from the value so far. size_t valueParsed; ///< Number of bytes parsed from the value so far.
size_t valueLength; ///< Expected length of the value. size_t valueLength; ///< Expected length of the value.
PsycBool valueLengthFound; ///< Is there a length given for this modifier? PsycBool valueLengthFound; ///< Is there a length given for this modifier?
} PsycParseState; } PsycParseState;
/** /**
* Struct for keeping list parser state. * Struct for keeping list parser state.
*/ */
typedef struct { typedef struct {
size_t cursor; ///< Current position in buffer. size_t cursor; ///< Current position in buffer.
size_t startc; ///< Line start position. size_t startc; ///< Line start position.
PsycString buffer; ///< Buffer with data to be parsed. PsycString buffer; ///< Buffer with data to be parsed.
PsycListType type; ///< List type. PsycListType type; ///< List type.
size_t elemParsed; ///< Number of bytes parsed from the elem so far. size_t elemParsed; ///< Number of bytes parsed from the elem so far.
size_t elemLength; ///< Expected length of the elem. size_t elemLength; ///< Expected length of the elem.
} PsycParseListState; } PsycParseListState;
/** /**
@ -250,14 +251,14 @@ typedef struct {
* @param flags Flags to be set for the parser, see PsycParseFlag. * @param flags Flags to be set for the parser, see PsycParseFlag.
* @see PsycParseFlag * @see PsycParseFlag
*/ */
static inline static inline void
void psyc_parse_state_init (PsycParseState *state, uint8_t flags) psyc_parse_state_init (PsycParseState *state, uint8_t flags)
{ {
memset(state, 0, sizeof(PsycParseState)); memset(state, 0, sizeof(PsycParseState));
state->flags = flags; state->flags = flags;
if (flags & PSYC_PARSE_START_AT_CONTENT) if (flags & PSYC_PARSE_START_AT_CONTENT)
state->part = PSYC_PART_CONTENT; state->part = PSYC_PART_CONTENT;
} }
/** /**
@ -271,16 +272,17 @@ void psyc_parse_state_init (PsycParseState *state, uint8_t flags)
* @param length length of the data in bytes * @param length length of the data in bytes
* @see PsycString * @see PsycString
*/ */
static inline static inline void
void psyc_parse_buffer_set (PsycParseState *state, char *buffer, size_t length) psyc_parse_buffer_set (PsycParseState *state, char *buffer,
size_t length)
{ {
state->buffer = (PsycString) {length, buffer}; state->buffer = (PsycString) {length, buffer};
state->cursor = 0; state->cursor = 0;
if (state->flags & PSYC_PARSE_START_AT_CONTENT) { if (state->flags & PSYC_PARSE_START_AT_CONTENT) {
state->contentLength = length; state->contentLength = length;
state->contentLengthFound = PSYC_TRUE; state->contentLengthFound = PSYC_TRUE;
} }
} }
/** /**
@ -288,68 +290,68 @@ void psyc_parse_buffer_set (PsycParseState *state, char *buffer, size_t length)
* *
* @param state Pointer to the list state struct that should be initialized. * @param state Pointer to the list state struct that should be initialized.
*/ */
static inline static inline void
void psyc_parse_list_state_init (PsycParseListState *state) psyc_parse_list_state_init (PsycParseListState *state)
{ {
memset(state, 0, sizeof(PsycParseListState)); memset(state, 0, sizeof(PsycParseListState));
} }
/** /**
* Sets a new buffer in the list parser state struct with data to be parsed. * Sets a new buffer in the list parser state struct with data to be parsed.
*/ */
static inline static inline void
void psyc_parse_list_buffer_set (PsycParseListState *state, char *buffer, size_t length) psyc_parse_list_buffer_set (PsycParseListState *state, char *buffer, size_t length)
{ {
state->buffer = (PsycString) {length, buffer}; state->buffer = (PsycString) {length, buffer};
state->cursor = 0; state->cursor = 0;
} }
static inline static inline size_t
size_t psyc_parse_content_length (PsycParseState *state) psyc_parse_content_length (PsycParseState *state)
{ {
return state->contentLength; return state->contentLength;
} }
static inline static inline PsycBool
PsycBool psyc_parse_content_length_found (PsycParseState *state) psyc_parse_content_length_found (PsycParseState *state)
{ {
return state->contentLengthFound; return state->contentLengthFound;
} }
static inline static inline size_t
size_t psyc_parse_value_length (PsycParseState *state) psyc_parse_value_length (PsycParseState *state)
{ {
return state->valueLength; return state->valueLength;
} }
static inline static inline PsycBool
PsycBool psyc_parse_value_length_found (PsycParseState *state) psyc_parse_value_length_found (PsycParseState *state)
{ {
return state->valueLengthFound; return state->valueLengthFound;
} }
static inline static inline size_t
size_t psyc_parse_cursor (PsycParseState *state) psyc_parse_cursor (PsycParseState *state)
{ {
return state->cursor; return state->cursor;
} }
static inline static inline size_t
size_t psyc_parse_buffer_length (PsycParseState *state) psyc_parse_buffer_length (PsycParseState *state)
{ {
return state->buffer.length; return state->buffer.length;
} }
static inline static inline size_t
size_t psyc_parse_remaining_length (PsycParseState *state) psyc_parse_remaining_length (PsycParseState *state)
{ {
return state->buffer.length - state->cursor; return state->buffer.length - state->cursor;
} }
static inline static inline const char *
const char * psyc_parse_remaining_buffer (PsycParseState *state) psyc_parse_remaining_buffer (PsycParseState *state)
{ {
return state->buffer.data + state->cursor; return state->buffer.data + state->cursor;
} }
/** /**
@ -371,8 +373,9 @@ const char * psyc_parse_remaining_buffer (PsycParseState *state)
#ifdef __INLINE_PSYC_PARSE #ifdef __INLINE_PSYC_PARSE
static inline static inline
#endif #endif
PsycParseRC psyc_parse (PsycParseState *state, char *oper, PsycParseRC
PsycString *name, PsycString *value); psyc_parse (PsycParseState *state, char *oper,
PsycString *name, PsycString *value);
/** /**
* List parser. * List parser.
@ -388,142 +391,142 @@ PsycParseRC psyc_parse (PsycParseState *state, char *oper,
#ifdef __INLINE_PSYC_PARSE #ifdef __INLINE_PSYC_PARSE
static inline static inline
#endif #endif
PsycParseListRC psyc_parse_list (PsycParseListState *state, PsycString *elem); PsycParseListRC
psyc_parse_list (PsycParseListState *state, PsycString *elem);
static inline static inline PsycBool
PsycBool psyc_parse_number (const char *value, size_t len, int64_t *n) psyc_parse_number (const char *value, size_t len, int64_t *n)
{ {
size_t c = 0; size_t c = 0;
uint8_t neg = 0; uint8_t neg = 0;
if (!value) if (!value)
return PSYC_FALSE;
if (value[0] == '-')
neg = ++c;
*n = 0;
while (c < len && value[c] >= '0' && value[c] <= '9')
*n = 10 * *n + (value[c++] - '0');
if (c != len)
return PSYC_FALSE;
if (neg)
*n = 0 - *n;
return PSYC_TRUE;
}
static inline
PsycBool psyc_parse_number_unsigned (const char *value, size_t len, uint64_t *n)
{
size_t c = 0;
if (!value)
return PSYC_FALSE;
*n = 0;
while (c < len && value[c] >= '0' && value[c] <= '9')
*n = 10 * *n + (value[c++] - '0');
return c == len ? PSYC_TRUE : PSYC_FALSE;
}
static inline
PsycBool psyc_parse_time (const char *value, size_t len, time_t *t)
{
return psyc_parse_number(value, len, t);
}
static inline
PsycBool psyc_parse_date (const char *value, size_t len, time_t *t)
{
if (psyc_parse_number(value, len, t)) {
*t += PSYC_EPOCH;
return PSYC_TRUE;
}
return PSYC_FALSE; return PSYC_FALSE;
if (value[0] == '-')
neg = ++c;
*n = 0;
while (c < len && value[c] >= '0' && value[c] <= '9')
*n = 10 * *n + (value[c++] - '0');
if (c != len)
return PSYC_FALSE;
if (neg)
*n = 0 - *n;
return PSYC_TRUE;
}
static inline PsycBool
psyc_parse_number_unsigned (const char *value, size_t len, uint64_t *n)
{
size_t c = 0;
if (!value)
return PSYC_FALSE;
*n = 0;
while (c < len && value[c] >= '0' && value[c] <= '9')
*n = 10 * *n + (value[c++] - '0');
return c == len ? PSYC_TRUE : PSYC_FALSE;
}
static inline PsycBool
psyc_parse_time (const char *value, size_t len, time_t *t)
{
return psyc_parse_number(value, len, t);
}
static inline PsycBool
psyc_parse_date (const char *value, size_t len, time_t *t)
{
if (psyc_parse_number(value, len, t)) {
*t += PSYC_EPOCH;
return PSYC_TRUE;
}
return PSYC_FALSE;
} }
/** /**
* Determines if the argument is a glyph. * Determines if the argument is a glyph.
* Glyphs are: : = + - ? ! * Glyphs are: : = + - ? !
*/ */
static inline static inline char
char psyc_is_glyph (uint8_t g) psyc_is_glyph (uint8_t g)
{ {
switch(g) { switch (g) {
case ':': case ':':
case '=': case '=':
case '+': case '+':
case '-': case '-':
case '?': case '?':
case '!': case '!':
return 1; return 1;
default: default:
return 0; return 0;
} }
} }
/** /**
* Determines if the argument is numeric. * Determines if the argument is numeric.
*/ */
static inline static inline char
char psyc_is_numeric (uint8_t c) psyc_is_numeric (uint8_t c)
{ {
return c >= '0' && c <= '9'; return c >= '0' && c <= '9';
} }
/** /**
* Determines if the argument is alphabetic. * Determines if the argument is alphabetic.
*/ */
static inline static inline char
char psyc_is_alpha (uint8_t c) psyc_is_alpha (uint8_t c)
{ {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
} }
/** /**
* Determines if the argument is alphanumeric. * Determines if the argument is alphanumeric.
*/ */
static inline static inline char
char psyc_is_alpha_numeric (uint8_t c) psyc_is_alpha_numeric (uint8_t c)
{ {
return psyc_is_alpha(c) || psyc_is_numeric(c); return psyc_is_alpha(c) || psyc_is_numeric(c);
} }
/** /**
* Determines if the argument is a keyword character. * Determines if the argument is a keyword character.
* Keyword characters are: alphanumeric and _ * Keyword characters are: alphanumeric and _
*/ */
static inline static inline char
char psyc_is_kw_char (uint8_t c) psyc_is_kw_char (uint8_t c)
{ {
return psyc_is_alpha_numeric(c) || c == '_'; return psyc_is_alpha_numeric(c) || c == '_';
} }
/** /**
* Determines if the argument is a name character. * Determines if the argument is a name character.
* Name characters are: see opaque_part in RFC 2396 * Name characters are: see opaque_part in RFC 2396
*/ */
static inline static inline char
char psyc_is_name_char (uint8_t c) psyc_is_name_char (uint8_t c)
{ {
return psyc_is_alpha(c) || (c >= '$' && c <= ';') || return psyc_is_alpha(c) || (c >= '$' && c <= ';')
c == '_' || c == '!' || c == '?' || c == '=' || c == '@' || c == '~'; || c == '_' || c == '!' || c == '?' || c == '=' || c == '@' || c == '~';
} }
/** /**
* Determines if the argument is a hostname character. * Determines if the argument is a hostname character.
* Hostname characters are: alphanumeric and - * Hostname characters are: alphanumeric and -
*/ */
static inline static inline char
char psyc_is_host_char (uint8_t c) psyc_is_host_char (uint8_t c)
{ {
return psyc_is_alpha_numeric(c) || c == '.' || c == '-'; return psyc_is_alpha_numeric(c) || c == '.' || c == '-';
} }
/** @} */ // end of parse group /** @} */ // end of parse group
#define PSYC_PARSE_H
#endif #endif

View file

@ -1,4 +1,5 @@
#ifndef PSYC_RENDER_H #ifndef PSYC_RENDER_H
#define PSYC_RENDER_H
#include <psyc/packet.h> #include <psyc/packet.h>
@ -19,27 +20,25 @@
/** /**
* Return codes for psyc_render. * Return codes for psyc_render.
*/ */
typedef enum typedef enum {
{ /// Error, method is missing, but data is present.
/// Error, method is missing, but data is present. PSYC_RENDER_ERROR_METHOD_MISSING = -3,
PSYC_RENDER_ERROR_METHOD_MISSING = -3, /// Error, a modifier name is missing.
/// Error, a modifier name is missing. PSYC_RENDER_ERROR_MODIFIER_NAME_MISSING = -2,
PSYC_RENDER_ERROR_MODIFIER_NAME_MISSING = -2, /// Error, buffer is too small to render the packet.
/// Error, buffer is too small to render the packet. PSYC_RENDER_ERROR = -1,
PSYC_RENDER_ERROR = -1, /// Packet is rendered successfully in the buffer.
/// Packet is rendered successfully in the buffer. PSYC_RENDER_SUCCESS = 0,
PSYC_RENDER_SUCCESS = 0,
} PsycRenderRC; } PsycRenderRC;
/** /**
* Return codes for psyc_render_list. * Return codes for psyc_render_list.
*/ */
typedef enum typedef enum {
{ /// Error, buffer is too small to render the list.
/// Error, buffer is too small to render the list. PSYC_RENDER_LIST_ERROR = -1,
PSYC_RENDER_LIST_ERROR = -1, /// List is rendered successfully in the buffer.
/// List is rendered successfully in the buffer. PSYC_RENDER_LIST_SUCCESS = 0,
PSYC_RENDER_LIST_SUCCESS = 0,
} PsycRenderListRC; } PsycRenderListRC;
/** /**
@ -59,7 +58,8 @@ typedef enum
#ifdef __INLINE_PSYC_RENDER #ifdef __INLINE_PSYC_RENDER
static inline static inline
#endif #endif
PsycRenderRC psyc_render (PsycPacket *packet, char *buffer, size_t buflen); PsycRenderRC
psyc_render (PsycPacket *packet, char *buffer, size_t buflen);
/** /**
* Render a PSYC list into a buffer. * Render a PSYC list into a buffer.
@ -67,9 +67,9 @@ PsycRenderRC psyc_render (PsycPacket *packet, char *buffer, size_t buflen);
#ifdef __INLINE_PSYC_RENDER #ifdef __INLINE_PSYC_RENDER
static inline static inline
#endif #endif
PsycRenderListRC psyc_render_list (PsycList *list, char *buffer, size_t buflen); PsycRenderListRC
psyc_render_list (PsycList *list, char *buffer, size_t buflen);
/** @} */ // end of render group /** @} */ // end of render group
#define PSYC_RENDER_H
#endif #endif

View file

@ -1,4 +1,5 @@
#ifndef PSYC_TEXT_H #ifndef PSYC_TEXT_H
#define PSYC_TEXT_H
/** /**
* @file psyc/text.h * @file psyc/text.h
@ -19,39 +20,36 @@
* Return values for the text template parsing function. * Return values for the text template parsing function.
* @see psyc_text() * @see psyc_text()
*/ */
typedef enum typedef enum {
{ /// No substitution was made, nothing was written to the buffer.
/// No substitution was made, nothing was written to the buffer. PSYC_TEXT_NO_SUBST = -1,
PSYC_TEXT_NO_SUBST = -1, /// Text template parsing & rendering complete.
/// Text template parsing & rendering complete. PSYC_TEXT_COMPLETE = 0,
PSYC_TEXT_COMPLETE = 0, /// Text template parsing & rendering is incomplete, because the buffer was too
/// Text template parsing & rendering is incomplete, because the buffer was too small. /// small. Another call is required to this function after setting a new buffer.
/// Another call is required to this function after setting a new buffer. PSYC_TEXT_INCOMPLETE = 1,
PSYC_TEXT_INCOMPLETE = 1,
} PsycTextRC; } PsycTextRC;
/** /**
* Return values for PsycTextCB. * Return values for PsycTextCB.
*/ */
typedef enum typedef enum {
{ /// Value not found, don't substitute anything.
/// Value not found, don't substitute anything. PSYC_TEXT_VALUE_NOT_FOUND = -1,
PSYC_TEXT_VALUE_NOT_FOUND = -1, /// Value found, substitute contents of the value variable.
/// Value found, substitute contents of the value variable. PSYC_TEXT_VALUE_FOUND = 0,
PSYC_TEXT_VALUE_FOUND = 0,
} PsycTextValueRC; } PsycTextValueRC;
/** /**
* Struct for keeping PSYC text parser state. * Struct for keeping PSYC text parser state.
*/ */
typedef struct typedef struct {
{ size_t cursor; ///< current position in the template
size_t cursor; ///< current position in the template size_t written; ///< number of bytes written to buffer
size_t written; ///< number of bytes written to buffer PsycString tmpl; ///< input buffer with text template to parse
PsycString tmpl; ///< input buffer with text template to parse PsycString buffer; ///< output buffer for rendered text
PsycString buffer; ///< output buffer for rendered text PsycString open;
PsycString open; PsycString close;
PsycString close;
} PsycTextState; } PsycTextState;
/** /**
@ -64,7 +62,8 @@ typedef struct
* PSYC_TEXT_VALUE_NOT_FOUND if no match found in which case psyc_text * PSYC_TEXT_VALUE_NOT_FOUND if no match found in which case psyc_text
* leaves the original template text as is. * leaves the original template text as is.
*/ */
typedef PsycTextValueRC (*PsycTextCB)(const char *name, size_t len, PsycString *value, void *extra); typedef PsycTextValueRC (*PsycTextCB) (const char *name, size_t len,
PsycString *value, void *extra);
/** /**
* Initializes the PSYC text state struct. * Initializes the PSYC text state struct.
@ -75,17 +74,21 @@ typedef PsycTextValueRC (*PsycTextCB)(const char *name, size_t len, PsycString *
* @param buffer Output buffer where the rendered text is going to be written. * @param buffer Output buffer where the rendered text is going to be written.
* @param buflen Length of output buffer. * @param buflen Length of output buffer.
*/ */
static inline static inline void
void psyc_text_state_init (PsycTextState *state, psyc_text_state_init (PsycTextState *state,
char *tmpl, size_t tmplen, char *tmpl, size_t tmplen,
char *buffer, size_t buflen) char *buffer, size_t buflen)
{ {
state->cursor = 0; state->cursor = 0;
state->written = 0; state->written = 0;
state->tmpl = (PsycString) {tmplen, tmpl}; state->tmpl = (PsycString) {
state->buffer = (PsycString) {buflen, buffer}; tmplen, tmpl};
state->open = (PsycString) {1, "["}; state->buffer = (PsycString) {
state->close = (PsycString) {1, "]"}; buflen, buffer};
state->open = (PsycString) {
1, "["};
state->close = (PsycString) {
1, "]"};
} }
/** /**
@ -101,36 +104,40 @@ void psyc_text_state_init (PsycTextState *state,
* @param close Closing brace. * @param close Closing brace.
* @param closelen Length of closing brace. * @param closelen Length of closing brace.
*/ */
static inline static inline void
void psyc_text_state_init_custom (PsycTextState *state, psyc_text_state_init_custom (PsycTextState *state,
char *tmpl, size_t tmplen, char *tmpl, size_t tmplen,
char *buffer, size_t buflen, char *buffer, size_t buflen,
char *open, size_t openlen, char *open, size_t openlen,
char *close, size_t closelen) char *close, size_t closelen)
{ {
state->cursor = 0; state->cursor = 0;
state->written = 0; state->written = 0;
state->tmpl = (PsycString) {tmplen, tmpl}; state->tmpl = (PsycString) {
state->buffer = (PsycString) {buflen, buffer}; tmplen, tmpl};
state->open = (PsycString) {openlen, open}; state->buffer = (PsycString) {
state->close = (PsycString) {closelen, close}; buflen, buffer};
state->open = (PsycString) {
openlen, open};
state->close = (PsycString) {
closelen, close};
} }
/** /**
* Sets a new output buffer in the PSYC text state struct. * Sets a new output buffer in the PSYC text state struct.
*/ */
static inline static inline void
void psyc_text_buffer_set (PsycTextState *state, psyc_text_buffer_set (PsycTextState *state, char *buffer, size_t length)
char *buffer, size_t length)
{ {
state->buffer = (PsycString){length, buffer}; state->buffer = (PsycString) {
state->written = 0; length, buffer};
state->written = 0;
} }
static inline static inline size_t
size_t psyc_text_bytes_written (PsycTextState *state) psyc_text_bytes_written (PsycTextState *state)
{ {
return state->written; return state->written;
} }
/** /**
@ -148,9 +155,9 @@ size_t psyc_text_bytes_written (PsycTextState *state)
* *
* @see http://about.psyc.eu/psyctext * @see http://about.psyc.eu/psyctext
**/ **/
PsycTextRC psyc_text (PsycTextState *state, PsycTextCB getValue, void *extra); PsycTextRC
psyc_text (PsycTextState *state, PsycTextCB getValue, void *extra);
/** @} */ // end of text group /** @} */ // end of text group
#define PSYC_TEXT_H
#endif #endif

View file

@ -1,4 +1,6 @@
#ifndef PSYC_UNIFORM_H #ifndef PSYC_UNIFORM_H
#define PSYC_UNIFORM_H
/** /**
* @file uniform.h * @file uniform.h
* @brief Uniform parsing. * @brief Uniform parsing.
@ -7,76 +9,76 @@
#include <psyc.h> #include <psyc.h>
typedef enum { typedef enum {
PSYC_SCHEME_PSYC = 0, PSYC_SCHEME_PSYC = 0,
PSYC_SCHEME_IRC = 1, PSYC_SCHEME_IRC = 1,
PSYC_SCHEME_XMPP = 2, PSYC_SCHEME_XMPP = 2,
PSYC_SCHEME_SIP = 3, PSYC_SCHEME_SIP = 3,
} PsycScheme; } PsycScheme;
typedef struct { typedef struct {
// essential parts // essential parts
uint8_t valid; uint8_t valid;
PsycScheme type; PsycScheme type;
PsycString scheme; PsycString scheme;
PsycString user; PsycString user;
PsycString pass; PsycString pass;
PsycString host; PsycString host;
PsycString port; PsycString port;
PsycString transport; PsycString transport;
PsycString resource; PsycString resource;
PsycString query; PsycString query;
PsycString channel; PsycString channel;
// convenient snippets of the URL // convenient snippets of the URL
PsycString full; // the URL as such PsycString full; // the URL as such
PsycString body; // the URL without scheme and '//' PsycString body; // the URL without scheme and '//'
PsycString user_host; // mailto and xmpp style PsycString user_host; // mailto and xmpp style
PsycString host_port; // just host:port (and transport) PsycString host_port; // just host:port (and transport)
PsycString root; // root UNI PsycString root; // root UNI
PsycString entity; // entity UNI, without the channel PsycString entity; // entity UNI, without the channel
PsycString slashes; // the // if the protocol has them PsycString slashes; // the // if the protocol has them
PsycString slash; // first / after host PsycString slash; // first / after host
PsycString nick; // whatever works as a nickname PsycString nick; // whatever works as a nickname
} PsycUniform; } PsycUniform;
typedef enum { typedef enum {
PSYC_UNIFORM_SCHEME = 0, PSYC_UNIFORM_SCHEME = 0,
PSYC_UNIFORM_SLASHES, PSYC_UNIFORM_SLASHES,
PSYC_UNIFORM_USER, PSYC_UNIFORM_USER,
PSYC_UNIFORM_PASS, PSYC_UNIFORM_PASS,
PSYC_UNIFORM_HOST, PSYC_UNIFORM_HOST,
PSYC_UNIFORM_PORT, PSYC_UNIFORM_PORT,
PSYC_UNIFORM_TRANSPORT, PSYC_UNIFORM_TRANSPORT,
PSYC_UNIFORM_RESOURCE, PSYC_UNIFORM_RESOURCE,
PSYC_UNIFORM_QUERY, PSYC_UNIFORM_QUERY,
PSYC_UNIFORM_CHANNEL, PSYC_UNIFORM_CHANNEL,
} PsycUniformPart; } PsycUniformPart;
typedef enum { typedef enum {
PSYC_PARSE_UNIFORM_INVALID_SLASHES = -7, PSYC_PARSE_UNIFORM_INVALID_SLASHES = -7,
PSYC_PARSE_UNIFORM_INVALID_CHANNEL = -6, PSYC_PARSE_UNIFORM_INVALID_CHANNEL = -6,
PSYC_PARSE_UNIFORM_INVALID_RESOURCE = -5, PSYC_PARSE_UNIFORM_INVALID_RESOURCE = -5,
PSYC_PARSE_UNIFORM_INVALID_TRANSPORT = -4, PSYC_PARSE_UNIFORM_INVALID_TRANSPORT = -4,
PSYC_PARSE_UNIFORM_INVALID_PORT = -3, PSYC_PARSE_UNIFORM_INVALID_PORT = -3,
PSYC_PARSE_UNIFORM_INVALID_HOST = -2, PSYC_PARSE_UNIFORM_INVALID_HOST = -2,
PSYC_PARSE_UNIFORM_INVALID_SCHEME = -1, PSYC_PARSE_UNIFORM_INVALID_SCHEME = -1,
} PsycParseUniformRC; } PsycParseUniformRC;
typedef enum { typedef enum {
PSYC_TRANSPORT_TCP = 'c', PSYC_TRANSPORT_TCP = 'c',
PSYC_TRANSPORT_UDP = 'd', PSYC_TRANSPORT_UDP = 'd',
PSYC_TRANSPORT_TLS = 's', PSYC_TRANSPORT_TLS = 's',
PSYC_TRANSPORT_GNUNET = 'g', PSYC_TRANSPORT_GNUNET = 'g',
} PsycTransport; } PsycTransport;
typedef enum { typedef enum {
PSYC_ENTITY_ROOT = 0, PSYC_ENTITY_ROOT = 0,
PSYC_ENTITY_PERSON = '~', PSYC_ENTITY_PERSON = '~',
PSYC_ENTITY_PLACE = '@', PSYC_ENTITY_PLACE = '@',
PSYC_ENTITY_SERVICE = '$', PSYC_ENTITY_SERVICE = '$',
} PsycEntityType; } PsycEntityType;
int psyc_uniform_parse (PsycUniform *uni, char *str, size_t length); int
psyc_uniform_parse (PsycUniform * uni, char *str, size_t length);
#define PSYC_UNIFORM_H
#endif #endif

View file

@ -1,4 +1,5 @@
#ifndef PSYC_VARIABLE_H #ifndef PSYC_VARIABLE_H
#define PSYC_VARIABLE_H
/** /**
* @file psyc/variable.h * @file psyc/variable.h
@ -16,22 +17,23 @@ extern const size_t psyc_var_types_num;
/** /**
* Is this a routing variable name? * Is this a routing variable name?
*/ */
PsycBool psyc_var_is_routing (const char *name, size_t len); PsycBool
psyc_var_is_routing (const char *name, size_t len);
/** /**
* Get the type of variable name. * Get the type of variable name.
*/ */
PsycType psyc_var_type (const char *name, size_t len); PsycType
psyc_var_type (const char *name, size_t len);
/** /**
* Is this a list variable name? * Is this a list variable name?
*/ */
static inline static inline PsycBool
PsycBool psyc_var_is_list (const char *name, size_t len) psyc_var_is_list (const char *name, size_t len)
{ {
return len < 5 || memcmp(name, "_list", 5) != 0 || return len < 5 || memcmp(name, "_list", 5) != 0 || (len > 5 && name[5] != '_')
(len > 5 && name[5] != '_') ? PSYC_FALSE : PSYC_TRUE; ? PSYC_FALSE : PSYC_TRUE;
} }
#define PSYC_VARIABLE_H
#endif #endif

View file

@ -1,39 +1,45 @@
#define ALPHANUMS "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" #define ALPHANUMS "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"
/** converts an integer to a string, using a base of 10 by default. /**
* Converts an integer to a string, using a base of 10 by default.
* *
* if you NULL out the output buffer it will return the expected * If you NULL out the output buffer it will return the expected
* output string length anyway. * output string length anyway.
*/ */
int itoa(int number, char* out, int base) { int
int t, count; itoa (int number, char *out, int base)
char *p, *q; {
char c; int t, count;
char *p, *q;
char c;
p = q = out; p = q = out;
if (base < 2 || base > 36) base = 10; if (base < 2 || base > 36)
base = 10;
do { do {
t = number; t = number;
number /= base; number /= base;
if (out) *p = ALPHANUMS[t+35 - number*base]; if (out)
p++; *p = ALPHANUMS[t + 35 - number * base];
} while (number); p++;
} while (number);
if (t < 0) { if (t < 0) {
if (out) *p = '-'; if (out)
p++; *p = '-';
p++;
}
count = p - out;
if (out) {
*p-- = '\0';
while (q < p) {
c = *p;
*p-- = *q;
*q++ = c;
} }
count = p-out; }
if (out) { return count;
*p-- = '\0';
while(q < p) {
c = *p;
*p-- = *q;
*q++ = c;
}
}
return count;
} }
/* This little test program shows that itoa() is roughly 3 times faster /* This little test program shows that itoa() is roughly 3 times faster
@ -45,41 +51,44 @@ int itoa(int number, char* out, int base) {
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
int main(int argc, char **argv) { int
char out[4404]; main (int argc, char **argv)
int in[44]; {
int c, i, j; char out[4404];
int in[44];
if (argc < 3 || argc > sizeof(in)) { int c, i, j;
printf("Usage: %s <times> <numbers>+\n\nExample: %s 999999 123 234 345 -49 -21892\n", argv[0], argv[0]);
return -1;
}
for (j=argc-1; j; j--) {
// printf("Looking at arg #%d: %s\n", j, argv[j]);
in[j] = atoi(argv[j]);
// printf("Got %d: %d\n", j, in[j]);
}
for (i=in[1]; i; i--) {
c = 0;
for (j=argc-1; j>1; j--) {
# if 0
// use good old sprintf
c += sprintf(&out[c], " %d", in[j]);
# else
# if 1
// use the itoa implementation
out[c++] = ' ';
c += itoa(in[j], &out[c], 10);
# else
// just count the needed space
c += itoa(in[j], NULL, 10) + 1;
# endif
# endif
}
}
printf("%d times, %d count, buffer len: %d, buffer: %s\n",
in[1], c, strlen(out), "<omitted>"); // out
return 0;
}
if (argc < 3 || argc > sizeof(in)) {
printf("Usage: %s <times> <numbers>+\n\n"
"Example: %s 999999 123 234 345 -49 -21892\n",
argv[0], argv[0]);
return -1;
}
for (j = argc - 1; j; j--) {
//printf("Looking at arg #%d: %s\n", j, argv[j]);
in[j] = atoi(argv[j]);
//printf("Got %d: %d\n", j, in[j]);
}
for (i = in[1]; i; i--) {
c = 0;
for (j = argc - 1; j > 1; j--) {
#if 0
// use good old sprintf
c += sprintf(&out[c], " %d", in[j]);
#else
#if 1
// use the itoa implementation
out[c++] = ' ';
c += itoa(in[j], &out[c], 10);
#else
// just count the needed space
c += itoa(in[j], NULL, 10) + 1;
#endif
#endif
}
}
printf("%d times, %d count, buffer len: %d, buffer: %s\n",
in[1], c, strlen(out), "<omitted>"); // out
return 0;
}
#endif #endif

View file

@ -1,158 +1,171 @@
#include "lib.h" #include "lib.h"
int psyc_inherits (char* sho, size_t slen, int
char* lon, size_t llen) { psyc_inherits(char *sho, size_t slen, char *lon, size_t llen)
{
// this allows to pass zero-terminated strings instead of providing
// 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)
// Disabled this, let's use that macro rather.
//if (!slen) slen = strlen(sho);
//if (!llen) llen = strlen(lon);
// this allows to pass zero-terminated strings instead of providing if (slen == 0 || *sho != '_' || llen == 0 || *lon != '_') {
// the length.. but we would be faster here if we expected the callee P1(("Please use long format keywords (compact ones would be faster, I know..)\n"));
// to always use the PSYC_C2ARG() macro instead. additionally, the return -2;
// empty string would then be fully supported (in case you want that) }
// Disabled this, let's use that macro rather.
//if (!slen) slen = strlen(sho);
//if (!llen) llen = strlen(lon);
if (slen == 0 || *sho != '_' || if (slen > llen) {
llen == 0 || *lon != '_') { P1(("The long string is shorter than the short one.\n"));
P1(("Please use long format keywords (compact ones would be faster, I know..)\n")) return -3;
return -2; }
}
if (slen > llen) { if (!strncmp(sho, lon, slen)) {
P1(("The long string is shorter than the short one.\n")) /* according to PSYC spec we have hereby already proved
return -3; * inheritance. the following check is optional!
} */
if (llen > slen && lon[slen] != '_') {
if (!strncmp(sho, lon, slen)) { /* It is illegal to introduce a keyword family
/* according to PSYC spec we have hereby already proved * that starts just like an existing one. Since
* inheritance. the following check is optional! * _failure exists, you can't use _fail. But
*/ * implementations are not required to recognize
if (llen > slen && lon[slen] != '_') { * that.
/* It is illegal to introduce a keyword family */
* that starts just like an existing one. Since P1(("Illegal choice of keyword names!\n"));
* _failure exists, you can't use _fail. But return -4;
* implementations are not required to recognize
* that.
*/
P1(("Illegal choice of keyword names!\n"))
return -4;
}
return 0;
}
P4(("%.*s does not inherit from %.*s.\n", (int)llen, lon, (int)slen, sho))
return 1;
}
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 == 0 || *sho != '_' ||
llen == 0 || *lon != '_') {
P1(("Please use long format keywords (compact ones would be faster, I know..)\n"))
return -2;
}
if (slen > llen) {
P1(("The long string is shorter than the short one.\n"))
return -3;
}
if (slen == llen) {
if (!strncmp(sho, lon, slen)) {
P1(("Identical arguments.\n"))
return 0;
}
P1(("Same length but different.\nNo match, but they could be related or have a common type.\n"))
return -4;
}
P3(("# psyc_matches short '%.*s' in long '%.*s' ?\n", (int)slen, sho, (int)llen, lon))
se = sho+slen;
le = lon+llen;
sho++; lon++; slen--; llen--;
while(*sho && sho < se) {
P3(("# comparing short '%.*s' (%d)\n", (int)slen, sho, (int)slen))
unless (s = memchr(sho, '_', slen)) s = se;
P4(("# sho goes '%c' and lon goes '%c'\n", *sho, (int)*lon))
while(*lon && lon < le) {
P3(("# against long '%.*s' (%d)\n", (int)llen, lon, (int)llen))
unless (l = memchr(lon, '_', llen)) l = le;
P3(("# %ld == %ld && !strncmp '%.*s', '%.*s'\n", s-sho, l-lon, (int)(s-sho), sho, (int)(s-sho), lon))
if (l-lon == s-sho && !strncmp(sho, lon, s-sho)) goto foundone;
P4(("# failed\n"))
llen -= l-lon + 1;
lon = ++l;
}
goto failed;
foundone:
P3(("# found %ld of short '%.*s' and long '%.*s'\n", s-sho, (int)(s-sho), sho, (int)(s-sho), lon))
llen -= l-lon;
slen -= s-sho;
sho = ++s;
lon = ++l;
} }
return 0; return 0;
failed: }
P4(("No, they don't match.\n")) P4(("%.*s does not inherit from %.*s.\n", (int) llen, lon, (int) slen, sho));
return 1; return 1;
}
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 == 0 || *sho != '_' || llen == 0 || *lon != '_') {
P1(("Please use long format keywords (compact ones would be faster, I know..)\n"));
return -2;
}
if (slen > llen) {
P1(("The long string is shorter than the short one.\n"));
return -3;
}
if (slen == llen) {
if (!strncmp(sho, lon, slen)) {
P1(("Identical arguments.\n"));
return 0;
}
P1(("Same length but different.\nNo match, but they could be related or have a common type.\n"));
return -4;
}
P3(("# psyc_matches short '%.*s' in long '%.*s' ?\n", (int) slen, sho,
(int) llen, lon));
se = sho + slen;
le = lon + llen;
sho++;
lon++;
slen--;
llen--;
while (*sho && sho < se) {
P3(("# comparing short '%.*s' (%d)\n", (int) slen, sho, (int) slen));
unless(s = memchr(sho, '_', slen)) s = se;
P4(("# sho goes '%c' and lon goes '%c'\n", *sho, (int) *lon));
while (*lon && lon < le) {
P3(("# against long '%.*s' (%d)\n", (int) llen, lon, (int) llen));
unless(l = memchr(lon, '_', llen)) l = le;
P3(("# %ld == %ld && !strncmp '%.*s', '%.*s'\n", s - sho, l - lon,
(int) (s - sho), sho, (int) (s - sho), lon));
if (l - lon == s - sho && !strncmp(sho, lon, s - sho))
goto foundone;
P4(("# failed\n"));
llen -= l - lon + 1;
lon = ++l;
}
goto failed;
foundone:
P3(("# found %ld of short '%.*s' and long '%.*s'\n", s - sho,
(int) (s - sho), sho, (int) (s - sho), lon));
llen -= l - lon;
slen -= s - sho;
sho = ++s;
lon = ++l;
}
return 0;
failed:
P4(("No, they don't match.\n"));
return 1;
} }
/** /**
* Look up value associated with a key in a dictionary. * Look up value associated with a key in a dictionary.
*/ */
void * psyc_dict_lookup (const PsycDict *dict, size_t size, void *
const char *key, size_t keylen, psyc_dict_lookup(const PsycDict * dict, size_t size,
PsycBool inherit, int8_t *matching) const char *key, size_t keylen,
PsycBool inherit, int8_t * matching)
{ {
size_t cursor = 1; size_t cursor = 1;
uint8_t i, m = 0; uint8_t i, m = 0;
if (keylen < 2 || key[0] != '_') if (keylen < 2 || key[0] != '_')
return 0; return 0;
// first find the keywords with matching length // first find the keywords with matching length
for (i=0; i<size; i++) for (i = 0; i < size; i++) {
if (keylen == dict[i].key.length || if (keylen == dict[i].key.length
(inherit && keylen > dict[i].key.length && key[dict[i].key.length] == '_')) || (inherit && keylen > dict[i].key.length
matching[m++] = i; && key[dict[i].key.length] == '_'))
matching[m++] = i;
}
matching[m] = -1; // mark the end of matching indexes matching[m] = -1; // mark the end of matching indexes
while (cursor < keylen && matching[0] >= 0) { while (cursor < keylen && matching[0] >= 0) {
for (i = m = 0; i < size; i++) { for (i = m = 0; i < size; i++) {
if (matching[i] < 0) if (matching[i] < 0)
break; // reached the end of possible matches break; // reached the end of possible matches
if (cursor < dict[matching[i]].key.length && if (cursor < dict[matching[i]].key.length &&
dict[matching[i]].key.data[cursor] == key[cursor]) dict[matching[i]].key.data[cursor] == key[cursor])
matching[m++] = matching[i]; // found a match, update matching indexes matching[m++] = matching[i]; // found a match, update matching indexes
else if (cursor == dict[matching[i]].key.length && key[cursor] == '_') else if (cursor == dict[matching[i]].key.length && key[cursor] == '_')
return dict[matching[0]].value; // _ after the end of a matching prefix return dict[matching[0]].value; // _ after the end of a matching prefix
else if (dict[matching[i]].key.data[cursor] > key[cursor]) else if (dict[matching[i]].key.data[cursor] > key[cursor])
break; // passed the possible matches in alphabetical order in the dict break; // passed the possible matches in alphabetical order in the dict
}
if (m < size)
matching[m] = -1; // mark the end of matching indexes
cursor++;
} }
// return first match if found if (m < size)
return matching[0] >= 0 ? dict[matching[0]].value : 0; matching[m] = -1; // mark the end of matching indexes
cursor++;
}
// return first match if found
return matching[0] >= 0 ? dict[matching[0]].value : 0;
} }
#ifdef CMDTOOL #ifdef CMDTOOL
int main(int argc, char **argv) { int
if (argc != 3) { main(int argc, char **argv)
printf("Usage: %s <short> <long>\n\nExample: %s _failure_delivery _failure_unsuccessful_delivery_death\n", argv[0], argv[0]); {
return -1; if (argc != 3) {
} printf("Usage: %s <short> <long>\n\n"
if (psyc_matches(argv[1], 0, argv[2], 0) == 0) "Example: %s _failure_delivery _failure_unsuccessful_delivery_death\n",
printf("Yes, %s matches %s!\n", argv[1], argv[2]); argv[0], argv[0]);
if (psyc_inherits(argv[1], 0, argv[2], 0) == 0) return -1;
printf("Yes, %s inherits from %s!\n", argv[2], argv[1]); }
if (psyc_matches(argv[1], 0, argv[2], 0) == 0)
printf("Yes, %s matches %s!\n", argv[1], argv[2]);
if (psyc_inherits(argv[1], 0, argv[2], 0) == 0)
printf("Yes, %s inherits from %s!\n", argv[2], argv[1]);
} }
#endif #endif

View file

@ -31,32 +31,31 @@
/* /*
* Find the first occurrence of the byte string s in byte string l. * Find the first occurrence of the byte string s in byte string l.
*/ */
void * void *
memmem(const void *l, size_t l_len, const void *s, size_t s_len) memmem(const void *l, size_t l_len, const void *s, size_t s_len)
{ {
register char *cur, *last; register char *cur, *last;
const char *cl = (const char *)l; const char *cl = (const char *) l;
const char *cs = (const char *)s; const char *cs = (const char *) s;
/* we need something to compare */
if (l_len == 0 || s_len == 0)
return NULL;
/* "s" must be smaller or equal to "l" */
if (l_len < s_len)
return NULL;
/* special case where s_len == 1 */
if (s_len == 1)
return memchr(l, (int)*cs, l_len);
/* the last position where its possible to find "s" in "l" */
last = (char *)cl + l_len - s_len;
for (cur = (char *)cl; cur <= last; cur++)
if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
return cur;
/* we need something to compare */
if (l_len == 0 || s_len == 0)
return NULL; return NULL;
/* "s" must be smaller or equal to "l" */
if (l_len < s_len)
return NULL;
/* special case where s_len == 1 */
if (s_len == 1)
return memchr(l, (int) *cs, l_len);
/* the last position where its possible to find "s" in "l" */
last = (char *) cl + l_len - s_len;
for (cur = (char *) cl; cur <= last; cur++)
if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
return cur;
return NULL;
} }

View file

@ -2,169 +2,164 @@
#include <psyc/syntax.h> #include <psyc/syntax.h>
#include <psyc/packet.h> #include <psyc/packet.h>
inline inline PsycListFlag
PsycListFlag psyc_list_length_check (PsycList *list) psyc_list_length_check (PsycList * list)
{ {
PsycListFlag flag = PSYC_LIST_NO_LENGTH; PsycListFlag flag = PSYC_LIST_NO_LENGTH;
size_t i, length = 0; size_t i, length = 0;
for (i = 0; i < list->num_elems; i++) {
PsycString *elem = &list->elems[i];
length += 1 + elem->length; // |elem
if (length > PSYC_MODIFIER_SIZE_THRESHOLD ||
memchr(elem->data, (int) '|', elem->length) ||
memchr(elem->data, (int) '\n', elem->length)) {
flag = PSYC_LIST_NEED_LENGTH;
break;
}
}
return flag;
}
inline PsycListFlag
psyc_list_length (PsycList * list)
{
size_t i, length = 0;
if (list->flag == PSYC_LIST_NEED_LENGTH) {
for (i = 0; i < list->num_elems; i++) {
if (i > 0)
length++; // |
length += // length SP elem
psyc_num_length(list->elems[i].length) + 1 + list->elems[i].length;
}
} else {
for (i = 0; i < list->num_elems; i++) for (i = 0; i < list->num_elems; i++)
{ length += 1 + list->elems[i].length; // |elem
PsycString *elem = &list->elems[i]; }
length += 1 + elem->length; // |elem
if (length > PSYC_MODIFIER_SIZE_THRESHOLD ||
memchr(elem->data, (int)'|', elem->length) ||
memchr(elem->data, (int)'\n', elem->length))
{
flag = PSYC_LIST_NEED_LENGTH;
break;
}
}
return flag; return length;
} }
inline inline void
PsycListFlag psyc_list_length (PsycList *list) psyc_list_init (PsycList * list, PsycString * elems, size_t num_elems,
PsycListFlag flag)
{ {
size_t i, length = 0; *list = (PsycList) {
num_elems, elems, 0, flag};
if (list->flag == PSYC_LIST_NEED_LENGTH) if (flag == PSYC_LIST_CHECK_LENGTH) // check if list elements need length
{ list->flag = psyc_list_length_check(list);
for (i = 0; i < list->num_elems; i++)
{
if (i > 0)
length++; // |
length += psyc_num_length(list->elems[i].length) + 1 + list->elems[i].length; // length SP elem
}
}
else
{
for (i = 0; i < list->num_elems; i++)
length += 1 + list->elems[i].length; // |elem
}
return length; list->length = psyc_list_length(list);
}
inline
void psyc_list_init (PsycList *list, PsycString *elems, size_t num_elems,
PsycListFlag flag)
{
*list = (PsycList) {num_elems, elems, 0, flag};
if (flag == PSYC_LIST_CHECK_LENGTH) // check if list elements need length
list->flag = psyc_list_length_check(list);
list->length = psyc_list_length(list);
} }
inline inline size_t
size_t psyc_modifier_length (PsycModifier *m) psyc_modifier_length (PsycModifier * m)
{ {
size_t length = 2; // oper\n size_t length = 2; // oper\n
if (m->name.length > 0) if (m->name.length > 0)
length += m->name.length + 1 + m->value.length; // name\tvalue length += m->name.length + 1 + m->value.length; // name\tvalue
if (m->flag == PSYC_MODIFIER_NEED_LENGTH) // add length of length if needed if (m->flag == PSYC_MODIFIER_NEED_LENGTH) // add length of length if needed
length += psyc_num_length(m->value.length) + 1; // SP length length += psyc_num_length(m->value.length) + 1; // SP length
return length; return length;
} }
inline inline PsycPacketFlag
PsycPacketFlag psyc_packet_length_check (PsycPacket *p) psyc_packet_length_check (PsycPacket * p)
{ {
if (p->data.length == 1 && p->data.data[0] == PSYC_PACKET_DELIMITER_CHAR) if (p->data.length == 1 && p->data.data[0] == PSYC_PACKET_DELIMITER_CHAR)
return PSYC_PACKET_NEED_LENGTH; return PSYC_PACKET_NEED_LENGTH;
if (p->data.length > PSYC_CONTENT_SIZE_THRESHOLD) if (p->data.length > PSYC_CONTENT_SIZE_THRESHOLD)
return PSYC_PACKET_NEED_LENGTH; return PSYC_PACKET_NEED_LENGTH;
int i; int i;
// if any entity modifiers need length it is possible they contain // If any entity modifiers need length, it is possible they contain
// a packet terminator, thus the content should have a length as well // a packet terminator, thus the content should have a length as well.
for (i = 0; i < p->entity.lines; i++)
if (p->entity.modifiers[i].flag == PSYC_MODIFIER_NEED_LENGTH)
return PSYC_PACKET_NEED_LENGTH;
if (memmem(p->data.data, p->data.length, PSYC_C2ARG(PSYC_PACKET_DELIMITER)))
return PSYC_PACKET_NEED_LENGTH;
return PSYC_PACKET_NO_LENGTH;
}
inline size_t
psyc_packet_length_set (PsycPacket * p)
{
size_t i;
p->routingLength = 0;
p->contentLength = 0;
// add routing header length
for (i = 0; i < p->routing.lines; i++)
p->routingLength += psyc_modifier_length(&(p->routing.modifiers[i]));
if (p->content.length)
p->contentLength = p->content.length;
else {
// add state operation
if (p->stateop != PSYC_STATE_NOOP)
p->contentLength += 2; // op\n
// add entity header length
for (i = 0; i < p->entity.lines; i++) for (i = 0; i < p->entity.lines; i++)
if (p->entity.modifiers[i].flag == PSYC_MODIFIER_NEED_LENGTH) p->contentLength += psyc_modifier_length(&(p->entity.modifiers[i]));
return PSYC_PACKET_NEED_LENGTH;
if (memmem(p->data.data, p->data.length, PSYC_C2ARG(PSYC_PACKET_DELIMITER))) // add length of method, data & delimiter
return PSYC_PACKET_NEED_LENGTH; if (p->method.length)
p->contentLength += p->method.length + 1; // method\n
if (p->data.length)
p->contentLength += p->data.length + 1; // data\n
}
return PSYC_PACKET_NO_LENGTH; // set total length: routing-header content |\n
p->length = p->routingLength + p->contentLength + 2;
if (p->contentLength > 0 || p->flag == PSYC_PACKET_NEED_LENGTH)
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 += psyc_num_length(p->contentLength);
return p->length;
} }
inline inline void
size_t psyc_packet_length_set (PsycPacket *p) psyc_packet_init (PsycPacket * p,
PsycModifier * routing, size_t routinglen,
PsycModifier * entity, size_t entitylen,
char *method, size_t methodlen,
char *data, size_t datalen,
char stateop, PsycPacketFlag flag)
{ {
size_t i; *p = (PsycPacket) {{routinglen, routing}, {entitylen, entity}, stateop,
p->routingLength = 0; {methodlen, method}, {datalen, data}, {0, 0}, 0, 0, flag};
p->contentLength = 0;
// add routing header length if (flag == PSYC_PACKET_CHECK_LENGTH) // find out if it needs length
for (i = 0; i < p->routing.lines; i++) p->flag = psyc_packet_length_check(p);
p->routingLength += psyc_modifier_length(&(p->routing.modifiers[i]));
if (p->content.length) psyc_packet_length_set(p);
p->contentLength = p->content.length;
else
{
// add state operation
if (p->stateop != PSYC_STATE_NOOP)
p->contentLength += 2; // op\n
// add entity header length
for (i = 0; i < p->entity.lines; i++)
p->contentLength += psyc_modifier_length(&(p->entity.modifiers[i]));
// add length of method, data & delimiter
if (p->method.length)
p->contentLength += p->method.length + 1; // method\n
if (p->data.length)
p->contentLength += p->data.length + 1; // data\n
}
// set total length: routing-header content |\n
p->length = p->routingLength + p->contentLength + 2;
if (p->contentLength > 0 || p->flag == PSYC_PACKET_NEED_LENGTH)
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 += psyc_num_length(p->contentLength);
return p->length;
} }
inline inline void
void psyc_packet_init (PsycPacket *p, psyc_packet_init_raw (PsycPacket * p,
PsycModifier *routing, size_t routinglen, PsycModifier * routing, size_t routinglen,
PsycModifier *entity, size_t entitylen, char *content, size_t contentlen,
char *method, size_t methodlen, PsycPacketFlag flag)
char *data, size_t datalen,
char stateop, PsycPacketFlag flag)
{ {
*p = (PsycPacket) {{routinglen, routing}, {entitylen, entity}, stateop, *p = (PsycPacket) {{routinglen, routing}, {0, 0}, 0, {0, 0}, {0, 0},
{methodlen, method}, {datalen, data}, {0,0}, 0, 0, flag}; {contentlen, content}, 0, 0, flag};
if (flag == PSYC_PACKET_CHECK_LENGTH) // find out if it needs length if (flag == PSYC_PACKET_CHECK_LENGTH) // find out if it needs length
p->flag = psyc_packet_length_check(p); p->flag = psyc_packet_length_check(p);
psyc_packet_length_set(p); psyc_packet_length_set(p);
}
inline
void psyc_packet_init_raw (PsycPacket *p,
PsycModifier *routing, size_t routinglen,
char *content, size_t contentlen,
PsycPacketFlag flag)
{
*p = (PsycPacket) {{routinglen, routing}, {0,0}, 0, {0,0}, {0,0},
{contentlen, content}, 0, 0, flag};
if (flag == PSYC_PACKET_CHECK_LENGTH) // find out if it needs length
p->flag = psyc_packet_length_check(p);
psyc_packet_length_set(p);
} }

View file

@ -9,19 +9,18 @@
#include <psyc/packet.h> #include <psyc/packet.h>
#include <psyc/parse.h> #include <psyc/parse.h>
#define ADVANCE_CURSOR_OR_RETURN(ret) \ #define ADVANCE_CURSOR_OR_RETURN(ret) \
if (++(state->cursor) >= state->buffer.length) \ if (++(state->cursor) >= state->buffer.length) { \
{ \ state->cursor = state->startc; \
state->cursor = state->startc; \ return ret; \
return ret; \ }
}
typedef enum { typedef enum {
PARSE_ERROR = -1, PARSE_ERROR = -1,
PARSE_SUCCESS = 0, PARSE_SUCCESS = 0,
PARSE_INSUFFICIENT = 1, PARSE_INSUFFICIENT = 1,
PARSE_COMPLETE = 100, PARSE_COMPLETE = 100,
PARSE_INCOMPLETE = 101, PARSE_INCOMPLETE = 101,
} ParseRC; } ParseRC;
/** /**
@ -29,19 +28,18 @@ typedef enum {
* It should contain one or more keyword characters. * It should contain one or more keyword characters.
* @return PARSE_ERROR or PARSE_SUCCESS * @return PARSE_ERROR or PARSE_SUCCESS
*/ */
static inline static inline ParseRC
ParseRC psyc_parse_keyword (PsycParseState *state, PsycString *name) psyc_parse_keyword (PsycParseState *state, PsycString *name)
{ {
name->data = state->buffer.data + state->cursor; name->data = state->buffer.data + state->cursor;
name->length = 0; name->length = 0;
while (psyc_is_kw_char(state->buffer.data[state->cursor])) while (psyc_is_kw_char(state->buffer.data[state->cursor])) {
{ name->length++; // was a valid char, increase length
name->length++; // was a valid char, increase length ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT); }
}
return name->length > 0 ? PARSE_SUCCESS : PARSE_ERROR; return name->length > 0 ? PARSE_SUCCESS : PARSE_ERROR;
} }
/** /**
@ -54,490 +52,448 @@ ParseRC psyc_parse_keyword (PsycParseState *state, PsycString *name)
* *
* @return PARSE_COMPLETE or PARSE_INCOMPLETE * @return PARSE_COMPLETE or PARSE_INCOMPLETE
*/ */
static inline static inline ParseRC
ParseRC psyc_parse_binary_value (PsycParseState *state, PsycString *value, psyc_parse_binary_value (PsycParseState *state, PsycString *value,
size_t *length, size_t *parsed) size_t *length, size_t *parsed)
{ {
size_t remaining = *length - *parsed; size_t remaining = *length - *parsed;
value->data = state->buffer.data + state->cursor; value->data = state->buffer.data + state->cursor;
if (state->cursor + remaining > state->buffer.length) if (state->cursor + remaining > state->buffer.length) {
{ // value doesn't fit in the buffer completely // value doesn't fit in the buffer completely
value->length = state->buffer.length - state->cursor; value->length = state->buffer.length - state->cursor;
state->cursor += value->length; state->cursor += value->length;
*parsed += value->length; *parsed += value->length;
return PARSE_INCOMPLETE; return PARSE_INCOMPLETE;
} }
value->length = remaining; value->length = remaining;
state->cursor += remaining; state->cursor += remaining;
*parsed += remaining; *parsed += remaining;
assert(*parsed == *length); assert(*parsed == *length);
return PARSE_COMPLETE; return PARSE_COMPLETE;
} }
/** /**
* Parse simple or binary variable. * Parse simple or binary variable.
* @return PARSE_ERROR or PARSE_SUCCESS * @return PARSE_ERROR or PARSE_SUCCESS
*/ */
static inline static inline ParseRC
ParseRC psyc_parse_modifier (PsycParseState *state, char *oper, psyc_parse_modifier (PsycParseState *state, char *oper,
PsycString *name, PsycString *value) PsycString *name, PsycString *value)
{ {
*oper = *(state->buffer.data + state->cursor); *oper = *(state->buffer.data + state->cursor);
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
ParseRC ret = psyc_parse_keyword(state, name);
if (ret == PARSE_ERROR)
return PSYC_PARSE_ERROR_MOD_NAME;
else if (ret != PARSE_SUCCESS)
return ret;
size_t length = 0;
value->length = 0;
state->valueLength = 0;
state->valueLengthFound = 0;
state->valueParsed = 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.data[state->cursor] == ' ') {
// binary arg
// After SP the length follows.
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT); ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
ParseRC ret = psyc_parse_keyword(state, name); if (psyc_is_numeric(state->buffer.data[state->cursor])) {
if (ret == PARSE_ERROR) state->valueLengthFound = 1;
return PSYC_PARSE_ERROR_MOD_NAME; do {
else if (ret != PARSE_SUCCESS) length = 10 * length + state->buffer.data[state->cursor] - '0';
return ret;
size_t length = 0;
value->length = 0;
state->valueLength = 0;
state->valueLengthFound = 0;
state->valueParsed = 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.data[state->cursor] == ' ') // binary arg
{ // After SP the length follows.
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT); ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
}
while (psyc_is_numeric(state->buffer.data[state->cursor]));
state->valueLength = length;
} else
return PSYC_PARSE_ERROR_MOD_LEN;
if (psyc_is_numeric(state->buffer.data[state->cursor])) // After the length a TAB follows.
{ if (state->buffer.data[state->cursor] != '\t')
state->valueLengthFound = 1; return PSYC_PARSE_ERROR_MOD_TAB;
do
{
length = 10 * length + state->buffer.data[state->cursor] - '0';
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
}
while (psyc_is_numeric(state->buffer.data[state->cursor]));
state->valueLength = length;
}
else
return PSYC_PARSE_ERROR_MOD_LEN;
// After the length a TAB follows. if (++(state->cursor) >= state->buffer.length)
if (state->buffer.data[state->cursor] != '\t') return length ? PARSE_INCOMPLETE : PARSE_SUCCESS; // if length=0 we're done
return PSYC_PARSE_ERROR_MOD_TAB;
if (++(state->cursor) >= state->buffer.length) ret =
return length ? PARSE_INCOMPLETE : PARSE_SUCCESS; // if length=0 we're done psyc_parse_binary_value(state, value, &(state->valueLength),
&(state->valueParsed));
if (ret == PARSE_INCOMPLETE)
return ret;
ret = psyc_parse_binary_value(state, value, &(state->valueLength), &(state->valueParsed)); return PARSE_SUCCESS;
if (ret == PARSE_INCOMPLETE) } else if (state->buffer.data[state->cursor] == '\t') { // simple arg
return ret; ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
value->data = state->buffer.data + state->cursor;
return PARSE_SUCCESS; while (state->buffer.data[state->cursor] != '\n') {
value->length++;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
} }
else if (state->buffer.data[state->cursor] == '\t') // simple arg
{
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
value->data = state->buffer.data + state->cursor;
while (state->buffer.data[state->cursor] != '\n') return PARSE_SUCCESS;
{ } else
value->length++; return PSYC_PARSE_ERROR_MOD_TAB;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
}
return PARSE_SUCCESS;
}
else
return PSYC_PARSE_ERROR_MOD_TAB;
} }
/** Parse PSYC packets. */ /** Parse PSYC packets. */
#ifdef __INLINE_PSYC_PARSE #ifdef __INLINE_PSYC_PARSE
static inline static inline
#endif #endif
PsycParseRC psyc_parse (PsycParseState *state, char *oper, PsycParseRC
PsycString *name, PsycString *value) psyc_parse (PsycParseState *state, char *oper,
PsycString *name, PsycString *value)
{ {
#ifdef DEBUG #ifdef DEBUG
if (state->flags & PSYC_PARSE_ROUTING_ONLY && if (state->flags & PSYC_PARSE_ROUTING_ONLY &&
state->flags & PSYC_PARSE_START_AT_CONTENT) state->flags & PSYC_PARSE_START_AT_CONTENT)
PP(("Invalid flag combination")) PP(("Invalid flag combination"));
#endif #endif
ParseRC ret; // a return value
size_t pos = state->cursor; // a cursor position
ParseRC ret; // a return value // Start position of the current line in the buffer
size_t pos = state->cursor; // a cursor position // in case we return insufficent, we rewind to this position.
state->startc = state->cursor;
// Start position of the current line in the buffer // First we test if we can access the first char.
// in case we return insufficent, we rewind to this position. if (state->cursor >= state->buffer.length) // Cursor is not inside the length.
state->startc = state->cursor; return PSYC_PARSE_INSUFFICIENT;
// First we test if we can access the first char. switch (state->part) {
if (state->cursor >= state->buffer.length) // cursor is not inside the length case PSYC_PART_RESET: // New packet starts here, reset state.
return PSYC_PARSE_INSUFFICIENT; state->valueParsed = 0;
state->valueLength = 0;
state->valueLengthFound = 0;
state->routingLength = 0;
state->contentParsed = 0;
state->contentLength = 0;
state->contentLengthFound = 0;
state->part = PSYC_PART_ROUTING;
// fall thru
switch (state->part) case PSYC_PART_ROUTING:
{ if (state->routingLength > 0) {
case PSYC_PART_RESET: // New packet starts here, reset state. if (state->buffer.data[state->cursor] != '\n')
state->valueParsed = 0; return PSYC_PARSE_ERROR_MOD_NL;
state->valueLength = 0; ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
state->valueLengthFound = 0;
state->routingLength = 0;
state->contentParsed = 0;
state->contentLength = 0;
state->contentLengthFound = 0;
state->part = PSYC_PART_ROUTING;
// fall thru
case PSYC_PART_ROUTING:
if (state->routingLength > 0)
{
if (state->buffer.data[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 (psyc_is_glyph(state->buffer.data[state->cursor])) // is the first char a glyph?
{ // it is a glyph, so a variable starts here
ret = psyc_parse_modifier(state, oper, name, value);
state->routingLength += state->cursor - pos;
return ret == PARSE_SUCCESS ? PSYC_PARSE_ROUTING : ret;
}
else // not a glyph
{
state->part = PSYC_PART_LENGTH;
state->startc = state->cursor;
// fall thru
}
case PSYC_PART_LENGTH:
// End of header, content starts with an optional length then a NL
if (psyc_is_numeric(state->buffer.data[state->cursor]))
{
state->contentLengthFound = 1;
state->contentLength = 0;
do
{
state->contentLength = 10 * state->contentLength + state->buffer.data[state->cursor] - '0';
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
}
while (psyc_is_numeric(state->buffer.data[state->cursor]));
}
if (state->buffer.data[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 (state->flags & PSYC_PARSE_ROUTING_ONLY)
{
state->part = PSYC_PART_DATA;
if (++(state->cursor) >= state->buffer.length)
return PSYC_PARSE_INSUFFICIENT;
goto PSYC_PART_DATA;
}
else
state->part = PSYC_PART_CONTENT;
}
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 (state->contentLengthFound)
return PSYC_PARSE_ERROR_LENGTH;
state->part = PSYC_PART_END;
goto PSYC_PART_END;
}
state->startc = state->cursor + 1;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
// fall thru
case PSYC_PART_CONTENT:
// In case of an incomplete binary variable resume parsing it.
if (state->valueParsed < state->valueLength)
{
ret = psyc_parse_binary_value(state, value, &(state->valueLength), &(state->valueParsed));
state->contentParsed += value->length;
if (ret == PARSE_INCOMPLETE)
return PSYC_PARSE_ENTITY_CONT;
return PSYC_PARSE_ENTITY_END;
}
pos = state->cursor;
if (state->contentParsed > 0)
{
if (state->buffer.data[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.
// In the body, the same applies, only that the
// method does not start with a glyph.
if (psyc_is_glyph(state->buffer.data[state->cursor]))
{
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
if (state->contentParsed == 0 && state->buffer.data[state->cursor] == '\n')
{
*oper = *(state->buffer.data + state->cursor - 1);
switch (*oper)
{
case PSYC_STATE_RESYNC:
state->contentParsed += 2;
return PSYC_PARSE_STATE_RESYNC;
case PSYC_STATE_RESET:
state->contentParsed += 2;
return PSYC_PARSE_STATE_RESET;
default:
return PSYC_PARSE_ERROR_MOD_NAME;
}
}
state->cursor--;
ret = psyc_parse_modifier(state, oper, name, value);
state->contentParsed += state->cursor - pos;
if (ret == PARSE_INCOMPLETE)
return PSYC_PARSE_ENTITY_START;
else if (ret == PARSE_SUCCESS)
return PSYC_PARSE_ENTITY;
return ret;
}
else
{
state->contentParsed += state->cursor - pos;
state->startc = state->cursor;
state->part = PSYC_PART_METHOD;
// fall thru
}
case PSYC_PART_METHOD:
pos = state->cursor;
ret = psyc_parse_keyword(state, name);
if (ret == PARSE_INSUFFICIENT)
return ret;
else if (ret == PARSE_SUCCESS)
{ // the method ends with a \n then the data follows
if (state->buffer.data[state->cursor] != '\n')
return PSYC_PARSE_ERROR_METHOD;
state->valueLengthFound = 0;
state->valueParsed = 0;
state->valueLength = 0;
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);
}
}
else // No method, which means the packet should end now.
{
state->part = PSYC_PART_END;
state->startc = state->cursor;
goto PSYC_PART_END;
}
// fall thru
case PSYC_PART_DATA:
PSYC_PART_DATA:
value->data = state->buffer.data + state->cursor;
value->length = 0;
if (state->contentLengthFound) // We know the length of the packet.
{
if (!state->valueLengthFound) // start of data
{
state->valueLengthFound = 1;
state->valueLength = state->contentLength - state->contentParsed; // length of data
if (state->valueLength && !(state->flags & PSYC_PARSE_ROUTING_ONLY))
state->valueLength--; // \n at the end is not part of data
}
if (state->valueParsed < state->valueLength)
{
ret = psyc_parse_binary_value(state, value, &(state->valueLength), &(state->valueParsed));
state->contentParsed += value->length;
if (ret == PARSE_INCOMPLETE)
return state->valueParsed == value->length ? PSYC_PARSE_BODY_START : PSYC_PARSE_BODY_CONT;
}
state->part = PSYC_PART_END;
return state->valueLength == value->length ? PSYC_PARSE_BODY : PSYC_PARSE_BODY_END;
}
else // Search for the terminator.
{
size_t datac = state->cursor; // start of data
if (state->flags & PSYC_PARSE_ROUTING_ONLY)
state->startc = datac; // in routing-only mode restart from the start of data
while (1)
{
uint8_t nl = state->buffer.data[state->cursor] == '\n';
// check for |\n if we're at the start of data or we have found a \n
if (state->cursor == datac || nl)
{
if (state->cursor+1+nl >= state->buffer.length) // incremented cursor inside length?
{
state->cursor = state->startc;
return PSYC_PARSE_INSUFFICIENT;
}
if (state->buffer.data[state->cursor+nl] == '|' &&
state->buffer.data[state->cursor+1+nl] == '\n') // packet ends here
{
if (state->flags & PSYC_PARSE_ROUTING_ONLY)
value->length++;
state->contentParsed += state->cursor - pos;
state->cursor += nl;
state->part = PSYC_PART_END;
return PSYC_PARSE_BODY;
}
}
value->length++;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
}
}
case PSYC_PART_END:
PSYC_PART_END:
if (state->contentLengthFound && state->valueLengthFound && state->valueLength &&
!(state->flags & PSYC_PARSE_ROUTING_ONLY))
{ // if data was not empty next is the \n at the end of data
state->valueLength = 0;
state->valueLengthFound = 0;
if (state->buffer.data[state->cursor] != '\n')
return PSYC_PARSE_ERROR_END;
state->contentParsed++;
state->cursor++;
}
// 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_PARSE_INSUFFICIENT;
if (state->buffer.data[state->cursor] == '|' &&
state->buffer.data[state->cursor+1] == '\n') // packet ends here
{
state->cursor += 2;
state->part = PSYC_PART_RESET;
return PSYC_PARSE_COMPLETE;
}
else // packet should've ended here, return error
{
state->part = PSYC_PART_RESET;
return PSYC_PARSE_ERROR_END;
}
} }
return PSYC_PARSE_ERROR; // should not be reached // 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 (psyc_is_glyph(state->buffer.data[state->cursor])) {
// it is a glyph, so a variable starts here
ret = psyc_parse_modifier(state, oper, name, value);
state->routingLength += state->cursor - pos;
return ret == PARSE_SUCCESS ? PSYC_PARSE_ROUTING : ret;
} else { // not a glyph
state->part = PSYC_PART_LENGTH;
state->startc = state->cursor;
// fall thru
}
case PSYC_PART_LENGTH:
// End of header, content starts with an optional length then a NL
if (psyc_is_numeric(state->buffer.data[state->cursor])) {
state->contentLengthFound = 1;
state->contentLength = 0;
do {
state->contentLength =
10 * state->contentLength +
state->buffer.data[state->cursor] - '0';
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
} while (psyc_is_numeric(state->buffer.data[state->cursor]));
}
if (state->buffer.data[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 (state->flags & PSYC_PARSE_ROUTING_ONLY) {
state->part = PSYC_PART_DATA;
if (++(state->cursor) >= state->buffer.length)
return PSYC_PARSE_INSUFFICIENT;
goto PSYC_PART_DATA;
} else
state->part = PSYC_PART_CONTENT;
} 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 (state->contentLengthFound)
return PSYC_PARSE_ERROR_LENGTH;
state->part = PSYC_PART_END;
goto PSYC_PART_END;
}
state->startc = state->cursor + 1;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
// fall thru
case PSYC_PART_CONTENT:
// In case of an incomplete binary variable resume parsing it.
if (state->valueParsed < state->valueLength) {
ret = psyc_parse_binary_value(state, value, &(state->valueLength),
&(state->valueParsed));
state->contentParsed += value->length;
if (ret == PARSE_INCOMPLETE)
return PSYC_PARSE_ENTITY_CONT;
return PSYC_PARSE_ENTITY_END;
}
pos = state->cursor;
if (state->contentParsed > 0) {
if (state->buffer.data[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.
// In the body, the same applies, only that the
// method does not start with a glyph.
if (psyc_is_glyph(state->buffer.data[state->cursor])) {
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
if (state->contentParsed == 0
&& state->buffer.data[state->cursor] == '\n') {
*oper = *(state->buffer.data + state->cursor - 1);
switch (*oper) {
case PSYC_STATE_RESYNC:
state->contentParsed += 2;
return PSYC_PARSE_STATE_RESYNC;
case PSYC_STATE_RESET:
state->contentParsed += 2;
return PSYC_PARSE_STATE_RESET;
default:
return PSYC_PARSE_ERROR_MOD_NAME;
}
}
state->cursor--;
ret = psyc_parse_modifier(state, oper, name, value);
state->contentParsed += state->cursor - pos;
if (ret == PARSE_INCOMPLETE)
return PSYC_PARSE_ENTITY_START;
else if (ret == PARSE_SUCCESS)
return PSYC_PARSE_ENTITY;
return ret;
} else {
state->contentParsed += state->cursor - pos;
state->startc = state->cursor;
state->part = PSYC_PART_METHOD;
// fall thru
}
case PSYC_PART_METHOD:
pos = state->cursor;
ret = psyc_parse_keyword(state, name);
if (ret == PARSE_INSUFFICIENT)
return ret;
else if (ret == PARSE_SUCCESS) {
// The method ends with a \n then the data follows.
if (state->buffer.data[state->cursor] != '\n')
return PSYC_PARSE_ERROR_METHOD;
state->valueLengthFound = 0;
state->valueParsed = 0;
state->valueLength = 0;
if (state->contentLengthFound) {
// Length 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);
}
} else { // No method, which means the packet should end now.
state->part = PSYC_PART_END;
state->startc = state->cursor;
goto PSYC_PART_END;
}
// fall thru
case PSYC_PART_DATA:
PSYC_PART_DATA:
value->data = state->buffer.data + state->cursor;
value->length = 0;
if (state->contentLengthFound) { // We know the length of the packet.
if (!state->valueLengthFound) { // start of data
state->valueLengthFound = 1;
state->valueLength = state->contentLength - state->contentParsed;
if (state->valueLength && !(state->flags & PSYC_PARSE_ROUTING_ONLY))
state->valueLength--; // \n at the end is not part of data
}
if (state->valueParsed < state->valueLength) {
ret = psyc_parse_binary_value(state, value, &(state->valueLength),
&(state->valueParsed));
state->contentParsed += value->length;
if (ret == PARSE_INCOMPLETE)
return state->valueParsed == value->length
? PSYC_PARSE_BODY_START : PSYC_PARSE_BODY_CONT;
}
state->part = PSYC_PART_END;
return state->valueLength == value->length ?
PSYC_PARSE_BODY : PSYC_PARSE_BODY_END;
} else { // Search for the terminator.
size_t datac = state->cursor; // start of data
if (state->flags & PSYC_PARSE_ROUTING_ONLY) // in routing-only mode restart
state->startc = datac; // from the start of data
while (1) {
uint8_t nl = state->buffer.data[state->cursor] == '\n';
// check for |\n if we're at the start of data or we have found a \n
if (state->cursor == datac || nl) {
// incremented cursor inside length?
if (state->cursor + 1 + nl >= state->buffer.length) {
state->cursor = state->startc;
return PSYC_PARSE_INSUFFICIENT;
}
if (state->buffer.data[state->cursor + nl] == '|'
&& state->buffer.data[state->cursor + 1 + nl] == '\n') {
// packet ends here
if (state->flags & PSYC_PARSE_ROUTING_ONLY)
value->length++;
state->contentParsed += state->cursor - pos;
state->cursor += nl;
state->part = PSYC_PART_END;
return PSYC_PARSE_BODY;
}
}
value->length++;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
}
}
case PSYC_PART_END:
PSYC_PART_END:
// if data was not empty next is the \n at the end of data
if (state->contentLengthFound && state->valueLengthFound
&& state->valueLength && !(state->flags & PSYC_PARSE_ROUTING_ONLY)) {
state->valueLength = 0;
state->valueLengthFound = 0;
if (state->buffer.data[state->cursor] != '\n')
return PSYC_PARSE_ERROR_END;
state->contentParsed++;
state->cursor++;
}
// 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)
return PSYC_PARSE_INSUFFICIENT;
if (state->buffer.data[state->cursor] == '|'
&& state->buffer.data[state->cursor + 1] == '\n') {
// Packet ends here.
state->cursor += 2;
state->part = PSYC_PART_RESET;
return PSYC_PARSE_COMPLETE;
} else { // Packet should've ended here, return error.
state->part = PSYC_PART_RESET;
return PSYC_PARSE_ERROR_END;
}
}
return PSYC_PARSE_ERROR; // should not be reached
} }
/** List parser. */ /** List parser. */
#ifdef __INLINE_PSYC_PARSE #ifdef __INLINE_PSYC_PARSE
static inline static inline
#endif #endif
PsycParseListRC psyc_parse_list (PsycParseListState *state, PsycString *elem) PsycParseListRC
psyc_parse_list (PsycParseListState *state, PsycString *elem)
{ {
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_LIST_INCOMPLETE;
state->startc = state->cursor;
if (!state->type) { // If type is not set we're at the start.
// First character is either | for text lists, or a number for binary lists
if (state->buffer.data[state->cursor] == '|') {
state->type = PSYC_LIST_TEXT;
state->cursor++;
} else if (psyc_is_numeric(state->buffer.data[state->cursor]))
state->type = PSYC_LIST_BINARY;
else
return PSYC_PARSE_LIST_ERROR_TYPE;
}
if (state->type == PSYC_LIST_TEXT) {
elem->data = state->buffer.data + state->cursor;
elem->length = 0;
if (state->cursor >= state->buffer.length) if (state->cursor >= state->buffer.length)
return PSYC_PARSE_LIST_END;
while (state->buffer.data[state->cursor] != '|') {
elem->length++;
if (++(state->cursor) >= state->buffer.length)
return PSYC_PARSE_LIST_END;
}
state->cursor++;
return PSYC_PARSE_LIST_ELEM;
} else { // binary list
if (!(state->elemParsed < state->elemLength)) {
// Element starts with a number.
if (psyc_is_numeric(state->buffer.data[state->cursor])) {
do {
state->elemLength =
10 * state->elemLength +
state->buffer.data[state->cursor] - '0';
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_LIST_INCOMPLETE);
} while (psyc_is_numeric(state->buffer.data[state->cursor]));
} else
return PSYC_PARSE_LIST_ERROR_LEN;
if (state->buffer.data[state->cursor] != ' ')
return PSYC_PARSE_LIST_ERROR_LEN;
state->cursor++;
elem->data = state->buffer.data + state->cursor;
elem->length = 0;
state->elemParsed = 0;
}
// Start or resume parsing the binary data
if (state->elemParsed < state->elemLength) {
if (PARSE_INCOMPLETE == psyc_parse_binary_value((PsycParseState*)state,
elem, &state->elemLength,
&state->elemParsed))
return PSYC_PARSE_LIST_INCOMPLETE; return PSYC_PARSE_LIST_INCOMPLETE;
state->startc = state->cursor; state->elemLength = 0;
if (!state->type) // If type is not set we're at the start if (state->cursor >= state->buffer.length)
{ return PSYC_PARSE_LIST_END;
// First character is either | for text lists, or a number for binary lists
if (state->buffer.data[state->cursor] == '|') if (state->buffer.data[state->cursor] != '|')
{ return PSYC_PARSE_LIST_ERROR_DELIM;
state->type = PSYC_LIST_TEXT;
state->cursor++; state->cursor++;
} return PSYC_PARSE_LIST_ELEM;
else if (psyc_is_numeric(state->buffer.data[state->cursor]))
state->type = PSYC_LIST_BINARY;
else
return PSYC_PARSE_LIST_ERROR_TYPE;
} }
}
if (state->type == PSYC_LIST_TEXT) return PSYC_PARSE_LIST_ERROR; // should not be reached
{
elem->data = state->buffer.data + state->cursor;
elem->length = 0;
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_LIST_END;
while (state->buffer.data[state->cursor] != '|')
{
elem->length++;
if (++(state->cursor) >= state->buffer.length)
return PSYC_PARSE_LIST_END;
}
state->cursor++;
return PSYC_PARSE_LIST_ELEM;
}
else // binary list
{
if (!(state->elemParsed < state->elemLength))
{
// Element starts with a number.
if (psyc_is_numeric(state->buffer.data[state->cursor]))
{
do
{
state->elemLength = 10 * state->elemLength + state->buffer.data[state->cursor] - '0';
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_LIST_INCOMPLETE);
}
while (psyc_is_numeric(state->buffer.data[state->cursor]));
}
else
return PSYC_PARSE_LIST_ERROR_LEN;
if (state->buffer.data[state->cursor] != ' ')
return PSYC_PARSE_LIST_ERROR_LEN;
state->cursor++;
elem->data = state->buffer.data + state->cursor;
elem->length = 0;
state->elemParsed = 0;
}
// Start or resume parsing the binary data
if (state->elemParsed < state->elemLength)
{
if (psyc_parse_binary_value((PsycParseState*)state, elem,
&(state->elemLength), &(state->elemParsed)) == PARSE_INCOMPLETE)
return PSYC_PARSE_LIST_INCOMPLETE;
state->elemLength = 0;
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_LIST_END;
if (state->buffer.data[state->cursor] != '|')
return PSYC_PARSE_LIST_ERROR_DELIM;
state->cursor++;
return PSYC_PARSE_LIST_ELEM;
}
}
return PSYC_PARSE_LIST_ERROR; // should not be reached
} }

View file

@ -6,134 +6,123 @@
#ifdef __INLINE_PSYC_RENDER #ifdef __INLINE_PSYC_RENDER
static inline static inline
#endif #endif
PsycRenderListRC psyc_render_list (PsycList *list, char *buffer, size_t buflen) PsycRenderListRC
psyc_render_list (PsycList * list, char *buffer, size_t buflen)
{ {
size_t i, cur = 0; size_t i, cur = 0;
PsycString *elem; PsycString *elem;
if (list->length > buflen) // return error if list doesn't fit in buffer if (list->length > buflen) // return error if list doesn't fit in buffer
return PSYC_RENDER_LIST_ERROR; return PSYC_RENDER_LIST_ERROR;
if (list->flag == PSYC_LIST_NEED_LENGTH) if (list->flag == PSYC_LIST_NEED_LENGTH) {
{ for (i = 0; i < list->num_elems; i++) {
for (i = 0; i < list->num_elems; i++) elem = &list->elems[i];
{ if (i > 0)
elem = &list->elems[i]; buffer[cur++] = '|';
if (i > 0) cur += itoa(elem->length, buffer + cur, 10);
buffer[cur++] = '|'; buffer[cur++] = ' ';
cur += itoa(elem->length, buffer + cur, 10); memcpy(buffer + cur, elem->data, elem->length);
buffer[cur++] = ' '; cur += elem->length;
memcpy(buffer + cur, elem->data, elem->length);
cur += elem->length;
}
} }
else } else {
{ for (i = 0; i < list->num_elems; i++) {
for (i = 0; i < list->num_elems; i++) elem = &list->elems[i];
{ buffer[cur++] = '|';
elem = &list->elems[i]; memcpy(buffer + cur, elem->data, elem->length);
buffer[cur++] = '|'; cur += elem->length;
memcpy(buffer + cur, elem->data, elem->length);
cur += elem->length;
}
} }
}
// actual length should be equal to pre-calculated length at this point // Actual length should be equal to pre-calculated length at this point.
assert(cur == list->length); assert(cur == list->length);
return PSYC_RENDER_LIST_SUCCESS; return PSYC_RENDER_LIST_SUCCESS;
} }
static inline static inline size_t
size_t psyc_render_modifier (PsycModifier *mod, char *buffer) psyc_render_modifier (PsycModifier * mod, char *buffer)
{ {
size_t cur = 0; size_t cur = 0;
buffer[cur++] = mod->oper; buffer[cur++] = mod->oper;
memcpy(buffer + cur, mod->name.data, mod->name.length); memcpy(buffer + cur, mod->name.data, mod->name.length);
cur += mod->name.length; cur += mod->name.length;
if (cur == 1) if (cur == 1)
return cur; // error, name can't be empty return cur; // error, name can't be empty
if (mod->flag == PSYC_MODIFIER_NEED_LENGTH) if (mod->flag == PSYC_MODIFIER_NEED_LENGTH) {
{ buffer[cur++] = ' ';
buffer[cur++] = ' '; cur += itoa(mod->value.length, buffer + cur, 10);
cur += itoa(mod->value.length, buffer + cur, 10); }
}
buffer[cur++] = '\t'; buffer[cur++] = '\t';
memcpy(buffer + cur, mod->value.data, mod->value.length); memcpy(buffer + cur, mod->value.data, mod->value.length);
cur += mod->value.length; cur += mod->value.length;
buffer[cur++] = '\n'; buffer[cur++] = '\n';
return cur; return cur;
} }
#ifdef __INLINE_PSYC_RENDER #ifdef __INLINE_PSYC_RENDER
static inline static inline
#endif #endif
PsycRenderRC psyc_render (PsycPacket *packet, char *buffer, size_t buflen) PsycRenderRC
psyc_render (PsycPacket * packet, char *buffer, size_t buflen)
{ {
size_t i, cur = 0, len; size_t i, cur = 0, len;
if (packet->length > buflen) // return error if packet doesn't fit in buffer if (packet->length > buflen) // return error if packet doesn't fit in buffer
return PSYC_RENDER_ERROR; return PSYC_RENDER_ERROR;
// render routing modifiers // render routing modifiers
for (i = 0; i < packet->routing.lines; i++) for (i = 0; i < packet->routing.lines; i++) {
{ len = psyc_render_modifier(&packet->routing.modifiers[i], buffer + cur);
len = psyc_render_modifier(&packet->routing.modifiers[i], buffer + cur); cur += len;
cur += len; if (len <= 1)
if (len <= 1) return PSYC_RENDER_ERROR_MODIFIER_NAME_MISSING;
return PSYC_RENDER_ERROR_MODIFIER_NAME_MISSING; }
// add length if needed
if (packet->flag == PSYC_PACKET_NEED_LENGTH)
cur += itoa(packet->contentLength, buffer + cur, 10);
if (packet->flag == PSYC_PACKET_NEED_LENGTH || packet->content.length
|| packet->stateop || packet->entity.lines
|| packet->method.length || packet->data.length)
buffer[cur++] = '\n'; // start of content part if there's content or length
if (packet->content.length) { // render raw content if present
memcpy(buffer + cur, packet->content.data, packet->content.length);
cur += packet->content.length;
} else {
if (packet->stateop) {
buffer[cur++] = packet->stateop;
buffer[cur++] = '\n';
} }
// render entity modifiers
for (i = 0; i < packet->entity.lines; i++)
cur += psyc_render_modifier(&packet->entity.modifiers[i],
buffer + cur);
// add length if needed if (packet->method.length) { // add method\n
if (packet->flag == PSYC_PACKET_NEED_LENGTH) memcpy(buffer + cur, packet->method.data, packet->method.length);
cur += itoa(packet->contentLength, buffer + cur, 10); cur += packet->method.length;
buffer[cur++] = '\n';
if (packet->flag == PSYC_PACKET_NEED_LENGTH || packet->content.length || if (packet->data.length) { // add data\n
packet->stateop || packet->entity.lines || memcpy(buffer + cur, packet->data.data, packet->data.length);
packet->method.length || packet->data.length) cur += packet->data.length;
buffer[cur++] = '\n'; // start of content part if there's content or length buffer[cur++] = '\n';
}
} else if (packet->data.length) // error, we have data but no modifier
return PSYC_RENDER_ERROR_METHOD_MISSING;
}
if (packet->content.length) // render raw content if present // add packet delimiter
{ buffer[cur++] = PSYC_PACKET_DELIMITER_CHAR;
memcpy(buffer + cur, packet->content.data, packet->content.length); buffer[cur++] = '\n';
cur += packet->content.length;
}
else
{
if (packet->stateop) {
buffer[cur++] = packet->stateop;
buffer[cur++] = '\n';
}
// render entity modifiers // actual length should be equal to pre-calculated length at this point
for (i = 0; i < packet->entity.lines; i++) assert(cur == packet->length);
cur += psyc_render_modifier(&packet->entity.modifiers[i], buffer + cur); return PSYC_RENDER_SUCCESS;
if (packet->method.length) // add method\n
{
memcpy(buffer + cur, packet->method.data, packet->method.length);
cur += packet->method.length;
buffer[cur++] = '\n';
if (packet->data.length) // add data\n
{
memcpy(buffer + cur, packet->data.data, packet->data.length);
cur += packet->data.length;
buffer[cur++] = '\n';
}
}
else if (packet->data.length) // error, we have data but no modifier
return PSYC_RENDER_ERROR_METHOD_MISSING;
}
// add packet delimiter
buffer[cur++] = PSYC_PACKET_DELIMITER_CHAR;
buffer[cur++] = '\n';
// actual length should be equal to pre-calculated length at this point
assert(cur == packet->length);
return PSYC_RENDER_SUCCESS;
} }

View file

@ -1,82 +1,81 @@
#include "lib.h" #include "lib.h"
#include <psyc/text.h> #include <psyc/text.h>
PsycTextRC psyc_text (PsycTextState *state, PsycTextCB getValue, void* extra) PsycTextRC
psyc_text (PsycTextState *state, PsycTextCB getValue, void *extra)
{ {
const char *start = state->tmpl.data, *end; // start & end of variable name const char *start = state->tmpl.data, *end; // start & end of variable name
const char *prev = state->tmpl.data + state->cursor; const char *prev = state->tmpl.data + state->cursor;
PsycString value; PsycString value;
int ret; int ret;
size_t len; size_t len;
uint8_t no_subst = (state->cursor == 0); // whether we can return NO_SUBST uint8_t no_subst = (state->cursor == 0); // whether we can return NO_SUBST
while (state->cursor < state->tmpl.length) while (state->cursor < state->tmpl.length) {
{ start = memmem(state->tmpl.data + state->cursor,
start = memmem(state->tmpl.data + state->cursor, state->tmpl.length - state->cursor,
state->tmpl.length - state->cursor, state->open.data, state->open.length);
state->open.data, state->open.length); if (!start)
if (!start) break;
break;
state->cursor = (start - state->tmpl.data) + state->open.length; state->cursor = (start - state->tmpl.data) + state->open.length;
if (state->cursor >= state->tmpl.length) if (state->cursor >= state->tmpl.length)
break; // [ at the end break; // [ at the end
end = memmem(state->tmpl.data + state->cursor, end = memmem(state->tmpl.data + state->cursor,
state->tmpl.length - state->cursor, state->tmpl.length - state->cursor,
state->close.data, state->close.length); state->close.data, state->close.length);
state->cursor = (end - state->tmpl.data) + state->close.length; state->cursor = (end - state->tmpl.data) + state->close.length;
if (!end) if (!end)
break; // ] not found break; // ] not found
if (start + state->open.length == end) if (start + state->open.length == end) {
{ state->cursor += state->close.length;
state->cursor += state->close.length; continue; // [] is invalid, name can't be empty
continue; // [] is invalid, name can't be empty
}
ret = getValue(start + state->open.length, end - start - state->open.length, &value, extra);
if (ret < 0)
continue; // value not found, no substitution
// 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->tmpl.data;
return PSYC_TEXT_INCOMPLETE;
}
memcpy((void *)(state->buffer.data + state->written), prev, len);
state->written += len;
// now substitute the value if there's enough buffer space
if (state->written + value.length > state->buffer.length)
{
state->cursor = start - state->tmpl.data;
return PSYC_TEXT_INCOMPLETE;
}
memcpy((void *)(state->buffer.data + state->written), value.data, value.length);
state->written += value.length;
// mark the start of the next chunk of text in the template
prev = state->tmpl.data + state->cursor;
no_subst = 0;
} }
if (no_subst) ret = getValue(start + state->open.length,
return PSYC_TEXT_NO_SUBST; end - start - state->open.length, &value, extra);
// copy the rest of the template after the last var if (ret < 0)
len = state->tmpl.length - (prev - state->tmpl.data); continue; // value not found, no substitution
if (state->written + len > state->buffer.length)
return PSYC_TEXT_INCOMPLETE;
memcpy((void *)(state->buffer.data + state->written), prev, len); // 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->tmpl.data;
return PSYC_TEXT_INCOMPLETE;
}
memcpy((void *) (state->buffer.data + state->written), prev, len);
state->written += len; state->written += len;
return PSYC_TEXT_COMPLETE; // Now substitute the value if there's enough buffer space.
if (state->written + value.length > state->buffer.length) {
state->cursor = start - state->tmpl.data;
return PSYC_TEXT_INCOMPLETE;
}
memcpy((void *) (state->buffer.data + state->written), value.data,
value.length);
state->written += value.length;
// Mark the start of the next chunk of text in the template.
prev = state->tmpl.data + state->cursor;
no_subst = 0;
}
if (no_subst)
return PSYC_TEXT_NO_SUBST;
// Copy the rest of the template after the last var.
len = state->tmpl.length - (prev - state->tmpl.data);
if (state->written + len > state->buffer.length)
return PSYC_TEXT_INCOMPLETE;
memcpy((void *) (state->buffer.data + state->written), prev, len);
state->written += len;
return PSYC_TEXT_COMPLETE;
} }

View file

@ -3,177 +3,182 @@
#include "psyc/uniform.h" #include "psyc/uniform.h"
#include "psyc/parse.h" #include "psyc/parse.h"
int psyc_uniform_parse (PsycUniform *uni, char *str, size_t length) int
psyc_uniform_parse (PsycUniform *uni, char *str, size_t length)
{ {
char c; char c;
PsycString *p; PsycString *p;
size_t pos = 0, part = PSYC_UNIFORM_SCHEME; size_t pos = 0, part = PSYC_UNIFORM_SCHEME;
uni->valid = 0; uni->valid = 0;
uni->full.data = str; uni->full.data = str;
uni->full.length = length; uni->full.length = length;
while (pos < length) {
c = str[pos];
if (c == ':') {
uni->scheme.data = str;
uni->scheme.length = pos++;
break;
} else if (!psyc_is_host_char(c))
return PSYC_PARSE_UNIFORM_INVALID_SCHEME;
pos++;
}
p = &uni->scheme;
if (p->length == 4 && (tolower(p->data[0]) == 'p' &&
tolower(p->data[1]) == 's' &&
tolower(p->data[2]) == 'y' &&
tolower(p->data[3]) == 'c')) {
uni->type = PSYC_SCHEME_PSYC;
part = PSYC_UNIFORM_SLASHES;
uni->slashes.data = str + pos;
uni->slashes.length = 0;
while (pos < length) { while (pos < length) {
c = str[pos]; c = str[pos];
if (c == ':') { switch (part) {
uni->scheme.data = str; case PSYC_UNIFORM_SLASHES:
uni->scheme.length = pos++; if (c == '/')
break; uni->slashes.length++;
} else if (!psyc_is_host_char(c)) else
return PSYC_PARSE_UNIFORM_INVALID_SCHEME; return PSYC_PARSE_UNIFORM_INVALID_SLASHES;
pos++;
}
p = &uni->scheme; if (uni->slashes.length == 2) {
if (p->length == 4 && part = PSYC_UNIFORM_HOST;
tolower(p->data[0]) == 'p' && uni->host.data = str + pos + 1;
tolower(p->data[1]) == 's' && uni->host.length = 0;
tolower(p->data[2]) == 'y' && }
tolower(p->data[3]) == 'c') { break;
uni->type = PSYC_SCHEME_PSYC; case PSYC_UNIFORM_HOST:
part = PSYC_UNIFORM_SLASHES; if (psyc_is_host_char(c)) {
uni->slashes.data = str + pos; uni->host.length++;
uni->slashes.length = 0; break;
while (pos < length) {
c = str[pos];
switch (part) {
case PSYC_UNIFORM_SLASHES:
if (c == '/')
uni->slashes.length++;
else return PSYC_PARSE_UNIFORM_INVALID_SLASHES;
if (uni->slashes.length == 2) {
part = PSYC_UNIFORM_HOST;
uni->host.data = str + pos + 1;
uni->host.length = 0;
}
break;
case PSYC_UNIFORM_HOST:
if (psyc_is_host_char(c)) {
uni->host.length++;
break;
}
if (uni->host.length == 0)
return PSYC_PARSE_UNIFORM_INVALID_HOST;
if (c == ':') {
part = PSYC_UNIFORM_PORT;
p = &uni->port;
} else if (c == '/') {
uni->slash.data = str + pos;
uni->slash.length = 1;
part = PSYC_UNIFORM_RESOURCE;
p = &uni->resource;
}
else return PSYC_PARSE_UNIFORM_INVALID_HOST;
p->data = str + pos + 1;
p->length = 0;
break;
case PSYC_UNIFORM_PORT:
if (psyc_is_numeric(c) || (uni->port.length == 0 && c == '-')) {
uni->port.length++;
break;
}
if (uni->port.length == 0 && c != PSYC_TRANSPORT_GNUNET)
return PSYC_PARSE_UNIFORM_INVALID_PORT;
if (c == '/') {
uni->slash.data = str + pos;
uni->slash.length = 1;
part = PSYC_UNIFORM_RESOURCE;
uni->resource.data = str + pos + 1;
uni->resource.length = 0;
break;
}
else {
part = PSYC_UNIFORM_TRANSPORT;
uni->transport.data = str + pos;
uni->transport.length = 0;
}
// fall thru
case PSYC_UNIFORM_TRANSPORT:
switch (c) {
case PSYC_TRANSPORT_GNUNET:
if (uni->port.length > 0)
return PSYC_PARSE_UNIFORM_INVALID_TRANSPORT;
case PSYC_TRANSPORT_TCP:
case PSYC_TRANSPORT_UDP:
case PSYC_TRANSPORT_TLS:
if (uni->transport.length > 0)
return PSYC_PARSE_UNIFORM_INVALID_TRANSPORT;
uni->transport.length++;
break;
case '/':
uni->slash.data = str + pos;
uni->slash.length = 1;
part = PSYC_UNIFORM_RESOURCE;
uni->resource.data = str + pos + 1;
uni->resource.length = 0;
break;
default:
return PSYC_PARSE_UNIFORM_INVALID_TRANSPORT;
}
break;
case PSYC_UNIFORM_RESOURCE:
if (psyc_is_name_char(c)) {
uni->resource.length++;
break;
} else if (c == '#') {
part = PSYC_UNIFORM_CHANNEL;
uni->channel.data = str + pos + 1;
uni->channel.length = 0;
break;
} else return PSYC_PARSE_UNIFORM_INVALID_RESOURCE;
case PSYC_UNIFORM_CHANNEL:
if (psyc_is_name_char(c)) {
uni->channel.length++;
break;
} else return PSYC_PARSE_UNIFORM_INVALID_CHANNEL;
}
pos++;
} }
if (uni->host.length == 0) if (uni->host.length == 0)
return PSYC_PARSE_UNIFORM_INVALID_HOST; return PSYC_PARSE_UNIFORM_INVALID_HOST;
uni->host_port.data = uni->host.data; if (c == ':') {
uni->host_port.length = uni->host.length + uni->port.length + uni->transport.length; part = PSYC_UNIFORM_PORT;
if (uni->port.length > 0 || uni->transport.length > 0) p = &uni->port;
uni->host_port.length++; } else if (c == '/') {
uni->slash.data = str + pos;
uni->slash.length = 1;
uni->root.data = str; part = PSYC_UNIFORM_RESOURCE;
uni->root.length = uni->scheme.length + 1 + uni->slashes.length + p = &uni->resource;
uni->host_port.length; } else
return PSYC_PARSE_UNIFORM_INVALID_HOST;
uni->entity.data = str; p->data = str + pos + 1;
uni->entity.length = uni->root.length + uni->slash.length + uni->resource.length; p->length = 0;
break;
uni->body.data = uni->host.data; case PSYC_UNIFORM_PORT:
uni->body.length = length - uni->scheme.length - 1 - uni->slashes.length; if (psyc_is_numeric(c) || (uni->port.length == 0 && c == '-')) {
uni->port.length++;
if (uni->resource.length) { break;
uni->nick.data = uni->resource.data + 1;
uni->nick.length = uni->resource.length;
} }
} else return PSYC_PARSE_UNIFORM_INVALID_SCHEME; if (uni->port.length == 0 && c != PSYC_TRANSPORT_GNUNET)
return PSYC_PARSE_UNIFORM_INVALID_PORT;
if (uni->host.length == 0) if (c == '/') {
return PSYC_PARSE_UNIFORM_INVALID_HOST; uni->slash.data = str + pos;
uni->slash.length = 1;
uni->valid = 1; part = PSYC_UNIFORM_RESOURCE;
return uni->type; uni->resource.data = str + pos + 1;
uni->resource.length = 0;
break;
} else {
part = PSYC_UNIFORM_TRANSPORT;
uni->transport.data = str + pos;
uni->transport.length = 0;
}
// fall thru
case PSYC_UNIFORM_TRANSPORT:
switch (c) {
case PSYC_TRANSPORT_GNUNET:
if (uni->port.length > 0)
return PSYC_PARSE_UNIFORM_INVALID_TRANSPORT;
case PSYC_TRANSPORT_TCP:
case PSYC_TRANSPORT_UDP:
case PSYC_TRANSPORT_TLS:
if (uni->transport.length > 0)
return PSYC_PARSE_UNIFORM_INVALID_TRANSPORT;
uni->transport.length++;
break;
case '/':
uni->slash.data = str + pos;
uni->slash.length = 1;
part = PSYC_UNIFORM_RESOURCE;
uni->resource.data = str + pos + 1;
uni->resource.length = 0;
break;
default:
return PSYC_PARSE_UNIFORM_INVALID_TRANSPORT;
}
break;
case PSYC_UNIFORM_RESOURCE:
if (psyc_is_name_char(c)) {
uni->resource.length++;
break;
} else if (c == '#') {
part = PSYC_UNIFORM_CHANNEL;
uni->channel.data = str + pos + 1;
uni->channel.length = 0;
break;
} else
return PSYC_PARSE_UNIFORM_INVALID_RESOURCE;
case PSYC_UNIFORM_CHANNEL:
if (psyc_is_name_char(c)) {
uni->channel.length++;
break;
} else
return PSYC_PARSE_UNIFORM_INVALID_CHANNEL;
}
pos++;
}
if (uni->host.length == 0)
return PSYC_PARSE_UNIFORM_INVALID_HOST;
uni->host_port.data = uni->host.data;
uni->host_port.length = uni->host.length + uni->port.length
+ uni->transport.length;
if (uni->port.length > 0 || uni->transport.length > 0)
uni->host_port.length++;
uni->root.data = str;
uni->root.length = uni->scheme.length + 1
+ uni->slashes.length + uni->host_port.length;
uni->entity.data = str;
uni->entity.length = uni->root.length + uni->slash.length
+ uni->resource.length;
uni->body.data = uni->host.data;
uni->body.length = length - uni->scheme.length - 1 - uni->slashes.length;
if (uni->resource.length) {
uni->nick.data = uni->resource.data + 1;
uni->nick.length = uni->resource.length;
}
} else
return PSYC_PARSE_UNIFORM_INVALID_SCHEME;
if (uni->host.length == 0)
return PSYC_PARSE_UNIFORM_INVALID_HOST;
uni->valid = 1;
return uni->type;
} }

View file

@ -3,44 +3,43 @@
/// Routing variables in alphabetical order. /// Routing variables in alphabetical order.
const PsycString psyc_routing_vars[] = const PsycString psyc_routing_vars[] = {
{ PSYC_C2STRI("_amount_fragments"),
PSYC_C2STRI("_amount_fragments"), PSYC_C2STRI("_context"),
PSYC_C2STRI("_context"), //PSYC_C2STRI("_count"), // older PSYC
//PSYC_C2STRI("_count"), // older PSYC PSYC_C2STRI("_counter"), // the name for this is supposed to be _count, not _counter
PSYC_C2STRI("_counter"), // the name for this is supposed to be _count, not _counter PSYC_C2STRI("_fragment"),
PSYC_C2STRI("_fragment"), //PSYC_C2STRI("_length"), // older PSYC
//PSYC_C2STRI("_length"), // older PSYC PSYC_C2STRI("_source"),
PSYC_C2STRI("_source"), //PSYC_C2STRI("_source_identification"), // older PSYC
//PSYC_C2STRI("_source_identification"), // older PSYC PSYC_C2STRI("_source_identity"),
PSYC_C2STRI("_source_identity"), PSYC_C2STRI("_source_relay"),
PSYC_C2STRI("_source_relay"), // until you have a better idea.. is this really in use?
PSYC_C2STRI("_source_relay_relay"), // until you have a better idea.. is this really in use? PSYC_C2STRI("_source_relay_relay"),
PSYC_C2STRI("_tag"), PSYC_C2STRI("_tag"),
PSYC_C2STRI("_tag_relay"), PSYC_C2STRI("_tag_relay"),
//PSYC_C2STRI("_tag_reply"), // older PSYC //PSYC_C2STRI("_tag_reply"), // older PSYC
PSYC_C2STRI("_target"), PSYC_C2STRI("_target"),
PSYC_C2STRI("_target_forward"), PSYC_C2STRI("_target_forward"),
PSYC_C2STRI("_target_relay"), PSYC_C2STRI("_target_relay"),
//PSYC_C2STRI("_understand_modules"), // older PSYC //PSYC_C2STRI("_understand_modules"), // older PSYC
//PSYC_C2STRI("_using_modules"), // older PSYC //PSYC_C2STRI("_using_modules"), // older PSYC
}; };
// Variable types in alphabetical order. // Variable types in alphabetical order.
const PsycDictInt psyc_var_types[] = const PsycDictInt psyc_var_types[] = {
{ {PSYC_C2STRI("_amount"), PSYC_TYPE_AMOUNT},
{PSYC_C2STRI("_amount"), PSYC_TYPE_AMOUNT}, {PSYC_C2STRI("_color"), PSYC_TYPE_COLOR},
{PSYC_C2STRI("_color"), PSYC_TYPE_COLOR}, {PSYC_C2STRI("_date"), PSYC_TYPE_DATE},
{PSYC_C2STRI("_date"), PSYC_TYPE_DATE}, {PSYC_C2STRI("_degree"), PSYC_TYPE_DEGREE},
{PSYC_C2STRI("_degree"), PSYC_TYPE_DEGREE}, {PSYC_C2STRI("_entity"), PSYC_TYPE_ENTITY},
{PSYC_C2STRI("_entity"), PSYC_TYPE_ENTITY}, {PSYC_C2STRI("_flag"), PSYC_TYPE_FLAG},
{PSYC_C2STRI("_flag"), PSYC_TYPE_FLAG}, {PSYC_C2STRI("_language"), PSYC_TYPE_LANGUAGE},
{PSYC_C2STRI("_language"), PSYC_TYPE_LANGUAGE}, {PSYC_C2STRI("_list"), PSYC_TYPE_LIST},
{PSYC_C2STRI("_list"), PSYC_TYPE_LIST}, {PSYC_C2STRI("_nick"), PSYC_TYPE_NICK},
{PSYC_C2STRI("_nick"), PSYC_TYPE_NICK}, {PSYC_C2STRI("_page"), PSYC_TYPE_PAGE},
{PSYC_C2STRI("_page"), PSYC_TYPE_PAGE}, {PSYC_C2STRI("_uniform"), PSYC_TYPE_UNIFORM},
{PSYC_C2STRI("_uniform"), PSYC_TYPE_UNIFORM}, {PSYC_C2STRI("_time"), PSYC_TYPE_TIME},
{PSYC_C2STRI("_time"), PSYC_TYPE_TIME},
}; };
const size_t psyc_routing_vars_num = PSYC_NUM_ELEM(psyc_routing_vars); const size_t psyc_routing_vars_num = PSYC_NUM_ELEM(psyc_routing_vars);
@ -49,51 +48,50 @@ const size_t psyc_var_types_num = PSYC_NUM_ELEM(psyc_var_types);
/** /**
* Get the type of variable name. * Get the type of variable name.
*/ */
inline inline PsycBool
PsycBool psyc_var_is_routing (const char *name, size_t len) psyc_var_is_routing (const char *name, size_t len)
{ {
size_t cursor = 1; size_t cursor = 1;
uint8_t i, m = 0; uint8_t i, m = 0;
int8_t matching[psyc_routing_vars_num]; // indexes of matching vars int8_t matching[psyc_routing_vars_num]; // indexes of matching vars
if (len < 2 || name[0] != '_') if (len < 2 || name[0] != '_')
return PSYC_FALSE; return PSYC_FALSE;
// first find the vars with matching length // first find the vars with matching length
for (i=0; i<psyc_routing_vars_num; i++) for (i = 0; i < psyc_routing_vars_num; i++)
if (len == psyc_routing_vars[i].length) if (len == psyc_routing_vars[i].length)
matching[m++] = i; matching[m++] = i;
matching[m] = -1; // mark the end of matching indexes matching[m] = -1; // mark the end of matching indexes
while (cursor < len && matching[0] >= 0) while (cursor < len && matching[0] >= 0) {
{ for (i = m = 0; i < psyc_routing_vars_num; i++) {
for (i = m = 0; i < psyc_routing_vars_num; i++) if (matching[i] < 0)
{ break; // reached the end of possible matches
if (matching[i] < 0) if (psyc_routing_vars[matching[i]].data[cursor] == name[cursor])
break; // reached the end of possible matches matching[m++] = matching[i]; // found a match, update matching indexes
if (psyc_routing_vars[matching[i]].data[cursor] == name[cursor]) else if (psyc_routing_vars[matching[i]].data[cursor] > name[cursor])
matching[m++] = matching[i]; // found a match, update matching indexes break; // passed the possible matches in alphabetical order in the array
else if (psyc_routing_vars[matching[i]].data[cursor] > name[cursor])
break; // passed the possible matches in alphabetical order in the array
}
if (m < psyc_routing_vars_num)
matching[m] = -1; // mark the end of matching indexes
cursor++;
} }
return matching[0] >= 0 ? PSYC_TRUE : PSYC_FALSE; if (m < psyc_routing_vars_num)
matching[m] = -1; // mark the end of matching indexes
cursor++;
}
return matching[0] >= 0 ? PSYC_TRUE : PSYC_FALSE;
} }
/** /**
* Get the type of variable name. * Get the type of variable name.
*/ */
inline inline PsycType
PsycType psyc_var_type (const char *name, size_t len) psyc_var_type (const char *name, size_t len)
{ {
int8_t m[psyc_var_types_num]; int8_t m[psyc_var_types_num];
return (PsycType) psyc_dict_lookup((PsycDict*)psyc_var_types, psyc_var_types_num, return (PsycType) psyc_dict_lookup((PsycDict *) psyc_var_types,
name, len, PSYC_YES, (int8_t*)&m); psyc_var_types_num, name, len, PSYC_YES,
(int8_t *) &m);
} }

View file

@ -30,236 +30,244 @@
// cmd line args // cmd line args
extern uint8_t verbose, stats; extern uint8_t verbose, stats;
void check_range(char c, const char *s, int min, int max) { void
int n = atoi(s); check_range (char c, const char *s, int min, int max)
if (n < min) { {
printf("-%c: error, should be >= %d\n", c, min); int n = atoi(s);
exit(-1); if (n < min) {
} printf("-%c: error, should be >= %d\n", c, min);
if (max > min && n > max) { exit(-1);
printf("-%c: error, should be <= %d\n", c, max); }
exit(-1); if (max > min && n > max) {
} printf("-%c: error, should be <= %d\n", c, max);
exit(-1);
}
} }
// get sockaddr, IPv4 or IPv6: // get sockaddr, IPv4 or IPv6:
void *get_in_addr (struct sockaddr *sa) { void *
if (sa->sa_family == AF_INET) get_in_addr (struct sockaddr *sa)
return &(((struct sockaddr_in*)sa)->sin_addr); {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr); return &(((struct sockaddr_in6*)sa)->sin6_addr);
} }
void test_file(const char* filename, size_t count, size_t recv_buf_size) { void
char *buf, *recvbuf; // cont buf + recv buf: [ ccrrrr] test_file (const char* filename, size_t count, size_t recv_buf_size)
size_t i, nbytes, size; {
struct timeval start, end; char *buf, *recvbuf; // cont buf + recv buf: [ ccrrrr]
struct stat st; size_t i, nbytes, size;
struct timeval start, end;
struct stat st;
int fd = open(filename, O_RDONLY); int fd = open(filename, O_RDONLY);
if (fd < 0) { if (fd < 0) {
perror("open"); perror("open");
exit(1); exit(1);
} }
fstat(fd, &st); fstat(fd, &st);
size = CONT_BUF_SIZE + st.st_size; size = CONT_BUF_SIZE + st.st_size;
buf = malloc(size); buf = malloc(size);
if (!buf) { if (!buf) {
perror("malloc"); perror("malloc");
exit(1); exit(1);
} }
recvbuf = buf + CONT_BUF_SIZE; recvbuf = buf + CONT_BUF_SIZE;
test_init(0); test_init(0);
if (recv_buf_size) { if (recv_buf_size) {
if (stats) if (stats)
gettimeofday(&start, NULL); gettimeofday(&start, NULL);
#ifdef NOREAD #ifdef NOREAD
memset(buf, 1, size); memset(buf, 1, size);
#else #else
size = 0; size = 0;
#endif #endif
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
#ifndef NOREAD #ifndef NOREAD
while ((nbytes = read(fd, (void*)recvbuf, recv_buf_size))) while ((nbytes = read(fd, (void*)recvbuf, recv_buf_size)))
#endif #endif
test_input(0, recvbuf, nbytes); test_input(0, recvbuf, nbytes);
} else { } else {
#ifdef NOREAD #ifdef NOREAD
memset(buf, 1, size); memset(buf, 1, size);
#else #else
size = 0; size = 0;
while ((nbytes = read(fd, (void*)recvbuf + size, RECV_BUF_SIZE))) while ((nbytes = read(fd, (void*)recvbuf + size, RECV_BUF_SIZE)))
size += nbytes; size += nbytes;
#endif #endif
if (stats) if (stats)
gettimeofday(&start, NULL); gettimeofday(&start, NULL);
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
test_input(0, recvbuf, size); test_input(0, recvbuf, size);
} }
if (stats) { if (stats) {
gettimeofday(&end, NULL); gettimeofday(&end, NULL);
printf("%ld\n", (end.tv_sec * 1000000 + end.tv_usec - start.tv_sec * 1000000 - start.tv_usec) / 1000); printf("%ld\n", (end.tv_sec * 1000000 + end.tv_usec - start.tv_sec * 1000000 - start.tv_usec) / 1000);
} }
} }
void test_server(const char* port, size_t count, size_t recv_buf_size) { void
char buf[CONT_BUF_SIZE + RECV_BUF_SIZE]; // cont buf + recv buf: [ ccrrrr] test_server (const char* port, size_t count, size_t recv_buf_size)
char *recvbuf = buf + CONT_BUF_SIZE; // recv buf: ^^^^ {
char buf[CONT_BUF_SIZE + RECV_BUF_SIZE]; // cont buf + recv buf: [ ccrrrr]
char *recvbuf = buf + CONT_BUF_SIZE; // recv buf: ^^^^
fd_set master; // master file descriptor list fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select() fd_set read_fds; // temp file descriptor list for select()
int fdmax; // maximum file descriptor number int fdmax; // maximum file descriptor number
int listener; // listening socket descriptor int listener; // listening socket descriptor
int newfd; // newly accept()ed socket descriptor int newfd; // newly accept()ed socket descriptor
struct sockaddr_storage remoteaddr; // client address struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen; socklen_t addrlen;
size_t nbytes; size_t nbytes;
char remoteIP[INET6_ADDRSTRLEN]; char remoteIP[INET6_ADDRSTRLEN];
int yes = 1; // for setsockopt() SO_REUSEADDR, below int yes = 1; // for setsockopt() SO_REUSEADDR, below
int i, rv, ret; int i, rv, ret;
struct addrinfo hints, *ai, *p; struct addrinfo hints, *ai, *p;
struct timeval start[NUM_PARSERS], end[NUM_PARSERS]; struct timeval start[NUM_PARSERS], end[NUM_PARSERS];
FD_ZERO(&master); // clear the master and temp sets FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds); FD_ZERO(&read_fds);
// get us a socket and bind it // get us a socket and bind it
memset(&hints, 0, sizeof hints); memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, port, &hints, &ai)) != 0) { if ((rv = getaddrinfo(NULL, port, &hints, &ai)) != 0) {
fprintf(stderr, "error: %s\n", gai_strerror(rv)); fprintf(stderr, "error: %s\n", gai_strerror(rv));
exit(1); exit(1);
} }
for (p = ai; p != NULL; p = p->ai_next) { for (p = ai; p != NULL; p = p->ai_next) {
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) if (listener < 0)
continue; continue;
// lose the pesky "address already in use" error message // lose the pesky "address already in use" error message
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) { if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener); close(listener);
continue; continue;
}
break;
} }
// if we got here, it means we didn't get bound break;
if (p == NULL) { }
fprintf(stderr, "failed to bind\n");
exit(2); // 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);
}
printf("# Listening on TCP port %s\n", port);
// 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);
} }
freeaddrinfo(ai); // all done with this // 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
// listen addrlen = sizeof remoteaddr;
if (listen(listener, 10) == -1) { newfd = accept(listener, (struct sockaddr *)&remoteaddr, &addrlen);
perror("listen");
exit(3);
}
printf("# Listening on TCP port %s\n", port); if (newfd == -1) {
perror("accept");
} else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) // keep track of the max
fdmax = newfd;
// add the listener to the master set test_init(newfd);
FD_SET(listener, &master);
// keep track of the biggest file descriptor if (verbose)
fdmax = listener; // so far, it's this one printf("# New connection from %s on socket %d\n",
inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),
newfd);
// main loop if (stats)
for (;;) { gettimeofday(&start[newfd], NULL);
read_fds = master; // copy it }
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { } else {
perror("select"); // handle data from a client
exit(4); if ((nbytes = recv(i, recvbuf, recv_buf_size, 0)) <= 0) {
} if (stats)
printf("%ld ms\n", (end[i].tv_sec * 1000000 + end[i].tv_usec - start[i].tv_sec * 1000000 - start[i].tv_usec) / 1000);
// run through the existing connections looking for data to read // got error or connection closed by client
for (i = 0; i <= fdmax; i++) { if (nbytes == 0) { // connection closed
if (FD_ISSET(i, &read_fds)) { // we got one!! if (verbose)
if (i == listener) { printf("# Socket %d hung up\n", i);
// handle new connections } else {
if (fdmax == NUM_PARSERS - 1) perror("recv");
continue; // ignore if there's too many }
addrlen = sizeof remoteaddr; close(i); // bye!
newfd = accept(listener, (struct sockaddr *)&remoteaddr, &addrlen); FD_CLR(i, &master); // remove from master set
} else {
// we got some data from a client
if (verbose >= 2)
printf("> %ld bytes\n", nbytes);
if (verbose >= 3)
printf("> [%.*s]", (int)nbytes, recvbuf);
if (newfd == -1) { ret = test_input(i, recvbuf, nbytes);
perror("accept");
} else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) // keep track of the max
fdmax = newfd;
test_init(newfd); if (stats)
gettimeofday(&end[i], NULL);
if (verbose) if (ret < 0) {
printf("# New connection from %s on socket %d\n", if (verbose)
inet_ntop(remoteaddr.ss_family, printf("# Closing connection: %i\n", i);
get_in_addr((struct sockaddr*)&remoteaddr), close(i); // bye!
remoteIP, INET6_ADDRSTRLEN), FD_CLR(i, &master); // remove from master set
newfd); }
}
if (stats) } // END handle data from client
gettimeofday(&start[newfd], NULL); } // END got new incoming connection
} } // END looping through file descriptors
} else { } // END for(;;)--and you thought it would never end!
// handle data from a client
if ((nbytes = recv(i, recvbuf, recv_buf_size, 0)) <= 0) {
if (stats)
printf("%ld ms\n", (end[i].tv_sec * 1000000 + end[i].tv_usec - start[i].tv_sec * 1000000 - start[i].tv_usec) / 1000);
// got error or connection closed by client
if (nbytes == 0) { // connection closed
if (verbose)
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
if (verbose >= 2)
printf("> %ld bytes\n", nbytes);
if (verbose >= 3)
printf("> [%.*s]", (int)nbytes, recvbuf);
ret = test_input(i, recvbuf, nbytes);
if (stats)
gettimeofday(&end[i], NULL);
if (ret < 0) {
if (verbose)
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!
} }

View file

@ -42,11 +42,19 @@
#define HELP_P " -P\t\t\tShow progress\n" #define HELP_P " -P\t\t\tShow progress\n"
#define HELP_h " -h\t\t\tShow this help\n" #define HELP_h " -h\t\t\tShow this help\n"
void test_init(int i); void
int test_input(int i, char *recvbuf, size_t nbytes); test_init (int i);
void test_file(const char* filename, size_t count, size_t recv_buf_size); int
void test_server(const char* port, size_t count, size_t recv_buf_size); test_input (int i, char *recvbuf, size_t nbytes);
void check_range(char c, const char *s, int min, int max);
void
test_file (const char* filename, size_t count, size_t recv_buf_size);
void
test_server (const char* port, size_t count, size_t recv_buf_size);
void
check_range (char c, const char *s, int min, int max);
#endif #endif

View file

@ -26,88 +26,93 @@ json_object *obj;
json_tokener *tok; json_tokener *tok;
enum json_tokener_error error; enum json_tokener_error error;
void test_init (int i) { void
tok = json_tokener_new(); test_init (int i)
{
tok = json_tokener_new();
} }
int test_input (int i, char *recvbuf, size_t nbytes) { int
size_t cursor = 0; test_input (int i, char *recvbuf, size_t nbytes)
int r, ret = 0; {
size_t cursor = 0;
int r, ret = 0;
json_tokener_reset(tok); json_tokener_reset(tok);
do { do {
obj = json_tokener_parse_ex(tok, recvbuf + cursor, nbytes - cursor); obj = json_tokener_parse_ex(tok, recvbuf + cursor, nbytes - cursor);
cursor += tok->char_offset; cursor += tok->char_offset;
if (verbose) if (verbose)
printf("#%d\n", tok->err); printf("#%d\n", tok->err);
switch (tok->err) { switch (tok->err) {
case json_tokener_continue: case json_tokener_continue:
return 0; return 0;
case json_tokener_success: case json_tokener_success:
if (!no_render) { if (!no_render) {
const char *str = json_object_to_json_string(obj); const char *str = json_object_to_json_string(obj);
if (!quiet) { if (!quiet) {
size_t len = strlen(str); size_t len = strlen(str);
if (filename) { if (filename) {
r = write(1, str, len); r = write(1, str, len);
r = write(1, "\n", 1); r = write(1, "\n", 1);
} else { } else {
send(i, str, len, 0); send(i, str, len, 0);
send(i, "\n", 1, 0); send(i, "\n", 1, 0);
} }
}
}
json_object_put(obj);
if (verbose)
printf("# Done parsing.\n");
else if (progress)
r = write(1, ".", 1);
if ((filename && !multiple) || (!filename && single))
return -1;
break;
default:
printf("parse error\n");
exit_code = tok->err;
return -1;
} }
} while (cursor < nbytes); }
return ret; json_object_put(obj);
}
int main (int argc, char **argv) { if (verbose)
int c; printf("# Done parsing.\n");
else if (progress)
r = write(1, ".", 1);
if ((filename && !multiple) || (!filename && single))
return -1;
break;
while ((c = getopt (argc, argv, "f:p:b:c:mnqsvPSh")) != -1) { default:
switch (c) { printf("parse error\n");
CASE_f CASE_p CASE_b CASE_c exit_code = tok->err;
CASE_m CASE_n CASE_q CASE_s return -1;
CASE_v CASE_S CASE_P
case 'h':
printf(
HELP_FILE("test_json", "mnqSsvP")
HELP_PORT("test_json", "nqsvP")
HELP_f HELP_p HELP_b HELP_c
HELP_m HELP_n HELP_q HELP_S
HELP_s HELP_v HELP_P HELP_h,
port, RECV_BUF_SIZE);
exit(0);
case '?': exit(-1);
default: abort();
}
} }
} while (cursor < nbytes);
if (filename) return ret;
test_file(filename, count, recv_buf_size); }
else
test_server(port, count, recv_buf_size); int
main (int argc, char **argv)
return exit_code; {
int c;
while ((c = getopt (argc, argv, "f:p:b:c:mnqsvPSh")) != -1) {
switch (c) {
CASE_f CASE_p CASE_b CASE_c
CASE_m CASE_n CASE_q CASE_s
CASE_v CASE_S CASE_P
case 'h':
printf(HELP_FILE("test_json", "mnqSsvP")
HELP_PORT("test_json", "nqsvP")
HELP_f HELP_p HELP_b HELP_c
HELP_m HELP_n HELP_q HELP_S
HELP_s HELP_v HELP_P HELP_h,
port, RECV_BUF_SIZE);
exit(0);
case '?': exit(-1);
default: abort();
}
}
if (filename)
test_file(filename, count, recv_buf_size);
else
test_server(port, count, recv_buf_size);
return exit_code;
} }

View file

@ -24,76 +24,79 @@ int exit_code;
JsonParser *parser; JsonParser *parser;
JsonGenerator *generator; JsonGenerator *generator;
void test_init (int i) { void
g_type_init(); test_init (int i)
parser = json_parser_new(); {
generator = json_generator_new(); g_type_init();
parser = json_parser_new();
generator = json_generator_new();
} }
int test_input (int i, char *recvbuf, size_t nbytes) { int
JsonNode *root; test_input (int i, char *recvbuf, size_t nbytes)
GError *error = NULL; {
char *str; JsonNode *root;
size_t len; GError *error = NULL;
int r, ret; char *str;
size_t len;
int r, ret;
ret = json_parser_load_from_data(parser, recvbuf, nbytes, &error); ret = json_parser_load_from_data(parser, recvbuf, nbytes, &error);
if (!ret) { if (!ret) {
printf("Parse error\n"); printf("Parse error\n");
exit(1); exit(1);
}
root = json_parser_get_root(parser);
if (!no_render) {
json_generator_set_root(generator, root);
str = json_generator_to_data(generator, &len);;
if (!quiet) {
if (filename) {
r = write(1, str, len);
r = write(1, "\n", 1);
} else {
send(i, str, len, 0);
send(i, "\n", 1, 0);
}
} }
}
root = json_parser_get_root(parser); if (verbose)
printf("# Done parsing.\n");
else if (progress)
r = write(1, ".", 1);
if (!no_render) { return ret;
json_generator_set_root(generator, root);
str = json_generator_to_data(generator, &len);;
if (!quiet) {
if (filename) {
r = write(1, str, len);
r = write(1, "\n", 1);
} else {
send(i, str, len, 0);
send(i, "\n", 1, 0);
}
}
}
if (verbose)
printf("# Done parsing.\n");
else if (progress)
r = write(1, ".", 1);
return ret;
} }
int main (int argc, char **argv) { int main (int argc, char **argv) {
int c; int c;
while ((c = getopt (argc, argv, "f:p:b:c:nqsvPh")) != -1) { while ((c = getopt (argc, argv, "f:p:b:c:nqsvPh")) != -1) {
switch (c) { switch (c) {
CASE_f CASE_p CASE_b CASE_f CASE_p CASE_b
CASE_c CASE_n CASE_q CASE_c CASE_n CASE_q
CASE_s CASE_v CASE_P CASE_s CASE_v CASE_P
case 'h': case 'h':
printf( printf(HELP_FILE("test_json_glib", "mnqSsvP")
HELP_FILE("test_json_glib", "mnqSsvP") HELP_PORT("test_json_glib", "nqsvP")
HELP_PORT("test_json_glib", "nqsvP") HELP_f HELP_p HELP_b HELP_c
HELP_f HELP_p HELP_b HELP_c HELP_m HELP_n HELP_q HELP_S
HELP_m HELP_n HELP_q HELP_S HELP_s HELP_v HELP_P HELP_h,
HELP_s HELP_v HELP_P HELP_h, port, RECV_BUF_SIZE);
port, RECV_BUF_SIZE); exit(0);
exit(0); case '?': exit(-1);
case '?': exit(-1); default: abort();
default: abort();
}
} }
}
if (filename) if (filename)
test_file(filename, count, recv_buf_size); test_file(filename, count, recv_buf_size);
else else
test_server(port, count, recv_buf_size); test_server(port, count, recv_buf_size);
return exit_code; return exit_code;
} }

View file

@ -2,19 +2,35 @@
#include <lib.h> #include <lib.h>
int main() { int main() {
if (psyc_matches(PSYC_C2ARG("_failure_delivery"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 1; if (psyc_matches(PSYC_C2ARG("_failure_delivery"),
if (psyc_matches(PSYC_C2ARG("_failure"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 2; PSYC_C2ARG("_failure_unsuccessful_delivery_death")))
if (psyc_matches(PSYC_C2ARG("_unsuccessful"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 3; return 1;
unless (psyc_matches(PSYC_C2ARG("_fail"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 4; if (psyc_matches(PSYC_C2ARG("_failure"),
unless (psyc_matches(PSYC_C2ARG("_truthahn"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 5; 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."); puts("psyc_matches passed all tests.");
unless (psyc_inherits(PSYC_C2ARG("_failure_delivery"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 11; unless (psyc_inherits(PSYC_C2ARG("_failure_delivery"),
if (psyc_inherits(PSYC_C2ARG("_failure_unsuccessful"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 12; PSYC_C2ARG("_failure_unsuccessful_delivery_death")))
unless (psyc_inherits(PSYC_C2ARG("_fail"), PSYC_C2ARG("_failure_unsuccessful_delivery_death"))) return 13; 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."); puts("psyc_inherits passed all tests.");
return 0; // passed all tests return 0; // passed all tests
} }

View file

@ -5,101 +5,96 @@
#include <psyc.h> #include <psyc.h>
#include <psyc/parse.h> #include <psyc/parse.h>
int main (int argc, char **argv) int
main (int argc, char **argv)
{ {
uint8_t routing_only = argc > 2 && memchr(argv[2], (int)'r', strlen(argv[2])); uint8_t routing_only = argc > 2 && memchr(argv[2], (int)'r', strlen(argv[2]));
uint8_t verbose = argc > 2 && memchr(argv[2], (int)'v', strlen(argv[2])); uint8_t verbose = argc > 2 && memchr(argv[2], (int)'v', strlen(argv[2]));
int idx, ret; int idx, ret;
char buffer[2048], oper; char buffer[2048], oper;
PsycString name, value, elem; PsycString name, value, elem;
PsycParseState state; PsycParseState state;
PsycParseListState listState; PsycParseListState listState;
if (argc < 2) if (argc < 2)
return -1; return -1;
int file = open(argv[1],O_RDONLY); int file = open(argv[1],O_RDONLY);
if (file < 0) if (file < 0)
return -1; return -1;
idx = read(file,(void*)buffer,sizeof(buffer)); idx = read(file,(void*)buffer,sizeof(buffer));
if (verbose) { if (verbose) {
printf(">> INPUT\n"); printf(">> INPUT\n");
printf("%.*s\n", (int)idx, buffer); printf("%.*s\n", (int)idx, buffer);
printf(">> PARSE\n"); printf(">> PARSE\n");
} }
psyc_parse_state_init(&state, routing_only ? psyc_parse_state_init(&state, routing_only ?
PSYC_PARSE_ROUTING_ONLY : PSYC_PARSE_ALL); PSYC_PARSE_ROUTING_ONLY : PSYC_PARSE_ALL);
psyc_parse_buffer_set(&state, buffer, idx); psyc_parse_buffer_set(&state, buffer, idx);
// try parsing that now // try parsing that now
do do {
{ oper = 0;
oper = 0; name.length = 0;
name.length = 0; value.length = 0;
value.length = 0;
ret = psyc_parse(&state, &oper, &name, &value); ret = psyc_parse(&state, &oper, &name, &value);
if (verbose)
printf(">> ret = %d\n", ret);
switch (ret) {
case PSYC_PARSE_ROUTING:
case PSYC_PARSE_ENTITY:
if (verbose)
printf("%c", oper);
case PSYC_PARSE_BODY:
// printf("the string is '%.*s'\n", name);
if (verbose)
printf("%.*s = %.*s\n",
(int)name.length, name.data,
(int)value.length, value.data);
if (psyc_var_is_list(PSYC_S2ARG(name))) {
if (verbose) if (verbose)
printf(">> ret = %d\n", ret); printf(">> LIST START\n");
switch (ret) psyc_parse_list_state_init(&listState);
{ psyc_parse_list_buffer_set(&listState, PSYC_S2ARG(value));
case PSYC_PARSE_ROUTING:
case PSYC_PARSE_ENTITY:
if (verbose)
printf("%c", oper);
case PSYC_PARSE_BODY:
// printf("the string is '%.*s'\n", name);
if (verbose)
printf("%.*s = %.*s\n",
(int)name.length, name.data,
(int)value.length, value.data);
if (psyc_var_is_list(PSYC_S2ARG(name))) while ((ret = psyc_parse_list(&listState, &elem))) {
{ switch (ret) {
if (verbose) case PSYC_PARSE_LIST_END:
printf(">> LIST START\n"); case PSYC_PARSE_LIST_ELEM:
if (verbose)
printf("|%.*s\n", (int)elem.length, elem.data);
break;
default:
printf("Error while parsing list: %i\n", ret);
return 1;
}
psyc_parse_list_state_init(&listState); if (ret == PSYC_PARSE_LIST_END) {
psyc_parse_list_buffer_set(&listState, PSYC_S2ARG(value)); if (verbose)
printf(">> LIST END\n");
while ((ret = psyc_parse_list(&listState, &elem))) break;
{ }
switch (ret)
{
case PSYC_PARSE_LIST_END:
case PSYC_PARSE_LIST_ELEM:
if (verbose)
printf("|%.*s\n", (int)elem.length, elem.data);
break;
default:
printf("Error while parsing list: %i\n", ret);
return 1;
}
if (ret == PSYC_PARSE_LIST_END)
{
if (verbose)
printf(">> LIST END\n");
break;
}
}
}
break;
case PSYC_PARSE_COMPLETE:
// printf("Done parsing.\n");
ret = 0;
continue;
case PSYC_PARSE_INSUFFICIENT:
printf("Insufficient data.\n");
return 1;
default:
printf("Error while parsing: %i\n", ret);
return 1;
} }
}
break;
case PSYC_PARSE_COMPLETE:
// printf("Done parsing.\n");
ret = 0;
continue;
case PSYC_PARSE_INSUFFICIENT:
printf("Insufficient data.\n");
return 1;
default:
printf("Error while parsing: %i\n", ret);
return 1;
} }
while (ret); }
while (ret);
return 0; return 0;
} }

View file

@ -31,323 +31,333 @@ PsycModifier entity[NUM_PARSERS][ENTITY_LINES];
int contbytes, exit_code; int contbytes, exit_code;
static inline static inline void
void resetString (PsycString *s, uint8_t freeptr); resetString (PsycString *s, uint8_t freeptr);
// initialize parser & packet variables // initialize parser & packet variables
void test_init (int i) { void
// reset parser state & packet test_init (int i)
psyc_parse_state_init(&parsers[i], routing_only ? {
PSYC_PARSE_ROUTING_ONLY : PSYC_PARSE_ALL); // reset parser state & packet
psyc_parse_state_init(&parsers[i],
routing_only ? PSYC_PARSE_ROUTING_ONLY : PSYC_PARSE_ALL);
memset(&packets[i], 0, sizeof(PsycPacket)); memset(&packets[i], 0, sizeof(PsycPacket));
memset(&routing[i], 0, sizeof(PsycModifier) * ROUTING_LINES); memset(&routing[i], 0, sizeof(PsycModifier) * ROUTING_LINES);
memset(&entity[i], 0, sizeof(PsycModifier) * ENTITY_LINES); memset(&entity[i], 0, sizeof(PsycModifier) * ENTITY_LINES);
packets[i].routing.modifiers = routing[i]; packets[i].routing.modifiers = routing[i];
packets[i].entity.modifiers = entity[i]; packets[i].entity.modifiers = entity[i];
} }
// parse & render input // parse & render input
int test_input (int i, char *recvbuf, size_t nbytes) { int
int j, ret, retl, r; test_input (int i, char *recvbuf, size_t nbytes)
char sendbuf[SEND_BUF_SIZE];
char *parsebuf = recvbuf - contbytes;
/* We have a buffer with pointers pointing to various parts of it:
* *contbuf-vv
* buffer: [ ccrrrr]
* *recvbuf---^^^^
* *parsebuf-^^^^^^
*
* New data is in recvbuf, if it contains an incomplete packet then remaining
* unparsed data is copied to contbuf that will be parsed during the next call
* to this function together with the new data.
*/
PsycParseState *parser = &parsers[i];
PsycPacket *packet = &packets[i];
char oper;
PsycString name, value, elem;
PsycString *pname = NULL, *pvalue = NULL;
PsycModifier *mod = NULL;
PsycParseListState listState;
size_t len;
// Set buffer with data for the parser.
psyc_parse_buffer_set(parser, parsebuf, contbytes + nbytes);
contbytes = 0;
oper = 0;
name.length = 0;
value.length = 0;
do {
if (verbose >= 3)
printf("\n# buffer = [%.*s]\n# part = %d\n", (int)parser->buffer.length, parser->buffer.data, parser->part);
// Parse the next part of the packet (a routing/entity modifier or the body)
ret = exit_code = psyc_parse(parser, &oper, &name, &value);
if (verbose >= 2)
printf("# ret = %d\n", ret);
switch (ret) {
case PSYC_PARSE_ROUTING:
assert(packet->routing.lines < ROUTING_LINES);
mod = &(packet->routing.modifiers[packet->routing.lines]);
pname = &mod->name;
pvalue = &mod->value;
mod->flag = PSYC_MODIFIER_ROUTING;
packet->routing.lines++;
break;
case PSYC_PARSE_STATE_RESYNC:
case PSYC_PARSE_STATE_RESET:
packet->stateop = oper;
break;
case PSYC_PARSE_ENTITY_START:
case PSYC_PARSE_ENTITY_CONT:
case PSYC_PARSE_ENTITY_END:
case PSYC_PARSE_ENTITY:
assert(packet->entity.lines < ENTITY_LINES);
mod = &(packet->entity.modifiers[packet->entity.lines]);
pname = &mod->name;
pvalue = &mod->value;
if (ret == PSYC_PARSE_ENTITY || ret == PSYC_PARSE_ENTITY_END) {
packet->entity.lines++;
mod->flag = psyc_parse_value_length_found(parser) ?
PSYC_MODIFIER_NEED_LENGTH : PSYC_MODIFIER_NO_LENGTH;
}
break;
case PSYC_PARSE_BODY_START:
case PSYC_PARSE_BODY_CONT:
case PSYC_PARSE_BODY_END:
case PSYC_PARSE_BODY:
pname = &(packet->method);
pvalue = &(packet->data);
break;
case PSYC_PARSE_COMPLETE:
if (verbose)
printf("# Done parsing.\n");
else if (progress)
r = write(1, ".", 1);
if ((filename && !multiple) || (!filename && single))
ret = -1;
if (!no_render) {
packet->flag = psyc_parse_content_length_found(parser) ?
PSYC_PACKET_NEED_LENGTH : PSYC_PACKET_NO_LENGTH;
if (routing_only) {
packet->content = packet->data;
resetString(&(packet->data), 0);
}
psyc_packet_length_set(packet);
if (psyc_render(packet, sendbuf, SEND_BUF_SIZE) == PSYC_RENDER_SUCCESS) {
if (!quiet) {
if (filename && write(1, sendbuf, packet->length) == -1) {
perror("write");
ret = -1;
} else if (!filename && send(i, sendbuf, packet->length, 0) == -1) {
perror("send");
ret = -1;
}
}
} else {
printf("# Render error");
ret = -1;
}
}
// reset packet
packet->routingLength = 0;
packet->contentLength = 0;
packet->length = 0;
packet->flag = 0;
for (j = 0; j < packet->routing.lines; j++) {
resetString(&(packet->routing.modifiers[j].name), 1);
resetString(&(packet->routing.modifiers[j].value), 1);
}
packet->routing.lines = 0;
if (routing_only) {
resetString(&(packet->content), 1);
} else {
for (j = 0; j < packet->entity.lines; j++) {
resetString(&(packet->entity.modifiers[j].name), 1);
resetString(&(packet->entity.modifiers[j].value), 1);
}
packet->entity.lines = 0;
resetString(&(packet->method), 1);
resetString(&(packet->data), 1);
}
break;
case PSYC_PARSE_INSUFFICIENT:
if (verbose >= 2)
printf("# Insufficient data.\n");
contbytes = psyc_parse_remaining_length(parser);
if (contbytes > 0) { // copy end of parsebuf before start of recvbuf
if (verbose >= 3)
printf("# remaining = [%.*s]\n", (int)contbytes, psyc_parse_remaining_buffer(parser));
assert(contbytes <= CONT_BUF_SIZE); // make sure it's still in the buffer
memmove(recvbuf - contbytes, psyc_parse_remaining_buffer(parser), contbytes);
}
ret = 0;
break;
default:
printf("# Error while parsing: %i\n", ret);
ret = -1;
}
switch (ret) {
case PSYC_PARSE_ENTITY_START:
case PSYC_PARSE_ENTITY_CONT:
case PSYC_PARSE_BODY_START:
case PSYC_PARSE_BODY_CONT:
ret = 0;
case PSYC_PARSE_ENTITY:
case PSYC_PARSE_ENTITY_END:
case PSYC_PARSE_ROUTING:
case PSYC_PARSE_BODY:
case PSYC_PARSE_BODY_END:
if (oper) {
mod->oper = oper;
if (verbose >= 2)
printf("%c", oper);
}
if (name.length) {
pname->data = malloc(name.length);
pname->length = name.length;
assert(pname->data != NULL);
memcpy((void*)pname->data, name.data, name.length);
name.length = 0;
if (verbose >= 2)
printf("%.*s = ", (int)pname->length, pname->data);
}
if (value.length) {
if (!pvalue->length) {
if (psyc_parse_value_length_found(parser))
len = psyc_parse_value_length(parser);
else
len = value.length;
pvalue->data = malloc(len);
}
assert(pvalue->data != NULL);
memcpy((void*)pvalue->data + pvalue->length, value.data, value.length);
pvalue->length += value.length;
value.length = 0;
if (verbose >= 2) {
printf("[%.*s]", (int)pvalue->length, pvalue->data);
if (parser->valueLength > pvalue->length)
printf("...");
printf("\n");
}
}
else if (verbose)
printf("\n");
if (verbose >= 3)
printf("\t\t\t\t\t\t\t\t# n:%ld v:%ld c:%ld r:%ld\n",
pname->length, pvalue->length,
parser->contentParsed, parser->routingLength);
}
switch (ret) {
case PSYC_PARSE_ROUTING:
case PSYC_PARSE_ENTITY:
case PSYC_PARSE_ENTITY_END:
oper = 0;
name.length = 0;
value.length = 0;
if (psyc_var_is_list(PSYC_S2ARG(*pname))) {
if (verbose >= 2)
printf("## LIST START\n");
psyc_parse_list_state_init(&listState);
psyc_parse_list_buffer_set(&listState, PSYC_S2ARG(*pvalue));
do {
retl = psyc_parse_list(&listState, &elem);
switch (retl) {
case PSYC_PARSE_LIST_END:
retl = 0;
case PSYC_PARSE_LIST_ELEM:
if (verbose >= 2) {
printf("|%.*s\n", (int)elem.length, elem.data);
if (ret == PSYC_PARSE_LIST_END)
printf("## LIST END");
}
break;
default:
printf("# Error while parsing list: %i\n", retl);
ret = retl = -1;
}
}
while (retl > 0);
}
}
}
while (ret > 0);
if (progress)
r = write(1, " ", 1);
return ret;
}
static inline
void resetString (PsycString *s, uint8_t freeptr)
{ {
if (freeptr && s->length) int j, ret, retl, r;
free((void*)s->data); char sendbuf[SEND_BUF_SIZE];
char *parsebuf = recvbuf - contbytes;
/* We have a buffer with pointers pointing to various parts of it:
* *contbuf-vv
* buffer: [ ccrrrr]
* *recvbuf---^^^^
* *parsebuf-^^^^^^
*
* New data is in recvbuf, if it contains an incomplete packet then remaining
* unparsed data is copied to contbuf that will be parsed during the next call
* to this function together with the new data.
*/
s->data = NULL; PsycParseState *parser = &parsers[i];
s->length = 0; PsycPacket *packet = &packets[i];
}
int main (int argc, char **argv) { char oper;
int c; PsycString name, value, elem;
while ((c = getopt (argc, argv, "f:p:b:c:mnqrsvPSh")) != -1) { PsycString *pname = NULL, *pvalue = NULL;
switch (c) { PsycModifier *mod = NULL;
CASE_f CASE_p CASE_b CASE_c PsycParseListState listState;
CASE_m CASE_n CASE_q CASE_r size_t len;
CASE_s CASE_v CASE_S CASE_P
case 'h': // Set buffer with data for the parser.
printf( psyc_parse_buffer_set(parser, parsebuf, contbytes + nbytes);
HELP_FILE("test_psyc", "mnqrSsvP") contbytes = 0;
HELP_PORT("test_psyc", "nqrsvP") oper = 0;
HELP_f HELP_p HELP_b HELP_c name.length = 0;
HELP_m HELP_n HELP_r value.length = 0;
HELP_q HELP_S HELP_s
HELP_v HELP_P HELP_h, do {
port, RECV_BUF_SIZE); if (verbose >= 3)
exit(0); printf("\n# buffer = [%.*s]\n# part = %d\n",
case '?': exit(-1); (int)parser->buffer.length, parser->buffer.data, parser->part);
default: abort(); // Parse the next part of the packet (a routing/entity modifier or the body)
ret = exit_code = psyc_parse(parser, &oper, &name, &value);
if (verbose >= 2)
printf("# ret = %d\n", ret);
switch (ret) {
case PSYC_PARSE_ROUTING:
assert(packet->routing.lines < ROUTING_LINES);
mod = &(packet->routing.modifiers[packet->routing.lines]);
pname = &mod->name;
pvalue = &mod->value;
mod->flag = PSYC_MODIFIER_ROUTING;
packet->routing.lines++;
break;
case PSYC_PARSE_STATE_RESYNC:
case PSYC_PARSE_STATE_RESET:
packet->stateop = oper;
break;
case PSYC_PARSE_ENTITY_START:
case PSYC_PARSE_ENTITY_CONT:
case PSYC_PARSE_ENTITY_END:
case PSYC_PARSE_ENTITY:
assert(packet->entity.lines < ENTITY_LINES);
mod = &(packet->entity.modifiers[packet->entity.lines]);
pname = &mod->name;
pvalue = &mod->value;
if (ret == PSYC_PARSE_ENTITY || ret == PSYC_PARSE_ENTITY_END) {
packet->entity.lines++;
mod->flag = psyc_parse_value_length_found(parser) ?
PSYC_MODIFIER_NEED_LENGTH : PSYC_MODIFIER_NO_LENGTH;
}
break;
case PSYC_PARSE_BODY_START:
case PSYC_PARSE_BODY_CONT:
case PSYC_PARSE_BODY_END:
case PSYC_PARSE_BODY:
pname = &(packet->method);
pvalue = &(packet->data);
break;
case PSYC_PARSE_COMPLETE:
if (verbose)
printf("# Done parsing.\n");
else if (progress)
r = write(1, ".", 1);
if ((filename && !multiple) || (!filename && single))
ret = -1;
if (!no_render) {
packet->flag = psyc_parse_content_length_found(parser) ?
PSYC_PACKET_NEED_LENGTH : PSYC_PACKET_NO_LENGTH;
if (routing_only) {
packet->content = packet->data;
resetString(&(packet->data), 0);
} }
psyc_packet_length_set(packet);
if (PSYC_RENDER_SUCCESS == psyc_render(packet, sendbuf,
SEND_BUF_SIZE)) {
if (!quiet) {
if (filename && write(1, sendbuf, packet->length) == -1) {
perror("write");
ret = -1;
} else if (!filename && -1 == send(i, sendbuf,
packet->length, 0)) {
perror("send");
ret = -1;
}
}
} else {
printf("# Render error");
ret = -1;
}
}
// reset packet
packet->routingLength = 0;
packet->contentLength = 0;
packet->length = 0;
packet->flag = 0;
for (j = 0; j < packet->routing.lines; j++) {
resetString(&(packet->routing.modifiers[j].name), 1);
resetString(&(packet->routing.modifiers[j].value), 1);
}
packet->routing.lines = 0;
if (routing_only) {
resetString(&(packet->content), 1);
} else {
for (j = 0; j < packet->entity.lines; j++) {
resetString(&(packet->entity.modifiers[j].name), 1);
resetString(&(packet->entity.modifiers[j].value), 1);
}
packet->entity.lines = 0;
resetString(&(packet->method), 1);
resetString(&(packet->data), 1);
}
break;
case PSYC_PARSE_INSUFFICIENT:
if (verbose >= 2)
printf("# Insufficient data.\n");
contbytes = psyc_parse_remaining_length(parser);
if (contbytes > 0) { // copy end of parsebuf before start of recvbuf
if (verbose >= 3)
printf("# remaining = [%.*s]\n",
(int)contbytes, psyc_parse_remaining_buffer(parser));
assert(contbytes <= CONT_BUF_SIZE); // make sure it fits in the buffer
memmove(recvbuf - contbytes,
psyc_parse_remaining_buffer(parser), contbytes);
}
ret = 0;
break;
default:
printf("# Error while parsing: %i\n", ret);
ret = -1;
} }
if (filename) switch (ret) {
test_file(filename, count, recv_buf_size); case PSYC_PARSE_ENTITY_START:
else case PSYC_PARSE_ENTITY_CONT:
test_server(port, count, recv_buf_size); case PSYC_PARSE_BODY_START:
case PSYC_PARSE_BODY_CONT:
ret = 0;
case PSYC_PARSE_ENTITY:
case PSYC_PARSE_ENTITY_END:
case PSYC_PARSE_ROUTING:
case PSYC_PARSE_BODY:
case PSYC_PARSE_BODY_END:
if (oper) {
mod->oper = oper;
if (verbose >= 2)
printf("%c", oper);
}
return exit_code; if (name.length) {
pname->data = malloc(name.length);
pname->length = name.length;
assert(pname->data != NULL);
memcpy((void*)pname->data, name.data, name.length);
name.length = 0;
if (verbose >= 2)
printf("%.*s = ", (int)pname->length, pname->data);
}
if (value.length) {
if (!pvalue->length) {
if (psyc_parse_value_length_found(parser))
len = psyc_parse_value_length(parser);
else
len = value.length;
pvalue->data = malloc(len);
}
assert(pvalue->data != NULL);
memcpy((void*)pvalue->data + pvalue->length, value.data, value.length);
pvalue->length += value.length;
value.length = 0;
if (verbose >= 2) {
printf("[%.*s]", (int)pvalue->length, pvalue->data);
if (parser->valueLength > pvalue->length)
printf("...");
printf("\n");
}
}
else if (verbose)
printf("\n");
if (verbose >= 3)
printf("\t\t\t\t\t\t\t\t# n:%ld v:%ld c:%ld r:%ld\n",
pname->length, pvalue->length,
parser->contentParsed, parser->routingLength);
}
switch (ret) {
case PSYC_PARSE_ROUTING:
case PSYC_PARSE_ENTITY:
case PSYC_PARSE_ENTITY_END:
oper = 0;
name.length = 0;
value.length = 0;
if (psyc_var_is_list(PSYC_S2ARG(*pname))) {
if (verbose >= 2)
printf("## LIST START\n");
psyc_parse_list_state_init(&listState);
psyc_parse_list_buffer_set(&listState, PSYC_S2ARG(*pvalue));
do {
retl = psyc_parse_list(&listState, &elem);
switch (retl) {
case PSYC_PARSE_LIST_END:
retl = 0;
case PSYC_PARSE_LIST_ELEM:
if (verbose >= 2) {
printf("|%.*s\n", (int)elem.length, elem.data);
if (ret == PSYC_PARSE_LIST_END)
printf("## LIST END");
}
break;
default:
printf("# Error while parsing list: %i\n", retl);
ret = retl = -1;
}
}
while (retl > 0);
}
}
}
while (ret > 0);
if (progress)
r = write(1, " ", 1);
return ret;
}
static inline void
resetString (PsycString *s, uint8_t freeptr)
{
if (freeptr && s->length)
free((void*)s->data);
s->data = NULL;
s->length = 0;
}
int
main (int argc, char **argv)
{
int c;
while ((c = getopt (argc, argv, "f:p:b:c:mnqrsvPSh")) != -1) {
switch (c) {
CASE_f CASE_p CASE_b CASE_c
CASE_m CASE_n CASE_q CASE_r
CASE_s CASE_v CASE_S CASE_P
case 'h':
printf(HELP_FILE("test_psyc", "mnqrSsvP")
HELP_PORT("test_psyc", "nqrsvP")
HELP_f HELP_p HELP_b HELP_c
HELP_m HELP_n HELP_r
HELP_q HELP_S HELP_s
HELP_v HELP_P HELP_h,
port, RECV_BUF_SIZE);
exit(0);
case '?': exit(-1);
default: abort();
}
}
if (filename)
test_file(filename, count, recv_buf_size);
else
test_server(port, count, recv_buf_size);
return exit_code;
} }

View file

@ -25,48 +25,52 @@ size_t count = 1, recv_buf_size;
PsycParseState parser; PsycParseState parser;
void test_init (int i) { void
psyc_parse_state_init(&parser, routing_only ? test_init (int i)
PSYC_PARSE_ROUTING_ONLY : PSYC_PARSE_ALL); {
psyc_parse_state_init(&parser, routing_only
? PSYC_PARSE_ROUTING_ONLY : PSYC_PARSE_ALL);
} }
int test_input (int i, char *recvbuf, size_t nbytes) { int
char oper; test_input (int i, char *recvbuf, size_t nbytes)
PsycString name, value; {
int ret; char oper;
PsycString name, value;
int ret;
psyc_parse_buffer_set(&parser, recvbuf, nbytes); psyc_parse_buffer_set(&parser, recvbuf, nbytes);
for (;;) { for (;;) {
ret = psyc_parse(&parser, &oper, &name, &value); ret = psyc_parse(&parser, &oper, &name, &value);
if (ret == PSYC_PARSE_COMPLETE || ret < 0) if (ret == PSYC_PARSE_COMPLETE || ret < 0)
return -1; return -1;
}
}
int
main (int argc, char **argv)
{
int c;
while ((c = getopt (argc, argv, "f:p:b:c:rsh")) != -1) {
switch (c) {
CASE_f CASE_p CASE_b CASE_c CASE_r CASE_s
case 'h':
printf(HELP_FILE("test_psyc_speed", "rs")
HELP_PORT("test_psyc_speed", "rs")
HELP_f HELP_p HELP_b HELP_c
HELP_r HELP_s HELP_h,
port, RECV_BUF_SIZE);
exit(0);
case '?': exit(-1);
default: abort();
} }
} }
int main (int argc, char **argv) { if (filename)
int c; test_file(filename, count, recv_buf_size);
while ((c = getopt (argc, argv, "f:p:b:c:rsh")) != -1) { else
switch (c) { test_server(port, count, recv_buf_size);
CASE_f CASE_p CASE_b CASE_c
CASE_r CASE_s return 0;
case 'h':
printf(
HELP_FILE("test_psyc_speed", "rs")
HELP_PORT("test_psyc_speed", "rs")
HELP_f HELP_p HELP_b HELP_c
HELP_r HELP_s HELP_h,
port, RECV_BUF_SIZE);
exit(0);
case '?': exit(-1);
default: abort();
}
}
if (filename)
test_file(filename, count, recv_buf_size);
else
test_server(port, count, recv_buf_size);
return 0;
} }

View file

@ -7,105 +7,111 @@
#define myUNI "psyc://10.100.1000/~ludwig" #define myUNI "psyc://10.100.1000/~ludwig"
/* example renderer generating a presence packet */ /* example renderer generating a presence packet */
int testPresence (const char *avail, int availlen, int
const char *desc, int desclen, testPresence (const char *avail, int availlen,
const char *rendered, uint8_t verbose) const char *desc, int desclen,
const char *rendered, uint8_t verbose)
{ {
PsycModifier routing[1]; PsycModifier routing[1];
psyc_modifier_init(&routing[0], PSYC_OPERATOR_SET, psyc_modifier_init(&routing[0], PSYC_OPERATOR_SET,
PSYC_C2ARG("_context"), PSYC_C2ARG("_context"),
PSYC_C2ARG(myUNI), PSYC_MODIFIER_ROUTING); PSYC_C2ARG(myUNI), PSYC_MODIFIER_ROUTING);
PsycModifier entity[2]; PsycModifier entity[2];
// presence is to be assigned permanently in distributed state // presence is to be assigned permanently in distributed state
psyc_modifier_init(&entity[0], PSYC_OPERATOR_ASSIGN, psyc_modifier_init(&entity[0], PSYC_OPERATOR_ASSIGN,
PSYC_C2ARG("_degree_availability"), PSYC_C2ARG("_degree_availability"),
avail, availlen, PSYC_MODIFIER_CHECK_LENGTH); avail, availlen, PSYC_MODIFIER_CHECK_LENGTH);
psyc_modifier_init(&entity[1], PSYC_OPERATOR_ASSIGN, psyc_modifier_init(&entity[1], PSYC_OPERATOR_ASSIGN,
PSYC_C2ARG("_description_presence"), PSYC_C2ARG("_description_presence"),
desc, desclen, PSYC_MODIFIER_CHECK_LENGTH); desc, desclen, PSYC_MODIFIER_CHECK_LENGTH);
PsycPacket packet; PsycPacket packet;
psyc_packet_init(&packet, routing, PSYC_NUM_ELEM(routing), psyc_packet_init(&packet, routing, PSYC_NUM_ELEM(routing),
entity, PSYC_NUM_ELEM(entity), entity, PSYC_NUM_ELEM(entity),
PSYC_C2ARG("_notice_presence"), PSYC_C2ARG("_notice_presence"),
NULL, 0, NULL, 0,
PSYC_STATE_NOOP, PSYC_STATE_NOOP,
PSYC_PACKET_CHECK_LENGTH); PSYC_PACKET_CHECK_LENGTH);
char buffer[512]; char buffer[512];
psyc_render(&packet, buffer, sizeof(buffer)); psyc_render(&packet, buffer, sizeof(buffer));
if (verbose) if (verbose)
printf("%.*s\n", (int)packet.length, buffer); printf("%.*s\n", (int)packet.length, buffer);
return strncmp(rendered, buffer, packet.length); return strncmp(rendered, buffer, packet.length);
} }
int testList (const char *rendered, uint8_t verbose) int
testList (const char *rendered, uint8_t verbose)
{ {
PsycModifier routing[2]; PsycModifier routing[2];
psyc_modifier_init(&routing[0], PSYC_OPERATOR_SET, psyc_modifier_init(&routing[0], PSYC_OPERATOR_SET,
PSYC_C2ARG("_source"), PSYC_C2ARG("_source"),
PSYC_C2ARG(myUNI), PSYC_MODIFIER_ROUTING); PSYC_C2ARG(myUNI), PSYC_MODIFIER_ROUTING);
psyc_modifier_init(&routing[1], PSYC_OPERATOR_SET, psyc_modifier_init(&routing[1], PSYC_OPERATOR_SET,
PSYC_C2ARG("_context"), PSYC_C2ARG("_context"),
PSYC_C2ARG(myUNI), PSYC_MODIFIER_ROUTING); PSYC_C2ARG(myUNI), PSYC_MODIFIER_ROUTING);
PsycString elems_text[] = { PsycString elems_text[] = {
PSYC_C2STR("foo"), PSYC_C2STR("foo"),
PSYC_C2STR("bar"), PSYC_C2STR("bar"),
PSYC_C2STR("baz"), PSYC_C2STR("baz"),
}; };
PsycString elems_bin[] = { PsycString elems_bin[] = {
PSYC_C2STR("foo"), PSYC_C2STR("foo"),
PSYC_C2STR("b|r"), PSYC_C2STR("b|r"),
PSYC_C2STR("baz\nqux"), PSYC_C2STR("baz\nqux"),
}; };
PsycList list_text, list_bin; PsycList list_text, list_bin;
psyc_list_init(&list_text, elems_text, PSYC_NUM_ELEM(elems_text), PSYC_LIST_CHECK_LENGTH); psyc_list_init(&list_text, elems_text,
psyc_list_init(&list_bin, elems_bin, PSYC_NUM_ELEM(elems_bin), PSYC_LIST_CHECK_LENGTH); PSYC_NUM_ELEM(elems_text), PSYC_LIST_CHECK_LENGTH);
psyc_list_init(&list_bin, elems_bin,
PSYC_NUM_ELEM(elems_bin), PSYC_LIST_CHECK_LENGTH);
char buf_text[32], buf_bin[32]; char buf_text[32], buf_bin[32];
psyc_render_list(&list_text, buf_text, sizeof(buf_text)); psyc_render_list(&list_text, buf_text, sizeof(buf_text));
psyc_render_list(&list_bin, buf_bin, sizeof(buf_bin)); psyc_render_list(&list_bin, buf_bin, sizeof(buf_bin));
PsycModifier entity[2]; PsycModifier entity[2];
psyc_modifier_init(&entity[0], PSYC_OPERATOR_SET, psyc_modifier_init(&entity[0], PSYC_OPERATOR_SET,
PSYC_C2ARG("_list_text"), PSYC_C2ARG("_list_text"),
buf_text, list_text.length, list_text.flag); buf_text, list_text.length, list_text.flag);
psyc_modifier_init(&entity[1], PSYC_OPERATOR_SET, psyc_modifier_init(&entity[1], PSYC_OPERATOR_SET,
PSYC_C2ARG("_list_binary"), PSYC_C2ARG("_list_binary"),
buf_bin, list_bin.length, list_bin.flag); buf_bin, list_bin.length, list_bin.flag);
PsycPacket packet; PsycPacket packet;
psyc_packet_init(&packet, routing, PSYC_NUM_ELEM(routing), psyc_packet_init(&packet, routing, PSYC_NUM_ELEM(routing),
entity, PSYC_NUM_ELEM(entity), entity, PSYC_NUM_ELEM(entity),
PSYC_C2ARG("_test_list"), PSYC_C2ARG("_test_list"),
PSYC_C2ARG("list test"), PSYC_C2ARG("list test"),
PSYC_STATE_NOOP, PSYC_STATE_NOOP,
PSYC_PACKET_CHECK_LENGTH); PSYC_PACKET_CHECK_LENGTH);
char buffer[512]; char buffer[512];
psyc_render(&packet, buffer, sizeof(buffer)); psyc_render(&packet, buffer, sizeof(buffer));
if (verbose) if (verbose)
printf("%.*s\n", (int)packet.length, buffer); printf("%.*s\n", (int)packet.length, buffer);
return strncmp(rendered, buffer, packet.length); return strncmp(rendered, buffer, packet.length);
} }
int main (int argc, char **argv) { int
uint8_t verbose = argc > 1; main (int argc, char **argv)
{
uint8_t verbose = argc > 1;
if (testPresence(PSYC_C2ARG("_here"), PSYC_C2ARG("I'm omnipresent right now"), "\ if (testPresence(PSYC_C2ARG("_here"), PSYC_C2ARG("I'm omnipresent right now"), "\
:_context\t" myUNI "\n\ :_context\t" myUNI "\n\
\n\ \n\
=_degree_availability\t_here\n\ =_degree_availability\t_here\n\
=_description_presence\tI'm omnipresent right now\n\ =_description_presence\tI'm omnipresent right now\n\
_notice_presence\n\ _notice_presence\n\
|\n", verbose)) |\n", verbose))
return 1; return 1;
if (testList("\ if (testList("\
:_source psyc://10.100.1000/~ludwig\n\ :_source psyc://10.100.1000/~ludwig\n\
:_context psyc://10.100.1000/~ludwig\n\ :_context psyc://10.100.1000/~ludwig\n\
85\n\ 85\n\
@ -115,9 +121,9 @@ qux\n\
_test_list\n\ _test_list\n\
list test\n\ list test\n\
|\n", verbose)) |\n", verbose))
return 2; return 2;
puts("psyc_render passed all tests."); puts("psyc_render passed all tests.");
return 0; return 0;
} }

View file

@ -21,44 +21,49 @@ size_t count = 1, recv_buf_size;
int exit_code; int exit_code;
void test_init (int i) { void
test_init (int i)
{
} }
int test_input (int i, char *recvbuf, size_t nbytes) { int
size_t len = strnlen(recvbuf, nbytes); test_input (int i, char *recvbuf, size_t nbytes)
{
size_t len = strnlen(recvbuf, nbytes);
if (!len) { if (!len) {
printf("Empty string\n"); printf("Empty string\n");
return -1; return -1;
}
return 0;
}
int
main (int argc, char **argv)
{
int c;
while ((c = getopt (argc, argv, "f:p:b:c:sh")) != -1) {
switch (c) {
CASE_f CASE_p CASE_b CASE_c CASE_s
case 'h':
printf(HELP_FILE("test_strlen", "s")
HELP_PORT("test_strlen", "s")
HELP_f HELP_p HELP_b HELP_c
HELP_s HELP_h,
port, RECV_BUF_SIZE);
exit(0);
case '?': exit(-1);
default: abort();
} }
}
return 0; if (filename)
} test_file(filename, count, recv_buf_size);
else
int main (int argc, char **argv) { test_server(port, count, recv_buf_size);
int c;
return exit_code;
while ((c = getopt (argc, argv, "f:p:b:c:sh")) != -1) {
switch (c) {
CASE_f CASE_p CASE_b CASE_c
CASE_s
case 'h':
printf(
HELP_FILE("test_strlen", "s")
HELP_PORT("test_strlen", "s")
HELP_f HELP_p HELP_b HELP_c
HELP_s HELP_h,
port, RECV_BUF_SIZE);
exit(0);
case '?': exit(-1);
default: abort();
}
}
if (filename)
test_file(filename, count, recv_buf_size);
else
test_server(port, count, recv_buf_size);
return exit_code;
} }

View file

@ -7,95 +7,99 @@
uint8_t verbose; uint8_t verbose;
PsycTextValueRC getValueFooBar (const char *name, size_t len, PsycString *value, void *extra) PsycTextValueRC
getValueFooBar (const char *name, size_t len, PsycString *value, void *extra)
{ {
if (verbose) if (verbose)
printf("> getValue: %.*s\n", (int)len, name); printf("> getValue: %.*s\n", (int)len, name);
value->data = "Foo Bar"; value->data = "Foo Bar";
value->length = 7; value->length = 7;
return PSYC_TEXT_VALUE_FOUND; return PSYC_TEXT_VALUE_FOUND;
} }
PsycTextValueRC getValueEmpty (const char *name, size_t len, PsycString *value, void *extra) PsycTextValueRC
getValueEmpty (const char *name, size_t len, PsycString *value, void *extra)
{ {
if (verbose) if (verbose)
printf("> getValue: %.*s\n", (int)len, name); printf("> getValue: %.*s\n", (int)len, name);
value->data = ""; value->data = "";
value->length = 0; value->length = 0;
return PSYC_TEXT_VALUE_FOUND; return PSYC_TEXT_VALUE_FOUND;
} }
PsycTextValueRC getValueNotFound (const char *name, size_t len, PsycString *value, void *extra) PsycTextValueRC
getValueNotFound (const char *name, size_t len, PsycString *value, void *extra)
{ {
if (verbose) if (verbose)
printf("> getValue: %.*s\n", (int)len, name); printf("> getValue: %.*s\n", (int)len, name);
return PSYC_TEXT_VALUE_NOT_FOUND; return PSYC_TEXT_VALUE_NOT_FOUND;
} }
int testText (char *template, size_t tmplen, char *buffer, size_t buflen, PsycString *result, PsycTextCB getValue) int
testText (char *template, size_t tmplen, char *buffer, size_t buflen,
PsycString *result, PsycTextCB getValue)
{ {
PsycTextState state; PsycTextState state;
size_t length = 0; size_t length = 0;
PsycTextRC ret; PsycTextRC ret;
psyc_text_state_init(&state, template, tmplen, buffer, buflen); psyc_text_state_init(&state, template, tmplen, buffer, buflen);
do do {
{ ret = psyc_text(&state, getValue, NULL);
ret = psyc_text(&state, getValue, NULL); length += psyc_text_bytes_written(&state);
length += psyc_text_bytes_written(&state); switch (ret) {
switch (ret) case PSYC_TEXT_INCOMPLETE:
{ if (verbose)
case PSYC_TEXT_INCOMPLETE: printf("# %.*s...\n", (int)length, buffer);
if (verbose) psyc_text_buffer_set(&state, buffer + length, BUFSIZE - length);
printf("# %.*s...\n", (int)length, buffer); break;
psyc_text_buffer_set(&state, buffer + length, BUFSIZE - length); case PSYC_TEXT_COMPLETE:
break; if (verbose)
case PSYC_TEXT_COMPLETE: printf("%.*s\n", (int)length, buffer);
if (verbose) result->length = length;
printf("%.*s\n", (int)length, buffer); result->data = buffer;
result->length = length; return ret;
result->data = buffer; case PSYC_TEXT_NO_SUBST:
return ret; if (verbose)
case PSYC_TEXT_NO_SUBST: printf("%.*s\n", (int)tmplen, template);
if (verbose) return ret;
printf("%.*s\n", (int)tmplen, template);
return ret;
}
} }
while (ret == PSYC_TEXT_INCOMPLETE); }
while (ret == PSYC_TEXT_INCOMPLETE);
return -2; // shouldn't be reached return -2; // shouldn't be reached
} }
int main(int argc, char **argv) int
main (int argc, char **argv)
{ {
verbose = argc > 1; verbose = argc > 1;
char buffer[BUFSIZE]; char buffer[BUFSIZE];
PsycString result; PsycString result;
char *str = "Hello [_foo] & [_bar]!"; char *str = "Hello [_foo] & [_bar]!";
size_t len = strlen(str); size_t len = strlen(str);
int i; int i;
testText(str, len, buffer, BUFSIZE, &result, &getValueFooBar); testText(str, len, buffer, BUFSIZE, &result, &getValueFooBar);
if (memcmp(result.data, PSYC_C2ARG("Hello Foo Bar & Foo Bar!")))
return 1;
testText(str, len, buffer, BUFSIZE, &result, &getValueEmpty);
if (memcmp(result.data, PSYC_C2ARG("Hello & !")))
return 2;
if (PSYC_TEXT_NO_SUBST != testText(str, len, buffer, BUFSIZE,
&result, &getValueNotFound))
return 3;
for (i = 1; i < 22; i++) {
testText(str, len, buffer, i, &result, &getValueFooBar);
if (memcmp(result.data, PSYC_C2ARG("Hello Foo Bar & Foo Bar!"))) if (memcmp(result.data, PSYC_C2ARG("Hello Foo Bar & Foo Bar!")))
return 1; return 10 + i;
}
testText(str, len, buffer, BUFSIZE, &result, &getValueEmpty); puts("psyc_text passed all tests.");
if (memcmp(result.data, PSYC_C2ARG("Hello & !")))
return 2;
if (testText(str, len, buffer, BUFSIZE, &result, &getValueNotFound) != PSYC_TEXT_NO_SUBST) return 0;
return 3;
for (i = 1; i < 22; i++)
{
testText(str, len, buffer, i, &result, &getValueFooBar);
if (memcmp(result.data, PSYC_C2ARG("Hello Foo Bar & Foo Bar!")))
return 10 + i;
}
puts("psyc_text passed all tests.");
return 0;
} }

View file

@ -4,51 +4,57 @@
#include <lib.h> #include <lib.h>
void void
testUniform (char *str, int ret) { testUniform (char *str, int ret)
PsycUniform *uni = malloc(sizeof(PsycUniform)); {
memset(uni, 0, sizeof(PsycUniform)); PsycUniform *uni = malloc(sizeof(PsycUniform));
printf("%s\n", str); memset(uni, 0, sizeof(PsycUniform));
int r = psyc_uniform_parse(uni, str, strlen(str)); printf("%s\n", str);
int r = psyc_uniform_parse(uni, str, strlen(str));
PP(("[%.*s] : [%.*s] [%.*s] : [%.*s] [%.*s] / [%.*s] # [%.*s]\n[%.*s]\n[%.*s] [%.*s]\n[%.*s]\n\n", PP(("[%.*s] : [%.*s] [%.*s] : [%.*s] [%.*s] / "
(int)PSYC_S2ARG2(uni->scheme), "[%.*s] # [%.*s]\n[%.*s]\n[%.*s] [%.*s]\n[%.*s]\n\n",
(int)PSYC_S2ARG2(uni->slashes), (int)PSYC_S2ARG2(uni->scheme),
(int)PSYC_S2ARG2(uni->host), (int)PSYC_S2ARG2(uni->slashes),
(int)PSYC_S2ARG2(uni->port), (int)PSYC_S2ARG2(uni->host),
(int)PSYC_S2ARG2(uni->transport), (int)PSYC_S2ARG2(uni->port),
(int)PSYC_S2ARG2(uni->resource), (int)PSYC_S2ARG2(uni->transport),
(int)PSYC_S2ARG2(uni->channel), (int)PSYC_S2ARG2(uni->resource),
(int)PSYC_S2ARG2(uni->entity), (int)PSYC_S2ARG2(uni->channel),
(int)PSYC_S2ARG2(uni->root), (int)PSYC_S2ARG2(uni->entity),
(int)PSYC_S2ARG2(uni->nick), (int)PSYC_S2ARG2(uni->root),
(int)PSYC_S2ARG2(uni->body))); (int)PSYC_S2ARG2(uni->nick),
(int)PSYC_S2ARG2(uni->body)));
free(uni); free(uni);
if (r != ret) { if (r != ret) {
fprintf(stderr, "ERROR: psyc_uniform_parse returned %d instead of %d\n", r, ret); fprintf(stderr, "ERROR: psyc_uniform_parse returned %d instead of %d\n",
exit(1); r, ret);
} exit(1);
}
} }
int main () { int
testUniform("psyc://foo.tld:4404d/@bar#baz", PSYC_SCHEME_PSYC); main ()
testUniform("psyc://foo:4405/~bar", PSYC_SCHEME_PSYC); {
testUniform("psyc://foo:1234", PSYC_SCHEME_PSYC); testUniform("psyc://foo.tld:4404d/@bar#baz", PSYC_SCHEME_PSYC);
testUniform("psyc://foo:1234d", PSYC_SCHEME_PSYC); testUniform("psyc://foo:4405/~bar", PSYC_SCHEME_PSYC);
testUniform("psyc://foo:-1234", PSYC_SCHEME_PSYC); testUniform("psyc://foo:1234", PSYC_SCHEME_PSYC);
testUniform("psyc://foo:-1234d", PSYC_SCHEME_PSYC); testUniform("psyc://foo:1234d", PSYC_SCHEME_PSYC);
testUniform("psyc://foo/", PSYC_SCHEME_PSYC); testUniform("psyc://foo:-1234", PSYC_SCHEME_PSYC);
testUniform("psyc://foo", PSYC_SCHEME_PSYC); testUniform("psyc://foo:-1234d", PSYC_SCHEME_PSYC);
testUniform("psyc://1234567890abcdef:g/~foo", PSYC_SCHEME_PSYC); testUniform("psyc://foo/", PSYC_SCHEME_PSYC);
testUniform("psyc://foo", PSYC_SCHEME_PSYC);
testUniform("psyc://1234567890abcdef:g/~foo", PSYC_SCHEME_PSYC);
testUniform("xmpp:user@host", PSYC_PARSE_UNIFORM_INVALID_SCHEME); testUniform("xmpp:user@host", PSYC_PARSE_UNIFORM_INVALID_SCHEME);
testUniform("psyc:host", PSYC_PARSE_UNIFORM_INVALID_SLASHES); testUniform("psyc:host", PSYC_PARSE_UNIFORM_INVALID_SLASHES);
testUniform("psyc://", PSYC_PARSE_UNIFORM_INVALID_HOST); testUniform("psyc://", PSYC_PARSE_UNIFORM_INVALID_HOST);
testUniform("psyc://:123/", PSYC_PARSE_UNIFORM_INVALID_HOST); testUniform("psyc://:123/", PSYC_PARSE_UNIFORM_INVALID_HOST);
testUniform("psyc://host:/~foo", PSYC_PARSE_UNIFORM_INVALID_PORT); testUniform("psyc://host:/~foo", PSYC_PARSE_UNIFORM_INVALID_PORT);
testUniform("psyc://host:d/~foo", PSYC_PARSE_UNIFORM_INVALID_PORT); testUniform("psyc://host:d/~foo", PSYC_PARSE_UNIFORM_INVALID_PORT);
testUniform("psyc://1234567890abcdef:1g/~foo", PSYC_PARSE_UNIFORM_INVALID_TRANSPORT); testUniform("psyc://1234567890abcdef:1g/~foo",
PSYC_PARSE_UNIFORM_INVALID_TRANSPORT);
printf("SUCCESS: psyc_uniform_parse passed all tests.\n"); printf("SUCCESS: psyc_uniform_parse passed all tests.\n");
return 0; return 0;
} }

View file

@ -6,34 +6,32 @@
int main() { int main() {
#if 0 #if 0
const char* vars[] = const char* vars[] = {
{ "_source",
"_source", "_source_relay",
"_source_relay", "_source_foo",
"_source_foo", "_sourcherry",
"_sourcherry", "_foo",
"_foo", "bar",
"bar", "_",
"_", };
};
int i; int i;
for (i = 0; i < sizeof(vars) / sizeof(*vars); i++) for (i = 0; i < sizeof(vars) / sizeof(*vars); i++) {
{ printf(">> %s: %d %d\n", vars[i], sizeof(vars[i]), sizeof(*vars[i]));
printf(">> %s: %d %d\n", vars[i], sizeof(vars[i]), sizeof(*vars[i])); printf("%s: %d\n", vars[i], psyc_var_is_routing(vars[i], strlen(vars[i])));
printf("%s: %d\n", vars[i], psyc_var_is_routing(vars[i], strlen(vars[i]))); }
}
#else #else
unless (psyc_var_is_routing(PSYC_C2ARG("_source"))) return 1; unless (psyc_var_is_routing(PSYC_C2ARG("_source"))) return 1;
unless (psyc_var_is_routing(PSYC_C2ARG("_source_relay"))) return 2; unless (psyc_var_is_routing(PSYC_C2ARG("_source_relay"))) return 2;
if (psyc_var_is_routing(PSYC_C2ARG("_source_foo"))) return 3; if (psyc_var_is_routing(PSYC_C2ARG("_source_foo"))) return 3;
if (psyc_var_is_routing(PSYC_C2ARG("_sourcherry"))) return 4; if (psyc_var_is_routing(PSYC_C2ARG("_sourcherry"))) return 4;
if (psyc_var_is_routing(PSYC_C2ARG("_sour"))) return 5; if (psyc_var_is_routing(PSYC_C2ARG("_sour"))) return 5;
if (psyc_var_is_routing(PSYC_C2ARG("_foo"))) return 6; if (psyc_var_is_routing(PSYC_C2ARG("_foo"))) return 6;
if (psyc_var_is_routing(PSYC_C2ARG("bar"))) return 7; if (psyc_var_is_routing(PSYC_C2ARG("bar"))) return 7;
if (psyc_var_is_routing(PSYC_C2ARG("_"))) return 8; if (psyc_var_is_routing(PSYC_C2ARG("_"))) return 8;
puts("psyc_var_is_routing passed all tests."); puts("psyc_var_is_routing passed all tests.");
#endif #endif
return 0; // passed all tests return 0; // passed all tests
} }

View file

@ -5,17 +5,17 @@
#include <lib.h> #include <lib.h>
int main() { int main() {
unless (psyc_var_type(PSYC_C2ARG("_list"))) return 1; unless (psyc_var_type(PSYC_C2ARG("_list"))) return 1;
unless (psyc_var_type(PSYC_C2ARG("_list_foo"))) return 2; unless (psyc_var_type(PSYC_C2ARG("_list_foo"))) return 2;
unless (psyc_var_type(PSYC_C2ARG("_color_red"))) return 3; unless (psyc_var_type(PSYC_C2ARG("_color_red"))) return 3;
if (psyc_var_type(PSYC_C2ARG("_last"))) return 4; if (psyc_var_type(PSYC_C2ARG("_last"))) return 4;
if (psyc_var_type(PSYC_C2ARG("_lost_foo"))) return 5; if (psyc_var_type(PSYC_C2ARG("_lost_foo"))) return 5;
if (psyc_var_type(PSYC_C2ARG("_colorful"))) return 6; if (psyc_var_type(PSYC_C2ARG("_colorful"))) return 6;
if (psyc_var_type(PSYC_C2ARG("_foo"))) return 7; if (psyc_var_type(PSYC_C2ARG("_foo"))) return 7;
if (psyc_var_type(PSYC_C2ARG("bar"))) return 8; if (psyc_var_type(PSYC_C2ARG("bar"))) return 8;
if (psyc_var_type(PSYC_C2ARG("______"))) return 9; if (psyc_var_type(PSYC_C2ARG("______"))) return 9;
if (psyc_var_type(PSYC_C2ARG("_"))) return 10; if (psyc_var_type(PSYC_C2ARG("_"))) return 10;
puts("psyc_var_type passed all tests."); puts("psyc_var_type passed all tests.");
return 0; // passed all tests return 0; // passed all tests
} }