+ return 0;
+} /* int parse_tag_rra_cf */
+
+static int parse_tag_rra(
+ xmlTextReaderPtr reader,
+ rrd_t *rrd)
+{
+ int status;
+ xmlChar *element;
+
+ rra_def_t *cur_rra_def;
+ cdp_prep_t *cur_cdp_prep;
+ rra_ptr_t *cur_rra_ptr;
+
+ /* Allocate more rra_def space for this RRA */
+ { /* {{{ */
+ rra_def_t *temp;
+
+ temp = (rra_def_t *) realloc(rrd->rra_def,
+ sizeof(rra_def_t) *
+ (rrd->stat_head->rra_cnt + 1));
+ if (temp == NULL) {
+ rrd_set_error("parse_tag_rra: realloc failed.");
+ return (-1);
+ }
+ rrd->rra_def = temp;
+ cur_rra_def = rrd->rra_def + rrd->stat_head->rra_cnt;
+ memset(cur_rra_def, '\0', sizeof(rra_def_t));
+ } /* }}} */
+
+ /* allocate cdp_prep_t */
+ { /* {{{ */
+ cdp_prep_t *temp;
+
+ temp = (cdp_prep_t *) realloc(rrd->cdp_prep, sizeof(cdp_prep_t)
+ * rrd->stat_head->ds_cnt
+ * (rrd->stat_head->rra_cnt + 1));
+ if (temp == NULL) {
+ rrd_set_error("parse_tag_rra: realloc failed.");
+ return (-1);
+ }
+ rrd->cdp_prep = temp;
+ cur_cdp_prep = rrd->cdp_prep
+ + (rrd->stat_head->ds_cnt * rrd->stat_head->rra_cnt);
+ memset(cur_cdp_prep, '\0',
+ sizeof(cdp_prep_t) * rrd->stat_head->ds_cnt);
+ } /* }}} */
+
+ /* allocate rra_ptr_t */
+ { /* {{{ */
+ rra_ptr_t *temp;
+
+ temp = (rra_ptr_t *) realloc(rrd->rra_ptr,
+ sizeof(rra_ptr_t) *
+ (rrd->stat_head->rra_cnt + 1));
+ if (temp == NULL) {
+ rrd_set_error("parse_tag_rra: realloc failed.");
+ return (-1);
+ }
+ rrd->rra_ptr = temp;
+ cur_rra_ptr = rrd->rra_ptr + rrd->stat_head->rra_cnt;
+ memset(cur_rra_ptr, '\0', sizeof(rra_ptr_t));
+ } /* }}} */
+
+ /* All space successfully allocated, increment number of RRAs. */
+ rrd->stat_head->rra_cnt++;
+
+ status = 0;
+ while ((element = get_xml_element(reader)) != NULL){
+ if (xmlStrcasecmp(element, (const xmlChar *) "cf") == 0)
+ status = parse_tag_rra_cf(reader, cur_rra_def);
+ else if (xmlStrcasecmp(element, (const xmlChar *) "pdp_per_row") == 0)
+ status = get_xml_ulong(reader,
+ &cur_rra_def->pdp_cnt);
+ else if (atoi(rrd->stat_head->version) == 1
+ && xmlStrcasecmp(element, (const xmlChar *) "xff") == 0)
+ status = get_xml_double(reader,
+ (double *) &cur_rra_def->
+ par[RRA_cdp_xff_val].u_val);
+ else if (atoi(rrd->stat_head->version) >= 2
+ && xmlStrcasecmp(element, (const xmlChar *) "params") == 0){
+ xmlFree(element);
+ status = parse_tag_rra_params(reader, cur_rra_def);
+ if (status == 0)
+ continue;
+ else
+ return status;
+ }
+ else if (xmlStrcasecmp(element, (const xmlChar *) "cdp_prep") == 0){
+ xmlFree(element);
+ status = parse_tag_rra_cdp_prep(reader, rrd, cur_cdp_prep);
+ if (status == 0)
+ continue;
+ else
+ return status;
+ }
+ else if (xmlStrcasecmp(element, (const xmlChar *) "database") == 0){
+ xmlFree(element);
+ status = parse_tag_rra_database(reader, rrd);
+ if (status == 0)
+ continue;
+ else
+ return status;
+ }
+ else if (xmlStrcasecmp(element,(const xmlChar *) "/rra") == 0){
+ xmlFree(element);
+ return status;
+ } /* }}} */
+ else {
+ rrd_set_error("line %d: parse_tag_rra: Unknown tag: %s",
+ xmlTextReaderGetParserLineNumber(reader), element);
+ status = -1;
+ }
+ if (status != 0) {
+ xmlFree(element);
+ return status;
+ }
+ status = expect_element_end(reader,(char *)element);
+ xmlFree(element);
+ if (status != 0) {
+ return status;
+ }
+ }
+ /* Set the RRA pointer to a random location */
+ cur_rra_ptr->cur_row = rrd_random() % cur_rra_def->row_cnt;
+
+ return (status);
+} /* int parse_tag_rra */
+
+/*
+ * Parse a DS definition
+ */
+static int parse_tag_ds_cdef(
+ xmlTextReaderPtr reader,
+ rrd_t *rrd)
+{
+ xmlChar *cdef;
+
+ cdef = get_xml_text(reader);
+ if (cdef != NULL){
+ /* We're always working on the last DS that has been added to the structure
+ * when we get here */
+ parseCDEF_DS((char *)cdef, rrd, rrd->stat_head->ds_cnt - 1);
+ xmlFree(cdef);
+ if (rrd_test_error())
+ return -1;
+ else
+ return 0;
+ }
+ return -1;
+} /* int parse_tag_ds_cdef */
+
+static int parse_tag_ds_type(
+ xmlTextReaderPtr reader,
+ ds_def_t *ds_def)
+{
+ char *dst;
+ dst = (char *)get_xml_text(reader);
+ if (dst != NULL){
+ int status;
+ status = dst_conv(dst);
+ if (status == -1) {
+ rrd_set_error("parse_tag_ds_type: Unknown data source type: %s",
+ dst);
+ return -1;
+ }
+ strncpy(ds_def->dst,dst,sizeof(ds_def->dst)-1);
+ ds_def->dst[sizeof(ds_def->dst)-1] = '\0';
+ xmlFree(dst);
+ return 0;
+ }
+ return -1;
+} /* int parse_tag_ds_type */
+
+static int parse_tag_ds(
+ xmlTextReaderPtr reader,
+ rrd_t *rrd)
+{
+ int status;
+ xmlChar *element;
+
+ ds_def_t *cur_ds_def;
+ pdp_prep_t *cur_pdp_prep;
+
+ /*
+ * If there are DS definitions after RRA definitions the number of values,
+ * cdp_prep areas and so on will be calculated wrong. Thus, enforce a
+ * specific order in this case.
+ */
+ if (rrd->stat_head->rra_cnt > 0) {
+ rrd_set_error("parse_tag_ds: All data source definitions MUST "
+ "precede the RRA definitions!");