// crm_expr_alter.c - Controllable Regex Mutilator, version v1.0
// Copyright 2001-2006 William S. Yerazunis, all rights reserved.
//
// This software is licensed to the public under the Free Software
// Foundation's GNU GPL, version 2. You may obtain a copy of the
// GPL by visiting the Free Software Foundations web site at
// www.fsf.org, and a copy is included in this distribution.
//
// Other licenses may be negotiated; contact the
// author for details.
//
// include some standard files
#include "crm114_sysincludes.h"
// include any local crm114 configuration file
#include "crm114_config.h"
// include the crm114 data structures file
#include "crm114_structs.h"
// and include the routine declarations file
#include "crm114.h"
// the command line argc, argv
extern int prog_argc;
extern char **prog_argv;
// the auxilliary input buffer (for WINDOW input)
extern char *newinputbuf;
// the globals used when we need a big buffer - allocated once, used
// wherever needed. These are sized to the same size as the data window.
extern char *inbuf;
extern char *outbuf;
extern char *tempbuf;
int crm_expr_eval (CSL_CELL *csl, ARGPARSE_BLOCK *apb)
{
// Here we evaluate the slash-string _repeatedly_, not just
// once as in ALTER.
//
// To prevent infinite loops (or at least many of them) we:
// 1) strictly limit the total number of loop iterations to
// the compile-time parameter MAX_EVAL_ITERATIONS
// 2) we also keep an array of the hashes of the last 256 values,
// if we see a repeat, we assume that it's a loop and we stop
// right there.
char varname[MAX_VARNAME];
long varnamelen = 0;
long newvallen;
unsigned long long ihash;
unsigned long long ahash [MAX_EVAL_ITERATIONS];
long ahindex;
long itercount;
long loop_abort;
long qex_stat;
long has_output_var;
// should use tempbuf for this instead.
// char newstr [MAX_PATTERN];
if (user_trace)
fprintf (stderr, "Executing an EVALuation\n");
qex_stat = 0;
has_output_var = 1;
// get the variable name
crm_get_pgm_arg (varname, MAX_VARNAME, apb->p1start, apb->p1len);
if (apb->p1len < 3)
{
has_output_var = 0;
if (user_trace)
fprintf (stderr, "There's no output var for this EVAL, so we won't "
"be assigning the result anywhere.\n It better have a "
"relational test, or you're just wasting CPU.\n");
};
if (has_output_var)
{
// do variable substitution on the variable name
varnamelen = crm_nexpandvar (varname, apb->p1len, MAX_VARNAME);
if (varnamelen < 3)
{
nonfatalerror (
"The variable you're asking me to alter has an utterly bogus name\n",
"so I'll pretend it has no output variable.");
has_output_var = 0;
};
};
// get the new pattern, and expand it.
crm_get_pgm_arg (tempbuf, data_window_size, apb->s1start, apb->s1len);
ihash = 0;
itercount = 0;
for (ahindex = 0; ahindex < MAX_EVAL_ITERATIONS; ahindex++)
ahash[ahindex] = 0;
ahindex = 0;
loop_abort = 0;
//
// Now, a loop - while it continues to change, keep looping.
// But to try and detect infinite loops, we keep track of the
// previous values (actually, their hashes) and if one of those
// values recur, we stop evaluating and throw an error.
//
newvallen = apb->s1len;
while (itercount < MAX_EVAL_ITERATIONS
&& ! (loop_abort))
{
int i;
itercount++;
ihash = strnhash (tempbuf, newvallen);
//
// build a 64-bit hash by changing the initial conditions and
// by using all but two of the characters and by overlapping
// the results by two bits. This is intentionally evil and
// tangled. Hopefully it will work.
//
if (newvallen > 3)
ihash = (ihash << 30) + strnhash (&tempbuf[1], newvallen - 2);
if (internal_trace)
fprintf (stderr, "Eval ihash = %lld\n", ihash);
for (i = 0; i < itercount; i++)
if (ahash[i] == ihash)
{
loop_abort = 1;
if ( i != itercount - 1)
loop_abort = 2;
};
ahash[i] = ihash;
newvallen = crm_qexpandvar (tempbuf, newvallen,
data_window_size, &qex_stat );
};
if (itercount == MAX_EVAL_ITERATIONS )
{
nonfatalerror ("The variable you're attempting to EVAL seems to eval "
"infinitely, and hence I cannot compute it. I did try "
"a lot, though. I got this far before I gave up: ",
tempbuf);
return (0);
}
if (loop_abort == 2)
{
nonfatalerror ("The variable you're attempting to EVAL seemes to return "
"to the same value after a number of iterations, "
"so it is probably an "
"infinite loop. I think I should give up. I got this "
"far: ", tempbuf);
return (0);
};
// and shove it out to wherever it needs to be shoved.
//
if (has_output_var)
crm_destructive_alter_nvariable (varname, varnamelen,
tempbuf, newvallen);
if (internal_trace)
fprintf (stderr, "Final qex_stat was %ld\n", qex_stat);
// for now, use the qex_stat that came back from qexpandvar.
if (qex_stat > 0)
{
if (user_trace)
fprintf (stderr, "Mathematical expression at line was not satisfied, doing a FAIL at line %ld\n", csl->cstmt);
csl->cstmt = csl->mct[csl->cstmt]->fail_index - 1;
csl->aliusstk [ csl->mct[csl->cstmt]->nest_level ] = -1;
}
return (0);
}
int crm_expr_alter (CSL_CELL *csl, ARGPARSE_BLOCK *apb)
{
// here's where we surgiclly alter a variable. We have to
// watch out in case a variable is not in the cdw (it might
// be in tdw; that's legal as well.
// syntax is to replace the contents of the variable in the
// varlist with the evaluated string.
// Syntax is "alter <flags> (var) /newvalue/
char varname[MAX_VARNAME];
long varnamestart;
long varnamelen;
long newvallen;
// should use tempbuf for this instead.
// char newstr [MAX_PATTERN];
if (user_trace)
fprintf (stderr, "Executing an ALTERation\n");
// get the variable name
crm_get_pgm_arg (varname, MAX_VARNAME, apb->p1start, apb->p1len);
if (apb->p1len < 3)
{
nonfatalerror (
"This statement is missing the variable to alter,\n",
"so I'll ignore the whole statement.");
return (0);
};
// do variable substitution on the variable name
varnamelen = crm_nexpandvar (varname, apb->p1len, MAX_VARNAME);
crm_nextword (varname, varnamelen, 0, &varnamestart, &varnamelen);
if (varnamelen - varnamestart < 3)
{
nonfatalerror (
"The variable you're asking me to alter has an utterly bogus name\n",
"so I'll ignore the whole statement.");
return (0);
};
// get the new pattern, and expand it.
crm_get_pgm_arg (tempbuf, data_window_size, apb->s1start, apb->s1len);
newvallen = crm_nexpandvar (tempbuf, apb->s1len, data_window_size);
crm_destructive_alter_nvariable (&varname[varnamestart], varnamelen,
tempbuf, newvallen);
return (0);
};
syntax highlighted by Code2HTML, v. 0.9.1