Contents

API suggestions

using only functions

renderer.h (waiting for feedback)

Feedback about the following would be nice:

  • Which api-functions are you missing here?
  • How do you like the way of calling them?

Remember, however, that this is LOW-LEVEL, and still has the requirement of not enforcing any specific structure on the user. There will be higherlevel functions, too, but this (this being renderer.h) is not the place for them. I expect the user to do quite a lot, thats the price for not having any structure requirements. And I think thats okay.

--Marenz 20:58, 23 February 2010 (CET)

<coyo> will there be intermediate high-level language libraries that use that library? i hope so. i guess that's up to the people including the language.


enum PSYC_PacketType
{
  MULTICAST, // only  :_context is set
  UNICAST,  // :_source and :_target is set
  SYNC /* :_context and :_target is set.
          this is used for initial state sync
          for a new joined entity */
};

/* @brief renders a write packet
 *
 * renders a write packet.
 * NOTE: old name for the method was
 *       _message. It was said, it should
 *       be renamed, but noone seemed to care
 *       enough about the name, yet noone would
 *       decide for one. So I simply choosed this
 *       name (_write). There was enough time
 *       to talk about this without actually
 *       getting anything done.
 *
 * @param target pointer to non-null
 *        terminated character array
 * @param tlength length of the array
 *        target points to
 * @param msg pointer to non-null
 *        terminated character array
 * @param mlength length of the array
 *        msg points to
 * @param buffer pointer to an allocated
 *        output buffer
 * @param blength length/size of the buffer
 * @param written out-parameter, containing
 *        the amount of bytes written
 *        to the buffer
 *
 * @returns 0 for success
 *         -1 for invalid target      
 *         -2 if the buffer length is to small
 */
int PSYC_renderWrite(uint8_t* target,unsigned int tlength,
                     uint8_t* msg   ,unsigned int mlength,
                     uint8_t* buffer,unsigned int blength,
                     unsigned int* written);

/* @brief renders a write packet with source
 *
 * behaives the same as its brother,
 * only that the source can also be specified
 *
 * @returns -3 for invalid source
 */
int PSYC_renderWrite(uint8_t* target,unsigned int tlength,
                     uint8_t* source,unsigned int slength,
                     uint8_t* msg   ,unsigned int mlength,
                     uint8_t* buffer,unsigned int blength,
                     unsigned int* written);

/* @brief renders a single variable
 *
 * Renders a variable according
 * to specification
 *
 * @param name pointer to a character array
 *             (not null terminated)
 * @param nlength length of the name array
 * @param buffer pointer to the output buffer
 * @param blength size of the output buffer
 * @param written out-parameter, the amount
 *        of bytes written to buffer
 * @param binary optional parameter, wether
 *        to check the variable for binary
 *        content and format it accordingly
 *
 *
 * @returns 0 for success
 *         -1 for invalid name
 *         -2 if the buffer is to small
 *        
 */
int PSYC_renderVariable(uint8_t* name ,unsigned int nlength,
                        uint8_t* value,unsigned int vlength,
                        uint8_t* buffer ,unsigned int blength,
                        unsigned int* written,
                        uint8_t binary = 1);



/* @brief renders the method part of a packet
 *
 * Renders the given method with the
 * given content.
 *
 * @param method pointer to character array,
 *        not null terminated
 * @param mlength size of the method array
 * @param content pointer to character array,
 *        not null terminated
 * @param clength size of the content array
 * @param buffer pointer to the output buffer
 * @param blength size of the output buffer
 * @param written outparamater, the amount
 *        of bytes written to buffer
 *
 * @returns 0 for success
 *         -1 for invalid method
 *         -2 when the buffer is to small
 * */
int PSYC_renderMethod(uint8_t* method,unsigned int mlength,
                      uint8_t* content,unsigned int clength,
                      uint8_t* buffer,unsigned blength,
                      unsigned int * written);


parser.h (partly implemented)

