Source code for lbmmonfmtcsv.c

/*
  All of the documentation and software included in this and any
  other Informatica Corporation Ultra Messaging Releases
  Copyright (C) Informatica Corporation. All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted only as covered by the terms of a
  valid software license agreement with Informatica Corporation.

  Copyright (C) 2004-2014, Informatica Corporation. All Rights Reserved.

  THE SOFTWARE IS PROVIDED "AS IS" AND INFORMATICA DISCLAIMS ALL WARRANTIES
  EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF
  NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
  PURPOSE.  INFORMATICA DOES NOT WARRANT THAT USE OF THE SOFTWARE WILL BE
  UNINTERRUPTED OR ERROR-FREE.  INFORMATICA SHALL NOT, UNDER ANY CIRCUMSTANCES, BE
  LIABLE TO LICENSEE FOR LOST PROFITS, CONSEQUENTIAL, INCIDENTAL, SPECIAL OR
  INDIRECT DAMAGES ARISING OUT OF OR RELATED TO THIS AGREEMENT OR THE
  TRANSACTIONS CONTEMPLATED HEREUNDER, EVEN IF INFORMATICA HAS BEEN APPRISED OF
  THE LIKELIHOOD OF SUCH DAMAGES.

*/

#ifdef __VOS__
#define _POSIX_C_SOURCE 200112L
#include <sys/time.h>
#endif

#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <time.h>
#include <limits.h>
#include <errno.h>
#ifdef _WIN32
        #define strcasecmp stricmp
        #define snprintf _snprintf
#else
#endif
#if defined(__TANDEM)
        #include <strings.h>
#endif
#include <lbm/lbmmon.h>
#include <lbm/lbmmonfmtcsv.h>
static const lbmmon_format_func_t LBMMON_FORMAT_CSV =
{
        lbmmon_format_csv_init,
        lbmmon_rcv_format_csv_serialize,
        lbmmon_src_format_csv_serialize,
        lbmmon_rcv_format_csv_deserialize,
        lbmmon_src_format_csv_deserialize,
        lbmmon_format_csv_finish,
        lbmmon_format_csv_errmsg,
        lbmmon_evq_format_csv_serialize,
        lbmmon_evq_format_csv_deserialize,
        lbmmon_ctx_format_csv_serialize,
        lbmmon_ctx_format_csv_deserialize
};

typedef struct
{
        unsigned char mSeparator;
        size_t mBufferSize;
        char * mBuffer;
} lbmmon_format_csv_t;

static const char * next_csv_value(const char * String, char * Value, size_t Size, char Separator);

#define LBMMON_FORMAT_CSV_MODULE_ID     1
#define LBMMON_FORMAT_CSV_VERSION_1 1
#define LBMMON_FORMAT_CSV_VERSION_2 2
#define LBMMON_FORMAT_CSV_VERSION_3 3
#define LBMMON_FORMAT_CSV_VERSION_4 4
#define LBMMON_FORMAT_CSV_VERSION_CURRENT LBMMON_FORMAT_CSV_VERSION_4
#define MAKE_MODULE_VERSION(version) ((unsigned short) ((((unsigned char) LBMMON_FORMAT_CSV_MODULE_ID) << 8) | ((unsigned char) version)))
#define MODULE_ID(id) ((unsigned char) ((id & 0xff00) >> 8))
#define MODULE_VERSION(id) ((unsigned char) (id & 0xff))

typedef struct
{
        const size_t * layout;
        size_t count;
} lbmmon_csv_layout_t;

static char ErrorString[1024];

const lbmmon_format_func_t *
lbmmon_format_csv_module(void)
{
        return (&LBMMON_FORMAT_CSV);
}

int
lbmmon_format_csv_init(void * * FormatClientData,
                                           const void * FormatOptions)
{
        char key[512];
        char value[512];
        const char * ptr = (const char *) FormatOptions;
        lbmmon_format_csv_t * data;

        memset(ErrorString, 0, sizeof(ErrorString));
        data = malloc(sizeof(lbmmon_format_csv_t));
        data->mSeparator = ',';
        data->mBufferSize = 1024;
        data->mBuffer = malloc(data->mBufferSize);

        while ((ptr = lbmmon_next_key_value_pair(ptr, key, sizeof(key), value, sizeof(value))) != NULL)
        {
                if (strcasecmp(key, "separator") == 0)
                {
                        data->mSeparator = value[0];
                }
        }
        *FormatClientData = (void *)data;
        return (0);
}

/*
 Format of the CSV receiver statistics data is:
     type (one of LBM_TRANSPORT_STAT_* values)
     source (as a string)
     actual statistics, depending on type....
         for LBTRM:
             msgs_rcved
             bytes_rcved
             nak_pckts_sent
             naks_sent
             lost
             ncfs_ignored
             ncfs_shed
             ncfs_rx_delay
             ncfs_unknown
             nak_stm_min
             nak_stm_mean
             nak_stm_max
             nak_tx_min
             nak_tx_mean
             nak_tx_max
             duplicate_data
             unrecovered_txw
             unrecovered_tmo
             lbm_msgs_rcved
             lbm_msgs_no_topic_rcved
             lbm_reqs_rcved
                         dgrams_dropped_size
                         dgrams_dropped_type
                         dgrams_dropped_version
                         dgrams_dropped_hdr
                         dgrams_dropped_other
             out_of_order
         for LBTRU:
             msgs_rcved
             bytes_rcved
             nak_pckts_sent
             naks_sent
             lost
             ncfs_ignored
             ncfs_shed
             ncfs_rx_delay
             ncfs_unknown
             nak_stm_min
             nak_stm_mean
             nak_stm_max
             nak_tx_min
             nak_tx_mean
             nak_tx_max
             duplicate_data
             unrecovered_txw
             unrecovered_tmo
             lbm_msgs_rcved
             lbm_msgs_no_topic_rcved
             lbm_reqs_rcved
                         dgrams_dropped_size
                         dgrams_dropped_type
                         dgrams_dropped_version
                         dgrams_dropped_hdr
                         dgrams_dropped_sid
                         dgrams_dropped_other
         for TCP:
             bytes_rcved
             lbm_msgs_rcved
             lbm_msgs_no_topic_rcved
             lbm_reqs_rcved
         for LBTIPC:
             msgs_rcved
                         bytes_rcved
                         lbm_msgs_rcved
                         lbm_msgs_no_topic_rcved
                         lbm_reqs_rcved
         for LBTRDMA:
             msgs_rcved
                         bytes_rcved
                         lbm_msgs_rcved
                         lbm_msgs_no_topic_rcved
                         lbm_reqs_rcved
*/

int
lbmmon_rcv_format_csv_serialize(char * Destination,
                                                                size_t * Size,
                                                                unsigned short * ModuleID,
                                                                const lbm_rcv_transport_stats_t * Statistics,
                                                                void * FormatClientData)
{
        char work[1024];
        lbmmon_format_csv_t     * fmt;

        if ((Destination == NULL) || (Size == NULL) || (*Size == 0) || (Statistics == NULL) || (FormatClientData == NULL))
        {
                return (-1);
        }
        fmt = (lbmmon_format_csv_t *) FormatClientData;

        *ModuleID = MAKE_MODULE_VERSION(LBMMON_FORMAT_CSV_VERSION_CURRENT);
        memset(work, 0, sizeof(work));
        snprintf(work, sizeof(work), "%d%c\"",
                         Statistics->type,
                         fmt->mSeparator);
        strncat(work, Statistics->source, sizeof(work) - strlen(work) - 1);
        strncat(work, "\"", sizeof(work) - strlen(work) - 1);
        strncpy(Destination, work, *Size);
        switch (Statistics->type)
        {
                case LBM_TRANSPORT_STAT_TCP:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.tcp.bytes_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.tcp.lbm_msgs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.tcp.lbm_msgs_no_topic_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.tcp.lbm_reqs_rcved);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;

                case LBM_TRANSPORT_STAT_LBTRM:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.msgs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.bytes_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.nak_pckts_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.naks_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.lost,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.ncfs_ignored,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.ncfs_shed,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.ncfs_rx_delay);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.ncfs_unknown,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.nak_stm_min,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.nak_stm_mean,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.nak_stm_max,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.nak_tx_min,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.nak_tx_mean,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.nak_tx_max,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.duplicate_data);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.unrecovered_txw,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.unrecovered_tmo,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.lbm_msgs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.lbm_msgs_no_topic_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.lbm_reqs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.dgrams_dropped_size,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.dgrams_dropped_type,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.dgrams_dropped_version);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.dgrams_dropped_hdr,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.dgrams_dropped_other,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.out_of_order);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;

                case LBM_TRANSPORT_STAT_LBTRU:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.msgs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.bytes_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.nak_pckts_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.naks_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.lost,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.ncfs_ignored,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.ncfs_shed,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.ncfs_rx_delay);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.ncfs_unknown,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.nak_stm_min,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.nak_stm_mean,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.nak_stm_max,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.nak_tx_min,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.nak_tx_mean,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.nak_tx_max,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.duplicate_data);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.unrecovered_txw,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.unrecovered_tmo,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.lbm_msgs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.lbm_msgs_no_topic_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.lbm_reqs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.dgrams_dropped_size,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.dgrams_dropped_type,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.dgrams_dropped_version);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.dgrams_dropped_hdr,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.dgrams_dropped_sid,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.dgrams_dropped_other);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;

                case LBM_TRANSPORT_STAT_LBTIPC:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtipc.msgs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtipc.bytes_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtipc.lbm_msgs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtipc.lbm_msgs_no_topic_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtipc.lbm_reqs_rcved);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;

                case LBM_TRANSPORT_STAT_LBTRDMA:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrdma.msgs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrdma.bytes_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrdma.lbm_msgs_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrdma.lbm_msgs_no_topic_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrdma.lbm_reqs_rcved);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;

                default:
                        strncpy(ErrorString, "Unknown LBM transport type", sizeof(ErrorString));
                        return (-1);
        }
        *Size = strlen(Destination);
        return (0);
}

