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

dict syntax; index & update mod parser; psyc-mode for emacs

This commit is contained in:
Gabor Adam Toth 2012-02-06 15:05:08 +01:00
parent 3ee2f0e392
commit d3aa4508b9
31 changed files with 2063 additions and 691 deletions

4
.gitignore vendored
View file

@ -19,7 +19,9 @@ test/test_strlen
test/test_text
test/test_table
test/test_packet_id
test/var_is_routing
test/test_index
test/test_update
test/var_routing
test/var_type
test/uniform_parse

124
emacs/psyc.el Normal file
View file

@ -0,0 +1,124 @@
(require 'font-lock)
(setq
psyc-op "\\([:!?=$@+-]\\)"
psyc-routing-op "^\\([:=]\\)"
psyc-state-op "^\\([?=]\\)$"
psyc-num "\\([0-9]+\\)"
psyc-kw "\\([a-z_][a-z0-9_]*\\)"
psyc-length "^[0-9]+$"
psyc-routing-var-names (regexp-opt '("_amount_fragments" "_context" "_counter"
"_fragment" "_source" "_source_relay"
"_target" "_target_relay"
"_tag" "_tag_relay") 'word)
psyc-routing-var (concat psyc-routing-op psyc-routing-var-names)
psyc-types (concat "\\([a-z][a-z0-9]+\\|"
(regexp-opt '("_dict" "_list" "_struct"
"_int" "_uint" "_num" "_unum" "_flag" "_amount"
"_date" "_time" "_uniform") nil)
"\\)")
psyc-mod-op (concat "^" psyc-op)
psyc-mod-name (concat psyc-mod-op psyc-kw) ;2
psyc-mod-type (concat psyc-mod-op psyc-types "\\b") ;2
psyc-mod-len (concat psyc-mod-op psyc-kw " " psyc-num) ;3
psyc-mod-delim (concat "\\(?: " psyc-num "\\)?[\t ]+")
psyc-mod (concat psyc-mod-op psyc-kw psyc-mod-delim) ;3
psyc-default-name (concat psyc-mod psyc-kw "[|{]") ;4
psyc-default-type (concat psyc-mod psyc-types "[_|{]") ;4
; psyc-default-name (concat "[\t ]" psyc-kw "[|{]")
; psyc-default-type (concat "[\t ]" psyc-types "[_|{]")
psyc-elem-delim "[|{}]"
psyc-elem-start "[|}]"
psyc-elem-op (concat psyc-elem-start "\\(=\\)")
psyc-elem-name (concat psyc-elem-start "=" psyc-kw)
psyc-elem-type (concat psyc-elem-start "=" psyc-types "\\b")
psyc-elem-name-delim (concat psyc-elem-name "\\(:\\)") ;2
psyc-elem-len (concat "\\(?:" psyc-elem-name-delim "\\)?" psyc-num) ;3
psyc-update-op (concat "^@" psyc-kw psyc-mod-delim ".+ " psyc-op) ;3
psyc-update-name (concat "^@" psyc-kw psyc-mod-delim ".+ "
psyc-op psyc-kw) ;4
psyc-update-type (concat "^@" psyc-kw psyc-mod-delim ".+ "
psyc-op psyc-types "\\b") ;4
psyc-update-len-delim (concat "^@" psyc-kw psyc-mod-delim ".+ "
psyc-op psyc-kw "?\\(:\\)") ;5
psyc-update-len (concat "^@" psyc-kw psyc-mod-delim ".+ "
psyc-op psyc-kw "?:" psyc-num) ;5
psyc-index-delim "\\(#\\)-?[0-9]+"
psyc-struct-delim "[\t0-9}]\\(\\.\\)"
psyc-struct-name (concat psyc-struct-delim psyc-kw) ;2
psyc-struct-type (concat psyc-struct-delim psyc-types "\\b") ;2
psyc-dict-key-len (concat "{" psyc-num)
psyc-dict-key (concat "{\\(?:" psyc-num " \\)?\\([^}]+\\)") ;2
psyc-method (concat "^_" psyc-kw)
;psyc-body "^[^_:!?=$@+-].*$"
psyc-tmpl-start (concat "\\(\\[\\)" psyc-kw ".+?\\]")
psyc-tmpl-end (concat "\\[" psyc-kw ".+?\\(\\]\\)")
psyc-packet-delim "^|$"
psyc-font-lock-keywords
`(
(,psyc-routing-var . (2 font-lock-keyword-face t))
(,psyc-length . (0 font-lock-constant-face))
(,psyc-state-op . (0 font-lock-preprocessor-face))
(,psyc-mod-op . (1 font-lock-preprocessor-face))
(,psyc-mod-name . (2 font-lock-variable-name-face))
(,psyc-mod-type . (2 font-lock-type-face t))
(,psyc-mod-len . (3 font-lock-constant-face))
(,psyc-default-name . (4 font-lock-variable-name-face))
(,psyc-default-type . (4 font-lock-type-face t))
(,psyc-dict-key-len . (1 font-lock-constant-face))
(,psyc-dict-key . (2 font-lock-string-face))
(,psyc-elem-op . (1 font-lock-preprocessor-face))
(,psyc-elem-name . (1 font-lock-variable-name-face))
(,psyc-elem-type . (1 font-lock-type-face t))
(,psyc-elem-name-delim . (2 font-lock-comment-face))
(,psyc-elem-len . (3 font-lock-constant-face))
(,psyc-elem-delim . (0 font-lock-keyword-face))
(,psyc-update-op . (3 font-lock-preprocessor-face))
(,psyc-update-name . (4 font-lock-variable-name-face))
(,psyc-update-type . (4 font-lock-type-face t))
(,psyc-update-len-delim . (5 font-lock-comment-face))
(,psyc-update-len . (5 font-lock-constant-face))
(,psyc-method . (0 font-lock-function-name-face))
;(,psyc-body . (0 font-lock-comment-face))
(,psyc-index-delim . (1 font-lock-comment-face))
(,psyc-struct-name . (1 font-lock-comment-face))
(,psyc-struct-name . (2 font-lock-variable-name-face))
(,psyc-struct-type . (2 font-lock-type-face t))
(,psyc-tmpl-start . (1 font-lock-keyword-face))
(,psyc-tmpl-end . (2 font-lock-keyword-face))
(,psyc-packet-delim . (0 font-lock-preprocessor-face))
))
(define-derived-mode psyc-mode fundamental-mode
"PSYC"
"Major mode for editing PSYC packets"
(setq font-lock-defaults '((psyc-font-lock-keywords)))
(setq show-trailing-whitespace t))
(provide 'psyc)

View file

@ -24,7 +24,6 @@
#define PSYC_VERSION 1
#define PSYC_EPOCH 1440444041 // 2015-08-24 21:20:41 CET (Monday)
#define PSYC_STRING(data, len) (PsycString) {len, data}
#define PSYC_C2STR(str) (PsycString) {sizeof(str)-1, str}
#define PSYC_C2STRI(str) {sizeof(str)-1, str}
#define PSYC_C2ARG(str) str, sizeof(str)-1
@ -50,53 +49,6 @@ typedef enum {
PSYC_ERROR = -1,
} PsycRC;
/// PSYC packet parts.
typedef enum {
PSYC_PART_RESET = -1,
PSYC_PART_ROUTING = 0,
PSYC_PART_LENGTH = 1,
PSYC_PART_CONTENT = 2,
PSYC_PART_METHOD = 3,
PSYC_PART_DATA = 4,
PSYC_PART_END = 5,
} PsycPart;
/**
* Different types that a variable can have.
*
* This enum lists PSYC variable types that
* this library is capable of checking for
* validity. Other variable types are treated
* as opaque data.
*/
typedef enum {
PSYC_TYPE_UNKNOWN,
PSYC_TYPE_AMOUNT,
PSYC_TYPE_COLOR,
PSYC_TYPE_COUNTER,
PSYC_TYPE_DEF,
PSYC_TYPE_DATE,
PSYC_TYPE_DEGREE,
PSYC_TYPE_ENTITY,
PSYC_TYPE_FLAG,
PSYC_TYPE_LANGUAGE,
PSYC_TYPE_LIST,
PSYC_TYPE_NICK,
PSYC_TYPE_PAGE,
PSYC_TYPE_TABLE,
PSYC_TYPE_TIME,
PSYC_TYPE_UNIFORM,
} PsycType;
/**
* List types.
* Possible types are text and binary.
*/
typedef enum {
PSYC_LIST_TEXT = 1,
PSYC_LIST_BINARY = 2,
} PsycListType;
/**
* String struct.
*
@ -109,14 +61,15 @@ typedef struct {
char *data;
} PsycString;
#include "psyc/syntax.h"
#define PSYC_STRING(data, len) (PsycString) {len, data}
#include "psyc/match.h"
#include "psyc/method.h"
#include "psyc/packet.h"
#include "psyc/variable.h"
#include "psyc/parse.h"
#include "psyc/render.h"
#include "psyc/text.h"
#include "psyc/uniform.h"
#include "psyc/variable.h"
#endif

View file

@ -4,7 +4,7 @@ prefix = /usr
includedir = ${prefix}/include
INSTALL = install
HEADERS = match.h method.h packet.h parse.h render.h syntax.h text.h uniform.h variable.h
HEADERS = match.h method.h packet.h parse.h render.h text.h uniform.h variable.h
install: ${HEADERS}

View file

@ -1,12 +1,15 @@
#ifndef PSYC_MATCH_H
#define PSYC_MATCH_H
typedef struct {
PsycString key;
void *value;
} PsycDict;
} PsycMap;
typedef struct {
PsycString key;
intptr_t value;
} PsycDictInt;
} PsycMapInt;
/**
* Checks if long keyword string inherits from short keyword string.
@ -21,10 +24,10 @@ int
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 map.
*
* @param dict The dictionary to search, should be ordered alphabetically.
* @param size Size of dict.
* @param map The dictionary to search, should be ordered alphabetically.
* @param size Size of map.
* @param key Key to look for.
* @param keylen Length of key.
* @param inherit If true, also look for anything inheriting from key,
@ -34,16 +37,18 @@ psyc_matches (char *sho, size_t slen, char *lon, size_t llen);
*/
void *
psyc_dict_lookup (const PsycDict *dict, size_t size,
psyc_map_lookup (const PsycMap *map, size_t size,
const char *key, size_t keylen, PsycBool inherit);
/**
* Look up value associated with a key in a dictionary of integers.
* @see psyc_dict_lookup
* Look up value associated with a key in a map with integer values.
* @see psyc_map_lookup
*/
static inline intptr_t
psyc_dict_lookup_int (const PsycDictInt * dict, size_t size,
psyc_map_lookup_int (const PsycMapInt * map, size_t size,
const char *key, size_t keylen, PsycBool inherit)
{
return (intptr_t) psyc_dict_lookup((PsycDict *) dict, size, key, keylen, inherit);
return (intptr_t) psyc_map_lookup((PsycMap *) map, size, key, keylen, inherit);
}
#endif

View file

@ -18,9 +18,53 @@
#include <math.h>
#include "syntax.h"
#include "method.h"
/**
* Maximum allowed content size without length.
* Parser stops after reaching this limit.
*/
#define PSYC_CONTENT_SIZE_MAX 512
/**
* Content size after which a length is added when rendering.
*/
#ifndef PSYC_CONTENT_SIZE_THRESHOLD
# define PSYC_CONTENT_SIZE_THRESHOLD 9
#endif
/**
* Maximum allowed modifier size without length.
* Parser stops after reaching this limit.
*/
#define PSYC_MODIFIER_SIZE_MAX 256
/**
* Modifier size after which a length is added when rendering.
*/
#ifndef PSYC_MODIFIER_SIZE_THRESHOLD
# define PSYC_MODIFIER_SIZE_THRESHOLD 9
#endif
/**
* Maximum allowed element size without length.
* Parser stops after reaching this limit.
*/
#define PSYC_ELEM_SIZE_MAX 128
/**
* Element size after which a length is added when rendering.
*/
#ifndef PSYC_ELEM_SIZE_THRESHOLD
# define PSYC_ELEM_SIZE_THRESHOLD 9
#endif
#define PSYC_PACKET_DELIMITER_CHAR '|'
#define PSYC_PACKET_DELIMITER "\n|\n"
#define PSYC_LIST_ELEM_START '|'
#define PSYC_DICT_KEY_START '{'
#define PSYC_DICT_KEY_END '}'
#define PSYC_DICT_VALUE_START PSYC_DICT_KEY_END
#define PSYC_DICT_VALUE_END PSYC_DICT_KEY_START
/** Modifier flags. */
typedef enum {
/// Modifier needs to be checked if it needs length.
@ -30,18 +74,18 @@ typedef enum {
/// Modifier doesn't need length.
PSYC_MODIFIER_NO_LENGTH = 2,
/// Routing modifier, which implies that it doesn't need length.
PSYC_MODIFIER_ROUTING = 3,
PSYC_MODIFIER_ROUTING = 4,
} PsycModifierFlag;
/** List flags. */
/** List/dict element flags. */
typedef enum {
/// List needs to be checked if it needs length.
PSYC_LIST_CHECK_LENGTH = 0,
/// List needs length.
PSYC_LIST_NEED_LENGTH = 1,
/// List doesn't need length.
PSYC_LIST_NO_LENGTH = 2,
} PsycListFlag;
/// Element needs to be checked if it needs length.
PSYC_ELEM_CHECK_LENGTH = 0,
/// Element needs length.
PSYC_ELEM_NEED_LENGTH = 1,
/// Element doesn't need length.
PSYC_ELEM_NO_LENGTH = 2,
} PsycElemFlag;
/** Packet flags. */
typedef enum {
@ -77,35 +121,90 @@ typedef enum {
PSYC_PACKET_ID_ELEMS = 5,
} PsycPacketId;
/** Structure for a modifier. */
typedef struct {
char oper;
PsycString type;
PsycString value;
size_t length;
PsycElemFlag flag;
} PsycElem;
#define PSYC_ELEM(typ, typlen, val, vallen, flg) \
(PsycElem) { \
.type = PSYC_STRING(typ, typlen), \
.value = PSYC_STRING(val, vallen), \
.flag = flg, \
}
#define PSYC_ELEM_TV(typ, typlen, val, vallen) \
(PsycElem) { \
.type = PSYC_STRING(typ, typlen), \
.value = PSYC_STRING(val, vallen), \
}
#define PSYC_ELEM_VF(val, vallen, flg) \
(PsycElem) { \
.value = PSYC_STRING(val, vallen), \
.flag = flg, \
}
#define PSYC_ELEM_V(val, vallen) \
(PsycElem) { \
.value = PSYC_STRING(val, vallen), \
}
/** Dict key */
typedef struct {
PsycString value;
size_t length;
PsycElemFlag flag;
} PsycDictKey;
#define PSYC_DICT_KEY(k, klen, flg) \
(PsycDictKey) { \
.value = PSYC_STRING(k, klen), \
.flag = flg, \
}
/** Dict key/value */
typedef struct {
PsycElem value;
PsycDictKey key;
} PsycDictElem;
#define PSYC_DICT_ELEM(k, v) \
(PsycDictElem) { \
.key = k, \
.value = v, \
}
/** Dictionary */
typedef struct {
PsycString type;
PsycDictElem *elems;
size_t num_elems;
size_t length;
} PsycDict;
/** List */
typedef struct {
PsycString type;
PsycElem *elems;
size_t num_elems;
size_t length;
} PsycList;
/** Modifier */
typedef struct {
PsycString name;
PsycString value;
PsycModifierFlag flag;
char oper;
} PsycModifier;
/** Structure for an entity or routing header. */
/** Entity or routing header */
typedef struct {
size_t lines;
PsycModifier *modifiers;
} PsycHeader;
/** Structure for a list. */
typedef struct {
size_t num_elems;
PsycString *elems;
size_t length;
PsycListFlag flag;
} PsycList;
typedef struct {
PsycList *list;
size_t width;
size_t length;
} PsycTable;
/** Intermediate struct for a PSYC packet */
/** Intermediate struct for a PSYC packet. */
typedef struct {
PsycHeader routing; ///< Routing header.
PsycHeader entity; ///< Entity header.
@ -135,16 +234,12 @@ psyc_num_length (size_t n)
static inline PsycModifierFlag
psyc_modifier_length_check (PsycModifier *m)
{
PsycModifierFlag flag;
if (m->value.length > 0
&& (m->value.length > PSYC_MODIFIER_SIZE_THRESHOLD
|| memchr(m->value.data, (int) '\n', m->value.length)))
return PSYC_MODIFIER_NEED_LENGTH;
if (m->value.length > PSYC_MODIFIER_SIZE_THRESHOLD)
flag = PSYC_MODIFIER_NEED_LENGTH;
else if (memchr(m->value.data, (int) '\n', m->value.length))
flag = PSYC_MODIFIER_NEED_LENGTH;
else
flag = PSYC_MODIFIER_NO_LENGTH;
return flag;
return PSYC_MODIFIER_NO_LENGTH;
}
/** Initialize modifier */
@ -153,33 +248,61 @@ psyc_modifier_init (PsycModifier *m, PsycOperator oper,
char *name, size_t namelen,
char *value, size_t valuelen, PsycModifierFlag flag)
{
*m = (PsycModifier) {oper, {namelen, name}, {valuelen, value}, flag};
*m = (PsycModifier) {
.oper = oper,
.name = {namelen, name},
.value = {valuelen, value},
.flag = flag
};
if (flag == PSYC_MODIFIER_CHECK_LENGTH) // find out if it needs a length
m->flag = psyc_modifier_length_check(m);
else if (flag & PSYC_MODIFIER_ROUTING)
m->flag |= PSYC_MODIFIER_NO_LENGTH;
}
/**
* \internal
* Get the total length of a modifier when rendered.
* Check if a list/dict element needs length.
*/
PsycElemFlag
psyc_elem_length_check (PsycString *value, const char end);
/**
* \internal
* Get the rendered length of a list/dict element.
*/
size_t
psyc_elem_length (PsycElem *elem);
/**
* \internal
* Get the rendered length of a dict key.
*/
size_t
psyc_dict_key_length (PsycDictKey *elem);
/**
* \internal
* Get the rendered length of a list.
*/
size_t
psyc_list_length_set (PsycList *list);
/**
* \internal
* Get the rendered length of a dict.
*/
size_t
psyc_dict_length_set (PsycDict *dict);
/**
* \internal
* Get the rendered length of a modifier.
*/
size_t
psyc_modifier_length (PsycModifier *m);
/**
* \internal
* Check if a list needs length.
*/
PsycListFlag
psyc_list_length_check (PsycList *list);
/**
* \internal
* Get the total length of a list when rendered.
*/
PsycListFlag
psyc_list_length (PsycList *list);
/**
* \internal
* Check if a packet needs length.
@ -195,12 +318,11 @@ psyc_packet_length_set (PsycPacket *p);
/** Initialize a list. */
void
psyc_list_init (PsycList *list, PsycString *elems, size_t num_elems,
PsycListFlag flag);
psyc_list_init (PsycList *list, PsycElem *elems, size_t num_elems);
/** Initialize a table. */
/** Initialize a dict. */
void
psyc_table_init (PsycTable *table, size_t width, PsycList *list);
psyc_dict_init (PsycDict *dict, PsycDictElem *elems, size_t num_elems);
/** Initialize a packet. */
void
@ -218,10 +340,13 @@ psyc_packet_init_raw (PsycPacket *packet,
char *content, size_t contentlen,
PsycPacketFlag flag);
/** Get the total length of a packet ID when rendered. */
size_t
psyc_packet_id_length (size_t contextlen, size_t sourcelen, size_t targetelen,
size_t counterlen, size_t fragmentlen);
void
psyc_packet_id (PsycList *list, PsycElem *elems,
char *context, size_t contextlen,
char *source, size_t sourcelen,
char *target, size_t targetlen,
char *counter, size_t counterlen,
char *fragment, size_t fragmentlen);
/** @} */ // end of packet group

View file

@ -132,6 +132,10 @@ typedef enum {
* @see psyc_parse()
*/
typedef enum {
/// Error, no length is set for a modifier which is longer than PSYC_MODIFIER_SIZE_THRESHOLD.
PSYC_PARSE_ERROR_MOD_NO_LEN = -10,
/// Error, no length is set for the content but it is longer than PSYC_CONTENT_SIZE_THRESHOLD.
PSYC_PARSE_ERROR_NO_LEN = -9,
/// Error, packet is not ending with a valid delimiter.
PSYC_PARSE_ERROR_END = -8,
/// Error, expected NL after the method.
@ -197,106 +201,286 @@ typedef enum {
PSYC_PARSE_COMPLETE = 13,
} PsycParseRC;
/// PSYC packet parts.
typedef enum {
PSYC_PART_RESET = -1,
PSYC_PART_ROUTING = 0,
PSYC_PART_LENGTH = 1,
PSYC_PART_CONTENT = 2,
PSYC_PART_METHOD = 3,
PSYC_PART_DATA = 4,
PSYC_PART_END = 5,
} PsycPart;
/**
* The return value definitions for the list parsing function.
* @see psyc_parse_list()
*/
typedef enum {
PSYC_PARSE_LIST_ERROR_DELIM = -4,
PSYC_PARSE_LIST_ERROR_LEN = -3,
/// Error, no length is set for an element which is longer than PSYC_ELEM_SIZE_THRESHOLD.
PSYC_PARSE_LIST_ERROR_ELEM_NO_LEN = -6,
PSYC_PARSE_LIST_ERROR_ELEM_LENGTH = -5,
PSYC_PARSE_LIST_ERROR_ELEM_TYPE = -4,
PSYC_PARSE_LIST_ERROR_ELEM_START = -3,
PSYC_PARSE_LIST_ERROR_TYPE = -2,
PSYC_PARSE_LIST_ERROR = -1,
/// Completed parsing a list element.
PSYC_PARSE_LIST_ELEM = 1,
/// Reached end of buffer.
PSYC_PARSE_LIST_END = 2,
/// Binary list is incomplete.
PSYC_PARSE_LIST_INCOMPLETE = 3,
/// Buffer contains insufficient amount of data.
/// Fill another buffer and concatenate it with the end of the current buffer,
/// from the cursor position to the end.
PSYC_PARSE_LIST_INSUFFICIENT = 1,
/// Completed parsing the default type of the list.
PSYC_PARSE_LIST_TYPE = 2,
/// Start of an element is parsed but still not complete.
PSYC_PARSE_LIST_ELEM_START = 3,
/// Continuation of an incomplete element.
PSYC_PARSE_LIST_ELEM_CONT = 4,
/// Element parsing completed.
PSYC_PARSE_LIST_ELEM_END = 5,
/// Completed parsing a list element.
PSYC_PARSE_LIST_ELEM = 6,
/// Completed parsing the last element in the list.
PSYC_PARSE_LIST_ELEM_LAST = 7,
/// Reached end of buffer.
PSYC_PARSE_LIST_END = 8,
} PsycParseListRC;
typedef enum {
PSYC_PARSE_TABLE_ERROR_BODY = -5,
PSYC_PARSE_TABLE_ERROR_DELIM = -4,
PSYC_PARSE_TABLE_ERROR_HEAD = -3,
PSYC_PARSE_TABLE_ERROR_WIDTH = -2,
PSYC_PARSE_TABLE_ERROR = -1,
/// Completed parsing the width of the table.
PSYC_PARSE_TABLE_WIDTH = 1,
#ifdef PSYC_PARSE_TABLE_HEAD
/// Completed parsing the name of the key column.
PSYC_PARSE_TABLE_NAME_KEY = 2,
/// Completed parsing the name of a value column.
PSYC_PARSE_TABLE_NAME_VALUE = 3,
#endif
/// Completed parsing a key.
PSYC_PARSE_TABLE_KEY = 4,
/// Completed parsing a value.
PSYC_PARSE_TABLE_VALUE = 5,
/// Completed parsing a key and reached end of buffer.
PSYC_PARSE_TABLE_KEY_END = 6,
/// Completed parsing a value and reached end of buffer.
PSYC_PARSE_TABLE_VALUE_END = 7,
/// Binary table is incomplete.
PSYC_PARSE_TABLE_INCOMPLETE = 8,
} PsycParseTableRC;
PSYC_LIST_PART_START = 0,
PSYC_LIST_PART_TYPE = 1,
PSYC_LIST_PART_ELEM_START = 2,
PSYC_LIST_PART_ELEM_TYPE = 3,
PSYC_LIST_PART_ELEM_LENGTH = 4,
PSYC_LIST_PART_ELEM = 5,
} PsycListPart;
typedef enum {
PSYC_TABLE_PART_START = 0,
PSYC_TABLE_PART_WIDTH = 1,
#ifdef PSYC_PARSE_TABLE_HEAD
PSYC_TABLE_PART_HEAD_START = 2,
PSYC_TABLE_PART_HEAD = 3,
#endif
PSYC_TABLE_PART_BODY_START = 4,
PSYC_TABLE_PART_BODY = 5,
} PsycTablePart;
PSYC_PARSE_DICT_ERROR_VALUE = -9,
PSYC_PARSE_DICT_ERROR_VALUE_LENGTH = -8,
PSYC_PARSE_DICT_ERROR_VALUE_TYPE = -7,
PSYC_PARSE_DICT_ERROR_VALUE_START = -6,
PSYC_PARSE_DICT_ERROR_KEY = -5,
PSYC_PARSE_DICT_ERROR_KEY_LENGTH = -4,
PSYC_PARSE_DICT_ERROR_KEY_START = -3,
PSYC_PARSE_DICT_ERROR_TYPE = -2,
PSYC_PARSE_DICT_ERROR = -1,
/// Reached end of buffer.
/// Buffer contains insufficient amount of data.
/// Fill another buffer and concatenate it with the end of the current buffer,
/// from the cursor position to the end.
PSYC_PARSE_DICT_INSUFFICIENT = 1,
/// Completed parsing the default type of the dict.
PSYC_PARSE_DICT_TYPE = 2,
/// Start of a key is parsed but still not complete.
PSYC_PARSE_DICT_KEY_START = 3,
/// Continuation of an incomplete key.
PSYC_PARSE_DICT_KEY_CONT = 4,
/// Last continuation of a key.
PSYC_PARSE_DICT_KEY_END = 5,
/// Completed parsing a key in one go.
PSYC_PARSE_DICT_KEY = 6,
/// Start of a value is parsed but still not complete.
PSYC_PARSE_DICT_VALUE_START = 7,
/// Continuation of an incomplete value.
PSYC_PARSE_DICT_VALUE_CONT = 8,
/// Last continuation of a value.
PSYC_PARSE_DICT_VALUE_END = 9,
/// Completed parsing a value.
PSYC_PARSE_DICT_VALUE = 10,
/// Completed parsing the last value.
PSYC_PARSE_DICT_VALUE_LAST = 11,
/// Reached end of buffer.
PSYC_PARSE_DICT_END = 12,
} PsycParseDictRC;
typedef enum {
PSYC_DICT_PART_START = 0,
PSYC_DICT_PART_TYPE = 1,
PSYC_DICT_PART_KEY_START = 2,
PSYC_DICT_PART_KEY_LENGTH = 3,
PSYC_DICT_PART_KEY = 4,
PSYC_DICT_PART_VALUE_START = 5,
PSYC_DICT_PART_VALUE_TYPE = 6,
PSYC_DICT_PART_VALUE_LENGTH = 7,
PSYC_DICT_PART_VALUE = 8,
} PsycDictPart;
typedef enum {
PSYC_PARSE_INDEX_ERROR_DICT = -6,
PSYC_PARSE_INDEX_ERROR_DICT_LENGTH = -5,
PSYC_PARSE_INDEX_ERROR_STRUCT = -4,
PSYC_PARSE_INDEX_ERROR_LIST = -3,
PSYC_PARSE_INDEX_ERROR_TYPE = -2,
PSYC_PARSE_INDEX_ERROR = -1,
/// Reached end of buffer.
/// Buffer contains insufficient amount of data.
/// Fill another buffer and concatenate it with the end of the current buffer,
/// from the cursor position to the end.
PSYC_PARSE_INDEX_INSUFFICIENT = 1,
// Completed parsing a list index.
PSYC_PARSE_INDEX_LIST = 3,
// Completed parsing a list index at the end of the buffer.
PSYC_PARSE_INDEX_LIST_LAST = 4,
// Completed parsing a struct element name.
PSYC_PARSE_INDEX_STRUCT = 5,
// Completed parsing a struct element name at the end of the buffer.
PSYC_PARSE_INDEX_STRUCT_LAST = 6,
/// Start of a dict key is parsed but still not complete.
PSYC_PARSE_INDEX_DICT_START = 7,
/// Continuation of an incomplete dict key.
PSYC_PARSE_INDEX_DICT_CONT = 8,
/// Last continuation of a dict key.
PSYC_PARSE_INDEX_DICT_END = 9,
/// Completed parsing a dict key in one go.
PSYC_PARSE_INDEX_DICT = 10,
/// Reached end of buffer.
PSYC_PARSE_INDEX_END = 11,
} PsycParseIndexRC;
typedef enum {
PSYC_INDEX_PART_START = 0,
PSYC_INDEX_PART_TYPE = 1,
PSYC_INDEX_PART_LIST = 2,
PSYC_INDEX_PART_STRUCT = 3,
PSYC_INDEX_PART_DICT_LENGTH = 4,
PSYC_INDEX_PART_DICT = 5,
} PsycIndexPart;
typedef enum {
PSYC_PARSE_UPDATE_ERROR_VALUE = -24,
PSYC_PARSE_UPDATE_ERROR_LENGTH = -23,
PSYC_PARSE_UPDATE_ERROR_TYPE = -22,
PSYC_PARSE_UPDATE_ERROR_OPER = -21,
PSYC_PARSE_UPDATE_ERROR = -1,
/// Reached end of buffer.
/// Buffer contains insufficient amount of data.
/// Fill another buffer and concatenate it with the end of the current buffer,
/// from the cursor position to the end.
PSYC_PARSE_UPDATE_INSUFFICIENT = 1,
// Completed parsing a list index.
PSYC_PARSE_UPDATE_INDEX_LIST = 3,
// Completed parsing a struct element name.
PSYC_PARSE_UPDATE_INDEX_STRUCT = 5,
/// Start of a dict key is parsed but still not complete.
PSYC_PARSE_UPDATE_INDEX_DICT_START = 7,
/// Continuation of an incomplete dict key.
PSYC_PARSE_UPDATE_INDEX_DICT_CONT = 8,
/// Last continuation of a dict key.
PSYC_PARSE_UPDATE_INDEX_DICT_END = 9,
/// Completed parsing a dict key in one go.
PSYC_PARSE_UPDATE_INDEX_DICT = 10,
/// Completed parsing the type.
PSYC_PARSE_UPDATE_TYPE = 21,
/// Completed parsing the type and reached end of buffer.
PSYC_PARSE_UPDATE_TYPE_END = 22,
/// Start of the value is parsed but still not complete.
PSYC_PARSE_UPDATE_VALUE_START = 23,
/// Continuation of incomplete value.
PSYC_PARSE_UPDATE_VALUE_CONT = 24,
/// Last continuation of the value.
PSYC_PARSE_UPDATE_VALUE_END = 25,
/// Completed parsing the value in one go.
PSYC_PARSE_UPDATE_VALUE = 26,
/// Reached end of buffer.
PSYC_PARSE_UPDATE_END = 27,
} PsycParseUpdateRC;
typedef enum {
PSYC_UPDATE_PART_START = 0,
PSYC_UPDATE_INDEX_PART_TYPE = 1,
PSYC_UPDATE_INDEX_PART_LIST = 2,
PSYC_UPDATE_INDEX_PART_STRUCT = 3,
PSYC_UPDATE_INDEX_PART_DICT_LENGTH = 4,
PSYC_UPDATE_INDEX_PART_DICT = 5,
PSYC_UPDATE_PART_TYPE = 12,
PSYC_UPDATE_PART_LENGTH = 13,
PSYC_UPDATE_PART_VALUE = 14,
} PsycUpdatePart;
/**
* Struct for keeping parser state.
*/
typedef struct {
PsycString buffer; ///< Buffer with data to be parsed.
size_t cursor; ///< Current position in buffer.
size_t startc; ///< Position where the parsing would be resumed.
PsycString buffer; ///< Buffer with data to be parsed.
uint8_t flags; ///< Flags for the parser, see PsycParseFlag.
PsycPart part; ///< Part of the packet being parsed currently.
size_t routinglen; ///< Length of routing part parsed so far.
size_t content_parsed; ///< Number of bytes parsed from the content so far.
size_t contentlen; ///< Expected length of the content.
PsycBool contentlen_found; ///< Is there a length given for this packet?
size_t value_parsed; ///< Number of bytes parsed from the value so far.
size_t content_parsed; ///< Number of bytes parsed from the content so far.
size_t valuelen; ///< Expected length of the value.
PsycBool valuelen_found; ///< Is there a length given for this modifier?
size_t value_parsed; ///< Number of bytes parsed from the value so far.
PsycPart part; ///< Part of the packet being parsed currently.
uint8_t flags; ///< Flags for the parser, see PsycParseFlag.
uint8_t contentlen_found; ///< Is there a length given for this packet?
uint8_t valuelen_found; ///< Is there a length given for this modifier?
} PsycParseState;
/**
* Struct for keeping list parser state.
*/
typedef struct {
PsycString buffer; ///< Buffer with data to be parsed.
size_t cursor; ///< Current position in buffer.
size_t startc; ///< Line start position.
PsycString buffer; ///< Buffer with data to be parsed.
PsycListType type; ///< List type.
char term; ///< Terminator character at the end.
uint8_t term_set; ///< Look for terminator.
size_t elem_parsed; ///< Number of bytes parsed from the elem so far.
PsycString type; ///< List type.
size_t elemlen; ///< Expected length of the elem.
size_t elem_parsed; ///< Number of bytes parsed from the elem so far.
PsycListPart part; ///< Part of the list being parsed currently.
uint8_t elemlen_found; ///< Is there a length given for this element?
} PsycParseListState;
/**
* Struct for keeping table parser state.
* Struct for keeping dict parser state.
*/
typedef struct {
PsycString buffer; ///< Buffer with data to be parsed.
size_t cursor; ///< Current position in buffer.
size_t startc; ///< Line start position.
size_t elemlen; ///< Expected length of the key/value.
size_t elem_parsed; ///< Number of bytes parsed from the key/value so far.
PsycDictPart part; ///< Part of the dict being parsed currently.
uint8_t elemlen_found; ///< Is there a length given for this key/value?
} PsycParseDictState;
/**
* Struct for keeping index parser state.
*/
typedef struct {
PsycString buffer; ///< Buffer with data to be parsed.
PsycTablePart part; ///< Table type.
size_t width; ///< Width of table.
size_t elems; ///< Elems parsed so far in the table.
PsycParseListState list;
} PsycParseTableState;
size_t cursor; ///< Current position in buffer.
size_t startc; ///< Position where the parsing would be resumed.
size_t elemlen; ///< Expected length of an element.
size_t elem_parsed; ///< Number of bytes parsed from the elem so far.
PsycIndexPart part; ///< Part of the packet being parsed currently.
uint8_t elemlen_found; ///< Is there a length given for this element?
} PsycParseIndexState;
/**
* Struct for keeping update modifier parser state.
*/
typedef struct {
PsycString buffer; ///< Buffer with data to be parsed.
size_t cursor; ///< Current position in buffer.
size_t startc; ///< Position where the parsing would be resumed.
size_t elemlen; ///< Expected length of an element.
size_t elem_parsed; ///< Number of bytes parsed from the elem so far.
PsycUpdatePart part; ///< Part of the packet being parsed currently.
uint8_t elemlen_found; ///< Is there a length given for this element?
} PsycParseUpdateState;
/**
* Initializes the state struct.
@ -339,7 +523,7 @@ psyc_parse_buffer_set (PsycParseState *state, const char *buffer, size_t length)
}
/**
* Initializes the list state.
* Initializes the list parser state.
*/
static inline void
psyc_parse_list_state_init (PsycParseListState *state)
@ -358,27 +542,60 @@ psyc_parse_list_buffer_set (PsycParseListState *state,
state->cursor = 0;
}
/**
* Initializes the dict parser state.
*/
static inline void
psyc_parse_list_term_set (PsycParseListState *state, char term)
psyc_parse_dict_state_init (PsycParseDictState *state)
{
state->term = term;
state->term_set = PSYC_TRUE;
memset(state, 0, sizeof(PsycParseDictState));
}
/**
* Initializes the table state.
* Sets a new buffer in the dict parser state struct with data to be parsed.
*/
static inline void
psyc_parse_table_state_init (PsycParseTableState *state)
psyc_parse_dict_buffer_set (PsycParseDictState *state,
const char *buffer, size_t length)
{
memset(state, 0, sizeof(PsycParseTableState));
state->buffer = (PsycString) {length, (char*)buffer};
state->cursor = 0;
}
/**
* Sets a new buffer in the list parser state struct with data to be parsed.
* Initializes the index parser state.
*/
static inline void
psyc_parse_table_buffer_set (PsycParseTableState *state,
psyc_parse_index_state_init (PsycParseIndexState *state)
{
memset(state, 0, sizeof(PsycParseIndexState));
}
/**
* Sets a new buffer in the index parser state struct with data to be parsed.
*/
static inline void
psyc_parse_index_buffer_set (PsycParseIndexState *state,
const char *buffer, size_t length)
{
state->buffer = (PsycString) {length, (char*)buffer};
state->cursor = 0;
}
/**
* Initializes the update modifier parser state.
*/
static inline void
psyc_parse_update_state_init (PsycParseUpdateState *state)
{
memset(state, 0, sizeof(PsycParseUpdateState));
}
/**
* Sets a new buffer in the update modifier parser state struct with data to be parsed.
*/
static inline void
psyc_parse_update_buffer_set (PsycParseUpdateState *state,
const char *buffer, size_t length)
{
state->buffer = (PsycString) {length, (char*)buffer};
@ -471,10 +688,25 @@ psyc_parse (PsycParseState *state, char *oper,
static inline
#endif
PsycParseListRC
psyc_parse_list (PsycParseListState *state, PsycString *elem);
psyc_parse_list (PsycParseListState *state, PsycString *type, PsycString *elem);
PsycParseTableRC
psyc_parse_table (PsycParseTableState *state, PsycString *elem);
#ifdef __INLINE_PSYC_PARSE
static inline
#endif
PsycParseDictRC
psyc_parse_dict (PsycParseDictState *state, PsycString *type, PsycString *elem);
#ifdef __INLINE_PSYC_PARSE
static inline
#endif
PsycParseIndexRC
psyc_parse_index (PsycParseIndexState *state, PsycString *idx);
#ifdef __INLINE_PSYC_PARSE
static inline
#endif
PsycParseUpdateRC
psyc_parse_update (PsycParseUpdateState *state, char *oper, PsycString *value);
static inline size_t
psyc_parse_int (const char *value, size_t len, int64_t *n)
@ -516,7 +748,7 @@ psyc_parse_uint (const char *value, size_t len, uint64_t *n)
}
static inline size_t
psyc_parse_index (const char *value, size_t len, int64_t *n)
psyc_parse_list_index (const char *value, size_t len, int64_t *n)
{
if (!value || len == 0 || value[0] != '#')
return 0;

View file

@ -51,6 +51,12 @@ static inline
PsycRenderRC
psyc_render (PsycPacket *packet, char *buffer, size_t buflen);
PsycRenderRC
psyc_render_elem (PsycElem *elem, char *buffer, size_t buflen);
PsycRenderRC
psyc_render_dict_key (PsycDictKey *elem, char *buffer, size_t buflen);
/**
* Render a PSYC list into a buffer.
*/
@ -61,15 +67,7 @@ PsycRenderRC
psyc_render_list (PsycList *list, char *buffer, size_t buflen);
PsycRenderRC
psyc_render_table (PsycTable *table, char *buffer, size_t buflen);
PsycRenderRC
psyc_render_packet_id (char *context, size_t contextlen,
char *source, size_t sourcelen,
char *target, size_t targetlen,
char *counter, size_t counterlen,
char *fragment, size_t fragmentlen,
char *buffer, size_t buflen);
psyc_render_dict (PsycDict *dict, char *buffer, size_t buflen);
/** @} */ // end of render group

View file

@ -1,21 +0,0 @@
#ifndef PSYC_SYNTAX_H
#ifndef PSYC_LIST_SIZE_LIMIT
# define PSYC_LIST_SIZE_LIMIT 404
#endif
/* beyond this a content length must be provided */
#ifndef PSYC_CONTENT_SIZE_THRESHOLD
# define PSYC_CONTENT_SIZE_THRESHOLD 444
#endif
/* beyond this a modifier value length must be provided */
#ifndef PSYC_MODIFIER_SIZE_THRESHOLD
# define PSYC_MODIFIER_SIZE_THRESHOLD 404
#endif
#define PSYC_PACKET_DELIMITER_CHAR '|'
#define PSYC_PACKET_DELIMITER "\n|\n"
#define PSYC_SYNTAX_H
#endif

View file

@ -5,16 +5,17 @@
#ifndef PSYC_VARIABLE_H
#define PSYC_VARIABLE_H
#include "match.h"
#include "packet.h"
/// Routing variables in alphabetical order.
extern const PsycDictInt psyc_rvars[];
extern const PsycMapInt psyc_rvars[];
// Variable types in alphabetical order.
extern const PsycDictInt psyc_var_types[];
extern const PsycMapInt psyc_var_types[];
/// Method names in alphabetical order.
extern const PsycDictInt psyc_methods[];
extern const PsycMapInt psyc_methods[];
extern const size_t psyc_rvars_num;
extern const size_t psyc_var_types_num;
@ -37,14 +38,41 @@ typedef enum {
PSYC_RVARS_NUM,
} PsycRoutingVar;
/**
* Variable types.
*
* This enum lists PSYC variable types that
* this library is capable of checking for
* validity. Other variable types are treated
* as opaque data.
*/
typedef enum {
PSYC_TYPE_UNKNOWN,
PSYC_TYPE_AMOUNT,
PSYC_TYPE_COLOR,
PSYC_TYPE_COUNTER,
PSYC_TYPE_DATE,
PSYC_TYPE_DEGREE,
PSYC_TYPE_DICT,
PSYC_TYPE_ENTITY,
PSYC_TYPE_FLAG,
PSYC_TYPE_LANGUAGE,
PSYC_TYPE_LIST,
PSYC_TYPE_NICK,
PSYC_TYPE_PAGE,
PSYC_TYPE_STRUCT,
PSYC_TYPE_TIME,
PSYC_TYPE_UNIFORM,
} PsycType;
/**
* Look up routing variable.
*/
static inline PsycRoutingVar
psyc_var_routing (const char *name, size_t len)
{
return (PsycRoutingVar) psyc_dict_lookup((PsycDict *)psyc_rvars,
psyc_rvars_num, name, len, PSYC_NO);
return (PsycRoutingVar)
psyc_map_lookup((PsycMap*)psyc_rvars, psyc_rvars_num, name, len, PSYC_NO);
}
/**
@ -53,8 +81,9 @@ psyc_var_routing (const char *name, size_t len)
static inline PsycType
psyc_var_type (const char *name, size_t len)
{
return (PsycType) psyc_dict_lookup((PsycDict *)psyc_var_types,
psyc_var_types_num, name, len, PSYC_YES);
return (PsycType)
psyc_map_lookup((PsycMap*)psyc_var_types, psyc_var_types_num,
name, len, PSYC_YES);
}
/**

View file

@ -4,8 +4,10 @@
#ifdef DEBUG
# include <stdio.h>
# define PP(args) printf args;
# define ASSERT(cond) assert(cond)
#else
# define PP(args)
# define ASSERT(cond)
#endif
#ifdef TEST

View file

@ -107,10 +107,10 @@ 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 map.
*/
void *
psyc_dict_lookup(const PsycDict * dict, size_t size,
psyc_map_lookup(const PsycMap * map, size_t size,
const char *key, size_t keylen, PsycBool inherit)
{
//size_t cursor = 1;
@ -122,25 +122,25 @@ psyc_dict_lookup(const PsycDict * dict, size_t size,
//for (c = 0, i = 0; c < keylen && i < size; c++) {
for (i = 0; i < size; i++) {
if (!(keylen == dict[i].key.length
|| (inherit && keylen > dict[i].key.length
&& key[dict[i].key.length] == '_')))
if (!(keylen == map[i].key.length
|| (inherit && keylen > map[i].key.length
&& key[map[i].key.length] == '_')))
continue;
match = 1;
for (c = 0; c < keylen; c++) {
if (c < dict[i].key.length && dict[i].key.data[c] == key[c])
if (c < map[i].key.length && map[i].key.data[c] == key[c])
continue;
else if (c == dict[i].key.length && key[c] == '_')
return dict[i].value; // after the end of a matching prefix
else if (dict[i].key.data[c] > key[c])
else if (c == map[i].key.length && key[c] == '_')
return map[i].value; // after the end of a matching prefix
else if (map[i].key.data[c] > key[c])
return NULL;
match = 0;
break;
}
if (match)
return dict[i].value;
return map[i].value;
}
return NULL;

View file

@ -1,73 +1,99 @@
#include "lib.h"
#include <psyc/syntax.h>
#include <psyc/packet.h>
inline PsycListFlag
psyc_list_length_check (PsycList *list)
inline PsycElemFlag
psyc_elem_length_check (PsycString *value, const char end)
{
PsycListFlag flag = PSYC_LIST_NO_LENGTH;
size_t i, length = 0;
if (value->length > PSYC_ELEM_SIZE_THRESHOLD
|| memchr(value->data, (int)end, value->length))
return PSYC_ELEM_NEED_LENGTH;
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;
return PSYC_ELEM_NO_LENGTH;;
}
inline PsycListFlag
psyc_list_length (PsycList *list)
inline size_t
psyc_elem_length (PsycElem *elem)
{
size_t i, length = 0;
return
(elem->type.length ? 1 + elem->type.length : 0)
+ (elem->value.length && elem->flag != PSYC_ELEM_NO_LENGTH
? (elem->type.length ? 1 : 0) + psyc_num_length(elem->value.length) : 0)
+ (elem->value.length ? 1 + elem->value.length : 0);
}
inline size_t
psyc_dict_key_length (PsycDictKey *elem)
{
return
(elem->flag != PSYC_ELEM_NO_LENGTH
? psyc_num_length(elem->value.length) : 0)
+ (elem->value.length ? 1 + elem->value.length : 0);
}
inline size_t
psyc_list_length_set (PsycList *list)
{
size_t i;
PsycElem *elem;
list->length = list->type.length;
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++)
length += 1 + list->elems[i].length; // |elem
elem = &list->elems[i];
if (elem->flag == PSYC_ELEM_CHECK_LENGTH)
elem->flag = psyc_elem_length_check(&elem->value, '|');
elem->length = psyc_elem_length(elem);
list->length += 1 + elem->length;
}
return length;
return list->length;
}
inline size_t
psyc_dict_length_set (PsycDict *dict)
{
size_t i;
PsycDictKey *key;
PsycElem *value;
dict->length = dict->type.length;
for (i = 0; i < dict->num_elems; i++) {
key = &dict->elems[i].key;
value = &dict->elems[i].value;
if (key->flag == PSYC_ELEM_CHECK_LENGTH)
key->flag = psyc_elem_length_check(&key->value, '}');
if (value->flag == PSYC_ELEM_CHECK_LENGTH)
value->flag = psyc_elem_length_check(&value->value, '{');
key->length = psyc_dict_key_length(key);
value->length = psyc_elem_length(value);
dict->length += 1 + key->length + 1 + value->length;
}
return dict->length;
}
void
psyc_list_init (PsycList *list, PsycString *elems, size_t num_elems,
PsycListFlag flag)
psyc_list_init (PsycList *list, PsycElem *elems, size_t num_elems)
{
*list = (PsycList) {
.num_elems = num_elems,
.elems = elems,
.length = 0,
.flag = 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);
psyc_list_length_set(list);
}
void
psyc_table_init (PsycTable *table, size_t width, PsycList *list)
psyc_dict_init (PsycDict *dict, PsycDictElem *elems, size_t num_elems)
{
*table = (PsycTable) {
.width = width,
.list = list,
*dict = (PsycDict) {
.num_elems = num_elems,
.elems = elems,
};
table->length = (width > 0 ? psyc_num_length(width) + 2 : 0) + list->length;
psyc_dict_length_set(dict);
}
inline size_t
@ -77,7 +103,10 @@ psyc_modifier_length (PsycModifier *m)
if (m->name.length > 0)
length += m->name.length + 1 + m->value.length; // name\tvalue
if (m->flag == PSYC_MODIFIER_NEED_LENGTH) // add length of length if needed
// add length of length if needed
if (m->value.length
&& (m->flag & PSYC_MODIFIER_NEED_LENGTH
|| m->flag == PSYC_MODIFIER_CHECK_LENGTH))
length += psyc_num_length(m->value.length) + 1; // SP length
return length;
@ -96,7 +125,8 @@ psyc_packet_length_check (PsycPacket *p)
// If any entity modifiers need length, it is possible they contain
// 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)
if (p->entity.modifiers[i].flag & PSYC_MODIFIER_NEED_LENGTH
|| p->entity.modifiers[i].flag == PSYC_MODIFIER_CHECK_LENGTH)
return PSYC_PACKET_NEED_LENGTH;
if (memmem(p->data.data, p->data.length, PSYC_C2ARG(PSYC_PACKET_DELIMITER)))
@ -137,10 +167,11 @@ psyc_packet_length_set (PsycPacket *p)
// set total length: routing-header content |\n
p->length = p->routinglen + p->contentlen + 2;
if (p->contentlen > 0 || p->flag == PSYC_PACKET_NEED_LENGTH)
if (p->contentlen)
p->length++; // add \n at the start of the content part
if (p->flag == PSYC_PACKET_NEED_LENGTH) // add length of length if needed
// add length of length if needed
if (p->contentlen && !(p->flag & PSYC_PACKET_NO_LENGTH))
p->length += psyc_num_length(p->contentlen);
return p->length;
@ -198,9 +229,29 @@ psyc_packet_init_raw (PsycPacket *p,
psyc_packet_length_set(p);
}
size_t
psyc_packet_id_length (size_t contextlen, size_t sourcelen, size_t targetlen,
size_t counterlen, size_t fragmentlen)
void
psyc_packet_id (PsycList *list, PsycElem *elems,
char *context, size_t contextlen,
char *source, size_t sourcelen,
char *target, size_t targetlen,
char *counter, size_t counterlen,
char *fragment, size_t fragmentlen)
{
return contextlen + sourcelen + targetlen + counterlen + fragmentlen + 5;
if (contextlen)
elems[PSYC_PACKET_ID_CONTEXT] =
PSYC_ELEM_VF(context, contextlen, PSYC_ELEM_NO_LENGTH);
if (sourcelen)
elems[PSYC_PACKET_ID_SOURCE] =
PSYC_ELEM_VF(source, sourcelen, PSYC_ELEM_NO_LENGTH);
if (targetlen)
elems[PSYC_PACKET_ID_TARGET] =
PSYC_ELEM_VF(target, targetlen, PSYC_ELEM_NO_LENGTH);
if (counterlen)
elems[PSYC_PACKET_ID_COUNTER] =
PSYC_ELEM_VF(counter, counterlen, PSYC_ELEM_NO_LENGTH);
if (fragmentlen)
elems[PSYC_PACKET_ID_FRAGMENT] =
PSYC_ELEM_VF(fragment, fragmentlen, PSYC_ELEM_NO_LENGTH);
psyc_list_init(list, elems, PSYC_PACKET_ID_ELEMS);
}

View file

@ -15,33 +15,67 @@
return ret; \
}
#define ADVANCE_STARTC_OR_RETURN(ret) \
state->startc = state->cursor + 1; \
if (++(state->cursor) >= state->buffer.length) \
return ret; \
typedef enum {
PARSE_ERROR = -1,
PARSE_SUCCESS = 0,
PARSE_INSUFFICIENT = 1,
PARSE_COMPLETE = 100,
PARSE_INCOMPLETE = 101,
PARSE_INCOMPLETE = 2,
} ParseRC;
typedef struct {
PsycString buffer;
size_t cursor;
size_t startc;
} ParseState;
/**
* Parse variable name or method name.
*
* It should contain one or more keyword characters.
*
* @return PARSE_ERROR or PARSE_SUCCESS
*/
static inline ParseRC
parse_keyword (PsycParseState *state, PsycString *name)
parse_keyword (ParseState *state, PsycString *name)
{
name->data = state->buffer.data + state->cursor;
name->length = 0;
while (psyc_is_kw_char(state->buffer.data[state->cursor])) {
name->length++; // was a valid char, increase length
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
ADVANCE_CURSOR_OR_RETURN(PARSE_INSUFFICIENT);
}
return name->length > 0 ? PARSE_SUCCESS : PARSE_ERROR;
}
/**
* Parse length.
*
* @return PARSE_SUCCESS, PARSE_ERROR or PARSE_INSUFFICIENT
*/
static inline ParseRC
parse_length (ParseState *state, size_t *len)
{
ParseRC ret = PARSE_ERROR;
*len = 0;
if (psyc_is_numeric(state->buffer.data[state->cursor])) {
ret = PARSE_SUCCESS;
do {
*len = 10 * *len + state->buffer.data[state->cursor] - '0';
ADVANCE_CURSOR_OR_RETURN(PARSE_INSUFFICIENT);
} while (psyc_is_numeric(state->buffer.data[state->cursor]));
}
return ret;
}
/**
* Parse binary data.
*
@ -50,13 +84,12 @@ parse_keyword (PsycParseState *state, PsycString *name)
* @param length Expected length of the data.
* @param parsed Number of bytes parsed so far.
*
* @return PARSE_COMPLETE or PARSE_INCOMPLETE
* @return PARSE_SUCCESS or PARSE_INCOMPLETE
*/
static inline ParseRC
psyc_parse_binary_value (PsycParseState *state, PsycString *value,
size_t *length, size_t *parsed)
parse_binary (ParseState *state, size_t length, PsycString *value, size_t *parsed)
{
size_t remaining = *length - *parsed;
size_t remaining = length - *parsed;
value->data = state->buffer.data + state->cursor;
if (state->cursor + remaining > state->buffer.length) {
@ -70,9 +103,32 @@ psyc_parse_binary_value (PsycParseState *state, PsycString *value,
value->length = remaining;
state->cursor += remaining;
*parsed += remaining;
assert(*parsed == *length);
ASSERT(*parsed == length);
return PARSE_COMPLETE;
return PARSE_SUCCESS;
}
/**
* Parse data until a given character is found.
*
* @param state Parser state.
* @param value Start & length of parsed data is saved here.
* @param end Parse until this character is found.
* @param parsed Number of bytes parsed so far.
*
* @return PARSE_SUCCESS or PARSE_INSUFFICIENT
*/
static inline ParseRC
parse_until (ParseState *state, const char end, PsycString *value)
{
value->data = state->buffer.data + state->cursor;
while (state->buffer.data[state->cursor] != end) {
value->length++;
ADVANCE_CURSOR_OR_RETURN(PARSE_INSUFFICIENT);
}
return PARSE_SUCCESS;
}
/**
@ -86,7 +142,7 @@ psyc_parse_modifier (PsycParseState *state, char *oper,
*oper = *(state->buffer.data + state->cursor);
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
ParseRC ret = parse_keyword(state, name);
ParseRC ret = parse_keyword((ParseState*)state, name);
if (ret == PARSE_ERROR)
return PSYC_PARSE_ERROR_MOD_NAME;
else if (ret != PARSE_SUCCESS)
@ -123,9 +179,7 @@ psyc_parse_modifier (PsycParseState *state, char *oper,
if (++(state->cursor) >= state->buffer.length)
return length ? PARSE_INCOMPLETE : PARSE_SUCCESS; // if length=0 we're done
ret =
psyc_parse_binary_value(state, value, &(state->valuelen),
&(state->value_parsed));
ret = parse_binary((ParseState*)state, state->valuelen, value, &state->value_parsed);
if (ret == PARSE_INCOMPLETE)
return ret;
@ -244,8 +298,8 @@ psyc_parse (PsycParseState *state, char *oper,
case PSYC_PART_CONTENT:
// In case of an incomplete binary variable resume parsing it.
if (state->value_parsed < state->valuelen) {
ret = psyc_parse_binary_value(state, value, &(state->valuelen),
&(state->value_parsed));
ret = parse_binary((ParseState*)state, state->valuelen, value,
&state->value_parsed);
state->content_parsed += value->length;
if (ret == PARSE_INCOMPLETE)
@ -303,7 +357,7 @@ psyc_parse (PsycParseState *state, char *oper,
case PSYC_PART_METHOD:
pos = state->cursor;
ret = parse_keyword(state, name);
ret = parse_keyword((ParseState*)state, name);
if (ret == PARSE_INSUFFICIENT)
return ret;
@ -345,8 +399,8 @@ psyc_parse (PsycParseState *state, char *oper,
state->valuelen--; // \n at the end is not part of data
}
if (state->value_parsed < state->valuelen) {
ret = psyc_parse_binary_value(state, value, &(state->valuelen),
&(state->value_parsed));
ret = parse_binary((ParseState*)state, state->valuelen, value,
&state->value_parsed);
state->content_parsed += value->length;
if (ret == PARSE_INCOMPLETE)
@ -422,191 +476,653 @@ psyc_parse (PsycParseState *state, char *oper,
return PSYC_PARSE_ERROR; // should not be reached
}
/** List parser. */
/**
* Parse list.
*
* list = [ default-type ] *list-elem
* list-elem = "|" ( type [ SP list-value ] / [ length ] [ ":" type ] [ SP *OCTET ] )
* list-value = %x00-7B / %x7D-FF ; any byte except "|"
*/
#ifdef __INLINE_PSYC_PARSE
static inline
#endif
PsycParseListRC
psyc_parse_list (PsycParseListState *state, PsycString *elem)
psyc_parse_list (PsycParseListState *state, PsycString *type, 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;
ParseRC ret;
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_LIST_END;
if (state->term_set) {
while (state->buffer.data[state->cursor] != '|') {
elem->length++;
if (state->buffer.data[state->cursor] == state->term)
return PSYC_PARSE_LIST_END;
if (++(state->cursor) >= state->buffer.length)
return PSYC_PARSE_LIST_END;
}
} else {
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->elem_parsed < state->elemlen)) {
// Element starts with a number.
if (psyc_is_numeric(state->buffer.data[state->cursor])) {
do {
state->elemlen =
10 * state->elemlen +
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->elem_parsed = 0;
}
// Start or resume parsing the binary data
if (state->elem_parsed < state->elemlen) {
if (PARSE_INCOMPLETE == psyc_parse_binary_value((PsycParseState*)state,
elem, &state->elemlen,
&state->elem_parsed))
return PSYC_PARSE_LIST_INCOMPLETE;
state->elemlen = 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
}
PsycParseTableRC
psyc_parse_table (PsycParseTableState *state, PsycString *elem)
{
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_TABLE_INCOMPLETE;
state->startc = state->cursor;
switch (state->part) {
case PSYC_TABLE_PART_START:
if (state->buffer.data[state->cursor] != '*') {
state->part = PSYC_TABLE_PART_BODY_START;
goto PSYC_TABLE_PART_BODY_START;
} else {
state->part = PSYC_TABLE_PART_WIDTH;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_TABLE_INCOMPLETE);
case PSYC_LIST_PART_START:
type->length = elem->length = 0;
type->data = elem->data = NULL;
state->part = PSYC_LIST_PART_TYPE;
// fall thru
case PSYC_LIST_PART_TYPE:
switch (parse_keyword((ParseState*)state, type)) {
case PARSE_SUCCESS: // end of keyword
state->part = PSYC_LIST_PART_ELEM_START;
return PSYC_PARSE_LIST_TYPE;
case PARSE_INSUFFICIENT: // end of buffer
return PSYC_PARSE_LIST_END;
case PARSE_ERROR: // no keyword
state->part = PSYC_LIST_PART_ELEM_START;
break;
default: // should not be reached
return PSYC_PARSE_LIST_ERROR;
}
// fall thru
case PSYC_TABLE_PART_WIDTH:
if (psyc_is_numeric(state->buffer.data[state->cursor])) {
do {
state->width =
10 * state->width + state->buffer.data[state->cursor] - '0';
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_TABLE_INCOMPLETE);
} while (psyc_is_numeric(state->buffer.data[state->cursor]));
} else
return PSYC_PARSE_TABLE_ERROR_WIDTH;
case PSYC_LIST_PART_ELEM_START:
if (state->buffer.data[state->cursor] != '|')
return PSYC_PARSE_LIST_ERROR_ELEM_START;
type->length = elem->length = 0;
type->data = elem->data = NULL;
state->elem_parsed = 0;
state->elemlen_found = 0;
state->part = PSYC_LIST_PART_ELEM_LENGTH;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_LIST_ELEM_LAST);
// fall thru
case PSYC_LIST_PART_ELEM_TYPE:
if (state->buffer.data[state->cursor] == '=') {
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
switch (parse_keyword((ParseState*)state, type)) {
case PARSE_SUCCESS:
switch (state->buffer.data[state->cursor]) {
case ':':
state->part = PSYC_LIST_PART_ELEM_LENGTH;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_LIST_ELEM_LAST);
break;
case ' ':
state->part = PSYC_LIST_PART_ELEM;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_LIST_ELEM_LAST);
goto PSYC_LIST_PART_ELEM;
case '|':
state->part = PSYC_LIST_PART_ELEM_START;
return PSYC_PARSE_LIST_ELEM;
break;
default:
return PSYC_PARSE_LIST_ERROR_ELEM_TYPE;
}
break;
case PARSE_INSUFFICIENT: // end of buffer
return PSYC_PARSE_LIST_ELEM_LAST;
case PARSE_ERROR:
return PSYC_PARSE_LIST_ERROR_ELEM_TYPE;
default: // should not be reached
return PSYC_PARSE_LIST_ERROR;
}
}
// fall thru
case PSYC_LIST_PART_ELEM_LENGTH:
switch (parse_length((ParseState*)state, &state->elemlen)) {
case PARSE_SUCCESS: // length is complete
state->elemlen_found = 1;
state->elem_parsed = 0;
elem->length = state->elemlen;
elem->data = NULL;
break;
case PARSE_INSUFFICIENT: // length is incomplete
return PSYC_PARSE_LIST_INSUFFICIENT;
case PARSE_ERROR: // no length
break;
default: // should not be reached
return PSYC_PARSE_LIST_ERROR;
}
switch (state->buffer.data[state->cursor]) {
#ifdef PSYC_PARSE_TABLE_HEAD
case '|':
state->part = PSYC_TABLE_PART_HEAD_START;
break;
#endif
case ' ':
state->part = PSYC_TABLE_PART_BODY_START;
state->cursor++;
state->part = PSYC_LIST_PART_ELEM;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_LIST_ELEM_LAST);
break;
case '|':
state->part = PSYC_LIST_PART_ELEM_START;
return PSYC_PARSE_LIST_ELEM;
default:
return PSYC_PARSE_LIST_ERROR_ELEM_LENGTH;
}
elem->length = state->width;
return PSYC_TABLE_PART_WIDTH;
#ifdef PSYC_PARSE_TABLE_HEAD
case PSYC_TABLE_PART_HEAD_START:
psyc_parse_list_buffer_set(&state->list, state->buffer.data + state->cursor,
state->buffer.length - state->cursor);
psyc_parse_list_term_set(&state->list, ' ');
state->part = PSYC_TABLE_PART_HEAD;
// fall thru
case PSYC_TABLE_PART_HEAD:
switch (psyc_parse_list(&state->list, elem)) {
case PSYC_PARSE_LIST_ELEM:
if (state->elems == 0) {
state->elems++;
return PSYC_PARSE_TABLE_NAME_KEY;
} else if (state->elems < state->width) {
state->elems++;
return PSYC_PARSE_TABLE_NAME_VALUE;
} else // too many elements
return PSYC_PARSE_TABLE_ERROR_HEAD;
case PSYC_PARSE_LIST_END:
if (state->elems != state->width)
return PSYC_PARSE_TABLE_ERROR_HEAD;
state->part = PSYC_TABLE_PART_BODY_START;
state->cursor += state->list.cursor + 1;
psyc_parse_list_state_init(&state->list);
return state->elems++ == 0
? PSYC_PARSE_TABLE_NAME_KEY : PSYC_PARSE_TABLE_NAME_VALUE;
default:
return PSYC_PARSE_TABLE_ERROR_HEAD;
case PSYC_LIST_PART_ELEM:
PSYC_LIST_PART_ELEM:
if (state->elemlen_found) {
switch (parse_binary((ParseState*)state, state->elemlen, elem,
&state->elem_parsed)) {
case PARSE_SUCCESS:
if (elem->length == state->elem_parsed)
ret = PSYC_PARSE_LIST_ELEM;
else
ret = PSYC_PARSE_LIST_ELEM_END;
break;
case PARSE_INCOMPLETE:
if (elem->length == state->elem_parsed)
ret = PSYC_PARSE_LIST_ELEM_START;
else
ret = PSYC_PARSE_LIST_ELEM_CONT;
break;
default: // should not be reached
return PSYC_PARSE_LIST_ERROR;
}
#endif
case PSYC_TABLE_PART_BODY_START:
PSYC_TABLE_PART_BODY_START:
psyc_parse_list_buffer_set(&state->list, state->buffer.data + state->cursor,
state->buffer.length - state->cursor);
state->part = PSYC_TABLE_PART_BODY;
// fall thru
case PSYC_TABLE_PART_BODY:
switch (psyc_parse_list(&state->list, elem)) {
case PSYC_PARSE_LIST_ELEM:
return state->elems++ % (state->width + 1) == 0
? PSYC_PARSE_TABLE_KEY : PSYC_PARSE_TABLE_VALUE;
case PSYC_PARSE_LIST_END:
return state->elems++ % (state->width + 1) == 0
? PSYC_PARSE_TABLE_KEY_END : PSYC_PARSE_TABLE_VALUE_END;
default:
return PSYC_PARSE_TABLE_ERROR_BODY;
} else {
switch (parse_until((ParseState*)state, '|', elem)) {
case PARSE_SUCCESS:
ret = PSYC_PARSE_LIST_ELEM;
break;
case PARSE_INSUFFICIENT:
return PSYC_PARSE_LIST_ELEM_LAST;
default: // should not be reached
return PSYC_PARSE_LIST_ERROR;
}
}
state->part = PSYC_LIST_PART_ELEM_START;
state->startc = state->cursor;
return ret;
}
return PSYC_PARSE_LIST_ERROR; // should not be reached
}
/**
* Parse dictionary.
*
* dict = [ type ] *dict-item
* dict-item = "{" ( dict-key / length SP OCTET) "}"
* ( type [ SP dict-value ] / [ length ] [ ":" type ] [ SP *OCTET ] )
* dict-key = %x00-7C / %x7E-FF ; any byte except "{"
* dict-value = %x00-7A / %x7C-FF ; any byte except "}"
*/
PsycParseDictRC
psyc_parse_dict (PsycParseDictState *state, PsycString *type, PsycString *elem)
{
ParseRC ret;
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_DICT_END;
state->startc = state->cursor;
switch (state->part) {
case PSYC_DICT_PART_START:
type->length = elem->length = 0;
type->data = elem->data = NULL;
state->part = PSYC_DICT_PART_TYPE;
// fall thru
case PSYC_DICT_PART_TYPE:
switch (parse_keyword((ParseState*)state, type)) {
case PARSE_SUCCESS: // end of keyword
state->part = PSYC_DICT_PART_KEY_START;
return PSYC_PARSE_DICT_TYPE;
case PARSE_INSUFFICIENT: // end of buffer
return PSYC_PARSE_DICT_END;
case PARSE_ERROR: // no keyword
state->part = PSYC_DICT_PART_KEY_START;
break;
default: // should not be reached
return PSYC_PARSE_DICT_ERROR;
}
// fall thru
case PSYC_DICT_PART_KEY_START:
if (state->buffer.data[state->cursor] != '{')
return PSYC_PARSE_DICT_ERROR_KEY_START;
type->length = elem->length = 0;
type->data = elem->data = NULL;
state->elem_parsed = 0;
state->elemlen_found = 0;
state->part = PSYC_DICT_PART_KEY_LENGTH;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_DICT_INSUFFICIENT);
// fall thru
case PSYC_DICT_PART_KEY_LENGTH:
switch (parse_length((ParseState*)state, &state->elemlen)) {
case PARSE_SUCCESS: // length is complete
state->elemlen_found = 1;
state->elem_parsed = 0;
elem->length = state->elemlen;
elem->data = NULL;
if (state->buffer.data[state->cursor] != ' ')
return PSYC_PARSE_DICT_ERROR_KEY_LENGTH;
state->part = PSYC_DICT_PART_KEY;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
break;
case PARSE_INSUFFICIENT: // length is incomplete
return PSYC_PARSE_DICT_INSUFFICIENT;
case PARSE_ERROR: // no length
state->part = PSYC_DICT_PART_KEY;
break;
default: // should not be reached
return PSYC_PARSE_DICT_ERROR;
}
// fall thru
case PSYC_DICT_PART_KEY:
if (state->elemlen_found) {
switch (parse_binary((ParseState*)state, state->elemlen, elem,
&state->elem_parsed)) {
case PARSE_SUCCESS:
if (elem->length == state->elem_parsed)
ret = PSYC_PARSE_DICT_KEY;
else
ret = PSYC_PARSE_DICT_KEY_END;
break;
case PARSE_INCOMPLETE:
if (elem->length == state->elem_parsed)
ret = PSYC_PARSE_DICT_KEY_START;
else
ret = PSYC_PARSE_DICT_KEY_CONT;
break;
default: // should not be reached
return PSYC_PARSE_DICT_ERROR;
}
} else {
switch (parse_until((ParseState*)state, '}', elem)) {
case PARSE_SUCCESS:
ret = PSYC_PARSE_DICT_KEY;
break;
case PARSE_INSUFFICIENT:
return PSYC_PARSE_DICT_INSUFFICIENT;
default: // should not be reached
return PSYC_PARSE_DICT_ERROR;
}
}
state->part = PSYC_DICT_PART_VALUE_START;
state->startc = state->cursor;
return ret;
case PSYC_DICT_PART_VALUE_START:
switch (state->buffer.data[state->cursor] != '}')
return PSYC_PARSE_DICT_ERROR_VALUE_START;
type->length = elem->length = 0;
type->data = elem->data = NULL;
state->elem_parsed = 0;
state->elemlen_found = 0;
state->part = PSYC_DICT_PART_VALUE_TYPE;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_DICT_VALUE_LAST);
// fall thru
case PSYC_DICT_PART_VALUE_TYPE:
if (state->buffer.data[state->cursor] == '=') {
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
switch (parse_keyword((ParseState*)state, type)) {
case PARSE_SUCCESS:
switch (state->buffer.data[state->cursor]) {
case ':':
state->part = PSYC_DICT_PART_VALUE_LENGTH;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_DICT_VALUE_LAST);
break;
case ' ':
state->part = PSYC_DICT_PART_VALUE;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_DICT_VALUE_LAST);
goto PSYC_DICT_PART_VALUE;
case '{':
state->part = PSYC_DICT_PART_KEY_START;
return PSYC_PARSE_DICT_VALUE;
break;
default:
return PSYC_PARSE_DICT_ERROR_VALUE_TYPE;
}
break;
case PARSE_INSUFFICIENT: // end of buffer
return PSYC_PARSE_DICT_VALUE_LAST;
case PARSE_ERROR:
return PSYC_PARSE_DICT_ERROR_VALUE_TYPE;
default: // should not be reached
return PSYC_PARSE_DICT_ERROR;
}
}
// fall thru
case PSYC_DICT_PART_VALUE_LENGTH:
switch (parse_length((ParseState*)state, &state->elemlen)) {
case PARSE_SUCCESS: // length is complete
state->elemlen_found = 1;
state->elem_parsed = 0;
elem->length = state->elemlen;
elem->data = NULL;
break;
case PARSE_INSUFFICIENT: // length is incomplete
return PSYC_PARSE_DICT_INSUFFICIENT;
case PARSE_ERROR: // no length
break;
default: // should not be reached
return PSYC_PARSE_DICT_ERROR;
}
switch (state->buffer.data[state->cursor]) {
case ' ':
state->part = PSYC_DICT_PART_VALUE;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_DICT_VALUE_LAST);
break;
case '{':
state->part = PSYC_DICT_PART_KEY_START;
return PSYC_PARSE_DICT_VALUE;
default:
return PSYC_PARSE_DICT_ERROR_VALUE_LENGTH;
}
// fall thru
case PSYC_DICT_PART_VALUE:
PSYC_DICT_PART_VALUE:
if (state->elemlen_found) {
switch (parse_binary((ParseState*)state, state->elemlen, elem,
&state->elem_parsed)) {
case PARSE_SUCCESS:
if (elem->length == state->elem_parsed)
ret = PSYC_PARSE_DICT_VALUE;
else
ret = PSYC_PARSE_DICT_VALUE_END;
break;
case PARSE_INCOMPLETE:
if (elem->length == state->elem_parsed)
ret = PSYC_PARSE_DICT_VALUE_START;
else
ret = PSYC_PARSE_DICT_VALUE_CONT;
break;
default: // should not be reached
return PSYC_PARSE_DICT_ERROR;
}
} else {
switch (parse_until((ParseState*)state, '{', elem)) {
case PARSE_SUCCESS:
ret = PSYC_PARSE_DICT_VALUE;
break;
case PARSE_INSUFFICIENT:
return PSYC_PARSE_DICT_VALUE_LAST;
default: // should not be reached
return PSYC_PARSE_DICT_ERROR;
}
}
state->part = PSYC_DICT_PART_KEY_START;
return ret;
}
return PSYC_PARSE_DICT_ERROR; // should not be reached
}
#ifdef __INLINE_PSYC_PARSE
static inline
#endif
PsycParseIndexRC
psyc_parse_index (PsycParseIndexState *state, PsycString *idx)
{
ParseRC ret;
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_INDEX_END;
state->startc = state->cursor;
switch (state->part) {
case PSYC_INDEX_PART_START:
case PSYC_INDEX_PART_TYPE:
idx->length = 0;
idx->data = NULL;
switch (state->buffer.data[state->cursor]) {
case '#':
state->part = PSYC_INDEX_PART_LIST;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
goto PSYC_INDEX_PART_LIST;
case '.':
state->part = PSYC_INDEX_PART_DICT;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
goto PSYC_INDEX_PART_STRUCT;
case '{':
state->part = PSYC_INDEX_PART_DICT;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
goto PSYC_INDEX_PART_DICT_LENGTH;
default:
return PSYC_PARSE_INDEX_ERROR_TYPE;
}
case PSYC_INDEX_PART_LIST:
PSYC_INDEX_PART_LIST:
switch (parse_length((ParseState*)state, &idx->length)) {
case PARSE_SUCCESS: // list index is complete
state->part = PSYC_INDEX_PART_TYPE;
return PSYC_PARSE_INDEX_LIST;
case PARSE_INSUFFICIENT: // list index at the end of buffer
return PSYC_PARSE_INDEX_LIST_LAST;
case PARSE_ERROR: // no index
return PSYC_PARSE_INDEX_ERROR_LIST;
default: // should not be reached
return PSYC_PARSE_INDEX_ERROR;
}
case PSYC_INDEX_PART_STRUCT:
PSYC_INDEX_PART_STRUCT:
switch (parse_keyword((ParseState*)state, idx)) {
case PARSE_SUCCESS: // end of keyword
state->part = PSYC_INDEX_PART_TYPE;
return PSYC_PARSE_INDEX_STRUCT;
case PARSE_INSUFFICIENT: // end of buffer
return PSYC_PARSE_INDEX_STRUCT_LAST;
case PARSE_ERROR: // no keyword
return PSYC_PARSE_INDEX_ERROR_STRUCT;
default: // should not be reached
return PSYC_PARSE_INDEX_ERROR;
}
case PSYC_INDEX_PART_DICT_LENGTH:
PSYC_INDEX_PART_DICT_LENGTH:
switch (parse_length((ParseState*)state, &state->elemlen)) {
case PARSE_SUCCESS: // length is complete
state->elemlen_found = 1;
state->elem_parsed = 0;
idx->length = state->elemlen;
idx->data = NULL;
if (state->buffer.data[state->cursor] != ' ')
return PSYC_PARSE_INDEX_ERROR_DICT_LENGTH;
state->part = PSYC_INDEX_PART_DICT;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
break;
case PARSE_INSUFFICIENT: // length is incomplete
return PSYC_PARSE_DICT_INSUFFICIENT;
case PARSE_ERROR: // no length
state->part = PSYC_INDEX_PART_DICT;
break;
default: // should not be reached
return PSYC_PARSE_INDEX_ERROR;
}
// fall thru
case PSYC_INDEX_PART_DICT:
if (state->elemlen_found) {
switch (parse_binary((ParseState*)state, state->elemlen, idx,
&state->elem_parsed)) {
case PARSE_SUCCESS:
if (idx->length == state->elem_parsed)
ret = PSYC_PARSE_INDEX_DICT;
else
ret = PSYC_PARSE_INDEX_DICT_END;
break;
case PARSE_INCOMPLETE:
if (idx->length == state->elem_parsed)
ret = PSYC_PARSE_INDEX_DICT_START;
else
ret = PSYC_PARSE_INDEX_DICT_CONT;
break;
default: // should not be reached
return PSYC_PARSE_INDEX_ERROR_DICT;
}
} else {
switch (parse_until((ParseState*)state, '}', idx)) {
case PARSE_SUCCESS:
ret = PSYC_PARSE_INDEX_DICT;
break;
case PARSE_INSUFFICIENT:
return PSYC_PARSE_INDEX_INSUFFICIENT;
default: // should not be reached
return PSYC_PARSE_INDEX_ERROR_DICT;
}
}
state->part = PSYC_INDEX_PART_TYPE;
state->cursor++;
return ret;
}
return PSYC_PARSE_INDEX_ERROR; // should not be reached
}
#ifdef __INLINE_PSYC_PARSE
static inline
#endif
PsycParseUpdateRC
psyc_parse_update (PsycParseUpdateState *state, char *oper, PsycString *value)
{
PsycParseIndexRC ret;
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_UPDATE_END;
state->startc = state->cursor;
switch (state->part) {
case PSYC_UPDATE_PART_START:
value->length = 0;
value->data = NULL;
// fall thru
case PSYC_INDEX_PART_TYPE:
case PSYC_INDEX_PART_LIST:
case PSYC_INDEX_PART_STRUCT:
case PSYC_INDEX_PART_DICT_LENGTH:
case PSYC_INDEX_PART_DICT:
ret = psyc_parse_index((PsycParseIndexState*)state, value);
switch (ret) {
case PSYC_PARSE_INDEX_INSUFFICIENT:
case PSYC_PARSE_INDEX_LIST_LAST:
case PSYC_PARSE_INDEX_STRUCT_LAST:
case PSYC_PARSE_INDEX_END:
return PSYC_PARSE_UPDATE_INSUFFICIENT;
case PSYC_PARSE_INDEX_ERROR_TYPE:
if (state->buffer.data[state->cursor] != ' ')
return ret;
state->part = PSYC_PARSE_UPDATE_TYPE;
value->length = 0;
value->data = NULL;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_UPDATE_INSUFFICIENT);
break;
default:
return ret;
}
case PSYC_UPDATE_PART_TYPE:
if (!psyc_is_oper(state->buffer.data[state->cursor]))
return PSYC_PARSE_UPDATE_ERROR_OPER;
*oper = state->buffer.data[state->cursor];
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_UPDATE_END);
switch (parse_keyword((ParseState*)state, value)) {
case PARSE_SUCCESS: // end of keyword
case PARSE_ERROR: // no keyword
switch (state->buffer.data[state->cursor]) {
case ':':
state->part = PSYC_UPDATE_PART_LENGTH;
break;
case ' ':
state->part = PSYC_UPDATE_PART_VALUE;
break;
default:
return PSYC_PARSE_UPDATE_ERROR_TYPE;
}
state->cursor++;
return PSYC_PARSE_UPDATE_TYPE;
break;
case PARSE_INSUFFICIENT: // end of buffer
return PSYC_PARSE_UPDATE_TYPE_END;
default: // should not be reached
return PSYC_PARSE_UPDATE_ERROR;
}
break;
case PSYC_UPDATE_PART_LENGTH:
switch (parse_length((ParseState*)state, &state->elemlen)) {
case PARSE_SUCCESS: // length is complete
state->elemlen_found = 1;
state->elem_parsed = 0;
value->length = state->elemlen;
value->data = NULL;
if (state->buffer.data[state->cursor] != ' ')
return PSYC_PARSE_UPDATE_ERROR_LENGTH;
state->part = PSYC_UPDATE_PART_VALUE;
if (value->length == 0)
return PSYC_PARSE_UPDATE_END;
ADVANCE_STARTC_OR_RETURN(PSYC_PARSE_UPDATE_INSUFFICIENT);
break;
case PARSE_INSUFFICIENT: // length is incomplete
if (value->length == 0)
return PSYC_PARSE_UPDATE_END;
return PSYC_PARSE_UPDATE_INSUFFICIENT;
case PARSE_ERROR: // no length after :
return PSYC_PARSE_UPDATE_ERROR_LENGTH;
default: // should not be reached
return PSYC_PARSE_UPDATE_ERROR;
}
// fall thru
case PSYC_UPDATE_PART_VALUE:
if (state->elemlen_found) {
switch (parse_binary((ParseState*)state, state->elemlen, value,
&state->elem_parsed)) {
case PARSE_SUCCESS:
if (value->length == state->elem_parsed)
ret = PSYC_PARSE_UPDATE_VALUE;
else
ret = PSYC_PARSE_UPDATE_VALUE_END;
break;
case PARSE_INCOMPLETE:
if (value->length == state->elem_parsed)
ret = PSYC_PARSE_UPDATE_VALUE_START;
else
ret = PSYC_PARSE_UPDATE_VALUE_CONT;
break;
default: // should not be reached
return PSYC_PARSE_UPDATE_ERROR_VALUE;
}
} else {
value->data = state->buffer.data + state->cursor;
value->length = state->buffer.length - state->cursor;
ret = PSYC_PARSE_UPDATE_VALUE;
}
state->part = PSYC_INDEX_PART_TYPE;
state->cursor++;
return ret;
}
return PSYC_PARSE_INDEX_ERROR; // should not be reached
}

View file

@ -3,7 +3,59 @@
#include "lib.h"
#include <psyc/packet.h>
#include <psyc/render.h>
#include <psyc/syntax.h>
inline PsycRenderRC
psyc_render_elem (PsycElem *elem, char *buffer, size_t buflen)
{
size_t cur = 0;
if (elem->length > buflen) // return error if element doesn't fit in buffer
return PSYC_RENDER_ERROR;
if (elem->type.length) {
buffer[cur++] = '=';
memcpy(buffer + cur, PSYC_S2ARG(elem->type));
cur += elem->type.length;
}
if (elem->value.length && !(elem->flag & PSYC_ELEM_NO_LENGTH)) {
if (elem->type.length)
buffer[cur++] = ':';
cur += itoa(elem->value.length, buffer + cur, 10);
}
if (elem->value.length) {
buffer[cur++] = ' ';
memcpy(buffer + cur, PSYC_S2ARG(elem->value));
cur += elem->value.length;
}
// Actual length should be equal to pre-calculated length at this point.
ASSERT(cur == elem->length);
return PSYC_RENDER_SUCCESS;
}
inline PsycRenderRC
psyc_render_dict_key (PsycDictKey *elem, char *buffer, size_t buflen)
{
size_t cur = 0;
if (elem->length > buflen) // return error if element doesn't fit in buffer
return PSYC_RENDER_ERROR;
if (elem->value.length && !(elem->flag & PSYC_ELEM_NO_LENGTH))
cur += itoa(elem->value.length, buffer + cur, 10);
if (elem->value.length) {
buffer[cur++] = ' ';
memcpy(buffer + cur, PSYC_S2ARG(elem->value));
cur += elem->value.length;
}
// Actual length should be equal to pre-calculated length at this point.
ASSERT(cur == elem->length);
return PSYC_RENDER_SUCCESS;
}
#ifdef __INLINE_PSYC_RENDER
static inline
@ -12,51 +64,55 @@ PsycRenderRC
psyc_render_list (PsycList *list, char *buffer, size_t buflen)
{
size_t i, cur = 0;
PsycString *elem;
if (list->length > buflen) // return error if list doesn't fit in buffer
return PSYC_RENDER_ERROR;
if (list->flag == PSYC_LIST_NEED_LENGTH) {
for (i = 0; i < list->num_elems; i++) {
elem = &list->elems[i];
if (i > 0)
buffer[cur++] = '|';
cur += itoa(elem->length, buffer + cur, 10);
buffer[cur++] = ' ';
memcpy(buffer + cur, elem->data, elem->length);
cur += elem->length;
}
} else {
for (i = 0; i < list->num_elems; i++) {
elem = &list->elems[i];
buffer[cur++] = '|';
memcpy(buffer + cur, elem->data, elem->length);
cur += elem->length;
}
if (list->type.length) {
memcpy(buffer + cur, PSYC_S2ARG(list->type));
cur += list->type.length;
}
for (i = 0; i < list->num_elems; i++) {
buffer[cur++] = '|';
psyc_render_elem(&list->elems[i], buffer + cur, buflen - cur);
cur += list->elems[i].length;
}
#ifdef DEBUG
// Actual length should be equal to pre-calculated length at this point.
assert(cur == list->length);
#endif
ASSERT(cur == list->length);
return PSYC_RENDER_SUCCESS;
}
#ifdef __INLINE_PSYC_RENDER
static inline
#endif
PsycRenderRC
psyc_render_table (PsycTable *table, char *buffer, size_t buflen)
psyc_render_dict (PsycDict *dict, char *buffer, size_t buflen)
{
size_t cur = 0;
size_t i, cur = 0;
if (table->length > buflen) // return error if table doesn't fit in buffer
if (dict->length > buflen) // return error if dict doesn't fit in buffer
return PSYC_RENDER_ERROR;
if (table->width > 0) {
cur = sprintf(buffer, "*%ld", table->width);
buffer[cur++] = ' ';
if (dict->type.length) {
memcpy(buffer + cur, PSYC_S2ARG(dict->type));
cur += dict->type.length;
}
return psyc_render_list(table->list, buffer + cur, buflen - cur);
for (i = 0; i < dict->num_elems; i++) {
buffer[cur++] = '{';
psyc_render_dict_key(&dict->elems[i].key, buffer + cur, buflen - cur);
cur += dict->elems[i].key.length;
buffer[cur++] = '}';
psyc_render_elem(&dict->elems[i].value, buffer + cur, buflen - cur);
cur += dict->elems[i].value.length;
}
// Actual length should be equal to pre-calculated length at this point.
ASSERT(cur == dict->length);
return PSYC_RENDER_SUCCESS;
}
static inline size_t
@ -70,7 +126,9 @@ psyc_render_modifier (PsycModifier *mod, char *buffer)
if (cur == 1)
return cur; // error, name can't be empty
if (mod->flag == PSYC_MODIFIER_NEED_LENGTH) {
if (mod->value.length
&& (mod->flag & PSYC_MODIFIER_NEED_LENGTH
|| mod->flag == PSYC_MODIFIER_CHECK_LENGTH)) {
buffer[cur++] = ' ';
cur += itoa(mod->value.length, buffer + cur, 10);
}
@ -87,54 +145,52 @@ psyc_render_modifier (PsycModifier *mod, char *buffer)
static inline
#endif
PsycRenderRC
psyc_render (PsycPacket *packet, char *buffer, size_t buflen)
psyc_render (PsycPacket *p, char *buffer, size_t buflen)
{
size_t i, cur = 0, len;
if (packet->length > buflen) // return error if packet doesn't fit in buffer
if (p->length > buflen) // return error if packet doesn't fit in buffer
return PSYC_RENDER_ERROR;
// render routing modifiers
for (i = 0; i < packet->routing.lines; i++) {
len = psyc_render_modifier(&packet->routing.modifiers[i], buffer + cur);
for (i = 0; i < p->routing.lines; i++) {
len = psyc_render_modifier(&p->routing.modifiers[i], buffer + cur);
cur += len;
if (len <= 1)
return PSYC_RENDER_ERROR_MODIFIER_NAME_MISSING;
}
// add length if needed
if (packet->flag == PSYC_PACKET_NEED_LENGTH)
cur += itoa(packet->contentlen, buffer + cur, 10);
if (p->contentlen && !(p->flag & PSYC_PACKET_NO_LENGTH))
cur += itoa(p->contentlen, buffer + cur, 10);
if (packet->flag == PSYC_PACKET_NEED_LENGTH || packet->content.length
|| packet->stateop || packet->entity.lines
|| packet->method.length || packet->data.length)
if (p->contentlen)
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;
if (p->content.length) { // render raw content if present
memcpy(buffer + cur, p->content.data, p->content.length);
cur += p->content.length;
} else {
if (packet->stateop) {
buffer[cur++] = packet->stateop;
if (p->stateop) {
buffer[cur++] = p->stateop;
buffer[cur++] = '\n';
}
// render entity modifiers
for (i = 0; i < packet->entity.lines; i++)
cur += psyc_render_modifier(&packet->entity.modifiers[i],
for (i = 0; i < p->entity.lines; i++)
cur += psyc_render_modifier(&p->entity.modifiers[i],
buffer + cur);
if (packet->method.length) { // add method\n
memcpy(buffer + cur, packet->method.data, packet->method.length);
cur += packet->method.length;
if (p->method.length) { // add method\n
memcpy(buffer + cur, p->method.data, p->method.length);
cur += p->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;
if (p->data.length) { // add data\n
memcpy(buffer + cur, p->data.data, p->data.length);
cur += p->data.length;
buffer[cur++] = '\n';
}
} else if (packet->data.length) // error, we have data but no modifier
} else if (p->data.length) // error, we have data but no modifier
return PSYC_RENDER_ERROR_METHOD_MISSING;
}
@ -143,32 +199,6 @@ psyc_render (PsycPacket *packet, char *buffer, size_t buflen)
buffer[cur++] = '\n';
// actual length should be equal to pre-calculated length at this point
assert(cur == packet->length);
ASSERT(cur == p->length);
return PSYC_RENDER_SUCCESS;
}
PsycRenderRC
psyc_render_packet_id (char *context, size_t contextlen,
char *source, size_t sourcelen,
char *target, size_t targetlen,
char *counter, size_t counterlen,
char *fragment, size_t fragmentlen,
char *buffer, size_t buflen)
{
PsycList list;
PsycString elems[PSYC_PACKET_ID_ELEMS] = {};
if (contextlen)
elems[PSYC_PACKET_ID_CONTEXT] = PSYC_STRING(context, contextlen);
if (sourcelen)
elems[PSYC_PACKET_ID_SOURCE] = PSYC_STRING(source, sourcelen);
if (targetlen)
elems[PSYC_PACKET_ID_TARGET] = PSYC_STRING(target, targetlen);
if (counterlen)
elems[PSYC_PACKET_ID_COUNTER] = PSYC_STRING(counter, counterlen);
if (fragmentlen)
elems[PSYC_PACKET_ID_FRAGMENT] = PSYC_STRING(fragment, fragmentlen);
psyc_list_init(&list, elems, PSYC_PACKET_ID_ELEMS, PSYC_LIST_NO_LENGTH);
return psyc_render_list(&list, buffer, buflen);
}

View file

@ -4,7 +4,7 @@
#include <psyc/packet.h>
/// Routing variables in alphabetical order.
const PsycDictInt psyc_rvars[] = {
const PsycMapInt psyc_rvars[] = {
{ PSYC_C2STRI("_amount_fragments"), PSYC_RVAR_AMOUNT_FRAGMENTS },
{ PSYC_C2STRI("_context"), PSYC_RVAR_CONTEXT },
{ PSYC_C2STRI("_counter"), PSYC_RVAR_COUNTER },
@ -30,26 +30,26 @@ const PsycDictInt psyc_rvars[] = {
const size_t psyc_rvars_num = PSYC_NUM_ELEM(psyc_rvars);
// Variable types in alphabetical order.
const PsycDictInt psyc_var_types[] = {
const PsycMapInt psyc_var_types[] = {
{ PSYC_C2STRI("_amount"), PSYC_TYPE_AMOUNT },
{ PSYC_C2STRI("_color"), PSYC_TYPE_COLOR },
{ PSYC_C2STRI("_date"), PSYC_TYPE_DATE },
{ PSYC_C2STRI("_def"), PSYC_TYPE_DEF },
{ PSYC_C2STRI("_degree"), PSYC_TYPE_DEGREE },
{ PSYC_C2STRI("_dict"), PSYC_TYPE_DICT },
{ PSYC_C2STRI("_entity"), PSYC_TYPE_ENTITY },
{ PSYC_C2STRI("_flag"), PSYC_TYPE_FLAG },
{ PSYC_C2STRI("_language"), PSYC_TYPE_LANGUAGE },
{ PSYC_C2STRI("_list"), PSYC_TYPE_LIST },
{ PSYC_C2STRI("_nick"), PSYC_TYPE_NICK },
{ PSYC_C2STRI("_page"), PSYC_TYPE_PAGE },
{ PSYC_C2STRI("_table"), PSYC_TYPE_TABLE },
{ PSYC_C2STRI("_struct"), PSYC_TYPE_STRUCT },
{ PSYC_C2STRI("_time"), PSYC_TYPE_TIME },
{ PSYC_C2STRI("_uniform"), PSYC_TYPE_UNIFORM },
};
const size_t psyc_var_types_num = PSYC_NUM_ELEM(psyc_var_types);
/// Method names in alphabetical order.
const PsycDictInt psyc_methods[] = {
const PsycMapInt psyc_methods[] = {
{ PSYC_C2STRI("_data"), PSYC_MC_DATA },
{ PSYC_C2STRI("_echo_context_enter"), PSYC_MC_ECHO_CONTEXT_ENTER },
{ PSYC_C2STRI("_echo_context_leave"), PSYC_MC_ECHO_CONTEXT_LEAVE },
@ -88,7 +88,7 @@ const size_t psyc_methods_num = PSYC_NUM_ELEM(psyc_methods);
PsycMethod
psyc_method (char *method, size_t methodlen, PsycMethod *family, unsigned int *flag)
{
int mc = psyc_dict_lookup_int(psyc_methods, psyc_methods_num,
int mc = psyc_map_lookup_int(psyc_methods, psyc_methods_num,
method, methodlen, PSYC_YES);
switch (mc) {

View file

@ -3,7 +3,7 @@ DEBUG = 2
CFLAGS = -I../include -I../src -Wall -std=c99 ${OPT}
LDFLAGS = -L../lib
LOADLIBES = -lpsyc -lm
TARGETS = test_psyc test_psyc_speed test_parser test_match test_render test_text var_routing var_type uniform_parse test_list test_table test_packet_id method
TARGETS = test_psyc test_psyc_speed test_parser test_match test_render test_text var_routing var_type uniform_parse test_packet_id test_index test_update method
O = test.o
WRAPPER =
DIET = diet
@ -47,10 +47,13 @@ test: ${TARGETS}
./test_text
./var_routing
./var_type
./method
./uniform_parse
./test_list
./test_table
# ./test_list
# ./test_table
./test_packet_id
./test_index
./test_update
x=0; for f in packets/[0-9]*; do echo ">> $$f"; ./test_psyc -f $$f | ${DIFF} -u $$f -; x=$$((x+$$?)); done; exit $$x
x=0; for f in packets/[0-9]*; do echo ">> $$f"; ./test_psyc -rf $$f | ${DIFF} -u $$f -; x=$$((x+$$?)); done; exit $$x

View file

@ -1,4 +0,0 @@
:_source psyc://foo.example.com/
:_target psyc://bar.example.com/
0
|

View file

@ -1,7 +0,0 @@
:_source psyc://foo.example.com/
:_target psyc://bar.example.com/
:_foo 0
_message_private
OHAI
|

View file

@ -1,18 +1,17 @@
=_source psyc://foo/~bar
:_target psyc://bar/~baz
=_list_foo |foo|bar|baz
:_tag sch1828hu3r2cm
=_context psyc://foo/~bar
=_foo bar baz
=_abc_def 11 ghi jkl
xq
=_list_bar 36 3 foo|3 bar|7 foo
bar|11 foo
bar
baz
:_foo_bar yay
_message_foo_bar
ohai there!
\o/
=_list_xxx |=_foo|=_bar|=_baz|4 abc
=_list_foo |=_foo|=_bar ||=_baz|
=_list_foo _test|3 foo|=_color:4 blue|=_nick bar
=_list_bar 43 |3 foo|=_color:4 blue|=_nick bar|8
foo|bar
=_list_bar 43 |3 foo|=_color:4 blue|=_nick bar|9
foo|bar
=_list_a _type| elem1| elem2| elem3
=_list_b |=_type1 elem1|=_type2 elem2|=_type3 elem3
=_list_members _uniform| psyc://example.net/~alice| psyc://example.org/~bob
=_list_topic |9 democracy|3 now
=_list_c | foo| bar|6 foobar|3 baz|=_int 234|=_time 1234
=_list_foo |=_int 234|=_time 1234|=_picture:3 \o/|7 \oXoXo/
_test_list
|

7
test/packets/02-list2 Normal file
View file

@ -0,0 +1,7 @@
:_source psyc://foo/~bar
:_target psyc://bar/~baz
=_list_foo _test|3 foo|=_color:4 blue|=_nick bar
=_list_bar |3 foo|=_color:4 blue|=_nick bar
_test
|

11
test/packets/03-dict Normal file
View file

@ -0,0 +1,11 @@
=_context psyc://foo/~bar
=_dict _type{4 key1}6 value1{key2} value2{key3}6 value3{key4} value4
=_dict_example {4 key1}=_type1:6 value1{key2}=_type2 value2{key3}6 value3{key4} value4
=_struct_member |=_nick|=_picture
=_dict_owners {psyc://example.net/~alice}{psyc://example.org/~bob}
=_dict_members {psyc://example.net/~alice}=_struct_member | alice| \o/{psyc://example.org/~bob}=_struct_member | bob| \oXo/
=_dict_members {25 psyc://example.net/~alice}=_struct_member:12 | alice| \o/{psyc://example.org/~bob}=_struct_member | bob| \oXo/
=_dict_members _struct_member{25 psyc://example.net/~alice}12 | alice| \o/{psyc://example.org/~bob} | bob| \oXo/
_test_dict
|

View file

@ -1,20 +0,0 @@
=_source psyc://foo/~bar
:_target psyc://bar/~baz
=_list_foo |foo|bar|baz
:_tag sch1828hu3r2cm
?_test ignored
=_foo bar baz
=_abc_def 11 ghi jkl
xq
=_list_bar 36 3 foo|3 bar|7 foo
bar|11 foo
b|r
baz
:_foo_bar yay
=_amount_x 10
_message_foo_bar
ohai there!
\o/
|

View file

@ -1,4 +1,4 @@
:_list_understand_modules |_state|_fragments|_context
:_list_understand_modules | _state| _fragments| _context
_request_features
|

87
test/test_index.c Normal file
View file

@ -0,0 +1,87 @@
#include <psyc.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <lib.h>
uint8_t verbose;
int
test_index (const char *buf, size_t buflen)
{
char *res = malloc(buflen * 2);
size_t reslen = 0;
int ret, reti, len = 0;
PsycString idx;
PsycParseIndexState state;
psyc_parse_index_state_init(&state);
psyc_parse_index_buffer_set(&state, buf, buflen);
if (verbose)
printf(">> %.*s\n", (int)buflen, buf);
do {
ret = reti = psyc_parse_index(&state, &idx);
len = 0;
switch (ret) {
case PSYC_PARSE_INDEX_LIST_LAST:
ret = 0;
case PSYC_PARSE_INDEX_LIST:
len = sprintf(res + reslen, "#%ld", idx.length);
break;
case PSYC_PARSE_INDEX_STRUCT_LAST:
ret = 0;
case PSYC_PARSE_INDEX_STRUCT:
len = sprintf(res + reslen, ".%.*s", PSYC_S2ARGP(idx));
break;
case PSYC_PARSE_INDEX_DICT:
if (state.elemlen_found)
len = sprintf(res + reslen, "{%ld %.*s}",
idx.length, PSYC_S2ARGP(idx));
else
len = sprintf(res + reslen, "{%.*s}", PSYC_S2ARGP(idx));
break;
case PSYC_PARSE_INDEX_END:
ret = 0;
break;
default:
ret = -1;
}
if (verbose)
printf("%2d: %.*s\n", reti, len, res + reslen);
reslen += len;
} while (ret > 0);
if (reslen != buflen || memcmp(res, buf, buflen) != 0) {
printf("ERROR: got\n\[%.*s] (%ld) instead of\n[%.*s] (%ld)\n",
(int)reslen, res, reslen, (int)buflen, buf, buflen);
ret = 1;
} else
ret = 0;
free(res);
return ret;
}
int
main (int argc, char **argv)
{
verbose = argc > 1;
if (test_index(PSYC_C2ARG("#1{foo}._bar")) != 0)
return 1;
if (test_index(PSYC_C2ARG("{3 foo}._bar#0")) != 0)
return 2;
if (test_index(PSYC_C2ARG("{foo}#2._bar")) != 0)
return 3;
if (test_index(PSYC_C2ARG("._bar#1{3 foo}")) != 0)
return 4;
printf("test_index passed all tests.\n");
return 0; // passed all tests
}

View file

@ -17,21 +17,25 @@ main (int argc, char **argv)
PsycParseListState listState;
PsycList list_text, list_bin;
PsycString elems_text[NELEMS], elems_bin[NELEMS], elem;
PsycElem elems_text[NELEMS], elems_bin[NELEMS];
PsycString type, value;
char buf_text[NELEMS * 200], buf_bin[NELEMS * 200], *elems[NELEMS], **elems2 = NULL;
struct timeval start, end;
for (i=0; i<NELEMS; i++)
elems_text[i] = PSYC_C2STR("1234567890abcdefghijklmnopqrstuvwxyz-._ "
char *text = "1234567890abcdefghijklmnopqrstuvwxyz-._ "
"1234567890abcdefghijklmnopqrstuvwxyz-._ "
"1234567890abcdefghijklmnopqrstuvwxyz-._ "
"1234567890");
"1234567890";
char *bin = "1234567890|abcdefghijklmnopqrstuvwxyz|_\n"
"1234567890|abcdefghijklmnopqrstuvwxyz|_\n"
"1234567890|abcdefghijklmnopqrstuvwxyz|_\n"
"1234567890";
for (i=0; i<NELEMS; i++)
elems_bin[i] = PSYC_C2STR("1234567890|abcdefghijklmnopqrstuvwxyz|_\n"
"1234567890|abcdefghijklmnopqrstuvwxyz|_\n"
"1234567890|abcdefghijklmnopqrstuvwxyz|_\n"
"1234567890");
elems_text[i] = PSYC_ELEM_V(text, strlen(text));
for (i=0; i<NELEMS; i++)
elems_bin[i] = PSYC_ELEM_V(bin, strlen(bin));
psyc_list_init(&list_text, elems_text, PSYC_NUM_ELEM(elems_text),
PSYC_LIST_NO_LENGTH);
@ -54,13 +58,14 @@ main (int argc, char **argv)
psyc_parse_list_buffer_set(&listState, buf_text, list_text.length);
i = 0;
do {
ret = psyc_parse_list(&listState, &elem);
ret = psyc_parse_list(&listState, &type, &value);
switch (ret) {
case PSYC_PARSE_LIST_END:
ret = 0;
case PSYC_PARSE_LIST_ELEM:
if (verbose)
printf("|%d: %.*s... (%ld)\n", i, 10, elem.data, elem.length);
printf("|%ld:%.*s %.*s...\n", value.length,
(int)type.length, type.data, 10, value.data);
//elems[i] = malloc(elem.length);
//memcpy(&elems[i++], elem.data, elem.length);
break;

View file

@ -5,6 +5,8 @@
#include <psyc/packet.h>
#include <psyc/render.h>
uint8_t verbose;
int
packet_id (char *context, size_t contextlen,
char *source, size_t sourcelen,
@ -13,16 +15,22 @@ packet_id (char *context, size_t contextlen,
char *fragment, size_t fragmentlen,
char *result, size_t resultlen)
{
size_t idlen = psyc_packet_id_length(contextlen, sourcelen, targetlen,
counterlen, fragmentlen);
PsycList list;
PsycElem elems[PSYC_PACKET_ID_ELEMS];
memset(&list, 0, sizeof(PsycList));
memset(elems, 0, sizeof(PsycElem) * PSYC_PACKET_ID_ELEMS);
psyc_packet_id(&list, elems, context, contextlen,
source, sourcelen, target, targetlen,
counter, counterlen, fragment, fragmentlen);
size_t idlen = list.length;
char *id = malloc(idlen);
psyc_render_packet_id(context, contextlen,
source, sourcelen,
target, targetlen,
counter, counterlen,
fragment, fragmentlen,
id, idlen);
printf("%.*s\n", (int)idlen, id);
psyc_render_list(&list, id, idlen);
if (verbose)
printf("[%.*s]\n", (int)idlen, id);
int ret = idlen == resultlen && memcmp(result, id, idlen) == 0;
free(id);
return ret;
@ -31,13 +39,16 @@ packet_id (char *context, size_t contextlen,
int
main (int argc, char **argv)
{
verbose = argc > 1;
if (!packet_id(PSYC_C2ARG(""),
PSYC_C2ARG("psyc://example.net/~alice"),
PSYC_C2ARG("psyc://example.net/~bob"),
PSYC_C2ARG("1337"),
PSYC_C2ARG("42"),
PSYC_C2ARG("||psyc://example.net/~alice|psyc://example.net/~bob"
"|1337|42")))
PSYC_C2ARG("|| psyc://example.net/~alice"
"| psyc://example.net/~bob"
"| 1337| 42")))
return 1;
if (!packet_id(PSYC_C2ARG("psyc://example.net/@bar"),
@ -45,8 +56,9 @@ main (int argc, char **argv)
PSYC_C2ARG(""),
PSYC_C2ARG("1337"),
PSYC_C2ARG("42"),
PSYC_C2ARG("|psyc://example.net/@bar|psyc://example.net/~alice|"
"|1337|42")))
PSYC_C2ARG("| psyc://example.net/@bar"
"| psyc://example.net/~alice|"
"| 1337| 42")))
return 2;
if (!packet_id(PSYC_C2ARG("psyc://example.net/@bar"),
@ -54,8 +66,9 @@ main (int argc, char **argv)
PSYC_C2ARG("psyc://example.net/~alice"),
PSYC_C2ARG("1337"),
PSYC_C2ARG("42"),
PSYC_C2ARG("|psyc://example.net/@bar||psyc://example.net/~alice"
"|1337|42")))
PSYC_C2ARG("| psyc://example.net/@bar|"
"| psyc://example.net/~alice"
"| 1337| 42")))
return 3;
if (!packet_id(PSYC_C2ARG("psyc://example.net/@bar"),
@ -63,7 +76,7 @@ main (int argc, char **argv)
PSYC_C2ARG(""),
PSYC_C2ARG(""),
PSYC_C2ARG(""),
PSYC_C2ARG("|psyc://example.net/@bar||||")))
PSYC_C2ARG("| psyc://example.net/@bar||||")))
return 4;
return 0;

View file

@ -12,7 +12,7 @@ main (int argc, char **argv)
uint8_t verbose = argc > 2 && memchr(argv[2], (int)'v', strlen(argv[2]));
int idx, ret;
char buffer[2048], oper;
PsycString name, value, elem;
PsycString name, value, type;
PsycParseState state;
PsycParseListState listState;
@ -62,12 +62,13 @@ main (int argc, char **argv)
psyc_parse_list_state_init(&listState);
psyc_parse_list_buffer_set(&listState, PSYC_S2ARG(value));
while ((ret = psyc_parse_list(&listState, &elem))) {
while ((ret = psyc_parse_list(&listState, &type, &value))) {
switch (ret) {
case PSYC_PARSE_LIST_END:
case PSYC_PARSE_LIST_ELEM:
if (verbose)
printf("|%.*s\n", (int)elem.length, elem.data);
printf("|%.*s %.*s\n", (int)type.length, type.data,
(int)value.length, value.data);
break;
default:
printf("Error while parsing list: %i\n", ret);

View file

@ -8,9 +8,6 @@
#include <sys/socket.h>
#include <psyc.h>
#include <psyc/parse.h>
#include <psyc/render.h>
#include <psyc/syntax.h>
#include "test.c"
@ -71,10 +68,11 @@ test_input (int i, char *recvbuf, size_t nbytes)
PsycPacket *packet = &packets[i];
char oper;
PsycString name, value, elem;
PsycString name, value, type;
PsycString *pname = NULL, *pvalue = NULL;
PsycModifier *mod = NULL;
PsycParseListState listState;
PsycParseListState lstate;
PsycParseDictState dstate;
size_t len;
// Set buffer with data for the parser.
@ -283,37 +281,131 @@ test_input (int i, char *recvbuf, size_t nbytes)
oper = 0;
name.length = 0;
value.length = 0;
type.length = 0;
if (psyc_var_is_list(PSYC_S2ARG(*pname))) {
switch (psyc_var_type(PSYC_S2ARG(*pname))) {
case PSYC_TYPE_LIST:
if (verbose >= 2)
printf("## LIST START\n");
psyc_parse_list_state_init(&listState);
psyc_parse_list_buffer_set(&listState, PSYC_S2ARG(*pvalue));
psyc_parse_list_state_init(&lstate);
psyc_parse_list_buffer_set(&lstate, PSYC_S2ARG(*pvalue));
do {
retl = psyc_parse_list(&listState, &elem);
retl = psyc_parse_list(&lstate, &type, &value);
switch (retl) {
case PSYC_PARSE_LIST_END:
case PSYC_PARSE_LIST_TYPE:
if (verbose >= 2)
printf("## LIST TYPE: %.*s\n", (int)type.length, type.data);
break;
case PSYC_PARSE_LIST_ELEM_START:
case PSYC_PARSE_LIST_ELEM_LAST:
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");
printf("|%.*s [%.*s]", (int)type.length, type.data,
(int)value.length, value.data);
if (retl == PSYC_PARSE_LIST_ELEM_START)
printf(" ...");
printf("\n");
if (ret == PSYC_PARSE_LIST_ELEM_LAST)
printf("## LAST ELEM\n");
}
break;
case PSYC_PARSE_LIST_ELEM_CONT:
retl = 0;
case PSYC_PARSE_LIST_ELEM_END:
if (verbose >= 2) {
printf("... [%.*s]", (int)value.length, value.data);
if (retl == PSYC_PARSE_LIST_ELEM_CONT)
printf(" ...");
printf("\n");
}
break;
case PSYC_PARSE_LIST_END:
retl = 0;
if (verbose >= 2)
printf("## LIST END\n");
break;
default:
printf("# Error while parsing list: %i\n", retl);
ret = retl = -1;
}
} while (retl > 0);
break;
case PSYC_TYPE_DICT:
if (verbose >= 2)
printf("## DICT START\n");
psyc_parse_dict_state_init(&dstate);
psyc_parse_dict_buffer_set(&dstate, PSYC_S2ARG(*pvalue));
do {
retl = psyc_parse_dict(&dstate, &type, &value);
switch (retl) {
case PSYC_PARSE_DICT_TYPE:
if (verbose >= 2)
printf("## DICT TYPE: %.*s\n", (int)type.length, type.data);
break;
case PSYC_PARSE_DICT_KEY_START:
retl = 0;
case PSYC_PARSE_DICT_KEY:
if (verbose >= 2) {
printf("{[%.*s]", (int)value.length, value.data);
if (retl == PSYC_PARSE_DICT_KEY_START)
printf(" ...");
printf("\n");
}
while (retl > 0);
break;
case PSYC_PARSE_DICT_KEY_CONT:
retl = 0;
case PSYC_PARSE_DICT_KEY_END:
if (verbose >= 2) {
printf("... [%.*s]", (int)value.length, value.data);
if (retl == PSYC_PARSE_DICT_KEY_CONT)
printf(" ...");
printf("\n");
}
break;
case PSYC_PARSE_DICT_VALUE_START:
case PSYC_PARSE_DICT_VALUE_LAST:
retl = 0;
case PSYC_PARSE_DICT_VALUE:
if (verbose >= 2) {
printf("}%.*s [%.*s]", (int)type.length, type.data,
(int)value.length, value.data);
if (retl == PSYC_PARSE_DICT_VALUE_START)
printf(" ...");
printf("\n");
if (ret == PSYC_PARSE_DICT_VALUE_LAST)
printf("## LAST VALUE\n");
}
break;
case PSYC_PARSE_DICT_VALUE_CONT:
retl = 0;
case PSYC_PARSE_DICT_VALUE_END:
if (verbose >= 2) {
printf("... [%.*s]", (int)value.length, value.data);
if (retl == PSYC_PARSE_DICT_VALUE_CONT)
printf(" ...");
printf("\n");
}
break;
case PSYC_PARSE_DICT_END:
retl = 0;
printf("## DICT END\n");
break;
default:
printf("# Error while parsing dict: %i\n", retl);
ret = retl = -1;
}
} while (retl > 0);
break;
default:
break;
}
}
}
while (ret > 0);
} while (ret > 0);
if (progress)
r = write(1, " ", 1);

View file

@ -1,14 +1,13 @@
#include <stdio.h>
#include <lib.h>
#include <psyc/render.h>
#include <psyc/syntax.h>
#include <psyc.h>
#define myUNI "psyc://10.100.1000/~ludwig"
/* example renderer generating a presence packet */
int
testPresence (char *avail, int availlen,
test_presence (char *avail, int availlen,
char *desc, int desclen,
char *rendered, uint8_t verbose)
{
@ -42,7 +41,7 @@ testPresence (char *avail, int availlen,
}
int
testList (const char *rendered, uint8_t verbose)
test_list (const char *rendered, uint8_t verbose)
{
PsycModifier routing[2];
psyc_modifier_init(&routing[0], PSYC_OPERATOR_SET,
@ -52,23 +51,21 @@ testList (const char *rendered, uint8_t verbose)
PSYC_C2ARG("_context"),
PSYC_C2ARG(myUNI), PSYC_MODIFIER_ROUTING);
PsycString elems_text[] = {
PSYC_C2STR("foo"),
PSYC_C2STR("bar"),
PSYC_C2STR("baz"),
PsycElem elems_text[] = {
PSYC_ELEM_V("foo", 3),
PSYC_ELEM_V("bar", 3),
PSYC_ELEM_V("baz", 3),
};
PsycString elems_bin[] = {
PSYC_C2STR("foo"),
PSYC_C2STR("b|r"),
PSYC_C2STR("baz\nqux"),
PsycElem elems_bin[] = {
PSYC_ELEM_V("foo", 3),
PSYC_ELEM_V("b|r", 3),
PSYC_ELEM_V("baz\nqux", 7),
};
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_bin, elems_bin,
PSYC_NUM_ELEM(elems_bin), PSYC_LIST_CHECK_LENGTH);
psyc_list_init(&list_text, elems_text, PSYC_NUM_ELEM(elems_text));
psyc_list_init(&list_bin, elems_bin, PSYC_NUM_ELEM(elems_bin));
char buf_text[32], buf_bin[32];
psyc_render_list(&list_text, buf_text, sizeof(buf_text));
@ -77,10 +74,12 @@ testList (const char *rendered, uint8_t verbose)
PsycModifier entity[2];
psyc_modifier_init(&entity[0], PSYC_OPERATOR_SET,
PSYC_C2ARG("_list_text"),
buf_text, list_text.length, list_text.flag);
buf_text, list_text.length,
PSYC_MODIFIER_CHECK_LENGTH);
psyc_modifier_init(&entity[1], PSYC_OPERATOR_SET,
PSYC_C2ARG("_list_binary"),
buf_bin, list_bin.length, list_bin.flag);
buf_bin, list_bin.length,
PSYC_MODIFIER_CHECK_LENGTH);
PsycPacket packet;
psyc_packet_init(&packet, routing, PSYC_NUM_ELEM(routing),
@ -102,21 +101,21 @@ main (int argc, char **argv)
{
uint8_t verbose = argc > 1;
if (testPresence(PSYC_C2ARG("_here"), PSYC_C2ARG("I'm omnipresent right now"), "\
if (test_presence(PSYC_C2ARG("_here"), PSYC_C2ARG("I'm omnipresent right now"), "\
:_context\t" myUNI "\n\
\n\
97\n\
=_degree_availability\t_here\n\
=_description_presence\tI'm omnipresent right now\n\
=_description_presence 25\tI'm omnipresent right now\n\
_notice_presence\n\
|\n", verbose))
return 1;
if (testList("\
if (test_list("\
:_source psyc://10.100.1000/~ludwig\n\
:_context psyc://10.100.1000/~ludwig\n\
85\n\
:_list_text |foo|bar|baz\n\
:_list_binary 21 3 foo|3 b|r|7 baz\n\
90\n\
:_list_text 15 | foo| bar| baz\n\
:_list_binary 20 | foo|3 b|r| baz\n\
qux\n\
_test_list\n\
list test\n\

140
test/test_update.c Normal file
View file

@ -0,0 +1,140 @@
#include <psyc.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <lib.h>
uint8_t verbose;
int
test_update (const char *buf, size_t buflen,
const char *r_idx, size_t r_idxlen, char r_oper,
const char *r_typ, size_t r_typlen,
const char *r_val, size_t r_vallen)
{
char *idx = malloc(r_idxlen * 2);
char *typ = NULL, *val = NULL;
size_t idxlen = 0, typlen = 0, vallen = 0;
int ret, reti, len = 0;
char oper;
PsycString value;
PsycParseUpdateState state;
psyc_parse_update_state_init(&state);
psyc_parse_update_buffer_set(&state, buf, buflen);
if (verbose)
printf(">> %.*s\n", (int)buflen, buf);
do {
ret = reti = psyc_parse_update(&state, &oper, &value);
len = 0;
switch (ret) {
case PSYC_PARSE_INDEX_LIST:
len = sprintf(idx + idxlen, "#%ld", value.length);
break;
case PSYC_PARSE_INDEX_STRUCT:
len = sprintf(idx + idxlen, ".%.*s", PSYC_S2ARGP(value));
break;
case PSYC_PARSE_INDEX_DICT:
if (state.elemlen_found)
len = sprintf(idx + idxlen, "{%ld %.*s}",
value.length, PSYC_S2ARGP(value));
else
len = sprintf(idx + idxlen, "{%.*s}", PSYC_S2ARGP(value));
break;
case PSYC_PARSE_UPDATE_TYPE_END:
ret = 0;
case PSYC_PARSE_UPDATE_TYPE:
typ = value.data;
typlen = value.length;
if (verbose)
printf("%c[%.*s]\n", oper, PSYC_S2ARGP(value));
break;
case PSYC_PARSE_UPDATE_VALUE:
val = value.data;
vallen = value.length;
ret = 0;
if (verbose)
printf("[%.*s]\n", PSYC_S2ARGP(value));
break;
case PSYC_PARSE_UPDATE_END:
ret = 0;
break;
default:
ret = -1;
}
if (verbose && len)
printf("%2d: %.*s\n", reti, len, idx + idxlen);
idxlen += len;
} while (ret > 0);
if (ret == 0) {
if (idxlen != r_idxlen || oper != r_oper
|| typlen != r_typlen || vallen != r_vallen
|| memcmp(r_idx, idx, idxlen) != 0
|| memcmp(r_typ, typ, typlen) != 0
|| memcmp(r_val, val, vallen) != 0) {
printf("ERROR: got\n\[%.*s] %c[%.*s]:[%ld] [%.*s] instead of\n[%.*s]\n",
(int)idxlen, idx, oper, (int)typlen, typ, vallen, (int)vallen, val,
(int)buflen, buf);
ret = 1;
} else
ret = 0;
}
free(idx);
return ret;
}
int
main (int argc, char **argv)
{
verbose = argc > 1;
if (test_update(PSYC_C2ARG("#1{foo}._bar =_foo:3 bar"),
PSYC_C2ARG("#1{foo}._bar"), '=',
PSYC_C2ARG("_foo"),
PSYC_C2ARG("bar")) != 0)
return 1;
if (test_update(PSYC_C2ARG("{3 foo}._bar#0 +:3 baz"),
PSYC_C2ARG("{3 foo}._bar#0"), '+',
PSYC_C2ARG(""),
PSYC_C2ARG("baz")) != 0)
return 2;
if (test_update(PSYC_C2ARG("{foo}#2._bar - 1337"),
PSYC_C2ARG("{foo}#2._bar"), '-',
PSYC_C2ARG(""),
PSYC_C2ARG("1337")) != 0)
return 3;
if (test_update(PSYC_C2ARG("._bar#1{3 foo} ="),
PSYC_C2ARG("._bar#1{3 foo}"), '=',
PSYC_C2ARG(""),
PSYC_C2ARG("")) != 0)
return 4;
if (test_update(PSYC_C2ARG("#1{3 foo}._bar =_list"),
PSYC_C2ARG("#1{3 foo}._bar"), '=',
PSYC_C2ARG("_list"),
PSYC_C2ARG("")) != 0)
return 5;
if (test_update(PSYC_C2ARG("#1{3 foo}._bar =_list "),
PSYC_C2ARG("#1{3 foo}._bar"), '=',
PSYC_C2ARG("_list"),
PSYC_C2ARG("")) != 0)
return 6;
if (test_update(PSYC_C2ARG("#1{3 foo}._bar =_list"),
PSYC_C2ARG("#1{3 foo}._bar"), '=',
PSYC_C2ARG("_list"),
PSYC_C2ARG("")) != 0)
return 7;
printf("test_update passed all tests.\n");
return 0; // passed all tests
}