mirror of
git://git.psyc.eu/libpsyc
synced 2024-08-15 03:19:02 +00:00
indent
This commit is contained in:
parent
aee9203df6
commit
1cc58abd0e
31 changed files with 2797 additions and 2759 deletions
3
Makefile
3
Makefile
|
@ -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
|
||||||
|
|
||||||
|
|
128
include/psyc.h
128
include/psyc.h
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
135
src/itoa.c
135
src/itoa.c
|
@ -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
|
||||||
|
|
281
src/match.c
281
src/match.c
|
@ -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
|
||||||
|
|
45
src/memmem.c
45
src/memmem.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
259
src/packet.c
259
src/packet.c
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
874
src/parse.c
874
src/parse.c
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
197
src/render.c
197
src/render.c
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
133
src/text.c
133
src/text.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
317
src/uniform.c
317
src/uniform.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
136
src/variable.c
136
src/variable.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
370
test/test.c
370
test/test.c
|
@ -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!
|
|
||||||
}
|
}
|
||||||
|
|
18
test/test.h
18
test/test.h
|
@ -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
|
||||||
|
|
147
test/test_json.c
147
test/test_json.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
622
test/test_psyc.c
622
test/test_psyc.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
144
test/test_text.c
144
test/test_text.c
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue