move the script parser from qfbsp into libQFutil and correct a spelling error

This is an imperfect revision of history.
This commit is contained in:
Bill Currie 2004-11-02 05:05:00 +00:00 committed by Jeff Teunissen
parent 33bc7858f7
commit 25484f415b
6 changed files with 352 additions and 174 deletions

View file

@ -7,9 +7,9 @@ nobase_pkginclude_HEADERS = \
llist.h locs.h mathlib.h mdfour.h model.h modelgen.h msg.h object.h pak.h \
pakfile.h pcx.h png.h plugin.h pr_comp.h pr_debug.h pr_obj.h progs.h \
qargs.h qdefs.h qendian.h qfplist.h qtypes.h quakefs.h quakeio.h render.h \
riff.h ruamoko.h screen.h sizebuf.h skin.h sound.h spritegn.h sys.h \
teamplay.h tga.h uint32.h va.h ver_check.h vid.h view.h wad.h wadfile.h \
zone.h \
riff.h ruamoko.h screen.h script.h sizebuf.h skin.h sound.h spritegn.h \
sys.h teamplay.h tga.h uint32.h va.h ver_check.h vid.h view.h wad.h \
wadfile.h zone.h \
\
GL/ati.h GL/defines.h GL/extensions.h GL/funcs.h GL/qf_explosions.h \
GL/qf_funcs_list.h GL/qf_lightmap.h GL/qf_noisetextures.h \

96
include/QF/script.h Normal file
View file

@ -0,0 +1,96 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
See file, 'COPYING', for details.
*/
#ifndef __QF_script_h
#define __QF_script_h
/** \addtogroup utils */
//@{
/** \defgroup script Scripts
Line oriented script parsing. Multiple scripts being parsed at the same
time is supported.
*/
//@{
#include "QF/qtypes.h"
typedef struct script_s {
/// The current (or next when unget is true) token
struct dstring_s *token;
/// True if the last token has been pushed back.
qboolean unget;
/// current position within the script
const char *p;
/// name of the file being processed. used only for error reporting
const char *file;
/// line number of the file being processed. used only for error reporting
/// but updated internally.
int line;
/// if set, will be called instead of the internal error handler
void (*error)(struct script_s *script, const char *msg);
/// if set, multi line quoted tokens will be treated as errors
int no_quote_lines;
} script_t;
/** Return a new script_t object.
\return A new, blank, script object. Use Script_Start() to initialize.
*/
script_t *Script_New (void);
/** Delete a script_t object.
\param script The script_t object to be deleted
Does not free the memory passed to Script_Start().
*/
void Script_Delete (script_t *script);
/** Prepare a script_t object for parsing.
The caller is responsible for freeing the memory associated with file and
data when parsing is complete.
\param script The script_t object being parsed
\param file Name of the file being parsed. used only for error reporting
\param data The script to be parsed
*/
void Script_Start (script_t *script, const char *file, const char *data);
/** Check if a new token is available.
\param script The script_t object being parsed
\param crossline True to allow passing \n
\return True if a token is available, false if end of file
or end of line (if crossline is false) has been hit
*/
qboolean Script_TokenAvailable (script_t *script, qboolean crossline);
/** Get the next token. Generates an error and exits the program if no token
is available and crossline is false.
\param script The script_t object being parsed
\param crossline True to allow passing \n
\return True on success, false on failure (no token available)
*/
qboolean Script_GetToken (script_t *script, qboolean crossline);
/** Unget the current token. Only one level of unget is supported.
\param script The script_t object being parsed
*/
void Script_UngetToken (script_t *script);
//@}
//@}
#endif//__QF_script_h

View file

@ -38,7 +38,7 @@ libQFutil_la_SOURCES= \
bspfile.c buildnum.c cbuf.c checksum.c cmd.c crc.c cvar.c dstring.c \
fendian.c hash.c idparse.c info.c link.c llist.c \
mathlib.c mdfour.c msg.c pakfile.c plugin.c qargs.c qendian.c \
qfplist.c quakefs.c quakeio.c riff.c sizebuf.c string.c sys.c \
qfplist.c quakefs.c quakeio.c riff.c script.c sizebuf.c string.c sys.c \
va.c ver_check.c wad.c wadfile.c zone.c $(fnmatch) $(getopt)
EXTRA_DIST= $(fnmatch_src) $(getopt_src)

