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:
parent
3ee2f0e392
commit
d3aa4508b9
31 changed files with 2063 additions and 691 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -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
124
emacs/psyc.el
Normal 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)
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
20
src/match.c
20
src/match.c
|
@ -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;
|
||||
|
|
153
src/packet.c
153
src/packet.c
|
@ -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;
|
||||
|
||||
return PSYC_ELEM_NO_LENGTH;;
|
||||
}
|
||||
|
||||
inline size_t
|
||||
psyc_elem_length (PsycElem *elem)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
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 flag;
|
||||
return list->length;
|
||||
}
|
||||
|
||||
inline PsycListFlag
|
||||
psyc_list_length (PsycList *list)
|
||||
inline size_t
|
||||
psyc_dict_length_set (PsycDict *dict)
|
||||
{
|
||||
size_t i, length = 0;
|
||||
size_t i;
|
||||
PsycDictKey *key;
|
||||
PsycElem *value;
|
||||
|
||||
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
|
||||
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 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);
|
||||
}
|
||||
|
|
876
src/parse.c
876
src/parse.c
|
@ -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
|
||||
}
|
||||
|
|
190
src/render.c
190
src/render.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
:_source psyc://foo.example.com/
|
||||
:_target psyc://bar.example.com/
|
||||
0
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
:_source psyc://foo.example.com/
|
||||
:_target psyc://bar.example.com/
|
||||
|
||||
:_foo 0
|
||||
_message_private
|
||||
OHAI
|
||||
|
|
|
@ -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
7
test/packets/02-list2
Normal 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
11
test/packets/03-dict
Normal 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
|
||||
|
|
|
@ -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/
|
||||
|
|
87
test/test_index.c
Normal file
87
test/test_index.c
Normal 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
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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,12 +39,15 @@ 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"
|
||||
PSYC_C2ARG("|| psyc://example.net/~alice"
|
||||
"| psyc://example.net/~bob"
|
||||
"| 1337| 42")))
|
||||
return 1;
|
||||
|
||||
|
@ -45,7 +56,8 @@ main (int argc, char **argv)
|
|||
PSYC_C2ARG(""),
|
||||
PSYC_C2ARG("1337"),
|
||||
PSYC_C2ARG("42"),
|
||||
PSYC_C2ARG("|psyc://example.net/@bar|psyc://example.net/~alice|"
|
||||
PSYC_C2ARG("| psyc://example.net/@bar"
|
||||
"| psyc://example.net/~alice|"
|
||||
"| 1337| 42")))
|
||||
return 2;
|
||||
|
||||
|
@ -54,7 +66,8 @@ 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"
|
||||
PSYC_C2ARG("| psyc://example.net/@bar|"
|
||||
"| psyc://example.net/~alice"
|
||||
"| 1337| 42")))
|
||||
return 3;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
126
test/test_psyc.c
126
test/test_psyc.c
|
@ -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);
|
||||
|
|
|
@ -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
140
test/test_update.c
Normal 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
|
||||
}
|
Loading…
Reference in a new issue