q3rally/engine/code/botlib/l_script.c
zturtleman 95fbb18fa1 ioquake3 resync to revision 3385 from 3347.
Fix going to previous browser source in q3_ui
Limit ui_smallFont/ui_bigFont/cg_noTaunt cvars to missionpack
Fix team chat box for spectators
Don't draw crosshair 0 in Team Arena setup menu
Make client for Windows x86_64 use OpenAL64.dll by default
Fix loading renderer DLLs on Windows x86
Add Windows application manifest
Disable DPI scaling on Windows
ignore window resize event on fullscreen
Don't reload arenas.txt/*.arena files in Team Arena UI
Fix crash when out of memory in Team Arena's String_Alloc
Fix in_nograb not releasing the mouse cursor
Update UI player animation handling to match CGame
Fix specifying minimum mac os version in make-macosx.sh
Fix listen server sending snapshots each client frame
Statically link libgcc on Windows
Fix hit accuracy stats for lightning gun and shotgun kills
Don't link to libGL at compile time
Add common OpenGL version parsing + OpenGL 3 fixes
Support parsing OpenGL ES version strings
Fix setting cflags/libs from sdl2-config
Load OpenGL ES 1.1 function procs
[qcommon] Use unsigned types where wrapping arithmetic is intended
OpenGL2: Fix brightness when r_autoExposure is disabled
OpenGL2: Fix MD3 surface with zero shaders dividing by zero
[botlib/be_aas_def.h] Change array size from MAX_PATH to MAX_QPATH
Don't redefine MAX_PATH in bot code
Fix memory leak in (unused) AAS_FloodAreas()
Fix compiling GLSL shaders under Windows.
Only draw cm_patch/bot debug polygons in world scenes
Fix reading crash log when log wraps around buffer
Don't send team overlay info to bots
Fix a race condition in the makedirs target
Fix shader corruption on OpenBSD
2017-11-04 11:30:30 +00:00

