i finally got tired of pounding on the tab key to auto-complete options to commands just to have urjtag respond back with useless stuff. so i rewrote the readline completion support and now any command can have its options auto-completed by declaring a completion handler.
for example: jtag> help <tab> - all of the possible commands will be shown jtag> cable <tab> - all of the possible cables will be shown jtag> initbus <tab> - all of the possible buses will be shown jtag> instruction <tab> - all of the registered instructions will be shown etc... below you can find the patch. any feedback before i commit things ? -mike diff --git a/urjtag/include/urjtag/cmd.h b/urjtag/include/urjtag/cmd.h index 849313c..b7ea807 100644 --- a/urjtag/include/urjtag/cmd.h +++ b/urjtag/include/urjtag/cmd.h @@ -42,18 +42,18 @@ * handled in the same way, urj_error is set to #URJ_ERROR_SYNTAX. */ int urj_cmd_run (urj_chain_t *chain, char *params[]); + /** - * Search through registered commands + * Attempt completion of part of a command string * - * @param text match commands whose prefix equals <code>text</code>. Rotates - * through the registered commands. The prefix length is set when - * the rotating state is reset. - * @@@@ RFHH that is weird behaviour. Why not do the prefix length as strlen(text)? - * @param state if 0, reset the rotating state to start from the beginning + * @param chain chain to possibly use for some completions + * @param line full (incomplete) command line + * @param point current cursor position in the line * - * @return malloc'ed value. The caller is responsible for freeing it. - * NULL for malloc failure or end of command list. + * @return malloc'ed array of strings. The caller is responsible for freeing + * all of them, and the array itself. NULL for malloc failure or end of + * possible completions. */ -char *urj_cmd_find_next (const char *text, int state); +char **urj_cmd_complete (urj_chain_t *chain, const char *line, int point); #endif /* URJ_CMD_H */ diff --git a/urjtag/include/urjtag/parse.h b/urjtag/include/urjtag/parse.h index 141a882..fa7524a 100644 --- a/urjtag/include/urjtag/parse.h +++ b/urjtag/include/urjtag/parse.h @@ -30,6 +30,22 @@ #include "types.h" /** + * Turn a string into a bunch of tokens (space delimited). Returns the + * number of tokens via token_cnt. Memory is all allocated as needed, so + * tokens should be passed to urj_tokens_free() when finished. + * + * @return + * URJ_STATUS_OK on success + * URJ_STATUS_ERROR on error + */ +int urj_tokenize_line (const char *line, char ***tokens, size_t *token_cnt); + +/** + * Free memory allocated for the tokens by urj_tokenize_line(). + */ +void urj_tokens_free (char **tokens); + +/** * Take care of tokenizing the line before sending to urj_cmd_run(). * * @return diff --git a/urjtag/src/apps/jtag/jtag.c b/urjtag/src/apps/jtag/jtag.c index 30751de..af60cc9 100644 --- a/urjtag/src/apps/jtag/jtag.c +++ b/urjtag/src/apps/jtag/jtag.c @@ -152,13 +152,31 @@ jtag_create_jtagdir (void) #ifdef HAVE_LIBREADLINE #ifdef HAVE_READLINE_COMPLETION -static char ** -urj_cmd_completion (const char *text, int start, int end) +static urj_chain_t *active_chain; + +static char * +urj_cmd_completion (const char *text, int matches) { - char **ret = NULL; + /* Cache the current set of matches */ + static char **all_matches = NULL; + static int idx; + char *ret = NULL; + + if (matches == 0) + { /* Build new list of completions */ + free (all_matches); + all_matches = NULL; + idx = 0; + + all_matches = urj_cmd_complete (active_chain, rl_line_buffer, rl_point); + } - if (start == 0) - ret = rl_completion_matches (text, urj_cmd_find_next); + if (all_matches) + { + ret = all_matches[idx]; + if (ret) + ++idx; + } return ret; } @@ -544,10 +562,12 @@ main (int argc, char *const argv[]) #ifdef HAVE_LIBREADLINE #ifdef HAVE_READLINE_COMPLETION + active_chain = chain; + rl_readline_name = "urjtag"; rl_completer_quote_characters = "\""; rl_filename_completion_desired = 1; rl_filename_quote_characters = " "; - rl_attempted_completion_function = urj_cmd_completion; + rl_completion_entry_function = urj_cmd_completion; #endif #endif diff --git a/urjtag/src/cmd/cmd.h b/urjtag/src/cmd/cmd.h index 9a63daf..059920c 100644 --- a/urjtag/src/cmd/cmd.h +++ b/urjtag/src/cmd/cmd.h @@ -47,6 +47,8 @@ typedef struct /** @return URJ_STATUS_OK on success; URJ_STATUS_FAIL on error, both * syntax and library errors */ int (*run) (urj_chain_t *chain, char *params[]); + void (*complete) (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point); } urj_cmd_t; #define _URJ_CMD(cmd) extern const urj_cmd_t urj_cmd_##cmd; @@ -87,4 +89,13 @@ do { \ arr[i]->name, _(arr[i]->description)); \ } while (0) +/** + */ +void urj_completion_add_match (char ***matches, size_t *cnt, char *match); +void urj_completion_add_match_dupe (char ***matches, size_t *cnt, const char *match); +void urj_completion_maybe_add_match (char ***matches, size_t *cnt, const char *text, const char *match); +void urj_completion_mayben_add_match (char ***matches, size_t *cnt, const char *text, size_t text_len, const char *match); + +void cmd_signal_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, const char *text, size_t text_len); + #endif /* URJ_CMD_H */ diff --git a/urjtag/src/cmd/cmd_bfin.c b/urjtag/src/cmd/cmd_bfin.c index 15b67d1..573bff7 100644 --- a/urjtag/src/cmd/cmd_bfin.c +++ b/urjtag/src/cmd/cmd_bfin.c @@ -493,9 +493,22 @@ cmd_bfin_help (void) "bfin", "bfin", "bfin" ); } +static void +cmd_bfin_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + if (token_point != 1) + return; + + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "execute"); + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "emulation"); + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "reset"); +} + const urj_cmd_t urj_cmd_bfin = { "bfin", N_("Blackfin specific commands"), cmd_bfin_help, - cmd_bfin_run + cmd_bfin_run, + cmd_bfin_complete, }; diff --git a/urjtag/src/cmd/cmd_cable.c b/urjtag/src/cmd/cmd_cable.c index 49366fd..3fd5700 100644 --- a/urjtag/src/cmd/cmd_cable.c +++ b/urjtag/src/cmd/cmd_cable.c @@ -194,9 +194,32 @@ cmd_cable_help (void) urj_cmd_show_list (urj_tap_cable_drivers); } +static void +cmd_cable_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + size_t i; + + switch (token_point) + { + case 1: + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "probe"); + + for (i = 0; urj_tap_cable_drivers[i]; i++) + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, + urj_tap_cable_drivers[i]->name); + break; + case 2: + /* XXX: in the future, we want to complete cable options too */ + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "help"); + break; + } +} + const urj_cmd_t urj_cmd_cable = { "cable", N_("select JTAG cable"), cmd_cable_help, - cmd_cable_run + cmd_cable_run, + cmd_cable_complete, }; diff --git a/urjtag/src/cmd/cmd_cmd.c b/urjtag/src/cmd/cmd_cmd.c index 0fe0954..de4eb06 100644 --- a/urjtag/src/cmd/cmd_cmd.c +++ b/urjtag/src/cmd/cmd_cmd.c @@ -26,10 +26,11 @@ #include <stdio.h> #include <string.h> +#include <ctype.h> #include <urjtag/error.h> #include <urjtag/chain.h> - +#include <urjtag/parse.h> #include <urjtag/cmd.h> #include "cmd.h" @@ -42,36 +43,130 @@ const urj_cmd_t * const urj_cmds[] = { /* * @param text match commands whose prefix equals <code>text</code>. Rotates - * through the registered commands. The prefix length is set when - * the rotating state is reset. - * @@@@ RFHH that is weird behaviour. Why not do the prefix length as strlen(text)? + * through the registered commands. The prefix length is set when the + * rotating state is reset. This is the behavior as dictated by readline. */ -char * -urj_cmd_find_next (const char *text, int state) +static const urj_cmd_t * +urj_cmd_find (const char *text, ssize_t last_idx) { - static size_t cmd_idx, len; - char *next = NULL; + static size_t len; + const urj_cmd_t *ret; - if (!state) - { - cmd_idx = 0; + if (last_idx == -1) len = strlen (text); + + while (urj_cmds[++last_idx]) + { + ret = urj_cmds[last_idx]; + if (!strncmp (ret->name, text, len)) + return ret; } - while (urj_cmds[cmd_idx]) + return NULL; +} + +/* These three funcs are meant to be used by sub-command completers */ +void +urj_completion_add_match (char ***matches, size_t *cnt, char *match) +{ + *matches = realloc (*matches, sizeof (**matches) * (*cnt + 2)); + (*matches)[(*cnt)++] = match; +} + +void +urj_completion_add_match_dupe (char ***matches, size_t *cnt, const char *match) +{ + urj_completion_add_match (matches, cnt, strdup (match)); +} + +void +urj_completion_mayben_add_match (char ***matches, size_t *cnt, const char *text, + size_t text_len, const char *match) +{ + if (!strncmp (text, match, text_len)) + urj_completion_add_match_dupe (matches, cnt, match); +} + +void +urj_completion_maybe_add_match (char ***matches, size_t *cnt, const char *text, + const char *match) +{ + urj_completion_mayben_add_match (matches, cnt, text, strlen (text), match); +} + +static size_t +urt_completion_find_token_point (const char *line, int point) +{ + const char *cs = line; + size_t token_point = 0; + + /* Skip all leading whitespace first to make 2nd loop easier */ + while (isspace (*cs)) + ++cs; + + while (*cs) { - char *name = urj_cmds[cmd_idx++]->name; - if (!strncmp (name, text, len)) - { - next = strdup (name); - if (next == NULL) - urj_error_set (URJ_ERROR_OUT_OF_MEMORY, "strdup(%s) fails", - name); + if (point <= (cs - line)) break; + + ++cs; + + if (isspace (*cs)) + { + ++token_point; + while (isspace (*cs)) + ++cs; } } - return next; + return token_point; +} + +char ** +urj_cmd_complete (urj_chain_t *chain, const char *line, int point) +{ + char **tokens, **ret; + size_t token_cnt, token_point, ret_cnt; + const urj_cmd_t *cmd; + const char *name; + + /* Split up the current line to make completion easier */ + if (urj_tokenize_line (line, &tokens, &token_cnt)) + return NULL; + if (token_cnt == 0) + name = ""; + else + name = tokens[0]; + + ret = NULL; + ret_cnt = 0; + + /* Figure out which token we're pointing to */ + token_point = urt_completion_find_token_point (line, point); + + /* Are we completing the command itself ? Re-use the 'help' ... */ + if (token_point == 0) + name = "help"; + + /* Figure out options for which command we want to complete */ + cmd = urj_cmd_find (name, -1); + if (cmd && cmd->complete) + { + if (token_cnt) + name = tokens[token_point] ? : ""; + else + name = ""; + + cmd->complete (chain, &ret, &ret_cnt, name, strlen (name), token_point); + + if (ret_cnt) + ret[ret_cnt] = NULL; + } + + if (token_cnt) + urj_tokens_free (tokens); + + return ret; } int diff --git a/urjtag/src/cmd/cmd_get.c b/urjtag/src/cmd/cmd_get.c index 2863862..7a52419 100644 --- a/urjtag/src/cmd/cmd_get.c +++ b/urjtag/src/cmd/cmd_get.c @@ -92,9 +92,20 @@ cmd_get_help (void) "get"); } +static void +cmd_get_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + if (token_point != 1) + return; + + cmd_signal_complete (chain, matches, match_cnt, text, text_len); +} + const urj_cmd_t urj_cmd_get = { "get", N_("get external signal value"), cmd_get_help, - cmd_get_run + cmd_get_run, + cmd_get_complete, }; diff --git a/urjtag/src/cmd/cmd_help.c b/urjtag/src/cmd/cmd_help.c index 117ddc4..1081828 100644 --- a/urjtag/src/cmd/cmd_help.c +++ b/urjtag/src/cmd/cmd_help.c @@ -78,9 +78,25 @@ cmd_help_help (void) "help"); } +static void +cmd_help_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + size_t i; + + /* Completing the command itself will come here as token 0 */ + if (token_point > 1) + return; + + for (i = 0; urj_cmds[i]; ++i) + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, + urj_cmds[i]->name); +} + const urj_cmd_t urj_cmd_help = { "help", N_("display this help"), cmd_help_help, - cmd_help_run + cmd_help_run, + cmd_help_complete, }; diff --git a/urjtag/src/cmd/cmd_include.c b/urjtag/src/cmd/cmd_include.c index b354877..e2f3043 100644 --- a/urjtag/src/cmd/cmd_include.c +++ b/urjtag/src/cmd/cmd_include.c @@ -29,6 +29,10 @@ #include <stdlib.h> #include <string.h> +#ifdef HAVE_LIBREADLINE +#include <readline/readline.h> +#endif + #include <urjtag/error.h> #include <urjtag/parse.h> #include <urjtag/jtag.h> @@ -97,11 +101,55 @@ cmd_include_help (void) cmd_include_or_script_help ("include"); } +static void +cmd_include_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ +#ifdef HAVE_LIBREADLINE + int state; + size_t implicit_len; + char *match, *search_text; + + /* Use the search path if path isn't explicitly relative/absolute */ + if (text[0] != '/' && text[0] != '.') + { + const char *jtag_data_dir = urj_get_data_dir (); + implicit_len = strlen (jtag_data_dir) + 1; + + search_text = malloc (implicit_len + text_len + 1); + if (!search_text) + return; + + sprintf (search_text, "%s/%s", jtag_data_dir, text); + text = search_text; + text_len += implicit_len; + } + else + { + implicit_len = 0; + search_text = NULL; + } + + state = 0; + while (1) + { + match = rl_filename_completion_function (text, state++); + if (!match) + break; + urj_completion_add_match_dupe (matches, match_cnt, match + implicit_len); + free (match); + } + + free (search_text); +#endif +} + const urj_cmd_t urj_cmd_include = { "include", N_("include command sequence from external repository"), cmd_include_help, - cmd_include_run + cmd_include_run, + cmd_include_complete, }; static int diff --git a/urjtag/src/cmd/cmd_initbus.c b/urjtag/src/cmd/cmd_initbus.c index d35004c..2c9f266 100644 --- a/urjtag/src/cmd/cmd_initbus.c +++ b/urjtag/src/cmd/cmd_initbus.c @@ -101,9 +101,24 @@ cmd_initbus_help (void) urj_cmd_show_list (urj_bus_drivers); } +static void +cmd_initbus_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + size_t i; + + if (token_point != 1) + return; + + for (i = 0; urj_bus_drivers[i]; i++) + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, + urj_bus_drivers[i]->name); +} + const const urj_cmd_t urj_cmd_initbus = { "initbus", N_("initialize bus driver for active part"), cmd_initbus_help, - cmd_initbus_run + cmd_initbus_run, + cmd_initbus_complete, }; diff --git a/urjtag/src/cmd/cmd_instruction.c b/urjtag/src/cmd/cmd_instruction.c index 4c9b042..77949c9 100644 --- a/urjtag/src/cmd/cmd_instruction.c +++ b/urjtag/src/cmd/cmd_instruction.c @@ -30,6 +30,7 @@ #include <urjtag/error.h> #include <urjtag/part.h> +#include <urjtag/part_instruction.h> #include <urjtag/chain.h> #include <urjtag/cmd.h> @@ -110,9 +111,33 @@ cmd_instruction_help (void) "instruction", "instruction", "instruction"); } +static void +cmd_instruction_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + urj_part_t *part; + urj_part_instruction_t *i; + + if (token_point != 1) + return; + + part = urj_tap_chain_active_part (chain); + if (part == NULL) + return; + + i = part->instructions; + while (i) + { + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, + i->name); + i = i->next; + } +} + const urj_cmd_t urj_cmd_instruction = { "instruction", N_("change active instruction for a part or declare new instruction"), cmd_instruction_help, - cmd_instruction_run + cmd_instruction_run, + cmd_instruction_complete, }; diff --git a/urjtag/src/cmd/cmd_salias.c b/urjtag/src/cmd/cmd_salias.c index 274fbe4..637deed 100644 --- a/urjtag/src/cmd/cmd_salias.c +++ b/urjtag/src/cmd/cmd_salias.c @@ -94,9 +94,20 @@ cmd_salias_help (void) "signal"); } +static void +cmd_salias_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + if (token_point != 2) + return; + + cmd_signal_complete (chain, matches, match_cnt, text, text_len); +} + const urj_cmd_t urj_cmd_salias = { "salias", N_("define an alias for a signal"), cmd_salias_help, - cmd_salias_run + cmd_salias_run, + cmd_salias_complete, }; diff --git a/urjtag/src/cmd/cmd_set.c b/urjtag/src/cmd/cmd_set.c index 005b202..c23f954 100644 --- a/urjtag/src/cmd/cmd_set.c +++ b/urjtag/src/cmd/cmd_set.c @@ -117,9 +117,33 @@ cmd_set_help (void) "set"); } +static void +cmd_set_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + switch (token_point) + { + case 1: /* name */ + cmd_signal_complete (chain, matches, match_cnt, text, text_len); + break; + + case 2: /* direction */ + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "in"); + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "out"); + break; + + case 3: /* value */ + /* XXX: Only applies if token[1] == "out" ... */ + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "0"); + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "1"); + break; + } +} + const urj_cmd_t urj_cmd_set = { "set", N_("set external signal value"), cmd_set_help, - cmd_set_run + cmd_set_run, + cmd_set_complete, }; diff --git a/urjtag/src/cmd/cmd_shift.c b/urjtag/src/cmd/cmd_shift.c index 9741a3a..b2d2979 100644 --- a/urjtag/src/cmd/cmd_shift.c +++ b/urjtag/src/cmd/cmd_shift.c @@ -77,9 +77,21 @@ cmd_shift_help (void) "shift ir", "shift dr"); } +static void +cmd_shift_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + if (token_point != 1) + return; + + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "dr"); + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "ir"); +} + const urj_cmd_t urj_cmd_shift = { "shift", N_("shift data/instruction registers through JTAG chain"), cmd_shift_help, - cmd_shift_run + cmd_shift_run, + cmd_shift_complete, }; diff --git a/urjtag/src/cmd/cmd_signal.c b/urjtag/src/cmd/cmd_signal.c index 2345485..c84c9ef 100644 --- a/urjtag/src/cmd/cmd_signal.c +++ b/urjtag/src/cmd/cmd_signal.c @@ -101,6 +101,27 @@ cmd_signal_help (void) "signal"); } +/* This is used indirectly by other signal commands */ +void +cmd_signal_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len) +{ + urj_part_t *part; + urj_part_signal_t *s; + + part = urj_tap_chain_active_part (chain); + if (part == NULL) + return; + + s = part->signals; + while (s) + { + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, + s->name); + s = s->next; + } +} + const urj_cmd_t urj_cmd_signal = { "signal", N_("define new signal for a part"), diff --git a/urjtag/src/cmd/cmd_test.c b/urjtag/src/cmd/cmd_test.c index de8a700..d88b2f0 100644 --- a/urjtag/src/cmd/cmd_test.c +++ b/urjtag/src/cmd/cmd_test.c @@ -108,9 +108,26 @@ cmd_test_help (void) "test"); } +static void +cmd_test_complete (urj_chain_t *chain, char ***matches, size_t *match_cnt, + const char *text, size_t text_len, size_t token_point) +{ + switch (token_point) + { + case 1: /* name */ + cmd_signal_complete (chain, matches, match_cnt, text, text_len); + break; + case 2: /* value */ + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "0"); + urj_completion_mayben_add_match (matches, match_cnt, text, text_len, "1"); + break; + } +} + const urj_cmd_t urj_cmd_test = { "test", N_("test external signal value"), cmd_test_help, - cmd_test_run + cmd_test_run, + cmd_test_complete, }; diff --git a/urjtag/src/global/parse.c b/urjtag/src/global/parse.c index a190d2c..b7d2714 100644 --- a/urjtag/src/global/parse.c +++ b/urjtag/src/global/parse.c @@ -41,20 +41,22 @@ #include <urjtag/bsdl.h> int -urj_parse_line (urj_chain_t *chain, const char *line) +urj_tokenize_line (const char *line, char ***tokens, size_t *token_cnt) { - int l, i, r, tcnt; - int escape = 0, quote_single = 0, quote_double = 0; + size_t l, i; + int escape, quote_single, quote_double; char **a; const char *c; - char *d; - char *sline; + char *d, *sline; - if (line == NULL) + if (!line || !tokens || !token_cnt) { - urj_error_set (URJ_ERROR_INVALID, "NULL line"); + urj_error_set (URJ_ERROR_INVALID, "NULL input(s)"); return URJ_STATUS_FAIL; } + + *token_cnt = 0; + l = strlen (line); if (l == 0) return URJ_STATUS_OK; @@ -69,9 +71,9 @@ urj_parse_line (urj_chain_t *chain, const char *line) } /* count and copy the tokens */ + escape = quote_single = quote_double = 0; c = line; d = sline; - tcnt = 0; while (1) { /* eat up leading spaces */ @@ -111,38 +113,59 @@ urj_parse_line (urj_chain_t *chain, const char *line) } /* mark the end to the destination string */ *d++ = '\0'; - tcnt++; + ++*token_cnt; } - if (tcnt == 0) + if (*token_cnt == 0) { free (sline); return URJ_STATUS_OK; } /* allocate the token pointer table */ - a = malloc ((tcnt + 1) * sizeof (char *)); + l = (*token_cnt + 1) * sizeof (*a); + *tokens = a = malloc (l); if (a == NULL) { - urj_error_set (URJ_ERROR_OUT_OF_MEMORY, "malloc(%zd) fails", - (size_t) ((tcnt + 1) * sizeof (char *))); + urj_error_set (URJ_ERROR_OUT_OF_MEMORY, "malloc(%zd) fails", l); return URJ_STATUS_FAIL; } /* find the starting points for the tokens */ d = sline; - for (i = 0; i < tcnt; i++) + for (i = 0; i < *token_cnt; i++) { a[i] = d; while (*d++ != '\0') ; } - a[tcnt] = NULL; + a[*token_cnt] = NULL; + + return URJ_STATUS_OK; +} + +void +urj_tokens_free (char **tokens) +{ + free (tokens[0]); + free (tokens); +} + +int +urj_parse_line (urj_chain_t *chain, const char *line) +{ + int r; + size_t tcnt; + char **a; + + r = urj_tokenize_line (line, &a, &tcnt); + if (r != URJ_STATUS_OK || tcnt == 0) + return r; r = urj_cmd_run (chain, a); urj_log (URJ_LOG_LEVEL_DEBUG, "Return in urj_parse_line r=%d\n", r); - free (a); - free (sline); + + urj_tokens_free (a); return r; } @@ -313,4 +336,3 @@ urj_parse_include (urj_chain_t *chain, const char *filename, int ignore_path) return r; } -
signature.asc
Description: This is a digitally signed message part.
------------------------------------------------------------------------------ The ultimate all-in-one performance toolkit: Intel(R) Parallel Studio XE: Pinpoint memory and threading errors before they happen. Find and fix more than 250 security defects in the development cycle. Locate bottlenecks in serial and parallel code that limit performance. http://p.sf.net/sfu/intel-dev2devfeb
_______________________________________________ UrJTAG-development mailing list UrJTAG-development@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/urjtag-development