diff options
Diffstat (limited to 'collection')
-rw-r--r-- | collection/elapi_collection.c | 229 | ||||
-rw-r--r-- | collection/elapi_collection.h | 29 | ||||
-rw-r--r-- | collection/elapi_util.c | 411 | ||||
-rw-r--r-- | collection/elapi_util.h | 5 |
4 files changed, 671 insertions, 3 deletions
diff --git a/collection/elapi_collection.c b/collection/elapi_collection.c index 50809ae..7045130 100644 --- a/collection/elapi_collection.c +++ b/collection/elapi_collection.c @@ -35,6 +35,13 @@ /* Special internal error code to indicate that collection search was interrupted */ #define EINTR_INTERNAL 10000 + +/* Potential subjest for management with libtools */ +#define DATE_FORMAT "%+" + +#define TIME_ARRAY_SIZE 100 + + /* Struct used for passing parameter for update operation */ struct update_property { int type; @@ -712,10 +719,10 @@ static int update_item(struct collection_item *current, int error = EOK; DEBUG_STRING("update_item","Entry"); - /* If type is different or samew but it is string or binary we need to replace the storage */ + /* If type is different or same but it is string or binary we need to replace the storage */ if((current->type != update_data->type) || ((current->type == update_data->type) && - ((current->type != ELAPI_TYPE_STRING) || (current->type != ELAPI_TYPE_BINARY)))) { + ((current->type == ELAPI_TYPE_STRING) || (current->type == ELAPI_TYPE_BINARY)))) { DEBUG_STRING("Replacing item data buffer",""); free(current->data); current->data = malloc(update_data->length); @@ -1174,6 +1181,224 @@ int add_any_property(struct collection_item *ci, return error; } +/* Add a string property. + If length equals 0, the length is determined based on the string. + Lenght INCLUDES the terminating 0 */ +int add_str_property_with_ref(struct collection_item *ci,char *subcollection, char *property,char *string,int length, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_str_property_with_ref","Entry."); + + if(length == 0) length = strlen(string) + 1; + item = add_property(ci,subcollection,property,(void *)(string),length, ELAPI_TYPE_STRING, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_str_property_with_ref returning",error); + return error; +} + +/* Add a binary property. */ +int add_binary_property_with_ref(struct collection_item *ci,char *subcollection, char *property,void *binary_data,int length, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_binary_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,binary_data,length, ELAPI_TYPE_BINARY, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_binary_property_with_ref returning",error); + return error; +} + +/* Add an int property. */ +int add_int_property_with_ref(struct collection_item *ci,char *subcollection, char *property,int number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_int_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(int), ELAPI_TYPE_INTEGER, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_int_property_with_ref returning",error); + return error; +} + +/* Add an unsigned int property. */ +int add_unsigned_property_with_ref(struct collection_item *ci,char *subcollection, char *property,unsigned int number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_unsigned_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(int), ELAPI_TYPE_UNSIGNED, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_unsigned_property_with_ref returning",error); + return error; +} + +/* Add an long property. */ +int add_long_property_with_ref(struct collection_item *ci,char *subcollection, char *property,long number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_long_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(long), ELAPI_TYPE_LONG, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_long_property_with_ref returning",error); + return error; +} + +/* Add an unsigned long property. */ +int add_ulong_property_with_ref(struct collection_item *ci,char *subcollection, char *property,unsigned long number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_ulong_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(long), ELAPI_TYPE_ULONG, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_ulong_property_with_ref returning",error); + return error; +} + +/* Add a double property. */ +int add_double_property_with_ref(struct collection_item *ci,char *subcollection, char *property,double number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_double_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(double), ELAPI_TYPE_DOUBLE, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_double_property_with_ref returning",error); + return error; +} + +/* A function to add a property */ +int add_any_property_with_ref(struct collection_item *ci, + char *subcollection, + char *property, + int type, + void *data, + int length, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_any_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,data,length, type, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_any_property_with_ref returning",error); + return error; +} + +/* Set time stamp in the collection */ +int set_timestamp(struct collection_item *ci,struct collection_item **timestr_ref,struct collection_item **timeint_ref) +{ + time_t utctime; + struct tm time_struct; + char time_array[TIME_ARRAY_SIZE+1]; + int len; + struct collection_item *timestr = (struct collection_item *)(NULL); + struct collection_item *timeint = (struct collection_item *)(NULL); + + DEBUG_STRING("set_timestamp","Entry point"); + + utctime = time(NULL); + localtime_r(&utctime,&time_struct); + + len = strftime(time_array, TIME_ARRAY_SIZE, date_format, &time_struct); + if(len == 0) { + DEBUG_STRING("add_time","CODING ERROR - INCREASE THE BUFFER"); + return EMSGSIZE; + } + + /* Check if we have the timestamp item already */ + error = get_item(event, TS_NAME, ELAPI_TYPE_STRING,ELAPI_TRAVERSE_IGNORE,×tr); + if(error) { + DEBUG_NUMBER("search failed with error:",error); + return error; + } + + if(timestr != (struct collection_item *)(NULL)) { + /* There is a timestamp */ + free(timestr->data); + timestr->data = strdup(time_array); + if(timestr->data == NULL) { + DEBUG_NUMBER("failed to add timestamp property:",error); + return ENOMEM; + } + timestr->length = len+1; + *timestr_ref = timestr; + } + else { + /* Add timestamp to the collection */ + error = add_str_property_with_ref(event,NULL, TS_NAME,time_array,len+1,timestr_ref); + if(error) { + DEBUG_NUMBER("failed to add timestamp property:",error); + return error; + } + } + + /* Check if we have the time item already */ + error = get_item(event, T_NAME, ELAPI_TYPE_INTEGER,ELAPI_TRAVERSE_IGNORE,&timeint); + if(error) { + DEBUG_NUMBER("search failed with error:",error); + return error; + } + + if(timeint != (struct collection_item *)(NULL)) { + /* There is a time property */ + *((int *)(timeint->data)) = utctime; + *timeint_ref = timeint; + } + else { + /* Add time to the collection */ + error = add_int_property_with_ref(event,NULL, T_NAME,utctime,timeint_ref); + if(error) { + DEBUG_NUMBER("failed to add time property:",error); + return error; + } + } + + DEBUG_STRING("set_timestamp","Exit point"); + return EOK; +} + + /* COPY */ diff --git a/collection/elapi_collection.h b/collection/elapi_collection.h index 361c0c6..1451484 100644 --- a/collection/elapi_collection.h +++ b/collection/elapi_collection.h @@ -55,6 +55,10 @@ #define ELAPI_TRAVERSE_END 0x00000002 /* Call handler once more when end of the collection is reached - good for processing nested collections */ #define ELAPI_TRAVERSE_IGNORE 0x00000004 /* Ignore sub collections at all as if there are none */ +/* Time stamp property name */ +#define TS_NAME "timestamp" +/* Time property name */ +#define T_NAME "time" /* Match values */ #define ELAPI_NOMATCH 0 @@ -110,6 +114,29 @@ int add_any_property(struct collection_item *ci, /* Collection to find things void *data, /* Pointer to the new data */ int length); /* Length of the data. For strings should include trailing 0 */ +/* The functions that add an item and immediately return you this item in the ret_ref paramter */ +int add_str_property_with_ref(struct collection_item *ci,char *subcollection, char *property,char *string,int length, + struct collection_item **ret_ref); +int add_binary_property_with_ref(struct collection_item *ci,char *subcollection, char *property,void *binary_data,int length, + struct collection_item **ret_ref); +int add_int_property_with_ref(struct collection_item *ci,char *subcollection, char *property,int number, + struct collection_item **ret_ref); +int add_unsigned_property_with_ref(struct collection_item *ci,char *subcollection, char *property,unsigned int number, + struct collection_item **ret_ref); +int add_long_property_with_ref(struct collection_item *ci,char *subcollection, char *property,long number, + struct collection_item **ret_ref); +int add_ulong_property_with_ref(struct collection_item *ci,char *subcollection, char *property,unsigned long number, + struct collection_item **ret_ref); +int add_double_property_with_ref(struct collection_item *ci,char *subcollection, char *property,double number, + struct collection_item **ret_ref); +int add_any_property_with_ref(struct collection_item *ci,char *subcollection,char *property,int type,void *data,int length, + struct collection_item **ret_ref); + +/* Function to create a timestamp */ +/* Automatically adds/updates time and timestamp properties in the collection returning references */ +int set_timestamp(struct collection_item *ci, + struct collection_item **timestr_ref, + struct collection_item **timeint_ref); /* Update functions */ @@ -192,7 +219,7 @@ int get_item_and_do(struct collection_item *ci, /* Collection to find thin /* Convenience function to get individual item */ /* Caller should be aware that this is not a copy of the item * but the pointer to actual item stored in the collection. - * The retuned pointer should never be altered or freed by caller of the function. + * The returned pointer should never be altered or freed by caller of the function. * The caller should be sure that the collection does not go out of scope * while the pointer to its data is in use. */ int get_item(struct collection_item *ci, /* Collection to find things in */ 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; +} + + + diff --git a/collection/elapi_util.h b/collection/elapi_util.h index a379ec3..3c2a650 100644 --- a/collection/elapi_util.h +++ b/collection/elapi_util.h @@ -22,6 +22,7 @@ #define ELAPI_UTIL_H #include <libxml/xmlwriter.h> +#include "elapi_collection.h" #define DEFAULT_ENCODING "ISO-8859-1" @@ -90,5 +91,9 @@ int xml_add(char *property, void *custom_data, int *dummy); +/* Serialize using format */ +int serialize_with_format(struct collection_item *event, + char *format_str, + struct serial_data *data); #endif |