// crm_expr_isolate.c - isolate a variable (includes mem management)
// 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;
// Allow creation of a temporary isolated variable;
// this lives in the same big buffer as the environ
// args, the arg0 args, and the basic formatting args
// (like :_nl:, :_ht:, :_bs:, etc).
int crm_expr_isolate (CSL_CELL *csl, ARGPARSE_BLOCK *apb)
{
char temp_vars [MAX_VARNAME];
long tvlen;
long vn_start_here;
long vstart;
long vlen;
long mc;
long done;
long vallen;
int iso_status;
if (user_trace)
fprintf (stderr, "executing an ISOLATE statement\n");
// get the list of variable names
//
crm_get_pgm_arg (temp_vars, MAX_VARNAME, apb->p1start, apb->p1len);
tvlen = crm_nexpandvar (temp_vars, apb->p1len, MAX_VARNAME);
if (tvlen == 0)
{
nonfatalerror( "This statement is missing the variable to isolate"
" so I'll just ignore the whole statement.", "");
}
if (internal_trace)
fprintf (stderr, " creating isolated vars: ***%s***\n", temp_vars);
done = 0;
mc = 0;
// Now, find the vars (space-delimited, doncha know) and make them
// isolated.
//
vstart = 0;
vlen = 0;
vn_start_here = 0;
while (!done)
{
crm_nextword (temp_vars, tvlen, vn_start_here, &vstart, &vlen);
vn_start_here = vstart + vlen + 1;
if (vlen == 0)
{
done = 1;
}
else // not done yet.
{
// must make a copy of the varname.
char vname[MAX_VARNAME];
long vmidx;
memmove (vname, &(temp_vars[vstart]), vlen);
vname [vlen] = '\000';
if (vlen < 3)
{
nonfatalerror ("The variable you're asking me to ISOLATE "
" has an utterly bogus name. I'll ignore"
" the rest of the statement", " ");
break;
};
if (strcmp (vname, ":_dw:") == 0)
{
nonfatalerror ("You can't ISOLATE the :_dw: data window! ",
"We'll just ignore that for now");
}
else // OK- isolate this variable
{
vmidx = crm_vht_lookup (vht, vname, vlen);
//
// get initial value - that's the slashed value.
crm_get_pgm_arg (tempbuf, data_window_size,
apb->s1start, apb->s1len);
//
// Now, check these cases in order:
//
// not preexisting, no /value/ - isolate, set to ""
// not preexisting, with /value/ -isolate, set /val/
// preexisting _dw, with /value/ - isolate, set to /val/
// preexisting _dw, no /value/ - isolate, set to dwval.
// if preexisting AND default turned on - do nothing!
// preexisting isolated, no /value/ - copy value.
// preexisting isolated, with /value/ - alter /value/
//
// not preexisting.
if (vht[vmidx] == NULL)
{
// not preexisting, no slash value
if (internal_trace)
fprintf (stderr, "Not a preexisting var.\n");
if (!apb->s1start)
{
// no slash value- set to ""
if (internal_trace)
fprintf (stderr, "No initialization value given, using"
" a zero-length string.\n");
tempbuf[0] = '\0';
vallen = 0;
}
else
{
// not preexisting, has a /value/, use it.
if (internal_trace)
fprintf (stderr, "using the slash-value given.\n");
crm_get_pgm_arg (tempbuf, data_window_size,
apb->s1start, apb->s1len);
vallen = crm_nexpandvar(tempbuf, apb->s1len,
data_window_size - tdw->nchars);
};
}
else
// it IS preexisting
{
// It is preexisting, maybe in isolation, maybe
// not but we're isolating again. So we need to
// copy again.
//
if (internal_trace)
fprintf (stderr, "Preexisting var.\n");
if (apb->sflags & CRM_DEFAULT)
{
if (user_trace)
fprintf (stderr, " var exists, default flag on, "
"so no action taken.\n");
goto no_isolate_action;
// return (0);
};
if (apb->s1start)
{
// yes, statement has a /value/
// get the /value/
if (internal_trace)
fprintf (stderr, "Using the provided slash-val.\n");
crm_get_pgm_arg (tempbuf, data_window_size,
apb->s1start, apb->s1len);
vallen =
crm_nexpandvar(tempbuf, apb->s1len,
data_window_size - tdw->nchars);
}
else
{
// no /value/, so we need to use the old value.
//
if (internal_trace)
fprintf (stderr, "No slash-value, using old value.\n");
strcpy (tempbuf, ":*");
strncat (tempbuf, vname, vlen);
vallen =
crm_nexpandvar (tempbuf, vlen+2,
data_window_size - tdw->nchars);
};
};
//
// Now we have the name of the variable in vname/vlen,
// and the value string in tempbuf/vallen. We can then
// isolate it with crm_isolate_this, which always does
// the right thing (pretty much). :-)
//
iso_status = crm_isolate_this (&vmidx,
vname, 0, vlen,
tempbuf, 0, vallen);
if ( iso_status > 0)
return (iso_status);
};
// the semicolon is to keep the C compiler happy.
no_isolate_action: ;
};
vstart = vstart + vlen;
if (temp_vars[vstart] == '\000'
|| vstart >= tvlen )
done = 1;
};
return (0);
};
//
// General-purpose routine to "do the right thing" to isolate a
// string value. This routine takes care of all of the possible
// extenuating circumstances, like is/is not already isolated,
// is/is not requiring a reclaim, etc. (how it knows? If the
// value is in the TDW, it may need to be reclaimed, otherwise it
// doesn't reclaim.)
//
// Note - this routine will malloc and then free a spare buffer if
// it gets handed data that's already in the TDW. Best not to do
// that if you can avoid it; that is an efficiency speedup
//
int crm_isolate_this (long *vptr,
char *nametext, long namestart, long namelen,
char *valuetext, long valuestart, long valuelen)
{
long is_old;
long is_old_isolated;
long vmidx;
long oldvstart = 0;
long oldvlen = 0;
long neededlen;
if (internal_trace)
{
fprintf (stderr, "using crm_isolate_this, vptr = %lX\n", (long) vptr);
}
// keep track of the amount of storage needed for this variable
// to be inserted into the isolated space.
neededlen = 10;
//
// gather information
// In particular - does the name already exits? Is it
// already isolated?
if (vptr)
{
vmidx = *vptr;
}
else
{
vmidx = crm_vht_lookup ( vht, &nametext[namestart], namelen);
}
// check the vht - if it's not here, we need to add it.
//
if (vht[vmidx] == NULL)
{
// optimization - if it's not old, we don't need to run a reclaim
// phase later on.
is_old = 0;
// must allow space for the name.
neededlen += namelen;
}
else
{
is_old = 1;
};
if (is_old && vht[vmidx]->valtxt == tdw->filetext)
{
is_old_isolated = 1;
// and save old start and length for the incremental reclaimer
oldvstart = vht[vmidx]->vstart;
oldvlen = vht[vmidx]->vlen;
// how much space will the new value take up?
neededlen += valuelen - oldvlen;
}
else
{
is_old_isolated = 0;
// and how much space will we need?
neededlen += valuelen;
};
// Do a check - is there enough space in the tdw to hold
// the new variable (both name and value)?
if ( tdw->nchars + neededlen > data_window_size )
{
char vname[129];
strncpy (vname, &nametext[namestart],
( (128 < namelen) ? 128 : namelen));
vname[129] = 0;
fatalerror ("You have blown the memory-storage gaskets while trying"
"to store the ISOLATEd variable ", vname);
return (1);
}
// If we get to here, there's more than enough space; so we're good to
// go with no further checks.
// If there wasn't a vht slot existing, make one.
//
if (!is_old)
{
// nope, never seen this var before, add it into the VHT
// namestart is where we are now.
long nstart, vstart;
if (internal_trace)
fprintf (stderr, "... this is a new isolated var\n");
//
// Put the name into the tdw memory area, add a & after it.
//
// do the name first. Start on a newline.
tdw->filetext[tdw->nchars] = '\n';
tdw->nchars++;
nstart = tdw->nchars;
memmove (&tdw->filetext[nstart], &nametext[namestart], namelen);
tdw->nchars = tdw->nchars + namelen;
tdw->filetext[tdw->nchars] = '=';
tdw->nchars++;
// and put in the value in now
vstart = tdw->nchars;
memmove (&tdw->filetext[vstart], &valuetext[valuestart], valuelen);
tdw->nchars = tdw->nchars + valuelen;
tdw->filetext[tdw->nchars] = '\n';
tdw->nchars++;
// now, we whack the actual VHT.
crm_setvar (NULL, 0,
tdw->filetext, nstart, namelen,
tdw->filetext, vstart, valuelen,
csl->cstmt);
// that's it. It's now in the TDW and in the VHT
return (0);
}
// No, it's a preexisting variable. We need to do the shuffle.
//
// Note that this code is almost but not quite a mirror
// of the code that lives in crm_set_temp_nvar.
//
//
if (internal_trace)
fprintf (stderr, "Resetting valtxt to point at tdw.\n");
vht[vmidx]->valtxt = tdw->filetext;
if (internal_trace)
fprintf (stderr, "Fresh start: offset %ld length %ld.\n",
tdw->nchars, valuelen);
//
//
// If we have a zero-length string, followed by a
// non-zero-lenth string, next to each other, with
// no intervening allocations, both strings will
// have the _same_ start point. This messes things
// up badly on subsequent alters. Thus, we
// _must_ put a spacer in.
//
// This code must also be echoed in crm_set_temp_nvar
//
if (valuelen == 0)
{
tdw->filetext[tdw->nchars] = '\n';
tdw->nchars++;
};
// (end of danger zone)
//
vht[vmidx]->vstart = tdw->nchars;
vht[vmidx]->vlen = valuelen;
if (internal_trace)
fprintf (stderr, "Memmoving the value in.\n");
memmove (&(tdw->filetext[tdw->nchars]),
tempbuf,
valuelen);
tdw->nchars = tdw->nchars + valuelen;
//
// trailing separator
tdw->filetext[tdw->nchars] = '\n';
tdw->nchars++;
//
// and reset 'previous match' start and length
if (internal_trace)
fprintf (stderr, "reset the previous-match to start.\n");
vht[vmidx]->mstart = vht[vmidx]->vstart;
vht[vmidx]->mlen = 0;
// Step 2 - if this was isolated, reclaim the
// old storage if nobody else is using it.
//
if (is_old_isolated)
{
if (internal_trace)
fprintf (stderr, "This was already an isolated var, so "
"do a reclamation on the old space.\n");
// vstart==0 means "ignore this value" to reclamation
//
crm_compress_tdw_section (vht[vmidx]->valtxt,
oldvstart ,
oldvstart+oldvlen);
};
return (0);
};
syntax highlighted by Code2HTML, v. 0.9.1