/*
 Format of the CSV source statistics data is:
     type (one of LBM_TRANSPORT_STAT_* values)
     source (as a string)
     actual statistics, depending on type....
         for LBTRM:
             msgs_sent
             bytes_sent
             txw_msgs
             txw_bytes
             nak_pckts_rcved
             naks_rcved
             naks_ignored
             naks_shed
             naks_rx_delay_ignored
             rxs_sent
             rctlr_data_msgs
             rctlr_rx_msgs
             rx_bytes_sent
         for LBTRU:
             msgs_sent
             bytes_sent
             nak_pckts_rcved
             naks_rcved
             naks_ignored
             naks_shed
             naks_rx_delay_ignored
             rxs_sent
             num_clients
             rx_bytes_sent
         for TCP:
             num_clients
             bytes_buffered
         for LBTIPC:
             num_clients
                         msgs_sent
                         bytes_sent
         for LBTRDMA:
             num_clients
                         msgs_sent
                         bytes_sent
*/

int
lbmmon_src_format_csv_serialize(char * Destination,
                                                                size_t * Size,
                                                                unsigned short * ModuleID,
                                                                const lbm_src_transport_stats_t * Statistics,
                                                                void * FormatClientData)
{
        char work[1024];
        lbmmon_format_csv_t     * fmt;

        if ((Destination == NULL) || (Size == NULL) || (*Size == 0) || (Statistics == NULL) || (FormatClientData == NULL))
        {
                return (-1);
        }
        fmt = (lbmmon_format_csv_t *) FormatClientData;

        *ModuleID = MAKE_MODULE_VERSION(LBMMON_FORMAT_CSV_VERSION_CURRENT);
        memset(work, 0, sizeof(work));
        snprintf(work, sizeof(work), "%d%c\"",
                         Statistics->type,
                         fmt->mSeparator);
        strncat(work, Statistics->source, sizeof(work) - strlen(work) - 1);
        strncat(work, "\"", sizeof(work) - strlen(work) - 1);
        strncpy(Destination, work, *Size);
        switch (Statistics->type)
        {
                case LBM_TRANSPORT_STAT_TCP:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.tcp.num_clients,
                                         fmt->mSeparator,
                                         Statistics->transport.tcp.bytes_buffered);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;

                case LBM_TRANSPORT_STAT_LBTRM:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.msgs_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.bytes_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.txw_msgs,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.txw_bytes,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.nak_pckts_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.naks_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.naks_ignored,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.naks_shed);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.naks_rx_delay_ignored,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.rxs_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.rctlr_data_msgs,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.rctlr_rx_msgs,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrm.rx_bytes_sent);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;

                case LBM_TRANSPORT_STAT_LBTRU:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.msgs_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.bytes_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.nak_pckts_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.naks_rcved,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.naks_ignored,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.naks_shed,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.naks_rx_delay_ignored,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.rxs_sent);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.num_clients,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtru.rx_bytes_sent);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;

                case LBM_TRANSPORT_STAT_LBTIPC:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtipc.num_clients,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtipc.msgs_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtipc.bytes_sent);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;
                case LBM_TRANSPORT_STAT_LBTRDMA:
                        snprintf(work,
                                         sizeof(work),
                                         "%c%lx%c%lx%c%lx",
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrdma.num_clients,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrdma.msgs_sent,
                                         fmt->mSeparator,
                                         Statistics->transport.lbtrdma.bytes_sent);
                        if (strlen(work) >= (*Size - strlen(Destination) - 1))
                        {
                                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                                return (-1);
                        }
                        strncat(Destination, work, *Size - strlen(Destination) - 1);
                        break;
        }
        *Size = strlen(Destination);
        return (0);
}

/*
 Format of the CSV event queue statistics data is:
        data_msgs
        data_msgs_tot
        data_msgs_svc_min
        data_msgs_svc_mean
        data_msgs_svc_max
        resp_msgs
        resp_msgs_tot
        resp_msgs_svc_min
        resp_msgs_svc_mean
        resp_msgs_svc_max
        topicless_im_msgs
        topicless_im_msgs_tot
        topicless_im_msgs_svc_min
        topicless_im_msgs_svc_mean
        topicless_im_msgs_svc_max
        wrcv_msgs
        wrcv_msgs_tot
        wrcv_msgs_svc_min
        wrcv_msgs_svc_mean
        wrcv_msgs_svc_max
        io_events
        io_events_tot
        io_events_svc_min
        io_events_svc_mean
        io_events_svc_max
        timer_events
        timer_events_tot
        timer_events_svc_min
        timer_events_svc_mean
        timer_events_svc_max
        source_events
        source_events_tot
        source_events_svc_min
        source_events_svc_mean
        source_events_svc_max
        unblock_events
        unblock_events_tot
        cancel_events
        cancel_events_tot
        cancel_events_svc_min
        cancel_events_svc_mean
        cancel_events_svc_max
        context_source_events
        context_source_events_tot
        context_source_events_svc_min
        context_source_events_svc_mean
        context_source_events_svc_max
        events
        events_tot
        age_min
        age_mean
        age_max
        callback_events
        callback_events_tot
        callback_events_svc_min
        callback_events_svc_mean
        callback_events_svc_max
*/

int
lbmmon_evq_format_csv_serialize(char * Destination,
                                                                size_t * Size,
                                                                unsigned short * ModuleID,
                                                                const lbm_event_queue_stats_t * Statistics,
                                                                void * FormatClientData)
{
        lbmmon_format_csv_t     * fmt;
        char work[1024];

        if ((Destination == NULL) || (Size == NULL) || (*Size == 0) || (Statistics == NULL) || (FormatClientData == NULL))
        {
                return (-1);
        }
        fmt = (lbmmon_format_csv_t *) FormatClientData;

        *ModuleID = MAKE_MODULE_VERSION(LBMMON_FORMAT_CSV_VERSION_CURRENT);
        memset(work, 0, sizeof(work));
        memset(Destination, 0, *Size);
        snprintf(work,
                         sizeof(work),
                         "%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c",
                         Statistics->data_msgs,
                         fmt->mSeparator,
                         Statistics->data_msgs_tot,
                         fmt->mSeparator,
                         Statistics->data_msgs_svc_min,
                         fmt->mSeparator,
                         Statistics->data_msgs_svc_mean,
                         fmt->mSeparator,
                         Statistics->data_msgs_svc_max,
                         fmt->mSeparator,
                         Statistics->resp_msgs,
                         fmt->mSeparator,
                         Statistics->resp_msgs_tot,
                         fmt->mSeparator,
                         Statistics->resp_msgs_svc_min,
                         fmt->mSeparator,
                         Statistics->resp_msgs_svc_mean,
                         fmt->mSeparator,
                         Statistics->resp_msgs_svc_max,
                         fmt->mSeparator,
                         Statistics->topicless_im_msgs,
                         fmt->mSeparator,
                         Statistics->topicless_im_msgs_tot,
                         fmt->mSeparator,
                         Statistics->topicless_im_msgs_svc_min,
                         fmt->mSeparator,
                         Statistics->topicless_im_msgs_svc_mean,
                         fmt->mSeparator,
                         Statistics->topicless_im_msgs_svc_max,
                         fmt->mSeparator);
        if (strlen(work) >= (*Size - strlen(Destination) - 1))
        {
                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                return (-1);
        }
        strncat(Destination, work, *Size - strlen(Destination) - 1);
        snprintf(work,
                         sizeof(work),
                         "%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c",
                         Statistics->wrcv_msgs,
                         fmt->mSeparator,
                         Statistics->wrcv_msgs_tot,
                         fmt->mSeparator,
                         Statistics->wrcv_msgs_svc_min,
                         fmt->mSeparator,
                         Statistics->wrcv_msgs_svc_mean,
                         fmt->mSeparator,
                         Statistics->wrcv_msgs_svc_max,
                         fmt->mSeparator,
                         Statistics->io_events,
                         fmt->mSeparator,
                         Statistics->io_events_tot,
                         fmt->mSeparator,
                         Statistics->io_events_svc_min,
                         fmt->mSeparator,
                         Statistics->io_events_svc_mean,
                         fmt->mSeparator,
                         Statistics->io_events_svc_max,
                         fmt->mSeparator,
                         Statistics->timer_events,
                         fmt->mSeparator,
                         Statistics->timer_events_tot,
                         fmt->mSeparator,
                         Statistics->timer_events_svc_min,
                         fmt->mSeparator,
                         Statistics->timer_events_svc_mean,
                         fmt->mSeparator,
                         Statistics->timer_events_svc_max,
                         fmt->mSeparator);
        if (strlen(work) >= (*Size - strlen(Destination) - 1))
        {
                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                return (-1);
        }
        strncat(Destination, work, *Size - strlen(Destination) - 1);
        snprintf(work,
                         sizeof(work),
                         "%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c",
                         Statistics->source_events,
                         fmt->mSeparator,
                         Statistics->source_events_tot,
                         fmt->mSeparator,
                         Statistics->source_events_svc_min,
                         fmt->mSeparator,
                         Statistics->source_events_svc_mean,
                         fmt->mSeparator,
                         Statistics->source_events_svc_max,
                         fmt->mSeparator,
                         Statistics->unblock_events,
                         fmt->mSeparator,
                         Statistics->unblock_events_tot,
                         fmt->mSeparator,
                         Statistics->cancel_events,
                         fmt->mSeparator,
                         Statistics->cancel_events_tot,
                         fmt->mSeparator,
                         Statistics->cancel_events_svc_min,
                         fmt->mSeparator,
                         Statistics->cancel_events_svc_mean,
                         fmt->mSeparator,
                         Statistics->cancel_events_svc_max,
                         fmt->mSeparator);
        if (strlen(work) >= (*Size - strlen(Destination) - 1))
        {
                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                return (-1);
        }
        strncat(Destination, work, *Size - strlen(Destination) - 1);
        snprintf(work,
                         sizeof(work),
                         "%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx",
                         Statistics->context_source_events,
                         fmt->mSeparator,
                         Statistics->context_source_events_tot,
                         fmt->mSeparator,
                         Statistics->context_source_events_svc_min,
                         fmt->mSeparator,
                         Statistics->context_source_events_svc_mean,
                         fmt->mSeparator,
                         Statistics->context_source_events_svc_max,
                         fmt->mSeparator,
                         Statistics->events,
                         fmt->mSeparator,
                         Statistics->events_tot,
                         fmt->mSeparator,
                         Statistics->age_min,
                         fmt->mSeparator,
                         Statistics->age_mean,
                         fmt->mSeparator,
                         Statistics->age_max,
                         fmt->mSeparator,
                         Statistics->callback_events,
                         fmt->mSeparator,
                         Statistics->callback_events_tot,
                         fmt->mSeparator,
                         Statistics->callback_events_svc_min,
                         fmt->mSeparator,
                         Statistics->callback_events_svc_mean,
                         fmt->mSeparator,
                         Statistics->callback_events_svc_max);
        if (strlen(work) >= (*Size - strlen(Destination) - 1))
        {
                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                return (-1);
        }
        strncat(Destination, work, *Size - strlen(Destination) - 1);
        *Size = strlen(Destination);
        return (0);
}

