1 // crm_var_hash_table.c - handle variable hash tables
2
3 // Copyright 2001-2009 William S. Yerazunis.
4 // This file is under GPLv3, as described in COPYING.
5
6 // include some standard files
7 #include "crm114_sysincludes.h"
8
9 // include any local crm114 configuration file
10 #include "crm114_config.h"
11
12 // include the crm114 data structures file
13 #include "crm114_structs.h"
14
15 // and include the routine declarations file
16 #include "crm114.h"
17
18 // the globals used when we need a big buffer - allocated once, used
19 // wherever needed. These are sized to the same size as the data window.
20 extern char *tempbuf;
21
22
23 // initialize the variable hash table (the vht)
24 // and stuff in the "standards" (:_vars:, environment vars)
25 //
crm_vht_init(int argc,char ** argv)26 void crm_vht_init (int argc, char **argv)
27 {
28 long i, j, k;
29 long uvstart = 0; // uvstart is the arg that the user sees (post "--")
30 long uvlist = 0;
31 char uvset[MAX_VARNAME];
32 extern char **environ;
33 char posvars[MAX_VARNAME];
34
35
36 // create the variable hash table (one big one, shared )
37 vht = (VHT_CELL **) malloc (sizeof (VHT_CELL *) * vht_size);
38 if (!vht)
39 untrappableerror5("Couldn't malloc VHT cell.\n",
40 "No VHT cells, no variables, so no can run. Sorry.",
41 CRM_ENGINE_HERE);
42 for (i = 0; i < vht_size; i++)
43 vht[i] = NULL;
44
45
46 // initialize the temporary (non-data-window) area...
47 tdw = malloc (sizeof (CSL_CELL));
48 if (!tdw)
49 untrappableerror5 ("Couldn't malloc tdw.\n"
50 "We need the TDW for isolated variables."
51 "Can't continue. Sorry.\n","", CRM_ENGINE_HERE);
52 tdw->filename = NULL;
53 tdw->rdwr = 1;
54 tdw->filedes = -1;
55 tdw->filetext = malloc (sizeof (char) * data_window_size);
56 if (!tdw->filetext)
57 untrappableerror5("Couldn't malloc tdw->filetext.\n"
58 "Without this space, you can't have any isolated "
59 "variables,\n and we're stuck. Sorry.","",
60 CRM_ENGINE_HERE);
61 tdw->filetext[0] = '\000';
62 tdw->nchars = 0;
63 tdw->hash = 0;
64 tdw->mct = NULL;
65 tdw->nstmts = -1;
66 tdw->cstmt = -1;
67 tdw->caller = NULL;
68
69 // install a few constants.
70
71 crm_set_temp_var (":_nl:", "\n");
72 crm_set_temp_var (":_ht:", "\t");
73 crm_set_temp_var (":_bs:", "\b");
74 crm_set_temp_var (":_sl:", "/");
75 crm_set_temp_var (":_sc:", ";");
76 crm_set_temp_var (":_cd:", "0");
77 crm_set_temp_var ("::", " ");
78
79 // put the version string in as a variable.
80 {
81 char verstr[1025];
82 verstr[0] = 0;
83 strcat (verstr, VERSION);
84 strcat (verstr, " ( ");
85 strcat (verstr, crm_regversion());
86 strcat (verstr, " )");
87 crm_set_temp_var (":_crm_version:", verstr);
88 };
89
90 //
91 // install the argc and argv values; restart argv values from [2]
92 // if a "--" metaflag is seen.
93 //
94 // argv[0] and argv[1] are not overrideable by "--".
95 crm_set_temp_var ( ":_arg0:", argv[0] );
96 crm_set_temp_var ( ":_arg1:", argv[1] );
97
98 // Check to see if there's a "--" arg. If so, mark uvstart
99 // (that is, "user var start" at that point)... but only the first "--".
100 {
101 long i, j;
102 uvstart = 2;
103 i = 0; j = 0;
104 for (i = 2; argc > i; i++)
105 {
106 // Check for the "--" metaflag
107 if (strlen (argv[i]) == 2
108 && strncmp (argv[i], "--", 2) == 0
109 && uvstart == 2)
110 {
111 if (internal_trace)
112 fprintf (stderr, "Resetting uvstart counter to 2\n");
113 uvstart = i+1;
114 };
115 }
116 };
117
118 // The user variables start at argv[uvstart]
119 {
120 long i, j;
121 char anamebuf [255];
122 j = 2;
123 for ( i = uvstart; argc > i; i++ )
124 {
125 sprintf (anamebuf, ":_arg%ld:", j);
126 crm_set_temp_var ( anamebuf, argv[i] );
127 j++;
128 };
129 //
130 // and put the "user-visible" argc into a var as well.
131 sprintf (anamebuf, "%ld", j );
132 crm_set_temp_var (":_argc:", anamebuf);
133 //
134 // Go through argv, and place positional arguments (that is,
135 // arguments that don't contain any '-' preambles) into
136 // :_pos0:, :_pos1:, ...
137 //
138 // :_pos0: is always the name of the CRM114 engine.
139 // :_pos1: is always the name of the program being run.
140 // :_pos2: and so on are the command line args.
141 //
142 // prepare to treasure up the positional args
143 posvars[0] = '\000';
144 j = 0;
145
146 for ( i = uvstart; i < argc ; i++ )
147 {
148 //
149 // check for the "-" sign; this is a positional argument only
150 // if there is no "-" sign.
151 if (argv[i][0] != '-')
152 {
153 sprintf (anamebuf, ":_pos%ld:", j);
154 crm_set_temp_var ( anamebuf, argv[i] );
155 j++;
156 if (j>0) strcat (posvars, " ");
157 strcat (posvars, argv[i]);
158 };
159 };
160 sprintf (anamebuf, "%ld", j);
161 crm_set_temp_var (":_posc:", anamebuf);
162 crm_set_temp_var (":_pos_str:", posvars);
163 //
164 // and set the fault to be a null string for now.
165 crm_set_temp_var (":_fault:", "");
166 //
167 // set the current line number to a set of zeroes...
168 crm_set_temp_var (":_cs:", "00000000");
169 //
170 // Set the "lazy" intermediate variable to just a space.
171 // This will get rebound to point to the active lazy var.
172 crm_set_temp_var (":_lazy:", " ");
173
174 // set the current pid and parent pid.
175 {
176 char pidstr [32];
177 long pid;
178 pid = (long) getpid();
179 sprintf (pidstr, "%ld", pid);
180 crm_set_temp_var (":_pid:", pidstr);
181 #ifndef CRM_WINDOWS
182 pid = (long) getppid();
183 sprintf (pidstr, "%ld", pid);
184 crm_set_temp_var (":_ppid:", pidstr);
185 #endif // !CRM_WINDOWS
186 }
187
188
189 };
190
191 // now, we shove the whole contents of the ENVIRON
192 // vector into the VHT.
193
194 i = 0;
195 tempbuf[0] = '\000';
196 if ( ! ignore_environment_vars)
197 while (environ [i])
198 {
199 char *name;
200 char *value ;
201 j = 0;
202 if (strlen (tempbuf) + strlen (environ[i]) < (data_window_size - 1000))
203 {
204 strcat (tempbuf, environ[i]);
205 strcat (tempbuf, "\n");
206 }
207 else
208 untrappableerror5 ("The ENVIRONMENT variables don't fit into the "
209 "available space. \nThis is very broken. Try "
210 "a larger data window (with flag -w NNNNN), \nor "
211 "drop the environment vars with "
212 "the (with flag -e)", "", CRM_ENGINE_HERE);
213 while (environ[i][j] != '=') j++;
214 name = (char *) malloc ((sizeof (char)) * (j+200));
215 if (!name)
216 untrappableerror5("Couldn't malloc :_env_ space."
217 "Can't continue.\n","", CRM_ENGINE_HERE);
218 strcpy (name, ":_env_");
219 memmove (&(name[strlen(name)]), &(environ[i][0]), j);
220 name[j+6] = '\000';
221 strcat (name, ":");
222 j++; // step past the equals sign.
223 k = 0;
224 value = strdup (&(environ[i][j+k]));
225 crm_set_temp_var (name, value);
226 free (name);
227 free (value);
228 i++; // and do the next environment variable
229 };
230 crm_set_temp_var (":_env_string:", tempbuf);
231
232 // see if argv [1] is a '-( whatever) arg, which limits the
233 // set of runtime parameters allowed on the command line.
234 // If so, we have the limit list. We put spaces around the
235 // args so we can just use strstr(3) to see if an arg is permitted
236 // or if we should fault out. Note that at this point,
237 // we've trashed the contents of uvlist (the parens and the
238 // trailing '--', if there was one.
239 //
240 if (strncmp (argv[1], "-(", 2) == 0)
241 {
242 long closepos;
243 uvlist = 1;
244 strcpy (uvset, " ");
245 strncat (uvset, &argv[1][2], strlen (argv[1]) - 3);
246 // nuke the closing paren
247 closepos = 2;
248 while (uvset[closepos] != ')' && uvset[closepos] != '\000')
249 closepos++;
250 uvset[closepos] = '\000';
251 strcat (uvset, " ");
252 if (user_trace) fprintf (stderr, "UVset: =%s=\n", uvset);
253 }
254 //
255 //
256 // go through argv again, but this time look for "--foo"
257 // and "--foo=bar" args.
258 //
259 {
260 long i, j, k;
261 char anamebuf [MAX_VARNAME];
262 char avalbuf [MAX_VARNAME];
263 long isok;
264 i = 0; j = 0; k = 0;
265 for ( i = uvstart; argc > i; i++ )
266 {
267 // check for the "--" metaflag preamble
268 if (strlen ( argv[i] ) > 2 && strncmp (argv[i], "--", 2) == 0)
269 {
270 isok = 1;
271 if (uvlist == 1)
272 {
273 isok = 0;
274 // build a testable name out of the -- flagname
275 strcpy (anamebuf, " ");
276 j=2; k = 1;
277 while (argv[i][j] != '\000' && argv[i][j] != '=')
278 {
279 anamebuf[k] = argv[i][j];
280 j++;
281 k++;
282 };
283 anamebuf[k] = 0;
284 strcat (anamebuf, " ");
285 //
286 // now we have the var name, surrounded by spaces
287 // we strstr() it to see if it's allowed or not.
288 if (strstr(uvset, anamebuf)) isok = 1;
289 //
290 // Well, maybe the name by itself is too loose;
291 // also allow name=value
292 strcpy (anamebuf, " ");
293 strcat (anamebuf, &argv[i][2]);
294 strcat (anamebuf, " ");
295 if (strstr(uvset, anamebuf)) isok = 1;
296 }
297 if (isok)
298 {
299 if (internal_trace)
300 fprintf (stderr, "setting cmdline string %s", argv[i]);
301 strcpy (avalbuf, "SET");
302 j = 2; k = 0;
303 // copy the varname into anamebuf
304 anamebuf[k] = ':';
305 k++;
306 while (argv[i][j] != '\000' && argv[i][j] != '=')
307 {
308 anamebuf[k] = argv[i][j];
309 j++;
310 k++;
311 };
312 anamebuf[k] = ':';
313 k++;
314 anamebuf[k] = '\000';
315 if (argv[i][j] == '=')
316 {
317 j++; // skip over the = sign
318 k = 0;
319 while (argv[i][j] != '\000')
320 {
321 avalbuf[k] = argv[i][j];
322 j++;
323 k++;
324 }
325 avalbuf [k] = '\000';
326 }
327 if (user_trace)
328 fprintf (stderr, "\n Setting cmdline var '%s' to '%s'\n",
329 anamebuf, avalbuf);
330 crm_set_temp_var ( anamebuf, avalbuf );
331 }
332 else
333 {
334 fprintf (stderr,
335 "\n ***Warning*** "
336 "This program does not accept the "
337 "flag '%s' , \n", anamebuf);
338 fprintf (stderr,
339 " so we'll just ignore it for now. \n");
340 };
341 };
342 };
343 };
344 }
345 // routine to put a variable into the temporary (tdw)
346 // buffer. names and values end up interleaved
347 // sequentially, separated by newlines. TDW really should have
348 // been called the idw (Isolated Data Window) but it's too
349 // late to fix it now.
350 //
351 //
crm_set_temp_nvar(char * varname,char * value,long vallen)352 void crm_set_temp_nvar (char *varname, char *value, long vallen)
353 {
354 long namestart, namelen;
355 long valstart;
356 long i;
357 long vnidx, vnlen;
358
359 // do the internal_trace thing
360 if (internal_trace)
361 fprintf (stderr, " setting temp-area variable %s to value %s\n",
362 varname, value);
363
364 i = crm_nextword (varname,strlen (varname), 0, &vnidx, &vnlen);
365 if ( i == 0)
366 {
367 nonfatalerror5 ("Somehow, you are assigning a value to a variable with",
368 "an unprintable name. I'll permit it for now, but"
369 "your program is probably broken.", CRM_ENGINE_HERE);
370 };
371
372 if ( (strlen (varname) + vallen + tdw->nchars + 1024) > data_window_size)
373 {
374 nonfatalerror5 ("This program has overflowed the ISOLATEd data "
375 "area with a variable that's just too big. We'll "
376 "clip the tail off the string to fit in available memory. "
377 "The big bad variable was named: ",
378 varname, CRM_ENGINE_HERE);
379 vallen = data_window_size - (strlen (varname)) - tdw->nchars - 1024;
380 if (vallen < 1)
381 fatalerror5 ("Your program is so low on memory that it could not "
382 "even clip the big variable. This is really bad. "
383 "The evil variable was named: " ,
384 varname, CRM_ENGINE_HERE);
385 };
386
387 // check- is this the first time we've seen this variable? Or
388 // are we re-assigning a previous variable?
389 i = crm_vht_lookup (vht, &varname[vnidx], vnlen);
390 if (vht[i] == NULL)
391 {
392 // never assigned this variable before, so we stick it in the
393 // tdr window.
394 //
395 // do the name first. Start with a newline.
396 // GROT GROT GROT
397 tdw->filetext[tdw->nchars] = '\n';
398 tdw->nchars++;
399 namestart = tdw->nchars;
400 namelen = vnlen;
401 memmove (&(tdw->filetext[tdw->nchars]), &(varname[vnidx]), namelen);
402 tdw->nchars = tdw->nchars + namelen;
403 //
404 // and add a separator to prevent the varname from sharing
405 // an endpoint offset with the var value.
406 tdw->filetext[tdw->nchars] = '=';
407 tdw->nchars++;
408 //
409 // and the value second
410 valstart = tdw->nchars;
411 memmove (&tdw->filetext [tdw->nchars], value, vallen);
412 tdw->nchars = tdw->nchars + vallen;
413 //
414 // add a separator again, so we don't get strings with overlapped
415 // ranges into the var hash table
416 tdw->filetext[tdw->nchars] = ' ';
417 tdw->nchars++;
418 //
419 // and put a NUL at the end of the tdw, so debuggers won't get
420 // all bent out of shape.
421 tdw->filetext[tdw->nchars] = '\000';
422 //
423 // now, we whack the actual VHT.
424 crm_setvar (NULL, 0,
425 tdw->filetext, namestart, namelen,
426 tdw->filetext, valstart, vallen,
427 0, 0);
428 // that's it.
429
430 }
431 else
432 {
433 // This variable is preexisting. Perform an ALTER on it.
434 //
435 crm_destructive_alter_nvariable ( &varname[vnidx], vnlen,
436 value, vallen );
437 };
438 }
439
440 // GROT GROT GROT this routine needs to replaced for 8-bit-safeness.
441 // Use ONLY where you can be sure no embedded NULs will be seen (i.e.
442 // fixed strings in the early startup.
443 //
crm_set_temp_var(char * varname,char * value)444 void crm_set_temp_var (char *varname, char *value)
445 {
446 crm_set_temp_nvar (varname, value, strlen (value));
447 }
448
449
450
451 // routine to put a data-window-based (the cdw, that is)
452 // variable into the VHT. The text of the variable's name
453 // goes into the tdw buffer, and the value stays in the main
454 // data window (cdw) buffer.
455 //
456 // This is equivalent to a "bind" operation - that is, the
457 // pointers move around, but the data window doesn't get
458 // changed.
459 //
460 // Note - if you rebind a var, you should consider if your
461 // routine should also evaluate the old area for reclamation.
462 // (reclamation uses "crm_compress_tdw_section", see comments
463 // further down in the code here)
464
crm_set_windowed_nvar(char * varname,long varlen,char * valtext,long start,long len,long stmtnum)465 void crm_set_windowed_nvar ( char *varname,
466 long varlen,
467 char *valtext,
468 long start,
469 long len,
470 long stmtnum)
471 {
472 long i;
473 long namestart, namelen;
474 // do the internal_trace thing
475 if (internal_trace)
476 {
477 long i;
478 fprintf (stderr, " setting data-window variable %s to value ",
479 varname);
480 for (i = start; i < start+len; i++)
481 fprintf (stderr, "%c", valtext[i]);
482 fprintf (stderr, "\n");
483 };
484
485 // check and see if the variable is already in the VHT
486 i = crm_vht_lookup (vht, varname, varlen);
487 if (vht[i] == NULL)
488 {
489 // nope, never seen this var before, add it into the VHT
490 // namestart is where we are now.
491 if (internal_trace)
492 fprintf (stderr, "... new var\n");
493 //
494 // Put the name into the tdw memory area, add a & after it.
495 //
496 // do the name first. Start on a newline.
497 tdw->filetext[tdw->nchars] = '\n';
498 tdw->nchars++;
499 namestart = tdw->nchars;
500 namelen = varlen;
501 memmove (&tdw->filetext[namestart], varname, varlen);
502 tdw->nchars = tdw->nchars + namelen;
503 //
504 // put in an "&" separator
505 tdw->filetext[tdw->nchars] = '&';
506 tdw->nchars++;
507 //
508 // now, we whack the actual VHT.
509 crm_setvar (NULL, 0,
510 tdw->filetext, namestart, namelen,
511 valtext, start, len,
512 stmtnum, 0);
513 // that's it.
514 }
515 else
516 {
517 // We've seen this var before. But, there's a gotcha.
518 // If the var _was_ in the tdw, but is now being moved back
519 // to the cdw, or being rebound inside another tdw var,
520 // then the prior var value might now be dead- that is, "leaked
521 // memory", and now inaccessible.
522 //
523 {
524
525 // move the text/start/len values around to accomodate the new
526 // value.
527 //
528 if (internal_trace)
529 fprintf (stderr, "... old var\n");
530 crm_setvar (NULL, 0,
531 vht[i]->nametxt, vht[i]->nstart, vht[i]->nlen,
532 valtext, start, len,
533 stmtnum, 0);
534
535 // Do we need to repair the leaked memory? Only necessary if the
536 // old text was in the tdw area; this is harmless if the area
537 // is in use by another var, but if we have removed the last
538 // reference to any tdw-based vars, we ought to reclaim them..
539 //
540 // NOTE - we don't do it here since synchronicity issues
541 // between a var being rebound, reclamation happening,
542 // and then another var _in the same match_ being bound
543 // (to a old, unupdated set of offsets) is such a pain.
544 //
545 // Instead, routines using this routine should also be sure
546 // to call crm_compress_tdw_section if there's a chance they
547 // should be releasing TDW memory. AFTER they've done ALL the
548 // rebinding. That way, all indices and offsets are in the VHT
549 // where they can be safely updated.
550 //
551 };
552 };
553 }
554
555 //#define RECLAIM_ALL_EVERY_TIME 1
556 #ifdef RECLAIM_ALL_EVERY_TIME
557 //
558 // How we compress out an area that might no longer be in use.
559 static long crm_recursive_compress_tdw_section
560 (char *oldtext, long oldstart, long oldend);
561
crm_compress_tdw_section(char * oldtext,long oldstart,long oldend)562 long crm_compress_tdw_section (char *oldtext, long oldstart, long oldend)
563 {
564 // let's court death, and do a FULL compress.
565 return (crm_recursive_compress_tdw_section
566 (tdw->filetext, 0, tdw->nchars + 1));
567 }
crm_recursive_compress_tdw_section(char * oldtext,long oldstart,long oldend)568 long crm_recursive_compress_tdw_section
569 (char *oldtext, long oldstart, long oldend)
570 #else // !RECLAIM_ALL_EVERY_TIME
571 long crm_compress_tdw_section (char *oldtext, long oldstart, long oldend)
572 #endif // !RECLAIM_ALL_EVERY_TIME
573 {
574
575 // The algorithm basically checks to see if there is any region of
576 // the given tdw space that is not currently used by another var.
577 // All such regions are reclaimed with a slice-n-splice. We return
578 // the number of reclaimed characters.
579 //
580 // The algorithm starts out with start and end of the tenatively
581 // unused "to be killed" region. It checks each member of the VHT
582 // in the TDW. If the region overlaps, don't kill the overlapping
583 // part of the region. If at any time the region length goes to 0,
584 // we know that there's no region left to kill. (Option- if the
585 // gap is less than MAX_RECLAIMER_GAP chars, we don't bother moving
586 // it; we retain it as buffer. This minimizes thrashing
587 //
588 // NOTE that the END VALUES ONLY "oldend" and "newend" vars are
589 // NON-inclusive, they index the first NON-involved character
590 // (oldstart and newstart index "involved" characters, that we _do_
591 // include in our strings)
592 //
593 // BIG ISSUE: As coded, this routine needs to leave a _buffer_ of at
594 // least one UNUSED character between each used (but isolated) string
595 // area. Knowing when to get rid of extra copies of this character
596 // has been a big hassle. Right now there may be a small leak here
597 // so if you can find it, please let me know! Note that any fix that
598 // does not keep two adjacent isolated regions from merging (including
599 // when the first or second becomes a zero-length string!) will get
600 // the submittor a gentle smile and a pointer to this very comment.
601 // (the reason being that prior code that did not leave a buffer
602 // exhibited the property that if A and B were isolated but adjacent,
603 // and then A shrank to 0 length, then B would share the same start
604 // point, and an alteration to A would then *also* insert at the start
605 // point of B, causing A and B to become NONisolated and space-sharing.
606 // That said- enjoy the bug hunt. :)
607
608 long j, newstart, newend, reclaimed;
609
610 j = newstart = newend = reclaimed = 0;
611
612 // return (0);
613
614 j = newstart = newend = reclaimed = 0;
615 if (internal_trace)
616 fprintf (stderr, " [ Compressing isolated data. Length %ld chars, "
617 "start %ld, len %ld ]\n",
618 tdw->nchars,
619 oldstart,
620 oldend - oldstart);
621
622 // If oldstart >= oldend, then there's no compression to be done.
623 //
624 if (oldstart >= oldend )
625 {
626 if (internal_trace)
627 fprintf (stderr, " [ Zero-length compression string... don't do this! ]\n");
628 return (0);
629 }
630
631 if (oldtext != tdw->filetext)
632 {
633 fatalerror5 (" Request to compress non-TDW data. This is bogus. ",
634 " Please file a bug report", CRM_ENGINE_HERE);
635 return ( 0 );
636 };
637
638 // Look one character further to before and after;
639 //if (oldstart > 3) oldstart --;
640 //if (oldend < data_window_size - 1) oldend ++;
641
642 for (j = 0; j < vht_size; j++)
643 {
644 if (vht[j] // is this slot in use?
645 && vht[j]->valtxt == tdw->filetext
646 // Note that being part of :_iso: does NOT exclude from reclamation
647 && 0 != strncmp (&vht[j]->nametxt[vht[j]->nstart], ":_iso:", 6 ))
648 {
649 // for convenience, we get nice short names:
650 newstart = vht[j]->vstart - 1;
651 newend = newstart + vht[j]->vlen + 2;
652 // leave some space no matter what...
653 if (newend < newstart + 2) newend = newstart + 2;
654
655 // 6 Possible cases:
656 // dead zone entirely before current var
657 // dead zone entirely after current var
658 // dead zone entirely inside current var
659 // dead zone overlaps front of current var
660 // dead zone overlaps back of current var
661 // dead zone split by current var
662 //
663
664 // 1: dead zone entirely before current var
665 //
666 // <os------------oe>
667 // <ns--------ne>
668 //
669 if ( oldend <= newstart)
670 {
671 // nothing to be done here - not overlapping
672 goto end_of_vstring_tests;
673 };
674
675 // 2: dead zone entirely after current var
676 //
677 // <os------------oe>
678 // <ns--------ne>
679 //
680 if ( newend <= oldstart )
681 {
682 // nothing to be done here - not overlapping
683 goto end_of_vstring_tests;
684 };
685
686 // If we get this far, the dead zone in some way overlaps with
687 // our current variable.
688
689 // 3: dead zone entirely inside a currently live var
690 //
691 // <os-------oe>
692 // <ns----------------ne>
693 //
694 // So we terminate this procedure (nothing can be reclaimed)
695 //
696 if (oldstart >= newstart && oldend <= newend)
697 {
698 // the dead zone is inside a non-dead var, so
699 // we can terminate our search right now.
700 if ( internal_trace)
701 fprintf (stderr, " [ Compression not needed after all. ]\n");
702 return ( 0 );
703 };
704
705 // 4: dead zone overlaps front of current var; we trim the
706 // dead zone to not include the current var.
707 //
708 // <os------------oe>
709 // <ns--------ne>
710 //
711 if ( oldstart < newstart && oldend <= newend )
712 {
713 // The dead zone should not include the part that's
714 // also new variable. So, we clip out the part
715 // that's still active.
716 if ( internal_trace)
717 fprintf (stderr, " [ Trimming tail off of compression. ]\n");
718 //
719 // newstart is a "good" char, but since oldend is
720 // noninclusive, this is right.
721 oldend = newstart;
722 goto end_of_vstring_tests;
723 };
724
725 // 5: dead zone overlaps back of current var; trim the front off
726 // the dead zone.
727 //
728 // <os------------oe>
729 // <ns--------ne>
730 //
731 if (newstart <= oldstart && newend <= oldend)
732 {
733 if (internal_trace)
734 fprintf (stderr, " [ Trimming head off of compression. ]\n");
735 //
736 // Newend is the first char that ISN'T in the var, so this
737 // is correct.
738 oldstart = newend ;
739 goto end_of_vstring_tests;
740 };
741 // 6: dead zone split by current var - the dead zone is actually
742 // split into two distinct pieces. In this case, we need to
743 // recurse on the two pieces.
744 //
745 // <os--------------------oe>
746 // <ns--------ne>
747 //
748 if ( oldstart <= newstart && newend <= oldend )
749 {
750 if (internal_trace)
751 {
752 fprintf (stderr, " [ Compression split ]\n");
753 fprintf (stderr, " [ First part will be %ld to %ld .]\n",
754 oldstart, newstart);
755 fprintf (stderr, " [ Second part will be %ld to %ld .]\n",
756 newend, oldend);
757 };
758 //
759 // Tricky bit here - we have to do the aft (ne-oe
760 // section) first, so we don't move the os-ns
761 // section offsets.
762 //
763
764 // was newend - 1, but should be same as case 3
765 // above (dead zone overlaps tail)
766 #ifdef RECLAIM_ALL_EVERY_TIME
767 reclaimed = crm_recursive_compress_tdw_section (oldtext, newend, oldend);
768 reclaimed +=crm_recursive_compress_tdw_section(oldtext, oldstart, newstart);
769 #else // ! RECLAIM_ALL_EVERY_TIME
770 reclaimed = crm_compress_tdw_section (oldtext, newend, oldend);
771 reclaimed +=crm_compress_tdw_section(oldtext, oldstart, newstart);
772 #endif // ! RECLAIM_ALL_EVERY_TIME
773 // Return here instead of executing common slice-and-splice
774 // tail, because each of our recursive children will do
775 // that for us.
776 return (reclaimed);
777 }
778 }
779 // and the semicolon to keep some compilers happy
780 end_of_vstring_tests: ;
781 // Now, repeat with the name string - all name strings are protected
782 if (vht[j]
783 && vht[j]->nametxt == tdw->filetext)
784 {
785 newstart = vht[j]->nstart - 1 ;
786 newend = newstart + vht[j]->nlen + 2;
787 // leave some space no matter what...
788 if (newend < newstart + 4) newend = newstart + 2;
789
790 // Possible cases:
791 // dead zone entirely before current var
792 // dead zone entirely after current var
793 // dead zone entirely inside current var
794 // dead zone overlaps front of current var
795 // dead zone overlaps back of current var
796 // dead zone split by current var
797 //
798 // dead zone entirely before current var
799 //
800 // <os------------oe>
801 // <ns--------ne>
802 // OK
803 if ( oldend <= newstart)
804 {
805 // nothing to be done here - not overlapping
806 goto end_of_nstring_tests;
807 };
808
809 // dead zone entirely after current var
810 //
811 // <os------------oe>
812 // <ns--------ne>
813 //
814 if ( newend <= oldstart )
815 {
816 // nothing to be done here - not overlapping
817 goto end_of_nstring_tests;
818 };
819
820 // If we get this far, the dead zone in some way overlaps with
821 // our current variable.
822
823 // dead zone entirely inside a currently live var
824 //
825 // <os-------oe>
826 // <ns----------------ne>
827 //
828 // So we terminate this procedure (nothing can be reclaimed)
829 //
830 if (oldstart >= newstart && oldend <= newend)
831 {
832 // the dead zone is inside a non-dead var, so
833 // we can terminate our search right now.
834 if ( internal_trace)
835 fprintf (stderr, " [ Compression not needed after all. ]\n");
836 return ( 0 );
837 };
838
839 // dead zone overlaps front of current var; we trim the
840 // dead zone to not include the current var.
841 //
842 // <os------------oe>
843 // <ns--------ne>
844 //
845 if ( oldstart < newstart && oldend <= newend )
846 {
847 // The dead zone should not include the part that's
848 // also new variable. So, we clip out the part
849 // that's still active.
850 if ( internal_trace)
851 fprintf (stderr, " [ Trimming tail off of compression. ]\n");
852 //
853 // newstart is a "good" char, but since oldend is
854 // noninclusive, this is right.
855 oldend = newstart;
856 goto end_of_nstring_tests;
857 };
858
859 // dead zone overlaps back of current var; trim the front off
860 // the dead zone.
861 //
862 // <os------------oe>
863 // <ns--------ne>
864 //
865 if (newstart <= oldstart && newend <= oldend)
866 {
867 if (internal_trace)
868 fprintf (stderr, " [ Trimming head off of compression. ]\n");
869 //
870 // Newend is the first char that ISN'T in the var, so this
871 // is correct.
872 oldstart = newend ;
873 goto end_of_nstring_tests;
874 };
875 // dead zone split by current var - the dead zone is actually
876 // split into two distinct pieces. In this case, we need to
877 // recurse on the two pieces.
878 //
879 // <os--------------------oe>
880 // <ns--------ne>
881 //
882 if ( oldstart <= newstart && newend <= oldend )
883 {
884 if (internal_trace)
885 {
886 fprintf (stderr, " [ Compression split ]\n");
887 fprintf (stderr, " [ First part will be %ld to %ld .]\n",
888 oldstart, newstart);
889 fprintf (stderr, " [ Second part will be %ld to %ld .]\n",
890 newend, oldend);
891 };
892 //
893 // Tricky bit here - we have to do the aft (ne-oe
894 // section) first, so we don't move the os-ns
895 // section offsets.
896 //
897
898 // was newend - 1, but should be same as case 3
899 // above (dead zone overlaps tail)
900 #ifdef RECLAIM_ALL_EVERY_TIME
901 reclaimed = crm_recursive_compress_tdw_section (oldtext, newend, oldend);
902 reclaimed +=crm_recursive_compress_tdw_section (oldtext, oldstart, newstart);
903 #else // ! RECLAIM_ALL_EVERY_TIME
904 reclaimed = crm_compress_tdw_section (oldtext, newend, oldend);
905 reclaimed +=crm_compress_tdw_section (oldtext, oldstart, newstart);
906 #endif // ! RECLAIM_ALL_EVERY_TIME
907 // Return here instead of executing common slice-and-splice
908 // tail, because each of our recursive children will do
909 // that for us.
910 return (reclaimed);
911 }
912 // and the semicolon to keep some compilers happy
913 end_of_nstring_tests: ;
914 };
915 };
916 //
917 // Well, we've now scanned the VHT, and oldstart/oldend are the
918 // actual dead zone (storage that really isn't used).
919 //
920 // So, we can compress this storage out with a slice-and-splice
921 // return how many character cells we were able to reclaim.
922 //
923 {
924 long cutlen;
925 // cutlen is supposed to be negative for compress
926 cutlen = oldstart - oldend - 1;
927 if (cutlen > 0)
928 fatalerror5 ("Internal cut-length error in isolated var reclamation.",
929 " Please file a bug report", CRM_ENGINE_HERE);
930
931 // Future Enhancement - dead zones of some small size should be
932 // allowed to stay. This would speed up WINDOW a lot. (but we
933 // would need to expand the range of oldstart and oldend to
934 // actually reclaim those areas if storage really ran low.
935 // Maybe this should be compile-time or command-line parameter?)
936
937 if (cutlen < 0)
938 {
939 if (internal_trace)
940 {
941 fprintf (stderr, " [ compression slice-splice at %ld for %ld chars. ]\n",
942 oldstart, cutlen);
943 }
944 crm_slice_and_splice_window (tdw, oldstart, cutlen);
945 if (internal_trace)
946 {
947 fprintf (stderr, " [ new isolated area will be %ld bytes. ]\n",
948 tdw->nchars);
949 };
950 };
951 return (- (cutlen));
952 };
953 }
954
955 //
956 // Destructive alteration of a preexisting variable, which can be
957 // anywhere. If the variable is not preexisting, we create it and
958 // toss a nonfatal error.
959 //
960
crm_destructive_alter_nvariable(char * varname,long varlen,char * newstr,long newlen)961 void crm_destructive_alter_nvariable (char *varname, long varlen,
962 char *newstr, long newlen)
963 {
964 long i;
965 long vhtindex, oldlen, delta;
966
967 // get the first variable name and verify it exists.
968 // GROT GROT GROT this should use nextword!!!
969 i = 0;
970 while (varname[i] < 0x021 && i < varlen) i++;
971 vhtindex = crm_vht_lookup (vht, &(varname[i]), varlen);
972 if (vht[vhtindex] == NULL)
973 {
974 // IGNORE FOR NOW
975 nonfatalerror5 (" Attempt to alter the value of a nonexistent "
976 "variable, so I'm creating an ISOLATED variable. "
977 "I hope that's OK. The nonexistent variable is: ",
978 &(varname[i]), CRM_ENGINE_HERE);
979 crm_set_temp_var (&varname[i], "");
980 };
981
982 // make enough space in the input buffer to accept the new value
983 oldlen = vht[vhtindex]->vlen;
984 delta = newlen - oldlen;
985 mdw = NULL;
986 if (tdw->filetext == vht[vhtindex]->valtxt)
987 mdw = tdw;
988 if (cdw->filetext == vht[vhtindex]->valtxt)
989 mdw = cdw;
990
991 // GROT GROT GROT get rid of this if we go to MAPped file vars.
992 if (mdw == NULL)
993 {
994 fatalerror5 (" Bogus text bloc containing variable : ",
995 varname, CRM_ENGINE_HERE);
996 goto bailout;
997 };
998
999 //
1000 if (user_trace) // major debug
1001 {
1002 long i;
1003 // fprintf (stderr, "\n surgery on the var %s\n ", varname);
1004 fprintf (stderr, " surgery on the var >");
1005 for (i = 0; i < varlen; i++ )
1006 fprintf (stderr, "%c", varname[i]);
1007 fprintf (stderr, "<\n");
1008 //fprintf (stderr, "new value is: \n***%s***\n", newstr);
1009 fprintf (stderr, " new value is ***>");
1010 for (i = 0; i < newlen; i++ )
1011 fprintf (stderr, "%c", newstr[i]);
1012 fprintf (stderr, "<***\n");
1013 }
1014 // slice and splice the mdw text area, to make the right amount of
1015 // space...
1016 crm_slice_and_splice_window (mdw, vht[vhtindex]->vstart, delta);
1017 //
1018 // Zap the mstart and mlen markers so that searches are reset to start
1019 // of the variable. Note that we have to do this _after_ we slice
1020 // and splice, otherwise we mangle our own mstart and mlen.
1021 vht[vhtindex]->mstart = vht[vhtindex]->vstart;
1022 vht[vhtindex]->mlen = 0;
1023 //
1024 // now we have space, and we can put in the characters from
1025 // the new pattern
1026 memmove (&(mdw->filetext[vht[vhtindex]->vstart]),
1027 newstr,
1028 newlen);
1029
1030 // semicolon (null stmt) on next line to keep some compilers happy:
1031 //
1032 bailout: ;
1033 };
1034
1035
1036 // Surgically lengthen or shorten a window. The window pointed
1037 // to by mdw gets delta extra characters added or cut at "where".
1038 // (more precisely, just _before_ "where" - the insert/delet
1039 // point is just before the "where'th" character, and the
1040 // where'th character will be the first one moved. If the
1041 // allocated length is not enough, additional space can be
1042 // malloced. Finally, the vht is fixed up so everything still
1043 // points "correctly".
1044 //
crm_slice_and_splice_window(CSL_CELL * mdw,long where,long delta)1045 void crm_slice_and_splice_window ( CSL_CELL *mdw, long where, long delta)
1046 {
1047 char *taildest;
1048 char *tailsrc;
1049 long taillen;
1050
1051 // these are to keep the compiler quiet.
1052 taildest = NULL;
1053 tailsrc = NULL;
1054 taillen = 0;
1055
1056 if (delta + mdw->nchars > data_window_size - 10)
1057 {
1058 fatalerror5 (" Data window trying to get too long.",
1059 " Try increasing the data window maximum size.",
1060 CRM_ENGINE_HERE);
1061 goto bailout;
1062 };
1063
1064 if (delta == 0)
1065 {
1066 if (internal_trace)
1067 {
1068 fprintf (stderr, " zero delta, no buffer hackery required\n");
1069 };
1070 return;
1071 };
1072
1073 // bump chars in input window delta places
1074 if (internal_trace)
1075 {
1076 fprintf (stderr, "moving text in window %lx,", (long int) mdw->filetext);
1077 fprintf (stderr, " starting at %ld, ", where);
1078 fprintf (stderr, "delta length is %ld\n", delta);
1079 };
1080
1081 if (delta > 0)
1082 { // lengthening alteration...
1083 taildest = &(mdw->filetext[where + delta]);
1084 tailsrc = &(mdw->filetext[where]);
1085 taillen = mdw->nchars - where;
1086 };
1087
1088 if (delta < 0) // shortening alteration
1089 {
1090 taildest = &(mdw->filetext[where]);
1091 tailsrc = &(mdw->filetext[where - delta]); // delta is minus already!!
1092 taillen = mdw->nchars - where + delta;
1093 // taillen = mdw->nchars + 1 - where;
1094
1095 }
1096 if (internal_trace)
1097 fprintf (stderr,
1098 "buffer sliding, tailsrc: %lx, taildest: %lx, length: %ld\n",
1099 (long int) tailsrc, (long int) taildest, taillen);
1100
1101 // and move the actual data
1102 if (taillen + 1 > 0) memmove ( taildest, tailsrc, taillen + 1 );
1103
1104 // update the length of the window as well.
1105 mdw->nchars = mdw->nchars + delta;
1106
1107 // and update all of our captured variables to have the right ptrs.
1108 crm_updatecaptures (mdw->filetext,
1109 where,
1110 delta);
1111 bailout:
1112 // GROT GROT GROT
1113 // The following bit of absolutely meaningless code is just there
1114 // so that some versions of the C compiler don't complain. It does
1115 // nothing.
1116 {
1117 delta = 0;
1118 }
1119
1120 }
1121
1122 // allow_data_window_to_grow
1123 #ifdef no_dont_do_this_yet
1124 // Grow the window to hold the incoming text, if needed.
1125 // Grow it by 4x each time.
1126 while (delta + mdw->nchars > data_window_size - 1)
1127 {
1128 char *ndw;
1129 long odws, i;
1130 odws = data_window_size;
1131 data_window_size = 4 * data_window_size;
1132 nonfatalerror5 (" Data window trying to get too long.",
1133 " increasing data window... ", CRM_ENGINE_HERE);
1134 ndw = (char *) malloc ( data_window_size);
1135 if (!ndw)
1136 untrappableerror5("Couldn't malloc ndw. This is bad too.\n","",
1137 CRM_ENGINE_HERE);
1138
1139 // now copy the old data window into the new one
1140 memmove (ndw, mdw->filetext, odws);
1141
1142 // and update the outstanding pointers, like the ones in the
1143 // vht...
1144 for (i = 0; i < vht_size; i++)
1145 if (vht[i] != NULL)
1146 {
1147 if (vht[i]->nametxt == mdw->filetext)
1148 vht[i]->nametxt = ndw;
1149 if (vht[i]->valtxt == mdw->filetext)
1150 vht[i]->valtxt = ndw;
1151 };
1152
1153 // and lastly, point the cdw or tdw to the new larger window.
1154 free (mdw->filetext);
1155 mdw->filetext = ndw;
1156 };
1157 #endif // no_dont_do_this_yet
1158
1159
1160 //
1161 // crm_vht_lookup - given a char *start, long len, varnam
1162 // finds and returns the vht index of the variable
1163 // or the index of the appropriate NULL slot to put
1164 // the var in, if not found.
1165
crm_vht_lookup(VHT_CELL ** vht,char * vname,long vlen)1166 long crm_vht_lookup (VHT_CELL **vht, char *vname, long vlen)
1167 {
1168 unsigned long hc;
1169 unsigned long i, j, k;
1170 int done;
1171 long vsidx;
1172 long vslen;
1173
1174 j = 0; // just so J is used.
1175
1176 // Consistency scan - look for those null varnames! Do this every
1177 // time!
1178 if (1)
1179 {
1180 long i, j;
1181 long corrupted;
1182 for (i = 0; i < vht_size; i++)
1183 {
1184 corrupted = 0;
1185 if (vht[i] != NULL && vht[i]->nlen < 2)
1186 fprintf (stderr, "Short length %ld ", i);
1187 if (vht[i] !=NULL && vht[i]->nlen > 1)
1188 {
1189 if (vht[i]->nametxt[vht[i]->nstart] != ':')
1190 {
1191 fprintf (stderr, "Ztart corrupted ");
1192 corrupted = 1;
1193 };
1194 if (vht[i]->nametxt[vht[i]->nstart + vht[i]->nlen - 1] != ':')
1195 {
1196 fprintf (stderr, "Zend corrupted ");
1197 corrupted = 1;
1198 };
1199 if (corrupted)
1200 {
1201 fprintf (stderr, " i %ld len %ld name = -",
1202 i, vht[i]->nlen );
1203 for (j = 0; j < vht[i]->nlen; j++)
1204 fprintf (stderr, "%c",
1205 vht[i]->nametxt[vht[i]->nstart + j]);
1206 fprintf (stderr, "- ");
1207 }
1208 };
1209 }
1210 };
1211
1212
1213 crm_nextword ( vname, vlen, 0, &vsidx, &vslen);
1214 if (internal_trace)
1215 {
1216 fprintf (stderr, " variable len %ld, name is -", vslen);
1217 for (k = vsidx; k < vsidx+vslen; k++)
1218 fprintf (stderr, "%c", vname[k]);
1219
1220 fprintf (stderr, "- .\n");
1221 };
1222
1223 hc = (strnhash ( &vname[vsidx], vslen)) % vht_size;
1224
1225 // go exploring - find either an empty cell (meaning that this
1226 // is the first time this variable name has been entered into the
1227 // vht) or find the variable already entered. Or find that we've
1228 // gone the whole way 'round the vht, in which case the vht is full
1229 // and we should print ut a message and fatal error away (or maybe
1230 // even build a bigger vht?)
1231
1232 i = hc;
1233
1234 // consider a "wrap" to have occurred if we even think about
1235 // the slot just before the hashcoded slot
1236
1237 done = 0;
1238 while ( ! done )
1239 {
1240 // is there anything here yet?
1241 if (vht[i] == NULL)
1242 {
1243 if (internal_trace)
1244 {
1245 int ic;
1246 fprintf (stderr, " var ");
1247 for (ic = 0; ic < vlen; ic++)
1248 fprintf (stderr, "%c", vname[ic]);
1249 fprintf (stderr, "(len %ld) not at %ld (empty)\n", vlen, i);
1250 fprintf (stderr, "Returning the index where it belonged.\n");
1251 };
1252 return (i);
1253 };
1254
1255 // there's something here - is it what we have been seeking
1256 if ( vlen == vht[i]->nlen &&
1257 memcmp (&((vht[i]->nametxt)[vht[i]->nstart]),
1258 vname,
1259 vlen) == 0)
1260 { // Yes, we found it.
1261 if (internal_trace)
1262 {
1263 int ic;
1264 fprintf (stderr, " var '");
1265 for (ic = 0; ic < vht[i]->nlen; ic++)
1266 fprintf (stderr, "%c", (vht[i]->nametxt)[ic+vht[i]->nstart] );
1267 fprintf (stderr, " (len %ld) found at %ld (",
1268 vlen, i);
1269 if (vht[i]->valtxt == cdw->filetext)
1270 { fprintf (stderr, "(main)"); }
1271 else
1272 { fprintf (stderr, "(isol)"); };
1273 fprintf (stderr, " s: %ld, l:%ld)\n",
1274 vht[i]->vstart, vht[i]->vlen);
1275 };
1276 return (i);
1277 }
1278 else
1279 {
1280 if (internal_trace)
1281 {
1282 int ic;
1283 fprintf (stderr, "\n Hash clash (at %ld): wanted %s (len %ld)",
1284 i, vname, vlen);
1285 fprintf (stderr, " but found '");
1286 for (ic = 0; ic < vht[i]->nlen; ic++)
1287 fprintf (stderr, "%c", (vht[i]->nametxt)[ic+vht[i]->nstart] );
1288 fprintf (stderr, "' instead.");
1289 };
1290 };
1291
1292 i++;
1293 // check wraparound
1294 if (i >= vht_size)
1295 i = 0;
1296
1297 // check for hash table full - if it is, right now we
1298 // do a fatal error. Eventually we should just resize the
1299 // hash table. Even better- we should keep track of the number
1300 // of variables, and thereby resize automatically whenever we
1301 // get close to overflow.
1302 if (i == (hc - 1))
1303 {
1304 static char badvarname [MAX_VARNAME];
1305 strncpy (badvarname, &vname[vsidx], vslen);
1306 badvarname[vslen+1] = 0;
1307 {
1308 long index;
1309 fprintf (stderr, "Variable Hash Table Dump\n");
1310 for (index = 0; index < vht_size; index++)
1311 {
1312 int ic;
1313 fprintf (stderr, " var '");
1314 for (ic = 0; ic < vht[index]->nlen; ic++)
1315 fprintf (stderr, "%c",
1316 (vht[index]->nametxt) [ic+vht[index]->nstart] );
1317 fprintf (stderr, "'[%ld] found at %ld (",
1318 vht[index]->nlen, index);
1319 if (vht[index]->valtxt == cdw->filetext)
1320 { fprintf (stderr, "(main)"); }
1321 else
1322 { fprintf (stderr, "(isol)"); };
1323 fprintf (stderr, " s: %ld, l:%ld)\n",
1324 vht[index]->vstart, vht[index]->vlen);
1325 ; }
1326 };
1327 fatalerror5 (" Variable hash table overflow while looking "
1328 "for variable: " ,
1329 badvarname, CRM_ENGINE_HERE);
1330 done = 1;
1331 return (0);
1332 };
1333 };
1334 return (0);
1335 }
1336
1337
1338 //
1339 // crm_setvar - set the value of a variable into the VHT, putting a
1340 // new cell in if necessary. Note that this ONLY modifies the VHT
1341 // data itself. It does NOT do any of the background work like
1342 // copying data at all, copying varnames into the tdw, keeping track
1343 // of the cdw and tdw usage, etc.
1344 //
crm_setvar(char * filename,int filedesc,char * nametxt,long nstart,long nlen,char * valtxt,long vstart,long vlen,long linenumber,long lazy_redirects)1345 void crm_setvar (char *filename,
1346 int filedesc,
1347 char *nametxt,
1348 long nstart,
1349 long nlen,
1350 char *valtxt,
1351 long vstart,
1352 long vlen,
1353 long linenumber,
1354 long lazy_redirects)
1355 {
1356 int i, j; // some indices to bang on
1357
1358 // first off, see if the variable is already stored.
1359
1360 i = crm_vht_lookup (vht, &(nametxt[nstart]), nlen);
1361
1362
1363 if (vht[i] == NULL)
1364 {
1365 // Nope, this is an empty VHT slot
1366
1367 // allocate a fresh, empty VHT cell
1368 vht[i] = (VHT_CELL *) malloc (sizeof (VHT_CELL));
1369 if (!vht[i])
1370 untrappableerror5("Couldn't malloc space for VHT cell. We need VHT cells for variables. We can't continue.","", CRM_ENGINE_HERE);
1371
1372 // fill in the name info data
1373 vht[i]->filename = filename;
1374 vht[i]->filedesc = filedesc;
1375 vht[i]->nametxt = nametxt;
1376 vht[i]->nstart = nstart;
1377 vht[i]->nlen = nlen;
1378 vht[i]->vstart = 0 ;
1379 vht[i]->vlen = 0;\
1380 vht[i]->lazy_redirects = lazy_redirects;
1381
1382 // and now that the slot has proper initial information,
1383 // we can use the same code as is used in an update to do
1384 // the initial setting of values. This is good because
1385 // if we someday change the way variable values are stored,
1386 // we need change it only in one place.
1387 }
1388 else
1389 {
1390 // The cell is already here. :)
1391 };
1392 // Either way, the cell is now here, so we can set the value.
1393 //
1394 vht[i]->valtxt = valtxt;
1395 vht[i]->vstart = vstart;
1396 vht[i]->vlen = vlen;
1397 vht[i]->mstart = vstart;
1398 vht[i]->mlen = 0;
1399 vht[i]->linenumber = linenumber;
1400 vht[i]->lazy_redirects = lazy_redirects;
1401
1402 if(internal_trace)
1403 {
1404 j = 0;
1405 fprintf (stderr, " Successful set value of ");
1406
1407 //for (j = 0; j < vht[i]->nlen; j++)
1408 // fprintf (stderr, "%c", vht[i]->nametxt[vht[i]->nstart+j]);
1409 dontcare = fwrite (&(vht[i]->nametxt[vht[i]->nstart]), vht[i]->nlen, 1, stderr);
1410
1411 fprintf (stderr, " at vht entry %d ", i);
1412
1413 fprintf (stderr, " with value -");
1414 // for (j = 0; j < vht[i]->vlen; j++)
1415 // fprintf (stderr, "%c", vht[i]->valtxt[vht[i]->vstart+j]);
1416 dontcare = fwrite (&(vht[i]->valtxt[vht[i]->vstart]), vht[i]->vlen, 1, stderr);
1417
1418 fprintf (stderr, "- (start %ld, length %ld)",
1419 vht[i]->vstart, vht[i]->vlen);
1420
1421 fprintf (stderr, "and %ld lazy redirects", vht[i]->lazy_redirects);
1422
1423 fprintf (stderr, "\n");
1424 };
1425
1426 }
1427
1428 // look up what the line number is of a variable.
1429 //
crm_lookupvarline(VHT_CELL ** vht,char * text,long start,long len)1430 long crm_lookupvarline (VHT_CELL **vht, char *text, long start, long len)
1431 {
1432 int i; // some indices to bang on
1433
1434 i = crm_vht_lookup (vht, &(text[start]), len);
1435
1436
1437 // GROT GROT GROT
1438 // We should check here for GOTOing a label that isn't in
1439 // the current file (i.e. the equivalent of a C "longjmp").
1440 if (vht[i] != NULL)
1441 { // Yes, we found it. Return the line number
1442 if (internal_trace)
1443 fprintf (stderr, " looked up ... line number %ld\n",
1444 vht[i]->linenumber);
1445 return (vht[i]->linenumber);
1446 }
1447 else
1448 {
1449 // long q;
1450 // char *deathfu ;
1451 // deathfu = (char *) malloc ( len+10);
1452 // if (!deathfu)
1453 // untrappableerror("Couldn't malloc 'deathfu'.\n Time to die. ","");
1454 // strncpy (deathfu, &(csl->filetext[start]), len);
1455 // q = fatalerror ("Control Referencinge a non-existent variable- this"
1456 // "is almost always a very _bad_ thing",
1457 // deathfu);
1458 // If fatalerror found a TRAP for this error, cstmt now points to
1459 // the TRAP - 1. We want to go to the trap itself, no auto-incr...
1460 // if ( q == 0)
1461 // return ( csl->cstmt + 1);
1462 };
1463 return (-1);
1464 }
1465
1466 // Update the start and length of all captured variables whenever
1467 // a buffer gets mangled. Mangles are all expressed in
1468 // the form of a start point and a delta.
1469 //
1470 // Note to the Reader - yes, I consider the nonlinearity of this
1471 // function to be a grossitude. Not quite an obscenity, but definitely
1472 // a wart.
1473
crm_updatecaptures(char * text,long loc,long delta)1474 void crm_updatecaptures (char *text, long loc, long delta)
1475 {
1476 long vht_index;
1477 long i;
1478 long ostart = 0, oend = 0 ;
1479 long nstart = 0, nend = 0 ;
1480
1481 if (internal_trace)
1482 fprintf (stderr, "\n updating captured values start %ld len %ld \n",
1483 loc, delta);
1484
1485 // check each VHT entry for a need to relocate
1486 for (vht_index = 0; vht_index < vht_size; vht_index++)
1487 {
1488 // is this an actual entry?
1489 if (vht[vht_index] != NULL)
1490 {
1491 if (vht[vht_index]->valtxt == text)
1492 { // start of valtext block check
1493 // value text area
1494 if (internal_trace > 1)
1495 {
1496 fprintf (stderr, "\n checking var ");
1497 for (i = 0; i < vht[vht_index]->nlen; i++)
1498 fprintf (stderr, "%c",
1499 vht[vht_index]->nametxt[vht[vht_index]->nstart+i]);
1500 fprintf (stderr, " ");
1501 fprintf (stderr, " s: %ld, l:%ld, e:%ld n:%ld ~ %ld ...",
1502 vht[vht_index]->vstart,
1503 vht[vht_index]->vlen,
1504 vht[vht_index]->vstart+vht[vht_index]->vlen,
1505 vht[vht_index]->nstart,
1506 vht[vht_index]->nstart + vht[vht_index]->nlen
1507 );
1508 };
1509 ostart = nstart = vht[vht_index]->vstart;
1510 oend = nstart = ostart + vht[vht_index]->vlen;
1511 nstart = crm_mangle_offset (ostart, loc, delta, 0);
1512 nend = crm_mangle_offset (oend, loc, delta, 1);
1513 if (internal_trace)
1514 fprintf (stderr, "\n index %ld vstart/vlen upd: %ld, %ld ",
1515 vht_index,
1516 vht[vht_index]->vstart, vht[vht_index]->vlen);
1517 vht[vht_index]->vstart = nstart;
1518 vht[vht_index]->vlen = nend - nstart;
1519 if (internal_trace)
1520 fprintf (stderr, "to %ld, %ld.\n",
1521 vht[vht_index]->vstart,
1522 vht[vht_index]->vlen);
1523 //
1524 // And do the same for mstart/mlen (match start/length)
1525 ostart = vht[vht_index]->mstart;
1526 oend = ostart + vht[vht_index]->mlen;
1527 nstart = crm_mangle_offset (ostart, loc, delta, 0);
1528 nend = crm_mangle_offset (oend, loc, delta, 1);
1529 if (internal_trace)
1530 fprintf (stderr, "\n index %ld mstart/mlen upd: %ld, %ld ",
1531 vht_index,
1532 vht[vht_index]->mstart, vht[vht_index]->mlen);
1533 vht[vht_index]->mstart = nstart;
1534 vht[vht_index]->mlen = nend - nstart;
1535 if (internal_trace)
1536 fprintf (stderr, "to %ld, %ld.\n",
1537 vht[vht_index]->mstart,
1538 vht[vht_index]->mlen);
1539 };
1540 // Don't forget entries that may be varNAMES, not just
1541 // var values!
1542 if (vht[vht_index]->nametxt == text)
1543 {
1544 long orig_len;
1545 //
1546 // Same thing here...
1547 //
1548 ostart = nstart = vht[vht_index]->nstart;
1549 orig_len = vht[vht_index]->nlen;
1550 oend = nend = ostart + orig_len;
1551 if (orig_len == 0) fprintf (stderr, "CRUD on %ld", vht_index);
1552 nstart = crm_mangle_offset (ostart, loc, delta, 0);
1553 nend = crm_mangle_offset (oend, loc, delta, 1);
1554 if (oend - ostart != orig_len)
1555 fprintf (stderr, "Length change on %ld! Was %ld, now %ld ",
1556 vht_index,
1557 orig_len,
1558 oend-ostart);
1559
1560 if (internal_trace)
1561 fprintf (stderr,
1562 "\n index %ld nstart/nlen upd: %ld, %ld ",
1563 vht_index,
1564 vht[vht_index]->nstart, vht[vht_index]->nlen);
1565 vht[vht_index]->nstart = nstart;
1566 vht[vht_index]->nlen = nend - nstart;
1567 if (internal_trace)
1568 fprintf (stderr, "to %ld, %ld.\n",
1569 vht[vht_index]->nstart,
1570 vht[vht_index]->nlen);
1571 }
1572 }
1573 }
1574 if (internal_trace)
1575 fprintf (stderr, "\n end of updates\n");
1576 }
1577
1578 //
1579 // How to calculate the new offsets of the start and end
1580 // (that is, a "mark"), given a location (dot) and a delta of that
1581 // location. Dot doesn't move... only mark does.
1582 //
1583 // sl is Start v. End - do we treat this mangle as altering the
1584 // _start_ of a var, or the _end_ ? (this is because we don't move
1585 // a Start if Dot is the same, but we do move an End. Alternatively,
1586 // this is "is "dot considered to be before or after a mark with the
1587 // same value)
1588 //
1589
crm_mangle_offset(long mark,long dot,long delta,long sl)1590 long crm_mangle_offset ( long mark, long dot, long delta, long sl)
1591 {
1592 long absdelta;
1593
1594 absdelta = delta;
1595 if (absdelta < 0) absdelta = -absdelta;
1596
1597 if (sl == 0)
1598 {
1599 // HOW WE DEAL WITH START POINTS
1600 // (that is, "dot" is considered to follow "mark")
1601 //
1602 // are we earlier than dot? If so, we can't be changed by dot.
1603 //
1604 // edge condition for start:
1605 //
1606 // Mark ==> Mark
1607 // Dot Dot
1608 //
1609 if (mark <= dot) return (mark);
1610
1611 // are we beyond the reach of dot and delta? If so, we just slide.
1612 //
1613 // edge condition:
1614 //
1615 // Mark ==> Mark
1616 // Dot+Delta Dot
1617 //
1618
1619 if ((dot + absdelta) < mark ) return (mark + delta);
1620
1621 // Neither - we're in the range where dot and mark can affect us
1622 //
1623 // If delta is positive, we can just slide further out.
1624 if (delta > 0) return (mark + delta);
1625 //
1626 // but, if delta is negative (a deletion) then we can move toward
1627 // dot, but not earlier than dot.
1628 mark = mark + delta; // delta is negative, so we ADD it to subtract!
1629 if (mark < dot) mark = dot;
1630 return (mark);
1631 }
1632 else
1633 {
1634 // HOW WE DEAL WITH END POINTS
1635 // (that is, "dot" is considered to be in front of "mark")
1636 //
1637 // are we earlier than dot? If so, we can't be changed by dot.
1638 //
1639 // edge condition for finish points:
1640 //
1641 // Mark ==> Mark
1642 // Dot Dot
1643 //
1644 if (mark < dot) return (mark);
1645
1646 // are we beyond the reach of dot and delta? If so, we just slide.
1647 //
1648 // edge condition:
1649 //
1650 // Mark ==> Mark
1651 // Dot+Delta Dot
1652 //
1653
1654 if ((dot + absdelta) <= mark ) return (mark + delta);
1655
1656 // Neither - we're in the range where dot and mark can affect us
1657 //
1658 // If delta is positive, we can just slide further out.
1659 if (delta > 0) return (mark + delta);
1660 //
1661 // but, if delta is negative (a deletion) then we can move toward
1662 // dot, but not earlier than dot.
1663 mark = mark + delta; // delta is negative, so we ADD it to subtract!
1664 if (mark < dot) mark = dot;
1665 return (mark);
1666 };
1667 }
1668
1669 ///
1670 //
1671 // crm_buffer_gc - garbage-collect a buffer. This isn't a perfect
1672 // solution, but it will work. (i.e. it's slow and annoying)//
1673 //
1674 // The algorithm:
1675 // - find the lowest index currently used (takes 1 pass thru VHT)
1676 // - find the highest user of that index (takes 1 pass thru VHT)
1677 // * - see if any block overlaps that block
1678 // - find the next lowest starting block
1679 //
1680
crm_buffer_gc(CSL_CELL * zdw)1681 int crm_buffer_gc ( CSL_CELL *zdw)
1682 {
1683 fprintf (stderr, "Sorry, GC is not yet implemented");
1684 exit (EXIT_FAILURE);
1685 return (0);
1686 }
1687