/** @brief parses a routerVariable
 *
 *  This function parses one routing variable,
 *  advances the cursor after the variable,
 *  writes the variables name, value and their
 *  lengths in the corresponding out parameters
 *  and returns 0 or an errorcode.
 *
 *  
 *  
 *
 *  @param data pointer to the packet data
 *  @param dlength length of the data (amount of bytes)
 *  @param cursor pointer to the current parsing position
 *  @param name pointer-pointer, used to return the position
 *         of the name string
 *  @param nlength pointer to which the length of
 *         the name string will be written
 *  @param value pointer-pointer, used to retrun the position
 *         of the value string
 *  @param vlength pointer to which the length of
 *         the value string will be written
 *
 *  @returns 0 on success
 *           1 on insufficient data.
 *             This does not advance
 *             the cursor.            
 *           2 when no longer in the header,
 *             This advances the cursor to the
 *             body/entity section, but leaves
 *             the other out parameters invalid.
 *           3 the packet is complete.
 *           >2 on a context error,
 *           <0 on a parsing error.
 *              This invalidates all but the cursor
 *              out paramater. */
int PSYC_parseHeader(
                  unsigned int* cursor,
                  const uint8_t * data, unsigned int dlength,
                  const uint8_t** name, unsigned int *nlength,
                  const uint8_t** value, unsigned int *vlength);

/** @brief parses one variable in two buffers
 *
 *  This function is nearly identical to its
 *  brother parseHeader. The difference is,
 *  it uses two buffers and return parameters
 *  for everything. It is meant to be used
 *  in case parseHeader returned 2 for
 *  insufficient data and you don’t
 *  like to copy memory around to
 *  have all the data in one buffer.
 *  Using this function, you can pass two
 *  data buffers. The consequence is,
 *  that name and value can be distributed
 *  on two different buffers and thus need
 *  also two out paramaters. If only one
 *  will be used, length of the second
 *  will be 0.
 *
 *  If your data is spread over more
 *  than two buffers, you need to
 *  copy that in one or two buffers.
 *  Given the unlikleyness of that
 *  event, we don't offer a three
 *  or more buffer function here.
 *
 */
int PSYC_parseHeader2(
                  unsigned int* cursor,
                  const uint8_t * data1, unsigned int dlength1,
                  const uint8_t * data2, unsigned int dlength2,
                  const uint8_t** name1, unsigned int *nlength1,
                  const uint8_t** name2, unsigned int *nlength2,
                  const uint8_t** value1, unsigned int *vlength1,
                  const uint8_t** value2, unsigned int *vlength2);

/** @brief parses one bodyelement
 *
 *  This parses one body element, that is
 *  either an entity-variable or the method
 *
 *  The function assumes that dlength is set
 *  to the exact length of the packet
 *  so that data[dlength-1]  would be the
 *  ending "|" of the packet.
 *
 *  The parameters are nearly the same as for
 *  PSYC_routerVariable, only difference is
 *  that a returnvalue of 2 means, we encountered
 *  the method.
 *  This means that the out paramterer
 *  name contains the methodname and
 *  value the content.
 *  */
int PSYC_parseClosedBody(
                  unsigned int* cursor,
                  const uint8_t * data, unsigned int dlength,
                  const uint8_t** name, unsigned int *nlength,
                  const uint8_t** value, unsigned int *vlength);

/** @brief parses one bodyelement
 *
 * This function is nearly identical to
 * its brother parseClosedBody. *
 *
 * It assumes that we don’t know the
 * real length of the packet and thus
 * searches for the terminator.
 */
int PSYC_parseOpenBody(
                  unsigned int* cursor,
                  const uint8_t * data, unsigned int dlength,
                  const uint8_t** name, unsigned int *nlength,
                  const uint8_t** value, unsigned int *vlength);



/* @brief parses an bodyelement in two buffers
 *
 * This function is the borther of parseHeader2.
 * It behaives the same as
 * parseOpenBody and parseHeader2. */
int PSYC_parseOpenBody2(
                  unsigned int* cursor,
                  const uint8_t * data1, unsigned int dlength1,
                  const uint8_t * data2, unsigned int dlength2,
                  const uint8_t** name1, unsigned int *nlength1,
                  const uint8_t** name2, unsigned int *nlength2,
                  const uint8_t** value1, unsigned int *vlength1,
                  const uint8_t** value2, unsigned int *vlength2);




#include <psyc_impl.h>

using callbacks

<Marenz> I just wasn’t happey with this interface, to much things can go if the user makes a small mistake, to much problems arise when we parse in two stages, i just don’t like it.


#include <stdint.h>

struct PSYC_Parser;

/** @brief initialize a pstate struct
 *
 *  @param pstate pointer to an allocated
 *         PSYC_Parser struct.
 */
void PSYC_initState(struct PSYC_Parser* pstate);


