Skip to content

Commit

Permalink
Allow regex replacement variables in HAO commands
Browse files Browse the repository at this point in the history
The following variables are recognized in the command string
of an Hercules Automatic Operator rule:

$1 to $9 - the text which matched the 1st to 9th capturing
group in the target regular expression
$` - the text which precedes the regular expression match
$' - the text which follows the regular expression match
$$ - replaced by a single dollar sign

Substitution of a $n variable does not occur if there are
fewer than n capturing groups in the regular expression.
  • Loading branch information
rbowler committed Jun 15, 2013
1 parent 5fa14b0 commit 3ccdab8
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 53 deletions.
85 changes: 79 additions & 6 deletions hao.c
Expand Up @@ -60,6 +60,7 @@

#define HAO_WKLEN 256 /* (maximum message length able to tolerate) */
#define HAO_MAXRULE 64 /* (purely arbitrary and easily increasable) */
#define HAO_MAXCAPT 9 /* (maximum number of capturing groups) */

/*---------------------------------------------------------------------------*/
/* local variables */
Expand Down Expand Up @@ -257,7 +258,7 @@ static void hao_tgt(char *arg)
}

/* compile the target string */
rc = regcomp(&ao_preg[i], arg, 0);
rc = regcomp(&ao_preg[i], arg, REG_EXTENDED);

/* check for error */
if(rc)
Expand Down Expand Up @@ -574,6 +575,31 @@ static void* hao_thread(void* dummy)
return NULL;
}

/*---------------------------------------------------------------------------*/
/* size_t hao_subst(char *str, size_t soff, size_t eoff, */
/* char *cmd, size_t coff, size_t csize) */
/* */
/* This function copies a substring of the original string into */
/* the command buffer. The input parameters are: */
/* str the original string */
/* soff starting offset of the substring in the original string */
/* eoff offset of the first character following the substring */
/* cmd the destination command buffer */
/* coff offset in the command buffer to copy the substring */
/* csize size of the command buffer (including terminating zero) */
/* The return value is the number of characters copied. */
/*---------------------------------------------------------------------------*/
static size_t hao_subst(char *str, size_t soff, size_t eoff,
char *cmd, size_t coff, size_t csize)
{
size_t len = eoff - soff;

if (soff + len > strlen(str)) len = strlen(str) - soff;
if (coff + len > csize-1) len = csize-1 - coff;
memcpy(cmd + coff, str + soff, len);
return len;
}

/*---------------------------------------------------------------------------*/
/* void hao_message(char *buf) */
/* */
Expand All @@ -584,8 +610,11 @@ static void* hao_thread(void* dummy)
DLL_EXPORT void hao_message(char *buf)
{
char work[HAO_WKLEN];
regmatch_t rm;
int i;
char cmd[HAO_WKLEN];
regmatch_t rm[HAO_MAXCAPT+1];
int i, j, k, numcapt;
size_t n;
char *p;

/* copy and strip spaces */
hao_cpstrp(work, buf);
Expand Down Expand Up @@ -615,11 +644,55 @@ DLL_EXPORT void hao_message(char *buf)
if(ao_tgt[i] && ao_cmd[i]) /* complete rule defined in this slot? */
{
/* does this rule match our message? */
if (regexec(&ao_preg[i], work, 1, &rm, 0) == 0)
if (regexec(&ao_preg[i], work, HAO_MAXCAPT+1, rm, 0) == 0)
{
/* count the capturing group matches */
for (j = 0; j <= HAO_MAXCAPT && rm[j].rm_so >= 0; j++);
numcapt = j - 1;

/* copy the command and process replacement patterns */
for (n=0, p=ao_cmd[i]; *p && n < sizeof(cmd)-1; ) {
/* replace $$ by $ */
if (*p == '$' && p[1] == '$') {
cmd[n++] = '$';
p += 2;
continue;
}
/* replace $` by characters to the left of the match */
if (*p == '$' && p[1] == '`') {
n += hao_subst(work, 0, rm[0].rm_so, cmd, n, sizeof(cmd));
p += 2;
continue;
}
/* replace $' by characters to the right of the match */
if (*p == '$' && p[1] == '\'') {
n += hao_subst(work, rm[0].rm_eo, strlen(work), cmd, n, sizeof(cmd));
p += 2;
continue;
}
/* replace $1..$99 by the corresponding capturing group */
if (*p == '$' && isdigit(p[1])) {
if (isdigit(p[2])) {
j = (p[1]-'0') * 10 + (p[2]-'0');
k = 3;
} else {
j = p[1]-'0';
k = 2;
}
if (j > 0 && j <= numcapt) {
n += hao_subst(work, rm[j].rm_so, rm[j].rm_eo, cmd, n, sizeof(cmd));
p += k;
continue;
}
}
/* otherwise copy one character */
cmd[n++] = *p++;
}
cmd[n] = '\0';