/*
 Format of the CSV context statistics data is:
        tr_dgrams_sent
        tr_bytes_sent
        tr_dgrams_rcved
        tr_bytes_rcved
        tr_dgrams_dropped_ver
        tr_dgrams_dropped_type
        tr_dgrams_dropped_malformed
        tr_dgrams_send_failed
        tr_src_topics
        tr_rcv_topics
        tr_rcv_unresolved_topics
        lbtrm_unknown_msgs_rcved
        lbtru_unknown_msgs_rcved
        send_blocked
        send_would_block
        resp_blocked
        resp_would_block
        uim_dup_msgs_rcved
        uim_msg_no_stream_rcved
*/

int
lbmmon_ctx_format_csv_serialize(char * Destination,
                                                                size_t * Size,
                                                                unsigned short * ModuleID,
                                                                const lbm_context_stats_t * Statistics,
                                                                void * FormatClientData)
{
        lbmmon_format_csv_t     * fmt;
        char work[1024];

        if ((Destination == NULL) || (Size == NULL) || (*Size == 0) || (Statistics == NULL) || (FormatClientData == NULL))
        {
                return (-1);
        }
        fmt = (lbmmon_format_csv_t *) FormatClientData;

        *ModuleID = MAKE_MODULE_VERSION(LBMMON_FORMAT_CSV_VERSION_CURRENT);
        memset(work, 0, sizeof(work));
        memset(Destination, 0, *Size);
        snprintf(work,
                         sizeof(work),
                         "%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c%lx%c",
                         Statistics->tr_dgrams_sent,
                         fmt->mSeparator,
                         Statistics->tr_bytes_sent,
                         fmt->mSeparator,
                         Statistics->tr_dgrams_rcved,
                         fmt->mSeparator,
                         Statistics->tr_bytes_rcved,
                         fmt->mSeparator,
                         Statistics->tr_dgrams_dropped_ver,
                         fmt->mSeparator,
                         Statistics->tr_dgrams_dropped_type,
                         fmt->mSeparator,
                         Statistics->tr_dgrams_dropped_malformed,
                         fmt->mSeparator,
                         Statistics->tr_dgrams_send_failed,
                         fmt->mSeparator,
                         Statistics->tr_src_topics,
                         fmt->mSeparator,
                         Statistics->tr_rcv_topics,
                         fmt->mSeparator,
                         Statistics->tr_rcv_unresolved_topics,
                         fmt->mSeparator,
                         Statistics->lbtrm_unknown_msgs_rcved,
                         fmt->mSeparator,
                         Statistics->lbtru_unknown_msgs_rcved,
                         fmt->mSeparator,
                         Statistics->send_blocked,
                         fmt->mSeparator,
                         Statistics->send_would_block,
                         fmt->mSeparator,
                         Statistics->resp_blocked,
                         fmt->mSeparator,
                         Statistics->resp_would_block,
                         fmt->mSeparator);
        if (strlen(work) >= (*Size - strlen(Destination) - 1))
        {
                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                return (-1);
        }
        strncat(Destination, work, *Size - strlen(Destination) - 1);
        snprintf(work,
                         sizeof(work),
                         "%lx%c%lx",
                         Statistics->uim_dup_msgs_rcved,
                         fmt->mSeparator,
                         Statistics->uim_msgs_no_stream_rcved);
        if (strlen(work) >= (*Size - strlen(Destination) - 1))
        {
                strncpy(ErrorString, "Destination too small for data", sizeof(ErrorString));
                return (-1);
        }
        strncat(Destination, work, *Size - strlen(Destination) - 1);
        *Size = strlen(Destination);
        return (0);
}

const char *
next_csv_value(const char * String,
                           char * Value,
                           size_t Size,
                           char Separator)
{
        const char * ptr = String;
        size_t pos;

        if ((ptr == NULL) || (Value == NULL) || (Size == 0))
        {
                return (NULL);
        }
        memset(Value, 0, Size);

        /* Skip any whitespace */
        while ((*ptr != '\0') && (*ptr != Separator) && ((*ptr == ' ') || (*ptr == '\t')))
        {
                ptr++;
        }
        pos = 0;

        if (*ptr == '\0')
        {
                return (NULL);
        }
        else if (*ptr == Separator)
        {
                ptr++;
                return (ptr);
        }
        else if ((*ptr == '\"') || (*ptr == '\''))
        {
                char quote = *ptr;
                ptr++;
                while ((*ptr != '\0') && (*ptr != quote) && (pos < (Size - 1)))
                {
                        Value[pos++] = *ptr++;
                }
                /* In case we exceeded the Value size, scan for the ending quote. */
                while ((*ptr != '\0') && (*ptr != quote))
                {
                        ptr++;
                }
                /* Finally, scan for the separator */
                while ((*ptr != '\0') && (*ptr != Separator))
                {
                        ptr++;
                }
        }
        else
        {
                /* Copy into Value */
                while ((*ptr != '\0') && (*ptr != Separator) && (pos < (Size - 1)))
                {
                        Value[pos++] = *ptr++;
                }
                /* In case we exceeded the Value size, scan for the separator. */
                while ((*ptr != '\0') && (*ptr != Separator))
                {
                        ptr++;
                }
        }
        /* If we're at the separator, advance the pointer */
        if (*ptr == Separator)
        {
                ptr++;
        }
        return (ptr);
}

static lbm_ulong_t
convert_value(const char * Buffer)
{
        lbm_ulong_t value = 0;
        const char * ptr = Buffer;

        while (1)
        {
                errno = 0;
                value = strtoul(ptr, NULL, 16);
                if ((value == ULONG_MAX) && (errno == ERANGE))
                {
                        ptr++;
                }
                else
                {
                        return (value);
                }
        }
}

/*************************************************************************************************/
/* A note to maintainers:                                                                        */
/*                                                                                               */
/*      Ideally, the code to deserialize statistics would be completely generic. Instead of separate */
/*      parsing loops for each of n message types, a single function could parse the string and put  */
/*      the values into the structure (given the appropriate pointers). Access to the statistics     */
/*      structure would also be generic, casting a pointer to the actual structure into a char *,    */
/*      then indexing using the field offset arrays (below) to locate the correct position for the   */
/*      field within the structure.                                                                  */
/*                                                                                               */
/*      That is, as long as the type of each field in every statistics structure is the same.        */
/*      Which it currently is... and probably will remain so. But there's no guarantee that it       */
/*      _will_ remain so. So better to bite the bullet now, and make the possibility of non-         */
/*      homogeneous structures simple to implement.                                                  */
/*************************************************************************************************/

