Esempio n. 1
0
/*! Reset cligen variable vector resetting it to an initial state as returned by cvec_new
 *
 * @param[in]  cvv   Cligen variable vector
 * @see also cvec_free. But this function does not actually free the cvec.
 */
int
cvec_reset(cvec *cvv)
{
    cg_var *cv = NULL;
    
    while ((cv = cvec_each(cvv, cv)) != NULL)  
	cv_reset(cv);
    if (cvv->vr_vec)
	free(cvv->vr_vec);
    if (cvv->vr_name)
	free(cvv->vr_name);
    memset(cvv, 0, sizeof(*cvv));
    return 0;
}
Esempio n. 2
0
/*
 * Help function to append a cv to a cvec. For expansion cvec passed to pt_expand_2
 * IN:
 *  co     A cligen variable that has a matching value
 *  cmd    Value in string of the variable
 * OUT:
 *  cvec   The cligen variable vector to push a cv with name of co and value in cmd
 */
static cg_var *
add_cov_to_cvec(cg_obj *co, char *cmd, cvec *cvec)
{
    cg_var *cv = NULL;

    if ((cv = cvec_add(cvec, co->co_vtype)) == NULL)
	return NULL;
    cv_name_set(cv, co->co_command);
    cv_const_set(cv, iskeyword(co));
    if (cv_parse(cmd, cv) < 0) {
	cv_reset(cv);
	cvec_del(cvec, cv);
	return NULL;
    }
    return cv;
}
Esempio n. 3
0
/*
 * match_pattern_node
 * Non-terminal. Need to match exact.
 * INPUT:
 *   h         CLIgen handle
 *   string0   Input string to match
 *   pt        Vector of commands (array of cligen object pointers (cg_obj)
 *   pt_max    Length of the pt array
 *   level     How many levels (words) into string0
 *   use_pref  Set this flag value if you want to use the preferences between
 *             matches. It is only when you want a final exact match (not 
 *             completion or show options) that you should set this.
 * RETURNS:
 *   The number of matches (0-n) in pt or -1 on error. See matchlen below.
 * OUTPUT:
 *   ptp       Returns the vector at the place of matching
 *   matchv    A vector of integers containing which 
 *   matchlen  Length of matchv. That is, # of matches and same as return 
 *              value (if 0-n)
 *   cvec      cligen variable vector containing vars/values pair for completion
 *   reason0   If retval = 0, this may be malloced to indicate reason for not
 *             matching variables, if given. Need to be free:d
 */
