diff options
Diffstat (limited to 'collection/elapi_util.c')
-rw-r--r-- | collection/elapi_util.c | 411 |
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,×tamp,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; +} + + + |