static const size_t csv_rcv_tcp_stat_offset_v1[] =
{
        offsetof(lbm_rcv_transport_stats_tcp_t, bytes_rcved),
        offsetof(lbm_rcv_transport_stats_tcp_t, lbm_msgs_rcved),
        offsetof(lbm_rcv_transport_stats_tcp_t, lbm_msgs_no_topic_rcved),
        offsetof(lbm_rcv_transport_stats_tcp_t, lbm_reqs_rcved)
};
#define csv_rcv_tcp_stat_offset_v2 csv_rcv_tcp_stat_offset_v1
#define csv_rcv_tcp_stat_offset_v3 csv_rcv_tcp_stat_offset_v2
#define csv_rcv_tcp_stat_offset_v4 csv_rcv_tcp_stat_offset_v3
static const lbmmon_csv_layout_t csv_rcv_tcp_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { csv_rcv_tcp_stat_offset_v1, sizeof(csv_rcv_tcp_stat_offset_v1)/sizeof(csv_rcv_tcp_stat_offset_v1[0]) },
        { csv_rcv_tcp_stat_offset_v2, sizeof(csv_rcv_tcp_stat_offset_v2)/sizeof(csv_rcv_tcp_stat_offset_v2[0]) },
        { csv_rcv_tcp_stat_offset_v3, sizeof(csv_rcv_tcp_stat_offset_v3)/sizeof(csv_rcv_tcp_stat_offset_v3[0]) },
        { csv_rcv_tcp_stat_offset_v4, sizeof(csv_rcv_tcp_stat_offset_v4)/sizeof(csv_rcv_tcp_stat_offset_v4[0]) }
};

static const size_t csv_rcv_lbtrm_stat_offset_v1[] =
{
        offsetof(lbm_rcv_transport_stats_lbtrm_t, msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, bytes_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_pckts_sent),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, naks_sent),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, lost),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, ncfs_ignored),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, ncfs_shed),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, ncfs_rx_delay),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, ncfs_unknown),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_stm_min),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_stm_mean),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_stm_max),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_tx_min),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_tx_mean),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_tx_max),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, duplicate_data),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, unrecovered_txw),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, unrecovered_tmo),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, lbm_msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, lbm_msgs_no_topic_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, lbm_reqs_rcved)
};
#define csv_rcv_lbtrm_stat_offset_v2 csv_rcv_lbtrm_stat_offset_v1
static const size_t csv_rcv_lbtrm_stat_offset_v3[] =
{
        offsetof(lbm_rcv_transport_stats_lbtrm_t, msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, bytes_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_pckts_sent),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, naks_sent),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, lost),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, ncfs_ignored),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, ncfs_shed),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, ncfs_rx_delay),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, ncfs_unknown),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_stm_min),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_stm_mean),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_stm_max),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_tx_min),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_tx_mean),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, nak_tx_max),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, duplicate_data),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, unrecovered_txw),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, unrecovered_tmo),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, lbm_msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, lbm_msgs_no_topic_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, lbm_reqs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, dgrams_dropped_size),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, dgrams_dropped_type),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, dgrams_dropped_version),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, dgrams_dropped_hdr),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, dgrams_dropped_other),
        offsetof(lbm_rcv_transport_stats_lbtrm_t, out_of_order)
};
#define csv_rcv_lbtrm_stat_offset_v4 csv_rcv_lbtrm_stat_offset_v3
static const lbmmon_csv_layout_t csv_rcv_lbtrm_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { csv_rcv_lbtrm_stat_offset_v1, sizeof(csv_rcv_lbtrm_stat_offset_v1)/sizeof(csv_rcv_lbtrm_stat_offset_v1[0]) },
        { csv_rcv_lbtrm_stat_offset_v2, sizeof(csv_rcv_lbtrm_stat_offset_v2)/sizeof(csv_rcv_lbtrm_stat_offset_v2[0]) },
        { csv_rcv_lbtrm_stat_offset_v3, sizeof(csv_rcv_lbtrm_stat_offset_v3)/sizeof(csv_rcv_lbtrm_stat_offset_v3[0]) },
        { csv_rcv_lbtrm_stat_offset_v4, sizeof(csv_rcv_lbtrm_stat_offset_v4)/sizeof(csv_rcv_lbtrm_stat_offset_v4[0]) }
};

static const size_t csv_rcv_lbtru_stat_offset_v1[] =
{
        offsetof(lbm_rcv_transport_stats_lbtru_t, msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtru_t, bytes_rcved),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_pckts_sent),
        offsetof(lbm_rcv_transport_stats_lbtru_t, naks_sent),
        offsetof(lbm_rcv_transport_stats_lbtru_t, lost),
        offsetof(lbm_rcv_transport_stats_lbtru_t, ncfs_ignored),
        offsetof(lbm_rcv_transport_stats_lbtru_t, ncfs_shed),
        offsetof(lbm_rcv_transport_stats_lbtru_t, ncfs_rx_delay),
        offsetof(lbm_rcv_transport_stats_lbtru_t, ncfs_unknown),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_stm_min),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_stm_mean),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_stm_max),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_tx_min),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_tx_mean),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_tx_max),
        offsetof(lbm_rcv_transport_stats_lbtru_t, duplicate_data),
        offsetof(lbm_rcv_transport_stats_lbtru_t, unrecovered_txw),
        offsetof(lbm_rcv_transport_stats_lbtru_t, unrecovered_tmo),
        offsetof(lbm_rcv_transport_stats_lbtru_t, lbm_msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtru_t, lbm_msgs_no_topic_rcved),
        offsetof(lbm_rcv_transport_stats_lbtru_t, lbm_reqs_rcved)
};
#define csv_rcv_lbtru_stat_offset_v2 csv_rcv_lbtru_stat_offset_v1
static const size_t csv_rcv_lbtru_stat_offset_v3[] =
{
        offsetof(lbm_rcv_transport_stats_lbtru_t, msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtru_t, bytes_rcved),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_pckts_sent),
        offsetof(lbm_rcv_transport_stats_lbtru_t, naks_sent),
        offsetof(lbm_rcv_transport_stats_lbtru_t, lost),
        offsetof(lbm_rcv_transport_stats_lbtru_t, ncfs_ignored),
        offsetof(lbm_rcv_transport_stats_lbtru_t, ncfs_shed),
        offsetof(lbm_rcv_transport_stats_lbtru_t, ncfs_rx_delay),
        offsetof(lbm_rcv_transport_stats_lbtru_t, ncfs_unknown),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_stm_min),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_stm_mean),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_stm_max),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_tx_min),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_tx_mean),
        offsetof(lbm_rcv_transport_stats_lbtru_t, nak_tx_max),
        offsetof(lbm_rcv_transport_stats_lbtru_t, duplicate_data),
        offsetof(lbm_rcv_transport_stats_lbtru_t, unrecovered_txw),
        offsetof(lbm_rcv_transport_stats_lbtru_t, unrecovered_tmo),
        offsetof(lbm_rcv_transport_stats_lbtru_t, lbm_msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtru_t, lbm_msgs_no_topic_rcved),
        offsetof(lbm_rcv_transport_stats_lbtru_t, lbm_reqs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtru_t, dgrams_dropped_size),
        offsetof(lbm_rcv_transport_stats_lbtru_t, dgrams_dropped_type),
        offsetof(lbm_rcv_transport_stats_lbtru_t, dgrams_dropped_version),
        offsetof(lbm_rcv_transport_stats_lbtru_t, dgrams_dropped_hdr),
        offsetof(lbm_rcv_transport_stats_lbtru_t, dgrams_dropped_sid),
        offsetof(lbm_rcv_transport_stats_lbtru_t, dgrams_dropped_other)
};
#define csv_rcv_lbtru_stat_offset_v4 csv_rcv_lbtru_stat_offset_v3
static const lbmmon_csv_layout_t csv_rcv_lbtru_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { csv_rcv_lbtru_stat_offset_v1, sizeof(csv_rcv_lbtru_stat_offset_v1)/sizeof(csv_rcv_lbtru_stat_offset_v1[0]) },
        { csv_rcv_lbtru_stat_offset_v2, sizeof(csv_rcv_lbtru_stat_offset_v2)/sizeof(csv_rcv_lbtru_stat_offset_v2[0]) },
        { csv_rcv_lbtru_stat_offset_v3, sizeof(csv_rcv_lbtru_stat_offset_v3)/sizeof(csv_rcv_lbtru_stat_offset_v3[0]) },
        { csv_rcv_lbtru_stat_offset_v4, sizeof(csv_rcv_lbtru_stat_offset_v4)/sizeof(csv_rcv_lbtru_stat_offset_v4[0]) }
};