173
libs/util/script.c Normal file
View file

@ -0,0 +1,173 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
See file, 'COPYING', for details.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((unused)) const char rcsid[] =
"$Id$";
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include "QF/dstring.h"
#include "QF/script.h"
static void __attribute__ ((format (printf, 2, 3), noreturn))
script_error (script_t *script, const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
fprintf (stderr, "%s:%d: ", script->file, script->line);
vfprintf (stderr, fmt, args);
fprintf (stderr, "\n");
va_end (args);
exit (1);
}
script_t *
Script_New (void)
{
script_t *script = calloc (1, sizeof (script_t));
script->token = dstring_newstr ();
return script;
}
void
Script_Delete (script_t *script)
{
dstring_delete (script->token);
free (script);
}
void
Script_Start (script_t *script, const char *file, const char *data)
{
script->line = 1;
script->file = file;
script->p = data;
script->unget = false;
}
qboolean
Script_TokenAvailable (script_t *script, qboolean crossline)
{
if (script->unget)
return true;
skipspace:
while (isspace ((unsigned char) *script->p)) {
if (*script->p == '\n') {
if (!crossline)
return false;
script->line++;
}
script->p++;
}
if (!*script->p)
return false;
if (*script->p == 26 || *script->p == 4) {
// end of file characters
script->p++;
goto skipspace;
}
if (script->p[0] == '/' && script->p[1] == '/') {
// comment field
while (*script->p && *script->p != '\n')
script->p++;
if (!*script->p)
return false;
if (!crossline)
return false;
goto skipspace;
}
return true;
}
qboolean
Script_GetToken (script_t *script, qboolean crossline)
{
const char *token_p;
if (script->unget) { // is a token allready waiting?
script->unget = false;
return true;
}
if (!Script_TokenAvailable (script, crossline)) {
if (!crossline) {
if (script->error)
script->error (script, "line is incomplete");
else
script_error (script, "line is incomplete");
}
return false;
}
// copy token
if (*script->p == '"') {
int start_line = script->line;
script->p++;
token_p = script->p;
while (*script->p != '"') {
if (!*script->p) {
script->line = start_line;
if (script->error)
script->error (script, "EOF inside quoted token");
else
script_error (script, "EOF inside quoted token");
return false;
}
if (*script->p == '\n') {
if (script->no_quote_lines) {
if (script->error)
script->error (script, "EOL inside quoted token");
else
script_error (script, "EOL inside quoted token");
}
script->line++;
}
script->p++;
}
dstring_copysubstr (script->token, token_p, script->p - token_p);
script->p++;
} else {
token_p = script->p;
while (*script->p && !isspace ((unsigned char) *script->p))
script->p++;
dstring_copysubstr (script->token, token_p, script->p - token_p);
}
return true;
}
void
Script_UngetToken (script_t *script)
{
script->unget = true;
}

View file

@ -287,7 +287,7 @@ CopyFacesToOutside (brush_t *b)
/*
CSGFaces
Returns a list of surfaces containing aall of the faces
Returns a list of surfaces containing all of the faces
*/
surface_t *
CSGFaces (brushset_t *bs)

View file