static int 
match_pattern_node(cligen_handle h, 
		   char *string0, 
		   parse_tree pt,
		   int level, 
		   int use_pref, 
		   int hide,
		   pt_vec *ptp, 
		   int *matchv[], 
		   int *matchlen,
		   cvec  *cvec,
		   char **reason0
		   )
{
    char *string = NULL;
    int i;
    int match;
    int matches = 0;
    int perfect = 0;
    int retval = -1;
    cg_obj *co, *co_match;
    cg_obj *co_orig;
    int rest_match = -1;
    int cmd_levels;
    int p;
    int preference = 0;
    int exact;
    char *reason;
    int findreason;
    parse_tree ptn={0,};     /* Expanded */
    cg_var *cv = NULL;

    co_match = NULL;
    if (level > command_levels(string0)){
	fprintf(stderr, "%s: level > command_level in %s\n",
		__FUNCTION__, string0);
	return -1;
    }
    /* If there are only variables in the list, then keep track of variable match errors */
    findreason = 0;
    if (reason0)
	for (i=0; i<pt.pt_len; i++){ 
	    if ((co = pt.pt_vec[i]) == NULL)
		continue;
	    if (co->co_type != CO_VARIABLE){
		findreason = 0;
		break;
	    }
	    findreason++;
	}
    extract_substring(string0, level, &string);
    for (i=0; i<pt.pt_len; i++){
	if ((co = pt.pt_vec[i]) == NULL)
	    continue;
	reason = NULL;
	if ((match = match_object(string, co, &exact, findreason?&reason:NULL)) < 0)
	    goto error;
	if (match){
	    assert(reason==NULL);
	    /* Special case to catch rest variable and space delimited
	       arguments after it */
	    if (co->co_type == CO_VARIABLE && co->co_vtype == CGV_REST)
		rest_match = i;
	    if (match_perfect(string, co)){
		if (!perfect){
		    matches = 0;
		    perfect = 1;
		}
	    }
	    else{
		if (perfect)
		    break;
 		if (1 || use_pref){
		    p = co_pref(co, exact);
		    if (p < preference)
			continue; /* ignore */
		    if (p > preference){
			preference = p;
			matches = 0; /* Start again at this level */
		    }
		}
	    }
	    co_match = co;
	    matches++;
	}
	/* match == 0, co type is variable and findreason, then reason is set 
	   this may not be the best preference, we just set the first
	*/
	if (reason){
	    if (*reason0 == NULL)
		*reason0 = reason;
	    reason = NULL;
	    findreason = 0;
	}
    } /* for */
    if (matches != 0 && reason0 && *reason0){
	    free(*reason0);
	    *reason0 = NULL;
	}

    if (matches != 1) {
#ifdef notneeded
	if (matches == 0){
	    cligen_nomatch_set(h, "Unrecognized command");
	}
	else
	    cligen_nomatch_set(h, "Ambigious command");
#endif
	retval = 0;
	goto quit;
    }
    assert(co_match);
    if ((cmd_levels = command_levels(string0)) < 0)
	goto error;

    /* co_orig is original object in case of expansion */
    co_orig = co_match->co_ref?co_match->co_ref: co_match;
    if (pt_expand_1(h, co_match, &co_match->co_pt) < 0) /* sub-tree expansion */
	goto error; 

    if (co_match->co_type == CO_VARIABLE){
	if ((cv = add_cov_to_cvec(co_match, string, cvec)) == NULL)
	    goto error;
    }
    else
	if (co_match->co_type == CO_COMMAND && co_orig->co_type == CO_VARIABLE)
	    if ((cv = add_cov_to_cvec(co_orig, string, cvec)) == NULL)
		goto error;
    if (pt_expand_2(h, &co_match->co_pt, cvec, &ptn, hide) < 0) /* expand/choice variables */
	goto error;
    if (level+1 == cmd_levels)
	retval = match_pattern_terminal(h,
					string0, ptn, 
					level+1, use_pref,
					ptp, matchv, matchlen, reason0);
    else
	retval = match_pattern_node(h, 
				    string0, ptn,
				    level+1, use_pref, hide,
				    ptp, matchv, matchlen, cvec, reason0);

    if (pt_expand_add(co_orig, ptn) < 0) /* add expanded ptn to orig parsetree */
	goto error;
    if (co_match->co_type == CO_COMMAND && co_orig->co_type == CO_VARIABLE)
	if (co_value_set(co_orig, co_match->co_command) < 0)
	    goto error;


    /* Cleanup made on top-level */
    
    /* 
     * Special case: we have matched a REST variable (anything) and
     * there is more text have this word, then we can match REST
     */
    if (retval == 0 && rest_match != -1){
	retval = 1;
	if (*matchlen < 1){
	    *matchlen = 1;
	    if ((*matchv = realloc(*matchv, (*matchlen)*sizeof(int))) == NULL){
		fprintf(stderr, "%s: realloc: %s\n", __FUNCTION__, strerror(errno));
		return -1;
	    }
	}
	else
	    *matchlen = 1;
	*ptp = pt.pt_vec;
	(*matchv)[0] = rest_match;
    }
  quit:
    if (cv){ /* cv may be stale */
	cv = cvec_i(cvec, cvec_len(cvec)-1);
	cv_reset(cv);
	cvec_del(cvec, cv);
    }
    /* Only the last level may have multiple matches */
    if (string)
	free(string);
    return retval;
  error:
    retval = -1;
    goto quit;
}