aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Slaven <bpk@hoopajoo.net>2023-01-24 06:28:34 (GMT)
committerSteve Slaven <bpk@hoopajoo.net>2023-01-24 06:28:34 (GMT)
commit4a4c430d3affc992737d11c6b403c62ceb97007c (patch)
tree5fc22b1f6abb68ef51492f6707d09d6ce0926537
parente5419a02b2e84e2a792d8b385e099c85f1489cf4 (diff)
downloadpowwow-master.zip
powwow-master.tar.gz
powwow-master.tar.bz2
factor out parsing #substitute and #markHEADmaster
-rw-r--r--doc/powwow.doc.in7
-rw-r--r--src/cmd.c4
-rw-r--r--src/cmd2.c487
-rw-r--r--src/defines.h2
-rw-r--r--src/prove.c25
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
diff --git a/src/cmd.c b/src/cmd.c
index 847fbdc..9ef0539 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -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,
diff --git a/src/cmd2.c b/src/cmd2.c
index 1503f88..b21ede3 100644
--- a/src/cmd2.c
+++ b/src/cmd2.c
@@ -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();