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); +