diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index f30467dd..f347e6f9 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -694,7 +694,7 @@ from_client_create_subscription(clicon_handle h, } } } - if (client_subscription_add(ce, stream, MSG_NOTIFY_XML, filter) == NULL) + if (client_subscription_add(ce, stream, FORMAT_XML, filter) == NULL) goto done; cprintf(cbret, ""); ok: diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 2832af7d..ce68fca5 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -72,7 +72,7 @@ #include "backend_handle.h" /* Command line options to be passed to getopt(3) */ -#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc:rg:pt" +#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc:rg:pty:" /*! Terminate. Cannot use h after this */ static int @@ -426,6 +426,9 @@ main(int argc, char **argv) case 't' : /* Print alternative dbspec format (eg if YANG, print KEY) */ printalt++; break; + case 'y' : /* yang module */ + clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg); + break; default: usage(argv[0], h); break; diff --git a/apps/backend/clixon_backend_handle.c b/apps/backend/clixon_backend_handle.c index 84ecebbe..720337e8 100644 --- a/apps/backend/clixon_backend_handle.c +++ b/apps/backend/clixon_backend_handle.c @@ -162,7 +162,7 @@ backend_notify(clicon_handle h, /* Then go thru all global (handle) subscriptions and find matches */ hs = NULL; while ((hs = subscription_each(h, hs)) != NULL){ - if (hs->hs_format != MSG_NOTIFY_TXT) + if (hs->hs_format != FORMAT_TEXT) continue; if (strcmp(hs->hs_stream, stream)) continue; @@ -240,7 +240,7 @@ backend_notify_xml(clicon_handle h, /* Then go thru all global (handle) subscriptions and find matches */ hs = NULL; while ((hs = subscription_each(h, hs)) != NULL){ - if (hs->hs_format != MSG_NOTIFY_XML) + if (hs->hs_format != FORMAT_XML) continue; if (strcmp(hs->hs_stream, stream)) continue; diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index c41bf3e1..0ea1383c 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -74,6 +74,7 @@ #include "cli_common.h" + /*! Register log notification stream * @param[in] h Clicon handle * @param[in] stream Event stream. CLICON is predefined, others are application-defined @@ -594,7 +595,7 @@ load_config_filev(clicon_handle h, { int ret = -1; struct stat st; - char **vecp; + char **vecp = NULL; char *filename; int replace; cg_var *cv; @@ -668,6 +669,13 @@ load_config_filev(clicon_handle h, ret = 0; done: unchunk_group(__FUNCTION__); + if (vecp){ + if (vecp[0]) + free(vecp[0]); + if (vecp[1]) + free(vecp[1]); + free(vecp); + } if (xt) xml_free(xt); if (fd != -1) @@ -803,14 +811,6 @@ db_copy(clicon_handle h, return clicon_rpc_copy_config(h, db1, db2); } -/* These are strings that can be used as 3rd argument to cli_setlog */ -#ifdef notused // broke in new version -static const char *SHOWAS_TXT = "txt"; -static const char *SHOWAS_XML = "xml"; -static const char *SHOWAS_XML2TXT = "xml2txt"; -static const char *SHOWAS_XML2JSON = "xml2json"; -#endif - /*! This is the callback used by cli_setlog to print log message in CLI * param[in] s UNIX socket from backend where message should be read * param[in] arg format: txt, xml, xml2txt, xml2json @@ -824,11 +824,7 @@ cli_notification_cb(int s, int retval = -1; cxobj *xt = NULL; cxobj *xe; - char *format = (char*)arg; -#if 0 - char *eventstr = NULL; - cxobj *xn; -#endif + enum format_enum format = (enum format_enum)arg; /* get msg (this is the reason this function is called) */ if (clicon_msg_rcv(s, &reply, &eof) < 0) @@ -840,40 +836,25 @@ cli_notification_cb(int s, event_unreg_fd(s, cli_notification_cb); goto done; } - if (format == NULL) - goto done; if (clicon_msg_decode(reply, &xt) < 0) goto done; - if ((xe = xpath_first(xt, "//event")) != NULL){ + xe = xpath_first(xt, "//event"); + switch (format){ + case FORMAT_XML: if (xml_print(stdout, xe) < 0) goto done; + break; + case FORMAT_TEXT: + if (xml2txt(stdout, xe, 0) < 0) + goto done; + break; + case FORMAT_JSON: + if (xml2json(stdout, xe, 0) < 0) + goto done; + break; + default: + break; } -#ifdef notyet /* Broke in new version */ - if (strcmp(format, SHOWAS_TXT) == 0){ - fprintf(stdout, "%s\n", eventstr); - } - else - if (strcmp(format, SHOWAS_XML) == 0){ - if (clicon_xml_parse_string(&eventstr, &xt) < 0) - goto done; - if ((xn = xml_child_i(xt, 0)) != NULL) - if (xml_print(stdout, xn) < 0) - goto done; - } - else - if (strcmp(format, SHOWAS_XML2TXT) == 0){ - if ((xn = xml_child_i(xe, 0)) != NULL) - if (xml2txt(stdout, xn, 0) < 0) - goto done; - } - else - if (strcmp(format, SHOWAS_XML2JSON) == 0){ - if ((xn = xml_child_i(xe, 0)) != NULL){ - if (xml2json(stdout, xn, 0) < 0) - goto done; - } - } -#endif retval = 0; done: if (xt) @@ -905,7 +886,7 @@ cli_notifyv(clicon_handle h, int retval = -1; int status; char *formatstr = NULL; - enum format_enum format = MSG_NOTIFY_TXT; + enum format_enum format = FORMAT_TEXT; if (cvec_len(argv) != 2 && cvec_len(argv) != 3){ clicon_err(OE_PLUGIN, 0, "%s Requires arguments: []", __FUNCTION__); @@ -915,12 +896,7 @@ cli_notifyv(clicon_handle h, status = atoi(cv_string_get(cvec_i(argv, 1))); if (cvec_len(argv) > 2){ formatstr = cv_string_get(cvec_i(argv, 2)); - if (strcmp(formatstr, "SHOWAS_TXT") != 0) - format = MSG_NOTIFY_XML; - if ((formatstr = strdup(formatstr)) == NULL){ /* XXX */ - clicon_err(OE_PLUGIN, 0, "%s Requires arguments: []", __FUNCTION__); - goto done; - } + format = format_str2int(formatstr); } if (cli_notification_register(h, stream, @@ -928,7 +904,7 @@ cli_notifyv(clicon_handle h, "", status, cli_notification_cb, - formatstr) < 0) + (void*)format) < 0) goto done; retval = 0; @@ -1046,7 +1022,7 @@ load_config_file(clicon_handle h, cvec *argv; cg_var *cv; char *str; - char **vec; + char **vec = NULL; int nvec; /* Split string into two parts and build a cvec of it and supply that to @@ -1055,10 +1031,8 @@ load_config_file(clicon_handle h, clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); goto done; } - if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){ - clicon_err(OE_PLUGIN, errno, "clicon_strsplit"); + if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) goto done; - } if (nvec != 2){ clicon_err(OE_PLUGIN, 0, "Arg syntax is "); goto done; @@ -1076,7 +1050,8 @@ load_config_file(clicon_handle h, retval = load_config_filev(h, cvv, argv); done: - unchunk_group(__FUNCTION__); + if (vec) + free(vec); return retval; } int @@ -1088,7 +1063,7 @@ save_config_file(clicon_handle h, cvec *argv; cg_var *cv; char *str; - char **vec; + char **vec = NULL; int nvec; /* Split string into two parts and build a cvec of it and supply that to @@ -1097,10 +1072,8 @@ save_config_file(clicon_handle h, clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); goto done; } - if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){ - clicon_err(OE_PLUGIN, errno, "clicon_strsplit"); + if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) goto done; - } if (nvec != 2){ clicon_err(OE_PLUGIN, 0, "Arg syntax is "); goto done; @@ -1118,7 +1091,8 @@ save_config_file(clicon_handle h, retval = save_config_filev(h, cvv, argv); done: - unchunk_group(__FUNCTION__); + if (vec) + free(vec); return retval; } @@ -1131,7 +1105,7 @@ cli_notify(clicon_handle h, cvec *argv; cg_var *cv; char *str; - char **vec; + char **vec = NULL; int nvec; /* Split string into two parts and build a cvec of it and supply that to @@ -1140,10 +1114,8 @@ cli_notify(clicon_handle h, clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); goto done; } - if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){ - clicon_err(OE_PLUGIN, errno, "clicon_strsplit"); + if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) goto done; - } if (nvec != 2 && nvec != 3){ clicon_err(OE_PLUGIN, 0, "Arg syntax is []"); goto done; @@ -1166,7 +1138,8 @@ cli_notify(clicon_handle h, } retval = cli_notifyv(h, cvv, argv); done: - unchunk_group(__FUNCTION__); + if (vec) + free(vec); return retval; } diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 78cb7879..4a47ba78 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -174,7 +174,7 @@ main(int argc, char **argv) int help = 0; char *treename; int logdst = CLICON_LOG_STDERR; - char *restarg; /* what remains after options */ + char *restarg = NULL; /* what remains after options */ /* Defaults */ @@ -366,7 +366,7 @@ main(int argc, char **argv) clicon_option_dump(h, debug); /* Join rest of argv to a single command */ - restarg = clicon_strjoin(argc, argv, " ", __FUNCTION__); + restarg = clicon_strjoin(argc, argv, " "); /* If several cligen object variables match same preference, select first */ cligen_match_cgvar_same(1); @@ -389,6 +389,8 @@ main(int argc, char **argv) if (!once) cli_interactive(h); done: + if (restarg) + free(restarg); unchunk_group(__FUNCTION__); // Gets in your face if we log on stderr clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */ diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index d60c052f..4c3f75bf 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -398,9 +398,8 @@ cli_load_syntax(clicon_handle h, const char *filename, const char *clispec_dir) clicon_err(OE_PLUGIN, 0, "No syntax mode specified in %s", filepath); goto done; } - if ((vec = clicon_strsplit(mode, ":", &nvec, __FUNCTION__)) == NULL) { + if ((vec = clicon_strsep(mode, ":", &nvec)) == NULL) goto done; - } for (i = 0; i < nvec; i++) { if (syntax_append(h, cli_syntax(h), vec[i], pt) < 0) { goto done; @@ -415,6 +414,8 @@ cli_load_syntax(clicon_handle h, const char *filename, const char *clispec_dir) done: if (vr) cvec_free(vr); + if (vec) + free(vec); unchunk_group(__FUNCTION__); return retval; } @@ -1020,7 +1021,7 @@ cli_ptpush(clicon_handle h, char *mode, char *string, char *op) return 0; pt = &co_cmd->co_pt; /* vec is the command, eg 'edit policy_option' */ - if ((vec = clicon_strsplit(string, " ", &nvec, __FUNCTION__)) == NULL) + if ((vec = clicon_strsep(string, " ", &nvec)) == NULL) goto catch; co = NULL; found = 0; @@ -1050,7 +1051,8 @@ cli_ptpush(clicon_handle h, char *mode, char *string, char *op) co_up_set(cc, co_cmd); } catch: - unchunk_group(__FUNCTION__) ; + if (vec) + free(vec); return 0; } diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 561ed85e..cdba9012 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -787,10 +787,8 @@ expand_dbvar(void *h, goto done; } /* In the example, str = "candidate /x/m1/%s/b" */ - if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){ - clicon_err(OE_PLUGIN, errno, "clicon_strsplit"); + if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) goto done; - } dbstr = vec[0]; if (strcmp(dbstr, "running") != 0 && strcmp(dbstr, "candidate") != 0 && @@ -856,7 +854,8 @@ expand_dbvar(void *h, } retval = 0; done: - unchunk_group(__FUNCTION__); + if (vec) + free(vec); if (xvec) free(xvec); if (xt) @@ -905,10 +904,8 @@ show_conf_as(clicon_handle h, clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); goto done; } - if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){ - clicon_err(OE_PLUGIN, errno, "clicon_strsplit"); + if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) goto done; - } if (nvec != 2 && nvec != 3){ clicon_err(OE_PLUGIN, 0, "format error \"%s\" - expected [] got %d arg", str, nvec); goto done; @@ -956,7 +953,8 @@ done: free(val); if (cbx) cbuf_free(cbx); - unchunk_group(__FUNCTION__); + if (vec) + free(vec); return retval; } diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index 043d6c63..41619c31 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -129,7 +129,7 @@ request_process(clicon_handle h, char *path; char *query; char *method; - char **pvec; + char **pvec = NULL; int pn; cvec *qvec = NULL; cvec *dvec = NULL; @@ -141,7 +141,7 @@ request_process(clicon_handle h, clicon_debug(1, "%s", __FUNCTION__); path = FCGX_GetParam("DOCUMENT_URI", r->envp); query = FCGX_GetParam("QUERY_STRING", r->envp); - if ((pvec = clicon_strsplit(path, "/", &pn, __FUNCTION__)) == NULL) + if ((pvec = clicon_strsep(path, "/", &pn)) == NULL) goto done; if (str2cvec(query, '&', '=', &qvec) < 0) @@ -171,7 +171,6 @@ request_process(clicon_handle h, if (auth == 0) goto done; clicon_debug(1, "%s credentials ok 2", __FUNCTION__); - clicon_debug(1, "%s credentials ok 3", __FUNCTION__); if (strcmp(method, "data") == 0) /* restconf, skip /api/data */ retval = api_data(h, r, path, pcvec, 2, qvec, data); @@ -181,6 +180,8 @@ request_process(clicon_handle h, retval = notfound(r); done: clicon_debug(1, "%s retval:%d K", __FUNCTION__, retval); + if (pvec) + free(pvec); if (dvec) cvec_free(dvec); if (qvec) @@ -189,7 +190,6 @@ request_process(clicon_handle h, cvec_free(pcvec); if (cb) cbuf_free(cb); - unchunk_group(__FUNCTION__); return retval; } diff --git a/example/routing_cli.cli b/example/routing_cli.cli index b596ee22..4b0b2342 100644 --- a/example/routing_cli.cli +++ b/example/routing_cli.cli @@ -45,7 +45,7 @@ load("Load configuration from XML file") ("Filename (local file } example("This is a comment") ("Just a random number"), mycallback("myarg"); downcall("This is a downcall") , downcall(); -notify("Get notifications from backend"), cli_notifyv("ROUTING", "1", "txt"); +notify("Get notifications from backend"), cli_notifyv("ROUTING", "1", "text"); no("Negate") notify("Get notifications from backend"), cli_notifyv("ROUTING", "0", "xml"); lock,cli_lock("candidate"); unlock,cli_unlock("candidate"); \ No newline at end of file diff --git a/lib/clixon/clixon_proto.h b/lib/clixon/clixon_proto.h index e892788f..85342170 100644 --- a/lib/clixon/clixon_proto.h +++ b/lib/clixon/clixon_proto.h @@ -42,8 +42,11 @@ * Types */ enum format_enum{ - MSG_NOTIFY_TXT, /* means filter works on strings */ - MSG_NOTIFY_XML, /* means filter works on xml */ + FORMAT_XML, + FORMAT_JSON, + FORMAT_TEXT, + FORMAT_CLI, + FORMAT_NETCONF }; /* Protocol message header */ @@ -55,6 +58,9 @@ struct clicon_msg { /* * Prototypes */ +char *format_int2str(enum format_enum showas); +enum format_enum format_str2int(char *str); + struct clicon_msg *clicon_msg_encode(char *format, ...); int clicon_msg_decode(struct clicon_msg *msg, cxobj **xml); diff --git a/lib/clixon/clixon_string.h b/lib/clixon/clixon_string.h index 55ec7a6f..86c22e6d 100644 --- a/lib/clixon/clixon_string.h +++ b/lib/clixon/clixon_string.h @@ -54,17 +54,10 @@ static inline char * strdup4(char *str) /* * Prototypes */ -char **clicon_sepsplit (char *string, char *delim, int *nvec, const char *label); -char **clicon_strsplit (char *string, char *delim, int *nvec, const char *label); char **clicon_strsep(char *string, char *delim, int *nvec0); -char *clicon_strjoin (int argc, char **argv, char *delim, const char *label); -char *clicon_strtrim(char *str, const char *label); -int clicon_sep(char *s, const char sep[2], const char *label, char**a0, char **b0); +char *clicon_strjoin (int argc, char **argv, char *delim); #ifndef HAVE_STRNDUP char *clicon_strndup (const char *, size_t); #endif /* ! HAVE_STRNDUP */ -int clicon_strmatch(const char *str, const char *regexp, char **match); -char *clicon_strsub(char *str, char *from, char *to); - #endif /* _CLIXON_STRING_H_ */ diff --git a/lib/src/clixon_file.c b/lib/src/clixon_file.c index 3280c0c9..1b96ed08 100644 --- a/lib/src/clixon_file.c +++ b/lib/src/clixon_file.c @@ -62,19 +62,22 @@ #include "clixon_string.h" #include "clixon_file.h" -/* - * Resolve the real path of a given 'path', following symbolic links and '../'. +/*! Resolve the real path of a given 'path', following symbolic links and '../'. * If 'path' relative, it will be resolved based on the currnt working * directory 'cwd'. The response is a 2 entry vector of strings. The first * entry is the resolved path and the second is the part of the path which * actually exist. + * @retval vec */ char ** -clicon_realpath(const char *cwd, char *path, const char *label) +clicon_realpath(const char *cwd, + char *path, + const char *label) { char **ret = NULL; char *rest; - char **vec, **vec2; + char **vec = NULL; + char **vec2; int nvec, nvec2; char *p; char *rp = NULL; @@ -122,8 +125,10 @@ clicon_realpath(const char *cwd, char *path, const char *label) /* Split path based on '/'. Loop through vector from the end and copy each entry into a new vector, skipping '..' and it's previous directory as well as all '.' */ - vec = clicon_strsplit (p, "/", &nvec, __FUNCTION__); - vec2 = chunk(nvec * sizeof(char *), __FUNCTION__); + if ((vec = clicon_strsep(p, "/", &nvec)) == NULL) + goto catch; + if ((vec2 = malloc(nvec * sizeof(char *))) == NULL) + goto catch; nvec2 = i = nvec; while(--i >= 0) { if(strcmp(vec[i], "..") == 0) @@ -135,14 +140,14 @@ clicon_realpath(const char *cwd, char *path, const char *label) } /* Create resulting vector */ - if ((ret = chunk(sizeof(char *) * 2, label)) != NULL) { - if((ret[0] = clicon_strjoin(nvec-nvec2, &vec2[nvec2], "/", label)) == NULL) { - unchunk(ret); + if ((ret = malloc(sizeof(char *) * 2)) != NULL) { + if((ret[0] = clicon_strjoin(nvec-nvec2, &vec2[nvec2], "/")) == NULL) { + free(ret); ret = NULL; } - if ((ret[1] = chunkdup(rp, strlen(rp)+1, label)) == NULL) { - unchunk(ret[0]); - unchunk(ret); + if ((ret[1] = strdup(rp)) == NULL) { + free(ret[0]); + free(ret); ret = NULL; } } @@ -150,6 +155,10 @@ clicon_realpath(const char *cwd, char *path, const char *label) catch: if(rp) free(rp); + if(vec) + free(vec); + if(vec2) + free(vec2); unchunk_group(__FUNCTION__); return ret; } diff --git a/lib/src/clixon_proc.c b/lib/src/clixon_proc.c index 9d3d9472..41dd9f8b 100644 --- a/lib/src/clixon_proc.c +++ b/lib/src/clixon_proc.c @@ -121,13 +121,12 @@ clicon_proc_run (char *cmd, sigfn_t oldhandler = NULL; sigset_t oset; - argv = clicon_sepsplit (cmd, " \t", &argc, __FUNCTION__); + argv = clicon_strsep(cmd, " \t", &argc); if (!argv) return -1; if (pipe (outfd) == -1) goto done; - signal_get_mask(&oset); set_signal(SIGINT, clicon_proc_sigint, &oldhandler); @@ -194,7 +193,8 @@ clicon_proc_run (char *cmd, signal_set_mask (&oset); set_signal(SIGINT, oldhandler, NULL); - unchunk_group (__FUNCTION__); + if(argv) + free(argv); return retval; } @@ -216,7 +216,7 @@ clicon_proc_daemon (char *cmd) struct rlimit rlim; - argv = clicon_sepsplit (cmd, " \t", &argc, NULL); + argv = clicon_strsep(cmd, " \t", &argc); if (!argv) return -1; @@ -260,7 +260,8 @@ clicon_proc_daemon (char *cmd) retval = 0; done: - unchunk_group(__FUNCTION__); + if (argv) + free(argv); return (retval); } diff --git a/lib/src/clixon_proto.c b/lib/src/clixon_proto.c index e74e28b1..21c2b0ed 100644 --- a/lib/src/clixon_proto.c +++ b/lib/src/clixon_proto.c @@ -74,6 +74,46 @@ static int _atomicio_sig = 0; +/*! Formats (showas) derived from XML + */ +struct formatvec{ + char *fv_str; + int fv_int; +}; + +static struct formatvec _FORMATS[] = { + {"xml", FORMAT_XML}, + {"text", FORMAT_TEXT}, + {"json", FORMAT_JSON}, + {"cli", FORMAT_CLI}, + {"netconf", FORMAT_NETCONF}, + {NULL, -1} +}; + +/*! Translate from numeric error to string representation + */ +char * +format_int2str(enum format_enum showas) +{ + struct formatvec *fv; + + for (fv=_FORMATS; fv->fv_int != -1; fv++) + if (fv->fv_int == showas) + break; + return fv?(fv->fv_str?fv->fv_str:"unknown"):"unknown"; +} + +enum format_enum +format_str2int(char *str) +{ + struct formatvec *fv; + + for (fv=_FORMATS; fv->fv_int != -1; fv++) + if (strcmp(fv->fv_str, str) == 0) + break; + return fv?fv->fv_int:-1; +} + /*! Encode a clicon netconf message * @param[in] param Variable agrument list format an XML netconf string * @retval msg Clicon message to send to eg clicon_msg_send() diff --git a/lib/src/clixon_string.c b/lib/src/clixon_string.c index 139fdeff..ecf1431b 100644 --- a/lib/src/clixon_string.c +++ b/lib/src/clixon_string.c @@ -53,117 +53,6 @@ #include "clixon_string.h" #include "clixon_err.h" -/*! Split string into a vector based on character delimiters - * - * The given string is split into a vector where the delimiter can be - * any of the characters in the specified delimiter string. - * - * The vector returned is one single memory chunk that must be unchunked - * by the caller - * - * @param[in] string String to be split - * @param[in] delim String of delimiter characters - * @param[out] nvec Number of entries in returned vector - * @param[in] label Chunk label for returned vector - * @retval vec Vector of strings. Free with unchunk - * @retval NULL Error - * @see clicon_strsplit Operates on full string delimiters rather than - * individual character delimiters. - * @see clicon_strsep Use malloc instead of chunk - */ -char ** -clicon_sepsplit (char *string, - char *delim, - int *nvec, - const char *label) -{ - int idx; - size_t siz; - char *s, *s0; - char **vec, *vecp; - - *nvec = 0; - s0 = s = chunkdup (string, strlen(string)+1, __FUNCTION__); - while (strsep(&s, delim)) - (*nvec)++; - unchunk (s0); - - siz = ((*nvec +1) * sizeof (char *)) + strlen(string) + 1; - vec = (char **) chunk (siz, label); - if (!vec) { - return NULL; - } - bzero (vec, siz); - - vecp = (char *)&vec[*nvec +1]; - bcopy (string, vecp, strlen (string)); - - for (idx = 0; idx < *nvec; idx++) { - vec[idx] = vecp; - strsep (&vecp, delim); - } - - return vec; -} - -/*! Split string into a vector based on a string delimiter - * - * The given string is split into a vector where the delimited by the - * the full delimiter string. The matched delimiters are not part of the - * resulting vector. - * - * The vector returned is one single memory chunk that must be unchunked - * by the caller - * - * @param[in] string String to be split - * @param[in] delim String of delimiter characters - * @param[out] nvec Number of entries in returned vector - * @param[in] label Chunk label for returned vector - * @retval vec Vector of strings. Free with unchunk - * @retval NULL Error - * @see clicon_sepsplit Operates on individual character delimiters rather - * than full string delimiter. - * @see clicon_strsep Use malloc instead of chunk - */ -char ** -clicon_strsplit (char *string, - char *delim, - int *nvec, - const char *label) -{ - int idx; - size_t siz; - char *s; - char **vec, *vecp; - - *nvec = 1; - s = string; - while ((s = strstr(s, delim))) { - s += strlen(delim); - (*nvec)++; - } - - siz = ((*nvec +1) * sizeof (char *)) + strlen(string) + 1; - vec = (char **) chunk (siz, label); - if (!vec) { - return NULL; - } - bzero (vec, siz); - - vecp = (char *)&vec[*nvec +1]; - bcopy (string, vecp, strlen (string)); - - s = vecp; - for (idx = 0; idx < *nvec; idx++) { - vec[idx] = s; - if ((s = strstr(s, delim)) != NULL) { - *s = '\0'; - s += strlen(delim); - } - } - - return vec; -} /*! Split string into a vector based on character delimiters. Using malloc * @@ -189,14 +78,20 @@ clicon_strsep(char *string, char *p; int nvec = 1; int i; - - for (i=0; i str && isspace(*(end-1))) - end--; - if((new = chunkdup (start, end-start+1, label))) - new[end-start] = '\0'; - - return new; -} - -/*! Given a string s, on format: a[b], separate it into two parts: a and b - * [] are separators. - * alterative use: - * a/b -> a and b (where sep = "/") - * @param[in] label Chunk label for returned vector - */ -int -clicon_sep(char *s, - const char sep[2], - const char *label, - char **a0, - char **b0) -{ - char *a = NULL; - char *b = NULL; - char *ptr; + int i; int len; - int retval = -1; + char *str; - ptr = s; - /* move forward to last char of element name */ - while (*ptr && *ptr != sep[0] && *ptr != sep[1] ) - ptr++; - /* Copy first element name */ - len = ptr-s; - if ((a = chunkdup(s, len+1, label)) == NULL) - goto catch; - a[len] = '\0'; - /* Do we have an extended format? */ - if (*ptr == sep[0]) { - b = ++ptr; - /* move forward to end extension */ - while (*ptr && *ptr != sep[1]) - ptr++; - /* Copy extension */ - len = ptr-b; - if ((b = chunkdup(b, len+1, label)) == NULL) - goto catch; - b[len] = '\0'; + len = 0; + for (i = 0; i < argc; i++) + len += strlen(argv[i]); + if (delim) + len += (strlen(delim) * argc); + len += 1; /* '\0' */ + if ((str = malloc(len)) == NULL) + return NULL; + memset (str, '\0', len); + for (i = 0; i < argc; i++) { + if (i != 0) + strncat (str, delim, len - strlen(str)); + strncat (str, argv[i], len - strlen(str)); } - - *a0 = a; - *b0 = b; - retval = 0; - catch: - return retval; + return str; } @@ -346,82 +160,48 @@ clicon_strndup (const char *str, } #endif /* ! HAVE_STRNDUP */ -/*! Match string against regexp. - * - * If a match pointer is given, the matching substring - * will be allocated 'match' will be pointing to it. The match string must - * be free:ed by the application. - * @retval -1 Failure - * @retval 0 No match - * @retval >0 Match: Length of matching substring - */ +/* + * Turn this on for uni-test programs + * Usage: clixon_string join + * Example compile: + gcc -g -o clixon_string -I. -I../clixon ./clixon_string.c -lclixon -lcligen + * Example run: +*/ +#if 0 /* Test program */ + +static int +usage(char *argv0) +{ + fprintf(stderr, "usage:%s \n", argv0); + exit(0); +} + int -clicon_strmatch(const char *str, - const char *regexp, - char **match) +main(int argc, char **argv) { - size_t len; - int status; - regex_t re; - char rxerr[128]; - size_t nmatch = 1; - regmatch_t pmatch[1]; - - if (match) - *match = NULL; - - if ((status = regcomp(&re, regexp, REG_EXTENDED)) != 0) { - regerror(status, &re, rxerr, sizeof(rxerr)); - clicon_err(OE_REGEX, errno, "%s", rxerr); - return -1; - } - - status = regexec(&re, str, nmatch, pmatch, 0); - regfree(&re); - if (status != 0) - return 0; /* No match */ - - len = pmatch[0].rm_eo - pmatch[0].rm_so; -/* If we've specified a match pointer, allocate and populate it. */ - if (match) { - if ((*match = malloc(len + 1)) == NULL) { - clicon_err(OE_UNIX, errno, "Failed to allocate string"); - return -1; - } - memset(*match, '\0', len + 1); - strncpy(*match, str + pmatch[0].rm_so, len); - } - - return len; -} - -/*! Substitute pattern in string. - * @retval str Malloc:ed string on success, use free to deallocate - * @retval NULL Failure. - */ -char * -clicon_strsub(char *str, - char *from, - char *to) -{ - char **vec; int nvec; - char *new; - char *retval = NULL; + char **vec; + char *str0; + char *str1; + int i; - if ((vec = clicon_strsplit(str, from, &nvec, __FUNCTION__)) == NULL) { - clicon_err(OE_UNIX, errno, "Failed to split string"); - goto done; + if (argc != 2){ + usage(argv[0]); + return 0; } - - if ((new = clicon_strjoin (nvec, vec, to, __FUNCTION__)) == NULL) { - clicon_err(OE_UNIX, errno, "Failed to split string"); - goto done; - } - - retval = strdup(new); - - done: - unchunk_group(__FUNCTION__); - return retval; + str0 = argv[1]; + if ((vec = clicon_strsep("a b\tc", " \t", &nvec)) == NULL) + return -1; + fprintf(stderr, "nvec: %d\n", nvec); + for (i=0; i'"); goto done; } - if ((valvec = clicon_strsplit(restval, ",", &nvalvec, __FUNCTION__)) == NULL) + if (valvec) + free(valvec); + if ((valvec = clicon_strsep(restval, ",", &nvalvec)) == NULL) goto done; if (cvec_len(cvk) != nvalvec){ @@ -1398,6 +1405,11 @@ xmldb_put_xkey(clicon_handle h, cbuf_free(crx); if (cvk) cvec_free(cvk); + if (vec) + free(vec); + if (valvec) + free(valvec); + unchunk_group(__FUNCTION__); return retval; } @@ -1431,7 +1443,7 @@ xmldb_put_restconf_api_path(clicon_handle h, int retval = -1; yang_stmt *y = NULL; yang_stmt *ykey; - char **vec; + char **vec = NULL; int nvec; int i; char *name; @@ -1466,7 +1478,7 @@ xmldb_put_restconf_api_path(clicon_handle h, clicon_err(OE_UNIX, errno, "cbuf_new"); goto done; } - if ((vec = clicon_strsplit(api_path, "/", &nvec, __FUNCTION__)) == NULL) + if ((vec = clicon_strsep(api_path, "/", &nvec)) == NULL) goto done; if (nvec < 2){ clicon_err(OE_XML, 0, "Malformed key: %s", api_path); @@ -1611,6 +1623,8 @@ xmldb_put_restconf_api_path(clicon_handle h, cbuf_free(crx); if (cvk) cvec_free(cvk); + if (vec) + free(vec); unchunk_group(__FUNCTION__); return retval; } diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 6ab33816..7e0d0bf4 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -1695,11 +1695,9 @@ yang_xpath_abs(yang_node *yn, char *prefix = NULL; if ((vec = clicon_strsep(xpath, "/", &nvec)) == NULL){ - clicon_err(OE_YANG, errno, "%s: strsplit", __FUNCTION__); + clicon_err(OE_YANG, errno, "%s: strsep", __FUNCTION__); return NULL; } - - /* Assume path looks like: "/prefix:id[/prefix:id]*" */ if (nvec < 2){ clicon_err(OE_YANG, 0, "%s: NULL or truncated path: %s", @@ -1955,16 +1953,14 @@ cvec * yang_arg2cvec(yang_stmt *ys, char *delim) { - char **vec; + char **vec = NULL; int i; int nvec; cvec *cvv = NULL; cg_var *cv; - if ((vec = clicon_strsplit(ys->ys_argument, " ", &nvec, __FUNCTION__)) == NULL){ - clicon_err(OE_YANG, errno, "clicon_strsplit"); + if ((vec = clicon_strsep(ys->ys_argument, " ", &nvec)) == NULL) goto done; - } if ((cvv = cvec_new(nvec)) == NULL){ clicon_err(OE_YANG, errno, "cvec_new"); goto done; @@ -1979,7 +1975,8 @@ yang_arg2cvec(yang_stmt *ys, } } done: - unchunk_group(__FUNCTION__); + if (vec) + free(vec); return cvv; } diff --git a/test/test2.sh b/test/test2.sh index f23b070d..ef16c0cb 100755 --- a/test/test2.sh +++ b/test/test2.sh @@ -21,7 +21,7 @@ if [ $? -ne 0 ]; then err fi new "netconf get empty config" -expecteof "valgrind $clixon_netconf -qf $clixon_cf" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^]]>]]>$" new "netconf edit config" expecteof "$clixon_netconf -qf $clixon_cf" "eth0eth1true
9.2.3.424
]]>]]>" "^]]>]]>$"