Example #1
0
int
cmdline_complete(struct cmdline *cl, const char *buf, int *state,
		 char *dst, unsigned int size)
{
	const char *partial_tok = buf;
	unsigned int inst_num = 0;
	cmdline_parse_inst_t *inst;
	cmdline_parse_token_hdr_t *token_p;
	struct cmdline_token_hdr token_hdr;
	char tmpbuf[CMDLINE_BUFFER_SIZE], comp_buf[CMDLINE_BUFFER_SIZE];
	unsigned int partial_tok_len;
	int comp_len = -1;
	int tmp_len = -1;
	int nb_token = 0;
	unsigned int i, n;
	int l;
	unsigned int nb_completable;
	unsigned int nb_non_completable;
	int local_state = 0;
	const char *help_str;
	cmdline_parse_ctx_t *ctx;

	if (!cl || !buf || !state || !dst)
		return -1;

	ctx = cl->ctx;

	debug_printf("%s called\n", __func__);
	memset(&token_hdr, 0, sizeof(token_hdr));

	/* count the number of complete token to parse */
	for (i=0 ; buf[i] ; i++) {
		if (!isblank2(buf[i]) && isblank2(buf[i+1]))
			nb_token++;
		if (isblank2(buf[i]) && !isblank2(buf[i+1]))
			partial_tok = buf+i+1;
	}
	partial_tok_len = strnlen(partial_tok, RDLINE_BUF_SIZE);

	/* first call -> do a first pass */
	if (*state <= 0) {
		debug_printf("try complete <%s>\n", buf);
		debug_printf("there is %d complete tokens, <%s> is incomplete\n",
			     nb_token, partial_tok);

		nb_completable = 0;
		nb_non_completable = 0;

		inst = ctx[inst_num];
		while (inst) {
			/* parse the first tokens of the inst */
			if (nb_token &&
			    match_inst(inst, buf, nb_token, NULL, 0))
				goto next;

			debug_printf("instruction match\n");
			token_p = get_token(inst, nb_token);
			if (token_p)
				memcpy(&token_hdr, token_p, sizeof(token_hdr));

			/* non completable */
			if (!token_p ||
			    !token_hdr.ops->complete_get_nb ||
			    !token_hdr.ops->complete_get_elt ||
			    (n = token_hdr.ops->complete_get_nb(token_p)) == 0) {
				nb_non_completable++;
				goto next;
			}

			debug_printf("%d choices for this token\n", n);
			for (i=0 ; i<n ; i++) {
				if (token_hdr.ops->complete_get_elt(token_p, i,
								    tmpbuf,
								    sizeof(tmpbuf)) < 0)
					continue;

				/* we have at least room for one char */
				tmp_len = strnlen(tmpbuf, sizeof(tmpbuf));
				if (tmp_len < CMDLINE_BUFFER_SIZE - 1) {
					tmpbuf[tmp_len] = ' ';
					tmpbuf[tmp_len+1] = 0;
				}

				debug_printf("   choice <%s>\n", tmpbuf);

				/* does the completion match the
				 * beginning of the word ? */
				if (!strncmp(partial_tok, tmpbuf,
					     partial_tok_len)) {
					if (comp_len == -1) {
						snprintf(comp_buf, sizeof(comp_buf),
							 "%s", tmpbuf + partial_tok_len);
						comp_len =
							strnlen(tmpbuf + partial_tok_len,
									sizeof(tmpbuf) - partial_tok_len);

					}
					else {
						comp_len =
							nb_common_chars(comp_buf,
									tmpbuf+partial_tok_len);
						comp_buf[comp_len] = 0;
					}
					nb_completable++;
				}
			}
		next:
			debug_printf("next\n");
			inst_num ++;
			inst = ctx[inst_num];
		}

		debug_printf("total choices %d for this completion\n",
			     nb_completable);

		/* no possible completion */
		if (nb_completable == 0 && nb_non_completable == 0)
			return 0;

		/* if multichoice is not required */
		if (*state == 0 && partial_tok_len > 0) {
			/* one or several choices starting with the
			   same chars */
			if (comp_len > 0) {
				if ((unsigned)(comp_len + 1) > size)
					return 0;

				snprintf(dst, size, "%s", comp_buf);
				dst[comp_len] = 0;
				return 2;
			}
		}
	}

	/* init state correctly */
	if (*state == -1)
		*state = 0;

	debug_printf("Multiple choice STATE=%d\n", *state);

	inst_num = 0;
	inst = ctx[inst_num];
	while (inst) {
		/* we need to redo it */
		inst = ctx[inst_num];

		if (nb_token &&
		    match_inst(inst, buf, nb_token, NULL, 0))
			goto next2;

		token_p = get_token(inst, nb_token);
		if (token_p)
			memcpy(&token_hdr, token_p, sizeof(token_hdr));

		/* one choice for this token */
		if (!token_p ||
		    !token_hdr.ops->complete_get_nb ||
		    !token_hdr.ops->complete_get_elt ||
		    (n = token_hdr.ops->complete_get_nb(token_p)) == 0) {
			if (local_state < *state) {
				local_state++;
				goto next2;
			}
			(*state)++;
			if (token_p && token_hdr.ops->get_help) {
				token_hdr.ops->get_help(token_p, tmpbuf,
							sizeof(tmpbuf));
				help_str = inst->help_str;
				if (help_str)
					snprintf(dst, size, "[%s]: %s", tmpbuf,
						 help_str);
				else
					snprintf(dst, size, "[%s]: No help",
						 tmpbuf);
			}
			else {
				snprintf(dst, size, "[RETURN]");
			}
			return 1;
		}

		/* several choices */
		for (i=0 ; i<n ; i++) {
			if (token_hdr.ops->complete_get_elt(token_p, i, tmpbuf,
							    sizeof(tmpbuf)) < 0)
				continue;
			/* we have at least room for one char */
			tmp_len = strnlen(tmpbuf, sizeof(tmpbuf));
			if (tmp_len < CMDLINE_BUFFER_SIZE - 1) {
				tmpbuf[tmp_len] = ' ';
				tmpbuf[tmp_len + 1] = 0;
			}

			debug_printf("   choice <%s>\n", tmpbuf);

			/* does the completion match the beginning of
			 * the word ? */
			if (!strncmp(partial_tok, tmpbuf,
				     partial_tok_len)) {
				if (local_state < *state) {
					local_state++;
					continue;
				}
				(*state)++;
				l=snprintf(dst, size, "%s", tmpbuf);
				if (l>=0 && token_hdr.ops->get_help) {
					token_hdr.ops->get_help(token_p, tmpbuf,
								sizeof(tmpbuf));
					help_str = inst->help_str;
					if (help_str)
						snprintf(dst+l, size-l, "[%s]: %s",
							 tmpbuf, help_str);
					else
						snprintf(dst+l, size-l,
							 "[%s]: No help", tmpbuf);
				}

				return 1;
			}
		}
	next2:
		inst_num ++;
		inst = ctx[inst_num];
	}
	return 0;
}
Example #2
0
int8_t 
complete(parse_pgm_ctx_t ctx[], const char *buf, int16_t *state, 
	 char *dst, uint8_t size)
{
	const char * incomplete_token = buf;
	uint8_t inst_num = 0;
	parse_pgm_inst_t *inst;
	parse_pgm_token_hdr_t *token_p;
	struct token_hdr token_hdr;
	char tmpbuf[64], completion_buf[64];
	uint8_t incomplete_token_len;
	int8_t completion_len = -1;
	int8_t nb_token = 0;
	uint8_t i, n;
	int8_t l;
	uint8_t nb_completable;
	uint8_t nb_non_completable;
	uint16_t local_state=0;
	prog_char *help_str;

	debug_printf("%s called\n", __FUNCTION__);
	/* count the number of complete token to parse */
	for (i=0 ; buf[i] ; i++) {
		if (!isblank(buf[i]) && isblank(buf[i+1]))
			nb_token++;
		if (isblank(buf[i]) && !isblank(buf[i+1]))
			incomplete_token = buf+i+1;
	}
	incomplete_token_len = strlen(incomplete_token);

	/* first call -> do a first pass */
	if (*state <= 0) {
		debug_printf("try complete <%s>\n", buf);
		debug_printf("there is %d complete tokens, <%s> is incomplete\n", nb_token, incomplete_token);

		nb_completable = 0;
		nb_non_completable = 0;
		
		inst = (parse_pgm_inst_t *)pgm_read_word(ctx+inst_num);
		while (inst) {
			/* parse the first tokens of the inst */
			if (nb_token && match_inst(inst, buf, nb_token, NULL))
				goto next;
			
			debug_printf("instruction match \n");
			token_p = (parse_pgm_token_hdr_t *) pgm_read_word(&inst->tokens[nb_token]);
			if (token_p)
				memcpy_P(&token_hdr, token_p, sizeof(token_hdr));

			/* non completable */
			if (!token_p || 
			    !token_hdr.ops->complete_get_nb || 
			    !token_hdr.ops->complete_get_elt || 
			    (n = token_hdr.ops->complete_get_nb(token_p)) == 0) {
				nb_non_completable++;
				goto next;
			}

			debug_printf("%d choices for this token\n", n);
			for (i=0 ; i<n ; i++) {
				if (token_hdr.ops->complete_get_elt(token_p, i, tmpbuf, sizeof(tmpbuf)) < 0)
					continue;
				strcat_P(tmpbuf, PSTR(" ")); /* we have at least room for one char */
				debug_printf("   choice <%s>\n", tmpbuf);
				/* does the completion match the beginning of the word ? */
				if (!strncmp(incomplete_token, tmpbuf, incomplete_token_len)) {
					if (completion_len == -1) {
						strcpy(completion_buf, tmpbuf+incomplete_token_len);
						completion_len = strlen(tmpbuf+incomplete_token_len);
						
					}
					else {
						completion_len = nb_common_chars(completion_buf, 
										 tmpbuf+incomplete_token_len);
						completion_buf[completion_len] = 0;
					}
					nb_completable++;
				}
			}		
		next:
			inst_num ++;
			inst = (parse_pgm_inst_t *)pgm_read_word(ctx+inst_num);
		}

		debug_printf("total choices %d for this completion\n", nb_completable);

		/* no possible completion */
		if (nb_completable == 0 && nb_non_completable == 0)
			return 0;
		
		/* if multichoice is not required */
		if (*state == 0 && incomplete_token_len > 0) {
			/* one or several choices starting with the
			   same chars */
			if (completion_len > 0) { 
				if (completion_len + 1 > size)
					return 0;
				
				strcpy(dst, completion_buf);
				return 2;
			}
		}
	}

	/* init state correctly */
	if (*state == -1)
		*state = 0;

	debug_printf("Multiple choice STATE=%d\n", *state);

	inst_num = 0;
	inst = (parse_pgm_inst_t *)pgm_read_word(ctx+inst_num);
	while (inst) {
		/* we need to redo it */
		inst = (parse_pgm_inst_t *)pgm_read_word(ctx+inst_num);
		
		if (nb_token && match_inst(inst, buf, nb_token, NULL))
			goto next2;
		
		token_p = (parse_pgm_token_hdr_t *)pgm_read_word(&inst->tokens[nb_token]);
		if (token_p)
			memcpy_P(&token_hdr, token_p, sizeof(token_hdr));

		/* one choice for this token */
		if (!token_p || 
		    !token_hdr.ops->complete_get_nb || 
		    !token_hdr.ops->complete_get_elt || 
		    (n = token_hdr.ops->complete_get_nb(token_p)) == 0) {
			if (local_state < *state) {
				local_state++;
				goto next2;
			}
			(*state)++;
			if (token_p && token_hdr.ops->get_help) {
				token_hdr.ops->get_help(token_p, tmpbuf, sizeof(tmpbuf));
				help_str = (prog_char *) pgm_read_word(&inst->help_str);
				if (help_str)
					snprintf_P(dst, size, PSTR("[%s]: %S"), tmpbuf, help_str);
				else
					snprintf_P(dst, size, PSTR("[%s]: No help"), tmpbuf);
			}
			else {
				snprintf_P(dst, size, PSTR("[RETURN]"));
			}
			return 1;
		}

		/* several choices */
		for (i=0 ; i<n ; i++) {
			if (token_hdr.ops->complete_get_elt(token_p, i, tmpbuf, sizeof(tmpbuf)) < 0)
				continue;
			strcat_P(tmpbuf, PSTR(" ")); /* we have at least room for one char */
			debug_printf("   choice <%s>\n", tmpbuf);
			/* does the completion match the beginning of the word ? */
			if (!strncmp(incomplete_token, tmpbuf, incomplete_token_len)) {
				if (local_state < *state) {
					local_state++;
					continue;
				}
				(*state)++;
				l=snprintf(dst, size, "%s", tmpbuf);
				if (l>=0 && token_hdr.ops->get_help) {
					token_hdr.ops->get_help(token_p, tmpbuf, sizeof(tmpbuf));
					help_str = (prog_char *) pgm_read_word(&inst->help_str);
					if (help_str)
						snprintf_P(dst+l, size-l, PSTR("[%s]: %S"), tmpbuf, help_str);
					else
						snprintf_P(dst+l, size-l, PSTR("[%s]: No help"), tmpbuf);
				}
							      
				return 1;
			}
		}
	next2:
		inst_num ++;
		inst = (parse_pgm_inst_t *)pgm_read_word(ctx+inst_num);
	}
	return 0;
}