Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

l_script.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 /*****************************************************************************
00024  * name:        l_script.c
00025  *
00026  * desc:        lexicographical parser
00027  *
00028  * $Archive: /MissionPack/code/botlib/l_script.c $
00029  *
00030  *****************************************************************************/
00031 
00032 //#define SCREWUP
00033 //#define BOTLIB
00034 //#define MEQCC
00035 //#define BSPC
00036 
00037 #ifdef SCREWUP
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <limits.h>
00041 #include <string.h>
00042 #include <stdarg.h>
00043 #include "l_memory.h"
00044 #include "l_script.h"
00045 
00046 typedef enum {qfalse, qtrue}    qboolean;
00047 
00048 #endif //SCREWUP
00049 
00050 #ifdef BOTLIB
00051 //include files for usage in the bot library
00052 #include "../game/q_shared.h"
00053 #include "../game/botlib.h"
00054 #include "be_interface.h"
00055 #include "l_script.h"
00056 #include "l_memory.h"
00057 #include "l_log.h"
00058 #include "l_libvar.h"
00059 #endif //BOTLIB
00060 
00061 #ifdef MEQCC
00062 //include files for usage in MrElusive's QuakeC Compiler
00063 #include "qcc.h"
00064 #include "l_script.h"
00065 #include "l_memory.h"
00066 #include "l_log.h"
00067 
00068 #define qtrue   true
00069 #define qfalse  false
00070 #endif //MEQCC
00071 
00072 #ifdef BSPC
00073 //include files for usage in the BSP Converter
00074 #include "../bspc/qbsp.h"
00075 #include "../bspc/l_log.h"
00076 #include "../bspc/l_mem.h"
00077 
00078 #define qtrue   true
00079 #define qfalse  false
00080 #endif //BSPC
00081 
00082 
00083 #define PUNCTABLE
00084 
00085 //longer punctuations first
00086 punctuation_t default_punctuations[] =
00087 {
00088     //binary operators
00089     {">>=",P_RSHIFT_ASSIGN, NULL},
00090     {"<<=",P_LSHIFT_ASSIGN, NULL},
00091     //
00092     {"...",P_PARMS, NULL},
00093     //define merge operator
00094     {"##",P_PRECOMPMERGE, NULL},
00095     //logic operators
00096     {"&&",P_LOGIC_AND, NULL},
00097     {"||",P_LOGIC_OR, NULL},
00098     {">=",P_LOGIC_GEQ, NULL},
00099     {"<=",P_LOGIC_LEQ, NULL},
00100     {"==",P_LOGIC_EQ, NULL},
00101     {"!=",P_LOGIC_UNEQ, NULL},
00102     //arithmatic operators
00103     {"*=",P_MUL_ASSIGN, NULL},
00104     {"/=",P_DIV_ASSIGN, NULL},
00105     {"%=",P_MOD_ASSIGN, NULL},
00106     {"+=",P_ADD_ASSIGN, NULL},
00107     {"-=",P_SUB_ASSIGN, NULL},
00108     {"++",P_INC, NULL},
00109     {"--",P_DEC, NULL},
00110     //binary operators
00111     {"&=",P_BIN_AND_ASSIGN, NULL},
00112     {"|=",P_BIN_OR_ASSIGN, NULL},
00113     {"^=",P_BIN_XOR_ASSIGN, NULL},
00114     {">>",P_RSHIFT, NULL},
00115     {"<<",P_LSHIFT, NULL},
00116     //reference operators
00117     {"->",P_POINTERREF, NULL},
00118     //C++
00119     {"::",P_CPP1, NULL},
00120     {".*",P_CPP2, NULL},
00121     //arithmatic operators
00122     {"*",P_MUL, NULL},
00123     {"/",P_DIV, NULL},
00124     {"%",P_MOD, NULL},
00125     {"+",P_ADD, NULL},
00126     {"-",P_SUB, NULL},
00127     {"=",P_ASSIGN, NULL},
00128     //binary operators
00129     {"&",P_BIN_AND, NULL},
00130     {"|",P_BIN_OR, NULL},
00131     {"^",P_BIN_XOR, NULL},
00132     {"~",P_BIN_NOT, NULL},
00133     //logic operators
00134     {"!",P_LOGIC_NOT, NULL},
00135     {">",P_LOGIC_GREATER, NULL},
00136     {"<",P_LOGIC_LESS, NULL},
00137     //reference operator
00138     {".",P_REF, NULL},
00139     //seperators
00140     {",",P_COMMA, NULL},
00141     {";",P_SEMICOLON, NULL},
00142     //label indication
00143     {":",P_COLON, NULL},
00144     //if statement
00145     {"?",P_QUESTIONMARK, NULL},
00146     //embracements
00147     {"(",P_PARENTHESESOPEN, NULL},
00148     {")",P_PARENTHESESCLOSE, NULL},
00149     {"{",P_BRACEOPEN, NULL},
00150     {"}",P_BRACECLOSE, NULL},
00151     {"[",P_SQBRACKETOPEN, NULL},
00152     {"]",P_SQBRACKETCLOSE, NULL},
00153     //
00154     {"\\",P_BACKSLASH, NULL},
00155     //precompiler operator
00156     {"#",P_PRECOMP, NULL},
00157 #ifdef DOLLAR
00158     {"$",P_DOLLAR, NULL},
00159 #endif //DOLLAR
00160     {NULL, 0}
00161 };
00162 
00163 #ifdef BSPC
00164 char basefolder[MAX_PATH];
00165 #else
00166 char basefolder[MAX_QPATH];
00167 #endif
00168 
00169 //===========================================================================
00170 //
00171 // Parameter:               -
00172 // Returns:                 -
00173 // Changes Globals:     -
00174 //===========================================================================
00175 void PS_CreatePunctuationTable(script_t *script, punctuation_t *punctuations)
00176 {
00177     int i;
00178     punctuation_t *p, *lastp, *newp;
00179 
00180     //get memory for the table
00181     if (!script->punctuationtable) script->punctuationtable = (punctuation_t **)
00182                                                 GetMemory(256 * sizeof(punctuation_t *));
00183     Com_Memset(script->punctuationtable, 0, 256 * sizeof(punctuation_t *));
00184     //add the punctuations in the list to the punctuation table
00185     for (i = 0; punctuations[i].p; i++)
00186     {
00187         newp = &punctuations[i];
00188         lastp = NULL;
00189         //sort the punctuations in this table entry on length (longer punctuations first)
00190         for (p = script->punctuationtable[(unsigned int) newp->p[0]]; p; p = p->next)
00191         {
00192             if (strlen(p->p) < strlen(newp->p))
00193             {
00194                 newp->next = p;
00195                 if (lastp) lastp->next = newp;
00196                 else script->punctuationtable[(unsigned int) newp->p[0]] = newp;
00197                 break;
00198             } //end if
00199             lastp = p;
00200         } //end for
00201         if (!p)
00202         {
00203             newp->next = NULL;
00204             if (lastp) lastp->next = newp;
00205             else script->punctuationtable[(unsigned int) newp->p[0]] = newp;
00206         } //end if
00207     } //end for
00208 } //end of the function PS_CreatePunctuationTable
00209 //===========================================================================
00210 //
00211 // Parameter:               -
00212 // Returns:                 -
00213 // Changes Globals:     -
00214 //===========================================================================
00215 char *PunctuationFromNum(script_t *script, int num)
00216 {
00217     int i;
00218 
00219     for (i = 0; script->punctuations[i].p; i++)
00220     {
00221         if (script->punctuations[i].n == num) return script->punctuations[i].p;
00222     } //end for
00223     return "unkown punctuation";
00224 } //end of the function PunctuationFromNum
00225 //===========================================================================
00226 //
00227 // Parameter:               -
00228 // Returns:                 -
00229 // Changes Globals:     -
00230 //===========================================================================
00231 void QDECL ScriptError(script_t *script, char *str, ...)
00232 {
00233     char text[1024];
00234     va_list ap;
00235 
00236     if (script->flags & SCFL_NOERRORS) return;
00237 
00238     va_start(ap, str);
00239     vsprintf(text, str, ap);
00240     va_end(ap);
00241 #ifdef BOTLIB
00242     botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", script->filename, script->line, text);
00243 #endif //BOTLIB
00244 #ifdef MEQCC
00245     printf("error: file %s, line %d: %s\n", script->filename, script->line, text);
00246 #endif //MEQCC
00247 #ifdef BSPC
00248     Log_Print("error: file %s, line %d: %s\n", script->filename, script->line, text);
00249 #endif //BSPC
00250 } //end of the function ScriptError
00251 //===========================================================================
00252 //
00253 // Parameter:               -
00254 // Returns:                 -
00255 // Changes Globals:     -
00256 //===========================================================================
00257 void QDECL ScriptWarning(script_t *script, char *str, ...)
00258 {
00259     char text[1024];
00260     va_list ap;
00261 
00262     if (script->flags & SCFL_NOWARNINGS) return;
00263 
00264     va_start(ap, str);
00265     vsprintf(text, str, ap);
00266     va_end(ap);
00267 #ifdef BOTLIB
00268     botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", script->filename, script->line, text);
00269 #endif //BOTLIB
00270 #ifdef MEQCC
00271     printf("warning: file %s, line %d: %s\n", script->filename, script->line, text);
00272 #endif //MEQCC
00273 #ifdef BSPC
00274     Log_Print("warning: file %s, line %d: %s\n", script->filename, script->line, text);
00275 #endif //BSPC
00276 } //end of the function ScriptWarning
00277 //===========================================================================
00278 //
00279 // Parameter:               -
00280 // Returns:                 -
00281 // Changes Globals:     -
00282 //===========================================================================
00283 void SetScriptPunctuations(script_t *script, punctuation_t *p)
00284 {
00285 #ifdef PUNCTABLE
00286     if (p) PS_CreatePunctuationTable(script, p);
00287     else  PS_CreatePunctuationTable(script, default_punctuations);
00288 #endif //PUNCTABLE
00289     if (p) script->punctuations = p;
00290     else script->punctuations = default_punctuations;
00291 } //end of the function SetScriptPunctuations
00292 //============================================================================
00293 // Reads spaces, tabs, C-like comments etc.
00294 // When a newline character is found the scripts line counter is increased.
00295 //
00296 // Parameter:               -
00297 // Returns:                 -
00298 // Changes Globals:     -
00299 //============================================================================
00300 int PS_ReadWhiteSpace(script_t *script)
00301 {
00302     while(1)
00303     {
00304         //skip white space
00305         while(*script->script_p <= ' ')
00306         {
00307             if (!*script->script_p) return 0;
00308             if (*script->script_p == '\n') script->line++;
00309             script->script_p++;
00310         } //end while
00311         //skip comments
00312         if (*script->script_p == '/')
00313         {
00314             //comments //
00315             if (*(script->script_p+1) == '/')
00316             {
00317                 script->script_p++;
00318                 do
00319                 {
00320                     script->script_p++;
00321                     if (!*script->script_p) return 0;
00322                 } //end do
00323                 while(*script->script_p != '\n');
00324                 script->line++;
00325                 script->script_p++;
00326                 if (!*script->script_p) return 0;
00327                 continue;
00328             } //end if
00329             //comments /* */
00330             else if (*(script->script_p+1) == '*')
00331             {
00332                 script->script_p++;
00333                 do
00334                 {
00335                     script->script_p++;
00336                     if (!*script->script_p) return 0;
00337                     if (*script->script_p == '\n') script->line++;
00338                 } //end do
00339                 while(!(*script->script_p == '*' && *(script->script_p+1) == '/'));
00340                 script->script_p++;
00341                 if (!*script->script_p) return 0;
00342                 script->script_p++;
00343                 if (!*script->script_p) return 0;
00344                 continue;
00345             } //end if
00346         } //end if
00347         break;
00348     } //end while
00349     return 1;
00350 } //end of the function PS_ReadWhiteSpace
00351 //============================================================================
00352 // Reads an escape character.
00353 //
00354 // Parameter:               script      : script to read from
00355 //                              ch              : place to store the read escape character
00356 // Returns:                 -
00357 // Changes Globals:     -
00358 //============================================================================
00359 int PS_ReadEscapeCharacter(script_t *script, char *ch)
00360 {
00361     int c, val, i;
00362 
00363     //step over the leading '\\'
00364     script->script_p++;
00365     //determine the escape character
00366     switch(*script->script_p)
00367     {
00368         case '\\': c = '\\'; break;
00369         case 'n': c = '\n'; break;
00370         case 'r': c = '\r'; break;
00371         case 't': c = '\t'; break;
00372         case 'v': c = '\v'; break;
00373         case 'b': c = '\b'; break;
00374         case 'f': c = '\f'; break;
00375         case 'a': c = '\a'; break;
00376         case '\'': c = '\''; break;
00377         case '\"': c = '\"'; break;
00378         case '\?': c = '\?'; break;
00379         case 'x':
00380         {
00381             script->script_p++;
00382             for (i = 0, val = 0; ; i++, script->script_p++)
00383             {
00384                 c = *script->script_p;
00385                 if (c >= '0' && c <= '9') c = c - '0';
00386                 else if (c >= 'A' && c <= 'Z') c = c - 'A' + 10;
00387                 else if (c >= 'a' && c <= 'z') c = c - 'a' + 10;
00388                 else break;
00389                 val = (val << 4) + c;
00390             } //end for
00391             script->script_p--;
00392             if (val > 0xFF)
00393             {
00394                 ScriptWarning(script, "too large value in escape character");
00395                 val = 0xFF;
00396             } //end if
00397             c = val;
00398             break;
00399         } //end case
00400         default: //NOTE: decimal ASCII code, NOT octal
00401         {
00402             if (*script->script_p < '0' || *script->script_p > '9') ScriptError(script, "unknown escape char");
00403             for (i = 0, val = 0; ; i++, script->script_p++)
00404             {
00405                 c = *script->script_p;
00406                 if (c >= '0' && c <= '9') c = c - '0';
00407                 else break;
00408                 val = val * 10 + c;
00409             } //end for
00410             script->script_p--;
00411             if (val > 0xFF)
00412             {
00413                 ScriptWarning(script, "too large value in escape character");
00414                 val = 0xFF;
00415             } //end if
00416             c = val;
00417             break;
00418         } //end default
00419     } //end switch
00420     //step over the escape character or the last digit of the number
00421     script->script_p++;
00422     //store the escape character
00423     *ch = c;
00424     //succesfully read escape character
00425     return 1;
00426 } //end of the function PS_ReadEscapeCharacter
00427 //============================================================================
00428 // Reads C-like string. Escape characters are interpretted.
00429 // Quotes are included with the string.
00430 // Reads two strings with a white space between them as one string.
00431 //
00432 // Parameter:               script      : script to read from
00433 //                              token           : buffer to store the string
00434 // Returns:                 qtrue when a string was read succesfully
00435 // Changes Globals:     -
00436 //============================================================================
00437 int PS_ReadString(script_t *script, token_t *token, int quote)
00438 {
00439     int len, tmpline;
00440     char *tmpscript_p;
00441 
00442     if (quote == '\"') token->type = TT_STRING;
00443     else token->type = TT_LITERAL;
00444 
00445     len = 0;
00446     //leading quote
00447     token->string[len++] = *script->script_p++;
00448     //
00449     while(1)
00450     {
00451         //minus 2 because trailing double quote and zero have to be appended
00452         if (len >= MAX_TOKEN - 2)
00453         {
00454             ScriptError(script, "string longer than MAX_TOKEN = %d", MAX_TOKEN);
00455             return 0;
00456         } //end if
00457         //if there is an escape character and
00458         //if escape characters inside a string are allowed
00459         if (*script->script_p == '\\' && !(script->flags & SCFL_NOSTRINGESCAPECHARS))
00460         {
00461             if (!PS_ReadEscapeCharacter(script, &token->string[len]))
00462             {
00463                 token->string[len] = 0;
00464                 return 0;
00465             } //end if
00466             len++;
00467         } //end if
00468         //if a trailing quote
00469         else if (*script->script_p == quote)
00470         {
00471             //step over the double quote
00472             script->script_p++;
00473             //if white spaces in a string are not allowed
00474             if (script->flags & SCFL_NOSTRINGWHITESPACES) break;
00475             //
00476             tmpscript_p = script->script_p;
00477             tmpline = script->line;
00478             //read unusefull stuff between possible two following strings
00479             if (!PS_ReadWhiteSpace(script))
00480             {
00481                 script->script_p = tmpscript_p;
00482                 script->line = tmpline;
00483                 break;
00484             } //end if
00485             //if there's no leading double qoute
00486             if (*script->script_p != quote)
00487             {
00488                 script->script_p = tmpscript_p;
00489                 script->line = tmpline;
00490                 break;
00491             } //end if
00492             //step over the new leading double quote
00493             script->script_p++;
00494         } //end if
00495         else
00496         {
00497             if (*script->script_p == '\0')
00498             {
00499                 token->string[len] = 0;
00500                 ScriptError(script, "missing trailing quote");
00501                 return 0;
00502             } //end if
00503           if (*script->script_p == '\n')
00504             {
00505                 token->string[len] = 0;
00506                 ScriptError(script, "newline inside string %s", token->string);
00507                 return 0;
00508             } //end if
00509             token->string[len++] = *script->script_p++;
00510         } //end else
00511     } //end while
00512     //trailing quote
00513     token->string[len++] = quote;
00514     //end string with a zero
00515     token->string[len] = '\0';
00516     //the sub type is the length of the string
00517     token->subtype = len;
00518     return 1;
00519 } //end of the function PS_ReadString
00520 //============================================================================
00521 //
00522 // Parameter:               -
00523 // Returns:                 -
00524 // Changes Globals:     -
00525 //============================================================================
00526 int PS_ReadName(script_t *script, token_t *token)
00527 {
00528     int len = 0;
00529     char c;
00530 
00531     token->type = TT_NAME;
00532     do
00533     {
00534         token->string[len++] = *script->script_p++;
00535         if (len >= MAX_TOKEN)
00536         {
00537             ScriptError(script, "name longer than MAX_TOKEN = %d", MAX_TOKEN);
00538             return 0;
00539         } //end if
00540         c = *script->script_p;
00541    } while ((c >= 'a' && c <= 'z') ||
00542                 (c >= 'A' && c <= 'Z') ||
00543                 (c >= '0' && c <= '9') ||
00544                 c == '_');
00545     token->string[len] = '\0';
00546     //the sub type is the length of the name
00547     token->subtype = len;
00548     return 1;
00549 } //end of the function PS_ReadName
00550 //============================================================================
00551 //
00552 // Parameter:               -
00553 // Returns:                 -
00554 // Changes Globals:     -
00555 //============================================================================
00556 void NumberValue(char *string, int subtype, unsigned long int *intvalue,
00557                                                             long double *floatvalue)
00558 {
00559     unsigned long int dotfound = 0;
00560 
00561     *intvalue = 0;
00562     *floatvalue = 0;
00563     //floating point number
00564     if (subtype & TT_FLOAT)
00565     {
00566         while(*string)
00567         {
00568             if (*string == '.')
00569             {
00570                 if (dotfound) return;
00571                 dotfound = 10;
00572                 string++;
00573             } //end if
00574             if (dotfound)
00575             {
00576                 *floatvalue = *floatvalue + (long double) (*string - '0') /
00577                                                                     (long double) dotfound;
00578                 dotfound *= 10;
00579             } //end if
00580             else
00581             {
00582                 *floatvalue = *floatvalue * 10.0 + (long double) (*string - '0');
00583             } //end else
00584             string++;
00585         } //end while
00586         *intvalue = (unsigned long) *floatvalue;
00587     } //end if
00588     else if (subtype & TT_DECIMAL)
00589     {
00590         while(*string) *intvalue = *intvalue * 10 + (*string++ - '0');
00591         *floatvalue = *intvalue;
00592     } //end else if
00593     else if (subtype & TT_HEX)
00594     {
00595         //step over the leading 0x or 0X
00596         string += 2;
00597         while(*string)
00598         {
00599             *intvalue <<= 4;
00600             if (*string >= 'a' && *string <= 'f') *intvalue += *string - 'a' + 10;
00601             else if (*string >= 'A' && *string <= 'F') *intvalue += *string - 'A' + 10;
00602             else *intvalue += *string - '0';
00603             string++;
00604         } //end while
00605         *floatvalue = *intvalue;
00606     } //end else if
00607     else if (subtype & TT_OCTAL)
00608     {
00609         //step over the first zero
00610         string += 1;
00611         while(*string) *intvalue = (*intvalue << 3) + (*string++ - '0');
00612         *floatvalue = *intvalue;
00613     } //end else if
00614     else if (subtype & TT_BINARY)
00615     {
00616         //step over the leading 0b or 0B
00617         string += 2;
00618         while(*string) *intvalue = (*intvalue << 1) + (*string++ - '0');
00619         *floatvalue = *intvalue;
00620     } //end else if
00621 } //end of the function NumberValue
00622 //============================================================================
00623 //
00624 // Parameter:               -
00625 // Returns:                 -
00626 // Changes Globals:     -
00627 //============================================================================
00628 int PS_ReadNumber(script_t *script, token_t *token)
00629 {
00630     int len = 0, i;
00631     int octal, dot;
00632     char c;
00633 //  unsigned long int intvalue = 0;
00634 //  long double floatvalue = 0;
00635 
00636     token->type = TT_NUMBER;
00637     //check for a hexadecimal number
00638     if (*script->script_p == '0' &&
00639         (*(script->script_p + 1) == 'x' ||
00640         *(script->script_p + 1) == 'X'))
00641     {
00642         token->string[len++] = *script->script_p++;
00643         token->string[len++] = *script->script_p++;
00644         c = *script->script_p;
00645         //hexadecimal
00646         while((c >= '0' && c <= '9') ||
00647                     (c >= 'a' && c <= 'f') ||
00648                     (c >= 'A' && c <= 'A'))
00649         {
00650             token->string[len++] = *script->script_p++;
00651             if (len >= MAX_TOKEN)
00652             {
00653                 ScriptError(script, "hexadecimal number longer than MAX_TOKEN = %d", MAX_TOKEN);
00654                 return 0;
00655             } //end if
00656             c = *script->script_p;
00657         } //end while
00658         token->subtype |= TT_HEX;
00659     } //end if
00660 #ifdef BINARYNUMBERS
00661     //check for a binary number
00662     else if (*script->script_p == '0' &&
00663         (*(script->script_p + 1) == 'b' ||
00664         *(script->script_p + 1) == 'B'))
00665     {
00666         token->string[len++] = *script->script_p++;
00667         token->string[len++] = *script->script_p++;
00668         c = *script->script_p;
00669         //binary
00670         while(c == '0' || c == '1')
00671         {
00672             token->string[len++] = *script->script_p++;
00673             if (len >= MAX_TOKEN)
00674             {
00675                 ScriptError(script, "binary number longer than MAX_TOKEN = %d", MAX_TOKEN);
00676                 return 0;
00677             } //end if
00678             c = *script->script_p;
00679         } //end while
00680         token->subtype |= TT_BINARY;
00681     } //end if
00682 #endif //BINARYNUMBERS
00683     else //decimal or octal integer or floating point number
00684     {
00685         octal = qfalse;
00686         dot = qfalse;
00687         if (*script->script_p == '0') octal = qtrue;
00688         while(1)
00689         {
00690             c = *script->script_p;
00691             if (c == '.') dot = qtrue;
00692             else if (c == '8' || c == '9') octal = qfalse;
00693             else if (c < '0' || c > '9') break;
00694             token->string[len++] = *script->script_p++;
00695             if (len >= MAX_TOKEN - 1)
00696             {
00697                 ScriptError(script, "number longer than MAX_TOKEN = %d", MAX_TOKEN);
00698                 return 0;
00699             } //end if
00700         } //end while
00701         if (octal) token->subtype |= TT_OCTAL;
00702         else token->subtype |= TT_DECIMAL;
00703         if (dot) token->subtype |= TT_FLOAT;
00704     } //end else
00705     for (i = 0; i < 2; i++)
00706     {
00707         c = *script->script_p;
00708         //check for a LONG number
00709         if ( (c == 'l' || c == 'L') // bk001204 - brackets 
00710              && !(token->subtype & TT_LONG))
00711         {
00712             script->script_p++;
00713             token->subtype |= TT_LONG;
00714         } //end if
00715         //check for an UNSIGNED number
00716         else if ( (c == 'u' || c == 'U') // bk001204 - brackets 
00717               && !(token->subtype & (TT_UNSIGNED | TT_FLOAT)))
00718         {
00719             script->script_p++;
00720             token->subtype |= TT_UNSIGNED;
00721         } //end if
00722     } //end for
00723     token->string[len] = '\0';
00724 #ifdef NUMBERVALUE
00725     NumberValue(token->string, token->subtype, &token->intvalue, &token->floatvalue);
00726 #endif //NUMBERVALUE
00727     if (!(token->subtype & TT_FLOAT)) token->subtype |= TT_INTEGER;
00728     return 1;
00729 } //end of the function PS_ReadNumber
00730 //============================================================================
00731 //
00732 // Parameter:               -
00733 // Returns:                 -
00734 // Changes Globals:     -
00735 //============================================================================
00736 int PS_ReadLiteral(script_t *script, token_t *token)
00737 {
00738     token->type = TT_LITERAL;
00739     //first quote
00740     token->string[0] = *script->script_p++;
00741     //check for end of file
00742     if (!*script->script_p)
00743     {
00744         ScriptError(script, "end of file before trailing \'");
00745         return 0;
00746     } //end if
00747     //if it is an escape character
00748     if (*script->script_p == '\\')
00749     {
00750         if (!PS_ReadEscapeCharacter(script, &token->string[1])) return 0;
00751     } //end if
00752     else
00753     {
00754         token->string[1] = *script->script_p++;
00755     } //end else
00756     //check for trailing quote
00757     if (*script->script_p != '\'')
00758     {
00759         ScriptWarning(script, "too many characters in literal, ignored");
00760         while(*script->script_p &&
00761                 *script->script_p != '\'' &&
00762                 *script->script_p != '\n')
00763         {
00764             script->script_p++;
00765         } //end while
00766         if (*script->script_p == '\'') script->script_p++;
00767     } //end if
00768     //store the trailing quote
00769     token->string[2] = *script->script_p++;
00770     //store trailing zero to end the string
00771     token->string[3] = '\0';
00772     //the sub type is the integer literal value
00773     token->subtype = token->string[1];
00774     //
00775     return 1;
00776 } //end of the function PS_ReadLiteral
00777 //============================================================================
00778 //
00779 // Parameter:               -
00780 // Returns:                 -
00781 // Changes Globals:     -
00782 //============================================================================
00783 int PS_ReadPunctuation(script_t *script, token_t *token)
00784 {
00785     int len;
00786     char *p;
00787     punctuation_t *punc;
00788 
00789 #ifdef PUNCTABLE
00790     for (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next)
00791     {
00792 #else
00793     int i;
00794 
00795     for (i = 0; script->punctuations[i].p; i++)
00796     {
00797         punc = &script->punctuations[i];
00798 #endif //PUNCTABLE
00799         p = punc->p;
00800         len = strlen(p);
00801         //if the script contains at least as much characters as the punctuation
00802         if (script->script_p + len <= script->end_p)
00803         {
00804             //if the script contains the punctuation
00805             if (!strncmp(script->script_p, p, len))
00806             {
00807                 strncpy(token->string, p, MAX_TOKEN);
00808                 script->script_p += len;
00809                 token->type = TT_PUNCTUATION;
00810                 //sub type is the number of the punctuation
00811                 token->subtype = punc->n;
00812                 return 1;
00813             } //end if
00814         } //end if
00815     } //end for
00816     return 0;
00817 } //end of the function PS_ReadPunctuation
00818 //============================================================================
00819 //
00820 // Parameter:               -
00821 // Returns:                 -
00822 // Changes Globals:     -
00823 //============================================================================
00824 int PS_ReadPrimitive(script_t *script, token_t *token)
00825 {
00826     int len;
00827 
00828     len = 0;
00829     while(*script->script_p > ' ' && *script->script_p != ';')
00830     {
00831         if (len >= MAX_TOKEN)
00832         {
00833             ScriptError(script, "primitive token longer than MAX_TOKEN = %d", MAX_TOKEN);
00834             return 0;
00835         } //end if
00836         token->string[len++] = *script->script_p++;
00837     } //end while
00838     token->string[len] = 0;
00839     //copy the token into the script structure
00840     Com_Memcpy(&script->token, token, sizeof(token_t));
00841     //primitive reading successfull
00842     return 1;
00843 } //end of the function PS_ReadPrimitive
00844 //============================================================================
00845 //
00846 // Parameter:               -
00847 // Returns:                 -
00848 // Changes Globals:     -
00849 //============================================================================
00850 int PS_ReadToken(script_t *script, token_t *token)
00851 {
00852     //if there is a token available (from UnreadToken)
00853     if (script->tokenavailable)
00854     {
00855         script->tokenavailable = 0;
00856         Com_Memcpy(token, &script->token, sizeof(token_t));
00857         return 1;
00858     } //end if
00859     //save script pointer
00860     script->lastscript_p = script->script_p;
00861     //save line counter
00862     script->lastline = script->line;
00863     //clear the token stuff
00864     Com_Memset(token, 0, sizeof(token_t));
00865     //start of the white space
00866     script->whitespace_p = script->script_p;
00867     token->whitespace_p = script->script_p;
00868     //read unusefull stuff
00869     if (!PS_ReadWhiteSpace(script)) return 0;
00870     //end of the white space
00871     script->endwhitespace_p = script->script_p;
00872     token->endwhitespace_p = script->script_p;
00873     //line the token is on
00874     token->line = script->line;
00875     //number of lines crossed before token
00876     token->linescrossed = script->line - script->lastline;
00877     //if there is a leading double quote
00878     if (*script->script_p == '\"')
00879     {
00880         if (!PS_ReadString(script, token, '\"')) return 0;
00881     } //end if
00882     //if an literal
00883     else if (*script->script_p == '\'')
00884     {
00885         //if (!PS_ReadLiteral(script, token)) return 0;
00886         if (!PS_ReadString(script, token, '\'')) return 0;
00887     } //end if
00888     //if there is a number
00889     else if ((*script->script_p >= '0' && *script->script_p <= '9') ||
00890                 (*script->script_p == '.' &&
00891                 (*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9')))
00892     {
00893         if (!PS_ReadNumber(script, token)) return 0;
00894     } //end if
00895     //if this is a primitive script
00896     else if (script->flags & SCFL_PRIMITIVE)
00897     {
00898         return PS_ReadPrimitive(script, token);
00899     } //end else if
00900     //if there is a name
00901     else if ((*script->script_p >= 'a' && *script->script_p <= 'z') ||
00902         (*script->script_p >= 'A' && *script->script_p <= 'Z') ||
00903         *script->script_p == '_')
00904     {
00905         if (!PS_ReadName(script, token)) return 0;
00906     } //end if
00907     //check for punctuations
00908     else if (!PS_ReadPunctuation(script, token))
00909     {
00910         ScriptError(script, "can't read token");
00911         return 0;
00912     } //end if
00913     //copy the token into the script structure
00914     Com_Memcpy(&script->token, token, sizeof(token_t));
00915     //succesfully read a token
00916     return 1;
00917 } //end of the function PS_ReadToken
00918 //============================================================================
00919 //
00920 // Parameter:               -
00921 // Returns:                 -
00922 // Changes Globals:     -
00923 //============================================================================
00924 int PS_ExpectTokenString(script_t *script, char *string)
00925 {
00926     token_t token;
00927 
00928     if (!PS_ReadToken(script, &token))
00929     {
00930         ScriptError(script, "couldn't find expected %s", string);
00931         return 0;
00932     } //end if
00933 
00934     if (strcmp(token.string, string))
00935     {
00936         ScriptError(script, "expected %s, found %s", string, token.string);
00937         return 0;
00938     } //end if
00939     return 1;
00940 } //end of the function PS_ExpectToken
00941 //============================================================================
00942 //
00943 // Parameter:               -
00944 // Returns:                 -
00945 // Changes Globals:     -
00946 //============================================================================
00947 int PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token)
00948 {
00949     char str[MAX_TOKEN];
00950 
00951     if (!PS_ReadToken(script, token))
00952     {
00953         ScriptError(script, "couldn't read expected token");
00954         return 0;
00955     } //end if
00956 
00957     if (token->type != type)
00958     {
00959         if (type == TT_STRING) strcpy(str, "string");
00960         if (type == TT_LITERAL) strcpy(str, "literal");
00961         if (type == TT_NUMBER) strcpy(str, "number");
00962         if (type == TT_NAME) strcpy(str, "name");
00963         if (type == TT_PUNCTUATION) strcpy(str, "punctuation");
00964         ScriptError(script, "expected a %s, found %s", str, token->string);
00965         return 0;
00966     } //end if
00967     if (token->type == TT_NUMBER)
00968     {
00969         if ((token->subtype & subtype) != subtype)
00970         {
00971             if (subtype & TT_DECIMAL) strcpy(str, "decimal");
00972             if (subtype & TT_HEX) strcpy(str, "hex");
00973             if (subtype & TT_OCTAL) strcpy(str, "octal");
00974             if (subtype & TT_BINARY) strcpy(str, "binary");
00975             if (subtype & TT_LONG) strcat(str, " long");
00976             if (subtype & TT_UNSIGNED) strcat(str, " unsigned");
00977             if (subtype & TT_FLOAT) strcat(str, " float");
00978             if (subtype & TT_INTEGER) strcat(str, " integer");
00979             ScriptError(script, "expected %s, found %s", str, token->string);
00980             return 0;
00981         } //end if
00982     } //end if
00983     else if (token->type == TT_PUNCTUATION)
00984     {
00985         if (subtype < 0)
00986         {
00987             ScriptError(script, "BUG: wrong punctuation subtype");
00988             return 0;
00989         } //end if
00990         if (token->subtype != subtype)
00991         {
00992             ScriptError(script, "expected %s, found %s",
00993                             script->punctuations[subtype], token->string);
00994             return 0;
00995         } //end if
00996     } //end else if
00997     return 1;
00998 } //end of the function PS_ExpectTokenType
00999 //============================================================================
01000 //
01001 // Parameter:               -
01002 // Returns:                 -
01003 // Changes Globals:     -
01004 //============================================================================
01005 int PS_ExpectAnyToken(script_t *script, token_t *token)
01006 {
01007     if (!PS_ReadToken(script, token))
01008     {
01009         ScriptError(script, "couldn't read expected token");
01010         return 0;
01011     } //end if
01012     else
01013     {
01014         return 1;
01015     } //end else
01016 } //end of the function PS_ExpectAnyToken
01017 //============================================================================
01018 //
01019 // Parameter:               -
01020 // Returns:                 -
01021 // Changes Globals:     -
01022 //============================================================================
01023 int PS_CheckTokenString(script_t *script, char *string)
01024 {
01025     token_t tok;
01026 
01027     if (!PS_ReadToken(script, &tok)) return 0;
01028     //if the token is available
01029     if (!strcmp(tok.string, string)) return 1;
01030     //token not available
01031     script->script_p = script->lastscript_p;
01032     return 0;
01033 } //end of the function PS_CheckTokenString
01034 //============================================================================
01035 //
01036 // Parameter:               -
01037 // Returns:                 -
01038 // Changes Globals:     -
01039 //============================================================================
01040 int PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token)
01041 {
01042     token_t tok;
01043 
01044     if (!PS_ReadToken(script, &tok)) return 0;
01045     //if the type matches
01046     if (tok.type == type &&
01047             (tok.subtype & subtype) == subtype)
01048     {
01049         Com_Memcpy(token, &tok, sizeof(token_t));
01050         return 1;
01051     } //end if
01052     //token is not available
01053     script->script_p = script->lastscript_p;
01054     return 0;
01055 } //end of the function PS_CheckTokenType
01056 //============================================================================
01057 //
01058 // Parameter:               -
01059 // Returns:                 -
01060 // Changes Globals:     -
01061 //============================================================================
01062 int PS_SkipUntilString(script_t *script, char *string)
01063 {
01064     token_t token;
01065 
01066     while(PS_ReadToken(script, &token))
01067     {
01068         if (!strcmp(token.string, string)) return 1;
01069     } //end while
01070     return 0;
01071 } //end of the function PS_SkipUntilString
01072 //============================================================================
01073 //
01074 // Parameter:               -
01075 // Returns:                 -
01076 // Changes Globals:     -
01077 //============================================================================
01078 void PS_UnreadLastToken(script_t *script)
01079 {
01080     script->tokenavailable = 1;
01081 } //end of the function UnreadLastToken
01082 //============================================================================
01083 //
01084 // Parameter:               -
01085 // Returns:                 -
01086 // Changes Globals:     -
01087 //============================================================================
01088 void PS_UnreadToken(script_t *script, token_t *token)
01089 {
01090     Com_Memcpy(&script->token, token, sizeof(token_t));
01091     script->tokenavailable = 1;
01092 } //end of the function UnreadToken
01093 //============================================================================
01094 // returns the next character of the read white space, returns NULL if none
01095 //
01096 // Parameter:               -
01097 // Returns:                 -
01098 // Changes Globals:     -
01099 //============================================================================
01100 char PS_NextWhiteSpaceChar(script_t *script)
01101 {
01102     if (script->whitespace_p != script->endwhitespace_p)
01103     {
01104         return *script->whitespace_p++;
01105     } //end if
01106     else
01107     {
01108         return 0;
01109     } //end else
01110 } //end of the function PS_NextWhiteSpaceChar
01111 //============================================================================
01112 //
01113 // Parameter:               -
01114 // Returns:                 -
01115 // Changes Globals:     -
01116 //============================================================================
01117 void StripDoubleQuotes(char *string)
01118 {
01119     if (*string == '\"')
01120     {
01121         strcpy(string, string+1);
01122     } //end if
01123     if (string[strlen(string)-1] == '\"')
01124     {
01125         string[strlen(string)-1] = '\0';
01126     } //end if
01127 } //end of the function StripDoubleQuotes
01128 //============================================================================
01129 //
01130 // Parameter:               -
01131 // Returns:                 -
01132 // Changes Globals:     -
01133 //============================================================================
01134 void StripSingleQuotes(char *string)
01135 {
01136     if (*string == '\'')
01137     {
01138         strcpy(string, string+1);
01139     } //end if
01140     if (string[strlen(string)-1] == '\'')
01141     {
01142         string[strlen(string)-1] = '\0';
01143     } //end if
01144 } //end of the function StripSingleQuotes
01145 //============================================================================
01146 //
01147 // Parameter:               -
01148 // Returns:                 -
01149 // Changes Globals:     -
01150 //============================================================================
01151 long double ReadSignedFloat(script_t *script)
01152 {
01153     token_t token;
01154     long double sign = 1;
01155 
01156     PS_ExpectAnyToken(script, &token);
01157     if (!strcmp(token.string, "-"))
01158     {
01159         sign = -1;
01160         PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
01161     } //end if
01162     else if (token.type != TT_NUMBER)
01163     {
01164         ScriptError(script, "expected float value, found %s\n", token.string);
01165     } //end else if
01166     return sign * token.floatvalue;
01167 } //end of the function ReadSignedFloat
01168 //============================================================================
01169 //
01170 // Parameter:               -
01171 // Returns:                 -
01172 // Changes Globals:     -
01173 //============================================================================
01174 signed long int ReadSignedInt(script_t *script)
01175 {
01176     token_t token;
01177     signed long int sign = 1;
01178 
01179     PS_ExpectAnyToken(script, &token);
01180     if (!strcmp(token.string, "-"))
01181     {
01182         sign = -1;
01183         PS_ExpectTokenType(script, TT_NUMBER, TT_INTEGER, &token);
01184     } //end if
01185     else if (token.type != TT_NUMBER || token.subtype == TT_FLOAT)
01186     {
01187         ScriptError(script, "expected integer value, found %s\n", token.string);
01188     } //end else if
01189     return sign * token.intvalue;
01190 } //end of the function ReadSignedInt
01191 //============================================================================
01192 //
01193 // Parameter:               -
01194 // Returns:                 -
01195 // Changes Globals:     -
01196 //============================================================================
01197 void SetScriptFlags(script_t *script, int flags)
01198 {
01199     script->flags = flags;
01200 } //end of the function SetScriptFlags
01201 //============================================================================
01202 //
01203 // Parameter:               -
01204 // Returns:                 -
01205 // Changes Globals:     -
01206 //============================================================================
01207 int GetScriptFlags(script_t *script)
01208 {
01209     return script->flags;
01210 } //end of the function GetScriptFlags
01211 //============================================================================
01212 //
01213 // Parameter:               -
01214 // Returns:                 -
01215 // Changes Globals:     -
01216 //============================================================================
01217 void ResetScript(script_t *script)
01218 {
01219     //pointer in script buffer
01220     script->script_p = script->buffer;
01221     //pointer in script buffer before reading token
01222     script->lastscript_p = script->buffer;
01223     //begin of white space
01224     script->whitespace_p = NULL;
01225     //end of white space
01226     script->endwhitespace_p = NULL;
01227     //set if there's a token available in script->token
01228     script->tokenavailable = 0;
01229     //
01230     script->line = 1;
01231     script->lastline = 1;
01232     //clear the saved token
01233     Com_Memset(&script->token, 0, sizeof(token_t));
01234 } //end of the function ResetScript
01235 //============================================================================
01236 // returns true if at the end of the script
01237 //
01238 // Parameter:               -
01239 // Returns:                 -
01240 // Changes Globals:     -
01241 //============================================================================
01242 int EndOfScript(script_t *script)
01243 {
01244     return script->script_p >= script->end_p;
01245 } //end of the function EndOfScript
01246 //============================================================================
01247 //
01248 // Parameter:               -
01249 // Returns:                 -
01250 // Changes Globals:     -
01251 //============================================================================
01252 int NumLinesCrossed(script_t *script)
01253 {
01254     return script->line - script->lastline;
01255 } //end of the function NumLinesCrossed
01256 //============================================================================
01257 //
01258 // Parameter:               -
01259 // Returns:                 -
01260 // Changes Globals:     -
01261 //============================================================================
01262 int ScriptSkipTo(script_t *script, char *value)
01263 {
01264     int len;
01265     char firstchar;
01266 
01267     firstchar = *value;
01268     len = strlen(value);
01269     do
01270     {
01271         if (!PS_ReadWhiteSpace(script)) return 0;
01272         if (*script->script_p == firstchar)
01273         {
01274             if (!strncmp(script->script_p, value, len))
01275             {
01276                 return 1;
01277             } //end if
01278         } //end if
01279         script->script_p++;
01280     } while(1);
01281 } //end of the function ScriptSkipTo
01282 #ifndef BOTLIB
01283 //============================================================================
01284 //
01285 // Parameter:               -
01286 // Returns:                 -
01287 // Changes Globals:     -
01288 //============================================================================
01289 int FileLength(FILE *fp)
01290 {
01291     int pos;
01292     int end;
01293 
01294     pos = ftell(fp);
01295     fseek(fp, 0, SEEK_END);
01296     end = ftell(fp);
01297     fseek(fp, pos, SEEK_SET);
01298 
01299     return end;
01300 } //end of the function FileLength
01301 #endif
01302 //============================================================================
01303 //
01304 // Parameter:               -
01305 // Returns:                 -
01306 // Changes Globals:     -
01307 //============================================================================
01308 script_t *LoadScriptFile(const char *filename)
01309 {
01310 #ifdef BOTLIB
01311     fileHandle_t fp;
01312     char pathname[MAX_QPATH];
01313 #else
01314     FILE *fp;
01315 #endif
01316     int length;
01317     void *buffer;
01318     script_t *script;
01319 
01320 #ifdef BOTLIB
01321     if (strlen(basefolder))
01322         Com_sprintf(pathname, sizeof(pathname), "%s/%s", basefolder, filename);
01323     else
01324         Com_sprintf(pathname, sizeof(pathname), "%s", filename);
01325     length = botimport.FS_FOpenFile( pathname, &fp, FS_READ );
01326     if (!fp) return NULL;
01327 #else
01328     fp = fopen(filename, "rb");
01329     if (!fp) return NULL;
01330 
01331     length = FileLength(fp);
01332 #endif
01333 
01334     buffer = GetClearedMemory(sizeof(script_t) + length + 1);
01335     script = (script_t *) buffer;
01336     Com_Memset(script, 0, sizeof(script_t));
01337     strcpy(script->filename, filename);
01338     script->buffer = (char *) buffer + sizeof(script_t);
01339     script->buffer[length] = 0;
01340     script->length = length;
01341     //pointer in script buffer
01342     script->script_p = script->buffer;
01343     //pointer in script buffer before reading token
01344     script->lastscript_p = script->buffer;
01345     //pointer to end of script buffer
01346     script->end_p = &script->buffer[length];
01347     //set if there's a token available in script->token
01348     script->tokenavailable = 0;
01349     //
01350     script->line = 1;
01351     script->lastline = 1;
01352     //
01353     SetScriptPunctuations(script, NULL);
01354     //
01355 #ifdef BOTLIB
01356     botimport.FS_Read(script->buffer, length, fp);
01357     botimport.FS_FCloseFile(fp);
01358 #else
01359     if (fread(script->buffer, length, 1, fp) != 1)
01360     {
01361         FreeMemory(buffer);
01362         script = NULL;
01363     } //end if
01364     fclose(fp);
01365 #endif
01366     //
01367     script->length = COM_Compress(script->buffer);
01368 
01369     return script;
01370 } //end of the function LoadScriptFile
01371 //============================================================================
01372 //
01373 // Parameter:           -
01374 // Returns:             -
01375 // Changes Globals:     -
01376 //============================================================================
01377 script_t *LoadScriptMemory(char *ptr, int length, char *name)
01378 {
01379     void *buffer;
01380     script_t *script;
01381 
01382     buffer = GetClearedMemory(sizeof(script_t) + length + 1);
01383     script = (script_t *) buffer;
01384     Com_Memset(script, 0, sizeof(script_t));
01385     strcpy(script->filename, name);
01386     script->buffer = (char *) buffer + sizeof(script_t);
01387     script->buffer[length] = 0;
01388     script->length = length;
01389     //pointer in script buffer
01390     script->script_p = script->buffer;
01391     //pointer in script buffer before reading token
01392     script->lastscript_p = script->buffer;
01393     //pointer to end of script buffer
01394     script->end_p = &script->buffer[length];
01395     //set if there's a token available in script->token
01396     script->tokenavailable = 0;
01397     //
01398     script->line = 1;
01399     script->lastline = 1;
01400     //
01401     SetScriptPunctuations(script, NULL);
01402     //
01403     Com_Memcpy(script->buffer, ptr, length);
01404     //
01405     return script;
01406 } //end of the function LoadScriptMemory
01407 //============================================================================
01408 //
01409 // Parameter:               -
01410 // Returns:                 -
01411 // Changes Globals:     -
01412 //============================================================================
01413 void FreeScript(script_t *script)
01414 {
01415 #ifdef PUNCTABLE
01416     if (script->punctuationtable) FreeMemory(script->punctuationtable);
01417 #endif //PUNCTABLE
01418     FreeMemory(script);
01419 } //end of the function FreeScript
01420 //============================================================================
01421 //
01422 // Parameter:               -
01423 // Returns:                 -
01424 // Changes Globals:     -
01425 //============================================================================
01426 void PS_SetBaseFolder(char *path)
01427 {
01428 #ifdef BSPC
01429     sprintf(basefolder, path);
01430 #else
01431     Com_sprintf(basefolder, sizeof(basefolder), path);
01432 #endif
01433 } //end of the function PS_SetBaseFolder

Generated on Thu Aug 25 12:37:13 2005 for Quake III Arena by  doxygen 1.3.9.1