procmail
[Top] [All Lists]

Re: Counting score program exit code and negation

1997-02-06 13:21:09
When I said,

| >So far the only way I see to do this without an external program is a
| >recursive INCLUDERC, and those things can be vicious.

Philip Guenther responded,

| That sounded like a challenge, so I crafted the following.

Well, ok, I've deconstructed it.  (You knew I would.)

G>  # Put the regexp of the lines to examine in REGEXP
G>  :0
G>  * ^Resent-(From|Date|To|Cc|Message-Id):
G>  { REGEXP = "^Resent-(To|Cc):" }
G>  :0E
G>  { REGEXP = "^(To|Cc):" }

So far no quibbles.

G>  # Put the string to match against in HEADER
G>  :0
G>  * ^^\/.*^^
G>  { HEADER = $MATCH }

Given that the head will not start out with a match to $REGEXP, let's discard
the initial stuff (From_, Return-Path:, Received:, Message-Id:) right now.
Now, $HEADER will never contain the entire head, so it's a different concept,
which I'll name $HEADERLINES:

   # Put the string to match against into $HEADERLINES
   :0 # H is implicit
   * $ ()\/$REGEXP(.*)$
   { HEADERLINES = $MATCH }

Now, instead of using (and explaining) ${COUNT:-0} in both the main rcfile
and in the recursively called rcfile, let's just preset

    COUNT=0

right here.  It also takes care of the situation where we may have used
the same variable earlier and it may already have a value that we don't want.
Better yet, since we're going to subtract nineteen anyway,

    EXCESS=-19

G>  # Count'em
G>  INCLUDERC = count_comma_sep.rc

Here's the continuing code in the main rcfile after returning from the
recursion:

G>  # Beware: if there were no matches, then COUNT will be unset, so use
G>  # ${COUNT:-0} ala Bourne shell.
G>  :0
G>  * $ ${COUNT:-0}^0
G>  * -19^0
G>  { EXITCODE=77 HOST }

EXCESS is always set, and the 19 has already been subtracted, so

    :0 # count was predefined and prejudiced at -19 
    * $ $EXCESS^0
    { EXITCODE=77 HOST }

If, for some odd reason, there are no recipients in the head, we shouldn't
use the other rcfile even once.  So, then, we have this:

   # Put the string to match against into $HEADERLINES
   :0 # H is implicit
   * $ ()\/$REGEXP(.*)$
   {
     # Set up the initial run.

     HEADERLINES = $MATCH
     EXCESS = -19

     # Let it rip.
     INCLUDERC = count_comma_sep.rc

    :0 # count was predefined and prejudiced at -19 
    * $ $EXCESS^0
    { EXITCODE=77 HOST }

   }

Now, to the code in the included rcfile:

G>  Then in the file count_comma_sep.rc put:
G>  
G>  # Goal: count the number of commas separated items in HEADER at the
G>  # end of the lines that match $REGEXP.  COUNT will keep the running
G>  # total.

    # Goal: count the number of comma-separated items in $HEADERLINES in
    # lines that begin with $REGEXP.  EXCESS will keep the running excess
    # over 19.

G>  # Clear MATCH, then count the items in the first match, if any.
G>  MATCH=
G>  :0
G>  * 1^0 HEADER ?? $ $REGEXP\/.*
G>  * 1^1 MATCH ?? ,
G>  {

Looks good (though I'd need to change HEADER to HEADERLINES, of course).

G>      # Okay, increment COUNT by $=.  Beware, COUNT may be unset, so use
G>      # ${COUNT:-0} to get it's value if any, or zero if none.
G>      :0
G>      * $ $=^0
G>      * $ ${COUNT:-0}^0
G>      { COUNT = $= }

EXCESS won't be unset or null, and personally I like the addends in the other
order (though that part really doesn't matter).

        # Okay, increment EXCESS by $=.
        :0
        * $ $EXCESS^0
        * $ $=^0
        { EXCESS = $= }

All right then ... moving onward ...

G>      # Now, do we need to recurse?  Only if there's more than one
G>      # match of $REGEXP.
G>      :0
G>      * -1^0
G>      * 1^1 HEADER ?? $ $REGEXP
G>      {
G>      # We do.  We'll need to reset HEADER to only contain everything
G>      # *after* the first match.
G>      :0
G>      * HEADER ?? $ $REGEXP.*($)\/(.*($)?)*

If there are other lines between the line we just tested and the next one of
any value, we're still keeping them around in $HEADERLINES when we can, lose 
them
right now.  So let's do this:

        * HEADERLINES ?? $ $REGEXP(.*$)*\/$REGEXP(.*$)*

In fact, that can be used as the recursion test as well and makes the
previous scoring unnecessary.  I think I'll modify the entire recursion
test below, including the effect on the remaining lines, which were:

G>      { HEADER = $MATCH }
G>  
G>      # Recurse!
G>      INCLUDERC = $_
G>      }

        # Now, do we need to recurse?  Only if there's still another
        # match to $REGEXP.  If so, we reset $HEADERLINES to contain only
        # the second match and beyond, and then we take another ride.
        :0
        * HEADERLINES ?? $ $REGEXP(.*$)*\/$REGEXP(.*$)*
        {
          HEADERLINES = $MATCH
    
          # Recurse!
          INCLUDERC = $_
        }

Then let's include the closing brace from Philip's original code:

G>  }