/* issue command for this rule */
logmsg(HHCAO003I, ao_cmd[i]);
panel_command(ao_cmd[i]);
logmsg(HHCAO003I, cmd);
panel_command(cmd);
}
}
}
Expand Down
114 changes: 67 additions & 47 deletions html/hercinst.html
Expand Up @@ -860,81 +860,101 @@ <h4>The &nbsp;hercules.rc &nbsp;(run-commands)&nbsp; file</h4>
<h4>The "Hercules Automatic Operator" (HAO) Facility</h4>
</a>
<p>
The Hercules Automatic Operator (HAO) feature is a facility that allows one
to automatically issue panel commands in response to certain messages being
issued.
The Hercules Automatic Operator (HAO) feature is a facility which can
automatically issue panel commands in response to specific messages
appearing on the Hercules console.
<p>
To use the Hercules Automatic Operator facility, one first defines a "rule"
consisting of a "target" and an associated "command". The "target" is just
To use the Hercules Automatic Operator facility, you first define a "rule"
consisting of a "target" and an associated "command". The "target" is
a regular expression pattern used to match against the text of the various
messages that Hercules issues as it runs. Whenever a match is found, the
rule "fires" and its associated command is automatically issued.
<p>
The Hercules Automatic Operator facility is <i>only</i> for those messages
issued <i>by Hercules</i> to its HMC (hardware console). It <i>cannot</i>
be used for whatever messages the guest operating system may issue to any
of its terminals. It is only a <i>Hercules</i> automatic operator and
<i>not</i> a "VSE", "MVS", "VM", etc, automatic operator.
The Hercules Automatic Operator facility only operates on messages issued
to the Hercules console. These messages may originate from Hercules itself,
or from the guest operating system via the SCP SYSCONS interface or via the
integrated console printer-keyboard (3215-C or 1052-C). HAO cannot intercept
messages issued by the guest operating system to its own terminals.

<h5>Defining a Rule</h5>
<p>
To define a HAO rule, enter the command:
<pre>
hao <i>target</i>
hao tgt <i>target</i>
</pre>
<p>
to define the rule's "target" match pattern (a simple regular expression),
to define the rule's "target" match pattern
followed by the command:
<pre>
hao <i>command</i>
hao cmd <i>command</i>
</pre>
<p>
to define the rule's associated panel-command.
<p>
The target pattern is a simple regular expression value as defined by
whatever regular expression facility your host build platform happens
to support. For Windows it must be a Perl Compatible Regular Expression (PCRE).
For other supported build platforms it might be some other supported regular
expression syntax. Check your host platform's programming documentation for
further details.
The <i>target</i> is a regular expression as defined by your host platform.
When running on Linux, Hercules uses POSIX Extended Regular Expression syntax.
On a Windows platform, regular expression support is provided by
Perl Compatible Regular Expression (PCRE).
The HAO facility can only be used if regular expression support was included
in Hercules at build time.
<p>
The associated <i>command</i> is whatever valid Hercules panel command you
wish to issue in response to a message being issued that matches the given
pattern <i>target</i>.
<i>target</i> pattern.