@ -36,6 +36,7 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "QF/dstring.h"
#include "QF/quakefs.h"
#include "QF/script.h"
#include "QF/sys.h"
#include "QF/va.h"
@ -53,11 +54,7 @@ char miptex[MAX_MAP_TEXINFO][16];
int numdetailbrushes;
dstring_t token = {&dstring_default_mem};
qboolean unget;
char *script_p;
const char *script_file;
int script_line;
script_t *map;
static void __attribute__ ((format (printf, 1, 2), noreturn))
map_error (const char *fmt, ...)
@ -65,7 +62,7 @@ map_error (const char *fmt, ...)
va_list args;
va_start (args, fmt);
fprintf (stderr, "%s:%d: ", script_file, script_line);
fprintf (stderr, "%s:%d: ", map->file, map->line);
vfprintf (stderr, fmt, args);
fprintf (stderr, "\n");
va_end (args);
@ -133,95 +130,6 @@ FindTexinfo (texinfo_t *t)
return i;
}
static void
StartTokenParsing (char *data)
{
script_line = 1;
script_p = data;
unget = false;
}
static qboolean
TokenAvailable (qboolean crossline)
{
if (unget)
return true;
skipspace:
while (isspace ((unsigned char) *script_p)) {
if (*script_p == '\n') {
if (!crossline)
return false;
script_line++;
}
script_p++;
}
if (!*script_p)
return false;
if (*script_p == 26 || *script_p == 4) { // end of file characters
script_p++;
goto skipspace;
}
if (script_p[0] == '/' && script_p[1] == '/') { // comment field
while (*script_p && *script_p != '\n')
script_p++;
if (!*script_p)
return false;
if (!crossline)
return false;
goto skipspace;
}
return true;
}
static qboolean
GetToken (qboolean crossline)
{
char *token_p;
if (unget) { // is a token allready waiting?
unget = false;
return true;
}
if (!TokenAvailable (crossline)) {
if (!crossline)
map_error ("line is incomplete");
return false;
}
// copy token
if (*script_p == '"') {
script_p++;
token_p = script_p;
while (*script_p != '"') {
if (!*script_p)
map_error ("EOF inside quoted token");
if (*script_p == '\n')
script_line++;
script_p++;
}
dstring_copysubstr (&token, token_p, script_p - token_p);
script_p++;
} else {
token_p = script_p;
while (*script_p && !isspace ((unsigned char) *script_p))
script_p++;
dstring_copysubstr (&token, token_p, script_p - token_p);
}
*token_p = 0;
return true;
}
static void
UngetToken (void)
{
unget = true;
}
entity_t *mapent;
static void
@ -234,9 +142,9 @@ ParseEpair (void)
e->next = mapent->epairs;
mapent->epairs = e;
e->key = strdup (token.str);
GetToken (false);
e->value = strdup (token.str);
e->key = strdup (map->token->str);
Script_GetToken (map, false);
e->value = strdup (map->token->str);
}
vec3_t baseaxis[18] = {
@ -275,18 +183,18 @@ ParseVerts (int *n_verts)
vec3_t *verts;
int i;
if (token.str[0] != ':')
if (map->token->str[0] != ':')
map_error ("parsing brush");
*n_verts = atoi (token.str + 1);
*n_verts = atoi (map->token->str + 1);
verts = malloc (sizeof (vec3_t) * *n_verts);
for (i = 0; i < *n_verts; i++) {
GetToken (true);
verts[i][0] = atof (token.str);
GetToken (true);
verts[i][1] = atof (token.str);
GetToken (true);
verts[i][2] = atof (token.str);
Script_GetToken (map, true);
verts[i][0] = atof (map->token->str);
Script_GetToken (map, true);
verts[i][1] = atof (map->token->str);
Script_GetToken (map, true);
verts[i][2] = atof (map->token->str);
}
return verts;
@ -312,45 +220,45 @@ ParseBrush (void)
b->next = mapent->brushes;
mapent->brushes = b;
GetToken (true);
if (strcmp (token.str, "(") != 0) {
Script_GetToken (map, true);
if (strcmp (map->token->str, "(") != 0) {
verts = ParseVerts (&n_verts);
} else {
UngetToken ();
Script_UngetToken (map);
}
do {
if (!GetToken (true))
if (!Script_GetToken (map, true))
break;
if (!strcmp (token.str, "}"))
if (!strcmp (map->token->str, "}"))
break;
if (verts) {
int n_v, v;
n_v = atoi (token.str);
GetToken (false);
n_v = atoi (map->token->str);
Script_GetToken (map, false);
for (i = 0; i < n_v; i++) {
GetToken (false);
v = atof (token.str);
Script_GetToken (map, false);
v = atof (map->token->str);
if (i < 3)
VectorCopy (verts[v], planepts[i]);
}
GetToken (false);
Script_GetToken (map, false);
} else {
// read the three point plane definition
for (i = 0; i < 3; i++) {
if (i != 0)
GetToken (true);
if (strcmp (token.str, "("))
Script_GetToken (map, true);
if (strcmp (map->token->str, "("))
map_error ("parsing brush");
for (j = 0; j < 3; j++) {
GetToken (false);
planepts[i][j] = atof (token.str);
Script_GetToken (map, false);
planepts[i][j] = atof (map->token->str);
}
GetToken (false);
if (strcmp (token.str, ")"))
Script_GetToken (map, false);
if (strcmp (map->token->str, ")"))
map_error ("parsing brush");
}
}
@ -364,53 +272,53 @@ ParseBrush (void)
// read the texturedef
memset (&tx, 0, sizeof (tx));
GetToken (false);
tx.miptex = FindMiptex (token.str);
GetToken (false);
if ((hltexdef = !strcmp (token.str, "["))) {
Script_GetToken (map, false);
tx.miptex = FindMiptex (map->token->str);
Script_GetToken (map, false);
if ((hltexdef = !strcmp (map->token->str, "["))) {
// S vector
GetToken (false);
vecs[0][0] = atof (token.str);
GetToken (false);
vecs[0][1] = atof (token.str);
GetToken (false);
vecs[0][2] = atof (token.str);
GetToken (false);
vecs[0][3] = atof (token.str);
GetToken (false);
if (strcmp (token.str, "]"))
Script_GetToken (map, false);
vecs[0][0] = atof (map->token->str);
Script_GetToken (map, false);
vecs[0][1] = atof (map->token->str);
Script_GetToken (map, false);
vecs[0][2] = atof (map->token->str);
Script_GetToken (map, false);
vecs[0][3] = atof (map->token->str);
Script_GetToken (map, false);
if (strcmp (map->token->str, "]"))
map_error ("missing ]");
GetToken (false);
if (strcmp (token.str, "["))
Script_GetToken (map, false);
if (strcmp (map->token->str, "["))
map_error ("missing [");
// T vector
GetToken (false);
vecs[1][0] = atof (token.str);
GetToken (false);
vecs[1][1] = atof (token.str);
GetToken (false);
vecs[1][2] = atof (token.str);
GetToken (false);
vecs[1][3] = atof (token.str);
GetToken (false);
if (strcmp (token.str, "]"))
Script_GetToken (map, false);
vecs[1][0] = atof (map->token->str);
Script_GetToken (map, false);
vecs[1][1] = atof (map->token->str);
Script_GetToken (map, false);
vecs[1][2] = atof (map->token->str);
Script_GetToken (map, false);
vecs[1][3] = atof (map->token->str);
Script_GetToken (map, false);
if (strcmp (map->token->str, "]"))
map_error ("missing ]");
} else {
vecs[0][3] = atof (token.str);
GetToken (false);
vecs[1][3] = atof (token.str);
vecs[0][3] = atof (map->token->str);
Script_GetToken (map, false);
vecs[1][3] = atof (map->token->str);
}
GetToken (false);
rotate = atof (token.str);
GetToken (false);
scale[0] = atof (token.str);
GetToken (false);
scale[1] = atof (token.str);
Script_GetToken (map, false);
rotate = atof (map->token->str);
Script_GetToken (map, false);
scale[0] = atof (map->token->str);
Script_GetToken (map, false);
scale[1] = atof (map->token->str);
while (TokenAvailable (false)) {
GetToken (false);
if (!strcmp (token.str, "detail"))
while (Script_TokenAvailable (map, false)) {
Script_GetToken (map, false);
if (!strcmp (map->token->str, "detail"))
b->detail = 1;
else
map_error ("parse error");
@ -435,7 +343,7 @@ ParseBrush (void)
if (DotProduct (plane.normal, plane.normal) < 0.1) {
printf ("WARNING: brush plane with no normal on line %d\n",
script_line);
map->line);
continue;
}
@ -509,10 +417,10 @@ ParseBrush (void)
static qboolean
ParseEntity (void)
{
if (!GetToken (true))
if (!Script_GetToken (map, true))
return false;
if (strcmp (token.str, "{"))
if (strcmp (map->token->str, "{"))
map_error ("ParseEntity: { not found");
if (num_entities == MAX_MAP_ENTITIES)
@ -522,11 +430,11 @@ ParseEntity (void)
num_entities++;
do {
if (!GetToken (true))
if (!Script_GetToken (map, true))
map_error ("ParseEntity: EOF without closing brace");
if (!strcmp (token.str, "}"))
if (!strcmp (map->token->str, "}"))
break;
if (!strcmp (token.str, "{"))
if (!strcmp (map->token->str, "{"))
ParseBrush ();
else
ParseEpair ();
@ -572,15 +480,16 @@ LoadMapFile (const char *filename)
buf[bytes] = 0;
Qclose (file);
script_file = filename;
StartTokenParsing (buf);
map = Script_New ();
Script_Start (map, filename, buf);
num_entities = 0;
while (ParseEntity ()) {
}
Script_Delete (map);
map = 0;
free (buf);
qprintf ("--- LoadMapFile ---\n");