static const size_t csv_rcv_lbtipc_stat_offset_v2[] =
{
        offsetof(lbm_rcv_transport_stats_lbtipc_t, msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtipc_t, bytes_rcved),
        offsetof(lbm_rcv_transport_stats_lbtipc_t, lbm_msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtipc_t, lbm_msgs_no_topic_rcved),
        offsetof(lbm_rcv_transport_stats_lbtipc_t, lbm_reqs_rcved)
};
#define csv_rcv_lbtipc_stat_offset_v3 csv_rcv_lbtipc_stat_offset_v2
#define csv_rcv_lbtipc_stat_offset_v4 csv_rcv_lbtipc_stat_offset_v3
static const lbmmon_csv_layout_t csv_rcv_lbtipc_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { NULL, 0 },
        { csv_rcv_lbtipc_stat_offset_v2, sizeof(csv_rcv_lbtipc_stat_offset_v2)/sizeof(csv_rcv_lbtipc_stat_offset_v2[0]) },
        { csv_rcv_lbtipc_stat_offset_v3, sizeof(csv_rcv_lbtipc_stat_offset_v3)/sizeof(csv_rcv_lbtipc_stat_offset_v3[0]) },
        { csv_rcv_lbtipc_stat_offset_v4, sizeof(csv_rcv_lbtipc_stat_offset_v4)/sizeof(csv_rcv_lbtipc_stat_offset_v4[0]) }
};

static const size_t csv_rcv_lbtrdma_stat_offset_v2[] =
{
        offsetof(lbm_rcv_transport_stats_lbtrdma_t, msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrdma_t, bytes_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrdma_t, lbm_msgs_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrdma_t, lbm_msgs_no_topic_rcved),
        offsetof(lbm_rcv_transport_stats_lbtrdma_t, lbm_reqs_rcved)
};
#define csv_rcv_lbtrdma_stat_offset_v3 csv_rcv_lbtrdma_stat_offset_v2
#define csv_rcv_lbtrdma_stat_offset_v4 csv_rcv_lbtrdma_stat_offset_v3
static const lbmmon_csv_layout_t csv_rcv_lbtrdma_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { NULL, 0 },
        { csv_rcv_lbtrdma_stat_offset_v2, sizeof(csv_rcv_lbtrdma_stat_offset_v2)/sizeof(csv_rcv_lbtrdma_stat_offset_v2[0]) },
        { csv_rcv_lbtrdma_stat_offset_v3, sizeof(csv_rcv_lbtrdma_stat_offset_v3)/sizeof(csv_rcv_lbtrdma_stat_offset_v3[0]) },
        { csv_rcv_lbtrdma_stat_offset_v4, sizeof(csv_rcv_lbtrdma_stat_offset_v4)/sizeof(csv_rcv_lbtrdma_stat_offset_v4[0]) }
};

int
lbmmon_rcv_format_csv_deserialize(lbm_rcv_transport_stats_t * Statistics,
                                                                  const char * Source,
                                                                  size_t Length,
                                                                  unsigned short ModuleID,
                                                                  void * FormatClientData)
{
        const char * ptr;
        char value[1024];
        lbmmon_format_csv_t * fmt;
        size_t idx;
        unsigned char modid;
        unsigned char modver;
        const size_t * stat_layout = NULL;
        size_t stat_count = 0;

        if ((Statistics == NULL) || (Source == NULL) || (*Source == '\0') || (Length == 0) || (FormatClientData == NULL) )
        {
                strncpy(ErrorString, "Invalid parameter", sizeof(ErrorString));
                return (-1);
        }
        fmt = (lbmmon_format_csv_t *) FormatClientData;
        modid = MODULE_ID(ModuleID);
        modver = MODULE_VERSION(ModuleID);
        if (modid != LBMMON_FORMAT_CSV_MODULE_ID)
        {
                strncpy(ErrorString, "Invalid module ID", sizeof(ErrorString));
                return (-1);
        }

        if (fmt->mBuffer == NULL)
        {
                fmt->mBufferSize = 1024;
                fmt->mBuffer = malloc(fmt->mBufferSize);
        }
        if (Length >= fmt->mBufferSize)
        {
                fmt->mBufferSize = 2 * Length;
                free(fmt->mBuffer);
                fmt->mBuffer = malloc(fmt->mBufferSize);
        }
        memset(fmt->mBuffer, 0, fmt->mBufferSize);
        memcpy(fmt->mBuffer, Source, Length);
        ptr = fmt->mBuffer;
        ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
        if (ptr == NULL)
        {
                strncpy(ErrorString, "No type field found", sizeof(ErrorString));
                return (-1);
        }
        Statistics->type = atoi(value);
        ptr = next_csv_value(ptr, Statistics->source, sizeof(Statistics->source), fmt->mSeparator);
        if (ptr == NULL)
        {
                strncpy(ErrorString, "No source field found", sizeof(ErrorString));
                return (-1);
        }
        switch (Statistics->type)
        {
                case LBM_TRANSPORT_STAT_TCP:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_rcv_tcp_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_rcv_tcp_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_rcv_tcp_stat_layout[modver].layout;
                                stat_count = csv_rcv_tcp_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.tcp), 0, sizeof(lbm_rcv_transport_stats_tcp_t));
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.tcp)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                case LBM_TRANSPORT_STAT_LBTRM:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_rcv_lbtrm_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_rcv_lbtrm_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_rcv_lbtrm_stat_layout[modver].layout;
                                stat_count = csv_rcv_lbtrm_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.lbtrm), 0, sizeof(lbm_rcv_transport_stats_lbtrm_t));
                        
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        /* Due to an ambiguous case with version 3 lbtrm rcv stats,
                                         * older releases of lbm may have 26 fields and newer releases may have 27 fields.
                                         * See bug 5002 for more information.
                                         * For version 3, we will not consider it an error if there are only 26 fields.
                                         */
                                        if(modver == MODULE_VERSION(3) && idx == 26) {
                                                return 0;
                                        }
                                        
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.lbtrm)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                case LBM_TRANSPORT_STAT_LBTRU:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_rcv_lbtru_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_rcv_lbtru_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_rcv_lbtru_stat_layout[modver].layout;
                                stat_count = csv_rcv_lbtru_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.lbtru), 0, sizeof(lbm_rcv_transport_stats_lbtru_t));
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.lbtru)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                case LBM_TRANSPORT_STAT_LBTIPC:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_rcv_lbtipc_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_rcv_lbtipc_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_rcv_lbtipc_stat_layout[modver].layout;
                                stat_count = csv_rcv_lbtipc_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.lbtipc), 0, sizeof(lbm_rcv_transport_stats_lbtipc_t));
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.lbtipc)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                case LBM_TRANSPORT_STAT_LBTRDMA:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_rcv_lbtrdma_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_rcv_lbtrdma_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_rcv_lbtrdma_stat_layout[modver].layout;
                                stat_count = csv_rcv_lbtrdma_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.lbtrdma), 0, sizeof(lbm_rcv_transport_stats_lbtrdma_t));
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.lbtrdma)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                default:
                        strncpy(ErrorString, "Invalid LBM transport type", sizeof(ErrorString));
                        return (-1);
        }
        return (0);
}

static size_t csv_src_tcp_stat_offset_v1[] =
{
        offsetof(lbm_src_transport_stats_tcp_t, num_clients),
        offsetof(lbm_src_transport_stats_tcp_t, bytes_buffered)
};
#define csv_src_tcp_stat_offset_v2 csv_src_tcp_stat_offset_v1
#define csv_src_tcp_stat_offset_v3 csv_src_tcp_stat_offset_v2
#define csv_src_tcp_stat_offset_v4 csv_src_tcp_stat_offset_v3
static const lbmmon_csv_layout_t csv_src_tcp_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { csv_src_tcp_stat_offset_v1, sizeof(csv_src_tcp_stat_offset_v1)/sizeof(csv_src_tcp_stat_offset_v1[0]) },
        { csv_src_tcp_stat_offset_v2, sizeof(csv_src_tcp_stat_offset_v2)/sizeof(csv_src_tcp_stat_offset_v2[0]) },
        { csv_src_tcp_stat_offset_v3, sizeof(csv_src_tcp_stat_offset_v3)/sizeof(csv_src_tcp_stat_offset_v3[0]) },
        { csv_src_tcp_stat_offset_v4, sizeof(csv_src_tcp_stat_offset_v4)/sizeof(csv_src_tcp_stat_offset_v4[0]) }
};

