// crm_expr_isolate - isolate a variable (includes mem management) // Copyright 2001-2004 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; 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 { // 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) { 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, there's these cases // 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. // 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"); crm_set_temp_nvar (vname, "", 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); crm_set_temp_nvar (vname, tempbuf, vallen); }; } else // it IS preexisting { // It is preexisting, maybe in isolation, maybe // not but we're isolating again. So we need to // copy again. // // GROT GROT GROT // // There's an embarassment here - if something is // already isolated, and we isolate it again, what // does that mean with respect to values that may // be matched within it (or, for that matter, if // the var wasn't isolated per se, but MATCHed // onto an isolated var, so it represents an // aliasing of that other isolated var. // // Clearly, the semantics of ISOLATE are that the // result of an ISOLATE is never shared with // anything else, so this needs to be new storage. // // Steps: // 1) make a temporary copy of the data // // 2) if it was isolated before, let go of the old // storage (if other vars are using it, that's // ok). // // 3) make a new copy of the var. // // Step 1 - make a copy... use slash val if supplied, // else just nexpandvar the variable. // if (internal_trace) fprintf (stderr, "Preexisting var.\n"); 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); }; // Step 2 - if this was isolated, reclaim the // old storage if nobody else is using it. // if (vht[vmidx]->valtxt == tdw->filetext ) { long oldvstart, oldvlen; oldvstart = vht[vmidx]->vstart; oldvlen = vht[vmidx]->vlen; 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 // vht[vmidx]->vstart = 0; vht[vmidx]->vlen = 0; crm_compress_tdw_section (vht[vmidx]->valtxt, oldvstart, oldvstart+oldvlen); }; // Step 3 - make a new copy of the var's value. // // 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, vallen); // // DANGER DANGER DANGER // THIS WILL BREAK IF WE EVER DO REPACKING EN MASSE!!! // DANGER DANGER DANGER // // 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 (vallen == 0) tdw->nchars++; // (end of danger zone) // vht[vmidx]->vstart = tdw->nchars; vht[vmidx]->vlen = vallen; if (internal_trace) fprintf (stderr, "Memmoving the value in.\n"); memmove (&(tdw->filetext[tdw->nchars]), tempbuf, vallen); tdw->nchars = tdw->nchars + vallen; // // and reset previous match if (internal_trace) fprintf (stderr, "reset the previous-match to start.\n"); vht[vmidx]->mstart = vht[vmidx]->vstart; vht[vmidx]->mlen = 0; }; } else { nonfatalerror ("You can't ISOLATE the :_dw: data window! ", "We'll just ignore that for now"); }; }; vstart = vstart + vlen; if (temp_vars[vstart] == '\000' || vstart >= tvlen ) done = 1; }; return (0); };