diff options
| -rw-r--r-- | doc/powwow.doc.in | 7 | ||||
| -rw-r--r-- | src/cmd.c | 4 | ||||
| -rw-r--r-- | src/cmd2.c | 487 | ||||
| -rw-r--r-- | src/defines.h | 2 | ||||
| -rw-r--r-- | src/prove.c | 25 | 
5 files changed, 360 insertions, 165 deletions
| diff --git a/doc/powwow.doc.in b/doc/powwow.doc.in index 7236f87..649310b 100644 --- a/doc/powwow.doc.in +++ b/doc/powwow.doc.in @@ -580,6 +580,13 @@ SPECIAL COMMANDS: ALL OTHERS  					 at the beginning of a line)  	#mark \^=on blue		(mark a literal ^ )  	----------------------------------------------------------- +	Substitute output +	#substitute [pattern[=[replace]]] + +	This command substitutes the pattern with test from replace. + +	Uses the same pattern rules as #mark +	-----------------------------------------------------------  	#module [module name]  	This loads a shared library module by name, if supported by your system.  The @@ -227,10 +227,10 @@ cmdstruct default_commands[] =        "connect-id command\ttalk with a shell command"),      C("speedwalk",  cmd_speedwalk,        "[speedwalk sequence]\texecute a speedwalk sequence explicitly"), -    C("substitute",       cmd_substitute, -      "[string[=[text]]]\tdelete/list/define substitutions"),      C("stop",       cmd_stop,        "\t\t\t\tremove all delayed commands from active list"), +    C("substitute",       cmd_substitute, +      "[string[=[text]]]\tdelete/list/define substitutions"),      C("time",       cmd_time,        "\t\t\t\tprint current time and date"),      C("var",        cmd_var, @@ -41,6 +41,41 @@ int select();  #include "tty.h"  #include "eval.h" +typedef struct parsed_pattern_definition { +    int match_from_beginning; + +    int has_pattern; +    char pattern[BUFSIZE]; + +    int pattern_has_wild; + +    const char *pattern_start_p; +    int pattern_offset; +    int pattern_length; + +    int has_value; +    char value[BUFSIZE]; + +    const char *value_start_p; +    int value_offset; +    int value_length; + +    const char *error_string; +    int error_code; +} parsed_pattern_definition; + +typedef struct parse_pattern_action_result { +    int error_code; +    char message[BUFSIZE]; +    char display_value[BUFSIZE]; +    int action_complete; +    void (*post_call_f)(); +} parse_pattern_action_result; + +typedef void parse_pattern_action(parse_pattern_action_result *result, char *pattern, int match_from_beginning); +typedef void parse_pattern_with_value_action(parse_pattern_action_result *result, char *pattern, int match_from_beginning, int pattern_has_wild, char *value); + +  /* anyone knows if ANSI 6429 talks about more than 8 colors? */  static char *colornames[] = {      "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", @@ -883,99 +918,274 @@ void show_marks(void)  		   p->b.pattern, attr_name(p->attrcode));  } - -/* - * parse arguments to the #mark command - */ -void parse_mark(char *str) +static void parse_pattern_definition(char *str, parsed_pattern_definition *res)  {      char *p; -    marknode **np, *n; -    char mbeg = 0; + +    res->match_from_beginning = 0; + +    res->pattern_has_wild = 0; +    res->has_pattern = 0; +    res->pattern[0] = 0; +    res->pattern_start_p = NULL; +    res->pattern_offset = 0; +    res->pattern_length = 0; + +    res->has_value = 0; +    res->value[0] = 0; +    res->value_start_p = NULL; +    res->value_offset = 0; +    res->value_length = 0; + +    res->error_code = 0; +    res->error_string = NULL;      if (*str == '=') { -	PRINTF("#marker must be non-empty.\n"); -	return; +        res->error_string = "must be non-empty"; +        return; +    } + +    res->has_pattern = 1; +    if (*str ==  '^') { +        res->match_from_beginning = 1; +        res->pattern_offset++;      } + +    str += res->pattern_offset; +    res->pattern_start_p = str; +      p = first_regular(str, '='); +      if (!*p) { -	if (*str ==  '^') -	    mbeg = 1, str++; -        unescape(str); -        np = lookup_marker(str, mbeg); -        if ((n = *np)) { -	    ptr pbuf = (ptr)0; -	    char *name; -	    pbuf = ptrmescape(pbuf, n->b.pattern, strlen(n->b.pattern), 0); -	    if (MEM_ERROR) { ptrdel(pbuf); return; } -            name = attr_name(n->attrcode); -            sprintf(inserted_next, "#mark %s%.*s=%.*s", n->b.mbeg ? "^" : "", -		    BUFSIZE-(int)strlen(name)-9, pbuf ? ptrdata(pbuf) : "", -		    BUFSIZE-9, name); -	    ptrdel(pbuf); -        } else { -            PRINTF("#unknown marker, cannot show: \"%s\"\n", str); +        /* no = so just a pattern no value */ +        res->pattern_length = strlen(str); +    } else { +        res->pattern_length = p - str; +    } + +    my_strncpy(res->pattern, str, res->pattern_length); +    unescape(res->pattern); + +    if (1) { +        char *p2; +        p2 = res->pattern; +        while (*p2) { +            if (ISMARKWILDCARD(*p2)) { +                res->pattern_has_wild = 1; +                if (ISMARKWILDCARD(*(p2 + 1))) { +                    res->error_code = SYNTAX_ERROR; +                    res->error_string = "two wildcards (& or $) may not be next to eachother"; +                    //PRINTF("#error: two wildcards (& or $) may not be next to eachother\n"); +                    return; +                } +            } +            p2++;          } +    } -    } else { -        int attrcode, wild = 0; -	char pattern[BUFSIZE], *p2; +    // no value to parse +    if (!*p) { +        return; +    } -        *(p++) = '\0'; -	p = skipspace(p); -	if (*str ==  '^') -	    mbeg = 1, str++; -	my_strncpy(pattern, str, BUFSIZE-1); -        unescape(pattern); -	p2 = pattern; -	while (*p2) { -	    if (ISMARKWILDCARD(*p2)) { -		wild = 1; -		if (ISMARKWILDCARD(*(p2 + 1))) { -		    error=SYNTAX_ERROR; -		    PRINTF("#error: two wildcards (& or $) may not be next to eachother\n"); -		    return; -		} -	    } -	    p2++; -	} +    // skip the equals +    p++; -        np = lookup_marker(pattern, mbeg); -        attrcode = parse_attributes(p); -        if (attrcode == -1) { -            PRINTF("#invalid attribute syntax.\n"); -	    error=SYNTAX_ERROR; -            if (opt_info) show_attr_syntax(); -        } else if (!*p) -	    if ((n = *np)) { -		if (opt_info) { -		    PRINTF("#deleting mark: %s%s=%s\n", n->b.mbeg ? "^" : "", -			   n->b.pattern, attr_name(n->attrcode)); -		} -		delete_marknode(np); -	    } else { -		PRINTF("#unknown marker, cannot delete: \"%s%s\"\n", -		       mbeg ? "^" : "", pattern); -	    } -        else { -            if (*np) { -                (*np)->attrcode = attrcode; +    // this was only used in the #mark syntax, is it needed? +    int clear_leading_value_whitespace = 0; +    if (clear_leading_value_whitespace) { +        p = skipspace(p); +    } + +    res->has_value = 1; +    res->value_start_p = p; +    res->value_offset = p - str; +    res->value_length = strlen(p); + +    my_strncpy(res->value, p, BUFSIZE-1); +} + +void _dump_parsed(parsed_pattern_definition *res) +{ +    PRINTF("res->match_from_beginning = %d\n", res->match_from_beginning); + +    PRINTF("res->pattern_has_wild = %d\n", res->pattern_has_wild); +    PRINTF("res->has_pattern = %d\n", res->has_pattern); +    PRINTF("res->pattern = %s\n", res->pattern); +    PRINTF("res->pattern_start_p = %d\n", res->pattern_start_p); +    PRINTF("res->pattern_offset = %d\n", res->pattern_offset); +    PRINTF("res->pattern_length = %d\n", res->pattern_length); + +    PRINTF("res->has_value = %d\n", res->has_value); +    PRINTF("res->value = %s\n", res->value); +    PRINTF("res->value_start_p = %d\n", res->value_start_p); +    PRINTF("res->value_offset = %d\n", res->value_offset); +    PRINTF("res->value_length = %d\n", res->value_length); + +    PRINTF("res->error_code = %d\n", res->error_code); +    PRINTF("res->error_string = %d\n", res->error_string); +} + +void parse_pattern_definition_and_process_action(char *str, +    char *command, char *command_noun, int detail_magic_number, +    parse_pattern_action *do_delete, +    parse_pattern_with_value_action *do_update_or_insert, +    parse_pattern_action *do_show) +{ +    ptr pbuf = (ptr)0; +    char *detail_display; + +    parse_pattern_action_result action_result; +    parsed_pattern_definition parsed; + +    parse_pattern_definition(str, &parsed); +    //_dump_parsed(&parsed); + +    if (parsed.error_string) { +        error = parsed.error_code; +        PRINTF("%s %s\n", command, parsed.error_string); +        return; +    } + +    action_result.action_complete = 0; +    action_result.post_call_f = NULL; +    strcpy(action_result.display_value, ""); +    strcpy(action_result.message, ""); + +    if (parsed.has_value) { +        if (! parsed.value[0]) { +            (*do_delete)(&action_result, parsed.pattern, parsed.match_from_beginning); + +            if (action_result.action_complete) {                  if (opt_info) { -                    PRINTF("#changed"); +                    PRINTF("#deleting %s: %s%s=%s\n", +                        command_noun, +                        parsed.match_from_beginning ? "^" : "", +                        parsed.pattern, +                        action_result.display_value);                  }              } else { -                add_marknode(pattern, attrcode, mbeg, wild); +                PRINTF("#unknown %s, cannot delete: \"%s%s\"\n", +                    command_noun, +                    parsed.match_from_beginning ? "^" : "", +                    parsed.pattern); +            } +        } else { +            (*do_update_or_insert)(&action_result, parsed.pattern, parsed.match_from_beginning, parsed.pattern_has_wild, parsed.value); + +            if (action_result.action_complete) {                  if (opt_info) { -                    PRINTF("#new"); +                    if (action_result.action_complete == 1) { +                        PRINTF("#changed"); +                    } else if (action_result.action_complete == 2) { +                        PRINTF("#new"); +                    } + +                    tty_printf(" %s: %s%s=%s\n", +                        command_noun, +                        parsed.match_from_beginning ? "^" : "", +                        parsed.pattern, +                        action_result.display_value);                  } +            } else { +                PRINTF("%s\n", action_result.message); +                if (action_result.post_call_f != NULL) { +                    (*action_result.post_call_f)(); +                } +                return;              } -            if (opt_info) -		tty_printf(" mark: %s%s=%s\n", mbeg ? "^" : "", -			   pattern, attr_name(attrcode)); +        } +    } else { +        (*do_show)(&action_result, parsed.pattern, parsed.match_from_beginning); +        if (action_result.action_complete) { +            detail_display = action_result.display_value; + +            pbuf = ptrmescape(pbuf, parsed.pattern, strlen(parsed.pattern), 0); + +            if (MEM_ERROR) { ptrdel(pbuf); return; } + +            sprintf(inserted_next, "%s %s%.*s=%.*s", +                command, +                parsed.match_from_beginning ? "^" : "", +                BUFSIZE - (int)strlen(detail_display) - detail_magic_number, +                pbuf ? ptrdata(pbuf) : "", +                BUFSIZE - detail_magic_number, detail_display); + +            ptrdel(pbuf); +        } else { +            PRINTF("#unknown %s, cannot show: \"%s\"\n", +                command_noun, +                parsed.pattern);          }      }  } +marknode **parse_mark__action_with_marknode(parse_pattern_action_result *result, char *pattern, int match_from_beginning) +{ +    marknode **np, *n = NULL; +    np = lookup_marker(pattern, match_from_beginning); +    result->action_complete = 0; + +    if (n = *np) { +        strcpy(result->display_value, attr_name(n->attrcode)); +    } + +    return np; +} + +void parse_mark__action_delete(parse_pattern_action_result *result, char *pattern, int match_from_beginning) +{ +    marknode *n, **np = parse_mark__action_with_marknode(result, pattern, match_from_beginning); + +    if (n = *np) { +        result->action_complete = 1; +        delete_marknode(np); +    } +} + +void parse_mark__action_update_or_insert(parse_pattern_action_result *result, char *pattern, int match_from_beginning, int pattern_has_wild, char *value) +{ +    marknode *n, **np = parse_mark__action_with_marknode(result, pattern, match_from_beginning); +    int attrcode = parse_attributes(value); + +    if (attrcode == -1) { +        strcpy(result->message, "#invalid attribute syntax."); +        error = SYNTAX_ERROR; +        result->post_call_f = &show_attr_syntax; +        return; +    } + +    if (n = *np) { +        result->action_complete = 1; +        n->attrcode = attrcode; +    } else { +        result->action_complete = 2; +        add_marknode(pattern, attrcode, match_from_beginning, pattern_has_wild); +    } + +    strcpy(result->display_value, attr_name(attrcode)); +} + +void parse_mark__action_show(parse_pattern_action_result *result, char *pattern, int match_from_beginning) +{ +    marknode *n, **np = parse_mark__action_with_marknode(result, pattern, match_from_beginning); + +    if (n = *np) { +        result->action_complete = 1; +    } +} + +/* + * parse arguments to the #mark command + */ +void parse_mark(char *str) +{ +    parse_pattern_definition_and_process_action(str, +        "#mark", "mark", 9, +        &parse_mark__action_delete, +        &parse_mark__action_update_or_insert, +        &parse_mark__action_show); +}  /*   * show defined substitutions @@ -991,97 +1201,72 @@ void show_substitutions(void)  		   p->b.pattern, p->replacement);  } +substnode **parse_substitute__action_with_substnode(parse_pattern_action_result *result, char *pattern, int match_from_beginning) +{ +    substnode **np, *n = NULL; +    np = lookup_subst(pattern, match_from_beginning); +    result->action_complete = 0; -/* - * parse arguments to the #mark command - */ -void parse_substitute(char *str) +    if (n = *np) { +        strcpy(result->display_value, n->replacement); +    } + +    return np; +} + +void parse_substitute__action_delete(parse_pattern_action_result *result, char *pattern, int match_from_beginning)  { -    char *p; -    substnode **np, *n; -    char mbeg = 0; +    substnode *n, **np = parse_substitute__action_with_substnode(result, pattern, match_from_beginning); -    if (*str == '=') { -	PRINTF("#substitute must be non-empty.\n"); -	return; +    if (n = *np) { +        result->action_complete = 1; +        delete_substnode(np);      } -    p = first_regular(str, '='); -    if (!*p) { -	if (*str ==  '^') -	    mbeg = 1, str++; -        unescape(str); -        np = lookup_subst(str, mbeg); -        if ((n = *np)) { -	    char *replacement = n->replacement; -	    ptr pbuf = ptrmescape(pbuf, n->b.pattern, strlen(n->b.pattern), 0); -	    if (MEM_ERROR) { ptrdel(pbuf); return; } -            sprintf(inserted_next, "#substitute %s%.*s=%.*s", n->b.mbeg ? "^" : "", -		    BUFSIZE-(int)strlen(replacement)-14, pbuf ? ptrdata(pbuf) : "", -		    BUFSIZE-14, replacement); -	    ptrdel(pbuf); -        } else { -            PRINTF("#unknown substitution, cannot show: \"%s\"\n", str); -        } +} +void parse_substitute__action_update_or_insert(parse_pattern_action_result *result, char *pattern, int match_from_beginning, int pattern_has_wild, char *value) +{ +    char *replacement = value; +    substnode *n, **np = parse_substitute__action_with_substnode(result, pattern, match_from_beginning); + +    if (n = *np) { +        if (!(replacement = my_strdup(replacement))) { +            strcpy(result->message, "Failed to strdup"); +            return; +        } +        if (n->replacement) { free(n->replacement); } +        n->replacement = replacement; +        result->action_complete = 1;      } else { -	char pattern[BUFSIZE], *p2, *replacement; -        int  wild = 0; +        result->action_complete = 2; +        add_substnode(pattern, replacement, match_from_beginning, pattern_has_wild); +    } -        *(p++) = '\0'; -	if (*str ==  '^') -	    mbeg = 1, str++; -	my_strncpy(pattern, str, BUFSIZE-1); -        unescape(pattern); -	p2 = pattern; -	while (*p2) { -	    if (ISMARKWILDCARD(*p2)) { -		wild = 1; -		if (ISMARKWILDCARD(*(p2 + 1))) { -		    error = SYNTAX_ERROR; -		    PRINTF("#error: two wildcards (& or $) may not be next to eachother\n"); -		    return; -		} -	    } -	    p2++; -	} +    strcpy(result->display_value, replacement); +} -        np = lookup_subst(pattern, mbeg); -        replacement = p; -        if (!*p) -	    if ((n = *np)) { -		if (opt_info) { -		    PRINTF("#deleting substitution: %s%s=%s\n", n->b.mbeg ? "^" : "", -			   n->b.pattern, n->replacement); -		} -		delete_substnode(np); -	    } else { -		PRINTF("#unknown substitution, cannot delete: \"%s%s\"\n", -		       mbeg ? "^" : "", pattern); -	    } -        else { -            if ((n = *np)) { -                if (!(replacement = my_strdup(replacement))) { -                        return; -                } -                if (n->replacement) { free(n->replacement); } -                n->replacement = replacement; -                if (opt_info) { -                    PRINTF("#changed"); -                } -            } else { -                add_substnode(pattern, replacement, mbeg, wild); -                if (opt_info) { -                    PRINTF("#new"); -                } -            } -            if (opt_info) -		tty_printf(" substitution: %s%s=%s\n", mbeg ? "^" : "", -			   pattern, replacement); -        } +void parse_substitute__action_show(parse_pattern_action_result *result, char *pattern, int match_from_beginning) +{ +    substnode *n, **np = parse_substitute__action_with_substnode(result, pattern, match_from_beginning); + +    if (n = *np) { +        result->action_complete = 1;      }  }  /* + * parse arguments to the #substitute command + */ +void parse_substitute(char *str) +{ +    parse_pattern_definition_and_process_action(str, +        "#substitute", "substitution", 14, +        &parse_substitute__action_delete, +        &parse_substitute__action_update_or_insert, +        &parse_substitute__action_show); +} + +/*   * turn ASCII description of a sequence   * into raw escape sequence   * return pointer to end of ASCII description diff --git a/src/defines.h b/src/defines.h index 87687ef..52d50fe 100644 --- a/src/defines.h +++ b/src/defines.h @@ -218,7 +218,7 @@ typedef struct aliasnode {  typedef struct basenode {      char *pattern;      char *start, *end; // temporary data: start/end of current line match -    char mbeg; +    char mbeg; // match from beginning of string      char wild;  } basenode; diff --git a/src/prove.c b/src/prove.c index 33757f3..497ebda 100644 --- a/src/prove.c +++ b/src/prove.c @@ -265,12 +265,12 @@ static void TEST_mark_syntax_error()      C_output_from_user_input_is(          "#mark =bar", -        "#marker must be non-empty.\n", +        "#mark must be non-empty\n",          "#mark - empty error");      C_output_from_user_input_is(          "#mark foo&$foo=bar", -        "#error: two wildcards (& or $) may not be next to eachother\n", +        "#mark two wildcards (& or $) may not be next to eachother\n",          "#mark - two consecutive wildcards");  } @@ -396,9 +396,9 @@ static void TEST_mark()  static void TEST_substitute_syntax_error()  { -    C_output_from_user_input_contains( +    C_output_from_user_input_is(          "#substitute = ", -        "#substitute must be non-empty.", +        "#substitute must be non-empty\n",          "#substitute - syntax error");  } @@ -434,15 +434,18 @@ void prove()  {      _is_proving = 1; -    do_test(TEST_tap, "TAP output"); +    int looping = 2; +    while (looping--) { +        do_test(TEST_tap, "TAP output"); -    do_test(TEST_mark_syntax_error, "#mark syntax"); -    do_test(TEST_mark_reset_step1, "#mark reset step 1"); -    do_test(TEST_mark_reset_step2, "#mark reset step 2"); -    do_test(TEST_mark, "#mark usage"); +        do_test(TEST_mark_syntax_error, "#mark syntax"); +        do_test(TEST_mark_reset_step1, "#mark reset step 1"); +        do_test(TEST_mark_reset_step2, "#mark reset step 2"); +        do_test(TEST_mark, "#mark usage"); -    do_test(TEST_substitute_syntax_error, "#substitute syntax error"); -    do_test(TEST_substitute, "#substitute usage"); +        do_test(TEST_substitute_syntax_error, "#substitute syntax error"); +        do_test(TEST_substitute, "#substitute usage"); +    }      done_testing(); | 