static size_t csv_src_lbtrm_stat_offset_v1[] =
{
        offsetof(lbm_src_transport_stats_lbtrm_t, msgs_sent),
        offsetof(lbm_src_transport_stats_lbtrm_t, bytes_sent),
        offsetof(lbm_src_transport_stats_lbtrm_t, txw_msgs),
        offsetof(lbm_src_transport_stats_lbtrm_t, txw_bytes),
        offsetof(lbm_src_transport_stats_lbtrm_t, nak_pckts_rcved),
        offsetof(lbm_src_transport_stats_lbtrm_t, naks_rcved),
        offsetof(lbm_src_transport_stats_lbtrm_t, naks_ignored),
        offsetof(lbm_src_transport_stats_lbtrm_t, naks_shed),
        offsetof(lbm_src_transport_stats_lbtrm_t, naks_rx_delay_ignored),
        offsetof(lbm_src_transport_stats_lbtrm_t, rxs_sent),
        offsetof(lbm_src_transport_stats_lbtrm_t, rctlr_data_msgs),
        offsetof(lbm_src_transport_stats_lbtrm_t, rctlr_rx_msgs)
};
static size_t csv_src_lbtrm_stat_offset_v2[] =
{
        offsetof(lbm_src_transport_stats_lbtrm_t, msgs_sent),
        offsetof(lbm_src_transport_stats_lbtrm_t, bytes_sent),
        offsetof(lbm_src_transport_stats_lbtrm_t, txw_msgs),
        offsetof(lbm_src_transport_stats_lbtrm_t, txw_bytes),
        offsetof(lbm_src_transport_stats_lbtrm_t, nak_pckts_rcved),
        offsetof(lbm_src_transport_stats_lbtrm_t, naks_rcved),
        offsetof(lbm_src_transport_stats_lbtrm_t, naks_ignored),
        offsetof(lbm_src_transport_stats_lbtrm_t, naks_shed),
        offsetof(lbm_src_transport_stats_lbtrm_t, naks_rx_delay_ignored),
        offsetof(lbm_src_transport_stats_lbtrm_t, rxs_sent),
        offsetof(lbm_src_transport_stats_lbtrm_t, rctlr_data_msgs),
        offsetof(lbm_src_transport_stats_lbtrm_t, rctlr_rx_msgs),
        offsetof(lbm_src_transport_stats_lbtrm_t, rx_bytes_sent)
};
#define csv_src_lbtrm_stat_offset_v3 csv_src_lbtrm_stat_offset_v2
#define csv_src_lbtrm_stat_offset_v4 csv_src_lbtrm_stat_offset_v3
static const lbmmon_csv_layout_t csv_src_lbtrm_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { csv_src_lbtrm_stat_offset_v1, sizeof(csv_src_lbtrm_stat_offset_v1)/sizeof(csv_src_lbtrm_stat_offset_v1[0]) },
        { csv_src_lbtrm_stat_offset_v2, sizeof(csv_src_lbtrm_stat_offset_v2)/sizeof(csv_src_lbtrm_stat_offset_v2[0]) },
        { csv_src_lbtrm_stat_offset_v3, sizeof(csv_src_lbtrm_stat_offset_v3)/sizeof(csv_src_lbtrm_stat_offset_v3[0]) },
        { csv_src_lbtrm_stat_offset_v4, sizeof(csv_src_lbtrm_stat_offset_v4)/sizeof(csv_src_lbtrm_stat_offset_v4[0]) }
};

static size_t csv_src_lbtru_stat_offset_v1[] =
{
        offsetof(lbm_src_transport_stats_lbtru_t, msgs_sent),
        offsetof(lbm_src_transport_stats_lbtru_t, bytes_sent),
        offsetof(lbm_src_transport_stats_lbtru_t, nak_pckts_rcved),
        offsetof(lbm_src_transport_stats_lbtru_t, naks_rcved),
        offsetof(lbm_src_transport_stats_lbtru_t, naks_ignored),
        offsetof(lbm_src_transport_stats_lbtru_t, naks_shed),
        offsetof(lbm_src_transport_stats_lbtru_t, naks_rx_delay_ignored),
        offsetof(lbm_src_transport_stats_lbtru_t, rxs_sent),
        offsetof(lbm_src_transport_stats_lbtru_t, num_clients)
};
static size_t csv_src_lbtru_stat_offset_v2[] =
{
        offsetof(lbm_src_transport_stats_lbtru_t, msgs_sent),
        offsetof(lbm_src_transport_stats_lbtru_t, bytes_sent),
        offsetof(lbm_src_transport_stats_lbtru_t, nak_pckts_rcved),
        offsetof(lbm_src_transport_stats_lbtru_t, naks_rcved),
        offsetof(lbm_src_transport_stats_lbtru_t, naks_ignored),
        offsetof(lbm_src_transport_stats_lbtru_t, naks_shed),
        offsetof(lbm_src_transport_stats_lbtru_t, naks_rx_delay_ignored),
        offsetof(lbm_src_transport_stats_lbtru_t, rxs_sent),
        offsetof(lbm_src_transport_stats_lbtru_t, num_clients),
        offsetof(lbm_src_transport_stats_lbtru_t, rx_bytes_sent)
};
#define csv_src_lbtru_stat_offset_v3 csv_src_lbtru_stat_offset_v2
#define csv_src_lbtru_stat_offset_v4 csv_src_lbtru_stat_offset_v3
static const lbmmon_csv_layout_t csv_src_lbtru_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { csv_src_lbtru_stat_offset_v1, sizeof(csv_src_lbtru_stat_offset_v1)/sizeof(csv_src_lbtru_stat_offset_v1[0]) },
        { csv_src_lbtru_stat_offset_v2, sizeof(csv_src_lbtru_stat_offset_v2)/sizeof(csv_src_lbtru_stat_offset_v2[0]) },
        { csv_src_lbtru_stat_offset_v3, sizeof(csv_src_lbtru_stat_offset_v3)/sizeof(csv_src_lbtru_stat_offset_v3[0]) },
        { csv_src_lbtru_stat_offset_v4, sizeof(csv_src_lbtru_stat_offset_v4)/sizeof(csv_src_lbtru_stat_offset_v4[0]) }
};

static size_t csv_src_lbtipc_stat_offset_v2[] =
{
        offsetof(lbm_src_transport_stats_lbtipc_t, num_clients),
        offsetof(lbm_src_transport_stats_lbtipc_t, msgs_sent),
        offsetof(lbm_src_transport_stats_lbtipc_t, bytes_sent)
};
#define csv_src_lbtipc_stat_offset_v3 csv_src_lbtipc_stat_offset_v2
#define csv_src_lbtipc_stat_offset_v4 csv_src_lbtipc_stat_offset_v3
static const lbmmon_csv_layout_t csv_src_lbtipc_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { NULL, 0 },
        { csv_src_lbtipc_stat_offset_v2, sizeof(csv_src_lbtipc_stat_offset_v2)/sizeof(csv_src_lbtipc_stat_offset_v2[0]) },
        { csv_src_lbtipc_stat_offset_v3, sizeof(csv_src_lbtipc_stat_offset_v3)/sizeof(csv_src_lbtipc_stat_offset_v3[0]) },
        { csv_src_lbtipc_stat_offset_v4, sizeof(csv_src_lbtipc_stat_offset_v4)/sizeof(csv_src_lbtipc_stat_offset_v4[0]) }
};

static size_t csv_src_lbtrdma_stat_offset_v2[] =
{
        offsetof(lbm_src_transport_stats_lbtrdma_t, num_clients),
        offsetof(lbm_src_transport_stats_lbtrdma_t, msgs_sent),
        offsetof(lbm_src_transport_stats_lbtrdma_t, bytes_sent)
};
#define csv_src_lbtrdma_stat_offset_v3 csv_src_lbtrdma_stat_offset_v2
#define csv_src_lbtrdma_stat_offset_v4 csv_src_lbtrdma_stat_offset_v3
static const lbmmon_csv_layout_t csv_src_lbtrdma_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { NULL, 0 },
        { csv_src_lbtrdma_stat_offset_v2, sizeof(csv_src_lbtrdma_stat_offset_v2)/sizeof(csv_src_lbtrdma_stat_offset_v2[0]) },
        { csv_src_lbtrdma_stat_offset_v3, sizeof(csv_src_lbtrdma_stat_offset_v3)/sizeof(csv_src_lbtrdma_stat_offset_v3[0]) },
        { csv_src_lbtrdma_stat_offset_v4, sizeof(csv_src_lbtrdma_stat_offset_v4)/sizeof(csv_src_lbtrdma_stat_offset_v4[0]) }
};

