# include "jam.h"
# include "lists.h"
# include "parse.h"
# include "variable.h"
# include "expand.h"
# include "hash.h"
# include "filesys.h"
# include "newstr.h"
static struct hash *varhash = 0;
static LIST *exported_variables = L0;
#ifdef APPLE_EXTENSIONS
typedef struct _def_asg DEF_ASG ;
struct _def_asgs {
unsigned count;
unsigned capacity;
struct _def_asg {
char *symbol;
char *value;
unsigned short append;
unsigned short being_expanded;
} asgs[0];
} ;
static struct _def_asgs *def_asgs = NULL;
static unsigned committing_def_asgs = 0;
#endif
typedef struct _variable VARIABLE ;
struct _variable {
char *symbol;
LIST *value;
} ;
static VARIABLE *var_enter();
static void var_dump();
void
var_export( symbol )
char *symbol;
{
LIST * l = exported_variables;
while( l && strcmp(symbol, l->string) != 0 )
l = list_next( l );
if( l == NULL )
{
if( DEBUG_COMPILE )
printf( "marking %s for export\n", symbol );
exported_variables = list_new( exported_variables, newstr(symbol) );
}
}
void
var_defines( e, export )
char **e;
int export;
{
for( ; *e; e++ )
{
char *val;
if( (val = strchr( *e, '=' )) != NULL )
{
LIST *l = L0;
void * pp, * p;
char buf[ MAXSYM ];
#if defined(__APPLE__)
char split = '\01';
#else
char split = ' ';
if( val - 4 >= *e )
{
if( !strncmp( val - 4, "PATH", 4 ) ||
!strncmp( val - 4, "Path", 4 ) ||
!strncmp( val - 4, "path", 4 ) )
split = SPLITPATH;
}
#endif
for( pp = val + 1; p = strchr( pp, split ); pp = p + 1 )
{
strncpy( buf, pp, p - pp );
buf[ p - pp ] = '\0';
l = list_new( l, newstr( buf ) );
}
l = list_new( l, newstr( pp ) );
strncpy( buf, *e, val - *e );
buf[ val - *e ] = '\0';
var_set( buf, l, VAR_SET , export );
}
}
}
LIST *
var_list( ilist, lol )
LIST *ilist;
LOL *lol;
{
LIST *olist = 0;
while( ilist )
{
char *s = ilist->string;
olist = var_expand( olist, s, s + strlen(s), lol, 1 );
ilist = list_next( ilist );
}
return olist;
}
int
var_string( in, out, outsize, lol )
char *in;
char *out;
int outsize;
LOL *lol;
{
char *out0 = out;
char *oute = out + outsize - 1;
while( *in )
{
char *lastword;
int dollar = 0;
while( isspace( *in ) )
{
if( out >= oute )
return -1;
*out++ = *in++;
}
lastword = out;
while( *in && !isspace( *in ) )
{
if( out >= oute )
return -1;
if( in[0] == '$' && in[1] == '(' )
dollar++;
*out++ = *in++;
}
if( dollar )
{
LIST *l;
l = var_expand( L0, lastword, out, lol, 0 );
out = lastword;
for( ; l; l = list_next( l ) )
{
int so = strlen( l->string );
if( out + so >= oute )
return -1;
strcpy( out, l->string );
out += so;
*out++ = ' ';
}
list_free( l );
}
}
if( out >= oute )
return -1;
*out++ = '\0';
return out - out0;
}
LIST *
var_get( symbol )
char *symbol;
{
VARIABLE var, *v = &var;
v->symbol = symbol;
#ifdef APPLE_EXTENSIONS
if (APPLE_JAM_EXTENSIONS && def_asgs != NULL && !committing_def_asgs) {
int i;
for (i = def_asgs->count-1; i >= 0; i--) {
if (strcmp(symbol, def_asgs->asgs[i].symbol) == 0) {
LIST * value = list_new(NULL, newstr(def_asgs->asgs[i].value));
if (DEBUG_VARGET) {
var_dump(symbol, value, "get-uncommitted-deferred");
}
return value;
}
}
}
#endif
if( varhash && hashcheck( varhash, (HASHDATA **)&v ) )
{
if( DEBUG_VARGET )
var_dump( v->symbol, v->value, "get" );
return v->value;
}
return 0;
}
void
var_set( symbol, value, flag, export )
char *symbol;
LIST *value;
int flag;
int export;
{
VARIABLE *v = var_enter( symbol );
if( DEBUG_VARSET )
var_dump( symbol, value, "set" );
switch( flag )
{
case VAR_SET:
list_free( v->value );
v->value = value;
break;
case VAR_APPEND:
v->value = list_append( v->value, value );
break;
case VAR_DEFAULT:
if( !v->value )
v->value = value;
else
list_free( value );
break;
}
if( export )
var_export( symbol );
}
LIST *
var_swap( symbol, value )
char *symbol;
LIST *value;
{
VARIABLE *v = var_enter( symbol );
LIST *oldvalue = v->value;
if( DEBUG_VARSET )
var_dump( symbol, value, "set" );
v->value = value;
return oldvalue;
}
static VARIABLE *
var_enter( symbol )
char *symbol;
{
VARIABLE var, *v = &var;
if( !varhash )
varhash = hashinit( sizeof( VARIABLE ), "variables" );
v->symbol = symbol;
v->value = 0;
if( hashenter( varhash, (HASHDATA **)&v ) )
v->symbol = newstr( symbol );
return v;
}
static void
var_dump( symbol, value, what )
char *symbol;
LIST *value;
char *what;
{
printf( "%s %s = ", what, symbol );
list_print( value );
printf( "\n" );
}
void
var_done()
{
hashdone( varhash );
}
#ifdef MEASURE_SETENV
static unsigned setenv_num = 0;
static unsigned setenv_bytes = 0;
#endif
void
var_setenv( symbol, value )
const char *symbol;
LIST *value;
{
int shouldset = 1;
#ifdef EXPORT_ONLY_NONFUNKY_IDENTIFIERS
register const char *sp;
register char ch;
for( sp = symbol; (ch = *sp) != '\0'; sp++ )
{
if( !(ch >= 'A' && ch <= 'Z') && !(ch >= 'a' && ch <= 'z') && !(ch >= '0' && ch <= '9') && !(ch == '_') )
{
shouldset = 0;
break;
}
}
#endif
if( shouldset )
{
const int MAXVALUE_LEN = (1024 * 8) - 1; char buffer[MAXVALUE_LEN+1];
register char * bp = buffer;
LIST * l;
for( l = value ; l != NULL && (bp - buffer) < MAXVALUE_LEN; l = list_next( l ) )
{
register const char * sp;
register unsigned needsquotes = 0;
register int len = 0;
register int extralen = 0;
if( bp != buffer && (bp - buffer) + 1 <= MAXVALUE_LEN )
*bp++ = ' ';
for( sp = l->string; *sp; sp++, len++ )
{
#ifdef SHOULD_QUOTE_SETENV_VARS
register char ch = *sp;
if( !(ch >= 'A' && ch <= 'Z') && !(ch >= 'a' && ch <= 'z') && !(ch == '_') )
{
needsquotes = 1;
if( ch == '\\' || ch == '\"' )
extralen++;
}
#endif
}
if( (bp - buffer) + len + extralen + (needsquotes ? 2 : 0) > MAXVALUE_LEN )
{
fprintf(stderr, "warning: maximum value length exceeded when setting variable '%s' in environment; truncating value to %u characters\n", symbol, MAXVALUE_LEN);
len = MAXVALUE_LEN - (bp - buffer) - extralen - (needsquotes ? 2 : 0);
}
if( needsquotes )
{
if ( (bp - buffer) + 1 <= MAXVALUE_LEN )
*bp++ = '\"';
for( sp = l->string; *sp && len >= 0; sp++, len-- )
{
register char ch = *sp;
if( ch == '\\' || ch == '\"' )
*bp++ = '\\';
*bp++ = ch;
}
if ( (bp - buffer) + 1 <= MAXVALUE_LEN )
*bp++ = '\"';
}
else
{
memcpy(bp, l->string, len);
bp += len;
}
}
*bp = '\0';
#ifdef DEBUG_VARIABLE_EXPORTING
printf("[setenv '%s' '%s']\n", symbol, buffer);
#endif
setenv(symbol, buffer, 1);
#ifdef MEASURE_SETENV
setenv_num++;
setenv_bytes += strlen(symbol) + 1 + strlen(buffer) + 1;
#endif
}
}
void var_setenv_all_exported_variables()
{
register LIST *l;
#ifdef MEASURE_SETENV
setenv_num = 0;
setenv_bytes = 0;
#endif
for( l = exported_variables; l; l = list_next( l ) )
var_setenv( l->string, var_get( l->string ) );
#ifdef MEASURE_SETENV
printf("[did setenv %u variables (%u bytes)]\n", setenv_num, setenv_bytes);
#endif
}
#ifdef APPLE_EXTENSIONS
struct string_buffer {
unsigned length;
unsigned capacity;
char * characters;
} ;
static void strbuf_init (struct string_buffer * sbuf)
{
sbuf->length = 0;
sbuf->capacity = 16;
sbuf->characters = malloc(sbuf->capacity * sizeof(char));
}
static char * strbuf_characters (struct string_buffer * sbuf)
{
return sbuf->characters;
}
static unsigned strbuf_length (struct string_buffer * sbuf)
{
return sbuf->length;
}
static inline void strbuf_append_characters (struct string_buffer * sbuf, const char * characters, unsigned length)
{
if (sbuf->length + length > sbuf->capacity) {
sbuf->capacity += length;
sbuf->characters = realloc(sbuf->characters, sbuf->capacity);
}
memcpy(sbuf->characters + sbuf->length, characters, length);
sbuf->length += length;
}
static inline void strbuf_append_character (struct string_buffer * sbuf, char ch)
{
if (sbuf->length + 1 > sbuf->capacity) {
sbuf->capacity += 32;
sbuf->characters = realloc(sbuf->characters, sbuf->capacity);
}
*(sbuf->characters + sbuf->length++) = ch;
}
static void strbuf_append_quoted_characters (struct string_buffer * sbuf, const char * characters, unsigned length, unsigned quote_only_if_needed)
{
register unsigned needs_quotes = 0; #ifdef QUOTE_STRINGS_BY_ENCLOSING_IN_DOUBLEQUOTES
register unsigned extra_length = 2; #else // QUOTE_STRINGS_BY_ESCAPING_CHARACTERS_USING_BACKSLASHES
register unsigned extra_length = 0; #endif
register unsigned i;
for (i = 0; i < length; i++) {
register char ch = characters[i];
if (isspace(ch) || ch == '\\' || ch == '\"' || ch == '\'') {
needs_quotes = 1;
#ifdef QUOTE_STRINGS_BY_ENCLOSING_IN_DOUBLEQUOTES
if( ch == '\\' || ch == '\"' )
#endif // QUOTE_STRINGS_BY_ESCAPING_CHARACTERS_USING_BACKSLASHES
extra_length++;
}
}
if (quote_only_if_needed && !needs_quotes) {
extra_length = 0;
strbuf_append_characters(sbuf, characters, length);
}
else {
register char * dstp;
if (sbuf->length + length + extra_length > sbuf->capacity) {
sbuf->capacity += length + extra_length;
sbuf->characters = realloc(sbuf->characters, sbuf->capacity);
}
dstp = sbuf->characters + sbuf->length;
#ifdef QUOTE_STRINGS_BY_ENCLOSING_IN_DOUBLEQUOTES
*dstp++ = '\"';
for (i = 0; i < length; i++) {
register char ch = characters[i];
if (ch == '\\' || ch == '\"') {
*dstp++ = '\\';
}
*dstp++ = ch;
}
*dstp++ = '\"';
#else // QUOTE_STRINGS_BY_ESCAPING_CHARACTERS_USING_BACKSLASHES
for (i = 0; i < length; i++) {
register char ch = characters[i];
if (isspace(ch) || ch == '\\' || ch == '\"' || ch == '\'') {
*dstp++ = '\\';
}
*dstp++ = ch;
}
#endif
sbuf->length += length + extra_length;
}
}
static void strbuf_free (struct string_buffer * sbuf)
{
free(sbuf->characters);
}
static void strbuf_append_list_as_command_line_arguments (struct string_buffer * sbuf, LIST * list)
{
while (list != NULL) {
strbuf_append_quoted_characters(sbuf, list->string, strlen(list->string), 1);
if (list->next != NULL) {
strbuf_append_character(sbuf, ' ');
}
list = list->next;
}
}
static LIST * list_by_parsing_as_commandline_arguments (const char * characters, unsigned length)
{
LIST * list = NULL;
char dst_buffer[10240];
register unsigned in_escape_char = 0;
register unsigned in_single_quote = 0;
register unsigned in_double_quote = 0;
register unsigned had_quote = 0;
register const char * sp = characters;
register const char * ep = characters + length;
register char * dp = dst_buffer;
while (sp < ep) {
register unsigned ch = *sp++;
if (in_escape_char) {
*dp++ = ch;
in_escape_char = 0;
}
else if (ch == '\\') {
in_escape_char = 1;
}
else if (ch == '\'' && !in_double_quote) {
in_single_quote = !in_single_quote;
had_quote = 1;
}
else if (ch == '\"' && !in_single_quote) {
in_double_quote = !in_double_quote;
had_quote = 1;
}
else if ((ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') && !in_single_quote && !in_double_quote) {
if (dp > dst_buffer || had_quote) {
*dp = '\0';
list = list_new(list, newstr(dst_buffer));
had_quote = 0;
dp = dst_buffer;
}
}
else {
*dp++ = ch;
}
}
if (dp > dst_buffer || had_quote) {
*dp = '\0';
list = list_new(list, newstr(dst_buffer));
}
return list;
}
static int find_next_variable_reference (const char * characters, unsigned length, char ** varRefStartPtr, char ** varNameStartPtr, char ** varNameEndPtr, char ** varRefEndPtr)
{
#define is_variable_char(_ch_) (((_ch_) >= 'A' && (_ch_) <= 'Z') || ((_ch_) >= 'a' && (_ch_) <= 'z') || ((_ch_) >= '0' && (_ch_) <= '9') || (_ch_ == '_'))
register const char * bufferCurrent;
register const char * bufferEnd;
register const char * varRefStart = NULL;
register const char * varNameStart = NULL;
register const char * varNameEnd = NULL;
register const char * varRefEnd = NULL;
bufferCurrent = characters;
bufferEnd = characters + length;
while (bufferCurrent < bufferEnd && varRefStart == NULL) {
register char ch = *bufferCurrent++;
switch (ch) {
case '\\':
if (bufferCurrent < bufferEnd) {
bufferCurrent++;
}
break;
case '\'':
while (bufferCurrent < bufferEnd && (ch = *bufferCurrent++) != '\'') {
if (ch == '\\' && bufferCurrent < bufferEnd) bufferCurrent++;
}
break;
case '$':
varRefStart = bufferCurrent-1;
ch = *bufferCurrent++;
if (ch == '(' || ch == '{' || ch == '%' || ch == '[') {
const char closeDelimChar = (ch == '(') ? ')' : ((ch == '{') ? '}' : ((ch == '%') ? '%' : ']'));
varNameStart = bufferCurrent;
while (bufferCurrent < bufferEnd && (ch = *bufferCurrent++) != closeDelimChar) {
if (ch == '\\' && bufferCurrent < bufferEnd) bufferCurrent++;
}
if (ch == closeDelimChar) {
varNameEnd = bufferCurrent - 1;
varRefEnd = bufferCurrent;
}
else {
varRefStart = NULL;
}
}
else if (is_variable_char(ch)) {
varNameStart = bufferCurrent-1;
while (bufferCurrent < bufferEnd && (ch = *bufferCurrent++) && is_variable_char(ch))
;
if (bufferCurrent < bufferEnd) {
bufferCurrent--;
}
varNameEnd = bufferCurrent;
varRefEnd = bufferCurrent;
break;
}
else {
varRefStart = NULL;
bufferCurrent--;
}
break;
}
}
if (varRefStart != NULL) {
if (varRefStartPtr != NULL) *varRefStartPtr = (char *)varRefStart;
if (varNameStartPtr != NULL) *varNameStartPtr = (char *)varNameStart;
if (varNameEndPtr != NULL) *varNameEndPtr = (char *)varNameEnd;
if (varRefEndPtr != NULL) *varRefEndPtr = (char *)varRefEnd;
return 1;
}
else {
return 0;
}
#undef is_variable_char
}
static int var_append_expansion_of_deferred_variable (const char * symbol, unsigned length, int asgSearchStartIdx, struct string_buffer * expstrbuf)
{
const char * value = NULL;
char symbolstr[length+1];
int should_concatenate = 0;
int found_recursion = 0;
int i, asgIdx = -1;
int free_value = 0;
if (DEBUG_VARSET) {
printf("expanding ");fwrite(symbol, length, 1, stdout);printf(" {\n");
}
memcpy(symbolstr, symbol, length);
symbolstr[length] = '\0';
for (i = asgSearchStartIdx; i >= 0 && value == NULL; i--) {
if (strcmp(def_asgs->asgs[i].symbol, symbolstr) == 0) {
value = def_asgs->asgs[i].value;
if (DEBUG_VARSET) {
printf("[found deferred assignment of ");fwrite(symbol, length, 1, stdout);printf(" with value |%s| at index %u]\n", value, i);
}
should_concatenate = def_asgs->asgs[i].append;
found_recursion = def_asgs->asgs[i].being_expanded;
asgIdx = i;
}
}
if (found_recursion) {
return 0;
}
if (value == NULL) {
LIST * jamvar_list = var_get(symbolstr);
if (jamvar_list != NULL) {
struct string_buffer jamvar_sbuf;
strbuf_init(&jamvar_sbuf);
strbuf_append_list_as_command_line_arguments(&jamvar_sbuf, jamvar_list);
strbuf_append_character(&jamvar_sbuf, '\0');
value = (const char *)malloc(strbuf_length(&jamvar_sbuf) * sizeof(char));
memcpy((char *)value, strbuf_characters(&jamvar_sbuf), strbuf_length(&jamvar_sbuf) * sizeof(char));
strbuf_free(&jamvar_sbuf);
free_value = 1;
should_concatenate = 0;
if (DEBUG_VARSET) {
printf("[found normal value of ");fwrite(symbol, length, 1, stdout);printf(" with value |%s|]\n", value);
}
}
}
if (value != NULL) {
const char * subrange_start;
const char * subrange_end;
const char * var_ref_start;
const char * var_name_start;
const char * var_name_end;
const char * var_ref_end;
if (should_concatenate && asgIdx >= 0) {
if (DEBUG_VARSET) {
printf("[concatenation, so starting expansion of ");fwrite(symbol, length, 1, stdout);printf(" from search index %i]\n", asgIdx-1);
}
found_recursion |= (var_append_expansion_of_deferred_variable(symbol, length, asgIdx-1, expstrbuf) == 0);
strbuf_append_character(expstrbuf, ' ');
}
if (asgIdx >= 0) {
if (DEBUG_VARSET) {
printf("[marking symbol %i: %s]\n", asgIdx, def_asgs->asgs[asgIdx].symbol);
}
def_asgs->asgs[asgIdx].being_expanded = 1;
}
subrange_start = value;
subrange_end = subrange_start + strlen(subrange_start);
while (!found_recursion && find_next_variable_reference(subrange_start, subrange_end-subrange_start, (char **)(&var_ref_start), (char **)(&var_name_start), (char **)(&var_name_end), (char **)(&var_ref_end))) {
if (subrange_start < var_ref_start) {
strbuf_append_characters(expstrbuf, subrange_start, var_ref_start - subrange_start);
}
found_recursion |= (var_append_expansion_of_deferred_variable(var_name_start, var_name_end - var_name_start, def_asgs->count - 1, expstrbuf) == 0);
subrange_start = var_ref_end;
}
if (subrange_start < subrange_end) {
strbuf_append_characters(expstrbuf, subrange_start, subrange_end - subrange_start);
}
if (asgIdx >= 0) {
if (DEBUG_VARSET) {
printf("[unmarking symbol %i: %s]\n", asgIdx, def_asgs->asgs[asgIdx].symbol);
}
def_asgs->asgs[asgIdx].being_expanded = 0;
}
}
if (free_value) {
free((char *)value);
}
if (DEBUG_VARSET) {
printf("}\n");
}
return !found_recursion;
}
void var_set_deferred (const char * symbol, LIST * value, int flag, int export)
{
struct string_buffer sbuf;
char * valstr;
if (DEBUG_COMPILE) {
printf("set-deferred %s %s ", symbol, (flag == VAR_APPEND) ? "+=" : "=");
list_print(value);
printf("\n");
}
if (def_asgs == NULL) {
if (DEBUG_VARSET) {
printf("[allocating deferred-assignment array with initial capacity %u]\n", 4);
}
def_asgs = malloc(sizeof(*def_asgs) + 4 * sizeof(*def_asgs->asgs) );
def_asgs->count = 0;
def_asgs->capacity = 4;
}
else if (def_asgs->count == def_asgs->capacity) {
if (DEBUG_VARSET) {
printf("[growing deferred-assignment array capacity from %u to %u]\n", def_asgs->capacity, def_asgs->capacity * 2);
}
def_asgs->capacity *= 2;
def_asgs = realloc(def_asgs, sizeof(*def_asgs) + def_asgs->capacity * sizeof(*def_asgs->asgs));
}
strbuf_init(&sbuf);
strbuf_append_list_as_command_line_arguments(&sbuf, value);
strbuf_append_character(&sbuf, '\0');
valstr = (char *)malloc(strbuf_length(&sbuf) * sizeof(char));
memcpy((char *)valstr, strbuf_characters(&sbuf), strbuf_length(&sbuf) * sizeof(char));
strbuf_free(&sbuf);
list_free(value);
def_asgs->asgs[def_asgs->count].symbol = newstr(symbol);
def_asgs->asgs[def_asgs->count].value = valstr;
def_asgs->asgs[def_asgs->count].append = (flag == VAR_APPEND) ? 1 : 0;
def_asgs->asgs[def_asgs->count].being_expanded = 0;
def_asgs->count++;
if (export) {
var_export(symbol);
}
}
void var_commit_all_deferred_assignments ()
{
if (def_asgs != NULL) {
struct hash * commited_defvars_hash;
int i;
committing_def_asgs = 1;
for (i = 0; globs.cmdline_defines[i] != NULL; i++) {
char * equals_sign_p;
if ((equals_sign_p = strchr(globs.cmdline_defines[i], '=')) != NULL && (equals_sign_p > globs.cmdline_defines[i])) {
char buffer[MAXSYM];
LIST * list = NULL;
int flag = (equals_sign_p[-1] == '+') ? VAR_APPEND : VAR_SET;
const char * val_start_p;
const char * val_end_p;
for (val_start_p = equals_sign_p + 1; (val_end_p = strchr(val_start_p, '\01')) != NULL; val_end_p = val_start_p + 1) {
strncpy(buffer, val_start_p, val_end_p - val_start_p);
buffer[val_end_p - val_start_p] = '\0';
list = list_new(list, newstr(buffer));
}
list = list_new(list, newstr(val_start_p));
strncpy(buffer, globs.cmdline_defines[i], equals_sign_p - globs.cmdline_defines[i] - ((equals_sign_p[-1] == '+') ? 1 : 0));
buffer[equals_sign_p - globs.cmdline_defines[i]] = '\0';
#if 0
printf("set-deferred %s %s ", buffer, (flag == VAR_APPEND) ? "+=" : "=");
list_print(list);
printf("\n");
#endif
var_set_deferred(buffer, list, flag, 1 );
}
}
commited_defvars_hash = hashinit(sizeof(char *), "committed defvars" );
for (i = def_asgs->count-1; i >= 0; i--) {
char ** v = &def_asgs->asgs[i].symbol;
if (!hashcheck(commited_defvars_hash, (HASHDATA **)&v)) {
struct string_buffer sbuf;
LIST * lst;
int found_recursion;
(void)hashenter(commited_defvars_hash, (HASHDATA **)&v);
strbuf_init(&sbuf);
found_recursion = (var_append_expansion_of_deferred_variable(def_asgs->asgs[i].symbol, strlen(def_asgs->asgs[i].symbol), def_asgs->count - 1, &sbuf) == 0);
if (found_recursion) {
printf("Error: '%s' refers to itself (either directly or indirectly)\n", def_asgs->asgs[i].symbol);
}
else {
strbuf_append_character(&sbuf, '\0');
lst = list_by_parsing_as_commandline_arguments(strbuf_characters(&sbuf), strbuf_length(&sbuf)-1);
if (DEBUG_COMPILE) {
printf("committing deferred assignment %s := %s\n", def_asgs->asgs[i].symbol, strbuf_characters(&sbuf));
}
var_set(def_asgs->asgs[i].symbol, lst, VAR_SET, 1);
}
strbuf_free(&sbuf);
}
else {
if (DEBUG_COMPILE) {
printf("skipping %s %s %s\n", def_asgs->asgs[i].symbol, def_asgs->asgs[i].append ? "+=" : "=", def_asgs->asgs[i].value);
}
}
}
for (i = def_asgs->count-1; i >= 0; i--) {
free(def_asgs->asgs[i].value);
}
free(def_asgs);
def_asgs = NULL;
hashdone(commited_defvars_hash);
committing_def_asgs = 0;
}
}
#endif