From 7a1b1f0e080576ed9e53c07eef2fbec88ca76570 Mon Sep 17 00:00:00 2001 From: Marenz Date: Sat, 30 Apr 2011 14:30:01 +0200 Subject: [PATCH 1/4] added first draft for d binding --- include/d/psyc/parser.d | 166 +++++++++++++++++++++++++ include/d/psyc/psyc.d | 262 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 428 insertions(+) create mode 100644 include/d/psyc/parser.d create mode 100644 include/d/psyc/psyc.d diff --git a/include/d/psyc/parser.d b/include/d/psyc/parser.d new file mode 100644 index 0000000..19e343f --- /dev/null +++ b/include/d/psyc/parser.d @@ -0,0 +1,166 @@ +module psyc.parser; + +import psyc.psyc; + +/** + * @file d/psyc/parser.d + * @brief D Interface for various PSYC parser functions. + * + * All parsing functions and the definitions they use are + * defined in this file. +*/ + +/** + * @defgroup parsing-d Parsing Functions + * + * This module contains all parsing functions. + * @{ + */ + +extern (C): + +enum ParseFlag +{ + PARSE_HEADER_ONLY = 1, +} + +/** + * The return value definitions for the packet parsing function. + * @see parse() + */ +enum ParseRC +{ + PARSE_ERROR_END = -9, + PARSE_ERROR_BODY = -8, + PARSE_ERROR_METHOD = -7, + PARSE_ERROR_MOD_NL = -6, + PARSE_ERROR_MOD_LEN = -5, + PARSE_ERROR_MOD_TAB = -4, + PARSE_ERROR_MOD_NAME = -3, + PARSE_ERROR_LENGTH = -2, + PARSE_ERROR = -1, + PARSE_SUCCESS = 0, +/// 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. + PARSE_INSUFFICIENT = 1, +/// Routing modifier parsing done. +/// Operator, name & value contains the respective parts. + PARSE_ROUTING = 2, +/// Entity modifier parsing done. +/// Operator, name & value contains the respective parts. + PARSE_ENTITY = 3, +/// Entity modifier parsing is incomplete. +/// Operator & name are complete, value is incomplete. + PARSE_ENTITY_INCOMPLETE = 4, +/// Body parsing done, name contains method, value contains body. + PARSE_BODY = 5, +/// Body parsing is incomplete, name contains method, value contains part of the body. + PARSE_BODY_INCOMPLETE = 6, +/// Reached end of packet, parsing done. + PARSE_COMPLETE = 7, +/// Binary value parsing incomplete, used internally. + PARSE_INCOMPLETE = 8, +} + +/** + * The return value definitions for the list parsing function. + * @see parseList() + */ +enum ParseListRC +{ + PARSE_LIST_ERROR_DELIM = -5, + PARSE_LIST_ERROR_LEN = -4, + PARSE_LIST_ERROR_TYPE = -3, + PARSE_LIST_ERROR_NAME = -2, + PARSE_LIST_ERROR= -1, +/// Completed parsing a list element. + PARSE_LIST_ELEM = 1, +/// Reached end of buffer. + PARSE_LIST_END = 2, +/// Binary list is incomplete. + PARSE_LIST_INCOMPLETE = 3, +} + +/** + * Struct for keeping parser state. + */ +struct ParseState +{ + size_t cursor; ///< current position in buffer + size_t startc; ///< position where the parsing would be resumed + String buffer; ///< buffer with data to be parsed + ubyte flags; ///< flags for the parser, see ParseFlag + Part part; ///< part of the packet being parsed currently + + size_t routingLength; ///< length of routing part parsed so far + size_t contentParsed; ///< number of bytes parsed from the content so far + size_t contentLength; ///< expected length of the content + Bool contentLengthFound; ///< is there a length given for this packet? + size_t valueParsed; ///< number of bytes parsed from the value so far + size_t valueLength; ///< expected length of the value +} + +/** + * Struct for keeping list parser state. + */ +struct ParseListState +{ + size_t cursor; ///< current position in buffer + size_t startc; ///< line start position + String buffer; + ListType type; ///< list type + + size_t elemParsed; ///< number of bytes parsed from the elem so far + size_t elemLength; ///< expected length of the elem +} + +/** + * Initiates the state struct. + * + * @param state Pointer to the state struct that should be initiated. + */ +void psyc_initParseState (ParseState* state); + +/** + * Initiates the state struct with flags. + * + * @param state Pointer to the state struct that should be initiated. + * @param flags Flags to be set for the parser, see ParseFlag. + */ +void psyc_initParseState2 (ParseState* state, ubyte flags); + +/** + * Initiates the list state struct. + * + * @param state Pointer to the list state struct that should be initiated. + */ +void psyc_initParseListState (ParseListState* state); + +void psyc_nextParseBuffer (ParseState* state, String newBuf); + +void psyc_nextParseListBuffer (ParseListState* state, String newBuf); + +size_t psyc_getContentLength (ParseState* s); + +/** + * Parse PSYC packets. + * + * Generalized line-based packet parser. + * + * @param state An initialized ParseState + * @param oper A pointer to a character. In case of a variable, it will + * be set to the operator of that variable + * @param name A pointer to a String. It will point to the name of + * the variable or method and its length will be set accordingly + * @param value A pointer to a String. It will point to the + * value/body the variable/method and its length will be set accordingly + */ +ParseRC psyc_parse(ParseState* state, char* oper, String* name, String* value); + +/** + * List value parser. + */ +ParseListRC psyc_parseList(ParseListState* state, String *name, String* value, String* elem); + +/** @} */ // end of parsing group diff --git a/include/d/psyc/psyc.d b/include/d/psyc/psyc.d new file mode 100644 index 0000000..cb66937 --- /dev/null +++ b/include/d/psyc/psyc.d @@ -0,0 +1,262 @@ +/** @file d/.d + * + * @brief Main PSYC interface providing crucial functionality. +*/ + +/** @mainpage PSYC Core Library + * + * @section intro_sec Introduction + * + * This is the introduction. + * + * @section install_sec Installation + * + * @subsection step1 Step 1: Opening the box + * + * etc... + */ + +EPOCH = 1440444041 // 2015-08-24 21:20:41 CET (Monday) + +extern (C): + +enum Bool +{ + FALSE = 0, + TRUE = 1, +} + +/** + * PSYC packet parts. + */ +enum Part +{ + PART_RESET = -1, + PART_ROUTING, + PART_LENGTH, + PART_CONTENT, + PART_METHOD, + PART_DATA, + PART_END, +} + +/** + * 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. + */ +enum Type +{ + TYPE_UNKNOWN, + TYPE_AMOUNT, + TYPE_COLOR, + TYPE_DATE, + TYPE_DEGREE, + TYPE_ENTITY, + TYPE_FLAG, + TYPE_LANGUAGE, + TYPE_LIST, + TYPE_NICK, + TYPE_PAGE, + TYPE_UNIFORM, + TYPE_TIME, +} + +/** + * List types. + * Possible types are text and binary. + */ +enum ListType +{ + LIST_TEXT = 1, + LIST_BINARY = 2, +} + +enum ModifierFlag +{ + MODIFIER_CHECK_LENGTH = 0, + MODIFIER_NEED_LENGTH = 1, + MODIFIER_NO_LENGTH = 2, + MODIFIER_ROUTING = 3, +} + +enum ListFlag +{ + LIST_CHECK_LENGTH = 0, + LIST_NEED_LENGTH = 1, + LIST_NO_LENGTH = 2, +} + +enum PacketFlag +{ + PACKET_CHECK_LENGTH = 0, + PACKET_NEED_LENGTH = 1, + PACKET_NO_LENGTH = 2, +} + +struct String +{ + size_t length; + char *ptr; +} + +struct MatchVar +{ + String name; + int value; +} + +/** +* Shortcut for creating a String. + * + * @param memory Pointer to the buffer. + * @param length Length of that buffer. + * + * @return An instance of the String struct. + */ +String newString (char *str, size_t strlen); + +#define C2STR(_string) {sizeof(_string)-1, _string} +#define C2ARG(_string) _string, sizeof(_string)-1 + +/* intermediate struct for a PSYC variable modification */ +struct Modifier +{ + char oper; // not call it 'operator' as C++ may not like that.. + String name; + String value; + ModifierFlag flag; +} + +struct Header +{ + size_t lines; + Modifier *modifiers; +} + +struct List +{ + size_t num_elems; + String *elems; + size_t length; + ListFlag flag; +} + +/* intermediate struct for a PSYC packet */ +struct Packet +{ + Header routing; ///< Routing header. + Header entity; ///< Entity header. + String method; + String data; + size_t routingLength; ///< Length of routing part. + size_t contentLength; ///< Length of content part. + size_t length; ///< Total length of packet. + PacketFlag flag; +} + +int psyc_version(); + +/** Check if a modifier needs length */ +ModifierFlag checkModifierLength(Modifier *m); + +/** Get the total length of a modifier. */ +size_t getModifierLength(Modifier *m); + +/** Create new modifier */ +Modifier newModifier(char oper, String *name, String *value, + ModifierFlag flag); + +/** Create new modifier */ +Modifier newModifier2(char oper, + char *name, size_t namelen, + char *value, size_t valuelen, + ModifierFlag flag); + +/** Check if a list needs length */ +ListFlag checkListLength(List *list); + +/** Get the total length of a list. */ +ListFlag getListLength(List *list); + +/** Check if a packet needs length */ +PacketFlag checkPacketLength(Packet *p); + +/** Calculate and set the length of packet parts and total packet length */ +size_t setPacketLength(Packet *p); + +/** Create new list */ +List newList(String *elems, size_t num_elems, ListFlag flag); + +/** Create new packet */ +Packet newPacket(Header *routing, + Header *entity, + String *method, String *data, + PacketFlag flag); + +/** Create new packet */ +Packet newPacket2(Modifier *routing, size_t routinglen, + Modifier *entity, size_t entitylen, + char *method, size_t methodlen, + char *data, size_t datalen, + PacketFlag flag); + +/// Routing vars in alphabetical order. +extern (C) String routingVars[]; +extern (C) MatchVar varTypes[]; + +/** + * Get the type of variable name. + */ +Bool isRoutingVar(char *name, size_t len); + +/** + * Get the type of variable name. + */ +Type getVarType(char *name, size_t len); + +/** + * Checks if long keyword string inherits from short keyword string. + */ +int inherits(char *sho, size_t slen, + char *lon, size_t llen); + +/** + * Checks if short keyword string matches long keyword string. + */ +int matches(char *sho, size_t slen, + char *lon, size_t llen); + +/** + * Callback for text() that produces a value for a match. + * + * The application looks up a match such as _fruit from [_fruit] and + * if found writes its current value from its variable store into the + * outgoing buffer.. "Apple" for example. The template returns the + * number of bytes written. 0 is a legal return value. Should the + * callback return -1, text leaves the original template text as is. + */ +typedef int (*textCB)(char *match, size_t mlen, + char **buffer, size_t *blen); + +/** + * Fills out text templates by asking a callback for content. + * + * Copies the contents of the template into the buffer while looking + * for braceOpen and braceClose strings and calling the callback for + * each enclosed string between these braces. Should the callback + * return -1, the original template text is copied as is. + * + * By default PSYC's "[" and "]" are used but you can provide any other + * brace strings such as "${" and "}" or "". + * + * See also http://about..eu/text + */ +int text(char *template, size_t tlen, + char **buffer, size_t *blen, + textCB lookupValue, + char *braceOpen, char *braceClose); + From d94c76012aa747d661499cfad23749379f52348e Mon Sep 17 00:00:00 2001 From: Marenz Date: Sat, 30 Apr 2011 14:39:04 +0200 Subject: [PATCH 2/4] more work on the d binding --- include/d/psyc/{psyc.d => common.d} | 12 +++++------- include/d/psyc/parser.d | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) rename include/d/psyc/{psyc.d => common.d} (94%) diff --git a/include/d/psyc/psyc.d b/include/d/psyc/common.d similarity index 94% rename from include/d/psyc/psyc.d rename to include/d/psyc/common.d index cb66937..efb5a90 100644 --- a/include/d/psyc/psyc.d +++ b/include/d/psyc/common.d @@ -16,7 +16,9 @@ * etc... */ -EPOCH = 1440444041 // 2015-08-24 21:20:41 CET (Monday) +module psyc.common; + +const EPOCH = 1440444041; // 2015-08-24 21:20:41 CET (Monday) extern (C): @@ -119,9 +121,6 @@ struct MatchVar */ String newString (char *str, size_t strlen); -#define C2STR(_string) {sizeof(_string)-1, _string} -#define C2ARG(_string) _string, sizeof(_string)-1 - /* intermediate struct for a PSYC variable modification */ struct Modifier { @@ -239,8 +238,7 @@ int matches(char *sho, size_t slen, * number of bytes written. 0 is a legal return value. Should the * callback return -1, text leaves the original template text as is. */ -typedef int (*textCB)(char *match, size_t mlen, - char **buffer, size_t *blen); +alias extern (C) int function (char *match, size_t mlen, char **buffer, size_t *blen) textCB; /** * Fills out text templates by asking a callback for content. @@ -255,7 +253,7 @@ typedef int (*textCB)(char *match, size_t mlen, * * See also http://about..eu/text */ -int text(char *template, size_t tlen, +int text(char *_template, size_t tlen, char **buffer, size_t *blen, textCB lookupValue, char *braceOpen, char *braceClose); diff --git a/include/d/psyc/parser.d b/include/d/psyc/parser.d index 19e343f..4345d52 100644 --- a/include/d/psyc/parser.d +++ b/include/d/psyc/parser.d @@ -1,6 +1,6 @@ module psyc.parser; -import psyc.psyc; +import psyc.common; /** * @file d/psyc/parser.d From ac29663a474bf0b6619bbdb7bbdd3def95490923 Mon Sep 17 00:00:00 2001 From: Marenz Date: Sat, 30 Apr 2011 15:35:34 +0200 Subject: [PATCH 3/4] added flag to parse only contents of a packet --- include/psyc/parser.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/psyc/parser.h b/include/psyc/parser.h index ffac7d9..f1e8412 100644 --- a/include/psyc/parser.h +++ b/include/psyc/parser.h @@ -22,6 +22,8 @@ typedef enum { PSYC_PARSE_HEADER_ONLY = 1, + /// Expects only the content part of a packet. The length of the content must fit exactly in this case + PSYC_BEGIN_PARSE_AT_CONTENT = 2, } psycParseFlag; /** From 6463c3e9bb5e5e9524425fa8173cf18e1c4df67d Mon Sep 17 00:00:00 2001 From: Marenz Date: Sat, 30 Apr 2011 15:43:00 +0200 Subject: [PATCH 4/4] adjusted functions for flag PARSE_BEGIN_AT_CONTENT --- include/d/psyc/parser.d | 1 + include/psyc/parser.h | 2 +- src/parser.c | 13 ++++++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/d/psyc/parser.d b/include/d/psyc/parser.d index 4345d52..1d03adc 100644 --- a/include/d/psyc/parser.d +++ b/include/d/psyc/parser.d @@ -22,6 +22,7 @@ extern (C): enum ParseFlag { PARSE_HEADER_ONLY = 1, + PARSE_BEGIN_AT_CONTENT = 2, } /** diff --git a/include/psyc/parser.h b/include/psyc/parser.h index f1e8412..bff444d 100644 --- a/include/psyc/parser.h +++ b/include/psyc/parser.h @@ -23,7 +23,7 @@ typedef enum { PSYC_PARSE_HEADER_ONLY = 1, /// Expects only the content part of a packet. The length of the content must fit exactly in this case - PSYC_BEGIN_PARSE_AT_CONTENT = 2, + PSYC_PARSE_BEGIN_AT_CONTENT = 2, } psycParseFlag; /** diff --git a/src/parser.c b/src/parser.c index 501c300..914e483 100644 --- a/src/parser.c +++ b/src/parser.c @@ -24,6 +24,9 @@ inline void psyc_initParseState2 (psycParseState* state, uint8_t flags) { memset(state, 0, sizeof(psycParseState)); state->flags = flags; + + if (flags & PSYC_PARSE_BEGIN_AT_CONTENT) + state->part = PSYC_PART_CONTENT; } inline void psyc_initParseListState (psycParseListState* state) @@ -33,6 +36,12 @@ inline void psyc_initParseListState (psycParseListState* state) inline void psyc_nextParseBuffer (psycParseState* state, psycString newBuf) { + if (state->flags & PSYC_PARSE_BEGIN_AT_CONTENT) + { + state->contentLength = newBuf.length; + state->contentLengthFound = PSYC_TRUE; + } + state->buffer = newBuf; state->cursor = 0; } @@ -275,6 +284,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc { state->contentLengthFound = 1; state->contentLength = 0; + do { state->contentLength = 10 * state->contentLength + state->buffer.ptr[state->cursor] - '0'; @@ -308,7 +318,8 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc case PSYC_PART_CONTENT: // In case of an incomplete binary variable resume parsing it. - if (state->valueParsed < state->valueLength) { + if (state->valueParsed < state->valueLength) + { ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed)); state->contentParsed += value->length;