File: crm_expr_alter.c

package info (click to toggle)
crm114 20080330-2
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 2,788 kB
  • ctags: 1,244
  • sloc: ansic: 29,897; sh: 1,047; makefile: 407; lisp: 208
file content (225 lines) | stat: -rw-r--r-- 7,291 bytes parent folder | download
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);
};