summaryrefslogtreecommitdiffstats
path: root/collection/elapi_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'collection/elapi_util.c')
-rw-r--r--collection/elapi_util.c411
1 files changed, 411 insertions, 0 deletions
diff --git a/collection/elapi_util.c b/collection/elapi_util.c
index e275703..b5fbf59 100644
--- a/collection/elapi_util.c
+++ b/collection/elapi_util.c
@@ -26,6 +26,23 @@
#include "elapi_debug.h"
#include "elapi_util.h"
+
+/* Internal defines used in different places */
+#define UNKNOWN "<unknown:>"
+#define UNKNOWN_LEN sizeof(UNKNOWN)-1
+#define BAD_FORMAT "<bad format>"
+#define BAD_FORMAT_LEN sizeof(BAD_FORMAT)-1
+
+#define FMT_STRING 0
+#define FMT_INTEGER 1
+#define FMT_UNSIGNED 2
+#define FMT_LONG 3
+#define FMT_ULONG 4
+#define FMT_DOUBLE 5
+
+#define TIMESTAMP "(" TS_NAME ")"
+#define TIMESTAMP_LEN sizeof(TS_NAME) + 1
+
/* Return a static string based on type of the element */
const char *get_type(int type)
{
@@ -515,3 +532,397 @@ int xml_add(char *property,
return EOK;
}
+
+
+/* Extracet and lookup item */
+static int extract_item(char *start,
+ struct collection_item *event,
+ struct collection_item **item,
+ int *index)
+{
+ char *end;
+
+ DEBUG_STRING("extract_item","Entry point");
+
+ start++;
+ end = start;
+ while((*end != ')') && (*end != '\0')) end++;
+
+ if(*end == '\0') return EINVAL;
+
+ *end = '\0';
+ error = get_item(event,start,ELAPI_TYPE_ANY,
+ ELAPI_TRAVERSE_DEFAULT,item);
+ *end = ')';
+ *index += (end-start)+1;
+
+ DEBUG_STRING("extract_item","Exit point");
+ return error;
+}
+
+
+/* Function to serialize one item using provided format if any */
+int sprintf_item(struct serial_data *data,
+ struct collection_item *item,
+ char *one_format)
+{
+ int len;
+ int length;
+ int error = EOK;
+ int i;
+ int len_format = 0;
+ char *formats[] = {"\"%s\"","%d","%u","%ld","%lu","%.4f"};
+ char *fmt;
+ int block;
+ char *start;
+
+ DEBUG_STRING("sprintf_item","Entry point");
+
+ DEBUG_NUMBER("Buffer len: ", data->length);
+ DEBUG_NUMBER("Buffer size: ", data->size);
+ DEBUG_STRING("Buffer: ", data->buffer);
+
+
+ if(one_format!=NULL) len_format = strlen(one_format);
+
+ /* Handle special binary case - ignore format for it */
+ if(item->type == ELAPI_TYPE_BINARY) {
+ /* Bake sure we have enough memory */
+ if((error=grow_buffer(data,item->length * 2 + 2))) return error;
+ /* Put opening quote */
+ *(data->buffer+data->length) = '\'';
+ data->length++;
+ for(i=0;i<item->length;i++) sprintf(data->buffer+data->length+i*2,"%02X",*((unsigned char *)(item->data+i)));
+ data->length+=item->length*2;
+ *(buf_data->buffer+buf_data->length) = '\'';
+ buf_data->length++
+ *(buf_data->buffer+buf_data->length) = '\0';
+ }
+ else {
+
+ /* For other types use a version of sprintf, but determine format first */
+ switch(item->type) {
+ case ELAPI_TYPE_STRING: if((len_format > 0) && (*(one_format+len_format-1) == 's') fmt=one_format;
+ else fmt = formats[FMT_STRING];
+ break;
+ case ELAPI_TYPE_INTEGER: if((len_format > 0) && (*(one_format+len_format-1) != 's')) fmt=one_format;
+ else fmt = formats[FMT_INTEGER];
+ break;
+ case ELAPI_TYPE_UNSIGNED: if((len_format > 0) && (*(one_format+len_format-1) != 's')) fmt=one_format;
+ else fmt = formats[FMT_UNSIGNED];
+ break;
+ case ELAPI_TYPE_LONG: if((len_format > 0) && (*(one_format+len_format-1) != 's')) fmt=one_format;
+ else fmt = formats[FMT_LONG];
+ break;
+ case ELAPI_TYPE_ULONG: if((len_format > 0) && (*(one_format+len_format-1) != 's')) fmt=one_format;
+ else fmt = formats[FMT_ULONG];
+ break;
+ case ELAPI_TYPE_DOUBLE: if((len_format > 0) &&
+ (*(one_format+len_format-1) != 's') &&
+ (*(one_format+len_format-1) != 'c')) fmt=one_format;
+ else fmt = formats[FMT_INTEGER];
+ break;
+ default:
+ /* In case we do not know the type */
+ error = put_marker(data,UNKNOWN,UNKNOWN_LEN);
+ if(error) {
+ DEBUG_NUMBER("put_marker returned error:",error);
+ return error;
+ }
+ error = put_marker(data,item->property,item->property_len);
+ if(error) {
+ DEBUG_NUMBER("put_marker returned error:",error);
+ return error;
+ }
+ DEBUG_STRING("sprintf_item","Unknown item exit point");
+ return EOK;
+ }
+
+ start = buf_data->buffer+buf_data->length;
+ block = buf_data->size-buf_data->length-1;
+
+ while (1) {
+ switch(item->type) {
+ case ELAPI_TYPE_STRING: len = snprintf(start,block,
+ fmt, (char *)(item->data));
+ break;
+ case ELAPI_TYPE_INTEGER: len = snprintf(start,block,
+ fmt, *((int *)(item->data)));
+ break;
+ case ELAPI_TYPE_UNSIGNED: len = snprintf(start,block,
+ fmt, *((unsigned *)(item->data)));
+ break;
+ case ELAPI_TYPE_LONG: len = snprintf(start,block,
+ fmt, *((long *)(item->data)));
+ break;
+ case ELAPI_TYPE_ULONG: len = snprintf(start,block,
+ fmt, *((unsigned long *)(item->data)));
+ break;
+ case ELAPI_TYPE_DOUBLE: len = snprintf(start,block,
+ fmt, *((double *)(item->data)));
+ break;
+ default: /* Not possible */
+ DEBUG_STRING("sprintf_item","Unknown item exit point 2.");
+ return EOK;
+ }
+
+ /* Did it fit? */
+ if (len > -1 && len < block) break;
+
+ /* Else try again with more space. Based on printf example. */
+ if (len > -1) block = MAX(n+1,BLOCK_SIZE);
+ else block = MAX(block *2,BLOCK_SIZE);
+
+ if((error=grow_buffer(data,block))) return error;
+ }
+
+ /* Adjust length */
+ buf_data->length+=len;
+ *(buf_data->buffer+buf_data->length) = '\0';
+ }
+ DEBUG_STRING("Data: ",buf_data->buffer);
+ DEBUG_STRING("sprintf_item","Exit point");
+ return EOK;
+
+}
+
+
+/* If time is missing add it */
+static int add_time(struct serial_data *data,
+ struct collection_item *event)
+{
+ struct collection_item *timestamp;
+
+ DEBUG_STRING("add_time","Entry point");
+
+ error = set_timestamp(event,&timestamp,NULL);
+ if(error) {
+ DEBUG_NUMBER("set_timestamp returned error:",error);
+ return error;
+ }
+
+ error = put_marker(data,timestamp->data,timestamp->length-1);
+ if(error) {
+ DEBUG_NUMBER("put_marker returned error:",error);
+ return error;
+ }
+
+ DEBUG_STRING("add_time","Exit point");
+}
+
+
+/* Internal function to parse out item and put the item data based on the lookup */
+static int process_item(struct serial_data *data,
+ char *format_str,
+ int *index,
+ struct collection_item *event,
+ char *one_format,
+ int *brk)
+{
+ char *start;
+ char *end;
+ int block;
+ struct collection_item *item = (struct collection_item *)(NULL);
+
+ DEBUG_STRING("process_item","Entry point");
+
+ start = format_str + *index;
+ error = extract_item(start,event,&item,index);
+ if(error) {
+ /* This is a problem with format not with memory */
+ error = put_marker(data,BAD_FORMAT,BAD_FORMAT_LEN);
+ if(error) {
+ DEBUG_NUMBER("put_marker bad format returned error:",error);
+ return error;
+ }
+ /* Bad format - we are done */
+ *brk = 1;
+ }
+ else {
+ /* Check if item exists */
+ if(item == (struct collection_item *)(NULL)) {
+
+ if(strncmp(start,TIMESTAMP,TIMESTAMP_LEN) == 0) {
+ DEBUG_STRING("process_item","Adding time");
+ /* Add a timestamp automatically */
+ error = add_time(data,event);
+
+ }
+ else {
+ /* We will put placeholder instead */
+ error = put_marker(data,UNKNOWN,UNKNOWN_LEN);
+ if(error) {
+ DEBUG_NUMBER("put_marker returned error:",error);
+ return error;
+ }
+
+ /* Then put the piece we could not find */
+ error = put_marker(data,start+1,*index-(start-format_str)-2);
+ }
+ if(error) {
+ DEBUG_NUMBER("put_marker/add_time returned error:",error);
+ return error;
+ }
+ (*index)++;
+ DEBUG_STRING("Format after processing not found item:",format_str+*index);
+ }
+ else {
+ /* Item found - call sprintf_item using native format ! */
+ error = sprintf_item(data,item,one_format);
+ if(error) {
+ DEBUG_NUMBER("sprintf_item returned error:",error);
+ return error;
+ }
+ (*index)++;
+ DEBUG_STRING("Format after processing item:",format_str+*index);
+ }
+ }
+ DEBUG_STRING("process_item","Exit");
+ return EOK;
+}
+
+#define CHECK_VALID(x) ((x == 'd')||(x == 'i')||(x == 'o')||(x == 'u')||\
+ (x == 'x')||(x == 'X')||(x == 'c')||(x == 's')||\
+ (x == 'e')||(x == 'E')||(x == 'g')||(x == 'G')||\
+ (x == 'f')||(x == 'F')||(x == 'a')||(x == 'A'))
+
+
+/* Serialize using format */
+int serialize_with_format(struct collection_item *event,
+ char *format_str,
+ struct serial_data *data)
+{
+
+ int i=0;
+ char *one_format;
+ int brk;
+
+ DEBUG_STRING("serialize_with_format","Entry point");
+
+
+ /* Allocate output buffer */
+ errno = 0;
+ data->buffer = malloc(BLOCK_SIZE);
+ if(data->buffer == NULL) {
+ DEBUG_NUMBER("Out of memory",errno);
+ return ENOMEM;
+ }
+ data->size = BLOCK_SIZE;
+ data->length = 0;
+
+ /* Create buffer for format specifier */
+ errno = 0;
+ one_format = malloc(len+1);
+ if(one_format == NULL) {
+ DEBUG_NUMBER("Out of memory",errno);
+ free(data->buffer);
+ data->buffer=NULL;
+ return ENOMEM;
+ }
+
+ while(1) {
+ /* Copy characters directly into output */
+ start = format_str+i;
+ end = start;
+ block = 0;
+ while((*end != '%') && (*end != '\0')) end++;
+ if(end > start) {
+ /* We have a block to copy to output buffer */
+ block = end-start;
+ error = put_marker(data,start,block);
+ if(error) {
+ DEBUG_NUMBER("put_marker returned error:",error);
+ free(data->buffer);
+ data->buffer=NULL;
+ free(one_format);
+ return ENOMEM;
+ }
+ }
+ /* Check if we are done */
+ if(*end == '\0') break;
+
+ /* We are not done - we have %*/
+ i+=block+1;
+
+ /* Here we are at the beginning of the string after % */
+ DEBUG_STRING("Format after %:",format_str+i);
+
+ /* Handle special case */
+ if(*(format_str+i) == '%') {
+ error = put_marker(data,"%",1);
+ if(error) {
+ DEBUG_NUMBER("put_marker returned error:",error);
+ free(data->buffer);
+ data->buffer=NULL;
+ free(one_format);
+ return error;
+ }
+ i++;
+ DEBUG_STRING("Format after processing %%:",format_str+i);
+ continue;
+ }
+
+ /* We are here in case there is a real format token */
+ if(*(format_str+i) == '(') {
+ /* This is our special case when we have a event item specifier () */
+ brk = 0;
+ error = process_item(data,format_str,&i,event,NULL,&brk);
+ if(error) {
+ DEBUG_NUMBER("put_marker bad format returned error:",error);
+ free(data->buffer);
+ data->buffer=NULL;
+ free(one_format);
+ return error;
+ }
+ if(brk) break;
+ continue;
+ }
+
+ /* There is a format specifier ! */
+ start = format_str+i;
+ end = start;
+ block = 0;
+ while((*end != '(') && (*end != '\0')) end++;
+
+ /* Check why we stopped */
+ if((*end == '\0') || (!(CHECK_VALID(*(end-1))))) {
+ /* Someything is not right - put marker and we are done */
+ error = put_marker(data,BAD_FORMAT,BAD_FORMAT_LEN);
+ if(error) {
+ DEBUG_NUMBER("put_marker bad format returned error:",error);
+ free(data->buffer);
+ data->buffer=NULL;
+ free(one_format);
+ return error;
+ }
+ /* We are done */
+ break;
+ }
+
+ /* We are here becuase we have a valid (hopefully) format */
+ block = end - start - 1;
+ memcpy(one_format,start,block);
+ *(one_format+block) = '\0';
+
+ i = end - format_str;
+ brk = 0;
+ error = process_item(data,format_str,&i,event,one_format);
+ if(error) {
+ DEBUG_NUMBER("put_marker bad format returned error:",error);
+ free(data->buffer);
+ data->buffer=NULL;
+ free(one_format);
+ return error;
+ }
+
+ if(brk) break;
+ DEBUG_STRING("Format after another item:",format_str+i);
+ }
+
+ /* Out of the loop */
+ DEBUG_STRING("serialize_with_format","Success Exit");
+ return EOK;
+}
+
+
+