From cf3cf351c845a5a3dcce26d2d28e184cef952ec5 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 2 Mar 2016 09:38:52 +0100 Subject: [PATCH] xmldb api cleanup --- apps/backend/backend_client.c | 4 +- apps/backend/backend_main.c | 2 +- apps/cli/cli_common.c | 250 +++---------------------------- apps/cli/cli_generate.c | 1 - apps/cli/cli_main.c | 13 +- apps/cli/clixon_cli_api.h | 8 +- apps/dbctrl/dbctrl_main.c | 46 ++---- apps/netconf/netconf_rpc.c | 25 ---- example/routing_backend.c | 3 +- lib/clixon/clixon.h.in | 1 - lib/clixon/clixon_xml_db.h | 4 +- lib/clixon/clixon_xsl.h | 5 +- lib/{clixon => src}/clixon_qdb.h | 0 lib/src/clixon_xml_db.c | 122 +++++++++++---- lib/src/clixon_xml_map.c | 1 - lib/src/clixon_xsl.c | 53 ++++--- 16 files changed, 177 insertions(+), 361 deletions(-) rename lib/{clixon => src}/clixon_qdb.h (100%) diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index c028a3ad..6baa7706 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -486,7 +486,7 @@ from_client_load(clicon_handle h, send_msg_err(s, OE_UNIX, 0, "rm %s %s", filename, strerror(errno)); goto done; } - if (db_init(dbname) < 0) + if (xmldb_init(dbname) < 0) goto done; } @@ -559,7 +559,7 @@ from_client_initdb(clicon_handle h, goto done; } - if (db_init(filename1) < 0) + if (xmldb_init(filename1) < 0) goto done; /* Change mode if shared candidate. XXXX full rights for all is no good */ if (strcmp(filename1, candidate_db) == 0) diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 0f3423d5..6a34e54b 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -148,7 +148,7 @@ rundb_init(clicon_handle h, char *running_db) clicon_err(OE_UNIX, errno, "unlink"); return -1; } - if (db_init(running_db) < 0) + if (xmldb_init(running_db) < 0) return -1; return 0; diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index cdb7a964..18209696 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -404,9 +404,6 @@ cli_validate(clicon_handle h, cvec *vars, cg_var *arg) return retval; } - - - /*! Completion callback primarily intended for automatically generated data model * * Returns an expand-type list of commands as used by cligen 'expand' @@ -434,7 +431,7 @@ cli_validate(clicon_handle h, cvec *vars, cg_var *arg) * Assume callback given in a cligen spec: a " * @param[out] len len of return commands & helptxt * @param[out] commands vector of function pointers to callback functions @@ -459,10 +456,11 @@ expand_dbvar_dbxml(void *h, char *dbstr; cxobj *xt = NULL; char *xk = NULL; + cxobj **xvec = NULL; int i; int i0; - struct db_pair *pairs; - int npairs; + size_t xlen; + yang_spec *yspec; if (arg == NULL || (str = cv_string_get(arg)) == NULL){ clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); @@ -488,23 +486,28 @@ expand_dbvar_dbxml(void *h, goto done; } xkfmt = vec[1]; - /* xkfmt = "/test/kalle/%s/lasse" --> "^/test/kalle/.* /lasse$" */ - if (xmlkeyfmt2key2(xkfmt, cvv, &xk) < 0) - goto done; - if ((npairs = db_regexp(dbname, xk, __FUNCTION__, &pairs, 0)) < 0) + /* xkfmt = /interface/%s/address/%s + --> ^/interface/eth0/address/.*$ + --> /interface/[name=eth0]/address + */ + if (xmlkeyfmt2xpath(xkfmt, cvv, &xk) < 0) + goto done; + yspec = clicon_dbspec_yang(h); + if (xmldb_get_vec(dbname, xk, yspec, &xt, &xvec, &xlen) < 0) goto done; i0 = *nr; - *nr += npairs; + *nr += xlen; if ((*commands = realloc(*commands, sizeof(char *) * (*nr))) == NULL) { clicon_err(OE_UNDEF, errno, "realloc: %s", strerror (errno)); goto done; } - for (i = 0; i < npairs; i++) - (*commands)[i0+i] = strdup(pairs[i].dp_val); - + for (i = 0; i < xlen; i++) + (*commands)[i0+i] = strdup(xml_body(xvec[i])); retval = 0; done: unchunk_group(__FUNCTION__); + if (xvec) + free(xvec); if (xt) xml_free(xt); if (xk) @@ -512,221 +515,6 @@ expand_dbvar_dbxml(void *h, return retval; } -#ifdef NOTUSED - -/*! Expand based on database key and variable value (of that key) - * - * Return an expand-type list of commands as used by cligen 'expand' - * functionality. - * arg is a string: " ". - * is either running or candidate - * matches a set of database keys - * is name of a variable occuring in the cli command string - * Example: "candidate ^Create.*$" GroupName" - * (See also expand_db_variable(). - * - * Assume callback given in a cligen spec: a ", - str); - goto done; - } - dbstr = vec[0]; - keystr = vec[1]; - varstr = vec[2]; - if (strcmp(dbstr, "running") == 0) - dbname = clicon_running_db(h); - else - if (strcmp(dbstr, "candidate") == 0) - dbname = clicon_candidate_db(h); - else{ - clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr); - goto done; - } - if (dbname == NULL){ - clicon_err(OE_FATAL, 0, "dbname not set"); - goto done; - } - if ((retval = expand_db_variable(h, dbname, keystr, varstr, nr, commands)) < 0) - goto done; - retval = 0; - done: - unchunk_group(__FUNCTION__); - return retval; -} - -/*! Expand database variable - * Given a database, a basekey (pattern) and a variable, return an expand-type - * list of commands as used by cligen 'expand' functionality. - * @see expand_dbvar - */ -int -expand_db_variable(clicon_handle h, - char *dbname, - char *basekey, - char *variable, - int *nr, - char ***commands) -{ - char *key; - int i; - int j; - int retval = -1; - cvec *cvv; - cg_var *cv = NULL; - char **tmp; - char *val = NULL; - cvec **cvvp = NULL; - size_t len = 0; - - /* adhoc to detect regexp keys. If so, dont call db_gen_rxkey */ - if (index(basekey, '^') == NULL){ - if ((key = db_gen_rxkey(basekey, __FUNCTION__)) == NULL) - goto quit; - } - else - key = chunkdup(basekey, strlen(basekey)+1, __FUNCTION__); - - if (clicon_dbitems(dbname, key, &cvvp, &len) < 0) - goto quit; - for (i = 0; i < len; i++) { - cvv = cvvp[i]; - cv = NULL; - while ((cv = cvec_each(cvv, cv)) != NULL) { - if (strcmp(cv_name_get(cv), variable) != 0) - continue; - if ((val = cv2str_dup(cv)) == NULL) - goto quit; - /* Check if value already in vector? No duplicates */ - for (j=0; j<*nr; j++) - if (strcmp(val, (*commands)[j]) == 0) - break; - if (j<*nr){ - free(val); - val = NULL; - continue; - } - if ((tmp = realloc(*commands, sizeof(char *) * ((*nr)+1))) == NULL) { - clicon_err(OE_UNDEF, errno, "realloc: %s", strerror (errno)); - goto quit; - } - *commands = tmp; - (*commands)[*nr] = val; - val = NULL; - (*nr)++; - break; - } - } - retval = 0; -quit: - if (cvvp) - clicon_dbitems_free(cvvp, len); - unchunk_group(__FUNCTION__); - return retval; -} - -/*! Pattern match in candidate_db - */ -int -expand_db_symbol(clicon_handle h, - char *symbol, - int element, - int *nr, - char ***commands) -{ - int retval = -1; - char **tmp; - cvec **cvvp = NULL; - cvec *cvv; - size_t len = 0; - int i; - char *key; - int nvec; - int n; - char **vec = NULL; - char str[128]; - char *dbname; - - if ((dbname = clicon_running_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "running db not set"); - goto done; - } - snprintf(str, sizeof(str), "^%s\\..", symbol); - if (clicon_rpc_dbitems(h, dbname, str, NULL, NULL, &cvvp, &len) < 0) - goto done; - for (i = 0; i < len; i++) { - cvv = cvvp[i]; - key = cvec_name_get(cvv); - if ((vec = clicon_strsplit(key, ".", &nvec, __FUNCTION__)) == NULL){ - clicon_err(OE_UNDEF, errno, "clicon_strsplit"); - goto done; - } - /* Check if already exists */ - for (n=0; n<*nr; n++) - if (strcmp((*commands)[n], vec[element]) == 0) - break; /* Already exists */ - if (n<*nr) - continue; - /* Allocate new pointer */ - if ((tmp = realloc(*commands, sizeof(char *) * ((*nr)+1))) == NULL) { - clicon_err(OE_UNDEF, errno, "realloc: %s", strerror (errno)); - goto done; - } - *commands = tmp; - /* Duplicate string */ - if (((*commands)[*nr] = strdup(vec[element])) == NULL) { - clicon_err(OE_UNDEF, errno, "strdup: %s", strerror (errno)); - goto done; - } - (*nr)++; - } - retval = 0; - done: - unchunk_group(__FUNCTION__) ; - if (cvvp) - clicon_dbitems_free(cvvp, len); - if (retval < 0 && *commands){ - while ((*nr) >= 0) - free((*commands)[(*nr)--]); - free (*commands); - } - return retval; -} -#endif /* NOTUSED */ /* * expand_dir @@ -1165,7 +953,7 @@ load_config_file(clicon_handle h, cvec *cvv, cg_var *arg) clicon_err(OE_UNIX, 0, "rm %s %s", filename, strerror(errno)); goto done; } - if (db_init(dbname) < 0) + if (xmldb_init(dbname) < 0) goto done; } if ((fd = open(filename, O_RDONLY)) < 0){ @@ -1316,7 +1104,7 @@ delete_all(clicon_handle h, cvec *cvv, cg_var *arg) clicon_err(OE_FATAL, errno, "unlink(%s)", dbname); goto done; } - if (db_init(dbname) < 0) + if (xmldb_init(dbname) < 0) goto done; } retval = 0; diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index 86f2c607..afdb1837 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -54,7 +54,6 @@ #define GENERATE_CALLBACK "cli_set" /* variable expand function */ -#define GENERATE_EXPAND_LVEC "expand_dbvar_auto" #define GENERATE_EXPAND_XMLDB "expand_dbvar_dbxml" /*===================================================================== diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 9660d59b..fccf7d03 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -58,6 +58,7 @@ /* Command line options to be passed to getopt(3) */ #define CLI_OPTS "hD:f:F:1u:d:m:cP:qpGLl:" +/*! terminate cli application */ static int cli_terminate(clicon_handle h) { @@ -71,9 +72,7 @@ cli_terminate(clicon_handle h) return 0; } -/* - * cli_sig_term - * Unlink pidfile and quit +/*! Unlink pidfile and quit */ static void cli_sig_term(int arg) @@ -83,8 +82,7 @@ cli_sig_term(int arg) exit(1); } -/* - * Setup signal handlers +/*! Setup signal handlers */ static void cli_signal_init (clicon_handle h) @@ -93,6 +91,9 @@ cli_signal_init (clicon_handle h) set_signal(SIGTERM, cli_sig_term, NULL); } +/*! Interactive CLI command loop + * @see cligen_loop + */ static void cli_interactive(clicon_handle h) { @@ -366,7 +367,7 @@ main(int argc, char **argv) clicon_option_str_set(h, "CLICON_CANDIDATE_DB", private_db); if (!cli_send2backend(h)) - if (db_init(running_db) < 0){ + if (xmldb_init(running_db) < 0){ fprintf (stderr, "FATAL: Could not init running_db. (Run as root?)\n"); goto done; } diff --git a/apps/cli/clixon_cli_api.h b/apps/cli/clixon_cli_api.h index a12eced6..122b66d7 100644 --- a/apps/cli/clixon_cli_api.h +++ b/apps/cli/clixon_cli_api.h @@ -86,13 +86,9 @@ int cli_start_shell(clicon_handle h, cvec *vars, cg_var *argv); int cli_quit(clicon_handle h, cvec *vars, cg_var *arg); int cli_commit(clicon_handle h, cvec *vars, cg_var *arg); int cli_validate(clicon_handle h, cvec *vars, cg_var *arg); -int expand_dbvar(void *h, char *name, cvec *vars, cg_var *arg, - int *nr, char ***commands, char ***helptexts); -int expand_dbvar_auto(void *h, char *name, cvec *vars, cg_var *arg, - int *nr, char ***commands, char ***helptexts); -int expand_db_variable(clicon_handle h, char *dbname, char *basekey, char *variable, int *nr, char ***commands); -int expand_db_symbol(clicon_handle h, char *symbol, int element, int *nr, char ***commands); int expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail); +int expand_dbvar_dbxml(void *h, char *name, cvec *cvv, cg_var *arg, + int *nr, char ***commands, char ***helptexts); int compare_dbs(clicon_handle h, cvec *vars, cg_var *arg); int load_config_file(clicon_handle h, cvec *vars, cg_var *arg); diff --git a/apps/dbctrl/dbctrl_main.c b/apps/dbctrl/dbctrl_main.c index dc5964f6..2383f88e 100644 --- a/apps/dbctrl/dbctrl_main.c +++ b/apps/dbctrl/dbctrl_main.c @@ -52,41 +52,17 @@ /* Command line options to be passed to getopt(3) */ #define DBCTRL_OPTS "hDd:pbn:r:m:Zi" -/*! Write database contents to file, xml database variant - * @param[in] dbspec If set make a sanity check if key dont match (just) - */ -static int -dump_database(FILE *f, - char *dbname, - char *rxkey) -{ - int retval = 0; - int npairs; - struct db_pair *pairs; - - /* Default is match all */ - if (rxkey == NULL) - rxkey = "^.*$"; - - /* Get all keys/values for vector */ - if ((npairs = db_regexp(dbname, rxkey, __FUNCTION__, &pairs, 0)) < 0) - return -1; - - for (npairs--; npairs >= 0; npairs--) - fprintf(f, "%s %s\n", pairs[npairs].dp_key, - pairs[npairs].dp_val?pairs[npairs].dp_val:""); - unchunk_group(__FUNCTION__); - return retval; -} - - /* * remove_entry */ static int remove_entry(char *dbname, char *key) { - return db_del(dbname, key); +#ifdef NOTYET /* This assumes direct access to database */ + return db_del(dbname, key); +#else + return 0; +#endif } /* @@ -219,7 +195,7 @@ main(int argc, char **argv) } yspec = clicon_dbspec_yang(h); if (dumpdb){ - if (dump_database(stdout, dbname, matchkey)) { + if (xmldb_dump(stdout, dbname, matchkey)) { fprintf(stderr, "Match error\n"); goto done; } @@ -230,10 +206,14 @@ main(int argc, char **argv) if (rment) if (remove_entry(dbname, rmkey) < 0) goto done; - if (zapdb) /* remove databases */ - unlink(dbname); + if (zapdb) /* remove databases */ + /* XXX This assumes direct access to database */ + if (unlink(dbname) < 0){ + clicon_err(OE_FATAL, errno, "unlink %s", dbname); + goto done; + } if (initdb) - if (db_init(dbname) < 0) + if (xmldb_init(dbname) < 0) goto done; done: diff --git a/apps/netconf/netconf_rpc.c b/apps/netconf/netconf_rpc.c index 2bb864ce..a5874cb3 100644 --- a/apps/netconf/netconf_rpc.c +++ b/apps/netconf/netconf_rpc.c @@ -402,31 +402,6 @@ get_edit_opts(cxobj *xn, * * @note delete/remove not implemented * - * Call graph, client to backend and formats - * netconf_input_cb # client - * read - * process_incoming_packet # (char*) - * clicon_xml_parse_string # (xml) - * netconf_rpc_dispatch - * netconf_edit_config # client - * clicon_xml2file # (file) - * clicon_rpc_load - * from_client # backend - * from_client_load - * db_init # replace? - * load_xml_to_db - * clicon_xml_parse_file #(xml) - * xml2db - * xml2cvec_key #(cvec) - * clicon_dbput - * cvec2lvec #(lvec) - * db_set - * dpopen - * dpput #(db) - * dpclose - * Which means that for a single edit, the following format conversions are made: - * char*->xml->file->xml->cvec->lvec->db - * */ int netconf_edit_config(clicon_handle h, diff --git a/example/routing_backend.c b/example/routing_backend.c index 0b74e07e..6c365c75 100644 --- a/example/routing_backend.c +++ b/example/routing_backend.c @@ -63,7 +63,8 @@ transaction_commit(clicon_handle h, size_t len; /* Get all added i/fs */ - vec = xpath_vec_flag(target, "//interface", XML_FLAG_ADD, &len); + if (xpath_vec_flag(target, "//interface", XML_FLAG_ADD, &vec, &len) < 0) + return -1; for (i=0; i #include #include -#include #include #include #include diff --git a/lib/clixon/clixon_xml_db.h b/lib/clixon/clixon_xml_db.h index 9fadcec2..36e4415e 100644 --- a/lib/clixon/clixon_xml_db.h +++ b/lib/clixon/clixon_xml_db.h @@ -28,7 +28,7 @@ */ int yang2xmlkeyfmt(yang_stmt *ys, char **xkfmt); int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk); -int xmlkeyfmt2key2(char *xkfmt, cvec *cvv, char **xk); +int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk); int xmlkey2xml(char *xkey, yang_spec *yspec, char **xml); int xmldb_get(char *dbname, char *xpath, yang_spec *yspec, cxobj **xtop); @@ -38,5 +38,7 @@ int xmldb_put( char *dbname, cxobj *xt, yang_spec *yspec, enum operation_type op); int xmldb_put_xkey(char *dbname, char *xkey, char *val, yang_spec *yspec, enum operation_type op); +int xmldb_dump(FILE *f, char *dbname, char *rxkey); +int xmldb_init(char *file); #endif /* _CLIXON_XML_DB_H */ diff --git a/lib/clixon/clixon_xsl.h b/lib/clixon/clixon_xsl.h index c71150d8..a48918e1 100644 --- a/lib/clixon/clixon_xsl.h +++ b/lib/clixon/clixon_xsl.h @@ -28,7 +28,8 @@ */ cxobj *xpath_first(cxobj *xn_top, char *xpath); cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev); -cxobj **xpath_vec(cxobj *xn_top, char *xpath, size_t *xv_len); -cxobj **xpath_vec_flag(cxobj *cxtop, char *xpath, uint16_t flags, size_t *veclen); +int xpath_vec(cxobj *xn_top, char *xpath, cxobj ***vec, size_t *xv_len); +int xpath_vec_flag(cxobj *cxtop, char *xpath, uint16_t flags, + cxobj ***vec, size_t *veclen); #endif /* _CLIXON_XSL_H */ diff --git a/lib/clixon/clixon_qdb.h b/lib/src/clixon_qdb.h similarity index 100% rename from lib/clixon/clixon_qdb.h rename to lib/src/clixon_qdb.h diff --git a/lib/src/clixon_xml_db.c b/lib/src/clixon_xml_db.c index 920c0b41..ecb276f5 100644 --- a/lib/src/clixon_xml_db.c +++ b/lib/src/clixon_xml_db.c @@ -165,6 +165,7 @@ yang2xmlkeyfmt(yang_stmt *ys, char **xkfmt) } /*! Transform an xml key format and a vector of values to an XML key + * Used for actual key, eg in clicon_rpc_change(), xmldb_put_xkey() * Example: * xmlkeyfmt: /aaa/%s * cvv: key=17 @@ -188,6 +189,7 @@ xmlkeyfmt2key(char *xkfmt, char *str; /* Sanity check */ +#if 1 j = 0; /* Count % */ for (i=0; i a[x=y] */ + if ((str = strdup(cbuf_get(cb))) == NULL){ clicon_err(OE_UNIX, errno, "strdup"); goto done; } - } - else - if ((str = cv2str_dup(cvec_i(cvv, j++))) == NULL){ + str[strlen(str)-1] = '\0'; + cbuf_reset(cb); + cprintf(cb, "%s", str); + free(str); + + cv = cvec_i(cvv, j++); + if ((str = cv2str_dup(cv)) == NULL){ clicon_err(OE_UNIX, errno, "cv2str_dup"); goto done; } - cprintf(cb, "%s", str); - free(str); + cprintf(cb, "[%s=%s]", cv_name_get(cv), str); + free(str); + } } - else + else /* regular char */ if (c == '%') esc++; - else - cprintf(cb, "%c", c); + else{ + if (skip) + skip=0; + else + cprintf(cb, "%c", c); + } } - cprintf(cb, "$"); if ((*xk = strdup(cbuf_get(cb))) == NULL){ clicon_err(OE_UNIX, errno, "strdup"); goto done; @@ -435,6 +463,7 @@ xml_tree_prune_unmarked(cxobj *xt, /*! * @param[in] xkey xmlkey * @param[out] xt XML tree as result + * XXX cannot handle top-level list */ static int get(char *dbname, @@ -637,7 +666,6 @@ xml_default(cxobj *x, return retval; } - /*! Get content of database using xpath. return a single tree * The function returns a minimal tree that includes all sub-trees that match * xpath. @@ -691,7 +719,9 @@ xmldb_get(char *dbname, * 2. only read necessary parts,...? */ if (xpath){ - if ((xvec = xpath_vec(xt, xpath, &len)) != NULL){ + if (xpath_vec(xt, xpath, &xvec, &len) < 0) + goto done; + if (xvec != NULL){ /* Prune everything except nodes in xvec and how to get there * Alt: Create a new subtree from xt with that property,...(no) */ @@ -737,7 +767,7 @@ xmldb_get(char *dbname, * cxobj **xvec; * size_t xlen; * yang_spec *yspec = clicon_dbspec_yang(h); - * if (xmldb_get_vec(dbname, "/interfaces/interface[name="eth*"]", yspec, + * if (xmldb_get_vec(dbname, "/interfaces/interface[name="eth"]", yspec, * &xt, &xvec, &xlen) < 0) * err; * for (i=0; i= 0; npairs--) + fprintf(f, "%s %s\n", pairs[npairs].dp_key, + pairs[npairs].dp_val?pairs[npairs].dp_val:""); + unchunk_group(__FUNCTION__); + return retval; +} + +int +xmldb_init(char *file) +{ + return db_init(file); +} + #if 1 /* Test program */ /* * Turn this on to get an xpath test program diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 94a140b2..afbde0fa 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -67,7 +67,6 @@ #include "clixon_yang.h" #include "clixon_yang_type.h" #include "clixon_options.h" -#include "clixon_qdb.h" #include "clixon_xml.h" #include "clixon_xsl.h" #include "clixon_log.h" diff --git a/lib/src/clixon_xsl.c b/lib/src/clixon_xsl.c index dfe4a229..3e98517d 100644 --- a/lib/src/clixon_xsl.c +++ b/lib/src/clixon_xsl.c @@ -149,8 +149,9 @@ xpath_print(FILE *f, struct xpath_element *xplist) struct xpath_element *xe; for (xe=xplist; xe; xe=xe->xe_next) - fprintf(f, "\t:%s %s\n", axis_type2str(xe->xe_type), - xe->xe_str?xe->xe_str:""); + fprintf(f, "\t:%s %s %s\n", axis_type2str(xe->xe_type), + xe->xe_str?xe->xe_str:"", + xe->xe_predicate?xe->xe_predicate:""); return 0; } @@ -334,7 +335,7 @@ recursive_find(cxobj *xn, } static int -xpath_expr(char *e, +xpath_expr(char *e00, uint16_t flags, cxobj ***vec0, size_t *vec0len) @@ -350,7 +351,14 @@ xpath_expr(char *e, int oplen; char *tag; char *val; + char *e0; + char *e; + if ((e0 = strdup(e00)) == NULL){ + clicon_err(OE_UNIX, errno, "strdup"); + goto done; + } + e = e0; if (*e == '@'){ /* @ attribute */ e++; e_v=e; @@ -418,6 +426,8 @@ xpath_expr(char *e, *vec0len = veclen; retval = 0; done: + if (e0) + free(e0); return retval; } @@ -603,7 +613,7 @@ xpath_exec(char *xpath, goto done; if (xpath_parse(xpath, &xplist) < 0) goto done; - if (0) + if (debug > 1) xpath_print(stderr, xplist); if (xpath_find(xplist, 0, vec1, vec1len, flags, vec2, vec2len) < 0) goto done; @@ -767,9 +777,10 @@ xpath_each(cxobj *cxtop, * See xpath1() on details for subset. * @param[in] cxtop xml-tree where to search * @param[in] xpath string with XPATH syntax + * @param[out] vec vector of xml-trees. Vector must be free():d after use * @param[out] xv_len returns length of vector in return value - * @retval vec vector of xml-trees. Vector must be free():d after use - * @retval NULL NULL on error. + * @retval 0 OK + * @retval -1 error. * * @code * cxobj **xv; @@ -786,34 +797,30 @@ xpath_each(cxobj *cxtop, * trees need not be. * @see also xpath_first, xpath_each. */ -cxobj ** -xpath_vec(cxobj *cxtop, - char *xpath, - size_t *veclen) +int +xpath_vec(cxobj *cxtop, + char *xpath, + cxobj ***vec, + size_t *veclen) { - cxobj **vec=NULL; - + *vec = NULL; *veclen = 0; - if (xpath_choice(cxtop, xpath, 0, &vec, (size_t*)veclen) < 0) - return NULL; - return vec; + return xpath_choice(cxtop, xpath, 0, vec, veclen); } /* A restricted xpath that returns a vector of matches (only nodes marked with flags) * @param[in] flags Set of flags that return nodes must match (0 if all) */ -cxobj ** +int xpath_vec_flag(cxobj *cxtop, char *xpath, uint16_t flags, + cxobj ***vec, size_t *veclen) { - cxobj **vec=NULL; - + *vec=NULL; *veclen = 0; - if (xpath_choice(cxtop, xpath, flags, &vec, (size_t*)veclen) < 0) - return NULL; - return vec; + return xpath_choice(cxtop, xpath, flags, vec, veclen); } /* @@ -852,7 +859,9 @@ main(int argc, char **argv) } printf("\n"); - if ((xv = xpath_vec(x, argv[1], &xlen)) != NULL) { + if (xpath_vec(x, argv[1], &xv, &xlen) < 0) + goto done; + if (xv) for (i=0; i