COSC-4P82-Final-Project/lib/lilgp/kernel/params.c

752 lines
19 KiB
C

/* lil-gp Genetic Programming System, version 1.0, 11 July 1995
* Copyright (C) 1995 Michigan State University
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Douglas Zongker (zongker@isl.cps.msu.edu)
* Dr. Bill Punch (punch@isl.cps.msu.edu)
*
* Computer Science Department
* A-714 Wells Hall
* Michigan State University
* East Lansing, Michigan 48824
* USA
*
*/
#include <lilgp.h>
/** array of parameters, along with the size of the array and the number
of parameters used. **/
parameter *param;
int param_size = 0, param_alloc = 0;
/* read_parameter_file()
*
* reads and parses a parameter file.
*/
void read_parameter_file ( char *filename )
{
FILE *f;
char buffer[MAXPARAMLINELENGTH+1];
char *buf2;
int buf2size;
int line = 0;
int errors = 0;
int including = 1;
int flag;
int buflen, buf2len;
int cont;
/** open it. **/
f = fopen ( filename, "r" );
if ( f == NULL )
error ( E_FATAL_ERROR, "can't open parameter file \"%s\".",
filename );
/** lines are read into buffer. they are appended to buf2 until a
line which is not continued is hit, then buf2 is parsed and the
parameter added. **/
/* initial allocation of buf2. */
buf2 = (char *)MALLOC ( MAXPARAMLINELENGTH * sizeof ( char ) );
buf2size = MAXPARAMLINELENGTH;
buf2[0] = 0;
buf2len = 0;
cont = 0;
while ( fgets ( buffer, MAXPARAMLINELENGTH, f ) != NULL )
{
++line;
/* remove comments, skip line if it's blank after comment
removal. */
if ( delete_comment ( buffer ) )
continue;
/** if this is a %ifdef, %ifndef, or %endif directive, then
set the including variable accordingly. **/
if ( buffer[0] == '%' )
{
flag = 0;
if ( strncmp ( buffer+1, "ifdef", 5 ) == 0 )
including = test_directive ( buffer+6 );
else if ( strncmp ( buffer+1, "ifndef", 6 ) == 0 )
including = !test_directive ( buffer+7 );
else if ( strncmp ( buffer+1, "endif", 5 ) == 0 )
including = 1;
else
flag = 1;
if ( !flag )
continue;
}
/* skip this line unless including is set. */
if ( !including )
continue;
/** if this is a %define or %undefine directive, then process
it. **/
if ( buffer[0] == '%' )
{
if ( strncmp ( buffer+1, "define", 6 ) == 0 )
define_directive ( buffer+7 );
else if ( strncmp ( buffer+1, "undefine", 8 ) == 0 )
undefine_directive ( buffer+9 );
else
error ( E_ERROR, "%s line %d: unknown directive.",
filename, line );
continue;
}
/* is this line continued? (is the last nonwhitespace character
a backslash?) */
cont = check_continuation ( buffer );
/** make buf2 bigger if necessary. **/
buflen = strlen ( buffer );
while ( buf2len + buflen > buf2size + 10 )
{
buf2size += MAXPARAMLINELENGTH;
buf2 = (char *)REALLOC ( buf2, buf2size * sizeof ( char ) );
}
/** tack the current line onto buf2. **/
strcat ( buf2, buffer );
buf2len += buflen;
/** if this line is not continued further, then parse buf2. and
add the parameter. **/
if ( !cont )
{
if ( parse_one_parameter ( buf2 ) )
{
errors = 1;
error ( E_ERROR, "%s line %d: syntax error.",
filename, line );
}
/** reset buf2 as empty. **/
buf2len = 0;
buf2[0] = 0;
}
}
/* close file. */
fclose ( f );
/** if the last line was continued, and nothing followed it, that's
an error. **/
if ( buf2len != 0 )
{
errors = 1;
error ( E_ERROR, "unexpected EOF." );
}
/** if any errors occurred during parsing, stop now. **/
if ( errors )
error ( E_FATAL_ERROR,
"some syntax errors occurred parsing \"%s\".", filename );
FREE ( buf2 );
}
/* check_continuation()
*
* returns true/false depending on whether the given string is continued
* (the last nonwhitespace character is a backslash). If so, the backslash
* and everything after it is chopped.
*/
int check_continuation ( char *buffer )
{
int i, l;
l = strlen ( buffer );
for ( i = l-1; i >= 0; --i )
if ( !isspace(buffer[i]) )
{
if ( buffer[i] == '\\' )
{
buffer[i] = '\n';
buffer[i+1] = 0;
return 1;
}
else
return 0;
}
/* a blank line was passed. */
return 0;
}
/* delete_comment()
*
* this searches the string for a '#' or ';' and chops everything
* following, if one is found. returns 1 if the resulting line is blank
* (all whitespace), 0 otherwise.
*/
int delete_comment ( char *buffer )
{
int i, l;
l = strlen ( buffer );
/* zero-length lines are considered blank. */
if ( l == 0 )
return 1;
/* if the last character is a newline, chop it. */
if ( buffer[--l] == '\n' )
buffer[l] = 0;
for ( i = 0; i < l; ++i )
if ( buffer[i] == '#' || buffer[i] == ';' )
{
/* chop the line at a '#' or ';'. */
buffer[i] = 0;
break;
}
/* look for a nonwhitespace character. */
l = strlen ( buffer );
for ( i = 0; i < l; ++i )
if ( !isspace(buffer[i]) )
/* found one, return 0. */
return 0;
/* blank line, return 1. */
return 1;
}
/* translate_binary()
*
* this translates all of the valid strings representing binary values
* to the corresponding integer.
*/
int translate_binary ( char *string )
{
if ( strcmp ( string, "true" ) == 0 ||
strcmp ( string, "t" ) == 0 ||
strcmp ( string, "on" ) == 0 ||
strcmp ( string, "yes" ) == 0 ||
strcmp ( string, "y" ) == 0 ||
strcmp ( string, "1" ) == 0 )
return 1;
else if ( strcmp ( string, "false" ) == 0 ||
strcmp ( string, "f" ) == 0 ||
strcmp ( string, "off" ) == 0 ||
strcmp ( string, "no" ) == 0 ||
strcmp ( string, "n" ) == 0 ||
strcmp ( string, "0" ) == 0 )
return 0;
else
return -1;
}
/* read_parameter_database()
*
* this reads parameters from a checkpoint file.
*/
void read_parameter_database ( FILE *f )
{
int i, j, k;
int count;
char *buf1, *buf2;
int buf2len, buf2alloc;
/* how many parameters are we supposed to find? */
fscanf ( f, "%*s %d\n", &count );
if ( fgetc ( f ) != '#' )
error ( E_FATAL_ERROR, "error in parameter section of checkpoint file." );
buf1 = (char *)MALLOC ( MAXPARAMLINELENGTH );
buf2 = (char *)MALLOC ( MAXPARAMLINELENGTH );
buf2alloc = MAXPARAMLINELENGTH;
buf2[0] = 0;
buf2len = 0;
for ( i = 0; i < count; )
{
/* get a line in buf1. */
fgets ( buf1, MAXPARAMLINELENGTH, f );
/** lengthen buf2 if necessary. */
while ( buf2len + strlen ( buf1 ) >= buf2alloc )
{
buf2 = (char *)REALLOC ( buf2, buf2alloc + MAXPARAMLINELENGTH );
buf2alloc += MAXPARAMLINELENGTH;
}
/** tack line onto buf2. **/
strcat ( buf2, buf1 );
buf2len += strlen ( buf1 );
/* get the first character of the next line. */
k = fgetc ( f );
if ( k != '+' )
{
/** not a '+', so the line is not continued. **/
/* chop the final newline. */
buf2[buf2len-1] = 0;
for ( j = 0; j < buf2len; ++j )
/* look for a " = " substring, and break it into name/value
there. */
if ( buf2[j] == ' ' && buf2[j+1] == '=' &&
buf2[j+2] == ' ' )
{
/** add the parameter. **/
buf2[j] = 0;
add_parameter ( buf2, buf2+j+3,
PARAM_COPY_NAME|PARAM_COPY_VALUE );
#ifdef DEBUG
fprintf ( stderr, "name = [%s]\nvalue = [%s]\n",
buf2, buf2+j+3 );
#endif
}
/** reset buf2. **/
buf2[0] = 0;
buf2len = 0;
/* count of how many we've found. */
++i;
}
}
/* put the extra character we read back. */
ungetc ( k, f );
FREE ( buf1 );
FREE ( buf2 );
}
/* write_parameter_database()
*
* this writes all the parameters to a checkpoint file, as "name = value\n".
* since parameters can have embedded newlines, we begin each line of the
* file with a "#" to indicate the start of a new name/value pair or a "+"
* to indicate a continuation of the previous line.
*/
void write_parameter_database ( FILE *f )
{
int i, j;
/* write the total count. */
fprintf ( f, "parameter-count: %d\n", param_size );
for ( i = 0; i < param_size; ++i )
{
/* start the pair with a '#'. */
fputc ( '#', f );
/** write the name, adding '+' after newlines. */
for ( j = 0; j < strlen ( param[i].n ); ++j )
{
fputc ( param[i].n[j], f );
if ( param[i].n[j] == '\n' )
fputc ( '+', f );
}
/* write " = ". */
fputs ( " = ", f );
/** write the value, adding '+' after newlines. */
for ( j = 0; j < strlen ( param[i].v ); ++j )
{
fputc ( param[i].v[j], f );
if ( param[i].v[j] == '\n' )
fputc ( '+', f );
}
/* end the pair. */
fputc ( '\n', f );
}
}
/* initialize_parameters()
*
* initializes the parameter database. */
void initialize_parameters ( void )
{
oputs ( OUT_SYS, 30, " parameter database.\n" );
param = (parameter *)MALLOC ( PARAMETER_MINSIZE * sizeof ( parameter ) );
param_alloc = PARAMETER_MINSIZE;
param_size = 0;
}
/* free_parameters()
*
* frees all the parameters.
*/
void free_parameters ( void )
{
int i;
for ( i = 0; i < param_size; ++i )
{
/* if add_parameter made a copy of the name, then free it. */
if ( param[i].copyflags & PARAM_COPY_NAME )
FREE ( param[i].n );
/* if add_parameter make a copy of the value, then free it. */
if ( param[i].copyflags & PARAM_COPY_VALUE )
FREE ( param[i].v );
}
FREE ( param );
param = NULL;
param_alloc = 0;
param_size = 0;
}
/* add_parameter()
*
* adds the given name/value pair to the database. the flags indicate
* which if any of the strings need to be copied.
*/
void add_parameter ( char *name, char *value, int copyflags )
{
/* erase any existing parameter of the same name. */
delete_parameter ( name );
/** if the database is full, make it bigger. **/
while ( param_alloc < param_size+1 )
{
param_alloc += PARAMETER_CHUNKSIZE;
param = (parameter *)REALLOC ( param,
param_alloc * sizeof ( parameter ) );
}
/** add the name. **/
if ( copyflags & PARAM_COPY_NAME )
{
/* make a copy of the string if requested. */
param[param_size].n = (char *)MALLOC ( strlen(name)+1 );
strcpy ( param[param_size].n, name );
}
else
/* just store the pointer passed to us. */
param[param_size].n = name;
/** add the value. **/
if ( copyflags & PARAM_COPY_VALUE )
{
/* make a copy of the string if requested. */
param[param_size].v = (char *)MALLOC ( strlen(value)+1 );
strcpy ( param[param_size].v, value );
}
else
/* just store the pointer passed to us. */
param[param_size].v = value;
/* record whether our values are copies or not. */
param[param_size].copyflags = copyflags;
++param_size;
}
/* delete_parameter()
*
* deletes a parameter from the database.
*/
int delete_parameter ( char *name )
{
int i;
for ( i = 0; i < param_size; ++i )
if ( strcmp ( name, param[i].n ) == 0 )
{
/** free any copies make by add_parameter. **/
if ( param[i].copyflags & PARAM_COPY_NAME )
FREE ( param[i].n );
if ( param[i].copyflags & PARAM_COPY_VALUE )
FREE ( param[i].v );
/** move the last value in the database to the position
of the deleted one. **/
if ( param_size-1 != i )
{
param[i].n = param[param_size-1].n;
param[i].v = param[param_size-1].v;
param[i].copyflags = param[param_size-1].copyflags;
}
--param_size;
return 1;
}
return 0;
}
/* get_parameter()
*
* looks up a parameter in the database.
*/
char *get_parameter ( const char *name )
{
int i;
for ( i = 0; i < param_size; ++i )
if ( strcmp ( name, param[i].n ) == 0 )
return param[i].v;
return NULL;
}
/* print_parameters()
*
* dumps parameter database to stdout.
*/
void print_parameters ( void )
{
int i;
for ( i = 0; i < param_size; ++i )
printf ( "name: \"%s\" value: \"%s\" copy: %d\n",
param[i].n, param[i].v, param[i].copyflags );
}
/* parse_one_parameter()
*
* breaks a string at the first equals sign into name and value parts.
* removes leading and trailing whitespace from both parts. inserts the
* resulting pair into the parameter database.
*/
int parse_one_parameter ( char *buffer )
{
char name[MAXPARAMLINELENGTH+1];
char data[MAXPARAMLINELENGTH+1];
int i, j, k, l;
int n, d;
k = -1;
j = 0;
l = strlen ( buffer );
/** scan for a equals sign. **/
for ( i = 0; i < l; ++i )
{
/* j records whether or not we have found a nonwhitespace
character. */
j += (buffer[i] != ' ' && buffer[i] != '\t' && buffer[i] != '\n');
if ( buffer[i] == '=' )
{
k = i;
/* copy the name part. */
strncpy ( name, buffer, k );
name[k] = 0;
/* copy the value part. */
strcpy ( data, buffer+k+1 );
break;
}
}
/* if we found no '=', return an error unless the line was
completely blank. */
if ( k == -1 )
return !!j;
/* trim leading and trailing whitespace. */
n = trim_string ( name );
d = trim_string ( data );
/** if either section is blank, return an error, otherwise add
the pair as a parameter. **/
if ( n == 0 || d == 0 )
return 1;
else
add_parameter ( name, data, PARAM_COPY_NAME|PARAM_COPY_VALUE );
return 0;
}
/* trim_string()
*
* trims leading and trailing whitespace from a string, overwriting the
* argument with the result. returns number of characters in result.
*/
int trim_string ( char *string )
{
int i, j, l;
j = -1;
l = strlen ( string );
for ( i = 0; i < l; ++i )
{
if ( j == -1 )
{
if ( string[i] != ' ' && string[i] != '\t' &&
string[i] != '\n' )
{
j = i;
--i;
}
}
else
string[i-j] = string[i];
}
if ( j == -1 )
{
string[0] = 0;
return 0;
}
string[i-j] = 0;
l = i-j;
j = -1;
for ( i = 0; i < l; ++i )
{
if ( string[i] != ' ' && string[i] != '\t' && string[i] != '\n' )
j = i;
}
string[j+1] = 0;
return j+1;
}
/* define_directive()
*
* defines a directive "SYMBOL", which is just a parameter called
* "__define:SYMBOL". trims leading and trailing whitespace from SYMBOL.
*/
void define_directive ( char *string )
{
char *buffer;
int i;
for ( i = 0; i < strlen(string) && isspace(string[i]); ++i );
buffer = (char *)MALLOC ( (20 + strlen(string)) * sizeof ( char ) );
strcpy ( buffer, "__define:" );
strcat ( buffer, string+i );
for ( i = strlen(buffer)-1; i >= 0 && isspace(buffer[i]); --i )
buffer[i] = 0;
add_parameter ( buffer, "1", PARAM_COPY_NAME );
FREE ( buffer );
}
/* undefine_directive()
*
* undefines a directive "SYMBOL".
*/
void undefine_directive ( char *string )
{
char *buffer;
int i;
for ( i = 0; i < strlen(string) && isspace(string[i]); ++i );
buffer = (char *)MALLOC ( (20 + strlen(string)) * sizeof ( char ) );
strcpy ( buffer, "__define:" );
strcat ( buffer, string+i );
for ( i = strlen(buffer)-1; i >= 0 && isspace(buffer[i]); --i )
buffer[i] = 0;
delete_parameter ( buffer );
FREE ( buffer );
}
/* test_directive()
*
* returns 1 iff a given directive is defined.
*/
int test_directive ( char *string )
{
char *buffer;
int ret;
int i;
for ( i = 0; i < strlen(string) && isspace(string[i]); ++i );
buffer = (char *)MALLOC ( (20 + strlen(string)) * sizeof ( char ) );
strcpy ( buffer, "__define:" );
strcat ( buffer, string+i );
for ( i = strlen(buffer)-1; i >= 0 && isspace(buffer[i]); --i )
buffer[i] = 0;
if ( get_parameter ( buffer ) )
ret = 1;
else
ret = 0;
FREE ( buffer );
return ret;
}
/* binary_parameter()
*
* checks for the existence of a parameter. if it exists, then it is changed
* to the string "0" or "1" using lilgp's list of strings representing
* binary values. if the value is not on the list, or the parameter is
* not found, then the parameter is set according to the value argument (it
* acts as a default).
*/
void binary_parameter ( char *name, int value )
{
char *param = get_parameter ( name );
char string[2];
char *i, *is;
int v;
if ( param != NULL )
{
/* copy the value and lowercase it. */
v = strlen ( param );
i = (char *)MALLOC ( (v+1)*sizeof ( char ) );
strcpy ( i, param );
for ( is = i; *is; ++is )
*is = tolower(*is);
/* translate to a binary integer. */
v = translate_binary ( i );
if ( v == -1 )
{
/* translation failed, use the value argument. */
error ( E_ERROR,
"\"%s\" is not a legal value for \"%s\"; assuming default.",
i, name );
v = value;
}
FREE ( i );
}
else
/* parameter not found, use the value argument. */
v = value;
/** print the value to a string and put it in the parameter database. */
sprintf ( string, "%d", !!v );
add_parameter ( name, string, PARAM_COPY_VALUE|PARAM_COPY_NAME );
}