<h5>Substituting substrings in the command</h5>
<p>
The <i>command</i> may contain special variables $1, $2, etc, which will be
replaced by the values of "capturing groups" in the match pattern.
A capturing group is a part of the regular expression enclosed in parentheses
which is matched with text in the target message. In this way, commands may be
constructed which contain substrings extracted from the message which
triggered the command.
<p>
The following special variables are recognized:
<ul>
<li><code>$1</code> to <code>$9</code> -
the text which matched the 1st to 9th capturing
group in the target regular expression
<li><code>$`</code> - the text preceding the regular expression match
<li><code>$'</code> - the text following the regular expression match
<li><code>$$</code> - replaced by a single dollar sign
</ul>
<p>
Note that substitution of a $<i>n</i> variable does not occur if there are
fewer than <i>n</i> capturing groups in the regular expression.
<p>
As an example, the rule below issues the command 'i 001F' in response to
the message HHCTE014I 3270 device 001F client 127.0.0.1 connection reset:
<pre>
hao tgt HHCTE014I 3270 device ([0-9A-F]{3,4})
hao cmd i
</pre>
<p>
Another example, shown below, illustrates how the dot matrix display of a
3480 tape unit might be used to implement an automatic tape library:
<pre>
hao tgt HHCTA010I ([0-9A-F]{4}): Now Displays: (?:".{8}" / )?"M([A-Z0-9]{1,6})\s*S"
hao cmd devinit $1 /u/tapes/$2.awstape
</pre>

<h5>Other commands and limitations</h5>
<p>
To delete a fully or partially defined HAO rule, first use the 'hao list'
command to list all of the defined (or partially defined) rules, and then use
the 'hao del <i>nnn</i>' command to delete the specific rule identified by <i>nnn</i>.
(All rules are assigned numbers as they are defined and are thus identified
by their numeric value). Optionally, one may delete ALL defined or partially
defined rules by issuing the command 'hao clear'.
<p>
The current implementation limits the total number of defined rules to 64. If
you need to define more than 64 rules you will either have to build Hercules
for yourself (increasing the value of the HAO_MAXRULE constant in hao.c) or
else beg one of the Hercules developers to please do it for you.
<p>
Note that there is currently no way to define a command whose arguments vary
based on actual message text. That is to say, there is currently no way to say
<p>
"Reply with the command 'devinit <i>cuu</i> filename'
in response to message text 'HHCXXnnnI Device <i>cuu</i>
intervention required.' where <i>cuu</i> is whatever cuu
was identified in the message."
<p>
The HAO is <i><b>not</b></i> that sophisticated (yet). Only simple plain-text commands may
be defined and issued. No automatic substitution is done based on message text
(although normal 'DEFSYM' symbol substitution <i><b>is</b></i> supported however, as that
is a normal panel-command feature supported separately from the HAO). This may
possibly change in the future however, depending on user need/demand.
<p>
<i><b>All</b></i> defined rules are checked for a match each time Hercules issues a message.
the 'hao del <i>nnn</i>' command to delete the specific rule identified by
<i>nnn</i> (all rules are assigned numbers as they are defined and are thus
identified by their numeric value). Optionally, you can delete all defined or
partially defined rules by issuing the command 'hao clear'.
<p>
The current implementation limits the total number of defined rules to 64.
This limit may be raised by increasing the value of the HAO_MAXRULE
constant in hao.c and rebuilding Hercules.
<p>
All defined rules are checked for a match each time Hercules issues a message.
There is no way to specify "stop processing subsequent rules". If a message is
issued that matches two or more rules, each associated command is then issued
in sequence. Thus the advice to choose your rules' target patterns carefully
very much applies here.
in sequence.
<p>

<p><hr><a name="support"></a>
Expand Down

0 comments on commit 3ccdab8

Please sign in to comment.