/* Create a buffer containg JSON serialization */ int col_json_collection(struct collection_item *handle, char **storage) { struct col_serial_data buf_data; int error = EOK; TRACE_FLOW_STRING("col_json_collection", "Entry"); if (storage == NULL) { TRACE_ERROR_STRING("Error.", "Storage data is not passed in!"); return EINVAL; } *storage = NULL; buf_data.buffer = NULL; buf_data.length = 0; buf_data.size = 0; buf_data.nest_level = 0; /* Traverse collection */ error = col_traverse_collection(handle, COL_TRAVERSE_DEFAULT | COL_TRAVERSE_END , col_json, (void *)(&buf_data)); if (error) TRACE_ERROR_NUMBER("Error traversing collection ", error); else *storage = buf_data.buffer; TRACE_FLOW_NUMBER("col_json_collection returning", error); return error; }
/* Reset array */ void ref_array_reset(struct ref_array *ra) { int idx; TRACE_FLOW_ENTRY(); /* Check if array is not NULL */ if (!ra) { TRACE_ERROR_STRING("Uninitialized array.", "Coding error???"); return; } if (ra->cb) { for (idx = 0; idx < ra->len; idx++) { ra->cb((unsigned char *)(ra->storage) + idx * ra->elsize, REF_ARRAY_DESTROY, ra->cb_data); } } free(ra->storage); ra->storage = NULL; ra->size = 0; ra->len = 0; TRACE_FLOW_EXIT(); }
/* Get element */ void *ref_array_get(struct ref_array *ra, uint32_t idx, void *acptr) { TRACE_FLOW_ENTRY(); if (!ra) { TRACE_ERROR_STRING("Uninitialized argument.", ""); return NULL; } if (idx >= ra->len) { TRACE_INFO_NUMBER("Invalid idx.", idx); return NULL; } TRACE_INFO_NUMBER("Index: ", idx); if (acptr) { TRACE_INFO_STRING("Copying data.", ""); memcpy(acptr, (unsigned char *)(ra->storage) + idx * ra->elsize, ra->elsize); } TRACE_FLOW_EXIT(); return (unsigned char *)(ra->storage) + idx * ra->elsize; }
/* Print the collection using iterator */ int col_print_collection2(struct collection_item *handle) { struct collection_iterator *iterator = NULL; int error = EOK; struct collection_item *item = NULL; int nest_level = 0; int dummy = 0; int line = 1; TRACE_FLOW_STRING("col_print_collection2", "Entry"); /* If we have something to print print it */ if (handle == NULL) { TRACE_ERROR_STRING("No error list", ""); return EINVAL; } /* Bind iterator */ error = col_bind_iterator(&iterator, handle, COL_TRAVERSE_DEFAULT | COL_TRAVERSE_END | COL_TRAVERSE_SHOWSUB); if (error) { TRACE_ERROR_NUMBER("Error (bind):", error); return error; } do { /* Loop through a collection */ error = col_iterate_collection(iterator, &item); if (error) { TRACE_ERROR_NUMBER("Error (iterate):", error); col_unbind_iterator(iterator); return error; } /* Are we done ? */ if (item == NULL) break; if (item->type != COL_TYPE_END) printf("%05d", line); col_debug_handle(item->property, item->property_len, item->type, item->data, item->length, (void *)(&nest_level), &dummy); line++; } while(1); /* Do not forget to unbind iterator - otherwise there will be a leak */ col_unbind_iterator(iterator); TRACE_INFO_STRING("col_print_collection2", "Exit"); return EOK; }
/* Alternative function to get length */ uint32_t ref_array_len(struct ref_array *ra) { TRACE_FLOW_ENTRY(); if (!ra) { TRACE_ERROR_STRING("Uninitialized argument.", ""); errno = EINVAL; return 0; } TRACE_FLOW_EXIT(); return ra->len; }
/* Allocate buffer structure */ int simplebuffer_alloc(struct simplebuffer **data) { int error = EOK; TRACE_FLOW_ENTRY(); if (!data) { TRACE_ERROR_STRING("Invalid argument", ""); error = EINVAL; } else { *data = (struct simplebuffer *)calloc(1, sizeof(struct simplebuffer)); if (*data == NULL) { TRACE_ERROR_STRING("Failed to allocate memory", ""); error = ENOMEM; } else error = EOK; } TRACE_FLOW_RETURN(error); return error; }
/* Get length */ int ref_array_getlen(struct ref_array *ra, uint32_t *len) { TRACE_FLOW_ENTRY(); if ((!ra) || (!len)) { TRACE_ERROR_STRING("Uninitialized argument.", ""); return EINVAL; } *len = ra->len; TRACE_FLOW_EXIT(); return EOK; }
int col_push_str_property(struct collection_item *stack, const char *property, const char *string, int length) { int error = EOK; TRACE_FLOW_STRING("col_push_str_property", "Entry point."); /* Check that stack is not empty */ if (stack == NULL) { TRACE_ERROR_STRING("Stack can't be NULL", ""); return EINVAL; } /* Make sure it is a stack */ if (!col_is_of_class(stack, COL_CLASS_STACK)) { TRACE_ERROR_STRING("Wrong class", ""); return EINVAL; } error = col_add_str_property(stack, NULL, property, string, length); TRACE_FLOW_STRING("col_push_str_property", "Exit."); return error; }
/* Get new reference to an array */ struct ref_array *ref_array_getref(struct ref_array *ra) { TRACE_FLOW_ENTRY(); /* Check if array is not NULL */ if (ra) { TRACE_INFO_NUMBER("Increasing reference count. Current: ", ra->refcount); /* Increase reference count */ ra->refcount++; TRACE_INFO_NUMBER("Increased reference count. New: ", ra->refcount); } else { TRACE_ERROR_STRING("Uninitialized array.", "Returning NULL"); } TRACE_FLOW_EXIT(); return ra; }
/* Delete the array */ void ref_array_destroy(struct ref_array *ra) { int idx; TRACE_FLOW_ENTRY(); /* Check if array is not NULL */ if (!ra) { TRACE_INFO_STRING("Uninitialized array.", "Might be Ok..."); return; } TRACE_INFO_NUMBER("Current reference count: ", ra->refcount); if (ra->refcount) { /* Decrease reference count */ ra->refcount--; if (ra->refcount == 0) { TRACE_INFO_NUMBER("It is time to delete array. Count:", ra->refcount); if (ra->cb) { for (idx = 0; idx < ra->len; idx++) { ra->cb((unsigned char *)(ra->storage) + idx * ra->elsize, REF_ARRAY_DESTROY, ra->cb_data); } } free(ra->storage); free(ra); } } else { /* Should never be here... * This can happen if the caller by mistake would try to * destroy the object from within the callback. Brrr.... */ TRACE_ERROR_STRING("Reference count is 0.", "Coding error???"); } TRACE_FLOW_EXIT(); }
/* Use JSON formal for serialization */ int col_json(const char *property_in, int property_len_in, int type, void *data_in, int length_in, void *custom_data, int *dummy) { int len; struct col_serial_data *buf_data; const char *property; const void *data; int property_len; int length; int error = EOK; int i; TRACE_FLOW_STRING("col_json","Entry point"); *dummy = 0; /* Check is there is buffer. If not allocate */ buf_data = (struct col_serial_data *)custom_data; if (buf_data == NULL) { TRACE_ERROR_STRING("Error.", "Storage data is not passed in!"); return EINVAL; } if (buf_data->buffer == NULL) { TRACE_INFO_STRING("First time use.", "Allocating buffer."); buf_data->buffer = malloc(BLOCK_SIZE); if (buf_data->buffer == NULL) { TRACE_ERROR_NUMBER("Error. Failed to allocate memory.", ENOMEM); return ENOMEM; } buf_data->buffer[0] = '\0'; buf_data->length = 0; buf_data->size = BLOCK_SIZE; } TRACE_INFO_NUMBER("Buffer len: ", buf_data->length); TRACE_INFO_NUMBER("Buffer size: ", buf_data->size); TRACE_INFO_STRING("Buffer: ", buf_data->buffer); /* Check the beginning of the collection */ if (type == COL_TYPE_COLLECTION) { TRACE_INFO_STRING("Serializing collection: ", property_in); TRACE_INFO_STRING("First header. ", ""); error = col_put_marker(buf_data, "{", 1); if (error != EOK) return error; property = TEXT_EVENT; property_len = TEXT_EVENTLEN; data = property_in; length = property_len_in + 1; type = COL_TYPE_STRING; buf_data->nest_level++; } /* Check for subcollections */ else if (type == COL_TYPE_COLLECTIONREF) { /* Skip */ TRACE_FLOW_STRING("col_serialize", "skip reference return"); return EOK; } /* Check for the end of the collection */ else if (type == COL_TYPE_END) { if ((buf_data->length > 0) && (buf_data->buffer[buf_data->length-1] == ',')) { buf_data->length--; buf_data->buffer[buf_data->length] = '\0'; } if (buf_data->nest_level > 0) { buf_data->nest_level--; error = col_put_marker(buf_data, "}", 1); if (error != EOK) return error; } TRACE_FLOW_STRING("col_serialize", "end collection item processed returning"); return EOK; } else { property = property_in; property_len = property_len_in; data = data_in; length = length_in; } TRACE_INFO_STRING("Property: ", property); TRACE_INFO_NUMBER("Property length: ", property_len); /* Start with property and ":" */ if ((error = col_put_marker(buf_data, "\"", 1)) || (error = col_put_marker(buf_data, property, property_len)) || (error = col_put_marker(buf_data, "\":", 2))) { TRACE_ERROR_NUMBER("put_marker returned error: ", error); return error; } /* Get projected length of the item */ len = col_get_data_len(type,length); TRACE_INFO_NUMBER("Expected data length: ",len); TRACE_INFO_STRING("Buffer so far: ", buf_data->buffer); /* Make sure we have enough space */ if ((error = col_grow_buffer(buf_data, len))) { TRACE_ERROR_NUMBER("grow_buffer returned error: ", error); return error; } /* Add the value */ switch (type) { case COL_TYPE_STRING: /* Escape double quotes */ len = col_copy_esc(&buf_data->buffer[buf_data->length], (const char *)(data), '"'); break; case COL_TYPE_BINARY: buf_data->buffer[buf_data->length] = '\''; for (i = 0; i < length; i++) sprintf(&buf_data->buffer[buf_data->length + i *2] + 1, "%02X", (unsigned int)(((const unsigned char *)(data))[i])); len = length * 2 + 1; buf_data->buffer[buf_data->length + len] = '\''; len++; break; case COL_TYPE_INTEGER: len = sprintf(&buf_data->buffer[buf_data->length], "%d", *((const int32_t *)(data))); break; case COL_TYPE_UNSIGNED: len = sprintf(&buf_data->buffer[buf_data->length], "%u", *((const uint32_t *)(data))); break; case COL_TYPE_LONG: len = sprintf(&buf_data->buffer[buf_data->length], "%lld", (long long int)(*((const int64_t *)(data)))); break; case COL_TYPE_ULONG: len = sprintf(&buf_data->buffer[buf_data->length], "%llu", (long long unsigned)(*((const uint64_t *)(data)))); break; case COL_TYPE_DOUBLE: len = sprintf(&buf_data->buffer[buf_data->length], "%.4f", *((const double *)(data))); break; case COL_TYPE_BOOL: len = sprintf(&buf_data->buffer[buf_data->length], "%s", (*((const unsigned char *)(data))) ? "true" : "false"); break; default: buf_data->buffer[buf_data->length] = '\0'; len = 0; break; } /* Adjust length */ buf_data->length += len; buf_data->buffer[buf_data->length] = '\0'; /* Always put a comma at the end */ error = col_put_marker(buf_data, ",", 1); if (error != EOK) { TRACE_ERROR_NUMBER("put_marker returned error: ", error); return error; } TRACE_INFO_STRING("Data: ", buf_data->buffer); TRACE_FLOW_STRING("col_json", "Exit point"); return EOK; }
/* Handle key-value pair */ static int handle_kvp(struct parser_obj *po, uint32_t *action) { int error = EOK; char *eq = NULL; uint32_t len = 0; char *dupval = NULL; char *str; uint32_t full_len; TRACE_FLOW_ENTRY(); str = po->last_read; full_len = po->last_read_len; TRACE_INFO_STRING("Last read:", str); /* Trim spaces at the beginning */ while ((full_len > 0) && (isspace(*(str)))) { str++; full_len--; } /* Check if we have the key */ if (*(str) == '=') { TRACE_ERROR_STRING("No key", str); po->last_error = ERR_NOKEY; *action = PARSE_ERROR; return EOK; } /* Find "=" */ eq = strchr(str, '='); if (eq == NULL) { TRACE_ERROR_STRING("No equal sign", str); po->last_error = ERR_NOEQUAL; *action = PARSE_ERROR; return EOK; } /* Strip spaces around "=" */ /* Since eq > str we can substract 1 */ len = eq - str - 1; while ((len > 0) && (isspace(*(str + len)))) len--; /* Adjust length properly */ len++; /* Check the key length */ if(len >= MAX_KEY) { TRACE_ERROR_STRING("Key name is too long", str); po->last_error = ERR_LONGKEY; *action = PARSE_ERROR; return EOK; } if (po->key) { /* Complete processing of the previous value */ error = complete_value_processing(po); if (error) { TRACE_ERROR_NUMBER("Failed to complete value processing", error); return error; } } /* Dup the key name */ po->key = malloc(len + 1); if (!(po->key)) { TRACE_ERROR_NUMBER("Failed to dup key", ENOMEM); return ENOMEM; } memcpy(po->key, str, len); *(po->key + len) = '\0'; po->key_len = len; TRACE_INFO_STRING("Key:", po->key); TRACE_INFO_NUMBER("Keylen:", po->key_len); len = full_len - (eq - str) - 1; /* Trim spaces after equal sign */ eq++; while (isspace(*eq)) { eq++; len--; } TRACE_INFO_STRING("VALUE:", eq); TRACE_INFO_NUMBER("LENGTH:", len); /* Dup the part of the value */ dupval = malloc(len + 1); if (!dupval) { TRACE_ERROR_NUMBER("Failed to dup value", ENOMEM); return ENOMEM; } memcpy(dupval, eq, len); *(dupval + len) = '\0'; /* Create new arrays */ error = value_create_arrays(&(po->raw_lines), &(po->raw_lengths)); if (error) { TRACE_ERROR_NUMBER("Failed to create arrays", error); free(dupval); return error; } /* Save a duplicated part in the value */ error = value_add_to_arrays(dupval, len, po->raw_lines, po->raw_lengths); if (error) { TRACE_ERROR_NUMBER("Failed to add value to arrays", error); free(dupval); return error; } /* Save the line number of the last found key */ po->keylinenum = po->linenum; /* Prepare for reading */ free(po->last_read); po->last_read = NULL; po->last_read_len = 0; *action = PARSE_READ; TRACE_FLOW_EXIT(); return EOK; }
/* Function to read next line from the file */ static int parser_read(struct parser_obj *po) { int error = EOK; char *buffer = NULL; ssize_t res = 0; size_t len = 0; int32_t i = 0; uint32_t action; TRACE_FLOW_ENTRY(); /* Adjust line number */ (po->linenum)++; /* Get line from the file */ res = getline(&buffer, &len, po->file); if (res == -1) { if (feof(po->file)) { TRACE_FLOW_STRING("Read nothing", ""); if (po->inside_comment) { action = PARSE_ERROR; po->last_error = ERR_BADCOMMENT; } else action = PARSE_POST; } else { TRACE_ERROR_STRING("Error reading", ""); action = PARSE_ERROR; po->last_error = ERR_READ; } if(buffer) free(buffer); } else { /* Read Ok */ len = res; TRACE_INFO_STRING("Read line ok:", buffer); TRACE_INFO_NUMBER("Length:", len); TRACE_INFO_NUMBER("Strlen:", strlen(buffer)); if (buffer[0] == '\0') { /* Empty line - read again (should not ever happen) */ action = PARSE_READ; free(buffer); } else { /* Check length */ if (len >= BUFFER_SIZE) { TRACE_ERROR_STRING("Too long", ""); action = PARSE_ERROR; po->last_error = ERR_LONGDATA; free(buffer); } else { /* Trim end line */ i = len - 1; while ((i >= 0) && ((buffer[i] == '\r') || (buffer[i] == '\n'))) { TRACE_INFO_NUMBER("Offset:", i); TRACE_INFO_NUMBER("Code:", buffer[i]); buffer[i] = '\0'; i--; } po->last_read = buffer; po->last_read_len = i + 1; action = PARSE_INSPECT; TRACE_INFO_STRING("Line:", po->last_read); TRACE_INFO_NUMBER("Linelen:", po->last_read_len); } } } /* Move to the next action */ error = col_enqueue_unsigned_property(po->queue, PARSE_ACTION, action); if (error) { TRACE_ERROR_NUMBER("Failed to schedule an action", error); return error; } TRACE_FLOW_EXIT(); return EOK; }
/* Print errors and warnings that were detected while parsing * the whole configuration */ void print_config_parsing_errors(FILE *file, struct collection_item *error_list) { struct collection_iterator *iterator; int error; struct collection_item *item = NULL; struct collection_item *file_errors = NULL; TRACE_FLOW_STRING("print_config_parsing_errors", "Entry"); /* If we have something to print print it */ if (error_list == NULL) { TRACE_ERROR_STRING("No error list", ""); return; } /* Make sure we go the right collection */ if (!col_is_of_class(error_list, COL_CLASS_INI_PESET)) { TRACE_ERROR_STRING("Wrong collection class:", WRONG_COLLECTION); fprintf(file, "%s\n", WRONG_COLLECTION); return; } /* Bind iterator */ error = col_bind_iterator(&iterator, error_list, COL_TRAVERSE_DEFAULT); if (error) { TRACE_ERROR_STRING("Error (bind):", FAILED_TO_PROCCESS); fprintf(file,"%s\n", FAILED_TO_PROCCESS); return; } while(1) { /* Loop through a collection */ error = col_iterate_collection(iterator, &item); if (error) { TRACE_ERROR_STRING("Error (iterate):", FAILED_TO_PROCCESS); fprintf(file, "%s\n", FAILED_TO_PROCCESS); col_unbind_iterator(iterator); return; } /* Are we done ? */ if (item == NULL) break; /* Print per file sets of errors */ if (col_get_item_type(item) == COL_TYPE_COLLECTIONREF) { /* Extract a sub collection */ error = col_get_reference_from_item(item, &file_errors); if (error) { TRACE_ERROR_STRING("Error (extract):", FAILED_TO_PROCCESS); fprintf(file, "%s\n", FAILED_TO_PROCCESS); col_unbind_iterator(iterator); return; } print_file_parsing_errors(file, file_errors); col_destroy_collection(file_errors); } } /* Do not forget to unbind iterator - otherwise there will be a leak */ col_unbind_iterator(iterator); TRACE_FLOW_STRING("print_config_parsing_errors", "Exit"); }
/* Internal function that prints errors */ static void print_error_list(FILE *file, struct collection_item *error_list, int cclass, char *wrong_col_error, char *failed_to_process, char *error_header, char *line_format, int family) { struct collection_iterator *iterator; int error; struct collection_item *item = NULL; struct parse_error *pe; unsigned int count; TRACE_FLOW_STRING("print_error_list", "Entry"); /* If we have something to print print it */ if (error_list == NULL) { TRACE_ERROR_STRING("No error list",""); return; } /* Make sure we go the right collection */ if (!col_is_of_class(error_list, cclass)) { TRACE_ERROR_STRING("Wrong collection class:", wrong_col_error); fprintf(file,"%s\n", wrong_col_error); return; } /* Bind iterator */ error = col_bind_iterator(&iterator, error_list, COL_TRAVERSE_DEFAULT); if (error) { TRACE_ERROR_STRING("Error (bind):", failed_to_process); fprintf(file, "%s\n", failed_to_process); return; } while(1) { /* Loop through a collection */ error = col_iterate_collection(iterator, &item); if (error) { TRACE_ERROR_STRING("Error (iterate):", failed_to_process); fprintf(file, "%s\n", failed_to_process); col_unbind_iterator(iterator); return; } /* Are we done ? */ if (item == NULL) break; /* Process collection header */ if (col_get_item_type(item) == COL_TYPE_COLLECTION) { col_get_collection_count(item, &count); if (count <= 2) break; } else if (col_get_item_type(item) == COL_TYPE_STRING) { fprintf(file, error_header, (char *)col_get_item_data(item)); } else { /* Put error into provided format */ pe = (struct parse_error *)(col_get_item_data(item)); fprintf(file, line_format, col_get_item_property(item, NULL), /* Error or warning */ pe->error, /* Error */ pe->line, /* Line */ ini_get_error_str(pe->error, family)); /* Error str */ } } /* Do not forget to unbind iterator - otherwise there will be a leak */ col_unbind_iterator(iterator); TRACE_FLOW_STRING("print_error_list", "Exit"); }