/** @brief parses a packet
 *
 * This function parses rawdata
 * and uses the callbacks in PSYC_Parser
 * to communicate with the caller.
 *
 * First the header will be parsed,
 * after that the stateCallback
 * (with inEntity set to false)
 * will be called for each variable.
 * Then, routingCallback will be called
 * to find out if further parsing
 * is desired.
 * If it returns false, PSYC_parser returns.
 * If it returns true, parsing continues
 * to the body.
 * After the entitystate has been parsed,
 * stateCallback will be called for each
 * variable, having inEntity set to true.
 * Finally, bodyCallback will be called,
 * containing the method, and its data.
 *
 * In case of an parsing error <to continue>
 *
 * @param data constant pointer to the
 *        raw data that is to be processed.
 * @param length the amount of bytes to parse
 * @param pstate pointer to a preallocated
 *        and initialized (PSYC_initState)
 *        instance of the struct state
 *        
*/
void PSYC_parse(const uint8_t* data, unsigned int length,
                struct PSYC_Parser* pstate);

/** @brief FlagMod */
enum PSYC_Modifier
{
  // variable modifers
  ASSIGN=0x02,
  AUGMENT=0x04,
  DIMINISH=0x08,
  SET=0x10,
  QUERY=0x20 
};

struct PSYC_Parser
{    
  /** @brief Callback for the states
   *
   * This callback will be called to inform
   * the caller about the states.
   *
   * It will be called once for each variable.
   *
   * @param pstate pointer to the ParserState
   *        struct for identification
   * @param name not null terminated c-string,
   *        containing the name of the variable
   * @param nlength the length of the variable name
   * @param value not null terminated c-string,
   *        containing the value of the variable
   * @param vlength the length of the variable value
   * @param modifers modifer of the variable (see Modifer)
   * @param inEntity wether this variable is an entity
   *        variable(true) or a routing variable(false) */
  void (*stateCallback)(struct PSYC_Parser* pstate,
         const uint8_t *name, const unsigned int nlength,
         const uint8_t *value, const unsigned int vlength,
         enum PSYC_Modifier modifiers, char inEntity);

  /** @brief gets called after the routing-header was parsed
   *
   * @return if 0, parser will continue to parse
   *         the content part and calls bodyCallback
   *         when finished,
   *         if not 0, parser will stop parsing and
   *         calls contentCallback */
  char (*routingCallback)(struct PSYC_Parser* pstate);

  /** @brief Body callback, gets called when the body was parsed
   *
   * @param pstate pointer to the ParserState struct
   *        for identificiation
   * @param method not null terminated c-string,
   *        containing the method name
   * @param mlength the length of the methodname
   * @param dlength the length of the data
   * @param data not null terminated c-string,
   *        containing the data section
   * @param content not null terminated c-string
   * @param clength length of the content string */
  void (*bodyCallback)(struct PSYC_Parser* pstate,
                   const uint8_t* method, unsigned int mlength,
                   const uint8_t* data, unsigned int dlength,  
                   const uint8_t* content, unsigned int clength);

  /** @brief Error callback, gets called to indicate
   *         an error and the start of an error packet
   *          
   * If there was an error while parsing the rawdata,
   * instead of passing the packets data to the callbacks,
   * an error packet will be passed back, describing the
   * the error in more detail.
   *
   * On error, errorCallback will be called
   * to report the errortype (in the method),
   * after that errorStateCallback will be
   * called to inform about more detailed facts
   * of the error.
   *
   * Any previous state or body callbacks become
   * invalid and have to be purged.*/
  void (*errorCallback)(struct PSYC_Parser* pstate,
                   const uint8_t *method, unsigned int mlength);

  /** @brief error state callback
   *
   * The parameters are the same as for stateCallback.
   * The callback will be called once for each
   * state variable in the error report packet
   */
  void (*errorStateCallback)(struct PSYC_Parser* pstate,
         const uint8_t *name, const unsigned int nlength,
         const uint8_t *value, const unsigned int vlength,
         enum PSYC_Modifier modifiers);


  /*******************************************
   *  The following variables and datatypes  *
   *  are being used to remember the         *
   *  internal state. You should not         *
   *  touch them.                            *
   *******************************************/
  uint8_t glyph;
  unsigned int contpos; // position inside the content
  unsigned int mstart,mlength, // position and length of the method
  dstart,dlength;  //

};