1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
// 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)
{
nonfatalerror5
( "The variable you're asking me to alter has an utterly bogus name\n",
"so I'll pretend it has no output variable.",
CRM_ENGINE_HERE);
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 )
{
nonfatalerror5 ("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, CRM_ENGINE_HERE);
return (0);
}
if (loop_abort == 2)
{
nonfatalerror5 ("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, CRM_ENGINE_HERE);
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)
{
nonfatalerror5 (
"This statement is missing the variable to alter,\n",
"so I'll ignore the whole statement.",
CRM_ENGINE_HERE);
return (0);
};
// do variable substitution on the variable name
varnamelen = crm_nexpandvar (varname, apb->p1len, MAX_VARNAME);
// this next part goes away for LAZY variables
crm_nextword (varname, varnamelen, 0, &varnamestart, &varnamelen);
if (varnamelen - varnamestart < 3)
{
nonfatalerror5
( "The variable you're asking me to alter has an utterly bogus name\n",
"so I'll ignore the whole statement.",
CRM_ENGINE_HERE);
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);
};
|