int
lbmmon_src_format_csv_deserialize(lbm_src_transport_stats_t * Statistics,
                                                                  const char * Source,
                                                                  size_t Length,
                                                                  unsigned short ModuleID,
                                                                  void * FormatClientData)
{
        const char * ptr;
        char value[1024];
        lbmmon_format_csv_t * fmt;
        size_t idx;
        unsigned char modid;
        unsigned char modver;
        const size_t * stat_layout = NULL;
        size_t stat_count = 0;

        if ((Statistics == NULL) || (Source == NULL) || (*Source == '\0') || (Length == 0) || (FormatClientData == NULL) )
        {
                strncpy(ErrorString, "Invalid parameter", sizeof(ErrorString));
                return (-1);
        }
        fmt = (lbmmon_format_csv_t *) FormatClientData;

        modid = MODULE_ID(ModuleID);
        modver = MODULE_VERSION(ModuleID);
        if (modid != LBMMON_FORMAT_CSV_MODULE_ID)
        {
                strncpy(ErrorString, "Invalid module ID", sizeof(ErrorString));
                return (-1);
        }

        if (fmt->mBuffer == NULL)
        {
                fmt->mBufferSize = 1024;
                fmt->mBuffer = malloc(fmt->mBufferSize);
        }
        if (Length >= fmt->mBufferSize)
        {
                fmt->mBufferSize = 2 * Length;
                free(fmt->mBuffer);
                fmt->mBuffer = malloc(fmt->mBufferSize);
        }
        memset(fmt->mBuffer, 0, fmt->mBufferSize);
        memcpy(fmt->mBuffer, Source, Length);
        ptr = fmt->mBuffer;
        ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
        if (ptr == NULL)
        {
                strncpy(ErrorString, "No type field found", sizeof(ErrorString));
                return (-1);
        }
        Statistics->type = atoi(value);
        ptr = next_csv_value(ptr, Statistics->source, sizeof(Statistics->source), fmt->mSeparator);
        if (ptr == NULL)
        {
                strncpy(ErrorString, "No source field found", sizeof(ErrorString));
                return (-1);
        }
        switch (Statistics->type)
        {
                case LBM_TRANSPORT_STAT_TCP:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_src_tcp_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_src_tcp_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_src_tcp_stat_layout[modver].layout;
                                stat_count = csv_src_tcp_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.tcp), 0, sizeof(lbm_src_transport_stats_tcp_t));
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.tcp)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                case LBM_TRANSPORT_STAT_LBTRM:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_src_lbtrm_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_src_lbtrm_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_src_lbtrm_stat_layout[modver].layout;
                                stat_count = csv_src_lbtrm_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.lbtrm), 0, sizeof(lbm_src_transport_stats_lbtrm_t));
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.lbtrm)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                case LBM_TRANSPORT_STAT_LBTRU:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_src_lbtru_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_src_lbtru_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_src_lbtru_stat_layout[modver].layout;
                                stat_count = csv_src_lbtru_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.lbtru), 0, sizeof(lbm_src_transport_stats_lbtru_t));
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.lbtru)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                case LBM_TRANSPORT_STAT_LBTIPC:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_src_lbtipc_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_src_lbtipc_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_src_lbtipc_stat_layout[modver].layout;
                                stat_count = csv_src_lbtipc_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.lbtipc), 0, sizeof(lbm_src_transport_stats_lbtipc_t));
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.lbtipc)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                case LBM_TRANSPORT_STAT_LBTRDMA:
                        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
                        {
                                stat_layout = csv_src_lbtrdma_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                                stat_count = csv_src_lbtrdma_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
                        }
                        else
                        {
                                stat_layout = csv_src_lbtrdma_stat_layout[modver].layout;
                                stat_count = csv_src_lbtrdma_stat_layout[modver].count;
                        }
                        memset((void *) &(Statistics->transport.lbtrdma), 0, sizeof(lbm_src_transport_stats_lbtrdma_t));
                        for (idx = 0; idx < stat_count; ++idx)
                        {
                                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                                if (ptr == NULL)
                                {
                                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                                        return (-1);
                                }
                                *((lbm_ulong_t *)(((unsigned char *)&(Statistics->transport.lbtrdma)) + stat_layout[idx])) = convert_value(value);
                        }
                        break;

                default:
                        strncpy(ErrorString, "Invalid LBM transport type", sizeof(ErrorString));
                        return (-1);
        }
        return (0);
}

static size_t csv_evq_stat_offset_v2[] =
{
        offsetof(lbm_event_queue_stats_t, data_msgs),
        offsetof(lbm_event_queue_stats_t, data_msgs_tot),
        offsetof(lbm_event_queue_stats_t, data_msgs_svc_min),
        offsetof(lbm_event_queue_stats_t, data_msgs_svc_mean),
        offsetof(lbm_event_queue_stats_t, data_msgs_svc_max),
        offsetof(lbm_event_queue_stats_t, resp_msgs),
        offsetof(lbm_event_queue_stats_t, resp_msgs_tot),
        offsetof(lbm_event_queue_stats_t, resp_msgs_svc_min),
        offsetof(lbm_event_queue_stats_t, resp_msgs_svc_mean),
        offsetof(lbm_event_queue_stats_t, resp_msgs_svc_max),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs_tot),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs_svc_min),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs_svc_mean),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs_svc_max),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs_tot),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs_svc_min),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs_svc_mean),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs_svc_max),
        offsetof(lbm_event_queue_stats_t, io_events),
        offsetof(lbm_event_queue_stats_t, io_events_tot),
        offsetof(lbm_event_queue_stats_t, io_events_svc_min),
        offsetof(lbm_event_queue_stats_t, io_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, io_events_svc_max),
        offsetof(lbm_event_queue_stats_t, timer_events),
        offsetof(lbm_event_queue_stats_t, timer_events_tot),
        offsetof(lbm_event_queue_stats_t, timer_events_svc_min),
        offsetof(lbm_event_queue_stats_t, timer_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, timer_events_svc_max),
        offsetof(lbm_event_queue_stats_t, source_events),
        offsetof(lbm_event_queue_stats_t, source_events_tot),
        offsetof(lbm_event_queue_stats_t, source_events_svc_min),
        offsetof(lbm_event_queue_stats_t, source_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, source_events_svc_max),
        offsetof(lbm_event_queue_stats_t, unblock_events),
        offsetof(lbm_event_queue_stats_t, unblock_events_tot),
        offsetof(lbm_event_queue_stats_t, cancel_events),
        offsetof(lbm_event_queue_stats_t, cancel_events_tot),
        offsetof(lbm_event_queue_stats_t, cancel_events_svc_min),
        offsetof(lbm_event_queue_stats_t, cancel_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, cancel_events_svc_max),
        offsetof(lbm_event_queue_stats_t, context_source_events),
        offsetof(lbm_event_queue_stats_t, context_source_events_tot),
        offsetof(lbm_event_queue_stats_t, context_source_events_svc_min),
        offsetof(lbm_event_queue_stats_t, context_source_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, context_source_events_svc_max),
        offsetof(lbm_event_queue_stats_t, events),
        offsetof(lbm_event_queue_stats_t, events_tot),
        offsetof(lbm_event_queue_stats_t, age_min),
        offsetof(lbm_event_queue_stats_t, age_mean),
        offsetof(lbm_event_queue_stats_t, age_max)
};
static size_t csv_evq_stat_offset_v3[] =
{
        offsetof(lbm_event_queue_stats_t, data_msgs),
        offsetof(lbm_event_queue_stats_t, data_msgs_tot),
        offsetof(lbm_event_queue_stats_t, data_msgs_svc_min),
        offsetof(lbm_event_queue_stats_t, data_msgs_svc_mean),
        offsetof(lbm_event_queue_stats_t, data_msgs_svc_max),
        offsetof(lbm_event_queue_stats_t, resp_msgs),
        offsetof(lbm_event_queue_stats_t, resp_msgs_tot),
        offsetof(lbm_event_queue_stats_t, resp_msgs_svc_min),
        offsetof(lbm_event_queue_stats_t, resp_msgs_svc_mean),
        offsetof(lbm_event_queue_stats_t, resp_msgs_svc_max),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs_tot),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs_svc_min),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs_svc_mean),
        offsetof(lbm_event_queue_stats_t, topicless_im_msgs_svc_max),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs_tot),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs_svc_min),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs_svc_mean),
        offsetof(lbm_event_queue_stats_t, wrcv_msgs_svc_max),
        offsetof(lbm_event_queue_stats_t, io_events),
        offsetof(lbm_event_queue_stats_t, io_events_tot),
        offsetof(lbm_event_queue_stats_t, io_events_svc_min),
        offsetof(lbm_event_queue_stats_t, io_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, io_events_svc_max),
        offsetof(lbm_event_queue_stats_t, timer_events),
        offsetof(lbm_event_queue_stats_t, timer_events_tot),
        offsetof(lbm_event_queue_stats_t, timer_events_svc_min),
        offsetof(lbm_event_queue_stats_t, timer_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, timer_events_svc_max),
        offsetof(lbm_event_queue_stats_t, source_events),
        offsetof(lbm_event_queue_stats_t, source_events_tot),
        offsetof(lbm_event_queue_stats_t, source_events_svc_min),
        offsetof(lbm_event_queue_stats_t, source_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, source_events_svc_max),
        offsetof(lbm_event_queue_stats_t, unblock_events),
        offsetof(lbm_event_queue_stats_t, unblock_events_tot),
        offsetof(lbm_event_queue_stats_t, cancel_events),
        offsetof(lbm_event_queue_stats_t, cancel_events_tot),
        offsetof(lbm_event_queue_stats_t, cancel_events_svc_min),
        offsetof(lbm_event_queue_stats_t, cancel_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, cancel_events_svc_max),
        offsetof(lbm_event_queue_stats_t, context_source_events),
        offsetof(lbm_event_queue_stats_t, context_source_events_tot),
        offsetof(lbm_event_queue_stats_t, context_source_events_svc_min),
        offsetof(lbm_event_queue_stats_t, context_source_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, context_source_events_svc_max),
        offsetof(lbm_event_queue_stats_t, events),
        offsetof(lbm_event_queue_stats_t, events_tot),
        offsetof(lbm_event_queue_stats_t, age_min),
        offsetof(lbm_event_queue_stats_t, age_mean),
        offsetof(lbm_event_queue_stats_t, age_max),
        offsetof(lbm_event_queue_stats_t, callback_events),
        offsetof(lbm_event_queue_stats_t, callback_events_tot),
        offsetof(lbm_event_queue_stats_t, callback_events_svc_min),
        offsetof(lbm_event_queue_stats_t, callback_events_svc_mean),
        offsetof(lbm_event_queue_stats_t, callback_events_svc_max)
};
#define csv_evq_stat_offset_v4 csv_evq_stat_offset_v3
static const lbmmon_csv_layout_t csv_evq_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { NULL, 0 },
        { csv_evq_stat_offset_v2, sizeof(csv_evq_stat_offset_v2)/sizeof(csv_evq_stat_offset_v2[0]) },
        { csv_evq_stat_offset_v3, sizeof(csv_evq_stat_offset_v3)/sizeof(csv_evq_stat_offset_v3[0]) },
        { csv_evq_stat_offset_v4, sizeof(csv_evq_stat_offset_v4)/sizeof(csv_evq_stat_offset_v4[0]) }
};

