ioef/code/botlib/l_struct.c
2009-06-01 00:18:02 +00:00

462 lines
12 KiB
C

/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
/*****************************************************************************
* name: l_struct.c
*
* desc: structure reading / writing
*
* $Archive: /MissionPack/CODE/botlib/l_struct.c $
*
*****************************************************************************/
#ifdef BOTLIB
#include "../qcommon/q_shared.h"
#include "botlib.h" //for the include of be_interface.h
#include "l_script.h"
#include "l_precomp.h"
#include "l_struct.h"
#include "l_utils.h"
#include "be_interface.h"
#endif //BOTLIB
#ifdef BSPC
//include files for usage in the BSP Converter
#include "../bspc/qbsp.h"
#include "../bspc/l_log.h"
#include "../bspc/l_mem.h"
#include "l_precomp.h"
#include "l_struct.h"
#define qtrue true
#define qfalse false
#endif //BSPC
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
fielddef_t *FindField(fielddef_t *defs, char *name)
{
int i;
for (i = 0; defs[i].name; i++)
{
if (!strcmp(defs[i].name, name)) return &defs[i];
} //end for
return NULL;
} //end of the function FindField
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
qboolean ReadNumber(source_t *source, fielddef_t *fd, void *p)
{
token_t token;
int negative = qfalse;
long int intval, intmin = 0, intmax = 0;
double floatval;
if (!PC_ExpectAnyToken(source, &token)) return 0;
//check for minus sign
if (token.type == TT_PUNCTUATION)
{
if (fd->type & FT_UNSIGNED)
{
SourceError(source, "expected unsigned value, found %s", token.string);
return 0;
} //end if
//if not a minus sign
if (strcmp(token.string, "-"))
{
SourceError(source, "unexpected punctuation %s", token.string);
return 0;
} //end if
negative = qtrue;
//read the number
if (!PC_ExpectAnyToken(source, &token)) return 0;
} //end if
//check if it is a number
if (token.type != TT_NUMBER)
{
SourceError(source, "expected number, found %s", token.string);
return 0;
} //end if
//check for a float value
if (token.subtype & TT_FLOAT)
{
if ((fd->type & FT_TYPE) != FT_FLOAT)
{
SourceError(source, "unexpected float");
return 0;
} //end if
floatval = token.floatvalue;
if (negative) floatval = -floatval;
if (fd->type & FT_BOUNDED)
{
if (floatval < fd->floatmin || floatval > fd->floatmax)
{
SourceError(source, "float out of range [%f, %f]", fd->floatmin, fd->floatmax);
return 0;
} //end if
} //end if
*(float *) p = (float) floatval;
return 1;
} //end if
//
intval = token.intvalue;
if (negative) intval = -intval;
//check bounds
if ((fd->type & FT_TYPE) == FT_CHAR)
{
if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 255;}
else {intmin = -128; intmax = 127;}
} //end if
if ((fd->type & FT_TYPE) == FT_INT)
{
if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 65535;}
else {intmin = -32768; intmax = 32767;}
} //end else if
if ((fd->type & FT_TYPE) == FT_CHAR || (fd->type & FT_TYPE) == FT_INT)
{
if (fd->type & FT_BOUNDED)
{
intmin = Maximum(intmin, fd->floatmin);
intmax = Minimum(intmax, fd->floatmax);
} //end if
if (intval < intmin || intval > intmax)
{
SourceError(source, "value %d out of range [%d, %d]", intval, intmin, intmax);
return 0;
} //end if
} //end if
else if ((fd->type & FT_TYPE) == FT_FLOAT)
{
if (fd->type & FT_BOUNDED)
{
if (intval < fd->floatmin || intval > fd->floatmax)
{
SourceError(source, "value %d out of range [%f, %f]", intval, fd->floatmin, fd->floatmax);
return 0;
} //end if
} //end if
} //end else if
//store the value
if ((fd->type & FT_TYPE) == FT_CHAR)
{
if (fd->type & FT_UNSIGNED) *(unsigned char *) p = (unsigned char) intval;
else *(char *) p = (char) intval;
} //end if
else if ((fd->type & FT_TYPE) == FT_INT)
{
if (fd->type & FT_UNSIGNED) *(unsigned int *) p = (unsigned int) intval;
else *(int *) p = (int) intval;
} //end else
else if ((fd->type & FT_TYPE) == FT_FLOAT)
{
*(float *) p = (float) intval;
} //end else
return 1;
} //end of the function ReadNumber
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
qboolean ReadChar(source_t *source, fielddef_t *fd, void *p)
{
token_t token;
if (!PC_ExpectAnyToken(source, &token)) return 0;
//take literals into account
if (token.type == TT_LITERAL)
{
StripSingleQuotes(token.string);
*(char *) p = token.string[0];
} //end if
else
{
PC_UnreadLastToken(source);
if (!ReadNumber(source, fd, p)) return 0;
} //end if
return 1;
} //end of the function ReadChar
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int ReadString(source_t *source, fielddef_t *fd, void *p)
{
token_t token;
if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) return 0;
//remove the double quotes
StripDoubleQuotes(token.string);
//copy the string
strncpy((char *) p, token.string, MAX_STRINGFIELD);
//make sure the string is closed with a zero
((char *)p)[MAX_STRINGFIELD-1] = '\0';
//
return 1;
} //end of the function ReadString
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int ReadStructure(source_t *source, structdef_t *def, char *structure)
{
token_t token;
fielddef_t *fd;
void *p;
int num;
if (!PC_ExpectTokenString(source, "{")) return 0;
while(1)
{
if (!PC_ExpectAnyToken(source, &token)) return qfalse;
//if end of structure
if (!strcmp(token.string, "}")) break;
//find the field with the name
fd = FindField(def->fields, token.string);
if (!fd)
{
SourceError(source, "unknown structure field %s", token.string);
return qfalse;
} //end if
if (fd->type & FT_ARRAY)
{
num = fd->maxarray;
if (!PC_ExpectTokenString(source, "{")) return qfalse;
} //end if
else
{
num = 1;
} //end else
p = (void *)(structure + fd->offset);
while (num-- > 0)
{
if (fd->type & FT_ARRAY)
{
if (PC_CheckTokenString(source, "}")) break;
} //end if
switch(fd->type & FT_TYPE)
{
case FT_CHAR:
{
if (!ReadChar(source, fd, p)) return qfalse;
p = (char *) p + sizeof(char);
break;
} //end case
case FT_INT:
{
if (!ReadNumber(source, fd, p)) return qfalse;
p = (char *) p + sizeof(int);
break;
} //end case
case FT_FLOAT:
{
if (!ReadNumber(source, fd, p)) return qfalse;
p = (char *) p + sizeof(float);
break;
} //end case
case FT_STRING:
{
if (!ReadString(source, fd, p)) return qfalse;
p = (char *) p + MAX_STRINGFIELD;
break;
} //end case
case FT_STRUCT:
{
if (!fd->substruct)
{
SourceError(source, "BUG: no sub structure defined");
return qfalse;
} //end if
ReadStructure(source, fd->substruct, (char *) p);
p = (char *) p + fd->substruct->size;
break;
} //end case
} //end switch
if (fd->type & FT_ARRAY)
{
if (!PC_ExpectAnyToken(source, &token)) return qfalse;
if (!strcmp(token.string, "}")) break;
if (strcmp(token.string, ","))
{
SourceError(source, "expected a comma, found %s", token.string);
return qfalse;
} //end if
} //end if
} //end while
} //end while
return qtrue;
} //end of the function ReadStructure
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int WriteIndent(FILE *fp, int indent)
{
while(indent-- > 0)
{
if (fprintf(fp, "\t") < 0) return qfalse;
} //end while
return qtrue;
} //end of the function WriteIndent
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int WriteFloat(FILE *fp, float value)
{
char buf[128];
int l;
Com_sprintf(buf, sizeof(buf), "%f", value);
l = strlen(buf);
//strip any trailing zeros
while(l-- > 1)
{
if (buf[l] != '0' && buf[l] != '.') break;
if (buf[l] == '.')
{
buf[l] = 0;
break;
} //end if
buf[l] = 0;
} //end while
//write the float to file
if (fprintf(fp, "%s", buf) < 0) return 0;
return 1;
} //end of the function WriteFloat
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int WriteStructWithIndent(FILE *fp, structdef_t *def, char *structure, int indent)
{
int i, num;
void *p;
fielddef_t *fd;
if (!WriteIndent(fp, indent)) return qfalse;
if (fprintf(fp, "{\r\n") < 0) return qfalse;
indent++;
for (i = 0; def->fields[i].name; i++)
{
fd = &def->fields[i];
if (!WriteIndent(fp, indent)) return qfalse;
if (fprintf(fp, "%s\t", fd->name) < 0) return qfalse;
p = (void *)(structure + fd->offset);
if (fd->type & FT_ARRAY)
{
num = fd->maxarray;
if (fprintf(fp, "{") < 0) return qfalse;
} //end if
else
{
num = 1;
} //end else
while(num-- > 0)
{
switch(fd->type & FT_TYPE)
{
case FT_CHAR:
{
if (fprintf(fp, "%d", *(char *) p) < 0) return qfalse;
p = (char *) p + sizeof(char);
break;
} //end case
case FT_INT:
{
if (fprintf(fp, "%d", *(int *) p) < 0) return qfalse;
p = (char *) p + sizeof(int);
break;
} //end case
case FT_FLOAT:
{
if (!WriteFloat(fp, *(float *)p)) return qfalse;
p = (char *) p + sizeof(float);
break;
} //end case
case FT_STRING:
{
if (fprintf(fp, "\"%s\"", (char *) p) < 0) return qfalse;
p = (char *) p + MAX_STRINGFIELD;
break;
} //end case
case FT_STRUCT:
{
if (!WriteStructWithIndent(fp, fd->substruct, structure, indent)) return qfalse;
p = (char *) p + fd->substruct->size;
break;
} //end case
} //end switch
if (fd->type & FT_ARRAY)
{
if (num > 0)
{
if (fprintf(fp, ",") < 0) return qfalse;
} //end if
else
{
if (fprintf(fp, "}") < 0) return qfalse;
} //end else
} //end if
} //end while
if (fprintf(fp, "\r\n") < 0) return qfalse;
} //end for
indent--;
if (!WriteIndent(fp, indent)) return qfalse;
if (fprintf(fp, "}\r\n") < 0) return qfalse;
return qtrue;
} //end of the function WriteStructWithIndent
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int WriteStructure(FILE *fp, structdef_t *def, char *structure)
{
return WriteStructWithIndent(fp, def, structure, 0);
} //end of the function WriteStructure