1445 lines
40 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_script.c
*
* desc: lexicographical parser
*
* $Archive: /MissionPack/code/botlib/l_script.c $
*
*****************************************************************************/
//#define SCREWUP
//#define BOTLIB
//#define MEQCC
//#define BSPC
#ifdef SCREWUP
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <stdarg.h>
#include "l_memory.h"
#include "l_script.h"
typedef enum {qfalse, qtrue} qboolean;
#endif //SCREWUP
#ifdef BOTLIB
//include files for usage in the bot library
#include "../qcommon/q_shared.h"
#include "botlib.h"
#include "be_interface.h"
#include "l_script.h"
#include "l_memory.h"
#include "l_log.h"
#include "l_libvar.h"
#endif //BOTLIB
#ifdef MEQCC
//include files for usage in MrElusive's QuakeC Compiler
#include "qcc.h"
#include "l_script.h"
#include "l_memory.h"
#include "l_log.h"
#define qtrue true
#define qfalse false
#endif //MEQCC
#ifdef BSPC
//include files for usage in the BSP Converter
#include "../bspc/qbsp.h"
#include "../bspc/l_log.h"
#include "../bspc/l_mem.h"
#define qtrue true
#define qfalse false
#endif //BSPC
#define PUNCTABLE
//longer punctuations first
punctuation_t default_punctuations[] =
{
//binary operators
{">>=",P_RSHIFT_ASSIGN, NULL},
{"<<=",P_LSHIFT_ASSIGN, NULL},
//
{"...",P_PARMS, NULL},
//define merge operator
{"##",P_PRECOMPMERGE, NULL},
//logic operators
{"&&",P_LOGIC_AND, NULL},
{"||",P_LOGIC_OR, NULL},
{">=",P_LOGIC_GEQ, NULL},
{"<=",P_LOGIC_LEQ, NULL},
{"==",P_LOGIC_EQ, NULL},
{"!=",P_LOGIC_UNEQ, NULL},
//arithmatic operators
{"*=",P_MUL_ASSIGN, NULL},
{"/=",P_DIV_ASSIGN, NULL},
{"%=",P_MOD_ASSIGN, NULL},
{"+=",P_ADD_ASSIGN, NULL},
{"-=",P_SUB_ASSIGN, NULL},
{"++",P_INC, NULL},
{"--",P_DEC, NULL},
//binary operators
{"&=",P_BIN_AND_ASSIGN, NULL},
{"|=",P_BIN_OR_ASSIGN, NULL},
{"^=",P_BIN_XOR_ASSIGN, NULL},
{">>",P_RSHIFT, NULL},
{"<<",P_LSHIFT, NULL},
//reference operators
{"->",P_POINTERREF, NULL},
//C++
{"::",P_CPP1, NULL},
{".*",P_CPP2, NULL},
//arithmatic operators
{"*",P_MUL, NULL},
{"/",P_DIV, NULL},
{"%",P_MOD, NULL},
{"+",P_ADD, NULL},
{"-",P_SUB, NULL},
{"=",P_ASSIGN, NULL},
//binary operators
{"&",P_BIN_AND, NULL},
{"|",P_BIN_OR, NULL},
{"^",P_BIN_XOR, NULL},
{"~",P_BIN_NOT, NULL},
//logic operators
{"!",P_LOGIC_NOT, NULL},
{">",P_LOGIC_GREATER, NULL},
{"<",P_LOGIC_LESS, NULL},
//reference operator
{".",P_REF, NULL},
//seperators
{",",P_COMMA, NULL},
{";",P_SEMICOLON, NULL},
//label indication
{":",P_COLON, NULL},
//if statement
{"?",P_QUESTIONMARK, NULL},
//embracements
{"(",P_PARENTHESESOPEN, NULL},
{")",P_PARENTHESESCLOSE, NULL},
{"{",P_BRACEOPEN, NULL},
{"}",P_BRACECLOSE, NULL},
{"[",P_SQBRACKETOPEN, NULL},
{"]",P_SQBRACKETCLOSE, NULL},
//
{"\\",P_BACKSLASH, NULL},
//precompiler operator
{"#",P_PRECOMP, NULL},
#ifdef DOLLAR
{"$",P_DOLLAR, NULL},
#endif //DOLLAR
{NULL, 0}
};
#ifdef BOTLIB
char basefolder[MAX_QPATH];
#endif
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void PS_CreatePunctuationTable(script_t *script, punctuation_t *punctuations)
{
int i;
punctuation_t *p, *lastp, *newp;
//get memory for the table
if (!script->punctuationtable) script->punctuationtable = (punctuation_t **)
GetMemory(256 * sizeof(punctuation_t *));
Com_Memset(script->punctuationtable, 0, 256 * sizeof(punctuation_t *));
//add the punctuations in the list to the punctuation table
for (i = 0; punctuations[i].p; i++)
{
newp = &punctuations[i];
lastp = NULL;
//sort the punctuations in this table entry on length (longer punctuations first)
for (p = script->punctuationtable[(unsigned int) newp->p[0]]; p; p = p->next)
{
if (strlen(p->p) < strlen(newp->p))
{
newp->next = p;
if (lastp) lastp->next = newp;
else script->punctuationtable[(unsigned int) newp->p[0]] = newp;
break;
} //end if
lastp = p;
} //end for
if (!p)
{
newp->next = NULL;
if (lastp) lastp->next = newp;
else script->punctuationtable[(unsigned int) newp->p[0]] = newp;
} //end if
} //end for
} //end of the function PS_CreatePunctuationTable
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
char *PunctuationFromNum(script_t *script, int num)
{
int i;
for (i = 0; script->punctuations[i].p; i++)
{
if (script->punctuations[i].n == num) return script->punctuations[i].p;
} //end for
return "unkown punctuation";
} //end of the function PunctuationFromNum
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void QDECL ScriptError(script_t *script, char *str, ...)
{
char text[1024];
va_list ap;
if (script->flags & SCFL_NOERRORS) return;
va_start(ap, str);
Q_vsnprintf(text, sizeof(text), str, ap);
va_end(ap);
#ifdef BOTLIB
botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", script->filename, script->line, text);
#endif //BOTLIB
#ifdef MEQCC
printf("error: file %s, line %d: %s\n", script->filename, script->line, text);
#endif //MEQCC
#ifdef BSPC
Log_Print("error: file %s, line %d: %s\n", script->filename, script->line, text);
#endif //BSPC
} //end of the function ScriptError
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void QDECL ScriptWarning(script_t *script, char *str, ...)
{
char text[1024];
va_list ap;
if (script->flags & SCFL_NOWARNINGS) return;
va_start(ap, str);
Q_vsnprintf(text, sizeof(text), str, ap);
va_end(ap);
#ifdef BOTLIB
botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", script->filename, script->line, text);
#endif //BOTLIB
#ifdef MEQCC
printf("warning: file %s, line %d: %s\n", script->filename, script->line, text);
#endif //MEQCC
#ifdef BSPC
Log_Print("warning: file %s, line %d: %s\n", script->filename, script->line, text);
#endif //BSPC
} //end of the function ScriptWarning
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void SetScriptPunctuations(script_t *script, punctuation_t *p)
{
#ifdef PUNCTABLE
if (p) PS_CreatePunctuationTable(script, p);
else PS_CreatePunctuationTable(script, default_punctuations);
#endif //PUNCTABLE
if (p) script->punctuations = p;
else script->punctuations = default_punctuations;
} //end of the function SetScriptPunctuations
//============================================================================
// Reads spaces, tabs, C-like comments etc.
// When a newline character is found the scripts line counter is increased.
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ReadWhiteSpace(script_t *script)
{
while(1)
{
//skip white space
while(*script->script_p <= ' ')
{
if (!*script->script_p) return 0;
if (*script->script_p == '\n') script->line++;
script->script_p++;
} //end while
//skip comments
if (*script->script_p == '/')
{
//comments //
if (*(script->script_p+1) == '/')
{
script->script_p++;
do
{
script->script_p++;
if (!*script->script_p) return 0;
} //end do
while(*script->script_p != '\n');
script->line++;
script->script_p++;
if (!*script->script_p) return 0;
continue;
} //end if
//comments /* */
else if (*(script->script_p+1) == '*')
{
script->script_p++;
do
{
script->script_p++;
if (!*script->script_p) return 0;
if (*script->script_p == '\n') script->line++;
} //end do
while(!(*script->script_p == '*' && *(script->script_p+1) == '/'));
script->script_p++;
if (!*script->script_p) return 0;
script->script_p++;
if (!*script->script_p) return 0;
continue;
} //end if
} //end if
break;
} //end while
return 1;
} //end of the function PS_ReadWhiteSpace
//============================================================================
// Reads an escape character.
//
// Parameter: script : script to read from
// ch : place to store the read escape character
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ReadEscapeCharacter(script_t *script, char *ch)
{
int c, val, i;
//step over the leading '\\'
script->script_p++;
//determine the escape character
switch(*script->script_p)
{
case '\\': c = '\\'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
case 'b': c = '\b'; break;
case 'f': c = '\f'; break;
case 'a': c = '\a'; break;
case '\'': c = '\''; break;
case '\"': c = '\"'; break;
case '\?': c = '\?'; break;
case 'x':
{
script->script_p++;
for (i = 0, val = 0; ; i++, script->script_p++)
{
c = *script->script_p;
if (c >= '0' && c <= '9') c = c - '0';
else if (c >= 'A' && c <= 'Z') c = c - 'A' + 10;
else if (c >= 'a' && c <= 'z') c = c - 'a' + 10;
else break;
val = (val << 4) + c;
} //end for
script->script_p--;
if (val > 0xFF)
{
ScriptWarning(script, "too large value in escape character");
val = 0xFF;
} //end if
c = val;
break;
} //end case
default: //NOTE: decimal ASCII code, NOT octal
{
if (*script->script_p < '0' || *script->script_p > '9') ScriptError(script, "unknown escape char");
for (i = 0, val = 0; ; i++, script->script_p++)
{
c = *script->script_p;
if (c >= '0' && c <= '9') c = c - '0';
else break;
val = val * 10 + c;
} //end for
script->script_p--;
if (val > 0xFF)
{
ScriptWarning(script, "too large value in escape character");
val = 0xFF;
} //end if
c = val;
break;
} //end default
} //end switch
//step over the escape character or the last digit of the number
script->script_p++;
//store the escape character
*ch = c;
//successfully read escape character
return 1;
} //end of the function PS_ReadEscapeCharacter
//============================================================================
// Reads C-like string. Escape characters are interpretted.
// Quotes are included with the string.
// Reads two strings with a white space between them as one string.
//
// Parameter: script : script to read from
// token : buffer to store the string
// Returns: qtrue when a string was read successfully
// Changes Globals: -
//============================================================================
int PS_ReadString(script_t *script, token_t *token, int quote)
{
int len, tmpline;
char *tmpscript_p;
if (quote == '\"') token->type = TT_STRING;
else token->type = TT_LITERAL;
len = 0;
//leading quote
token->string[len++] = *script->script_p++;
//
while(1)
{
//minus 2 because trailing double quote and zero have to be appended
if (len >= MAX_TOKEN - 2)
{
ScriptError(script, "string longer than MAX_TOKEN = %d", MAX_TOKEN);
return 0;
} //end if
//if there is an escape character and
//if escape characters inside a string are allowed
if (*script->script_p == '\\' && !(script->flags & SCFL_NOSTRINGESCAPECHARS))
{
if (!PS_ReadEscapeCharacter(script, &token->string[len]))
{
token->string[len] = 0;
return 0;
} //end if
len++;
} //end if
//if a trailing quote
else if (*script->script_p == quote)
{
//step over the double quote
script->script_p++;
//if white spaces in a string are not allowed
if (script->flags & SCFL_NOSTRINGWHITESPACES) break;
//
tmpscript_p = script->script_p;
tmpline = script->line;
//read unusefull stuff between possible two following strings
if (!PS_ReadWhiteSpace(script))
{
script->script_p = tmpscript_p;
script->line = tmpline;
break;
} //end if
//if there's no leading double qoute
if (*script->script_p != quote)
{
script->script_p = tmpscript_p;
script->line = tmpline;
break;
} //end if
//step over the new leading double quote
script->script_p++;
} //end if
else
{
if (*script->script_p == '\0')
{
token->string[len] = 0;
ScriptError(script, "missing trailing quote");
return 0;
} //end if
if (*script->script_p == '\n')
{
token->string[len] = 0;
ScriptError(script, "newline inside string %s", token->string);
return 0;
} //end if
token->string[len++] = *script->script_p++;
} //end else
} //end while
//trailing quote
token->string[len++] = quote;
//end string with a zero
token->string[len] = '\0';
//the sub type is the length of the string
token->subtype = len;
return 1;
} //end of the function PS_ReadString
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ReadName(script_t *script, token_t *token)
{
int len = 0;
char c;
token->type = TT_NAME;
do
{
token->string[len++] = *script->script_p++;
if (len >= MAX_TOKEN)
{
ScriptError(script, "name longer than MAX_TOKEN = %d", MAX_TOKEN);
return 0;
} //end if
c = *script->script_p;
} while ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
c == '_');
token->string[len] = '\0';
//the sub type is the length of the name
token->subtype = len;
return 1;
} //end of the function PS_ReadName
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
void NumberValue(char *string, int subtype, unsigned long int *intvalue,
float *floatvalue)
{
unsigned long int dotfound = 0;
*intvalue = 0;
*floatvalue = 0;
//floating point number
if (subtype & TT_FLOAT)
{
while(*string)
{
if (*string == '.')
{
if (dotfound) return;
dotfound = 10;
string++;
} //end if
if (dotfound)
{
*floatvalue = *floatvalue + (float) (*string - '0') /
(float) dotfound;
dotfound *= 10;
} //end if
else
{
*floatvalue = *floatvalue * 10.0 + (float) (*string - '0');
} //end else
string++;
} //end while
*intvalue = (unsigned long) *floatvalue;
} //end if
else if (subtype & TT_DECIMAL)
{
while(*string) *intvalue = *intvalue * 10 + (*string++ - '0');
*floatvalue = *intvalue;
} //end else if
else if (subtype & TT_HEX)
{
//step over the leading 0x or 0X
string += 2;
while(*string)
{
*intvalue <<= 4;
if (*string >= 'a' && *string <= 'f') *intvalue += *string - 'a' + 10;
else if (*string >= 'A' && *string <= 'F') *intvalue += *string - 'A' + 10;
else *intvalue += *string - '0';
string++;
} //end while
*floatvalue = *intvalue;
} //end else if
else if (subtype & TT_OCTAL)
{
//step over the first zero
string += 1;
while(*string) *intvalue = (*intvalue << 3) + (*string++ - '0');
*floatvalue = *intvalue;
} //end else if
else if (subtype & TT_BINARY)
{
//step over the leading 0b or 0B
string += 2;
while(*string) *intvalue = (*intvalue << 1) + (*string++ - '0');
*floatvalue = *intvalue;
} //end else if
} //end of the function NumberValue
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ReadNumber(script_t *script, token_t *token)
{
int len = 0, i;
int octal, dot;
char c;
// unsigned long int intvalue = 0;
// double floatvalue = 0;
token->type = TT_NUMBER;
//check for a hexadecimal number
if (*script->script_p == '0' &&
(*(script->script_p + 1) == 'x' ||
*(script->script_p + 1) == 'X'))
{
token->string[len++] = *script->script_p++;
token->string[len++] = *script->script_p++;
c = *script->script_p;
//hexadecimal
while((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'A'))
{
token->string[len++] = *script->script_p++;
if (len >= MAX_TOKEN)
{
ScriptError(script, "hexadecimal number longer than MAX_TOKEN = %d", MAX_TOKEN);
return 0;
} //end if
c = *script->script_p;
} //end while
token->subtype |= TT_HEX;
} //end if
#ifdef BINARYNUMBERS
//check for a binary number
else if (*script->script_p == '0' &&
(*(script->script_p + 1) == 'b' ||
*(script->script_p + 1) == 'B'))
{
token->string[len++] = *script->script_p++;
token->string[len++] = *script->script_p++;
c = *script->script_p;
//binary
while(c == '0' || c == '1')
{
token->string[len++] = *script->script_p++;
if (len >= MAX_TOKEN)
{
ScriptError(script, "binary number longer than MAX_TOKEN = %d", MAX_TOKEN);
return 0;
} //end if
c = *script->script_p;
} //end while
token->subtype |= TT_BINARY;
} //end if
#endif //BINARYNUMBERS
else //decimal or octal integer or floating point number
{
octal = qfalse;
dot = qfalse;
if (*script->script_p == '0') octal = qtrue;
while(1)
{
c = *script->script_p;
if (c == '.') dot = qtrue;
else if (c == '8' || c == '9') octal = qfalse;
else if (c < '0' || c > '9') break;
token->string[len++] = *script->script_p++;
if (len >= MAX_TOKEN - 1)
{
ScriptError(script, "number longer than MAX_TOKEN = %d", MAX_TOKEN);
return 0;
} //end if
} //end while
if (octal) token->subtype |= TT_OCTAL;
else token->subtype |= TT_DECIMAL;
if (dot) token->subtype |= TT_FLOAT;
} //end else
for (i = 0; i < 2; i++)
{
c = *script->script_p;
//check for a LONG number
if ( (c == 'l' || c == 'L')
&& !(token->subtype & TT_LONG))
{
script->script_p++;
token->subtype |= TT_LONG;
} //end if
//check for an UNSIGNED number
else if ( (c == 'u' || c == 'U')
&& !(token->subtype & (TT_UNSIGNED | TT_FLOAT)))
{
script->script_p++;
token->subtype |= TT_UNSIGNED;
} //end if
} //end for
token->string[len] = '\0';
#ifdef NUMBERVALUE
NumberValue(token->string, token->subtype, &token->intvalue, &token->floatvalue);
#endif //NUMBERVALUE
if (!(token->subtype & TT_FLOAT)) token->subtype |= TT_INTEGER;
return 1;
} //end of the function PS_ReadNumber
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ReadLiteral(script_t *script, token_t *token)
{
token->type = TT_LITERAL;
//first quote
token->string[0] = *script->script_p++;
//check for end of file
if (!*script->script_p)
{
ScriptError(script, "end of file before trailing \'");
return 0;
} //end if
//if it is an escape character
if (*script->script_p == '\\')
{
if (!PS_ReadEscapeCharacter(script, &token->string[1])) return 0;
} //end if
else
{
token->string[1] = *script->script_p++;
} //end else
//check for trailing quote
if (*script->script_p != '\'')
{
ScriptWarning(script, "too many characters in literal, ignored");
while(*script->script_p &&
*script->script_p != '\'' &&
*script->script_p != '\n')
{
script->script_p++;
} //end while
if (*script->script_p == '\'') script->script_p++;
} //end if
//store the trailing quote
token->string[2] = *script->script_p++;
//store trailing zero to end the string
token->string[3] = '\0';
//the sub type is the integer literal value
token->subtype = token->string[1];
//
return 1;
} //end of the function PS_ReadLiteral
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ReadPunctuation(script_t *script, token_t *token)
{
int len;
char *p;
punctuation_t *punc;
#ifdef PUNCTABLE
for (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next)
{
#else
int i;
for (i = 0; script->punctuations[i].p; i++)
{
punc = &script->punctuations[i];
#endif //PUNCTABLE
p = punc->p;
len = strlen(p);
//if the script contains at least as much characters as the punctuation
if (script->script_p + len <= script->end_p)
{
//if the script contains the punctuation
if (!strncmp(script->script_p, p, len))
{
Q_strncpyz(token->string, p, MAX_TOKEN);
script->script_p += len;
token->type = TT_PUNCTUATION;
//sub type is the number of the punctuation
token->subtype = punc->n;
return 1;
} //end if
} //end if
} //end for
return 0;
} //end of the function PS_ReadPunctuation
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ReadPrimitive(script_t *script, token_t *token)
{
int len;
len = 0;
while(*script->script_p > ' ' && *script->script_p != ';')
{
if (len >= MAX_TOKEN - 1)
{
ScriptError(script, "primitive token longer than MAX_TOKEN = %d", MAX_TOKEN);
return 0;
} //end if
token->string[len++] = *script->script_p++;
} //end while
token->string[len] = 0;
//copy the token into the script structure
Com_Memcpy(&script->token, token, sizeof(token_t));
//primitive reading successfull
return 1;
} //end of the function PS_ReadPrimitive
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ReadToken(script_t *script, token_t *token)
{
//if there is a token available (from UnreadToken)
if (script->tokenavailable)
{
script->tokenavailable = 0;
Com_Memcpy(token, &script->token, sizeof(token_t));
return 1;
} //end if
//save script pointer
script->lastscript_p = script->script_p;
//save line counter
script->lastline = script->line;
//clear the token stuff
Com_Memset(token, 0, sizeof(token_t));
//start of the white space
script->whitespace_p = script->script_p;
token->whitespace_p = script->script_p;
//read unusefull stuff
if (!PS_ReadWhiteSpace(script)) return 0;
//end of the white space
script->endwhitespace_p = script->script_p;
token->endwhitespace_p = script->script_p;
//line the token is on
token->line = script->line;
//number of lines crossed before token
token->linescrossed = script->line - script->lastline;
//if there is a leading double quote
if (*script->script_p == '\"')
{
if (!PS_ReadString(script, token, '\"')) return 0;
} //end if
//if a literal
else if (*script->script_p == '\'')
{
//if (!PS_ReadLiteral(script, token)) return 0;
if (!PS_ReadString(script, token, '\'')) return 0;
} //end if
//if there is a number
else if ((*script->script_p >= '0' && *script->script_p <= '9') ||
(*script->script_p == '.' &&
(*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9')))
{
if (!PS_ReadNumber(script, token)) return 0;
} //end if
//if this is a primitive script
else if (script->flags & SCFL_PRIMITIVE)
{
return PS_ReadPrimitive(script, token);
} //end else if
//if there is a name
else if ((*script->script_p >= 'a' && *script->script_p <= 'z') ||
(*script->script_p >= 'A' && *script->script_p <= 'Z') ||
*script->script_p == '_')
{
if (!PS_ReadName(script, token)) return 0;
} //end if
//check for punctuations
else if (!PS_ReadPunctuation(script, token))
{
ScriptError(script, "can't read token");
return 0;
} //end if
//copy the token into the script structure
Com_Memcpy(&script->token, token, sizeof(token_t));
//successfully read a token
return 1;
} //end of the function PS_ReadToken
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ExpectTokenString(script_t *script, char *string)
{
token_t token;
if (!PS_ReadToken(script, &token))
{
ScriptError(script, "couldn't find expected %s", string);
return 0;
} //end if
if (strcmp(token.string, string))
{
ScriptError(script, "expected %s, found %s", string, token.string);
return 0;
} //end if
return 1;
} //end of the function PS_ExpectToken
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token)
{
char str[MAX_TOKEN];
if (!PS_ReadToken(script, token))
{
ScriptError(script, "couldn't read expected token");
return 0;
} //end if
if (token->type != type)
{
strcpy(str, "");
if (type == TT_STRING) strcpy(str, "string");
if (type == TT_LITERAL) strcpy(str, "literal");
if (type == TT_NUMBER) strcpy(str, "number");
if (type == TT_NAME) strcpy(str, "name");
if (type == TT_PUNCTUATION) strcpy(str, "punctuation");
ScriptError(script, "expected a %s, found %s", str, token->string);
return 0;
} //end if
if (token->type == TT_NUMBER)
{
if ((token->subtype & subtype) != subtype)
{
strcpy(str, "");
if (subtype & TT_DECIMAL) strcpy(str, "decimal");
if (subtype & TT_HEX) strcpy(str, "hex");
if (subtype & TT_OCTAL) strcpy(str, "octal");
if (subtype & TT_BINARY) strcpy(str, "binary");
if (subtype & TT_LONG) strcat(str, " long");
if (subtype & TT_UNSIGNED) strcat(str, " unsigned");
if (subtype & TT_FLOAT) strcat(str, " float");
if (subtype & TT_INTEGER) strcat(str, " integer");
ScriptError(script, "expected %s, found %s", str, token->string);
return 0;
} //end if
} //end if
else if (token->type == TT_PUNCTUATION)
{
if (subtype < 0)
{
ScriptError(script, "BUG: wrong punctuation subtype");
return 0;
} //end if
if (token->subtype != subtype)
{
ScriptError(script, "expected %s, found %s",
script->punctuations[subtype].p, token->string);
return 0;
} //end if
} //end else if
return 1;
} //end of the function PS_ExpectTokenType
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_ExpectAnyToken(script_t *script, token_t *token)
{
if (!PS_ReadToken(script, token))
{
ScriptError(script, "couldn't read expected token");
return 0;
} //end if
else
{
return 1;
} //end else
} //end of the function PS_ExpectAnyToken
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_CheckTokenString(script_t *script, char *string)
{
token_t tok;
if (!PS_ReadToken(script, &tok)) return 0;
//if the token is available
if (!strcmp(tok.string, string)) return 1;
//token not available
script->script_p = script->lastscript_p;
return 0;
} //end of the function PS_CheckTokenString
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token)
{
token_t tok;
if (!PS_ReadToken(script, &tok)) return 0;
//if the type matches
if (tok.type == type &&
(tok.subtype & subtype) == subtype)
{
Com_Memcpy(token, &tok, sizeof(token_t));
return 1;
} //end if
//token is not available
script->script_p = script->lastscript_p;
return 0;
} //end of the function PS_CheckTokenType
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int PS_SkipUntilString(script_t *script, char *string)
{
token_t token;
while(PS_ReadToken(script, &token))
{
if (!strcmp(token.string, string)) return 1;
} //end while
return 0;
} //end of the function PS_SkipUntilString
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
void PS_UnreadLastToken(script_t *script)
{
script->tokenavailable = 1;
} //end of the function UnreadLastToken
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
void PS_UnreadToken(script_t *script, token_t *token)
{
Com_Memcpy(&script->token, token, sizeof(token_t));
script->tokenavailable = 1;
} //end of the function UnreadToken
//============================================================================
// returns the next character of the read white space, returns NULL if none
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
char PS_NextWhiteSpaceChar(script_t *script)
{
if (script->whitespace_p != script->endwhitespace_p)
{
return *script->whitespace_p++;
} //end if
else
{
return 0;
} //end else
} //end of the function PS_NextWhiteSpaceChar
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
void StripDoubleQuotes(char *string)
{
if (*string == '\"')
{
memmove(string, string+1, strlen(string));
} //end if
if (string[strlen(string)-1] == '\"')
{
string[strlen(string)-1] = '\0';
} //end if
} //end of the function StripDoubleQuotes
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
void StripSingleQuotes(char *string)
{
if (*string == '\'')
{
memmove(string, string+1, strlen(string));
} //end if
if (string[strlen(string)-1] == '\'')
{
string[strlen(string)-1] = '\0';
} //end if
} //end of the function StripSingleQuotes
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
float ReadSignedFloat(script_t *script)
{
token_t token;
float sign = 1.0;
PS_ExpectAnyToken(script, &token);
if (!strcmp(token.string, "-"))
{
if(!PS_ExpectAnyToken(script, &token))
{
ScriptError(script, "Missing float value");
return 0;
}
sign = -1.0;
}
if (token.type != TT_NUMBER)
{
ScriptError(script, "expected float value, found %s", token.string);
return 0;
}
return sign * token.floatvalue;
} //end of the function ReadSignedFloat
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
signed long int ReadSignedInt(script_t *script)
{
token_t token;
signed long int sign = 1;
PS_ExpectAnyToken(script, &token);
if (!strcmp(token.string, "-"))
{
if(!PS_ExpectAnyToken(script, &token))
{
ScriptError(script, "Missing integer value");
return 0;
}
sign = -1;
}
if (token.type != TT_NUMBER || token.subtype == TT_FLOAT)
{
ScriptError(script, "expected integer value, found %s", token.string);
return 0;
}
return sign * token.intvalue;
} //end of the function ReadSignedInt
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
void SetScriptFlags(script_t *script, int flags)
{
script->flags = flags;
} //end of the function SetScriptFlags
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int GetScriptFlags(script_t *script)
{
return script->flags;
} //end of the function GetScriptFlags
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
void ResetScript(script_t *script)
{
//pointer in script buffer
script->script_p = script->buffer;
//pointer in script buffer before reading token
script->lastscript_p = script->buffer;
//begin of white space
script->whitespace_p = NULL;
//end of white space
script->endwhitespace_p = NULL;
//set if there's a token available in script->token
script->tokenavailable = 0;
//
script->line = 1;
script->lastline = 1;
//clear the saved token
Com_Memset(&script->token, 0, sizeof(token_t));
} //end of the function ResetScript
//============================================================================
// returns true if at the end of the script
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int EndOfScript(script_t *script)
{
return script->script_p >= script->end_p;
} //end of the function EndOfScript
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int NumLinesCrossed(script_t *script)
{
return script->line - script->lastline;
} //end of the function NumLinesCrossed
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int ScriptSkipTo(script_t *script, char *value)
{
int len;
char firstchar;
firstchar = *value;
len = strlen(value);
do
{
if (!PS_ReadWhiteSpace(script)) return 0;
if (*script->script_p == firstchar)
{
if (!strncmp(script->script_p, value, len))
{
return 1;
} //end if
} //end if
script->script_p++;
} while(1);
} //end of the function ScriptSkipTo
#ifndef BOTLIB
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
int FileLength(FILE *fp)
{
int pos;
int end;
pos = ftell(fp);
fseek(fp, 0, SEEK_END);
end = ftell(fp);
fseek(fp, pos, SEEK_SET);
return end;
} //end of the function FileLength
#endif
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
script_t *LoadScriptFile(const char *filename)
{
#ifdef BOTLIB
fileHandle_t fp;
char pathname[MAX_QPATH];
#else
FILE *fp;
#endif
int length;
void *buffer;
script_t *script;
#ifdef BOTLIB
if (strlen(basefolder))
Com_sprintf(pathname, sizeof(pathname), "%s/%s", basefolder, filename);
else
Com_sprintf(pathname, sizeof(pathname), "%s", filename);
length = botimport.FS_FOpenFile( pathname, &fp, FS_READ );
if (!fp) return NULL;
#else
fp = fopen(filename, "rb");
if (!fp) return NULL;
length = FileLength(fp);
#endif
buffer = GetClearedMemory(sizeof(script_t) + length + 1);
script = (script_t *) buffer;
Com_Memset(script, 0, sizeof(script_t));
Q_strncpyz(script->filename, filename, sizeof(script->filename));
script->buffer = (char *) buffer + sizeof(script_t);
script->buffer[length] = 0;
script->length = length;
//pointer in script buffer
script->script_p = script->buffer;
//pointer in script buffer before reading token
script->lastscript_p = script->buffer;
//pointer to end of script buffer
script->end_p = &script->buffer[length];
//set if there's a token available in script->token
script->tokenavailable = 0;
//
script->line = 1;
script->lastline = 1;
//
SetScriptPunctuations(script, NULL);
//
#ifdef BOTLIB
botimport.FS_Read(script->buffer, length, fp);
botimport.FS_FCloseFile(fp);
#else
if (fread(script->buffer, length, 1, fp) != 1)
{
FreeMemory(buffer);
script = NULL;
} //end if
fclose(fp);
#endif
return script;
} //end of the function LoadScriptFile
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
script_t *LoadScriptMemory(char *ptr, int length, char *name)
{
void *buffer;
script_t *script;
buffer = GetClearedMemory(sizeof(script_t) + length + 1);
script = (script_t *) buffer;
Com_Memset(script, 0, sizeof(script_t));
Q_strncpyz(script->filename, name, sizeof(script->filename));
script->buffer = (char *) buffer + sizeof(script_t);
script->buffer[length] = 0;
script->length = length;
//pointer in script buffer
script->script_p = script->buffer;
//pointer in script buffer before reading token
script->lastscript_p = script->buffer;
//pointer to end of script buffer
script->end_p = &script->buffer[length];
//set if there's a token available in script->token
script->tokenavailable = 0;
//
script->line = 1;
script->lastline = 1;
//
SetScriptPunctuations(script, NULL);
//
Com_Memcpy(script->buffer, ptr, length);
//
return script;
} //end of the function LoadScriptMemory
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
void FreeScript(script_t *script)
{
#ifdef PUNCTABLE
if (script->punctuationtable) FreeMemory(script->punctuationtable);
#endif //PUNCTABLE
FreeMemory(script);
} //end of the function FreeScript
//============================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//============================================================================
void PS_SetBaseFolder(char *path)
{
#ifdef BOTLIB
Com_sprintf(basefolder, sizeof(basefolder), "%s", path);
#endif
} //end of the function PS_SetBaseFolder