summaryrefslogtreecommitdiff
path: root/src/cli_val_engine.c
diff options
context:
space:
mode:
authorAn-Cheng Huang <ancheng@vyatta.com>2007-09-25 15:55:26 -0700
committerAn-Cheng Huang <ancheng@vyatta.com>2007-09-25 15:55:26 -0700
commite9a79a249cec69fc178098d2f75db9389068510a (patch)
tree0e366094b7fecd3988c243fbbb574015e0c900c8 /src/cli_val_engine.c
downloadvyatta-cfg-e9a79a249cec69fc178098d2f75db9389068510a.tar.gz
vyatta-cfg-e9a79a249cec69fc178098d2f75db9389068510a.zip
initial import (from eureka /cli) plus new build system.upstream
Diffstat (limited to 'src/cli_val_engine.c')
-rw-r--r--src/cli_val_engine.c881
1 files changed, 881 insertions, 0 deletions
diff --git a/src/cli_val_engine.c b/src/cli_val_engine.c
new file mode 100644
index 0000000..d597c68
--- /dev/null
+++ b/src/cli_val_engine.c
@@ -0,0 +1,881 @@
+
+/************************************************************************
+
+ Module: cli
+
+ **** License ****
+ Version: VPL 1.0
+
+ The contents of this file are subject to the Vyatta Public License
+ Version 1.0 ("License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.vyatta.com/vpl
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ This code was originally developed by Vyatta, Inc.
+ Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ All Rights Reserved.
+
+ Author: Oleg Moskalenko
+ Date: 2007
+ Description: "new" cli handler for the reference variables
+
+ **** End License ****
+
+*************************************************************************/
+
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <regex.h>
+#include <dirent.h>
+
+#include <string.h>
+
+#include "cli_val_engine.h"
+
+/*********************
+ * Data definitions
+ *
+ *********************/
+
+/**
+ * Special file names:
+ */
+#define VALUE_FILE ("node.val")
+#define NODE_TAG ("node.tag")
+#define NODE_DEF ("node.def")
+
+/**
+ * "Command" definition (element of a variable path):
+ */
+
+typedef struct {
+ clind_cmd_type cmd_type;
+ const char* text[10];
+} cmd_parse_definition;
+
+/**
+ * Structure to hold information about possible command entries:
+ */
+
+static cmd_parse_definition cmd_parse_definitions[] = {
+ { CLIND_CMD_PARENT_VALUE, {"..","@",NULL } },
+ { CLIND_CMD_NEIGHBOR, {"..","*",NULL } },
+ { CLIND_CMD_PARENT, {"..",NULL } },
+ { CLIND_CMD_PARENT, {".","..",NULL } },
+ { CLIND_CMD_CHILD, {".","*",NULL } },
+ { CLIND_CMD_VALUE, {".","@",NULL } },
+ { CLIND_CMD_SELF_NAME, {".",NULL } },
+ { CLIND_CMD_VALUE, {"@",NULL } },
+ { CLIND_CMD_MULTI_VALUE, {"@@",NULL } },
+ { CLIND_CMD_CHILD, {"*",NULL } },
+ { CLIND_CMD_UNKNOWN, {NULL} }
+};
+
+/************************
+ * Cmd utils forward declarations
+ *
+ ************************/
+
+static int clind_path_shift_cmd(clind_path_ref path,clind_cmd *cmd);
+
+/******************************
+ * Variable evaluation engine *
+ * *
+ ******************************/
+
+/**
+ * For a given config path, return the 'value' of the path.
+ * If the path ends with "node.val", then return the file content.
+ * If not, then return the last path element.
+ * If path is empty, or the file is empty, or the file does not exist,
+ * then return NULL.
+ * The user of this function is responsible for the memory deallocation.
+ */
+
+static char** clind_get_current_value(clind_path_ref cfg_path,
+ clind_path_ref tmpl_path,
+ int check_existence,
+ vtw_type_e *val_type,
+ const char* root_tmpl_path,
+ int return_value_file_name,
+ int multi_value,
+ int *ret_size) {
+
+ char** ret=NULL;
+ *ret_size=0;
+
+ if(val_type) *val_type=TEXT_TYPE;
+
+ if(cfg_path && (clind_path_get_size(cfg_path)>0)) {
+
+ clind_path_ref tmpl_path_clone = clind_path_clone(tmpl_path);
+
+ const char* cfg_path_string = clind_path_get_path_string(cfg_path);
+ const char* cfg_end = clind_path_last_string(cfg_path);
+ const char* tmpl_path_string = clind_path_get_path_string(tmpl_path_clone);
+ const char* tmpl_end = clind_path_last_string(tmpl_path_clone);
+
+ /*
+ printf("%s:111.111:%s:%s:%s:%s:%d\n",__FUNCTION__,
+ cfg_path_string,
+ cfg_end,
+ tmpl_path_string,
+ tmpl_end,
+ multi_value);
+ */
+
+ if(cfg_path_string && cfg_end) {
+
+ if(strcmp(cfg_end,VALUE_FILE)==0) {
+
+ /* Value reference: */
+
+ if(return_value_file_name) {
+
+ ret=(char**)realloc(ret,sizeof(char*)*1);
+ ret[0]=strdup(cfg_path_string);
+ *ret_size=1;
+
+ } else {
+
+ FILE* f = fopen(cfg_path_string,"r");
+ if(f) {
+ char buffer[8193];
+ if(multi_value) {
+ while(fgets(buffer, sizeof(buffer)-1,f)) {
+ int len=strlen(buffer);
+ while(len>0 && (buffer[len-1]==10 || buffer[len-1]==13)) {
+ buffer[len-1]=0;
+ len--;
+ }
+ if(len>0) {
+ ret=(char**)realloc(ret,sizeof(char*)*(*ret_size+1));
+ ret[*ret_size]=strdup(buffer);
+ *ret_size+=1;
+ }
+ }
+ } else {
+ int sz = fread(buffer, 1, sizeof(buffer)-1, f);
+ if(sz>0) {
+ int len=0;
+ buffer[sz]=0;
+ len=strlen(buffer);
+ while(len>0 && (buffer[len-1]==10 || buffer[len-1]==13)) {
+ buffer[len-1]=0;
+ len--;
+ }
+ ret=(char**)malloc(sizeof(char*)*1);
+ ret[0]=strdup(buffer);
+ *ret_size=1;
+ }
+ }
+ fclose(f);
+ }
+ }
+
+ } else if(return_value_file_name) {
+
+ ret=(char**)realloc(ret,sizeof(char*)*1);
+ ret[0]=(char*)malloc(strlen(cfg_path_string)+1+strlen(VALUE_FILE)+1);
+ strcpy(ret[0],cfg_path_string);
+ strcpy(ret[0]+strlen(ret[0]),"/");
+ strcpy(ret[0]+strlen(ret[0]),VALUE_FILE);
+ *ret_size=1;
+
+ } else {
+
+ struct stat statbuf;
+
+ /* Directory reference: */
+
+ if(!check_existence || (lstat(cfg_path_string, &statbuf) == 0)) {
+ ret=(char**)realloc(ret,sizeof(char*)*1);
+ ret[0]=clind_unescape(cfg_end);
+ *ret_size=1;
+ }
+ }
+
+ if(ret) {
+ if(tmpl_end && (strcmp(tmpl_end,NODE_TAG)==0)) {
+ clind_path_pop(tmpl_path_clone);
+ tmpl_path_string = clind_path_get_path_string(tmpl_path_clone);
+ tmpl_end = clind_path_last_string(tmpl_path_clone);
+ }
+ }
+
+ if(ret && tmpl_path_string && !return_value_file_name) {
+
+ vtw_def def;
+ struct stat statbuf;
+ int fn_node_def_size=strlen(tmpl_path_string)+1+strlen(NODE_DEF)+1;
+ char* fn_node_def=(char*)malloc(fn_node_def_size);
+
+ memset(&def, 0, sizeof(def));
+
+ fn_node_def[0]=0;
+
+ if(*tmpl_path_string!='/' && root_tmpl_path) {
+ fn_node_def_size+=strlen(root_tmpl_path+1);
+ fn_node_def=(char*)realloc(fn_node_def,fn_node_def_size);
+ strcpy(fn_node_def+strlen(fn_node_def),root_tmpl_path);
+ strcpy(fn_node_def+strlen(fn_node_def),"/");
+ }
+
+ strcpy(fn_node_def+strlen(fn_node_def),tmpl_path_string);
+ strcpy(fn_node_def+strlen(fn_node_def),"/");
+ strcpy(fn_node_def+strlen(fn_node_def),NODE_DEF);
+
+ if ((lstat(fn_node_def, &statbuf) == 0)&&
+ (parse_def(&def, fn_node_def, TRUE)==0)) {
+
+ if(def.def_type != ERROR_TYPE) {
+
+ int status=0;
+ valstruct res;
+ int i=0;
+
+ memset(&res,0,sizeof(res));
+
+ for(i=0;i<*ret_size;i++) {
+
+ if(ret[i]) {
+
+ /* return the value in the correct type */
+ status = char2val(&def, ret[i], &res);
+
+ if(status==0) {
+
+ if(val_type) *val_type=res.val_type;
+
+ if(res.free_me && res.val) {
+ free(ret[i]);
+ ret[i]=res.val;
+ }
+ } else {
+ /* Bad value ? */
+ }
+ }
+ }
+ }
+
+ } else {
+
+ while(*ret_size>0) {
+ if(ret[*ret_size-1]) {
+ free(ret[*ret_size-1]);
+ }
+ *ret_size-=1;
+ }
+ free(ret);
+ ret=NULL;
+
+ }
+
+ free(fn_node_def);
+ }
+ }
+
+ clind_path_destruct(&tmpl_path_clone);
+ }
+
+ return ret;
+}
+
+/**
+ * Return TRUE if current node is a multi-node value
+ */
+static int is_multi_node(clind_path_ref tmpl_path) {
+
+ int ret=0;
+
+ if(tmpl_path) {
+
+ const char* t_end = clind_path_last_string(tmpl_path);
+
+ if(t_end && (strcmp(t_end,NODE_TAG)==0)) {
+ ret=1;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Return TRUE if current node is node.def
+ */
+static int is_node_def(clind_path_ref tmpl_path) {
+
+ int ret=0;
+
+ if(tmpl_path) {
+
+ const char* t_end = clind_path_last_string(tmpl_path);
+
+ if(t_end && (strcmp(t_end,NODE_DEF)==0)) {
+ ret=1;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Apply a single command to the configuration path.
+ * cfg_path - absolute configuration path,
+ * tmpl_path - logical template path,
+ * cmd - single reference command from the variable path.
+ * The result is the array of "derived" paths.
+ * result_len output parameter contains the array size.
+ */
+
+static clind_path_ref* clind_config_engine_apply_command(clind_path_ref cfg_path,
+ clind_path_ref tmpl_path,
+ clind_cmd *cmd,
+ int *result_len) {
+ clind_path_ref* ret=NULL;
+
+ if(cfg_path && tmpl_path && result_len && cmd) {
+
+ /*
+ printf("%s:111.111:%s:%s:%d\n",__FUNCTION__,
+ clind_path_get_path_string(cfg_path),
+ clind_path_get_path_string(tmpl_path),
+ cmd->type);
+ */
+
+ switch (cmd->type) {
+
+ case CLIND_CMD_PARENT:
+
+ {
+ *result_len=1;
+ ret=(clind_path_ref*)(malloc(*result_len * sizeof(clind_path_ref)));
+ cfg_path = clind_path_clone(cfg_path);
+ ret[0]=cfg_path;
+
+ if(is_multi_node(tmpl_path)) {
+ clind_path_pop(cfg_path);
+ clind_path_pop(tmpl_path);
+ } else if(is_node_def(tmpl_path)) {
+ clind_path_pop(tmpl_path);
+ }
+
+ clind_path_pop(cfg_path);
+ clind_path_pop(tmpl_path);
+
+ if(is_multi_node(tmpl_path)) {
+ clind_path_pop(cfg_path);
+ clind_path_pop(tmpl_path);
+ }
+ }
+
+ break;
+
+ case CLIND_CMD_SELF_NAME:
+
+ {
+ *result_len=1;
+ ret=(clind_path_ref*)(malloc(*result_len * sizeof(clind_path_ref)));
+ cfg_path = clind_path_clone(cfg_path);
+ ret[0]=cfg_path;
+
+ if(is_multi_node(tmpl_path)) {
+ clind_path_pop(cfg_path);
+ clind_path_pop(tmpl_path);
+ } else if(is_node_def(tmpl_path)) {
+ clind_path_pop(tmpl_path);
+ }
+ }
+
+ break;
+
+ case CLIND_CMD_CHILD:
+
+ {
+ *result_len=1;
+ ret=(clind_path_ref*)(malloc(*result_len * sizeof(clind_path_ref)));
+ cfg_path = clind_path_clone(cfg_path);
+ ret[0]=cfg_path;
+
+ clind_path_push(cfg_path,cmd->value);
+ clind_path_push(tmpl_path,cmd->value);
+ }
+ break;
+
+ case CLIND_CMD_NEIGHBOR:
+
+ {
+ *result_len=1;
+ ret=(clind_path_ref*)(malloc(*result_len * sizeof(clind_path_ref)));
+ cfg_path = clind_path_clone(cfg_path);
+ ret[0]=cfg_path;
+
+ if(is_multi_node(tmpl_path)) {
+ clind_path_pop(cfg_path);
+ clind_path_pop(tmpl_path);
+ } else if(is_node_def(tmpl_path)) {
+ clind_path_pop(tmpl_path);
+ }
+
+ clind_path_pop(cfg_path);
+ clind_path_pop(tmpl_path);
+
+ clind_path_push(cfg_path,cmd->value);
+ clind_path_push(tmpl_path,cmd->value);
+ }
+
+ break;
+
+ case CLIND_CMD_VALUE:
+
+ {
+ const char* t_path_string = clind_path_get_path_string(tmpl_path);
+ const char* t_end = clind_path_last_string(tmpl_path);
+ const char* c_end = clind_path_last_string(cfg_path);
+
+ *result_len=1;
+ ret=(clind_path_ref*)(malloc(*result_len * sizeof(clind_path_ref)));
+ cfg_path = clind_path_clone(cfg_path);
+ ret[0]=cfg_path;
+
+ if(t_end && (strcmp(t_end,NODE_TAG)==0)) {
+ /* do nothing, we are there already */
+ } else if(t_path_string && clind_file_exists(t_path_string,NODE_TAG)) {
+ clind_path_push(tmpl_path,NODE_TAG);
+ } else if(c_end && (strcmp(c_end,VALUE_FILE)==0)) {
+ /* do nothing, we are there already */
+ } else {
+ clind_path_push(cfg_path,VALUE_FILE);
+ }
+ }
+
+ break;
+
+ case CLIND_CMD_PARENT_VALUE:
+
+ {
+ *result_len=1;
+ ret=(clind_path_ref*)(malloc(*result_len * sizeof(clind_path_ref)));
+ cfg_path = clind_path_clone(cfg_path);
+ ret[0]=cfg_path;
+
+ if(is_multi_node(tmpl_path)) {
+ clind_path_pop(cfg_path);
+ clind_path_pop(tmpl_path);
+ } else if(is_node_def(tmpl_path)) {
+ clind_path_pop(tmpl_path);
+ }
+
+ clind_path_pop(cfg_path);
+ clind_path_pop(tmpl_path);
+ }
+
+ break;
+
+ case CLIND_CMD_MULTI_VALUE:
+
+ {
+ const char* cfg_path_string = NULL;
+
+ if(is_multi_node(tmpl_path)) {
+ clind_path_pop(cfg_path);
+ clind_path_pop(tmpl_path);
+ } else if(is_node_def(tmpl_path)) {
+ clind_path_pop(tmpl_path);
+ }
+
+ cfg_path_string = clind_path_get_path_string(cfg_path);
+
+ if(cfg_path_string) {
+
+ const char* c_end = clind_path_last_string(cfg_path);
+
+ if(c_end && (strcmp(c_end,VALUE_FILE)==0)) {
+
+ *result_len=1;
+ ret=(clind_path_ref*)(malloc(*result_len * sizeof(clind_path_ref)));
+ cfg_path = clind_path_clone(cfg_path);
+ ret[0]=cfg_path;
+
+ } else if(clind_file_exists(cfg_path_string,VALUE_FILE)) {
+
+ *result_len=1;
+ ret=(clind_path_ref*)(malloc(*result_len * sizeof(clind_path_ref)));
+ cfg_path = clind_path_clone(cfg_path);
+ ret[0]=cfg_path;
+
+ clind_path_push(cfg_path,VALUE_FILE);
+
+ } else {
+
+ DIR* dir=NULL;
+
+ dir = opendir(cfg_path_string);
+
+ if(dir) {
+
+ *result_len=0;
+
+ ret=(clind_path_ref*)(malloc(*result_len * sizeof(clind_path_ref)));
+
+ do {
+ struct dirent *de = readdir(dir);
+
+ if(!de) break;
+ else if(de->d_name[0] && de->d_name[0]!='.') {
+ clind_path_ref cfg_path_1 = clind_path_clone(cfg_path);
+ clind_path_push(cfg_path_1,de->d_name);
+ (*result_len)++;
+ ret=(clind_path_ref*)(realloc(ret,*result_len * sizeof(clind_path_ref)));
+ ret[*result_len-1]=cfg_path_1;
+ }
+ } while(1);
+
+ clind_path_push(tmpl_path,NODE_TAG);
+
+ closedir(dir);
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * cfg_path - absolute configuration path,
+ * tmpl_path - logical template path,
+ * cmd_path - variable command path.
+ */
+
+int clind_config_engine_apply_command_path(clind_path_ref cfg_path_orig,
+ clind_path_ref tmpl_path_orig,
+ clind_path_ref cmd_path,
+ int check_existence,
+ clind_val* res,
+ const char* root_cfg_path,
+ const char* root_tmpl_path,
+ int return_value_file_name) {
+
+ int ret=-1;
+
+ /*
+ printf("%s:111.111:cfg_path=%s,tmpl_path=%s,cmd_path=%s,rtp=%s\n",__FUNCTION__,
+ clind_path_get_path_string(cfg_path_orig),
+ clind_path_get_path_string(tmpl_path_orig),
+ clind_path_get_path_string(cmd_path),
+ root_tmpl_path);
+ */
+
+ if(cfg_path_orig && tmpl_path_orig && cmd_path && res) {
+
+ /* Command to be processed: */
+ clind_cmd cmd;
+
+ /* Array of configuration pointers. Initially, contains only one
+ element - cfg_path. */
+ clind_path_ref* config_paths=
+ (clind_path_ref*)malloc(sizeof(clind_path_ref)*1);
+
+ /* Size of the array (initially - just one): */
+ int config_paths_size=1;
+
+ /* Clone the input paths to preserve the input objects intact: */
+ clind_path_ref tmpl_path=NULL;
+ clind_path_ref cfg_path=NULL;
+
+ if(clind_path_is_absolute(cmd_path)) {
+ tmpl_path=clind_path_construct(root_tmpl_path);
+ if(!tmpl_path) {
+ return -1;
+ }
+ cfg_path=clind_path_construct(root_cfg_path);
+ if(!cfg_path) {
+ return -1;
+ }
+ } else {
+ cfg_path=clind_path_clone(cfg_path_orig);
+ tmpl_path=clind_path_clone(tmpl_path_orig);
+ }
+
+ res->value=NULL;
+ res->val_type=TEXT_TYPE;
+
+ /* Set the initial array content: */
+ config_paths[0]=cfg_path;
+
+ /* Apply the commands one-by-one: */
+ while(clind_path_get_size(cmd_path)>0 &&
+ (clind_path_shift_cmd(cmd_path,&cmd)==0)) {
+
+ int i=0;
+
+ /* Temporary array to keep the config paths for the next
+ command application: */
+ clind_path_ref* new_config_paths=NULL;
+ int new_config_paths_size=0;
+
+ /* This path contains the template path at the beginning
+ of the cycle: */
+ clind_path_ref tmpl_path_curr=clind_path_clone(tmpl_path);
+
+ for (i=0;i<config_paths_size;i++) {
+
+ int size=0;
+
+ clind_path_ref* new_config_paths_1=NULL;
+
+ if(i==0) {
+ new_config_paths_1=
+ clind_config_engine_apply_command(config_paths[i],
+ tmpl_path,
+ &cmd,
+ &size);
+ } else {
+ clind_path_ref tmpl_path_curr_clone=clind_path_clone(tmpl_path_curr);
+ new_config_paths_1=
+ clind_config_engine_apply_command(config_paths[i],
+ tmpl_path_curr_clone,
+ &cmd,
+ &size);
+ clind_path_destruct(&tmpl_path_curr_clone);
+ }
+
+ if(new_config_paths_1) {
+
+ int j=0;
+
+ for(j=0;j<size;j++) {
+ if(new_config_paths_1[j]) {
+ new_config_paths_size++;
+ new_config_paths=
+ (clind_path_ref*)realloc(new_config_paths,
+ sizeof(clind_path_ref)*
+ new_config_paths_size);
+ new_config_paths[new_config_paths_size-1]=new_config_paths_1[j];
+ }
+ }
+
+ free(new_config_paths_1);
+ }
+
+ clind_path_destruct(&(config_paths[i]));
+ }
+
+ free(config_paths);
+ config_paths=new_config_paths;
+ config_paths_size=new_config_paths_size;
+ clind_path_destruct(&tmpl_path_curr);
+ }
+
+ if(config_paths) {
+
+ char** sarr=NULL;
+ int sarrlen=0;
+
+ vtw_type_e val_type=TEXT_TYPE;
+
+ int i=0;
+
+ for(i=0;i<config_paths_size;i++) {
+
+ if(config_paths[i]) {
+
+ int vallen=0;
+
+ char** valarr=clind_get_current_value(config_paths[i],
+ tmpl_path,
+ check_existence,
+ &val_type,
+ root_tmpl_path,
+ return_value_file_name,
+ /*Last command: */
+ (cmd.type==CLIND_CMD_MULTI_VALUE),
+ &vallen);
+
+ clind_path_destruct(&config_paths[i]);
+
+ if(valarr) {
+
+ int k=0;
+
+ for(k=0;k<vallen;k++) {
+
+ char* s=valarr[k];
+
+ if(s) {
+
+ /* search if we already have it: */
+ int j=0;
+ for(j=0;j<sarrlen;j++) {
+ if(!strcmp(sarr[j],s)) {
+ break;
+ }
+ }
+
+ if(j<sarrlen) {
+ free(s);
+ } else {
+ sarrlen++;
+ sarr=(char**)realloc(sarr,sizeof(char*)*sarrlen);
+ sarr[sarrlen-1]=s;
+ }
+ }
+ }
+ free(valarr);
+ }
+ }
+ }
+
+ free(config_paths);
+
+ if(sarr) {
+
+ ret=0;
+
+ if(sarrlen==1) {
+
+ res->value=sarr[0];
+
+ } else {
+
+ for(i=0;i<sarrlen;i++) {
+
+ if(sarr[i]) {
+
+ char* s = clind_quote(sarr[i]);
+
+ free(sarr[i]);
+ sarr[i]=NULL;
+
+ if(s) {
+
+ if(!res->value) {
+
+ res->value=s;
+
+ } else if(res->value[0]==0) {
+
+ free(res->value);
+ res->value=s;
+
+ } else {
+
+ res->value=(char*)realloc(res->value,
+ strlen(res->value)+1+strlen(s)+1);
+
+ strcpy(res->value+strlen(res->value)," ");
+ strcpy(res->value+strlen(res->value),s);
+
+ free(s);
+ }
+ }
+ }
+ }
+ }
+ free(sarr);
+ }
+ }
+
+ clind_path_destruct(&cmd_path);
+ clind_path_destruct(&cfg_path);
+ clind_path_destruct(&tmpl_path);
+ }
+
+ return ret;
+}
+
+/******************************
+ * Cmd utils.
+ *
+ ******************************/
+
+static int clind_path_shift_cmd(clind_path_ref path,clind_cmd *cmd) {
+
+ int ret=-1;
+
+ if(cmd) {
+
+ cmd->type = CLIND_CMD_UNKNOWN;
+ cmd->value[0]=0;
+
+ if(path && clind_path_get_size(path)>0) {
+
+ int i=0;
+ int done=0;
+
+ while(cmd_parse_definitions[i].text!=NULL && cmd_parse_definitions[i].text[0]!=NULL) {
+
+ int j=0;
+
+ while(cmd_parse_definitions[i].text[j]) {
+ const char* str = clind_path_get_string(path,j);
+ if(str) {
+ if(!strcmp(cmd_parse_definitions[i].text[j],"*")) {
+ if(*str!='.' && *str!='@') {
+ j++;
+ strncpy(cmd->value,str,sizeof(cmd->value)-1);
+ continue;
+ }
+ } else if(!strcmp(cmd_parse_definitions[i].text[j],str)) {
+ j++;
+ strncpy(cmd->value,str,sizeof(cmd->value)-1);
+ continue;
+ }
+ }
+ j=0;
+ break;
+ }
+
+ if(j<1) {
+ i++;
+ continue;
+ } else {
+ done=1;
+ }
+
+ cmd->type = cmd_parse_definitions[i].cmd_type;
+
+ while(j) {
+ clind_path_shift(path);
+ j--;
+ }
+
+ break;
+ }
+
+ if(done) {
+ ret=0;
+ }
+ }
+ }
+
+ return ret;
+}
+