mirror of
https://github.com/Q3Rally-Team/q3rally.git
synced 2024-12-01 08:01:06 +00:00
22a0949a26
Upgrade to build and run from VS2019 Upgrades to Xcode project and Apple Silicon support Update SDL2 to 2.0.14 Updated SDL2 include files to fix Mac build in GitHub Actions Added another mention of arm64 to command line help Restored original opus sse files, excluded from Xcode Added arm64 to the post-build symlinking step Merge branch 'main' into xcode Merge branch 'main' into vs2019 Added shell script to compile Universal 2 binary (x86_64+arm64) Reverting alert style to deprecated methods Upgrades to Xcode project and Apple Silicon support Update SDL2 to 2.0.14 Added another mention of arm64 to command line help Restored original opus sse files, excluded from Xcode Added arm64 to the post-build symlinking step Added shell script to compile Universal 2 binary (x86_64+arm64) Reverting alert style to deprecated methods Merge branch 'xcode' of https://github.com/tomkidd/ioq3 into xcode Removed signature from SDL dylib, enabled dark mode on macOS. spaces > tabs Ad-hoc signed libSDL2-2.0.0.dylib Fix compiling against SDL 2.0.17 UB2 now signs and notarizes, upgraded to SDL 2.0.16 Architectures in libSDL2 restored for ppc and i386 Merge remote-tracking branch 'upstream/main' into vs2019 Update SDL2 to 2.0.16 Added rudimentary support for automatically finding Microsoft Store version of Quake 3 GHA deprecated Ubuntu 16.04 - update to 18.04 qsort cannot be called with NULL Merge remote-tracking branch 'upstream/main' into vs2019 Addressed string concatenation issue and added dummy method for Mac/Linux Added missing variable. Merge remote-tracking branch 'upstream/main' into xcode Updated SDL 2.0.16 headers and Mac version of libraries to fix GitHub actions Addressed PR suggestions Modified MS Store path handling to better follow the pattern of Steam/GOG Merge pull request #481 from tomkidd/xcode Merge pull request #482 from tomkidd/vs2019 OpenGL2: Fix r_grayscale 1 making everything solid black Print full GL_EXTENSIONS list for OpenGL contexts before 3.0 Fix being unable to enter Team Arena CD key OpenGL2: GL_DEPTH_TEXTURE_MODE was removed from OpenGL 3.0/Core Improve setting Microsoft Store path Update building for macOS in README Make macOS arm64 default to target macOS 11 in Makefile Fix error when cross-compiling for macOS arm64 using Makefile Fix passing arguments to VM dylib on Apple M1 Fix compiling on older macOS Fix memory corruption in S_TransferPaintBuffer Fix memset Fix hex digit Fix uninitialized variable some old URL and doc updates Update README.md Update FUNDING.yml code/curl: update ifdef condition for MCST-LCC compiler in mcst-lcc compiler => 1.25 added a new macro definition to determine compiler Revert "code/curl: update ifdef condition for MCST-LCC compiler" Revert "E2K: fixed build by MCST lcc compiler when using USE_CURL=1 option" More predictable mesh normals generation vm_x86.c: Add `defined(_M_IX86) || defined(_M_X64)` (fix for VS2019) Add keys for SDL 2.0.14's new gamepad buttons Fix in_availableJoysticks cvar not updating Fix (disabled) Wavelet sound decompression Update to SDL 2.24.0 and add separate macOS UB2 dylib Update macOS UB1 to SDL 2.0.22 Fix running make-macosx{,-ub2}.sh on Linux Update MSVC .lib files to SDL 2.24.0
1445 lines
40 KiB
C
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 "unknown 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 <= 'F'))
|
|
{
|
|
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 successful
|
|
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
|