int
lbmmon_evq_format_csv_deserialize(lbm_event_queue_stats_t * Statistics,
                                                                  const char * Source,
                                                                  size_t Length,
                                                                  unsigned short ModuleID,
                                                                  void * FormatClientData)
{
        const char * ptr;
        char value[1024];
        lbmmon_format_csv_t * fmt;
        size_t idx;
        unsigned char modid;
        unsigned char modver;
        const size_t * stat_layout = NULL;
        size_t stat_count = 0;

        if ((Statistics == NULL) || (Source == NULL) || (*Source == '\0') || (Length == 0) || (FormatClientData == NULL) )
        {
                strncpy(ErrorString, "Invalid parameter", sizeof(ErrorString));
                return (-1);
        }
        fmt = (lbmmon_format_csv_t *) FormatClientData;

        modid = MODULE_ID(ModuleID);
        modver = MODULE_VERSION(ModuleID);
        if (modid != LBMMON_FORMAT_CSV_MODULE_ID)
        {
                strncpy(ErrorString, "Invalid module ID", sizeof(ErrorString));
                return (-1);
        }

        if (fmt->mBuffer == NULL)
        {
                fmt->mBufferSize = 1024;
                fmt->mBuffer = malloc(fmt->mBufferSize);
        }
        if (Length >= fmt->mBufferSize)
        {
                fmt->mBufferSize = 2 * Length;
                free(fmt->mBuffer);
                fmt->mBuffer = malloc(fmt->mBufferSize);
        }
        memset(fmt->mBuffer, 0, fmt->mBufferSize);
        memcpy(fmt->mBuffer, Source, Length);
        ptr = fmt->mBuffer;
        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
        {
                stat_layout = csv_evq_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                stat_count = csv_evq_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
        }
        else
        {
                stat_layout = csv_evq_stat_layout[modver].layout;
                stat_count = csv_evq_stat_layout[modver].count;
        }
        memset((void *) Statistics, 0, sizeof(lbm_event_queue_stats_t));
        for (idx = 0; idx < stat_count; ++idx)
        {
                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                if (ptr == NULL)
                {
                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                        return (-1);
                }
                *((lbm_ulong_t *)(((unsigned char *) Statistics) + stat_layout[idx])) = convert_value(value);
        }
        return (0);
}

static size_t csv_ctx_stat_offset_v2[] =
{
        offsetof(lbm_context_stats_t, tr_dgrams_sent),
        offsetof(lbm_context_stats_t, tr_bytes_sent),
        offsetof(lbm_context_stats_t, tr_dgrams_rcved),
        offsetof(lbm_context_stats_t, tr_bytes_rcved),
        offsetof(lbm_context_stats_t, tr_dgrams_dropped_ver),
        offsetof(lbm_context_stats_t, tr_dgrams_dropped_type),
        offsetof(lbm_context_stats_t, tr_dgrams_dropped_malformed),
        offsetof(lbm_context_stats_t, tr_dgrams_send_failed),
        offsetof(lbm_context_stats_t, tr_src_topics),
        offsetof(lbm_context_stats_t, tr_rcv_topics),
        offsetof(lbm_context_stats_t, tr_rcv_unresolved_topics),
        offsetof(lbm_context_stats_t, lbtrm_unknown_msgs_rcved),
        offsetof(lbm_context_stats_t, lbtru_unknown_msgs_rcved),
        offsetof(lbm_context_stats_t, send_blocked),
        offsetof(lbm_context_stats_t, send_would_block),
        offsetof(lbm_context_stats_t, resp_blocked),
        offsetof(lbm_context_stats_t, resp_would_block)
};
#define csv_ctx_stat_offset_v3 csv_ctx_stat_offset_v2
static size_t csv_ctx_stat_offset_v4[] =
{
        offsetof(lbm_context_stats_t, tr_dgrams_sent),
        offsetof(lbm_context_stats_t, tr_bytes_sent),
        offsetof(lbm_context_stats_t, tr_dgrams_rcved),
        offsetof(lbm_context_stats_t, tr_bytes_rcved),
        offsetof(lbm_context_stats_t, tr_dgrams_dropped_ver),
        offsetof(lbm_context_stats_t, tr_dgrams_dropped_type),
        offsetof(lbm_context_stats_t, tr_dgrams_dropped_malformed),
        offsetof(lbm_context_stats_t, tr_dgrams_send_failed),
        offsetof(lbm_context_stats_t, tr_src_topics),
        offsetof(lbm_context_stats_t, tr_rcv_topics),
        offsetof(lbm_context_stats_t, tr_rcv_unresolved_topics),
        offsetof(lbm_context_stats_t, lbtrm_unknown_msgs_rcved),
        offsetof(lbm_context_stats_t, lbtru_unknown_msgs_rcved),
        offsetof(lbm_context_stats_t, send_blocked),
        offsetof(lbm_context_stats_t, send_would_block),
        offsetof(lbm_context_stats_t, resp_blocked),
        offsetof(lbm_context_stats_t, resp_would_block),
        offsetof(lbm_context_stats_t, uim_dup_msgs_rcved),
        offsetof(lbm_context_stats_t, uim_msgs_no_stream_rcved)
};
static const lbmmon_csv_layout_t csv_ctx_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT+1] =
{
        { NULL, 0 },
        { NULL, 0 },
        { csv_ctx_stat_offset_v2, sizeof(csv_ctx_stat_offset_v2)/sizeof(csv_ctx_stat_offset_v2[0]) },
        { csv_ctx_stat_offset_v3, sizeof(csv_ctx_stat_offset_v3)/sizeof(csv_ctx_stat_offset_v3[0]) },
        { csv_ctx_stat_offset_v4, sizeof(csv_ctx_stat_offset_v4)/sizeof(csv_ctx_stat_offset_v4[0]) }
};

int
lbmmon_ctx_format_csv_deserialize(lbm_context_stats_t * Statistics,
                                                                  const char * Source,
                                                                  size_t Length,
                                                                  unsigned short ModuleID,
                                                                  void * FormatClientData)
{
        const char * ptr;
        char value[1024];
        lbmmon_format_csv_t * fmt;
        size_t idx;
        unsigned char modid;
        unsigned char modver;
        const size_t * stat_layout = NULL;
        size_t stat_count = 0;

        if ((Statistics == NULL) || (Source == NULL) || (*Source == '\0') || (Length == 0) || (FormatClientData == NULL) )
        {
                strncpy(ErrorString, "Invalid parameter", sizeof(ErrorString));
                return (-1);
        }
        fmt = (lbmmon_format_csv_t *) FormatClientData;

        modid = MODULE_ID(ModuleID);
        modver = MODULE_VERSION(ModuleID);
        if (modid != LBMMON_FORMAT_CSV_MODULE_ID)
        {
                strncpy(ErrorString, "Invalid module ID", sizeof(ErrorString));
                return (-1);
        }

        if (fmt->mBuffer == NULL)
        {
                fmt->mBufferSize = 1024;
                fmt->mBuffer = malloc(fmt->mBufferSize);
        }
        if (Length >= fmt->mBufferSize)
        {
                fmt->mBufferSize = 2 * Length;
                free(fmt->mBuffer);
                fmt->mBuffer = malloc(fmt->mBufferSize);
        }
        memset(fmt->mBuffer, 0, fmt->mBufferSize);
        memcpy(fmt->mBuffer, Source, Length);
        ptr = fmt->mBuffer;
        if (modver >= LBMMON_FORMAT_CSV_VERSION_CURRENT)
        {
                stat_layout = csv_ctx_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].layout;
                stat_count = csv_ctx_stat_layout[LBMMON_FORMAT_CSV_VERSION_CURRENT].count;
        }
        else
        {
                stat_layout = csv_ctx_stat_layout[modver].layout;
                stat_count = csv_ctx_stat_layout[modver].count;
        }
        memset((void *) Statistics, 0, sizeof(lbm_context_stats_t));
        for (idx = 0; idx < stat_count; ++idx)
        {
                ptr = next_csv_value(ptr, value, sizeof(value), fmt->mSeparator);
                if (ptr == NULL)
                {
                        strncpy(ErrorString, "Data contains too few fields", sizeof(ErrorString));
                        return (-1);
                }
                *((lbm_ulong_t *)(((unsigned char *) Statistics) + stat_layout[idx])) = convert_value(value);
        }
        return (0);
}

int
lbmmon_format_csv_finish(void * FormatClientData)
{
        if (FormatClientData != NULL)
        {
                lbmmon_format_csv_t * data = (lbmmon_format_csv_t *) FormatClientData;
                if (data->mBuffer != NULL)
                {
                        free(data->mBuffer);
                        data->mBuffer = NULL;
                }
                free(data);
        }
        return (0);
}

const char *
lbmmon_format_csv_errmsg(void)
{
        return (ErrorString);
}


Generated on Thu Mar 6 13:11:15 2014 for LBM API by  doxygen 1.5.2