From d3aa4508b958661c247408919426f3934e36c6ce Mon Sep 17 00:00:00 2001 From: Gabor Adam Toth Date: Mon, 6 Feb 2012 15:05:08 +0100 Subject: [PATCH] dict syntax; index & update mod parser; psyc-mode for emacs --- .gitignore | 4 +- emacs/psyc.el | 124 +++++ include/psyc.h | 53 +- include/psyc/Makefile | 2 +- include/psyc/match.h | 27 +- include/psyc/packet.h | 247 ++++++--- include/psyc/parse.h | 374 ++++++++++--- include/psyc/render.h | 16 +- include/psyc/syntax.h | 21 - include/psyc/variable.h | 43 +- src/debug.h | 2 + src/match.c | 22 +- src/packet.c | 159 ++++-- src/parse.c | 880 ++++++++++++++++++++++++------ src/render.c | 190 ++++--- src/variable.c | 12 +- test/Makefile | 9 +- test/packets/00-length-no-content | 4 - test/packets/00-length-no-value | 7 - test/packets/02-list | 31 +- test/packets/02-list2 | 7 + test/packets/03-dict | 11 + test/packets/03-list | 20 - test/packets/04-circuit | 2 +- test/test_index.c | 87 +++ test/test_list.c | 27 +- test/test_packet_id.c | 45 +- test/test_parser.c | 7 +- test/test_psyc.c | 128 ++++- test/test_render.c | 53 +- test/test_update.c | 140 +++++ 31 files changed, 2063 insertions(+), 691 deletions(-) create mode 100644 emacs/psyc.el delete mode 100644 include/psyc/syntax.h delete mode 100644 test/packets/00-length-no-content delete mode 100644 test/packets/00-length-no-value create mode 100644 test/packets/02-list2 create mode 100644 test/packets/03-dict delete mode 100644 test/packets/03-list create mode 100644 test/test_index.c create mode 100644 test/test_update.c diff --git a/.gitignore b/.gitignore index abeb59a..098e713 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/emacs/psyc.el b/emacs/psyc.el new file mode 100644 index 0000000..fb38ac6 --- /dev/null +++ b/emacs/psyc.el @@ -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) diff --git a/include/psyc.h b/include/psyc.h index b046a58..1689ac7 100644 --- a/include/psyc.h +++ b/include/psyc.h @@ -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 diff --git a/include/psyc/Makefile b/include/psyc/Makefile index 74d0e77..989f7c7 100644 --- a/include/psyc/Makefile +++ b/include/psyc/Makefile @@ -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} diff --git a/include/psyc/match.h b/include/psyc/match.h index 2b61f9f..8be0704 100644 --- a/include/psyc/match.h +++ b/include/psyc/match.h @@ -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, - const char *key, size_t keylen, PsycBool inherit); +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 diff --git a/include/psyc/packet.h b/include/psyc/packet.h index 4f37750..88af733 100644 --- a/include/psyc/packet.h +++ b/include/psyc/packet.h @@ -18,9 +18,53 @@ #include -#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 diff --git a/include/psyc/parse.h b/include/psyc/parse.h index 36b0991..01ea398 100644 --- a/include/psyc/parse.h +++ b/include/psyc/parse.h @@ -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; diff --git a/include/psyc/render.h b/include/psyc/render.h index 7563ece..17cf066 100644 --- a/include/psyc/render.h +++ b/include/psyc/render.h @@ -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 diff --git a/include/psyc/syntax.h b/include/psyc/syntax.h deleted file mode 100644 index d46e0c0..0000000 --- a/include/psyc/syntax.h +++ /dev/null @@ -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 diff --git a/include/psyc/variable.h b/include/psyc/variable.h index a17f56d..b947829 100644 --- a/include/psyc/variable.h +++ b/include/psyc/variable.h @@ -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); } /** diff --git a/src/debug.h b/src/debug.h index 073b280..6d9f081 100644 --- a/src/debug.h +++ b/src/debug.h @@ -4,8 +4,10 @@ #ifdef DEBUG # include # define PP(args) printf args; +# define ASSERT(cond) assert(cond) #else # define PP(args) +# define ASSERT(cond) #endif #ifdef TEST diff --git a/src/match.c b/src/match.c index ee82401..ff811b2 100644 --- a/src/match.c +++ b/src/match.c @@ -107,11 +107,11 @@ 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, - const char *key, size_t keylen, PsycBool inherit) +psyc_map_lookup(const PsycMap * map, size_t size, + const char *key, size_t keylen, PsycBool inherit) { //size_t cursor = 1; size_t c = 0; @@ -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; diff --git a/src/packet.c b/src/packet.c index 17bd207..98310fc 100644 --- a/src/packet.c +++ b/src/packet.c @@ -1,73 +1,99 @@ #include "lib.h" -#include #include -inline PsycListFlag -psyc_list_length_check (PsycList *list) +inline PsycElemFlag +psyc_elem_length_check (PsycString *value, const char end) { - PsycListFlag flag = PSYC_LIST_NO_LENGTH; - size_t i, length = 0; + if (value->length > PSYC_ELEM_SIZE_THRESHOLD + || memchr(value->data, (int)end, value->length)) + return PSYC_ELEM_NEED_LENGTH; - for (i = 0; i < list->num_elems; i++) { - PsycString *elem = &list->elems[i]; - length += 1 + elem->length; // |elem - if (length > PSYC_MODIFIER_SIZE_THRESHOLD || - memchr(elem->data, (int) '|', elem->length) || - memchr(elem->data, (int) '\n', elem->length)) { - flag = PSYC_LIST_NEED_LENGTH; - break; - } - } - - return flag; + return PSYC_ELEM_NO_LENGTH;; } -inline PsycListFlag -psyc_list_length (PsycList *list) +inline size_t +psyc_elem_length (PsycElem *elem) { - size_t i, length = 0; + return + (elem->type.length ? 1 + elem->type.length : 0) + + (elem->value.length && elem->flag != PSYC_ELEM_NO_LENGTH + ? (elem->type.length ? 1 : 0) + psyc_num_length(elem->value.length) : 0) + + (elem->value.length ? 1 + elem->value.length : 0); +} - 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 +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++) { + elem = &list->elems[i]; + if (elem->flag == PSYC_ELEM_CHECK_LENGTH) + elem->flag = psyc_elem_length_check(&elem->value, '|'); + elem->length = psyc_elem_length(elem); + list->length += 1 + elem->length; } - return length; + return list->length; +} + +inline size_t +psyc_dict_length_set (PsycDict *dict) +{ + size_t i; + PsycDictKey *key; + PsycElem *value; + + dict->length = dict->type.length; + + for (i = 0; i < dict->num_elems; i++) { + key = &dict->elems[i].key; + value = &dict->elems[i].value; + + if (key->flag == PSYC_ELEM_CHECK_LENGTH) + key->flag = psyc_elem_length_check(&key->value, '}'); + if (value->flag == PSYC_ELEM_CHECK_LENGTH) + value->flag = psyc_elem_length_check(&value->value, '{'); + + key->length = psyc_dict_key_length(key); + value->length = psyc_elem_length(value); + + dict->length += 1 + key->length + 1 + value->length; + } + + return dict->length; } void -psyc_list_init (PsycList *list, PsycString *elems, size_t num_elems, - PsycListFlag flag) +psyc_list_init (PsycList *list, PsycElem *elems, size_t num_elems) { *list = (PsycList) { .num_elems = num_elems, .elems = elems, - .length = 0, - .flag = flag, }; - - if (flag == PSYC_LIST_CHECK_LENGTH) // check if list elements need length - list->flag = psyc_list_length_check(list); - - list->length = psyc_list_length(list); + psyc_list_length_set(list); } void -psyc_table_init (PsycTable *table, size_t width, PsycList *list) +psyc_dict_init (PsycDict *dict, PsycDictElem *elems, size_t num_elems) { - *table = (PsycTable) { - .width = width, - .list = list, + *dict = (PsycDict) { + .num_elems = num_elems, + .elems = elems, }; - - table->length = (width > 0 ? psyc_num_length(width) + 2 : 0) + list->length; + psyc_dict_length_set(dict); } inline size_t @@ -77,7 +103,10 @@ psyc_modifier_length (PsycModifier *m) if (m->name.length > 0) length += m->name.length + 1 + m->value.length; // name\tvalue - if (m->flag == PSYC_MODIFIER_NEED_LENGTH) // add length of length if needed + // add length of length if needed + if (m->value.length + && (m->flag & PSYC_MODIFIER_NEED_LENGTH + || m->flag == PSYC_MODIFIER_CHECK_LENGTH)) length += psyc_num_length(m->value.length) + 1; // SP length return length; @@ -96,7 +125,8 @@ psyc_packet_length_check (PsycPacket *p) // If any entity modifiers need length, it is possible they contain // a packet terminator, thus the content should have a length as well. for (i = 0; i < p->entity.lines; i++) - if (p->entity.modifiers[i].flag == PSYC_MODIFIER_NEED_LENGTH) + if (p->entity.modifiers[i].flag & PSYC_MODIFIER_NEED_LENGTH + || p->entity.modifiers[i].flag == PSYC_MODIFIER_CHECK_LENGTH) return PSYC_PACKET_NEED_LENGTH; if (memmem(p->data.data, p->data.length, PSYC_C2ARG(PSYC_PACKET_DELIMITER))) @@ -137,10 +167,11 @@ psyc_packet_length_set (PsycPacket *p) // set total length: routing-header content |\n p->length = p->routinglen + p->contentlen + 2; - if (p->contentlen > 0 || p->flag == PSYC_PACKET_NEED_LENGTH) + if (p->contentlen) p->length++; // add \n at the start of the content part - if (p->flag == PSYC_PACKET_NEED_LENGTH) // add length of length if needed + // add length of length if needed + if (p->contentlen && !(p->flag & PSYC_PACKET_NO_LENGTH)) p->length += psyc_num_length(p->contentlen); return p->length; @@ -198,9 +229,29 @@ psyc_packet_init_raw (PsycPacket *p, psyc_packet_length_set(p); } -size_t -psyc_packet_id_length (size_t contextlen, size_t sourcelen, size_t targetlen, - size_t counterlen, size_t fragmentlen) +void +psyc_packet_id (PsycList *list, PsycElem *elems, + char *context, size_t contextlen, + char *source, size_t sourcelen, + char *target, size_t targetlen, + char *counter, size_t counterlen, + char *fragment, size_t fragmentlen) { - return contextlen + sourcelen + targetlen + counterlen + fragmentlen + 5; + if (contextlen) + elems[PSYC_PACKET_ID_CONTEXT] = + PSYC_ELEM_VF(context, contextlen, PSYC_ELEM_NO_LENGTH); + if (sourcelen) + elems[PSYC_PACKET_ID_SOURCE] = + PSYC_ELEM_VF(source, sourcelen, PSYC_ELEM_NO_LENGTH); + if (targetlen) + elems[PSYC_PACKET_ID_TARGET] = + PSYC_ELEM_VF(target, targetlen, PSYC_ELEM_NO_LENGTH); + if (counterlen) + elems[PSYC_PACKET_ID_COUNTER] = + PSYC_ELEM_VF(counter, counterlen, PSYC_ELEM_NO_LENGTH); + if (fragmentlen) + elems[PSYC_PACKET_ID_FRAGMENT] = + PSYC_ELEM_VF(fragment, fragmentlen, PSYC_ELEM_NO_LENGTH); + + psyc_list_init(list, elems, PSYC_PACKET_ID_ELEMS); } diff --git a/src/parse.c b/src/parse.c index f621491..3b13d0c 100644 --- a/src/parse.c +++ b/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) { + ParseRC ret; + if (state->cursor >= state->buffer.length) - return PSYC_PARSE_LIST_INCOMPLETE; - - state->startc = state->cursor; - - if (!state->type) { // If type is not set we're at the start. - // First character is either | for text lists, or a number for binary lists - if (state->buffer.data[state->cursor] == '|') { - state->type = PSYC_LIST_TEXT; - state->cursor++; - } else if (psyc_is_numeric(state->buffer.data[state->cursor])) - state->type = PSYC_LIST_BINARY; - else - return PSYC_PARSE_LIST_ERROR_TYPE; - } - - if (state->type == PSYC_LIST_TEXT) { - elem->data = state->buffer.data + state->cursor; - elem->length = 0; - - if (state->cursor >= state->buffer.length) - 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; + return PSYC_PARSE_LIST_END; 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; + } + } 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; + } } -#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; - } + 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 +} diff --git a/src/render.c b/src/render.c index d61e68e..21d9b08 100644 --- a/src/render.c +++ b/src/render.c @@ -3,7 +3,59 @@ #include "lib.h" #include #include -#include + +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); -} diff --git a/src/variable.c b/src/variable.c index 23c5e10..dfe1a3c 100644 --- a/src/variable.c +++ b/src/variable.c @@ -4,7 +4,7 @@ #include /// 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) { diff --git a/test/Makefile b/test/Makefile index 662f2a2..1b1d98c 100644 --- a/test/Makefile +++ b/test/Makefile @@ -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 diff --git a/test/packets/00-length-no-content b/test/packets/00-length-no-content deleted file mode 100644 index 0954c09..0000000 --- a/test/packets/00-length-no-content +++ /dev/null @@ -1,4 +0,0 @@ -:_source psyc://foo.example.com/ -:_target psyc://bar.example.com/ -0 -| diff --git a/test/packets/00-length-no-value b/test/packets/00-length-no-value deleted file mode 100644 index 87627cb..0000000 --- a/test/packets/00-length-no-value +++ /dev/null @@ -1,7 +0,0 @@ -:_source psyc://foo.example.com/ -:_target psyc://bar.example.com/ - -:_foo 0 -_message_private -OHAI -| diff --git a/test/packets/02-list b/test/packets/02-list index 9c9e37e..8f4b8ed 100644 --- a/test/packets/02-list +++ b/test/packets/02-list @@ -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 | diff --git a/test/packets/02-list2 b/test/packets/02-list2 new file mode 100644 index 0000000..59a722f --- /dev/null +++ b/test/packets/02-list2 @@ -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 +| diff --git a/test/packets/03-dict b/test/packets/03-dict new file mode 100644 index 0000000..174aefb --- /dev/null +++ b/test/packets/03-dict @@ -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 +| diff --git a/test/packets/03-list b/test/packets/03-list deleted file mode 100644 index f613741..0000000 --- a/test/packets/03-list +++ /dev/null @@ -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/ -| diff --git a/test/packets/04-circuit b/test/packets/04-circuit index 5905f2b..089cc3a 100644 --- a/test/packets/04-circuit +++ b/test/packets/04-circuit @@ -1,4 +1,4 @@ -:_list_understand_modules |_state|_fragments|_context +:_list_understand_modules | _state| _fragments| _context _request_features | diff --git a/test/test_index.c b/test/test_index.c new file mode 100644 index 0000000..340a7ae --- /dev/null +++ b/test/test_index.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +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 +} diff --git a/test/test_list.c b/test/test_list.c index 723a9d9..560a52b 100644 --- a/test/test_list.c +++ b/test/test_list.c @@ -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; + char *text = "1234567890abcdefghijklmnopqrstuvwxyz-._ " + "1234567890abcdefghijklmnopqrstuvwxyz-._ " + "1234567890abcdefghijklmnopqrstuvwxyz-._ " + "1234567890"; + char *bin = "1234567890|abcdefghijklmnopqrstuvwxyz|_\n" + "1234567890|abcdefghijklmnopqrstuvwxyz|_\n" + "1234567890|abcdefghijklmnopqrstuvwxyz|_\n" + "1234567890"; + for (i=0; i #include +uint8_t verbose; + int packet_id (char *context, size_t contextlen, char *source, size_t sourcelen, @@ -13,16 +15,22 @@ packet_id (char *context, size_t contextlen, char *fragment, size_t fragmentlen, char *result, size_t resultlen) { - size_t idlen = psyc_packet_id_length(contextlen, sourcelen, targetlen, - counterlen, fragmentlen); + PsycList list; + PsycElem elems[PSYC_PACKET_ID_ELEMS]; + memset(&list, 0, sizeof(PsycList)); + memset(elems, 0, sizeof(PsycElem) * PSYC_PACKET_ID_ELEMS); + + psyc_packet_id(&list, elems, context, contextlen, + source, sourcelen, target, targetlen, + counter, counterlen, fragment, fragmentlen); + + size_t idlen = list.length; char *id = malloc(idlen); - psyc_render_packet_id(context, contextlen, - source, sourcelen, - target, targetlen, - counter, counterlen, - fragment, fragmentlen, - id, idlen); - printf("%.*s\n", (int)idlen, id); + + psyc_render_list(&list, id, idlen); + + if (verbose) + printf("[%.*s]\n", (int)idlen, id); int ret = idlen == resultlen && memcmp(result, id, idlen) == 0; free(id); return ret; @@ -31,13 +39,16 @@ packet_id (char *context, size_t contextlen, int main (int argc, char **argv) { + verbose = argc > 1; + if (!packet_id(PSYC_C2ARG(""), PSYC_C2ARG("psyc://example.net/~alice"), PSYC_C2ARG("psyc://example.net/~bob"), PSYC_C2ARG("1337"), PSYC_C2ARG("42"), - PSYC_C2ARG("||psyc://example.net/~alice|psyc://example.net/~bob" - "|1337|42"))) + PSYC_C2ARG("|| psyc://example.net/~alice" + "| psyc://example.net/~bob" + "| 1337| 42"))) return 1; if (!packet_id(PSYC_C2ARG("psyc://example.net/@bar"), @@ -45,8 +56,9 @@ main (int argc, char **argv) PSYC_C2ARG(""), PSYC_C2ARG("1337"), PSYC_C2ARG("42"), - PSYC_C2ARG("|psyc://example.net/@bar|psyc://example.net/~alice|" - "|1337|42"))) + PSYC_C2ARG("| psyc://example.net/@bar" + "| psyc://example.net/~alice|" + "| 1337| 42"))) return 2; if (!packet_id(PSYC_C2ARG("psyc://example.net/@bar"), @@ -54,8 +66,9 @@ main (int argc, char **argv) PSYC_C2ARG("psyc://example.net/~alice"), PSYC_C2ARG("1337"), PSYC_C2ARG("42"), - PSYC_C2ARG("|psyc://example.net/@bar||psyc://example.net/~alice" - "|1337|42"))) + PSYC_C2ARG("| psyc://example.net/@bar|" + "| psyc://example.net/~alice" + "| 1337| 42"))) return 3; if (!packet_id(PSYC_C2ARG("psyc://example.net/@bar"), @@ -63,7 +76,7 @@ main (int argc, char **argv) PSYC_C2ARG(""), PSYC_C2ARG(""), PSYC_C2ARG(""), - PSYC_C2ARG("|psyc://example.net/@bar||||"))) + PSYC_C2ARG("| psyc://example.net/@bar||||"))) return 4; return 0; diff --git a/test/test_parser.c b/test/test_parser.c index 769ca23..d317903 100644 --- a/test/test_parser.c +++ b/test/test_parser.c @@ -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); diff --git a/test/test_psyc.c b/test/test_psyc.c index 55699e1..447c7b7 100644 --- a/test/test_psyc.c +++ b/test/test_psyc.c @@ -8,9 +8,6 @@ #include #include -#include -#include -#include #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); + } 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"); + } + 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); diff --git a/test/test_render.c b/test/test_render.c index be57804..e02ab25 100644 --- a/test/test_render.c +++ b/test/test_render.c @@ -1,16 +1,15 @@ #include #include -#include -#include +#include #define myUNI "psyc://10.100.1000/~ludwig" /* example renderer generating a presence packet */ int -testPresence (char *avail, int availlen, - char *desc, int desclen, - char *rendered, uint8_t verbose) +test_presence (char *avail, int availlen, + char *desc, int desclen, + char *rendered, uint8_t verbose) { PsycModifier routing[1]; psyc_modifier_init(&routing[0], PSYC_OPERATOR_SET, @@ -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\ diff --git a/test/test_update.c b/test/test_update.c new file mode 100644 index 0000000..2eeb8a5 --- /dev/null +++ b/test/test_update.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include + +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 +}