mirror of
https://github.com/tribes2/engine.git
synced 2026-02-26 18:13:41 +00:00
t2 engine svn checkout
This commit is contained in:
commit
ff569bd2ae
988 changed files with 394180 additions and 0 deletions
439
console/ast.h
Normal file
439
console/ast.h
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _AST_H_
|
||||
#define _AST_H_
|
||||
|
||||
// TO-DO: Console debugger stuff to be cleaned up later
|
||||
// extern void dbgDebuggerAddBreakPosition(const char *fileName, S32 lineNumber);
|
||||
// extern void dbgDebuggerRemoveBreakPosition(const char *fileName, S32 lineNumber);
|
||||
|
||||
class ExprEvalState;
|
||||
class Namespace;
|
||||
class SimObject;
|
||||
class SimGroup;
|
||||
|
||||
enum TypeReq {
|
||||
TypeReqNone,
|
||||
TypeReqUInt,
|
||||
TypeReqFloat,
|
||||
TypeReqString
|
||||
};
|
||||
|
||||
struct StmtNode
|
||||
{
|
||||
StmtNode *next;
|
||||
|
||||
StmtNode();
|
||||
void append(StmtNode *next);
|
||||
StmtNode *getNext() { return next; }
|
||||
|
||||
StringTableEntry dbgFileName;
|
||||
S32 dbgLineNumber;
|
||||
|
||||
void addBreakCount();
|
||||
void addBreakLine(U32 ip);
|
||||
virtual U32 precompileStmt(U32 loopCount) = 0;
|
||||
virtual U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint) = 0;
|
||||
virtual void setPackage(StringTableEntry packageName);
|
||||
};
|
||||
|
||||
struct BreakStmtNode : StmtNode
|
||||
{
|
||||
static BreakStmtNode *alloc();
|
||||
|
||||
U32 precompileStmt(U32 loopCount);
|
||||
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
|
||||
};
|
||||
|
||||
struct ContinueStmtNode : StmtNode
|
||||
{
|
||||
static ContinueStmtNode *alloc();
|
||||
U32 precompileStmt(U32 loopCount);
|
||||
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
|
||||
};
|
||||
|
||||
struct ExprNode : StmtNode
|
||||
{
|
||||
U32 precompileStmt(U32 loopCount);
|
||||
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
|
||||
|
||||
virtual U32 precompile(TypeReq type) = 0;
|
||||
virtual U32 compile(U32 *codeStream, U32 ip, TypeReq type) = 0;
|
||||
U32 compileX(U32 *codeStream, U32 ip, TypeReq type);
|
||||
virtual TypeReq getPreferredType() = 0;
|
||||
};
|
||||
|
||||
struct ReturnStmtNode : StmtNode
|
||||
{
|
||||
ExprNode *expr;
|
||||
|
||||
static ReturnStmtNode *alloc(ExprNode *expr);
|
||||
U32 precompileStmt(U32 loopCount);
|
||||
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
|
||||
};
|
||||
|
||||
struct IfStmtNode : StmtNode
|
||||
{
|
||||
ExprNode *testExpr;
|
||||
StmtNode *ifBlock, *elseBlock;
|
||||
U32 endifOffset;
|
||||
U32 elseOffset;
|
||||
bool integer;
|
||||
bool propagate;
|
||||
|
||||
static IfStmtNode *alloc(S32 lineNumber, ExprNode *testExpr, StmtNode *ifBlock, StmtNode *elseBlock, bool propagateThrough);
|
||||
void propagateSwitchExpr(ExprNode *left, bool string);
|
||||
ExprNode *getSwitchOR(ExprNode *left, ExprNode *list, bool string);
|
||||
U32 precompileStmt(U32 loopCount);
|
||||
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
|
||||
};
|
||||
|
||||
struct LoopStmtNode : StmtNode
|
||||
{
|
||||
ExprNode *testExpr;
|
||||
ExprNode *initExpr;
|
||||
ExprNode *endLoopExpr;
|
||||
StmtNode *loopBlock;
|
||||
bool isDoLoop;
|
||||
U32 breakOffset;
|
||||
U32 continueOffset;
|
||||
U32 loopBlockStartOffset;
|
||||
bool integer;
|
||||
|
||||
static LoopStmtNode *alloc(S32 lineNumber, ExprNode *testExpr, ExprNode *initExpr, ExprNode *endLoopExpr, StmtNode *loopBlock, bool isDoLoop);
|
||||
U32 precompileStmt(U32 loopCount);
|
||||
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
|
||||
};
|
||||
|
||||
struct BinaryExprNode : ExprNode
|
||||
{
|
||||
S32 op;
|
||||
ExprNode *left;
|
||||
ExprNode *right;
|
||||
};
|
||||
|
||||
struct FloatBinaryExprNode : BinaryExprNode
|
||||
{
|
||||
static FloatBinaryExprNode *alloc(S32 op, ExprNode *left, ExprNode *right);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct ConditionalExprNode : ExprNode
|
||||
{
|
||||
ExprNode *testExpr;
|
||||
ExprNode *trueExpr;
|
||||
ExprNode *falseExpr;
|
||||
bool integer;
|
||||
static ConditionalExprNode *alloc(ExprNode *testExpr, ExprNode *trueExpr, ExprNode *falseExpr);
|
||||
virtual U32 precompile(TypeReq type);
|
||||
virtual U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
virtual TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct IntBinaryExprNode : BinaryExprNode
|
||||
{
|
||||
TypeReq subType;
|
||||
U32 operand;
|
||||
|
||||
static IntBinaryExprNode *alloc(S32 op, ExprNode *left, ExprNode *right);
|
||||
|
||||
void getSubTypeOperand();
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct StreqExprNode : BinaryExprNode
|
||||
{
|
||||
bool eq;
|
||||
static StreqExprNode *alloc(ExprNode *left, ExprNode *right, bool eq);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct StrcatExprNode : BinaryExprNode
|
||||
{
|
||||
int appendChar;
|
||||
static StrcatExprNode *alloc(ExprNode *left, ExprNode *right, int appendChar);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct CommaCatExprNode : BinaryExprNode
|
||||
{
|
||||
static CommaCatExprNode *alloc(ExprNode *left, ExprNode *right);
|
||||
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct IntUnaryExprNode : ExprNode
|
||||
{
|
||||
S32 op;
|
||||
ExprNode *expr;
|
||||
bool integer;
|
||||
|
||||
static IntUnaryExprNode *alloc(S32 op, ExprNode *expr);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct FloatUnaryExprNode : ExprNode
|
||||
{
|
||||
S32 op;
|
||||
ExprNode *expr;
|
||||
|
||||
static FloatUnaryExprNode *alloc(S32 op, ExprNode *expr);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct VarNode : ExprNode
|
||||
{
|
||||
StringTableEntry varName;
|
||||
ExprNode *arrayIndex;
|
||||
|
||||
static VarNode *alloc(StringTableEntry varName, ExprNode *arrayIndex);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct IntNode : ExprNode
|
||||
{
|
||||
S32 value;
|
||||
U32 index; // if it's converted to float/string
|
||||
|
||||
static IntNode *alloc(S32 value);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct FloatNode : ExprNode
|
||||
{
|
||||
F64 value;
|
||||
U32 index;
|
||||
|
||||
static FloatNode *alloc(F64 value);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct StrConstNode : ExprNode
|
||||
{
|
||||
char *str;
|
||||
F64 fVal;
|
||||
U32 index;
|
||||
bool tag;
|
||||
|
||||
static StrConstNode *alloc(char *str, bool tag);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct ConstantNode : ExprNode
|
||||
{
|
||||
StringTableEntry value;
|
||||
F64 fVal;
|
||||
U32 index;
|
||||
|
||||
static ConstantNode *alloc(StringTableEntry value);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct AssignExprNode : ExprNode
|
||||
{
|
||||
StringTableEntry varName;
|
||||
ExprNode *expr;
|
||||
ExprNode *arrayIndex;
|
||||
TypeReq subType;
|
||||
|
||||
static AssignExprNode *alloc(StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct AssignDecl
|
||||
{
|
||||
S32 token;
|
||||
ExprNode *expr;
|
||||
bool integer;
|
||||
};
|
||||
|
||||
struct AssignOpExprNode : ExprNode
|
||||
{
|
||||
StringTableEntry varName;
|
||||
ExprNode *expr;
|
||||
ExprNode *arrayIndex;
|
||||
S32 op;
|
||||
U32 operand;
|
||||
TypeReq subType;
|
||||
|
||||
static AssignOpExprNode *alloc(StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr, S32 op);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct TTagSetStmtNode : StmtNode
|
||||
{
|
||||
StringTableEntry tag;
|
||||
ExprNode *valueExpr;
|
||||
ExprNode *stringExpr;
|
||||
|
||||
static TTagSetStmtNode *alloc(StringTableEntry tag, ExprNode *valueExpr, ExprNode *stringExpr);
|
||||
U32 precompileStmt(U32 loopCount);
|
||||
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
|
||||
};
|
||||
|
||||
struct TTagDerefNode : ExprNode
|
||||
{
|
||||
ExprNode *expr;
|
||||
|
||||
static TTagDerefNode *alloc(ExprNode *expr);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct TTagExprNode : ExprNode
|
||||
{
|
||||
StringTableEntry tag;
|
||||
|
||||
static TTagExprNode *alloc(StringTableEntry tag);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct FuncCallExprNode : ExprNode
|
||||
{
|
||||
StringTableEntry funcName;
|
||||
StringTableEntry nameSpace;
|
||||
ExprNode *args;
|
||||
U32 callType;
|
||||
enum {
|
||||
FunctionCall,
|
||||
MethodCall,
|
||||
ParentCall
|
||||
};
|
||||
|
||||
static FuncCallExprNode *alloc(StringTableEntry funcName, StringTableEntry nameSpace, ExprNode *args, bool dot);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct SlotDecl
|
||||
{
|
||||
ExprNode *object;
|
||||
StringTableEntry slotName;
|
||||
ExprNode *array;
|
||||
};
|
||||
|
||||
struct SlotAccessNode : ExprNode
|
||||
{
|
||||
ExprNode *objectExpr, *arrayExpr;
|
||||
StringTableEntry slotName;
|
||||
|
||||
static SlotAccessNode *alloc(ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct SlotAssignNode : ExprNode
|
||||
{
|
||||
ExprNode *objectExpr, *arrayExpr;
|
||||
StringTableEntry slotName;
|
||||
ExprNode *valueExpr;
|
||||
|
||||
static SlotAssignNode *alloc(ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName, ExprNode *valueExpr);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct SlotAssignOpNode : ExprNode
|
||||
{
|
||||
ExprNode *objectExpr, *arrayExpr;
|
||||
StringTableEntry slotName;
|
||||
S32 op;
|
||||
ExprNode *valueExpr;
|
||||
U32 operand;
|
||||
TypeReq subType;
|
||||
|
||||
static SlotAssignOpNode *alloc(ExprNode *objectExpr, StringTableEntry slotName, ExprNode *arrayExpr, S32 op, ExprNode *valueExpr);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct ObjectDeclNode : ExprNode
|
||||
{
|
||||
ExprNode *classNameExpr;
|
||||
StringTableEntry parentObject;
|
||||
ExprNode *objectNameExpr;
|
||||
ExprNode *argList;
|
||||
SlotAssignNode *slotDecls;
|
||||
ObjectDeclNode *subObjects;
|
||||
bool structDecl;
|
||||
U32 failOffset;
|
||||
|
||||
static ObjectDeclNode *alloc(ExprNode *classNameExpr, ExprNode *objectNameExpr, ExprNode *argList, StringTableEntry parentObject, SlotAssignNode *slotDecls, ObjectDeclNode *subObjects, bool structDecl);
|
||||
U32 precompile(TypeReq type);
|
||||
U32 precompileSubObject(bool);
|
||||
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
|
||||
U32 compileSubObject(U32 *codeStream, U32 ip, bool);
|
||||
TypeReq getPreferredType();
|
||||
};
|
||||
|
||||
struct ObjectBlockDecl
|
||||
{
|
||||
SlotAssignNode *slots;
|
||||
ObjectDeclNode *decls;
|
||||
};
|
||||
|
||||
struct FunctionDeclStmtNode : StmtNode
|
||||
{
|
||||
StringTableEntry fnName;
|
||||
VarNode *args;
|
||||
StmtNode *stmts;
|
||||
StringTableEntry nameSpace;
|
||||
StringTableEntry package;
|
||||
U32 endOffset;
|
||||
U32 argc;
|
||||
|
||||
static FunctionDeclStmtNode *alloc(StringTableEntry fnName, StringTableEntry nameSpace, VarNode *args, StmtNode *stmts);
|
||||
U32 precompileStmt(U32 loopCount);
|
||||
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
|
||||
void setPackage(StringTableEntry packageName);
|
||||
};
|
||||
|
||||
extern StmtNode *statementList;
|
||||
extern void createFunction(const char *fnName, VarNode *args, StmtNode *statements);
|
||||
extern ExprEvalState gEvalState;
|
||||
extern bool lookupFunction(const char *fnName, VarNode **args, StmtNode **statements);
|
||||
typedef const char *(*cfunc)(S32 argc, char **argv);
|
||||
extern bool lookupCFunction(const char *fnName, cfunc *f);
|
||||
|
||||
|
||||
#endif
|
||||
1222
console/compiledEval.cc
Normal file
1222
console/compiledEval.cc
Normal file
File diff suppressed because it is too large
Load diff
2609
console/compiler.cc
Normal file
2609
console/compiler.cc
Normal file
File diff suppressed because it is too large
Load diff
246
console/compiler.h
Normal file
246
console/compiler.h
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
enum CompiledInstructions
|
||||
{
|
||||
OP_FUNC_DECL,
|
||||
OP_CREATE_OBJECT,
|
||||
OP_CREATE_DATABLOCK,
|
||||
|
||||
OP_NAME_OBJECT,
|
||||
OP_ADD_OBJECT,
|
||||
OP_END_OBJECT,
|
||||
OP_JMPIFFNOT,
|
||||
OP_JMPIFNOT,
|
||||
OP_JMPIFF,
|
||||
OP_JMPIF,
|
||||
OP_JMPIFNOT_NP,
|
||||
OP_JMPIF_NP,
|
||||
OP_JMP,
|
||||
OP_RETURN,
|
||||
OP_CMPEQ,
|
||||
OP_CMPGR,
|
||||
OP_CMPGE,
|
||||
OP_CMPLT,
|
||||
OP_CMPLE,
|
||||
OP_CMPNE,
|
||||
OP_XOR,
|
||||
OP_MOD,
|
||||
OP_BITAND,
|
||||
OP_BITOR,
|
||||
OP_NOT,
|
||||
OP_NOTF,
|
||||
OP_ONESCOMPLEMENT,
|
||||
|
||||
OP_SHR,
|
||||
OP_SHL,
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
|
||||
OP_ADD,
|
||||
OP_SUB,
|
||||
OP_MUL,
|
||||
OP_DIV,
|
||||
OP_NEG,
|
||||
|
||||
OP_SETCURVAR,
|
||||
OP_SETCURVAR_CREATE,
|
||||
OP_SETCURVAR_ARRAY,
|
||||
OP_SETCURVAR_ARRAY_CREATE,
|
||||
|
||||
OP_LOADVAR_UINT,
|
||||
OP_LOADVAR_FLT,
|
||||
OP_LOADVAR_STR,
|
||||
|
||||
OP_SAVEVAR_UINT,
|
||||
OP_SAVEVAR_FLT,
|
||||
OP_SAVEVAR_STR,
|
||||
|
||||
OP_SETCUROBJECT,
|
||||
OP_SETCUROBJECT_NEW,
|
||||
|
||||
OP_SETCURFIELD,
|
||||
OP_SETCURFIELD_ARRAY,
|
||||
|
||||
OP_LOADFIELD_UINT,
|
||||
OP_LOADFIELD_FLT,
|
||||
OP_LOADFIELD_STR,
|
||||
|
||||
OP_SAVEFIELD_UINT,
|
||||
OP_SAVEFIELD_FLT,
|
||||
OP_SAVEFIELD_STR,
|
||||
|
||||
OP_STR_TO_UINT,
|
||||
OP_STR_TO_FLT,
|
||||
OP_STR_TO_NONE,
|
||||
OP_FLT_TO_UINT,
|
||||
OP_FLT_TO_STR,
|
||||
OP_FLT_TO_NONE,
|
||||
OP_UINT_TO_FLT,
|
||||
OP_UINT_TO_STR,
|
||||
OP_UINT_TO_NONE,
|
||||
|
||||
OP_LOADIMMED_UINT,
|
||||
OP_LOADIMMED_FLT,
|
||||
OP_TAG_TO_STR,
|
||||
OP_LOADIMMED_STR,
|
||||
OP_LOADIMMED_IDENT,
|
||||
|
||||
OP_CALLFUNC_RESOLVE,
|
||||
OP_CALLFUNC,
|
||||
OP_PROCESS_ARGS,
|
||||
|
||||
OP_ADVANCE_STR,
|
||||
OP_ADVANCE_STR_APPENDCHAR,
|
||||
OP_ADVANCE_STR_COMMA,
|
||||
OP_ADVANCE_STR_NUL,
|
||||
OP_REWIND_STR,
|
||||
OP_TERMINATE_REWIND_STR,
|
||||
OP_COMPARE_STR,
|
||||
|
||||
OP_PUSH,
|
||||
OP_PUSH_FRAME,
|
||||
|
||||
OP_BREAK,
|
||||
|
||||
OP_INVALID
|
||||
};
|
||||
|
||||
|
||||
// DON'T CHANGE THESE LINES!
|
||||
// DON'T CHANGE THESE LINES!
|
||||
// The script updateConsoleVersion.pl in //Dev/environment/usr/bin/ depends on them
|
||||
// being exactly as follows
|
||||
//
|
||||
enum {
|
||||
ConsoleDSOVersion = 33
|
||||
};
|
||||
//
|
||||
// DON'T CHANGE THESE LINES!
|
||||
// DON'T CHANGE THESE LINES!
|
||||
// DON'T CHANGE THESE LINES!
|
||||
|
||||
class Stream;
|
||||
|
||||
class CodeBlock
|
||||
{
|
||||
public:
|
||||
StringTableEntry name;
|
||||
|
||||
char *globalStrings;
|
||||
char *functionStrings;
|
||||
|
||||
F64 *globalFloats;
|
||||
F64 *functionFloats;
|
||||
|
||||
U32 codeSize;
|
||||
U32 *code;
|
||||
|
||||
U32 refCount;
|
||||
U32 lineBreakPairCount;
|
||||
U32 *lineBreakPairs;
|
||||
U32 breakListSize;
|
||||
U32 *breakList;
|
||||
CodeBlock *nextFile;
|
||||
|
||||
static CodeBlock *find(StringTableEntry);
|
||||
CodeBlock();
|
||||
~CodeBlock();
|
||||
|
||||
void addToCodeList();
|
||||
void removeFromCodeList();
|
||||
void calcBreakList();
|
||||
void clearAllBreaks();
|
||||
void setAllBreaks();
|
||||
void clearBreakpoint(U32 lineNumber);
|
||||
void setBreakpoint(U32 lineNumber);
|
||||
void findBreakLine(U32 ip, U32 &line, U32 &instruction);
|
||||
const char *getFileLine(U32 ip);
|
||||
|
||||
bool read(StringTableEntry fileName, Stream &st);
|
||||
bool compile(const char *dsoName, StringTableEntry fileName, const char *script);
|
||||
|
||||
void incRefCount();
|
||||
void decRefCount();
|
||||
const char *compileExec(StringTableEntry fileName, const char *script, bool noCalls);
|
||||
const char *exec(U32 offset, const char *fnName, Namespace *ns, U32 argc, const char **argv, bool noCalls);
|
||||
};
|
||||
extern CodeBlock *codeBlockList;
|
||||
|
||||
extern F64 consoleStringToNumber(const char *str, StringTableEntry file = 0, U32 line = 0);
|
||||
extern U32 precompileBlock(StmtNode *block, U32 loopCount);
|
||||
extern U32 compileBlock(StmtNode *block, U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
|
||||
|
||||
struct CompilerIdentTable
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
U32 offset;
|
||||
U32 ip;
|
||||
Entry *next;
|
||||
Entry *nextIdent;
|
||||
};
|
||||
Entry *list;
|
||||
void add(StringTableEntry ste, U32 ip);
|
||||
void reset();
|
||||
void write(Stream &st);
|
||||
};
|
||||
|
||||
struct CompilerStringTable
|
||||
{
|
||||
U32 totalLen;
|
||||
struct Entry
|
||||
{
|
||||
char *string;
|
||||
U32 start;
|
||||
U32 len;
|
||||
bool tag;
|
||||
Entry *next;
|
||||
};
|
||||
Entry *list;
|
||||
|
||||
char buf[256];
|
||||
|
||||
U32 add(const char *str, bool caseSens = true, bool tag = false);
|
||||
U32 addIntString(U32 value);
|
||||
U32 addFloatString(F64 value);
|
||||
void reset();
|
||||
char *build();
|
||||
void write(Stream &st);
|
||||
};
|
||||
|
||||
extern CompilerStringTable *currentStringTable;
|
||||
extern CompilerStringTable gGlobalStringTable;
|
||||
extern CompilerStringTable gFunctionStringTable;
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
struct CompilerFloatTable
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
F64 val;
|
||||
Entry *next;
|
||||
};
|
||||
U32 count;
|
||||
Entry *list;
|
||||
|
||||
U32 add(F64 value);
|
||||
void reset();
|
||||
F64 *build();
|
||||
void write(Stream &st);
|
||||
};
|
||||
|
||||
extern CompilerFloatTable *currentFloatTable, gGlobalFloatTable, gFunctionFloatTable;
|
||||
|
||||
extern U32 (*STEtoU32)(StringTableEntry ste, U32 ip);
|
||||
|
||||
inline StringTableEntry U32toSTE(U32 u)
|
||||
{
|
||||
return *((StringTableEntry *) &u);
|
||||
}
|
||||
|
||||
688
console/console.cc
Normal file
688
console/console.cc
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "Platform/platform.h"
|
||||
#include "console/console.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "console/consoleObject.h"
|
||||
#include "Core/fileStream.h"
|
||||
#include "Core/resManager.h"
|
||||
#include "console/ast.h"
|
||||
#include "Core/tAlgorithm.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/telnetDebugger.h"
|
||||
#include "console/simBase.h"
|
||||
#include "console/compiler.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
ExprEvalState gEvalState;
|
||||
StmtNode *statementList;
|
||||
ConsoleConstructor *ConsoleConstructor::first = NULL;
|
||||
|
||||
static char scratchBuffer[1024];
|
||||
// TO-DO: Console debugger stuff to be cleaned up later
|
||||
static S32 dbgGetCurrentFrame(void)
|
||||
{
|
||||
return gEvalState.stack.size() - 1;
|
||||
}
|
||||
|
||||
static const char * prependDollar ( const char * name )
|
||||
{
|
||||
if(name[0] != '$'){
|
||||
S32 len = dStrlen(name);
|
||||
AssertFatal(len < sizeof(scratchBuffer)-2, "CONSOLE: name too long");
|
||||
scratchBuffer[0] = '$';
|
||||
dMemcpy(scratchBuffer + 1, name, len + 1);
|
||||
name = scratchBuffer;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static const char * prependPercent ( const char * name )
|
||||
{
|
||||
if(name[0] != '%'){
|
||||
S32 len = dStrlen(name);
|
||||
AssertFatal(len < sizeof(scratchBuffer)-2, "CONSOLE: name too long");
|
||||
scratchBuffer[0] = '%';
|
||||
dMemcpy(scratchBuffer + 1, name, len + 1);
|
||||
name = scratchBuffer;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
void ConsoleConstructor::init(const char *cName, const char *fName, const char *usg, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
mina = minArgs;
|
||||
maxa = maxArgs;
|
||||
funcName = fName;
|
||||
usage = usg;
|
||||
className = cName;
|
||||
sc = 0; fc = 0; vc = 0; bc = 0; ic = 0;
|
||||
next = first;
|
||||
first = this;
|
||||
}
|
||||
|
||||
void ConsoleConstructor::setup()
|
||||
{
|
||||
for(ConsoleConstructor *walk = first; walk; walk = walk->next)
|
||||
{
|
||||
if(walk->sc)
|
||||
Con::addCommand(walk->className, walk->funcName, walk->sc, walk->usage, walk->mina, walk->maxa);
|
||||
else if(walk->ic)
|
||||
Con::addCommand(walk->className, walk->funcName, walk->ic, walk->usage, walk->mina, walk->maxa);
|
||||
else if(walk->fc)
|
||||
Con::addCommand(walk->className, walk->funcName, walk->fc, walk->usage, walk->mina, walk->maxa);
|
||||
else if(walk->vc)
|
||||
Con::addCommand(walk->className, walk->funcName, walk->vc, walk->usage, walk->mina, walk->maxa);
|
||||
else if(walk->bc)
|
||||
Con::addCommand(walk->className, walk->funcName, walk->bc, walk->usage, walk->mina, walk->maxa);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, StringCallback sfunc, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
init(className, funcName, usage, minArgs, maxArgs);
|
||||
sc = sfunc;
|
||||
}
|
||||
|
||||
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, IntCallback ifunc, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
init(className, funcName, usage, minArgs, maxArgs);
|
||||
ic = ifunc;
|
||||
}
|
||||
|
||||
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, FloatCallback ffunc, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
init(className, funcName, usage, minArgs, maxArgs);
|
||||
fc = ffunc;
|
||||
}
|
||||
|
||||
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, VoidCallback vfunc, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
init(className, funcName, usage, minArgs, maxArgs);
|
||||
vc = vfunc;
|
||||
}
|
||||
|
||||
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, BoolCallback bfunc, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
init(className, funcName, usage, minArgs, maxArgs);
|
||||
bc = bfunc;
|
||||
}
|
||||
|
||||
namespace Con
|
||||
{
|
||||
|
||||
static Vector<ConsumerCallback> gConsumers(__FILE__, __LINE__);
|
||||
static DataChunker consoleLogChunker;
|
||||
static Vector<ConsoleLogEntry> consoleLog(__FILE__, __LINE__);
|
||||
static bool logBufferEnabled=true;
|
||||
static S32 printLevel = 10;
|
||||
static FileStream consoleLogFile;
|
||||
static const char *defLogFileName = "console.log";
|
||||
static S32 consoleLogMode = 2; // default to no logging
|
||||
static bool active = false;
|
||||
static bool newLogFile;
|
||||
static const char *logFileName;
|
||||
|
||||
static void cClearScreen(SimObject *, S32 , const char **)
|
||||
{
|
||||
consoleLogChunker.freeBlocks();
|
||||
consoleLog.setSize(0);
|
||||
};
|
||||
|
||||
static const char* cGetClipboard(SimObject *, S32 , const char **)
|
||||
{
|
||||
return Platform::getClipboard();
|
||||
};
|
||||
|
||||
static bool cSetClipboard(SimObject *, S32 , const char **argv)
|
||||
{
|
||||
return Platform::setClipboard(argv[1]);
|
||||
};
|
||||
|
||||
void init()
|
||||
{
|
||||
AssertFatal(active == false, "Con::init should only be called once.");
|
||||
|
||||
active = true;
|
||||
logFileName = NULL;
|
||||
newLogFile = true;
|
||||
|
||||
Namespace::init();
|
||||
// Commands
|
||||
addCommand("getClipboard", cGetClipboard, "getClipboard()", 1, 1);
|
||||
addCommand("cls", cClearScreen, "cls()", 1, 1);
|
||||
addCommand("getClipboard", cGetClipboard, "getClipboard()", 1, 1);
|
||||
addCommand("setClipboard", cSetClipboard, "setClipboard(text)", 2, 2);
|
||||
|
||||
ConsoleConstructor::setup();
|
||||
|
||||
// Variables
|
||||
setVariable("Con::prompt", "% ");
|
||||
addVariable("Con::logBufferEnabled", TypeBool, &logBufferEnabled);
|
||||
addVariable("Con::printLevel", TypeS32, &printLevel);
|
||||
|
||||
AbstractClassRep::initialize();
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
AssertFatal(active == true, "Con::shutdown should only be called once.");
|
||||
active = false;
|
||||
|
||||
consoleLogFile.close();
|
||||
Namespace::shutdown();
|
||||
}
|
||||
|
||||
bool isActive()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
void getLog(ConsoleLogEntry *&log, U32 &size)
|
||||
{
|
||||
log = &consoleLog[0];
|
||||
size = consoleLog.size();
|
||||
}
|
||||
|
||||
const char *tabComplete(const char *prevText, S32 baseLen, bool fForward)
|
||||
{
|
||||
if (!prevText[0])
|
||||
return "";
|
||||
else if(prevText[0] == '$')
|
||||
return gEvalState.globalVars.tabComplete(prevText, baseLen, fForward);
|
||||
else
|
||||
return Namespace::global()->tabComplete(prevText, baseLen, fForward);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static void log(const char *string)
|
||||
{
|
||||
if(!consoleLogMode)
|
||||
return;
|
||||
|
||||
if(consoleLogMode == 1)
|
||||
consoleLogFile.open(defLogFileName, FileStream::ReadWrite);
|
||||
|
||||
if(consoleLogFile.getStatus() == Stream::Ok)
|
||||
{
|
||||
consoleLogFile.setPosition(consoleLogFile.getStreamSize());
|
||||
if (newLogFile)
|
||||
{
|
||||
Platform::LocalTime lt;
|
||||
Platform::getLocalTime(lt);
|
||||
|
||||
char buffer[128];
|
||||
dSprintf(buffer, sizeof(buffer), "-------------------------- %d/%d/%d -- %02d:%02d:%02d -----\r\n",
|
||||
lt.month,
|
||||
lt.monthday,
|
||||
lt.year,
|
||||
lt.hour,
|
||||
lt.min,
|
||||
lt.sec);
|
||||
consoleLogFile.write(dStrlen(buffer), buffer);
|
||||
newLogFile = false;
|
||||
}
|
||||
consoleLogFile.write(dStrlen(string), string);
|
||||
consoleLogFile.write(2, "\r\n");
|
||||
}
|
||||
if(consoleLogMode == 1)
|
||||
consoleLogFile.close();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static void _printf(ConsoleLogEntry::Level level, ConsoleLogEntry::Type type, const char* fmt, va_list argptr)
|
||||
{
|
||||
char buffer[1024];
|
||||
U32 offset = 0;
|
||||
if(gEvalState.traceOn && gEvalState.stack.size())
|
||||
{
|
||||
offset = (gEvalState.stack.size() - 1) * 2;
|
||||
for(U32 i = 0; i < offset; i++)
|
||||
buffer[i] = ' ';
|
||||
}
|
||||
dVsprintf(buffer + offset, sizeof(buffer) - offset, fmt, argptr);
|
||||
|
||||
for(U32 i = 0; i < gConsumers.size(); i++)
|
||||
gConsumers[i](level, buffer);
|
||||
|
||||
if(logBufferEnabled || consoleLogMode)
|
||||
{
|
||||
char *pos = buffer;
|
||||
while(*pos)
|
||||
{
|
||||
if(*pos == '\t')
|
||||
*pos = '^';
|
||||
pos++;
|
||||
}
|
||||
pos = buffer;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char *eofPos = dStrchr(pos, '\n');
|
||||
if(eofPos)
|
||||
*eofPos = 0;
|
||||
|
||||
log(pos);
|
||||
if(logBufferEnabled)
|
||||
{
|
||||
ConsoleLogEntry entry;
|
||||
entry.mLevel = level;
|
||||
entry.mType = type;
|
||||
entry.mString = (const char *)consoleLogChunker.alloc(dStrlen(pos) + 1);
|
||||
dStrcpy(const_cast<char*>(entry.mString), pos);
|
||||
consoleLog.push_back(entry);
|
||||
}
|
||||
if(!eofPos)
|
||||
break;
|
||||
pos = eofPos + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void printf(const char* fmt,...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
_printf(ConsoleLogEntry::Normal, ConsoleLogEntry::General, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
void warnf(ConsoleLogEntry::Type type, const char* fmt,...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
_printf(ConsoleLogEntry::Warning, type, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
void errorf(ConsoleLogEntry::Type type, const char* fmt,...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
_printf(ConsoleLogEntry::Error, type, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
void warnf(const char* fmt,...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
_printf(ConsoleLogEntry::Warning, ConsoleLogEntry::General, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
void errorf(const char* fmt,...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
_printf(ConsoleLogEntry::Error, ConsoleLogEntry::General, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void setVariable(const char *name, const char *value)
|
||||
{
|
||||
name = prependDollar(name);
|
||||
gEvalState.globalVars.setVariable(StringTable->insert(name), value);
|
||||
}
|
||||
|
||||
void setLocalVariable(const char *name, const char *value)
|
||||
{
|
||||
name = prependPercent(name);
|
||||
gEvalState.stack.last()->setVariable(StringTable->insert(name), value);
|
||||
}
|
||||
|
||||
void setBoolVariable(const char *varName, bool value)
|
||||
{
|
||||
setVariable(varName, value ? "1" : "0");
|
||||
}
|
||||
|
||||
void setIntVariable(const char *varName, S32 value)
|
||||
{
|
||||
char scratchBuffer[32];
|
||||
dSprintf(scratchBuffer, sizeof(scratchBuffer), "%d", value);
|
||||
setVariable(varName, scratchBuffer);
|
||||
}
|
||||
|
||||
void setFloatVariable(const char *varName, F32 value)
|
||||
{
|
||||
char scratchBuffer[32];
|
||||
dSprintf(scratchBuffer, sizeof(scratchBuffer), "%f", value);
|
||||
setVariable(varName, scratchBuffer);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void addConsumer(ConsumerCallback consumer)
|
||||
{
|
||||
gConsumers.push_back(consumer);
|
||||
}
|
||||
|
||||
void removeConsumer(ConsumerCallback)
|
||||
{
|
||||
}
|
||||
|
||||
const char *getVariable(const char *name)
|
||||
{
|
||||
// get the field info from the object..
|
||||
if(name[0] != '$' && dStrchr(name, '.') && !isFunction(name))
|
||||
{
|
||||
S32 len = dStrlen(name);
|
||||
AssertFatal(len < sizeof(scratchBuffer)-1, "CONSOLE: name too long");
|
||||
dMemcpy(scratchBuffer, name, len+1);
|
||||
|
||||
char * token = dStrtok(scratchBuffer, ".");
|
||||
SimObject * obj = Sim::findObject(token);
|
||||
if(!obj)
|
||||
return("");
|
||||
|
||||
token = dStrtok(0, ".\0");
|
||||
if(!token)
|
||||
return("");
|
||||
|
||||
while(token != NULL)
|
||||
{
|
||||
const char * val = obj->getDataField(StringTable->insert(token), 0);
|
||||
if(!val)
|
||||
return("");
|
||||
|
||||
token = dStrtok(0, ".\0");
|
||||
if(token)
|
||||
{
|
||||
obj = Sim::findObject(token);
|
||||
if(!obj)
|
||||
return("");
|
||||
}
|
||||
else
|
||||
return(val);
|
||||
}
|
||||
}
|
||||
|
||||
name = prependDollar(name);
|
||||
return gEvalState.globalVars.getVariable(StringTable->insert(name));
|
||||
}
|
||||
|
||||
const char *getLocalVariable(const char *name)
|
||||
{
|
||||
name = prependPercent(name);
|
||||
|
||||
return gEvalState.stack.last()->getVariable(StringTable->insert(name));
|
||||
}
|
||||
|
||||
bool getBoolVariable(const char *varName, bool def)
|
||||
{
|
||||
const char *value = getVariable(varName);
|
||||
return *value ? dAtob(value) : def;
|
||||
}
|
||||
|
||||
S32 getIntVariable(const char *varName, S32 def)
|
||||
{
|
||||
const char *value = getVariable(varName);
|
||||
return *value ? dAtoi(value) : def;
|
||||
}
|
||||
|
||||
F32 getFloatVariable(const char *varName, F32 def)
|
||||
{
|
||||
const char *value = getVariable(varName);
|
||||
return *value ? dAtof(value) : def;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool addVariable(const char *name, S32 t, void *dp)
|
||||
{
|
||||
gEvalState.globalVars.addVariable(name, t, dp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool removeVariable(const char *name)
|
||||
{
|
||||
name = StringTable->lookup(prependDollar(name));
|
||||
return name!=0 && gEvalState.globalVars.removeVariable(name);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void addCommand(const char *nsName, const char *name,StringCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace *ns = lookupNamespace(nsName);
|
||||
ns->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
void addCommand(const char *nsName, const char *name,VoidCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace *ns = lookupNamespace(nsName);
|
||||
ns->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
void addCommand(const char *nsName, const char *name,IntCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace *ns = lookupNamespace(nsName);
|
||||
ns->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
void addCommand(const char *nsName, const char *name,FloatCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace *ns = lookupNamespace(nsName);
|
||||
ns->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
void addCommand(const char *nsName, const char *name,BoolCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace *ns = lookupNamespace(nsName);
|
||||
ns->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
void addCommand(const char *name,StringCallback cb,const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace::global()->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
void addCommand(const char *name,VoidCallback cb,const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace::global()->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
void addCommand(const char *name,IntCallback cb,const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace::global()->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
void addCommand(const char *name,FloatCallback cb,const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace::global()->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
void addCommand(const char *name,BoolCallback cb,const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Namespace::global()->addCommand(StringTable->insert(name), cb, usage, minArgs, maxArgs);
|
||||
}
|
||||
|
||||
const char *evaluate(const char* string, bool echo, const char *fileName)
|
||||
{
|
||||
if (echo)
|
||||
printf("%s%s", getVariable( "$Con::Prompt" ), string);
|
||||
|
||||
if(fileName)
|
||||
fileName = StringTable->insert(fileName);
|
||||
|
||||
CodeBlock *newCodeBlock = new CodeBlock();
|
||||
return newCodeBlock->compileExec(fileName, string, false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char *evaluatef(const char* string, ...)
|
||||
{
|
||||
char buffer[512];
|
||||
va_list args;
|
||||
va_start(args, string);
|
||||
dVsprintf(buffer, sizeof(buffer), string, args);
|
||||
CodeBlock *newCodeBlock = new CodeBlock();
|
||||
return newCodeBlock->compileExec(NULL, buffer, false);
|
||||
}
|
||||
|
||||
const char *execute(S32 argc, const char *argv[])
|
||||
{
|
||||
Namespace::Entry *ent;
|
||||
StringTableEntry funcName = StringTable->insert(argv[0]);
|
||||
ent = Namespace::global()->lookup(funcName);
|
||||
|
||||
if(!ent)
|
||||
{
|
||||
warnf(ConsoleLogEntry::Script, "%s: Unknown command.", argv[0]);
|
||||
return "";
|
||||
}
|
||||
return ent->execute(argc, argv, &gEvalState);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char *execute(SimObject *object, S32 argc, const char *argv[])
|
||||
{
|
||||
static char idBuf[12];
|
||||
if(argc < 2)
|
||||
return "";
|
||||
if(object->getNamespace())
|
||||
{
|
||||
dSprintf(idBuf, sizeof(idBuf), "%d", object->getId());
|
||||
argv[1] = idBuf;
|
||||
|
||||
StringTableEntry funcName = StringTable->insert(argv[0]);
|
||||
Namespace::Entry *ent = object->getNamespace()->lookup(funcName);
|
||||
|
||||
if(!ent)
|
||||
{
|
||||
//warnf(ConsoleLogEntry::Script, "%s: undefined for object '%s' - id %d", funcName, object->getName(), object->getId());
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
SimObject *save = gEvalState.thisObject;
|
||||
gEvalState.thisObject = object;
|
||||
const char *ret = ent->execute(argc, argv, &gEvalState);
|
||||
gEvalState.thisObject = save;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
warnf(ConsoleLogEntry::Script, "Con::execute - %d has no namespace: %s", object->getId(), argv[0]);
|
||||
return "";
|
||||
}
|
||||
|
||||
const char *executef(SimObject *object, S32 argc, ...)
|
||||
{
|
||||
static char idBuf[12];
|
||||
const char *argv[128];
|
||||
|
||||
va_list args;
|
||||
va_start(args, argc);
|
||||
for(S32 i = 0; i < argc; i++)
|
||||
argv[i+1] = va_arg(args, const char *);
|
||||
va_end(args);
|
||||
argv[0] = argv[1];
|
||||
argc++;
|
||||
|
||||
return execute(object, argc, argv);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char *executef(S32 argc, ...)
|
||||
{
|
||||
const char *argv[128];
|
||||
|
||||
va_list args;
|
||||
va_start(args, argc);
|
||||
for(S32 i = 0; i < argc; i++)
|
||||
argv[i] = va_arg(args, const char *);
|
||||
va_end(args);
|
||||
return execute(argc, argv);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool isFunction(const char *fn)
|
||||
{
|
||||
const char *string = StringTable->lookup(fn);
|
||||
if(!string)
|
||||
return false;
|
||||
else
|
||||
return Namespace::global()->lookup(string) != NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void setLogMode(S32 newMode)
|
||||
{
|
||||
if(newMode != consoleLogMode)
|
||||
{
|
||||
if(newMode && !consoleLogMode)
|
||||
newLogFile = true;
|
||||
if(consoleLogMode == 2)
|
||||
consoleLogFile.close();
|
||||
else if(newMode == 2)
|
||||
consoleLogFile.open(defLogFileName, FileStream::Write);
|
||||
consoleLogMode = newMode;
|
||||
}
|
||||
}
|
||||
|
||||
Namespace *lookupNamespace(const char *ns)
|
||||
{
|
||||
if(!ns)
|
||||
return Namespace::global();
|
||||
return Namespace::find(StringTable->insert(ns));
|
||||
}
|
||||
|
||||
void linkNamespaces(const char *parent, const char *child)
|
||||
{
|
||||
Namespace *pns = lookupNamespace(parent);
|
||||
Namespace *cns = lookupNamespace(child);
|
||||
if(pns && cns)
|
||||
cns->classLinkTo(pns);
|
||||
}
|
||||
|
||||
void classLinkNamespaces(Namespace *parent, Namespace *child)
|
||||
{
|
||||
if(parent && child)
|
||||
child->classLinkTo(parent);
|
||||
}
|
||||
|
||||
enum {
|
||||
MaxDataTypes = 256
|
||||
};
|
||||
|
||||
static S32 typeSizes[MaxDataTypes];
|
||||
static GetDataFunction fnGetData[MaxDataTypes];
|
||||
static SetDataFunction fnSetData[MaxDataTypes];
|
||||
|
||||
void registerType(S32 type, S32 size, GetDataFunction gdf, SetDataFunction sdf)
|
||||
{
|
||||
fnGetData[type] = gdf;
|
||||
fnSetData[type] = sdf;
|
||||
typeSizes[type] = size;
|
||||
}
|
||||
|
||||
void setData(S32 type, void *dptr, S32 index, S32 argc, const char **argv, EnumTable *tbl, BitSet32 flag)
|
||||
{
|
||||
SetDataFunction fn = fnSetData[type];
|
||||
AssertFatal(fn != NULL, "Error, mull setData fn");
|
||||
fn((void *) (U32(dptr) + index * typeSizes[type]),argc, argv, tbl, flag);
|
||||
}
|
||||
|
||||
const char *getData(S32 type, void *dptr, S32 index, EnumTable *tbl, BitSet32 flag)
|
||||
{
|
||||
GetDataFunction fn = fnGetData[type];
|
||||
AssertFatal(fn != NULL, "Error, mull getData fn");
|
||||
return fn((void *) (U32(dptr) + index * typeSizes[type]), tbl, flag);
|
||||
}
|
||||
|
||||
} // end of Console namespace
|
||||
199
console/console.h
Normal file
199
console/console.h
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CONSOLE_H_
|
||||
#define _CONSOLE_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "Platform/platform.h"
|
||||
#endif
|
||||
#ifndef _BITSET_H_
|
||||
#include "Core/bitSet.h"
|
||||
#endif
|
||||
|
||||
class SimObject;
|
||||
struct EnumTable;
|
||||
class Namespace;
|
||||
|
||||
enum
|
||||
{
|
||||
StringTagPrefixByte = 0x01
|
||||
};
|
||||
|
||||
struct ConsoleLogEntry
|
||||
{
|
||||
enum Level
|
||||
{
|
||||
Normal = 0,
|
||||
Warning,
|
||||
Error,
|
||||
NUM_CLASS
|
||||
} mLevel;
|
||||
enum Type
|
||||
{
|
||||
General = 0,
|
||||
Assert,
|
||||
Script,
|
||||
GUI,
|
||||
Network,
|
||||
NUM_TYPE
|
||||
} mType;
|
||||
const char *mString;
|
||||
};
|
||||
|
||||
struct EnumTable
|
||||
{
|
||||
S32 size;
|
||||
|
||||
struct Enums
|
||||
{
|
||||
S32 index;
|
||||
const char *label;
|
||||
};
|
||||
|
||||
Enums *table;
|
||||
EnumTable(S32 sSize, Enums *sTable)
|
||||
{ size = sSize; table = sTable; }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
typedef const char *StringTableEntry;
|
||||
typedef const char *(*StringCallback)(SimObject *obj, S32 argc, const char *argv[]);
|
||||
typedef S32 (*IntCallback)(SimObject *obj, S32 argc, const char *argv[]);
|
||||
typedef F32 (*FloatCallback)(SimObject *obj, S32 argc, const char *argv[]);
|
||||
typedef void (*VoidCallback)(SimObject *obj, S32 argc, const char *argv[]);
|
||||
typedef bool (*BoolCallback)(SimObject *obj, S32 argc, const char *argv[]);
|
||||
typedef void (*ConsumerCallback)(ConsoleLogEntry::Level level, const char *consoleLine);
|
||||
|
||||
typedef const char* (*GetDataFunction)(void *dptr, EnumTable *tbl, BitSet32 flag);
|
||||
typedef void (*SetDataFunction)(void *dptr, S32 argc, const char **argv, EnumTable *tbl, BitSet32 flag);
|
||||
|
||||
|
||||
namespace Con
|
||||
{
|
||||
enum {
|
||||
MaxLineLength = 512
|
||||
};
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
bool isActive();
|
||||
|
||||
void addConsumer(ConsumerCallback cb);
|
||||
void removeConsumer(ConsumerCallback cb);
|
||||
|
||||
void setVariable(const char *name, const char *value);
|
||||
bool addVariable(const char *name, S32, void *);
|
||||
bool removeVariable(const char *name);
|
||||
const char* getVariable(const char* name);
|
||||
const char* getLocalVariable(const char* name);
|
||||
void setLocalVariable(const char *name, const char *value);
|
||||
|
||||
void addCommand(const char *name, StringCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(const char *name, IntCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(const char *name, FloatCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(const char *name, VoidCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(const char *name, BoolCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
|
||||
void addCommand(const char *nameSpace, const char *name,StringCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(const char *nameSpace, const char *name,IntCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(const char *nameSpace, const char *name,FloatCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(const char *nameSpace, const char *name,VoidCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(const char *nameSpace, const char *name,BoolCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
|
||||
bool removeCommand(const char *name);
|
||||
void printf(const char *_format, ...);
|
||||
void warnf(ConsoleLogEntry::Type type, const char *_format, ...);
|
||||
void errorf(ConsoleLogEntry::Type type, const char *_format, ...);
|
||||
void warnf(const char *_format, ...);
|
||||
void errorf(const char *_format, ...);
|
||||
|
||||
const char *execute(S32 argc, const char* argv[]);
|
||||
const char *executef(S32 argc, ...); // first param is funcName, remaining params are args
|
||||
|
||||
// first param is func name, second param MUST be empty (gets filled with object ID)
|
||||
// also, MUST have at least those two params
|
||||
const char *execute(SimObject *, S32 argc, const char *argv[]);
|
||||
|
||||
const char *executef(SimObject *, S32 argc, ...); // first param is funcName, remaining params are args
|
||||
|
||||
const char *evaluate(const char* string, bool echo = false, const char *fileName = NULL);
|
||||
const char *evaluatef(const char* string, ...);
|
||||
|
||||
bool isFunction(const char *fn);
|
||||
|
||||
void setBoolVariable(const char* name,bool var);
|
||||
bool getBoolVariable(const char* name,bool def = false);
|
||||
void setIntVariable(const char* name,S32 var);
|
||||
S32 getIntVariable(const char* name,S32 def = 0);
|
||||
void setFloatVariable(const char* name,F32 var);
|
||||
F32 getFloatVariable(const char* name,F32 def = .0f);
|
||||
|
||||
// console function implementation helpers
|
||||
char *getReturnBuffer(U32 bufferSize);
|
||||
|
||||
char *getArgBuffer(U32 bufferSize);
|
||||
char *getFloatArg(F64 arg);
|
||||
char *getIntArg(S32 arg);
|
||||
|
||||
|
||||
const char *tabComplete(const char *prevText, S32 baseLen, bool);
|
||||
void exportVariables(const char *varString, Vector<const char *> &varName, Vector<const char *> &value);
|
||||
|
||||
Namespace *lookupNamespace(const char *nsName);
|
||||
void linkNamespaces(const char *parentName, const char *childName);
|
||||
|
||||
// this should only be called from consoleObject.h
|
||||
void classLinkNamespaces(Namespace *parent, Namespace *child);
|
||||
|
||||
void getLog(ConsoleLogEntry * &log, U32 &size);
|
||||
// dynamic data management functions:
|
||||
void setLogMode(S32 mode);
|
||||
|
||||
void registerType(S32 type, S32 size, GetDataFunction gdf, SetDataFunction sdf);
|
||||
void setData(S32 type, void *dptr, S32 index, S32 argc, const char **argv, EnumTable *tbl = NULL, BitSet32 flag = 0);
|
||||
const char *getData(S32 type, void *dptr, S32 index, EnumTable *tbl = NULL, BitSet32 flag = 0);
|
||||
}
|
||||
|
||||
extern void expandEscape(char *dest, const char *src);
|
||||
extern bool collapseEscape(char *buf);
|
||||
extern S32 HashPointer(StringTableEntry ptr);
|
||||
|
||||
struct ConsoleConstructor
|
||||
{
|
||||
StringCallback sc;
|
||||
IntCallback ic;
|
||||
FloatCallback fc;
|
||||
VoidCallback vc;
|
||||
BoolCallback bc;
|
||||
S32 mina, maxa;
|
||||
const char *usage;
|
||||
const char *funcName;
|
||||
const char *className;
|
||||
ConsoleConstructor *next;
|
||||
static ConsoleConstructor *first;
|
||||
|
||||
void init(const char *cName, const char *fName, const char *usg, S32 minArgs, S32 maxArgs);
|
||||
static void setup();
|
||||
ConsoleConstructor(const char *className, const char *funcName, StringCallback sfunc, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
ConsoleConstructor(const char *className, const char *funcName, IntCallback ifunc, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
ConsoleConstructor(const char *className, const char *funcName, FloatCallback ffunc, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
ConsoleConstructor(const char *className, const char *funcName, VoidCallback vfunc, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
ConsoleConstructor(const char *className, const char *funcName, BoolCallback bfunc, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
};
|
||||
|
||||
#define ConsoleFunction(name,returnType,minArgs,maxArgs,usage) \
|
||||
static returnType c##name(SimObject *, S32, const char **argv); \
|
||||
static ConsoleConstructor g##name##obj(NULL,#name,c##name,usage,minArgs,maxArgs);\
|
||||
static returnType c##name(SimObject *, S32 argc, const char **argv)
|
||||
|
||||
#define ConsoleMethod(className,name,returnType,minArgs,maxArgs,usage) \
|
||||
static returnType c##className##name(SimObject *, S32, const char **argv); \
|
||||
static ConsoleConstructor className##name##obj(#className,#name,c##className##name,usage,minArgs,maxArgs);\
|
||||
static returnType c##className##name(SimObject *object, S32 argc, const char **argv)
|
||||
|
||||
#endif
|
||||
136
console/consoleDoc.cc
Normal file
136
console/consoleDoc.cc
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
|
||||
#include "platform/platform.h"
|
||||
#include "console/console.h"
|
||||
|
||||
#include "console/ast.h"
|
||||
#include "core/tAlgorithm.h"
|
||||
#include "core/resManager.h"
|
||||
|
||||
#include "core/findMatch.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "console/consoleObject.h"
|
||||
#include "core/fileStream.h"
|
||||
#include "console/compiler.h"
|
||||
|
||||
ConsoleFunction(dumpConsoleClasses, void, 1, 1, "()dumps all declared console classes to the console in C++ syntax for documenting with dOxygen or another auto documentation tool")
|
||||
{
|
||||
Namespace::dumpClasses();
|
||||
}
|
||||
|
||||
const char *typeNames[] = {
|
||||
"Script",
|
||||
"string",
|
||||
"int",
|
||||
"float",
|
||||
"void",
|
||||
"bool",
|
||||
};
|
||||
|
||||
void Namespace::dumpClasses()
|
||||
{
|
||||
Vector<Namespace *> vec;
|
||||
// the program
|
||||
trashCache();
|
||||
|
||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
||||
walk->mHashSequence = 0;
|
||||
|
||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
||||
{
|
||||
Vector<Namespace *> stack;
|
||||
Namespace *parentWalk = walk;
|
||||
while(parentWalk)
|
||||
{
|
||||
if(parentWalk->mHashSequence != 0)
|
||||
break;
|
||||
if(parentWalk->mPackage == 0)
|
||||
{
|
||||
parentWalk->mHashSequence = 1;
|
||||
stack.push_back(parentWalk);
|
||||
}
|
||||
parentWalk = parentWalk->mParent;
|
||||
}
|
||||
while(stack.size())
|
||||
{
|
||||
vec.push_back(stack[stack.size() - 1]);
|
||||
stack.pop_back();
|
||||
}
|
||||
}
|
||||
U32 i;
|
||||
for(i = 0; i < vec.size(); i++)
|
||||
{
|
||||
const char *className = vec[i]->mName;
|
||||
const char *superClassName = vec[i]->mParent ? vec[i]->mParent->mName : NULL;
|
||||
const char *virt = "virtual ";
|
||||
if(vec[i]->mEntryList == NULL && vec[i]->mClassRep == NULL)
|
||||
continue;
|
||||
|
||||
if(!className)
|
||||
{
|
||||
Con::printf("namespace Global {");
|
||||
virt = "";
|
||||
}
|
||||
else if(!superClassName)
|
||||
Con::printf("class %s { public:", className);
|
||||
else
|
||||
Con::printf("class %s : public %s { public:", className, superClassName);
|
||||
|
||||
|
||||
for(Entry *ewalk = vec[i]->mEntryList; ewalk; ewalk = ewalk->mNext)
|
||||
{
|
||||
char buffer[1024];
|
||||
if(ewalk->mType > Entry::ScriptFunctionType)
|
||||
{
|
||||
if(ewalk->mUsage[0] != '(')
|
||||
Con::printf(" %s %s %s() {} // %s", virt, typeNames[ewalk->mType], ewalk->mFunctionName, ewalk->mUsage);
|
||||
else
|
||||
{
|
||||
const char *use = ewalk->mUsage;
|
||||
const char *end = dStrchr(use, ')');
|
||||
if(!end)
|
||||
end = use + 1;
|
||||
use++;
|
||||
U32 len = end - use;
|
||||
dStrncpy(buffer, use, len);
|
||||
buffer[len] = 0;
|
||||
Con::printf(" %s %s %s(%s) {} // %s", virt, typeNames[ewalk->mType], ewalk->mFunctionName, buffer, end + 1);
|
||||
}
|
||||
}
|
||||
else if(ewalk->mFunctionOffset)
|
||||
{
|
||||
ewalk->mCode->getFunctionArgs(buffer, ewalk->mFunctionOffset);
|
||||
Con::printf(" %s void %s(%s) {} // declared script function", virt, ewalk->mFunctionName, buffer);
|
||||
}
|
||||
}
|
||||
AbstractClassRep *rep = vec[i]->mClassRep;
|
||||
AbstractClassRep::FieldList emptyList;
|
||||
AbstractClassRep::FieldList *parentList = &emptyList;
|
||||
AbstractClassRep::FieldList *fieldList = &emptyList;
|
||||
|
||||
if(rep)
|
||||
{
|
||||
AbstractClassRep *parentRep = vec[i]->mParent ? vec[i]->mParent->mClassRep : NULL;
|
||||
if(parentRep)
|
||||
parentList = &(parentRep->mFieldList);
|
||||
fieldList = &(rep->mFieldList);
|
||||
for(U32 j = 0; j < fieldList->size(); j++)
|
||||
{
|
||||
if((*fieldList)[j].type == AbstractClassRep::DepricatedFieldType)
|
||||
continue;
|
||||
|
||||
bool found = false;
|
||||
for(U32 k = 0; k < parentList->size(); k++)
|
||||
{
|
||||
if((*parentList)[k].pFieldname == (*fieldList)[j].pFieldname)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
Con::printf(" %s %s;", Con::getTypeName((*fieldList)[j].type), (*fieldList)[j].pFieldname);
|
||||
}
|
||||
}
|
||||
Con::printf("};");
|
||||
}
|
||||
}
|
||||
1110
console/consoleFunctions.cc
Normal file
1110
console/consoleFunctions.cc
Normal file
File diff suppressed because it is too large
Load diff
943
console/consoleInternal.cc
Normal file
943
console/consoleInternal.cc
Normal file
|
|
@ -0,0 +1,943 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "console/console.h"
|
||||
|
||||
#include "console/ast.h"
|
||||
#include "core/tAlgorithm.h"
|
||||
#include "core/resManager.h"
|
||||
|
||||
#include "core/findMatch.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "core/fileStream.h"
|
||||
#include "console/compiler.h"
|
||||
|
||||
#define ST_INIT_SIZE 15
|
||||
|
||||
static char scratchBuffer[1024];
|
||||
U32 Namespace::mCacheSequence = 0;
|
||||
DataChunker Namespace::mCacheAllocator;
|
||||
DataChunker Namespace::mAllocator;
|
||||
Namespace *Namespace::mNamespaceList = NULL;
|
||||
Namespace *Namespace::mGlobalNamespace = NULL;
|
||||
|
||||
bool canTabComplete(const char *prevText, const char *bestMatch,
|
||||
const char *newText, S32 baseLen, bool fForward)
|
||||
{
|
||||
// test if it matches the first baseLen chars:
|
||||
if(dStrnicmp(newText, prevText, baseLen))
|
||||
return false;
|
||||
|
||||
if (fForward)
|
||||
{
|
||||
if(!bestMatch)
|
||||
return dStricmp(newText, prevText) > 0;
|
||||
else
|
||||
return (dStricmp(newText, prevText) > 0) &&
|
||||
(dStricmp(newText, bestMatch) < 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dStrlen(prevText) == (U32) baseLen)
|
||||
{
|
||||
// look for the 'worst match'
|
||||
if(!bestMatch)
|
||||
return dStricmp(newText, prevText) > 0;
|
||||
else
|
||||
return dStricmp(newText, bestMatch) > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bestMatch)
|
||||
return (dStricmp(newText, prevText) < 0);
|
||||
else
|
||||
return (dStricmp(newText, prevText) < 0) &&
|
||||
(dStricmp(newText, bestMatch) > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
//
|
||||
// Dictionary functions
|
||||
//
|
||||
//---------------------------------------------------------------
|
||||
struct StringValue
|
||||
{
|
||||
S32 size;
|
||||
char *val;
|
||||
|
||||
operator char *() { return val; }
|
||||
StringValue &operator=(const char *string);
|
||||
|
||||
StringValue() { size = 0; val = NULL; }
|
||||
~StringValue() { dFree(val); }
|
||||
};
|
||||
|
||||
|
||||
StringValue & StringValue::operator=(const char *string)
|
||||
{
|
||||
if(!val)
|
||||
{
|
||||
val = dStrdup(string);
|
||||
size = dStrlen(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 len = dStrlen(string);
|
||||
if(len < size)
|
||||
dStrcpy(val, string);
|
||||
else
|
||||
{
|
||||
size = len;
|
||||
dFree(val);
|
||||
val = dStrdup(string);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
static S32 QSORT_CALLBACK varCompare(const void* a,const void* b)
|
||||
{
|
||||
return dStricmp( (*((Dictionary::Entry **) a))->name, (*((Dictionary::Entry **) b))->name );
|
||||
}
|
||||
|
||||
void Dictionary::exportVariables(const char *varString, const char *fileName, bool append)
|
||||
{
|
||||
const char *searchStr = varString;
|
||||
Vector<Entry *> sortList(__FILE__, __LINE__);
|
||||
|
||||
for(S32 i = 0; i < hashTableSize;i ++)
|
||||
{
|
||||
Entry *walk = hashTable[i];
|
||||
while(walk)
|
||||
{
|
||||
if(FindMatch::isMatch((char *) searchStr, (char *) walk->name))
|
||||
sortList.push_back(walk);
|
||||
|
||||
walk = walk->nextEntry;
|
||||
}
|
||||
}
|
||||
|
||||
if(!sortList.size())
|
||||
return;
|
||||
|
||||
dQsort((void *) &sortList[0], sortList.size(), sizeof(Entry *), varCompare);
|
||||
|
||||
Vector<Entry *>::iterator s;
|
||||
char expandBuffer[1024];
|
||||
FileStream strm;
|
||||
|
||||
if(fileName)
|
||||
{
|
||||
if(!ResourceManager->openFileForWrite(strm, ResourceManager->getBasePath(), fileName, append ? FileStream::ReadWrite : FileStream::Write))
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::General, "Unable to open file '%s for writing.", fileName);
|
||||
return;
|
||||
}
|
||||
if(append)
|
||||
strm.setPosition(strm.getStreamSize());
|
||||
}
|
||||
|
||||
char buffer[1024];
|
||||
const char *cat = fileName ? "\r\n" : "";
|
||||
|
||||
for(s = sortList.begin(); s != sortList.end(); s++)
|
||||
{
|
||||
switch((*s)->type)
|
||||
{
|
||||
case Entry::TypeInternalInt:
|
||||
dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->ival, cat);
|
||||
break;
|
||||
case Entry::TypeInternalFloat:
|
||||
dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->fval, cat);
|
||||
break;
|
||||
default:
|
||||
expandEscape(expandBuffer, (*s)->getStringValue());
|
||||
dSprintf(buffer, sizeof(buffer), "%s = \"%s\";%s", (*s)->name, expandBuffer, cat);
|
||||
break;
|
||||
}
|
||||
if(fileName)
|
||||
strm.write(dStrlen(buffer), buffer);
|
||||
else
|
||||
Con::printf("%s", buffer);
|
||||
}
|
||||
if(fileName)
|
||||
strm.close();
|
||||
}
|
||||
|
||||
void Dictionary::deleteVariables(const char *varString)
|
||||
{
|
||||
const char *searchStr = varString;
|
||||
|
||||
for(S32 i = 0; i < hashTableSize; i++)
|
||||
{
|
||||
Entry *walk = hashTable[i];
|
||||
while(walk)
|
||||
{
|
||||
Entry *matchedEntry = (FindMatch::isMatch((char *) searchStr, (char *) walk->name)) ? walk : NULL;
|
||||
walk = walk->nextEntry;
|
||||
if (matchedEntry)
|
||||
remove(matchedEntry); // assumes remove() is a stable remove (will not reorder entries on remove)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
S32 HashPointer(StringTableEntry ptr)
|
||||
{
|
||||
return S32(U32(ptr) >> 2);
|
||||
}
|
||||
|
||||
Dictionary::Entry *Dictionary::lookup(StringTableEntry name)
|
||||
{
|
||||
Entry *walk = hashTable[HashPointer(name) % hashTableSize];
|
||||
while(walk)
|
||||
{
|
||||
if(walk->name == name)
|
||||
return walk;
|
||||
else
|
||||
walk = walk->nextEntry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Dictionary::Entry *Dictionary::add(StringTableEntry name)
|
||||
{
|
||||
Entry *walk = hashTable[HashPointer(name) % hashTableSize];
|
||||
while(walk)
|
||||
{
|
||||
if(walk->name == name)
|
||||
return walk;
|
||||
else
|
||||
walk = walk->nextEntry;
|
||||
}
|
||||
Entry *ret;
|
||||
entryCount++;
|
||||
|
||||
if(entryCount > hashTableSize * 2)
|
||||
{
|
||||
Entry head(NULL), *walk;
|
||||
S32 i;
|
||||
walk = &head;
|
||||
walk->nextEntry = 0;
|
||||
for(i = 0; i < hashTableSize; i++) {
|
||||
while(walk->nextEntry) {
|
||||
walk = walk->nextEntry;
|
||||
}
|
||||
walk->nextEntry = hashTable[i];
|
||||
}
|
||||
delete[] hashTable;
|
||||
hashTableSize = hashTableSize * 4 - 1;
|
||||
hashTable = new Entry *[hashTableSize];
|
||||
for(i = 0; i < hashTableSize; i++)
|
||||
hashTable[i] = NULL;
|
||||
walk = head.nextEntry;
|
||||
while(walk)
|
||||
{
|
||||
Entry *temp = walk->nextEntry;
|
||||
S32 idx = HashPointer(walk->name) % hashTableSize;
|
||||
walk->nextEntry = hashTable[idx];
|
||||
hashTable[idx] = walk;
|
||||
walk = temp;
|
||||
}
|
||||
}
|
||||
|
||||
ret = new Entry(name);
|
||||
S32 idx = HashPointer(name) % hashTableSize;
|
||||
ret->nextEntry = hashTable[idx];
|
||||
hashTable[idx] = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// deleteVariables() assumes remove() is a stable remove (will not reorder entries on remove)
|
||||
void Dictionary::remove(Dictionary::Entry *ent)
|
||||
{
|
||||
Entry **walk = &hashTable[HashPointer(ent->name) % hashTableSize];
|
||||
while(*walk != ent)
|
||||
walk = &((*walk)->nextEntry);
|
||||
|
||||
*walk = (ent->nextEntry);
|
||||
delete ent;
|
||||
entryCount--;
|
||||
}
|
||||
|
||||
|
||||
Dictionary::Dictionary(ExprEvalState *state)
|
||||
{
|
||||
setState(state);
|
||||
}
|
||||
|
||||
void Dictionary::setState(ExprEvalState *state)
|
||||
{
|
||||
S32 i;
|
||||
entryCount = 0;
|
||||
exprState = state;
|
||||
hashTableSize = ST_INIT_SIZE;
|
||||
hashTable = new Entry *[hashTableSize];
|
||||
|
||||
for(i = 0; i < hashTableSize; i++)
|
||||
hashTable[i] = NULL;
|
||||
}
|
||||
|
||||
Dictionary::~Dictionary()
|
||||
{
|
||||
reset();
|
||||
delete [] hashTable;
|
||||
}
|
||||
|
||||
void Dictionary::reset()
|
||||
{
|
||||
S32 i;
|
||||
Entry *walk, *temp;
|
||||
|
||||
for(i = 0; i < hashTableSize; i++)
|
||||
{
|
||||
walk = hashTable[i];
|
||||
while(walk)
|
||||
{
|
||||
temp = walk->nextEntry;
|
||||
delete walk;
|
||||
walk = temp;
|
||||
}
|
||||
hashTable[i] = NULL;
|
||||
}
|
||||
hashTableSize = ST_INIT_SIZE;
|
||||
entryCount = 0;
|
||||
}
|
||||
|
||||
|
||||
const char *Dictionary::tabComplete(const char *prevText, S32 baseLen, bool fForward)
|
||||
{
|
||||
S32 i;
|
||||
|
||||
const char *bestMatch = NULL;
|
||||
for(i = 0; i < hashTableSize; i++)
|
||||
{
|
||||
Entry *walk = hashTable[i];
|
||||
while(walk)
|
||||
{
|
||||
if(canTabComplete(prevText, bestMatch, walk->name, baseLen, fForward))
|
||||
bestMatch = walk->name;
|
||||
walk = walk->nextEntry;
|
||||
}
|
||||
}
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
|
||||
char *typeValueEmpty = "";
|
||||
|
||||
Dictionary::Entry::Entry(StringTableEntry in_name)
|
||||
{
|
||||
dataPtr = NULL;
|
||||
name = in_name;
|
||||
type = -1;
|
||||
ival = 0;
|
||||
fval = 0;
|
||||
sval = typeValueEmpty;
|
||||
}
|
||||
|
||||
Dictionary::Entry::~Entry()
|
||||
{
|
||||
if(sval != typeValueEmpty)
|
||||
dFree(sval);
|
||||
}
|
||||
|
||||
struct InternalPoint3F { F32 x,y,z; InternalPoint3F(F32 F){x=y=z=F;} };
|
||||
|
||||
const char *Dictionary::getVariable(StringTableEntry name, bool *entValid)
|
||||
{
|
||||
Entry *ent = lookup(name);
|
||||
if(ent)
|
||||
{
|
||||
if(entValid)
|
||||
*entValid = true;
|
||||
return ent->getStringValue();
|
||||
}
|
||||
if(entValid)
|
||||
*entValid = false;
|
||||
return "";
|
||||
}
|
||||
|
||||
void Dictionary::Entry::setStringValue(const char * value)
|
||||
{
|
||||
if(type <= TypeInternalString)
|
||||
{
|
||||
if(!value[0] && name[0] == '$')
|
||||
{
|
||||
gEvalState.globalVars.remove(this);
|
||||
return;
|
||||
}
|
||||
fval = dAtof(value);
|
||||
ival = fval;
|
||||
type = TypeInternalString;
|
||||
|
||||
// may as well add to the next cache line
|
||||
U32 newLen = ((dStrlen(value) + 1) + 15) & ~15;
|
||||
if(sval == typeValueEmpty)
|
||||
sval = (char *) dMalloc(newLen);
|
||||
else if(newLen > bufferLen)
|
||||
sval = (char *) dRealloc(sval, newLen);
|
||||
bufferLen = newLen;
|
||||
dStrcpy(sval, value);
|
||||
}
|
||||
else
|
||||
Con::setData(type, dataPtr, 0, 1, &value);
|
||||
}
|
||||
|
||||
void Dictionary::setVariable(StringTableEntry name, const char *value)
|
||||
{
|
||||
Entry *ent = add(name);
|
||||
if(!value)
|
||||
value = "";
|
||||
ent->setStringValue(value);
|
||||
}
|
||||
|
||||
void Dictionary::addVariable(const char *name, S32 type, void *dataPtr)
|
||||
{
|
||||
if(name[0] != '$')
|
||||
{
|
||||
scratchBuffer[0] = '$';
|
||||
dStrcpy(scratchBuffer + 1, name);
|
||||
name = scratchBuffer;
|
||||
}
|
||||
Entry *ent = add(StringTable->insert(name));
|
||||
ent->type = type;
|
||||
if(ent->sval != typeValueEmpty)
|
||||
{
|
||||
dFree(ent->sval);
|
||||
ent->sval = typeValueEmpty;
|
||||
}
|
||||
ent->dataPtr = dataPtr;
|
||||
}
|
||||
|
||||
bool Dictionary::removeVariable(StringTableEntry name)
|
||||
{
|
||||
if( Entry *ent = lookup(name) ){
|
||||
remove( ent );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ExprEvalState::pushFrame(StringTableEntry frameName, Namespace *ns)
|
||||
{
|
||||
Dictionary *newFrame = new Dictionary(this);
|
||||
newFrame->scopeName = frameName;
|
||||
newFrame->scopeNamespace = ns;
|
||||
stack.push_back(newFrame);
|
||||
}
|
||||
|
||||
void ExprEvalState::popFrame()
|
||||
{
|
||||
Dictionary *last = stack.last();
|
||||
stack.pop_back();
|
||||
delete last;
|
||||
}
|
||||
|
||||
ExprEvalState::ExprEvalState()
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(stack);
|
||||
globalVars.setState(this);
|
||||
thisObject = NULL;
|
||||
traceOn = false;
|
||||
}
|
||||
|
||||
ExprEvalState::~ExprEvalState()
|
||||
{
|
||||
while(stack.size())
|
||||
popFrame();
|
||||
}
|
||||
|
||||
ConsoleFunction(backtrace, void, 1, 1, "backtrace();")
|
||||
{
|
||||
argc; argv;
|
||||
U32 totalSize = 1;
|
||||
|
||||
for(U32 i = 0; i < gEvalState.stack.size(); i++)
|
||||
{
|
||||
totalSize += dStrlen(gEvalState.stack[i]->scopeName) + 3;
|
||||
if(gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mName)
|
||||
totalSize += dStrlen(gEvalState.stack[i]->scopeNamespace->mName) + 2;
|
||||
}
|
||||
|
||||
char *buf = Con::getReturnBuffer(totalSize);
|
||||
buf[0] = 0;
|
||||
for(U32 i = 0; i < gEvalState.stack.size(); i++)
|
||||
{
|
||||
dStrcat(buf, "->");
|
||||
if(gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mName)
|
||||
{
|
||||
dStrcat(buf, gEvalState.stack[i]->scopeNamespace->mName);
|
||||
dStrcat(buf, "::");
|
||||
}
|
||||
dStrcat(buf, gEvalState.stack[i]->scopeName);
|
||||
}
|
||||
Con::printf("BackTrace: %s", buf);
|
||||
|
||||
}
|
||||
|
||||
Namespace::Entry::Entry()
|
||||
{
|
||||
mCode = NULL;
|
||||
mType = InvalidFunctionType;
|
||||
}
|
||||
|
||||
void Namespace::Entry::clear()
|
||||
{
|
||||
if(mCode)
|
||||
{
|
||||
mCode->decRefCount();
|
||||
mCode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Namespace::Namespace()
|
||||
{
|
||||
mPackage = NULL;
|
||||
mName = NULL;
|
||||
mParent = NULL;
|
||||
mNext = NULL;
|
||||
mEntryList = NULL;
|
||||
mHashSize = 0;
|
||||
mHashTable = 0;
|
||||
mHashSequence = 0;
|
||||
mRefCountToParent = 0;
|
||||
}
|
||||
|
||||
void Namespace::clearEntries()
|
||||
{
|
||||
for(Entry *walk = mEntryList; walk; walk = walk->mNext)
|
||||
walk->clear();
|
||||
}
|
||||
|
||||
Namespace *Namespace::find(StringTableEntry name, StringTableEntry package)
|
||||
{
|
||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
||||
if(walk->mName == name && walk->mPackage == package)
|
||||
return walk;
|
||||
|
||||
Namespace *ret = (Namespace *) mAllocator.alloc(sizeof(Namespace));
|
||||
constructInPlace(ret);
|
||||
ret->mPackage = package;
|
||||
ret->mName = name;
|
||||
ret->mNext = mNamespaceList;
|
||||
mNamespaceList = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Namespace::classLinkTo(Namespace *parent)
|
||||
{
|
||||
Namespace *walk = this;
|
||||
while(walk->mParent && walk->mParent->mName == mName)
|
||||
walk = walk->mParent;
|
||||
|
||||
if(walk->mParent && walk->mParent != parent)
|
||||
{
|
||||
AssertFatal(0, avar("ERROR: Attempting to re-link namespace %s from %s to %s with non-zero refcount.", walk->mName, walk->mParent->mName, parent->mName));
|
||||
Con::errorf(ConsoleLogEntry::General, "Attempting to re-link namespace %s from %s to %s with non-zero refcount.",
|
||||
walk->mName, walk->mParent->mName, parent->mName);
|
||||
return;
|
||||
}
|
||||
mRefCountToParent++;
|
||||
walk->mParent = parent;
|
||||
}
|
||||
|
||||
void Namespace::buildHashTable()
|
||||
{
|
||||
if(mHashSequence == mCacheSequence)
|
||||
return;
|
||||
if(!mEntryList && mParent)
|
||||
{
|
||||
mParent->buildHashTable();
|
||||
mHashTable = mParent->mHashTable;
|
||||
mHashSize = mParent->mHashSize;
|
||||
mHashSequence = mCacheSequence;
|
||||
return;
|
||||
}
|
||||
U32 entryCount = 0;
|
||||
Namespace * ns;
|
||||
for(ns = this; ns; ns = ns->mParent)
|
||||
for(Entry *walk = ns->mEntryList; walk; walk = walk->mNext)
|
||||
if(lookupRecursive(walk->mFunctionName) == walk)
|
||||
entryCount++;
|
||||
|
||||
mHashSize = entryCount + (entryCount >> 1) + 1;
|
||||
if(!(mHashSize &1))
|
||||
mHashSize++;
|
||||
mHashTable = (Entry **) mCacheAllocator.alloc(sizeof(Entry *) * mHashSize);
|
||||
for(U32 i = 0; i < mHashSize; i++)
|
||||
mHashTable[i] = NULL;
|
||||
|
||||
for(ns = this; ns; ns = ns->mParent)
|
||||
{
|
||||
for(Entry *walk = ns->mEntryList; walk; walk = walk->mNext)
|
||||
{
|
||||
U32 index = HashPointer(walk->mFunctionName) % mHashSize;
|
||||
while(mHashTable[index] && mHashTable[index]->mFunctionName != walk->mFunctionName)
|
||||
{
|
||||
index++;
|
||||
if(index >= mHashSize)
|
||||
index = 0;
|
||||
}
|
||||
if(!mHashTable[index])
|
||||
mHashTable[index] = walk;
|
||||
}
|
||||
}
|
||||
mHashSequence = mCacheSequence;
|
||||
}
|
||||
|
||||
void Namespace::init()
|
||||
{
|
||||
// create the global namespace
|
||||
mGlobalNamespace = find(NULL);
|
||||
}
|
||||
|
||||
Namespace *Namespace::global()
|
||||
{
|
||||
return mGlobalNamespace;
|
||||
}
|
||||
|
||||
void Namespace::shutdown()
|
||||
{
|
||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
||||
walk->clearEntries();
|
||||
}
|
||||
|
||||
void Namespace::trashCache()
|
||||
{
|
||||
mCacheSequence++;
|
||||
mCacheAllocator.freeBlocks();
|
||||
}
|
||||
|
||||
const char *Namespace::tabComplete(const char *prevText, S32 baseLen, bool fForward)
|
||||
{
|
||||
if(mHashSequence != mCacheSequence)
|
||||
buildHashTable();
|
||||
|
||||
const char *bestMatch = NULL;
|
||||
for(U32 i = 0; i < mHashSize; i++)
|
||||
if(mHashTable[i] && canTabComplete(prevText, bestMatch, mHashTable[i]->mFunctionName, baseLen, fForward))
|
||||
bestMatch = mHashTable[i]->mFunctionName;
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
Namespace::Entry *Namespace::lookupRecursive(StringTableEntry name)
|
||||
{
|
||||
for(Namespace *ns = this; ns; ns = ns->mParent)
|
||||
for(Entry *walk = ns->mEntryList; walk; walk = walk->mNext)
|
||||
if(walk->mFunctionName == name)
|
||||
return walk;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Namespace::Entry *Namespace::lookup(StringTableEntry name)
|
||||
{
|
||||
if(mHashSequence != mCacheSequence)
|
||||
buildHashTable();
|
||||
|
||||
U32 index = HashPointer(name) % mHashSize;
|
||||
while(mHashTable[index] && mHashTable[index]->mFunctionName != name)
|
||||
{
|
||||
index++;
|
||||
if(index >= mHashSize)
|
||||
index = 0;
|
||||
}
|
||||
return mHashTable[index];
|
||||
}
|
||||
|
||||
static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b)
|
||||
{
|
||||
const Namespace::Entry* fa = *((Namespace::Entry**)a);
|
||||
const Namespace::Entry* fb = *((Namespace::Entry**)b);
|
||||
|
||||
return dStricmp(fa->mFunctionName, fb->mFunctionName);
|
||||
}
|
||||
|
||||
void Namespace::getEntryList(Vector<Entry *> *vec)
|
||||
{
|
||||
if(mHashSequence != mCacheSequence)
|
||||
buildHashTable();
|
||||
for(U32 i = 0; i < mHashSize; i++)
|
||||
if(mHashTable[i])
|
||||
vec->push_back(mHashTable[i]);
|
||||
dQsort(vec->address(),vec->size(),sizeof(Namespace::Entry *),compareEntries);
|
||||
}
|
||||
|
||||
Namespace::Entry *Namespace::createLocalEntry(StringTableEntry name)
|
||||
{
|
||||
for(Entry *walk = mEntryList; walk; walk = walk->mNext)
|
||||
{
|
||||
if(walk->mFunctionName == name)
|
||||
{
|
||||
walk->clear();
|
||||
return walk;
|
||||
}
|
||||
}
|
||||
Entry *ent = (Entry *) mAllocator.alloc(sizeof(Entry));
|
||||
constructInPlace(ent);
|
||||
|
||||
ent->mNamespace = this;
|
||||
ent->mFunctionName = name;
|
||||
ent->mNext = mEntryList;
|
||||
mEntryList = ent;
|
||||
return ent;
|
||||
}
|
||||
|
||||
void Namespace::addFunction(StringTableEntry name, CodeBlock *cb, U32 functionOffset)
|
||||
{
|
||||
Entry *ent = createLocalEntry(name);
|
||||
trashCache();
|
||||
|
||||
ent->mUsage = NULL;
|
||||
ent->mCode = cb;
|
||||
ent->mFunctionOffset = functionOffset;
|
||||
ent->mCode->incRefCount();
|
||||
ent->mType = Entry::ScriptFunctionType;
|
||||
}
|
||||
|
||||
void Namespace::addCommand(StringTableEntry name,StringCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Entry *ent = createLocalEntry(name);
|
||||
trashCache();
|
||||
|
||||
ent->mUsage = usage;
|
||||
ent->mMinArgs = minArgs;
|
||||
ent->mMaxArgs = maxArgs;
|
||||
|
||||
ent->mType = Entry::StringCallbackType;
|
||||
ent->cb.mStringCallbackFunc = cb;
|
||||
}
|
||||
|
||||
void Namespace::addCommand(StringTableEntry name,IntCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Entry *ent = createLocalEntry(name);
|
||||
trashCache();
|
||||
|
||||
ent->mUsage = usage;
|
||||
ent->mMinArgs = minArgs;
|
||||
ent->mMaxArgs = maxArgs;
|
||||
|
||||
ent->mType = Entry::IntCallbackType;
|
||||
ent->cb.mIntCallbackFunc = cb;
|
||||
}
|
||||
|
||||
void Namespace::addCommand(StringTableEntry name,VoidCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Entry *ent = createLocalEntry(name);
|
||||
trashCache();
|
||||
|
||||
ent->mUsage = usage;
|
||||
ent->mMinArgs = minArgs;
|
||||
ent->mMaxArgs = maxArgs;
|
||||
|
||||
ent->mType = Entry::VoidCallbackType;
|
||||
ent->cb.mVoidCallbackFunc = cb;
|
||||
}
|
||||
|
||||
void Namespace::addCommand(StringTableEntry name,FloatCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Entry *ent = createLocalEntry(name);
|
||||
trashCache();
|
||||
|
||||
ent->mUsage = usage;
|
||||
ent->mMinArgs = minArgs;
|
||||
ent->mMaxArgs = maxArgs;
|
||||
|
||||
ent->mType = Entry::FloatCallbackType;
|
||||
ent->cb.mFloatCallbackFunc = cb;
|
||||
}
|
||||
|
||||
void Namespace::addCommand(StringTableEntry name,BoolCallback cb, const char *usage, S32 minArgs, S32 maxArgs)
|
||||
{
|
||||
Entry *ent = createLocalEntry(name);
|
||||
trashCache();
|
||||
|
||||
ent->mUsage = usage;
|
||||
ent->mMinArgs = minArgs;
|
||||
ent->mMaxArgs = maxArgs;
|
||||
|
||||
ent->mType = Entry::BoolCallbackType;
|
||||
ent->cb.mBoolCallbackFunc = cb;
|
||||
}
|
||||
|
||||
extern S32 executeBlock(StmtNode *block, ExprEvalState *state);
|
||||
|
||||
const char *Namespace::Entry::execute(S32 argc, const char **argv, ExprEvalState *state)
|
||||
{
|
||||
if(mType == ScriptFunctionType)
|
||||
{
|
||||
if(mFunctionOffset)
|
||||
return mCode->exec(mFunctionOffset, argv[0], mNamespace, argc, argv, false);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
if((mMinArgs && argc < mMinArgs) || (mMaxArgs && argc > mMaxArgs))
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::Script, "%s::%s - wrong number of arguments.", mNamespace->mName, mFunctionName);
|
||||
Con::warnf(ConsoleLogEntry::Script, "usage: %s", mUsage);
|
||||
return "";
|
||||
}
|
||||
static char returnBuffer[32];
|
||||
switch(mType)
|
||||
{
|
||||
case StringCallbackType:
|
||||
return cb.mStringCallbackFunc(state->thisObject, argc, argv);
|
||||
case IntCallbackType:
|
||||
dSprintf(returnBuffer, sizeof(returnBuffer), "%d",
|
||||
cb.mIntCallbackFunc(state->thisObject, argc, argv));
|
||||
return returnBuffer;
|
||||
case FloatCallbackType:
|
||||
dSprintf(returnBuffer, sizeof(returnBuffer), "%g",
|
||||
cb.mFloatCallbackFunc(state->thisObject, argc, argv));
|
||||
return returnBuffer;
|
||||
case VoidCallbackType:
|
||||
cb.mVoidCallbackFunc(state->thisObject, argc, argv);
|
||||
return "";
|
||||
case BoolCallbackType:
|
||||
dSprintf(returnBuffer, sizeof(returnBuffer), "%d",
|
||||
(U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv));
|
||||
return returnBuffer;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
StringTableEntry Namespace::mActivePackages[Namespace::MaxActivePackages];
|
||||
U32 Namespace::mNumActivePackages = 0;
|
||||
U32 Namespace::mOldNumActivePackages = 0;
|
||||
|
||||
bool Namespace::isPackage(StringTableEntry name)
|
||||
{
|
||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
||||
if(walk->mPackage == name)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Namespace::activatePackage(StringTableEntry name)
|
||||
{
|
||||
if(mNumActivePackages == MaxActivePackages)
|
||||
{
|
||||
Con::printf("ActivatePackage(%s) failed - Max package limit reached: %d", name, MaxActivePackages);
|
||||
return;
|
||||
}
|
||||
if(!name)
|
||||
return;
|
||||
|
||||
// see if this one's already active
|
||||
for(U32 i = 0; i < mNumActivePackages; i++)
|
||||
if(mActivePackages[i] == name)
|
||||
return;
|
||||
|
||||
// kill the cache
|
||||
trashCache();
|
||||
|
||||
// find all the package namespaces...
|
||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
||||
{
|
||||
if(walk->mPackage == name)
|
||||
{
|
||||
Namespace *parent = Namespace::find(walk->mName);
|
||||
// hook the parent
|
||||
walk->mParent = parent->mParent;
|
||||
parent->mParent = walk;
|
||||
|
||||
// now swap the entries:
|
||||
Entry *ew;
|
||||
for(ew = parent->mEntryList; ew; ew = ew->mNext)
|
||||
ew->mNamespace = walk;
|
||||
|
||||
for(ew = walk->mEntryList; ew; ew = ew->mNext)
|
||||
ew->mNamespace = parent;
|
||||
|
||||
ew = walk->mEntryList;
|
||||
walk->mEntryList = parent->mEntryList;
|
||||
parent->mEntryList = ew;
|
||||
}
|
||||
}
|
||||
mActivePackages[mNumActivePackages++] = name;
|
||||
}
|
||||
|
||||
void Namespace::deactivatePackage(StringTableEntry name)
|
||||
{
|
||||
S32 i, j;
|
||||
for(i = 0; i < mNumActivePackages; i++)
|
||||
if(mActivePackages[i] == name)
|
||||
break;
|
||||
if(i == mNumActivePackages)
|
||||
return;
|
||||
|
||||
trashCache();
|
||||
|
||||
for(j = mNumActivePackages - 1; j >= i; j--)
|
||||
{
|
||||
// gotta unlink em in reverse order...
|
||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
||||
{
|
||||
if(walk->mPackage == mActivePackages[j])
|
||||
{
|
||||
Namespace *parent = Namespace::find(walk->mName);
|
||||
// hook the parent
|
||||
parent->mParent = walk->mParent;
|
||||
walk->mParent = NULL;
|
||||
|
||||
// now swap the entries:
|
||||
Entry *ew;
|
||||
for(ew = parent->mEntryList; ew; ew = ew->mNext)
|
||||
ew->mNamespace = walk;
|
||||
|
||||
for(ew = walk->mEntryList; ew; ew = ew->mNext)
|
||||
ew->mNamespace = parent;
|
||||
|
||||
ew = walk->mEntryList;
|
||||
walk->mEntryList = parent->mEntryList;
|
||||
parent->mEntryList = ew;
|
||||
}
|
||||
}
|
||||
}
|
||||
mNumActivePackages = i;
|
||||
}
|
||||
|
||||
void Namespace::unlinkPackages()
|
||||
{
|
||||
mOldNumActivePackages = mNumActivePackages;
|
||||
if(!mNumActivePackages)
|
||||
return;
|
||||
deactivatePackage(mActivePackages[0]);
|
||||
}
|
||||
|
||||
void Namespace::relinkPackages()
|
||||
{
|
||||
if(!mOldNumActivePackages)
|
||||
return;
|
||||
for(U32 i = 0; i < mOldNumActivePackages; i++)
|
||||
activatePackage(mActivePackages[i]);
|
||||
}
|
||||
|
||||
ConsoleFunction(isPackage,bool,2,2,"isPackage(packageName)")
|
||||
{
|
||||
argc;
|
||||
StringTableEntry packageName = StringTable->insert(argv[1]);
|
||||
return Namespace::isPackage(packageName);
|
||||
}
|
||||
|
||||
ConsoleFunction(activatePackage, void,2,2,"activatePackage(packageName)")
|
||||
{
|
||||
argc;
|
||||
StringTableEntry packageName = StringTable->insert(argv[1]);
|
||||
Namespace::activatePackage(packageName);
|
||||
}
|
||||
|
||||
ConsoleFunction(deactivatePackage, void,2,2,"deactivatePackage(packageName)")
|
||||
{
|
||||
argc;
|
||||
StringTableEntry packageName = StringTable->insert(argv[1]);
|
||||
Namespace::deactivatePackage(packageName);
|
||||
}
|
||||
280
console/consoleInternal.h
Normal file
280
console/consoleInternal.h
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CONSOLEINTERNAL_H_
|
||||
#define _CONSOLEINTERNAL_H_
|
||||
|
||||
#ifndef _STRINGTABLE_H_
|
||||
#include "core/stringTable.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/tVector.h"
|
||||
#endif
|
||||
#ifndef _CONSOLETYPES_H_
|
||||
#include "console/consoleTypes.h"
|
||||
#endif
|
||||
|
||||
class ExprEvalState;
|
||||
struct FunctionDecl;
|
||||
class CodeBlock;
|
||||
|
||||
class Namespace
|
||||
{
|
||||
enum {
|
||||
MaxActivePackages = 512,
|
||||
};
|
||||
|
||||
static U32 mNumActivePackages;
|
||||
static U32 mOldNumActivePackages;
|
||||
static StringTableEntry mActivePackages[MaxActivePackages];
|
||||
public:
|
||||
StringTableEntry mName;
|
||||
StringTableEntry mPackage;
|
||||
|
||||
Namespace *mParent;
|
||||
Namespace *mNext;
|
||||
U32 mRefCountToParent;
|
||||
|
||||
struct Entry
|
||||
{
|
||||
enum {
|
||||
InvalidFunctionType = -1,
|
||||
ScriptFunctionType,
|
||||
StringCallbackType,
|
||||
IntCallbackType,
|
||||
FloatCallbackType,
|
||||
VoidCallbackType,
|
||||
BoolCallbackType
|
||||
};
|
||||
|
||||
Namespace *mNamespace;
|
||||
Entry *mNext;
|
||||
StringTableEntry mFunctionName;
|
||||
S32 mType;
|
||||
S32 mMinArgs;
|
||||
S32 mMaxArgs;
|
||||
const char *mUsage;
|
||||
|
||||
CodeBlock *mCode;
|
||||
U32 mFunctionOffset;
|
||||
union {
|
||||
StringCallback mStringCallbackFunc;
|
||||
IntCallback mIntCallbackFunc;
|
||||
VoidCallback mVoidCallbackFunc;
|
||||
FloatCallback mFloatCallbackFunc;
|
||||
BoolCallback mBoolCallbackFunc;
|
||||
} cb;
|
||||
Entry();
|
||||
void clear();
|
||||
|
||||
const char *execute(S32 argc, const char **argv, ExprEvalState *state);
|
||||
|
||||
};
|
||||
Entry *mEntryList;
|
||||
|
||||
Entry **mHashTable;
|
||||
U32 mHashSize;
|
||||
U32 mHashSequence;
|
||||
|
||||
Namespace();
|
||||
void addFunction(StringTableEntry name, CodeBlock *cb, U32 functionOffset);
|
||||
void addCommand(StringTableEntry name,StringCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(StringTableEntry name,IntCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(StringTableEntry name,FloatCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(StringTableEntry name,VoidCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
void addCommand(StringTableEntry name,BoolCallback, const char *usage, S32 minArgs, S32 maxArgs);
|
||||
|
||||
void getEntryList(Vector<Entry *> *);
|
||||
|
||||
Entry *lookup(StringTableEntry name);
|
||||
Entry *lookupRecursive(StringTableEntry name);
|
||||
Entry *createLocalEntry(StringTableEntry name);
|
||||
void buildHashTable();
|
||||
void clearEntries();
|
||||
void classLinkTo(Namespace *parent);
|
||||
|
||||
const char *tabComplete(const char *prevText, S32 baseLen, bool fForward);
|
||||
|
||||
static U32 mCacheSequence;
|
||||
static DataChunker mCacheAllocator;
|
||||
static DataChunker mAllocator;
|
||||
static void trashCache();
|
||||
static Namespace *mNamespaceList;
|
||||
static Namespace *mGlobalNamespace;
|
||||
|
||||
static void init();
|
||||
static void shutdown();
|
||||
static Namespace *global();
|
||||
|
||||
static Namespace *find(StringTableEntry name, StringTableEntry package=NULL);
|
||||
|
||||
static void activatePackage(StringTableEntry name);
|
||||
static void deactivatePackage(StringTableEntry name);
|
||||
static void unlinkPackages();
|
||||
static void relinkPackages();
|
||||
static bool isPackage(StringTableEntry name);
|
||||
};
|
||||
|
||||
extern char *typeValueEmpty;
|
||||
|
||||
class Dictionary
|
||||
{
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
enum
|
||||
{
|
||||
TypeInternalInt = -3,
|
||||
TypeInternalFloat = -2,
|
||||
TypeInternalString = -1,
|
||||
};
|
||||
|
||||
StringTableEntry name;
|
||||
Entry *nextEntry;
|
||||
S32 type;
|
||||
char *sval;
|
||||
U32 ival; // doubles as strlen when type = -1
|
||||
F32 fval;
|
||||
U32 bufferLen;
|
||||
void *dataPtr;
|
||||
|
||||
Entry(StringTableEntry name);
|
||||
~Entry();
|
||||
|
||||
U32 getIntValue()
|
||||
{
|
||||
if(type <= TypeInternalString)
|
||||
return ival;
|
||||
else
|
||||
return dAtoi(Con::getData(type, dataPtr, 0));
|
||||
}
|
||||
F32 getFloatValue()
|
||||
{
|
||||
if(type <= TypeInternalString)
|
||||
return fval;
|
||||
else
|
||||
return dAtof(Con::getData(type, dataPtr, 0));
|
||||
}
|
||||
const char *getStringValue()
|
||||
{
|
||||
if(type == TypeInternalString)
|
||||
return sval;
|
||||
if(type == TypeInternalFloat)
|
||||
return Con::getData(TypeF32, &fval, 0);
|
||||
else if(type == TypeInternalInt)
|
||||
return Con::getData(TypeS32, &ival, 0);
|
||||
else
|
||||
return Con::getData(type, dataPtr, 0);
|
||||
}
|
||||
void setIntValue(U32 val)
|
||||
{
|
||||
if(type <= TypeInternalString)
|
||||
{
|
||||
fval = val;
|
||||
ival = val;
|
||||
if(sval != typeValueEmpty)
|
||||
{
|
||||
dFree(sval);
|
||||
sval = typeValueEmpty;
|
||||
}
|
||||
type = TypeInternalInt;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *dptr = Con::getData(TypeS32, &val, 0);
|
||||
Con::setData(type, dataPtr, 0, 1, &dptr);
|
||||
}
|
||||
}
|
||||
void setFloatValue(F32 val)
|
||||
{
|
||||
if(type <= TypeInternalString)
|
||||
{
|
||||
fval = val;
|
||||
ival = val;
|
||||
if(sval != typeValueEmpty)
|
||||
{
|
||||
dFree(sval);
|
||||
sval = typeValueEmpty;
|
||||
}
|
||||
type = TypeInternalFloat;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *dptr = Con::getData(TypeF32, &val, 0);
|
||||
Con::setData(type, dataPtr, 0, 1, &dptr);
|
||||
}
|
||||
}
|
||||
void setStringValue(const char *value);
|
||||
};
|
||||
|
||||
private:
|
||||
S32 hashTableSize;
|
||||
S32 entryCount;
|
||||
|
||||
Entry **hashTable;
|
||||
ExprEvalState *exprState;
|
||||
public:
|
||||
StringTableEntry scopeName;
|
||||
Namespace *scopeNamespace;
|
||||
CodeBlock *code;
|
||||
U32 ip;
|
||||
|
||||
Dictionary() {}
|
||||
Dictionary(ExprEvalState *state);
|
||||
~Dictionary();
|
||||
Entry *lookup(StringTableEntry name);
|
||||
Entry *add(StringTableEntry name);
|
||||
void setState(ExprEvalState *state);
|
||||
void remove(Entry *);
|
||||
void reset();
|
||||
|
||||
void exportVariables(const char *varString, const char *fileName, bool append);
|
||||
void deleteVariables(const char *varString);
|
||||
|
||||
void setVariable(StringTableEntry name, const char *value);
|
||||
const char *getVariable(StringTableEntry name, bool *valid = NULL);
|
||||
|
||||
void addVariable(const char *name, S32 type, void *dataPtr);
|
||||
bool removeVariable(StringTableEntry name);
|
||||
|
||||
// return the best tab completion for prevText, with the length
|
||||
// of the pre-tab string in baseLen
|
||||
|
||||
const char *tabComplete(const char *prevText, S32 baseLen, bool);
|
||||
};
|
||||
|
||||
class ExprEvalState
|
||||
{
|
||||
public:
|
||||
// stuff for doing expression evaluation
|
||||
|
||||
SimObject *thisObject;
|
||||
Dictionary::Entry *currentVariable;
|
||||
bool traceOn;
|
||||
|
||||
ExprEvalState();
|
||||
~ExprEvalState();
|
||||
|
||||
// stack management
|
||||
Dictionary globalVars;
|
||||
Vector<Dictionary *> stack;
|
||||
void setCurVarName(StringTableEntry name);
|
||||
void setCurVarNameCreate(StringTableEntry name);
|
||||
S32 getIntVariable();
|
||||
F64 getFloatVariable();
|
||||
const char *getStringVariable();
|
||||
void setIntVariable(S32 val);
|
||||
void setFloatVariable(F64 val);
|
||||
void setStringVariable(const char *str);
|
||||
|
||||
void pushFrame(const char *frameName, Namespace *ns);
|
||||
void popFrame();
|
||||
};
|
||||
|
||||
#endif
|
||||
191
console/consoleObject.cc
Normal file
191
console/consoleObject.cc
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "console/consoleObject.h"
|
||||
#include "core/stringTable.h"
|
||||
#include "console/console.h"
|
||||
|
||||
static AbstractClassRep::FieldList sg_tempFieldList;
|
||||
AbstractClassRep *AbstractClassRep::classLinkList = NULL;
|
||||
AbstractClassRep *AbstractClassRep::classTable[MaxClassId+1];
|
||||
bool AbstractClassRep::initialized = false;
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
const AbstractClassRep::Field *AbstractClassRep::findField(StringTableEntry name) const
|
||||
{
|
||||
for(U32 i = 0; i < mFieldList.size(); i++)
|
||||
if(mFieldList[i].pFieldname == name)
|
||||
return &mFieldList[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
void AbstractClassRep::registerClassRep(AbstractClassRep* in_pRep)
|
||||
{
|
||||
AssertFatal(in_pRep != NULL, "Hmph, that's odd...");
|
||||
|
||||
#ifdef DEBUG // assert if this class is already registered.
|
||||
for(AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass)
|
||||
{
|
||||
AssertFatal(dStrcmp(in_pRep->mClassName, walk->mClassName),
|
||||
"Duplicate Class name registered.");
|
||||
}
|
||||
#endif
|
||||
in_pRep->nextClass = classLinkList;
|
||||
classLinkList = in_pRep;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
ConsoleObject* AbstractClassRep::create(const char* in_pClassName)
|
||||
{
|
||||
AssertFatal(initialized, "creating an object before AbstractClassRep::initialize.");
|
||||
|
||||
for (AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass)
|
||||
if (!dStrcmp(walk->getClassName(), in_pClassName))
|
||||
return walk->create();
|
||||
|
||||
AssertWarn(0, avar("Couldn't find class rep for dynamic class: %s", in_pClassName));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
ConsoleObject* AbstractClassRep::create(const S32 in_classId)
|
||||
{
|
||||
AssertFatal(initialized, "creating an object before AbstractClassRep::initialize.");
|
||||
AssertFatal(in_classId >= 0 && in_classId <= MaxClassId, "Class id out of range.");
|
||||
AssertFatal(classTable[in_classId] != NULL, "No class with declared id type.");
|
||||
|
||||
if(classTable[in_classId])
|
||||
return classTable[in_classId]->create();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
static S32 QSORT_CALLBACK ACRCompare(const void *aptr, const void *bptr)
|
||||
{
|
||||
const AbstractClassRep *a = *((const AbstractClassRep **) aptr);
|
||||
const AbstractClassRep *b = *((const AbstractClassRep **) bptr);
|
||||
|
||||
if(a->mClassIdBase != b->mClassIdBase)
|
||||
return a->mClassIdBase - b->mClassIdBase;
|
||||
if(a->mClassVersion != b->mClassVersion)
|
||||
return a->mClassVersion - b->mClassVersion;
|
||||
return dStrcmp(a->getClassName(), b->getClassName());
|
||||
}
|
||||
|
||||
void AbstractClassRep::initialize()
|
||||
{
|
||||
AssertFatal(!initialized, "Duplicate call to AbstractClassRep::initialize()");
|
||||
U32 i;
|
||||
for(i = 0; i <= MaxClassId; i++)
|
||||
classTable[i] = NULL;
|
||||
|
||||
Vector<AbstractClassRep *> dynamicTable(__FILE__, __LINE__);
|
||||
|
||||
AbstractClassRep *walk;
|
||||
|
||||
for (walk = classLinkList; walk; walk = walk->nextClass)
|
||||
walk->mNamespace = Con::lookupNamespace(StringTable->insert(walk->getClassName()));
|
||||
|
||||
for (walk = classLinkList; walk; walk = walk->nextClass)
|
||||
{
|
||||
sg_tempFieldList.setSize(0);
|
||||
walk->init();
|
||||
if (sg_tempFieldList.size() != 0)
|
||||
walk->mFieldList = sg_tempFieldList;
|
||||
|
||||
if(walk->mClassIdBase != -1)
|
||||
dynamicTable.push_back(walk);
|
||||
}
|
||||
dQsort((void *) &dynamicTable[0], dynamicTable.size(), sizeof(AbstractClassRep *), ACRCompare);
|
||||
|
||||
S32 prevClassBase = -1;
|
||||
S32 curClassId = 0;
|
||||
|
||||
for(i = 0; i < dynamicTable.size(); i++)
|
||||
{
|
||||
AbstractClassRep *cur = dynamicTable[i];
|
||||
if(cur->mClassIdBase != prevClassBase)
|
||||
{
|
||||
AssertFatal(cur->mClassIdBase >= curClassId, avar("Class range too small %d", prevClassBase));
|
||||
prevClassBase = cur->mClassIdBase;
|
||||
curClassId = cur->mClassIdBase;
|
||||
}
|
||||
cur->mClassId = curClassId++;
|
||||
classTable[cur->mClassId] = cur;
|
||||
}
|
||||
initialized = true;
|
||||
sg_tempFieldList.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- ConsoleObject
|
||||
void ConsoleObject::addField(const char* in_pFieldname,
|
||||
const U32 in_fieldType,
|
||||
const U32 in_fieldOffset,
|
||||
const U32 in_elementCount,
|
||||
EnumTable *in_table)
|
||||
{
|
||||
AbstractClassRep::Field f;
|
||||
f.pFieldname = StringTable->insert(in_pFieldname);
|
||||
f.type = in_fieldType;
|
||||
f.offset = in_fieldOffset;
|
||||
f.elementCount = in_elementCount;
|
||||
f.table = in_table;
|
||||
|
||||
sg_tempFieldList.push_back(f);
|
||||
}
|
||||
|
||||
void ConsoleObject::addDepricatedField(const char *fieldName)
|
||||
{
|
||||
AbstractClassRep::Field f;
|
||||
f.pFieldname = StringTable->insert(fieldName);
|
||||
f.type = AbstractClassRep::DepricatedFieldType;
|
||||
|
||||
sg_tempFieldList.push_back(f);
|
||||
}
|
||||
|
||||
|
||||
bool ConsoleObject::removeField(const char* in_pFieldname)
|
||||
{
|
||||
for (U32 i = 0; i < sg_tempFieldList.size(); i++) {
|
||||
if (dStricmp(in_pFieldname, sg_tempFieldList[i].pFieldname) == 0) {
|
||||
sg_tempFieldList.erase(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void ConsoleObject::initPersistFields()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
void ConsoleObject::consoleInit()
|
||||
{
|
||||
}
|
||||
|
||||
ConsoleObject::~ConsoleObject()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
AbstractClassRep* ConsoleObject::getClassRep() const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
334
console/consoleObject.h
Normal file
334
console/consoleObject.h
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CONSOLEOBJECT_H_
|
||||
#define _CONSOLEOBJECT_H_
|
||||
|
||||
//Includes
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/tVector.h"
|
||||
#endif
|
||||
#ifndef _STRINGTABLE_H_
|
||||
#include "core/stringTable.h"
|
||||
#endif
|
||||
#ifndef _BITSET_H_
|
||||
#include "core/bitSet.h"
|
||||
#endif
|
||||
#ifndef _CONSOLE_H_
|
||||
#include "console/console.h"
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- AbstractClassRep
|
||||
//
|
||||
|
||||
class Namespace;
|
||||
|
||||
enum {
|
||||
NetObjectClassFirst = 0,
|
||||
NetObjectClassLast = 127,
|
||||
NetObjectClassBitSize = 7,
|
||||
|
||||
DataBlockClassFirst = 128,
|
||||
DataBlockClassLast = 255,
|
||||
DataBlockClassBitSize = 7,
|
||||
|
||||
NetEventClassFirst = 255,
|
||||
NetEventClassLast = 318,
|
||||
NetEventClassBitSize = 6,
|
||||
|
||||
MaxClassId = 318
|
||||
};
|
||||
|
||||
class AbstractClassRep
|
||||
{
|
||||
friend class ConsoleObject;
|
||||
|
||||
//-------------------------------------- Public interface
|
||||
public:
|
||||
enum
|
||||
{
|
||||
DepricatedFieldType = 0xFFFFFFFF
|
||||
};
|
||||
virtual ~AbstractClassRep() { }
|
||||
AbstractClassRep() {
|
||||
VECTOR_SET_ASSOCIATION(mFieldList);
|
||||
}
|
||||
|
||||
S32 getClassId() const;
|
||||
const char* getClassName() const;
|
||||
Namespace * getNameSpace();
|
||||
virtual ConsoleObject* create() const = 0;
|
||||
AbstractClassRep *getNextClass();
|
||||
static AbstractClassRep *getClassList();
|
||||
|
||||
//-------------------------------------- Field interface
|
||||
public:
|
||||
struct Field {
|
||||
const char* pFieldname;
|
||||
U32 type;
|
||||
U32 offset;
|
||||
S32 elementCount;
|
||||
EnumTable *table;
|
||||
BitSet32 flag;
|
||||
};
|
||||
typedef Vector<Field> FieldList;
|
||||
|
||||
FieldList mFieldList;
|
||||
const Field *findField(StringTableEntry fieldName) const;
|
||||
public:
|
||||
S32 mClassIdBase;
|
||||
S32 mClassVersion;
|
||||
S32 mClassNetClass;
|
||||
static void initialize(); // Called from CMDCon::init once on startup
|
||||
|
||||
protected:
|
||||
static AbstractClassRep *classTable[MaxClassId+1];
|
||||
static AbstractClassRep *classLinkList;
|
||||
static bool initialized;
|
||||
|
||||
static void registerClassRep(AbstractClassRep*);
|
||||
|
||||
protected:
|
||||
virtual void init() const = 0;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// each registered tagged class has a id tag and a compiler
|
||||
// independant class name
|
||||
// if the class can be constructed by tag (network)
|
||||
// the tag is >= 0.
|
||||
|
||||
protected:
|
||||
|
||||
const char *mClassName;
|
||||
S32 mClassId;
|
||||
AbstractClassRep *nextClass;
|
||||
Namespace *mNamespace;
|
||||
|
||||
// Helper functions for ConsoleObject
|
||||
protected:
|
||||
static ConsoleObject* create(const char* in_pClassName);
|
||||
static ConsoleObject* create(const S32 in_classId);
|
||||
|
||||
};
|
||||
|
||||
inline AbstractClassRep *AbstractClassRep::getClassList()
|
||||
{
|
||||
return classLinkList;
|
||||
}
|
||||
|
||||
inline AbstractClassRep *AbstractClassRep::getNextClass()
|
||||
{
|
||||
return nextClass;
|
||||
}
|
||||
|
||||
inline S32 AbstractClassRep::getClassId() const
|
||||
{
|
||||
return mClassId;
|
||||
}
|
||||
|
||||
inline const char* AbstractClassRep::getClassName() const
|
||||
{
|
||||
return mClassName;
|
||||
}
|
||||
|
||||
inline Namespace *AbstractClassRep::getNameSpace()
|
||||
{
|
||||
return mNamespace;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- ConcreteClassRep
|
||||
//
|
||||
|
||||
enum
|
||||
{
|
||||
NetEventClassAny,
|
||||
NetEventClassClient,
|
||||
NetEventClassServer
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ConcreteClassRep : public AbstractClassRep
|
||||
{
|
||||
public:
|
||||
ConcreteClassRep(const char *name, S32 idBase = -1, S32 version=1,S32 netClass = NetEventClassAny)
|
||||
{
|
||||
// name is a static compiler string so no need to worry about copying or deleting
|
||||
mClassName = name;
|
||||
mClassId = -1;
|
||||
mClassIdBase = idBase;
|
||||
mClassVersion = version;
|
||||
mClassNetClass = netClass;
|
||||
registerClassRep(this);
|
||||
};
|
||||
void init() const
|
||||
{
|
||||
AbstractClassRep *parent = T::getParentStaticClassRep();
|
||||
AbstractClassRep *child = T::getStaticClassRep();
|
||||
if(parent && child)
|
||||
Con::classLinkNamespaces(parent->getNameSpace(), child->getNameSpace());
|
||||
T::initPersistFields();
|
||||
T::consoleInit();
|
||||
}
|
||||
ConsoleObject* create() const { return new T; }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- USER interface class. Derive from this,
|
||||
// and access functionality through its
|
||||
// static interface.
|
||||
class ConsoleObject
|
||||
{
|
||||
protected:
|
||||
ConsoleObject() { /* disallowed */ }
|
||||
ConsoleObject(const ConsoleObject&); // disallowed ?
|
||||
|
||||
protected:
|
||||
const AbstractClassRep::Field *findField(StringTableEntry fieldName) const;
|
||||
|
||||
public:
|
||||
virtual AbstractClassRep* getClassRep() const;
|
||||
bool setField(const char *fieldName, const char *value);
|
||||
virtual ~ConsoleObject();
|
||||
|
||||
// Object creation interface
|
||||
public:
|
||||
static ConsoleObject* create(const char* in_pClassName);
|
||||
static ConsoleObject* create(const U32 in_classId);
|
||||
|
||||
// Query interface
|
||||
public:
|
||||
static const char* lookupClassName(const U32 in_classTag);
|
||||
|
||||
// Field interface
|
||||
protected:
|
||||
static void addField(const char* in_pFieldname,
|
||||
const U32 in_fieldType,
|
||||
const U32 in_fieldOffset,
|
||||
const U32 in_elementCount = 1,
|
||||
EnumTable *in_table = NULL);
|
||||
static void addDepricatedField(const char *fieldName);
|
||||
static bool removeField(const char* in_pFieldname);
|
||||
|
||||
public:
|
||||
static void initPersistFields(); // declare one of these in a class to register dynamic fields in a class.
|
||||
static void consoleInit(); // declare one of these in a class to register console functions and establish namespace linkage
|
||||
const AbstractClassRep::FieldList& getFieldList() const;
|
||||
|
||||
static AbstractClassRep *getStaticClassRep() { return NULL; }
|
||||
static AbstractClassRep *getParentStaticClassRep() { return NULL; }
|
||||
|
||||
S32 getClassId() const;
|
||||
const char *getClassName() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- Inlines
|
||||
//
|
||||
inline S32 ConsoleObject::getClassId() const
|
||||
{
|
||||
AssertFatal(getClassRep() != NULL,
|
||||
"Cannot get tag from non-declared dynamic class");
|
||||
return getClassRep()->getClassId();
|
||||
}
|
||||
|
||||
inline const char * ConsoleObject::getClassName() const
|
||||
{
|
||||
AssertFatal(getClassRep() != NULL,
|
||||
"Cannot get tag from non-declared dynamic class");
|
||||
return getClassRep()->getClassName();
|
||||
}
|
||||
|
||||
inline const AbstractClassRep::Field * ConsoleObject::findField(StringTableEntry name) const
|
||||
{
|
||||
AssertFatal(getClassRep() != NULL,
|
||||
"Cannot get tag from non-declared dynamic class");
|
||||
return getClassRep()->findField(name);
|
||||
}
|
||||
|
||||
inline bool ConsoleObject::setField(const char *fieldName, const char *value)
|
||||
{
|
||||
//sanity check
|
||||
if ((! fieldName) || (! fieldName[0]) || (! value))
|
||||
return false;
|
||||
|
||||
if (! getClassRep())
|
||||
return false;
|
||||
const AbstractClassRep::Field *myField = getClassRep()->findField(StringTable->insert(fieldName));
|
||||
if (! myField)
|
||||
return false;
|
||||
Con::setData(myField->type, (void *) (S32(this) + myField->offset), 0, 1, &value, myField->table, myField->flag);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline ConsoleObject* ConsoleObject::create(const char* in_pClassName)
|
||||
{
|
||||
return AbstractClassRep::create(in_pClassName);
|
||||
}
|
||||
|
||||
inline ConsoleObject* ConsoleObject::create(const U32 in_classId)
|
||||
{
|
||||
return AbstractClassRep::create(in_classId);
|
||||
}
|
||||
|
||||
inline const AbstractClassRep::FieldList& ConsoleObject::getFieldList() const
|
||||
{
|
||||
return getClassRep()->mFieldList;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- MACROS for dynamic objects...
|
||||
//
|
||||
#define DECLARE_CONOBJECT(className) \
|
||||
static ConcreteClassRep<className> dynClassRep; \
|
||||
static AbstractClassRep* getParentStaticClassRep(); \
|
||||
static AbstractClassRep* getStaticClassRep(); \
|
||||
virtual AbstractClassRep* getClassRep() const
|
||||
|
||||
#define IMPLEMENT_CONOBJECT(className) \
|
||||
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
||||
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
||||
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
||||
ConcreteClassRep<className> className::dynClassRep(#className)
|
||||
|
||||
#define IMPLEMENT_CO_NETOBJECT_V1(className) \
|
||||
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
||||
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
||||
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
||||
ConcreteClassRep<className> className::dynClassRep(#className,NetObjectClassFirst,1)
|
||||
|
||||
#define IMPLEMENT_CO_DATABLOCK_V1(className) \
|
||||
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
||||
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
||||
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
||||
ConcreteClassRep<className> className::dynClassRep(#className,DataBlockClassFirst,1)
|
||||
|
||||
#define IMPLEMENT_CO_NETEVENT_V1(className) \
|
||||
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
||||
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
||||
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
||||
ConcreteClassRep<className> className::dynClassRep(#className,NetEventClassFirst,1,NetEventClassAny)
|
||||
|
||||
#define IMPLEMENT_CO_CLIENTEVENT_V1(className) \
|
||||
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
||||
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
||||
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
||||
ConcreteClassRep<className> className::dynClassRep(#className,NetEventClassFirst,1,NetEventClassClient)
|
||||
|
||||
#define IMPLEMENT_CO_SERVEREVENT_V1(className) \
|
||||
AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
|
||||
AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
|
||||
AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
|
||||
ConcreteClassRep<className> className::dynClassRep(#className,NetEventClassFirst,1,NetEventClassServer)
|
||||
|
||||
#endif //_CONSOLEOBJECT_H_
|
||||
429
console/consoleTypes.cc
Normal file
429
console/consoleTypes.cc
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "Core/stringTable.h"
|
||||
#include "Core/color.h"
|
||||
#include "console/simBase.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static const char *getDataTypeString(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
return *((const char **)(dptr));
|
||||
}
|
||||
|
||||
static void setDataTypeString(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
if(argc == 1)
|
||||
*((const char **) dptr) = StringTable->insert(argv[0]);
|
||||
else
|
||||
Con::printf("(TypeString) Cannot set multiple args to a single string.");
|
||||
}
|
||||
|
||||
static void setDataTypeCaseString(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
if(argc == 1)
|
||||
*((const char **) dptr) = StringTable->insert(argv[0], true);
|
||||
else
|
||||
Con::printf("(TypeCaseString) Cannot set multiple args to a single string.");
|
||||
}
|
||||
|
||||
static const char *getDataTypeCharArray(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
return (const char *)(dptr);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static const char *getDataTypeU8(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
char* returnBuffer = Con::getReturnBuffer(256);
|
||||
dSprintf(returnBuffer, 256, "%d", *((U8 *) dptr) );
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
static void setDataTypeU8(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
if(argc == 1)
|
||||
*((U8 *) dptr) = dAtoi(argv[0]);
|
||||
else
|
||||
Con::printf("(TypeU8) Cannot set multiple args to a single S32.");
|
||||
}
|
||||
|
||||
static const char *getDataTypeS32(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
char* returnBuffer = Con::getReturnBuffer(256);
|
||||
dSprintf(returnBuffer, 256, "%d", *((S32 *) dptr) );
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
static void setDataTypeS32(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
if(argc == 1)
|
||||
*((S32 *) dptr) = dAtoi(argv[0]);
|
||||
else
|
||||
Con::printf("(TypeS32) Cannot set multiple args to a single S32.");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static const char *getDataTypeS32Vector(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
Vector<S32> *vec = (Vector<S32> *)dptr;
|
||||
char* returnBuffer = Con::getReturnBuffer(1024);
|
||||
S32 maxReturn = 1024;
|
||||
returnBuffer[0] = '\0';
|
||||
S32 returnLeng = 0;
|
||||
for (Vector<S32>::iterator itr = vec->begin(); itr != vec->end(); itr++)
|
||||
{
|
||||
// concatenate the next value onto the return string
|
||||
dSprintf(returnBuffer + returnLeng, maxReturn - returnLeng, "%d ", *itr);
|
||||
// update the length of the return string (so far)
|
||||
returnLeng = dStrlen(returnBuffer);
|
||||
}
|
||||
// trim off that last extra space
|
||||
if (returnLeng > 0 && returnBuffer[returnLeng - 1] == ' ')
|
||||
returnBuffer[returnLeng - 1] = '\0';
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
static void setDataTypeS32Vector(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
Vector<S32> *vec = (Vector<S32> *)dptr;
|
||||
// we assume the vector should be cleared first (not just appending)
|
||||
vec->clear();
|
||||
if(argc == 1)
|
||||
{
|
||||
const char *values = argv[0];
|
||||
const char *endValues = values + dStrlen(values);
|
||||
S32 value;
|
||||
// advance through the string, pulling off S32's and advancing the pointer
|
||||
while (values < endValues && dSscanf(values, "%d", &value) != 0)
|
||||
{
|
||||
vec->push_back(value);
|
||||
const char *nextValues = dStrchr(values, ' ');
|
||||
if (nextValues != 0 && nextValues < endValues)
|
||||
values = nextValues + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (argc > 1)
|
||||
{
|
||||
for (S32 i = 0; i < argc; i++)
|
||||
vec->push_back(dAtoi(argv[i]));
|
||||
}
|
||||
else
|
||||
Con::printf("Vector<S32> must be set as { a, b, c, ... } or \"a b c ...\"");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static const char *getDataTypeF32(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
char* returnBuffer = Con::getReturnBuffer(256);
|
||||
dSprintf(returnBuffer, 256, "%g", *((F32 *) dptr) );
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
static void setDataTypeF32(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
if(argc == 1)
|
||||
*((F32 *) dptr) = dAtof(argv[0]);
|
||||
else
|
||||
Con::printf("(TypeF32) Cannot set multiple args to a single F32.");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static const char *getDataTypeF32Vector(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
Vector<F32> *vec = (Vector<F32> *)dptr;
|
||||
char* returnBuffer = Con::getReturnBuffer(1024);
|
||||
S32 maxReturn = 1024;
|
||||
returnBuffer[0] = '\0';
|
||||
S32 returnLeng = 0;
|
||||
for (Vector<F32>::iterator itr = vec->begin(); itr != vec->end(); itr++)
|
||||
{
|
||||
// concatenate the next value onto the return string
|
||||
dSprintf(returnBuffer + returnLeng, maxReturn - returnLeng, "%f ", *itr);
|
||||
// update the length of the return string (so far)
|
||||
returnLeng = dStrlen(returnBuffer);
|
||||
}
|
||||
// trim off that last extra space
|
||||
if (returnLeng > 0 && returnBuffer[returnLeng - 1] == ' ')
|
||||
returnBuffer[returnLeng - 1] = '\0';
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
static void setDataTypeF32Vector(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
Vector<F32> *vec = (Vector<F32> *)dptr;
|
||||
// we assume the vector should be cleared first (not just appending)
|
||||
vec->clear();
|
||||
if(argc == 1)
|
||||
{
|
||||
const char *values = argv[0];
|
||||
const char *endValues = values + dStrlen(values);
|
||||
F32 value;
|
||||
// advance through the string, pulling off F32's and advancing the pointer
|
||||
while (values < endValues && dSscanf(values, "%f", &value) != 0)
|
||||
{
|
||||
vec->push_back(value);
|
||||
const char *nextValues = dStrchr(values, ' ');
|
||||
if (nextValues != 0 && nextValues < endValues)
|
||||
values = nextValues + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (argc > 1)
|
||||
{
|
||||
for (S32 i = 0; i < argc; i++)
|
||||
vec->push_back(dAtof(argv[i]));
|
||||
}
|
||||
else
|
||||
Con::printf("Vector<F32> must be set as { a, b, c, ... } or \"a b c ...\"");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static const char *getDataTypeBool(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
return *((bool *) dptr) ? "1" : "0";
|
||||
}
|
||||
|
||||
static void setDataTypeBool(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
if(argc == 1)
|
||||
*((bool *) dptr) = dAtob(argv[0]);
|
||||
else
|
||||
Con::printf("(TypeBool) Cannot set multiple args to a single bool.");
|
||||
}
|
||||
|
||||
static const char *getDataTypeBoolVector(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
Vector<bool> *vec = (Vector<bool>*)dptr;
|
||||
char* returnBuffer = Con::getReturnBuffer(1024);
|
||||
S32 maxReturn = 1024;
|
||||
returnBuffer[0] = '\0';
|
||||
S32 returnLeng = 0;
|
||||
for (Vector<bool>::iterator itr = vec->begin(); itr < vec->end(); itr++)
|
||||
{
|
||||
// concatenate the next value onto the return string
|
||||
dSprintf(returnBuffer + returnLeng, maxReturn - returnLeng, "%d ", (*itr == true ? 1 : 0));
|
||||
returnLeng = dStrlen(returnBuffer);
|
||||
}
|
||||
// trim off that last extra space
|
||||
if (returnLeng > 0 && returnBuffer[returnLeng - 1] == ' ')
|
||||
returnBuffer[returnLeng - 1] = '\0';
|
||||
return(returnBuffer);
|
||||
}
|
||||
|
||||
static void setDataTypeBoolVector(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
Vector<bool> *vec = (Vector<bool>*)dptr;
|
||||
// we assume the vector should be cleared first (not just appending)
|
||||
vec->clear();
|
||||
if (argc == 1)
|
||||
{
|
||||
const char *values = argv[0];
|
||||
const char *endValues = values + dStrlen(values);
|
||||
S32 value;
|
||||
// advance through the string, pulling off bool's and advancing the pointer
|
||||
while (values < endValues && dSscanf(values, "%d", &value) != 0)
|
||||
{
|
||||
vec->push_back(value == 0 ? false : true);
|
||||
const char *nextValues = dStrchr(values, ' ');
|
||||
if (nextValues != 0 && nextValues < endValues)
|
||||
values = nextValues + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (argc > 1)
|
||||
{
|
||||
for (S32 i = 0; i < argc; i++)
|
||||
vec->push_back(dAtob(argv[i]));
|
||||
}
|
||||
else
|
||||
Con::printf("Vector<bool> must be set as { a, b, c, ... } or \"a b c ...\"");
|
||||
}
|
||||
|
||||
static const char *getDataTypeEnum(void *dptr, EnumTable *tbl, BitSet32)
|
||||
{
|
||||
AssertFatal(tbl, "Null enum table passed to getDataTypeEnum()");
|
||||
S32 dptrVal = *(S32*)dptr;
|
||||
for (S32 i = 0; i < tbl->size; i++)
|
||||
{
|
||||
if (dptrVal == tbl->table[i].index)
|
||||
{
|
||||
return tbl->table[i].label;
|
||||
}
|
||||
}
|
||||
|
||||
//not found
|
||||
return "";
|
||||
}
|
||||
|
||||
static void setDataTypeEnum(void *dptr, S32 argc, const char **argv, EnumTable *tbl, BitSet32)
|
||||
{
|
||||
AssertFatal(tbl, "Null enum table passed to setDataTypeEnum()");
|
||||
if (argc != 1) return;
|
||||
|
||||
S32 val = 0;
|
||||
for (S32 i = 0; i < tbl->size; i++)
|
||||
{
|
||||
if (! dStricmp(argv[0], tbl->table[i].label))
|
||||
{
|
||||
val = tbl->table[i].index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*((S32 *) dptr) = val;
|
||||
}
|
||||
|
||||
static const char *getDataTypeFlag(void *dptr, EnumTable *, BitSet32 flag)
|
||||
{
|
||||
BitSet32 tempFlags = *(BitSet32 *)dptr;
|
||||
if (tempFlags.test(flag)) return "true";
|
||||
else return "false";
|
||||
}
|
||||
|
||||
static void setDataTypeFlag(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32 flag)
|
||||
{
|
||||
bool value = true;
|
||||
if (argc != 1)
|
||||
{
|
||||
Con::printf("flag must be true or false");
|
||||
}
|
||||
else
|
||||
{
|
||||
value = dAtob(argv[0]);
|
||||
}
|
||||
((BitSet32 *)dptr)->set(flag, value);
|
||||
}
|
||||
|
||||
static const char *getDataTypeColorF(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
ColorF * color = (ColorF*)dptr;
|
||||
char* returnBuffer = Con::getReturnBuffer(256);
|
||||
dSprintf(returnBuffer, 256, "%f %f %f %f", color->red, color->green, color->blue, color->alpha);
|
||||
return(returnBuffer);
|
||||
}
|
||||
|
||||
static void setDataTypeColorF(void *dptr, S32 argc, const char ** argv, EnumTable *, BitSet32)
|
||||
{
|
||||
ColorF *tmpColor = (ColorF *) dptr;
|
||||
if(argc == 1)
|
||||
{
|
||||
tmpColor->set(0, 0, 0, 1);
|
||||
F32 r,g,b,a;
|
||||
S32 args = dSscanf(argv[0], "%f %f %f %f", &r, &g, &b, &a);
|
||||
tmpColor->red = r;
|
||||
tmpColor->green = g;
|
||||
tmpColor->blue = b;
|
||||
if (args == 4)
|
||||
tmpColor->alpha = a;
|
||||
}
|
||||
else if(argc == 3)
|
||||
{
|
||||
tmpColor->red = dAtof(argv[0]);
|
||||
tmpColor->green = dAtof(argv[1]);
|
||||
tmpColor->blue = dAtof(argv[2]);
|
||||
tmpColor->alpha = 1.f;
|
||||
}
|
||||
else if(argc == 4)
|
||||
{
|
||||
tmpColor->red = dAtof(argv[0]);
|
||||
tmpColor->green = dAtof(argv[1]);
|
||||
tmpColor->blue = dAtof(argv[2]);
|
||||
tmpColor->alpha = dAtof(argv[3]);
|
||||
}
|
||||
else
|
||||
Con::printf("Color must be set as { r, g, b [,a] }");
|
||||
}
|
||||
|
||||
static const char *getDataTypeColorI(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
ColorI *color = (ColorI *) dptr;
|
||||
char* returnBuffer = Con::getReturnBuffer(256);
|
||||
dSprintf(returnBuffer, 256, "%d %d %d %d", color->red, color->green, color->blue, color->alpha);
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
static void setDataTypeColorI(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
ColorI *tmpColor = (ColorI *) dptr;
|
||||
if(argc == 1)
|
||||
{
|
||||
tmpColor->set(0, 0, 0, 255);
|
||||
S32 r,g,b,a;
|
||||
S32 args = dSscanf(argv[0], "%d %d %d %d", &r, &g, &b, &a);
|
||||
tmpColor->red = r;
|
||||
tmpColor->green = g;
|
||||
tmpColor->blue = b;
|
||||
if (args == 4)
|
||||
tmpColor->alpha = a;
|
||||
}
|
||||
else if(argc == 3)
|
||||
{
|
||||
tmpColor->red = dAtoi(argv[0]);
|
||||
tmpColor->green = dAtoi(argv[1]);
|
||||
tmpColor->blue = dAtoi(argv[2]);
|
||||
tmpColor->alpha = 255;
|
||||
}
|
||||
else if(argc == 4)
|
||||
{
|
||||
tmpColor->red = dAtoi(argv[0]);
|
||||
tmpColor->green = dAtoi(argv[1]);
|
||||
tmpColor->blue = dAtoi(argv[2]);
|
||||
tmpColor->alpha = dAtoi(argv[3]);
|
||||
}
|
||||
else
|
||||
Con::printf("Color must be set as { r, g, b [,a] }");
|
||||
}
|
||||
|
||||
static void setDataTypeSimObjectPtr(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
|
||||
{
|
||||
if(argc == 1)
|
||||
{
|
||||
SimObject **obj = (SimObject **)dptr;
|
||||
*obj = Sim::findObject(argv[0]);
|
||||
}
|
||||
else
|
||||
Con::printf("(TypeSimObjectPtr) Cannot set multiple args to a single S32.");
|
||||
}
|
||||
|
||||
static const char *getDataTypeSimObjectPtr(void *dptr, EnumTable *, BitSet32)
|
||||
{
|
||||
SimObject **obj = (SimObject**)dptr;
|
||||
char* returnBuffer = Con::getReturnBuffer(256);
|
||||
dSprintf(returnBuffer, 256, "%s", *obj ? (*obj)->getName() : "");
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void RegisterCoreTypes(void)
|
||||
{
|
||||
Con::registerType(TypeS8, sizeof(U8), getDataTypeU8, setDataTypeU8);
|
||||
Con::registerType(TypeS32, sizeof(S32), getDataTypeS32, setDataTypeS32);
|
||||
Con::registerType(TypeS32Vector, sizeof(Vector<S32>), getDataTypeS32Vector, setDataTypeS32Vector);
|
||||
Con::registerType(TypeBool, sizeof(bool), getDataTypeBool, setDataTypeBool);
|
||||
Con::registerType(TypeBoolVector, sizeof(Vector<bool>), getDataTypeBoolVector, setDataTypeBoolVector);
|
||||
Con::registerType(TypeF32, sizeof(F32), getDataTypeF32, setDataTypeF32);
|
||||
Con::registerType(TypeF32Vector, sizeof(Vector<F32>), getDataTypeF32Vector, setDataTypeF32Vector);
|
||||
Con::registerType(TypeString, sizeof(const char *), getDataTypeString, setDataTypeString);
|
||||
Con::registerType(TypeCaseString, sizeof(const char *), getDataTypeString, setDataTypeCaseString);
|
||||
Con::registerType(TypeEnum, sizeof(S32), getDataTypeEnum, setDataTypeEnum);
|
||||
Con::registerType(TypeFlag, sizeof(S32), getDataTypeFlag, setDataTypeFlag);
|
||||
Con::registerType(TypeColorI, sizeof(ColorI), getDataTypeColorI, setDataTypeColorI);
|
||||
Con::registerType(TypeColorF, sizeof(ColorF), getDataTypeColorF, setDataTypeColorF);
|
||||
Con::registerType(TypeSimObjectPtr, sizeof(SimObject*), getDataTypeSimObjectPtr, setDataTypeSimObjectPtr);
|
||||
}
|
||||
|
||||
71
console/consoleTypes.h
Normal file
71
console/consoleTypes.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CONSOLETYPES_H_
|
||||
#define _CONSOLETYPES_H_
|
||||
|
||||
#define Offset(x, cls) (S32)&(((cls *)0)->x)
|
||||
|
||||
enum ConsoleDynamicTypes {
|
||||
|
||||
//Registered in ConsoleTypes.cc
|
||||
TypeS8 = 0,
|
||||
TypeS32,
|
||||
TypeS32Vector,
|
||||
TypeBool,
|
||||
TypeBoolVector,
|
||||
TypeF32,
|
||||
TypeF32Vector,
|
||||
TypeString,
|
||||
TypeCaseString,
|
||||
TypeEnum,
|
||||
TypeFlag,
|
||||
TypeColorI,
|
||||
TypeColorF,
|
||||
TypeSimObjectPtr,
|
||||
|
||||
//Registered in MathTypes.cc
|
||||
TypePoint2I,
|
||||
TypePoint2F,
|
||||
TypePoint3F,
|
||||
TypePoint4F,
|
||||
TypeRectI,
|
||||
TypeRectF,
|
||||
TypeMatrixPosition,
|
||||
TypeMatrixRotation,
|
||||
TypeBox3F,
|
||||
|
||||
//Registered in GuiTypes.cc
|
||||
TypeGuiProfile,
|
||||
|
||||
// Game types
|
||||
TypeGameBaseDataPtr,
|
||||
TypeExplosionDataPtr,
|
||||
TypeShockwaveDataPtr,
|
||||
TypeSplashDataPtr,
|
||||
TypeEnergyProjectileDataPtr,
|
||||
TypeBombProjectileDataPtr,
|
||||
TypeParticleEmitterDataPtr,
|
||||
TypeAudioDescriptionPtr,
|
||||
TypeAudioProfilePtr,
|
||||
TypeTriggerPolyhedron,
|
||||
TypeProjectileDataPtr,
|
||||
TypeCannedChatItemPtr,
|
||||
TypeWayPointTeam,
|
||||
TypeDebrisDataPtr,
|
||||
TypeCommanderIconDataPtr,
|
||||
TypeDecalDataPtr,
|
||||
TypeEffectProfilePtr,
|
||||
TypeAudioEnvironmentPtr,
|
||||
TypeAudioSampleEnvironmentPtr,
|
||||
|
||||
NumConsoleTypes
|
||||
};
|
||||
|
||||
void RegisterCoreTypes(void);
|
||||
|
||||
#endif
|
||||
2439
console/gram.cc
Normal file
2439
console/gram.cc
Normal file
File diff suppressed because it is too large
Load diff
84
console/gram.h
Normal file
84
console/gram.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define rwDEFINE 257
|
||||
#define rwENDDEF 258
|
||||
#define rwDECLARE 259
|
||||
#define rwBREAK 260
|
||||
#define rwELSE 261
|
||||
#define rwCONTINUE 262
|
||||
#define rwGLOBAL 263
|
||||
#define rwIF 264
|
||||
#define rwNIL 265
|
||||
#define rwRETURN 266
|
||||
#define rwWHILE 267
|
||||
#define rwENDIF 268
|
||||
#define rwENDWHILE 269
|
||||
#define rwENDFOR 270
|
||||
#define rwDEFAULT 271
|
||||
#define rwFOR 272
|
||||
#define rwDATABLOCK 273
|
||||
#define rwSWITCH 274
|
||||
#define rwCASE 275
|
||||
#define rwSWITCHSTR 276
|
||||
#define rwCASEOR 277
|
||||
#define rwPACKAGE 278
|
||||
#define ILLEGAL_TOKEN 279
|
||||
#define CHRCONST 280
|
||||
#define INTCONST 281
|
||||
#define TTAG 282
|
||||
#define VAR 283
|
||||
#define IDENT 284
|
||||
#define STRATOM 285
|
||||
#define TAGATOM 286
|
||||
#define FLTCONST 287
|
||||
#define opMINUSMINUS 288
|
||||
#define opPLUSPLUS 289
|
||||
#define STMT_SEP 290
|
||||
#define opSHL 291
|
||||
#define opSHR 292
|
||||
#define opPLASN 293
|
||||
#define opMIASN 294
|
||||
#define opMLASN 295
|
||||
#define opDVASN 296
|
||||
#define opMODASN 297
|
||||
#define opANDASN 298
|
||||
#define opXORASN 299
|
||||
#define opORASN 300
|
||||
#define opSLASN 301
|
||||
#define opSRASN 302
|
||||
#define opCAT 303
|
||||
#define opEQ 304
|
||||
#define opNE 305
|
||||
#define opGE 306
|
||||
#define opLE 307
|
||||
#define opAND 308
|
||||
#define opOR 309
|
||||
#define opSTREQ 310
|
||||
#define opCOLONCOLON 311
|
||||
typedef union {
|
||||
char c;
|
||||
int i;
|
||||
const char *s;
|
||||
char *str;
|
||||
double f;
|
||||
StmtNode *stmt;
|
||||
ExprNode *expr;
|
||||
SlotAssignNode *slist;
|
||||
VarNode *var;
|
||||
SlotDecl slot;
|
||||
ObjectBlockDecl odcl;
|
||||
ObjectDeclNode *od;
|
||||
AssignDecl asn;
|
||||
IfStmtNode *ifnode;
|
||||
} YYSTYPE;
|
||||
#define opMDASN 312
|
||||
#define opNDASN 313
|
||||
#define opNTASN 314
|
||||
#define opSTRNE 315
|
||||
#define UNARY 316
|
||||
extern YYSTYPE CMDlval;
|
||||
493
console/gram.y
Normal file
493
console/gram.y
Normal file
|
|
@ -0,0 +1,493 @@
|
|||
%{
|
||||
#include "console.h"
|
||||
#include "ast.h"
|
||||
#include <stdlib.h>
|
||||
#include "stdio.h"
|
||||
#include "consoleInternal.h"
|
||||
|
||||
#ifndef YYDEBUG
|
||||
#define YYDEBUG
|
||||
#endif
|
||||
|
||||
#define YYSSIZE 350
|
||||
|
||||
int outtext(char *fmt, ...);
|
||||
extern int serrors;
|
||||
#define nil 0
|
||||
#undef YY_ARGS
|
||||
#define YY_ARGS(x) x
|
||||
%}
|
||||
%{
|
||||
/* Reserved Word Definitions */
|
||||
%}
|
||||
%token <i> rwDEFINE rwENDDEF rwDECLARE
|
||||
%token <i> rwBREAK rwELSE rwCONTINUE rwGLOBAL
|
||||
%token <i> rwIF rwNIL rwRETURN rwWHILE
|
||||
%token <i> rwENDIF rwENDWHILE rwENDFOR rwDEFAULT
|
||||
%token <i> rwFOR rwDATABLOCK rwSWITCH rwCASE rwSWITCHSTR
|
||||
%token <i> rwCASEOR rwPACKAGE
|
||||
%token ILLEGAL_TOKEN
|
||||
%{
|
||||
/* Constants and Identifier Definitions */
|
||||
%}
|
||||
%token <c> CHRCONST
|
||||
%token <i> INTCONST
|
||||
%token <s> TTAG
|
||||
%token <s> VAR
|
||||
%token <s> IDENT
|
||||
%token <str> STRATOM
|
||||
%token <str> TAGATOM
|
||||
%token <f> FLTCONST
|
||||
|
||||
%{
|
||||
/* Operator Definitions */
|
||||
%}
|
||||
%token <i> '+' '-' '*' '/' '<' '>' '=' '.' '|' '&' '%'
|
||||
%token <i> '(' ')' ',' ':' ';' '{' '}' '^' '~' '!' '@'
|
||||
%token <i> opMINUSMINUS opPLUSPLUS
|
||||
%token <i> STMT_SEP
|
||||
%token <i> opSHL opSHR opPLASN opMIASN opMLASN opDVASN opMODASN opANDASN
|
||||
%token <i> opXORASN opORASN opSLASN opSRASN opCAT
|
||||
%token <i> opEQ opNE opGE opLE opAND opOR opSTREQ
|
||||
%token <i> opCOLONCOLON
|
||||
|
||||
%union {
|
||||
char c;
|
||||
int i;
|
||||
const char *s;
|
||||
char *str;
|
||||
double f;
|
||||
StmtNode *stmt;
|
||||
ExprNode *expr;
|
||||
SlotAssignNode *slist;
|
||||
VarNode *var;
|
||||
SlotDecl slot;
|
||||
ObjectBlockDecl odcl;
|
||||
ObjectDeclNode *od;
|
||||
AssignDecl asn;
|
||||
IfStmtNode *ifnode;
|
||||
}
|
||||
|
||||
%type <ifnode> case_block
|
||||
%type <stmt> switch_stmt
|
||||
%type <stmt> decl
|
||||
%type <stmt> decl_list
|
||||
%type <stmt> package_decl
|
||||
%type <stmt> fn_decl_stmt
|
||||
%type <stmt> fn_decl_list
|
||||
%type <stmt> statement_list
|
||||
%type <stmt> stmt
|
||||
%type <expr> expr_list
|
||||
%type <expr> expr_list_decl
|
||||
%type <expr> aidx_expr
|
||||
%type <expr> funcall_expr
|
||||
%type <expr> object_name
|
||||
%type <expr> object_args
|
||||
%type <expr> stmt_expr
|
||||
%type <expr> case_expr
|
||||
%type <expr> class_name_expr
|
||||
%type <stmt> if_stmt
|
||||
%type <stmt> while_stmt
|
||||
%type <stmt> for_stmt
|
||||
%type <stmt> stmt_block
|
||||
%type <stmt> datablock_decl
|
||||
%type <od> object_decl
|
||||
%type <od> object_decl_list
|
||||
%type <odcl> object_declare_block
|
||||
%type <expr> expr
|
||||
%type <slist> slot_assign_list
|
||||
%type <slist> slot_assign
|
||||
%type <slot> slot_acc
|
||||
%type <stmt> expression_stmt
|
||||
%type <var> var_list
|
||||
%type <var> var_list_decl
|
||||
%type <asn> assign_op_struct
|
||||
|
||||
%left '['
|
||||
%right opMODASN opANDASN opXORASN opPLASN opMIASN opMLASN opDVASN opMDASN opNDASN opNTASN opORASN opSLASN opSRASN '='
|
||||
%left '?' ':'
|
||||
%left opOR
|
||||
%left opAND
|
||||
%left '|'
|
||||
%left '^'
|
||||
%left '&'
|
||||
%left opEQ opNE
|
||||
%left '<' opLE '>' opGE
|
||||
%left '@' opCAT opSTREQ opSTRNE
|
||||
%left opSHL opSHR
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%right '!' '~' opPLUSPLUS opMINUSMINUS UNARY
|
||||
%left '.'
|
||||
|
||||
%%
|
||||
|
||||
start
|
||||
: decl_list
|
||||
{ }
|
||||
;
|
||||
|
||||
decl_list
|
||||
:
|
||||
{ $$ = nil; }
|
||||
| decl_list decl
|
||||
{ if(!statementList) { statementList = $2; } else { statementList->append($2); } }
|
||||
;
|
||||
|
||||
decl
|
||||
: stmt
|
||||
{ $$ = $1; }
|
||||
| fn_decl_stmt
|
||||
{ $$ = $1; }
|
||||
| package_decl
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
package_decl
|
||||
: rwPACKAGE IDENT '{' fn_decl_list '}' ';'
|
||||
{ $$ = $4; for(StmtNode *walk = ($4);walk;walk = walk->getNext() ) walk->setPackage($2); }
|
||||
;
|
||||
|
||||
fn_decl_list
|
||||
: fn_decl_stmt
|
||||
{ $$ = $1; }
|
||||
| fn_decl_list fn_decl_stmt
|
||||
{ $$ = $1; ($1)->append($2); }
|
||||
;
|
||||
|
||||
statement_list
|
||||
:
|
||||
{ $$ = nil; }
|
||||
| statement_list stmt
|
||||
{ if(!$1) { $$ = $2; } else { ($1)->append($2); $$ = $1; } }
|
||||
;
|
||||
|
||||
stmt
|
||||
: if_stmt
|
||||
| while_stmt
|
||||
| for_stmt
|
||||
| datablock_decl
|
||||
| switch_stmt
|
||||
| rwBREAK ';'
|
||||
{ $$ = BreakStmtNode::alloc(); }
|
||||
| rwCONTINUE ';'
|
||||
{ $$ = ContinueStmtNode::alloc(); }
|
||||
| rwRETURN ';'
|
||||
{ $$ = ReturnStmtNode::alloc(NULL); }
|
||||
| rwRETURN expr ';'
|
||||
{ $$ = ReturnStmtNode::alloc($2); }
|
||||
| expression_stmt ';'
|
||||
{ $$ = $1; }
|
||||
| TTAG '=' expr ';'
|
||||
{ $$ = TTagSetStmtNode::alloc($1, $3, NULL); }
|
||||
| TTAG '=' expr ',' expr ';'
|
||||
{ $$ = TTagSetStmtNode::alloc($1, $3, $5); }
|
||||
;
|
||||
|
||||
fn_decl_stmt
|
||||
: rwDEFINE IDENT '(' var_list_decl ')' '{' statement_list '}'
|
||||
{ $$ = FunctionDeclStmtNode::alloc($2, NULL, $4, $7); }
|
||||
| rwDEFINE IDENT opCOLONCOLON IDENT '(' var_list_decl ')' '{' statement_list '}'
|
||||
{ $$ = FunctionDeclStmtNode::alloc($4, $2, $6, $9); }
|
||||
;
|
||||
|
||||
var_list_decl
|
||||
:
|
||||
{ $$ = NULL; }
|
||||
| var_list
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
var_list
|
||||
: VAR
|
||||
{ $$ = VarNode::alloc($1, NULL); }
|
||||
| var_list ',' VAR
|
||||
{ $$ = $1; ((StmtNode*)($1))->append((StmtNode*)VarNode::alloc($3, NULL)); }
|
||||
;
|
||||
|
||||
datablock_decl
|
||||
: rwDATABLOCK IDENT '(' IDENT ')' '{' slot_assign_list '}' ';'
|
||||
{ $$ = ObjectDeclNode::alloc(ConstantNode::alloc($2), ConstantNode::alloc($4), NULL, NULL, $7, NULL, true); }
|
||||
| rwDATABLOCK IDENT '(' IDENT ')' ':' IDENT '{' slot_assign_list '}' ';'
|
||||
{ $$ = ObjectDeclNode::alloc(ConstantNode::alloc($2), ConstantNode::alloc($4), NULL, $7, $9, NULL, true); }
|
||||
;
|
||||
|
||||
object_decl
|
||||
: rwDECLARE class_name_expr '(' object_name object_args ')' '{' object_declare_block '}'
|
||||
{ $$ = ObjectDeclNode::alloc($2, $4, $5, NULL, $8.slots, $8.decls, false); }
|
||||
| rwDECLARE class_name_expr '(' object_name object_args ')'
|
||||
{ $$ = ObjectDeclNode::alloc($2, $4, $5, NULL, NULL, NULL, false); }
|
||||
;
|
||||
|
||||
object_name
|
||||
:
|
||||
{ $$ = StrConstNode::alloc("", false); }
|
||||
| expr
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
object_args
|
||||
:
|
||||
{ $$ = NULL; }
|
||||
| ',' expr_list
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
object_declare_block
|
||||
:
|
||||
{ $$.slots = NULL; $$.decls = NULL; }
|
||||
| slot_assign_list
|
||||
{ $$.slots = $1; $$.decls = NULL; }
|
||||
| object_decl_list
|
||||
{ $$.slots = NULL; $$.decls = $1; }
|
||||
| slot_assign_list object_decl_list
|
||||
{ $$.slots = $1; $$.decls = $2; }
|
||||
;
|
||||
|
||||
object_decl_list
|
||||
: object_decl ';'
|
||||
{ $$ = $1; }
|
||||
| object_decl_list object_decl ';'
|
||||
{ $1->append($2); $$ = $1; }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: '{' statement_list '}'
|
||||
{ $$ = $2; }
|
||||
| stmt
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
switch_stmt
|
||||
: rwSWITCH '(' expr ')' '{' case_block '}'
|
||||
{ $$ = $6; $6->propagateSwitchExpr($3, false); }
|
||||
| rwSWITCHSTR '(' expr ')' '{' case_block '}'
|
||||
{ $$ = $6; $6->propagateSwitchExpr($3, true); }
|
||||
;
|
||||
|
||||
case_block
|
||||
: rwCASE case_expr ':' statement_list
|
||||
{ $$ = IfStmtNode::alloc($1, $2, $4, NULL, false); }
|
||||
| rwCASE case_expr ':' statement_list rwDEFAULT ':' statement_list
|
||||
{ $$ = IfStmtNode::alloc($1, $2, $4, $7, false); }
|
||||
| rwCASE case_expr ':' statement_list case_block
|
||||
{ $$ = IfStmtNode::alloc($1, $2, $4, $5, true); }
|
||||
;
|
||||
|
||||
case_expr
|
||||
: expr
|
||||
{ $$ = $1;}
|
||||
| case_expr rwCASEOR expr
|
||||
{ ($1)->append($3); $$=$1; }
|
||||
;
|
||||
|
||||
if_stmt
|
||||
: rwIF '(' expr ')' stmt_block
|
||||
{ $$ = IfStmtNode::alloc($1, $3, $5, NULL, false); }
|
||||
| rwIF '(' expr ')' stmt_block rwELSE stmt_block
|
||||
{ $$ = IfStmtNode::alloc($1, $3, $5, $7, false); }
|
||||
;
|
||||
|
||||
while_stmt
|
||||
: rwWHILE '(' expr ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1, nil, $3, nil, $5, false); }
|
||||
;
|
||||
|
||||
for_stmt
|
||||
: rwFOR '(' expr ';' expr ';' expr ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1, $3, $5, $7, $9, false); }
|
||||
;
|
||||
|
||||
expression_stmt
|
||||
: stmt_expr
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
expr
|
||||
: stmt_expr
|
||||
{ $$ = $1; }
|
||||
| '(' expr ')'
|
||||
{ $$ = $2; }
|
||||
| expr '^' expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr '%' expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr '&' expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr '|' expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr '+' expr
|
||||
{ $$ = FloatBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr '-' expr
|
||||
{ $$ = FloatBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr '*' expr
|
||||
{ $$ = FloatBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr '/' expr
|
||||
{ $$ = FloatBinaryExprNode::alloc($2, $1, $3); }
|
||||
| '-' expr %prec UNARY
|
||||
{ $$ = FloatUnaryExprNode::alloc($1, $2); }
|
||||
| '*' expr %prec UNARY
|
||||
{ $$ = TTagDerefNode::alloc($2); }
|
||||
| TTAG
|
||||
{ $$ = TTagExprNode::alloc($1); }
|
||||
| expr '?' expr ':' expr
|
||||
{ $$ = ConditionalExprNode::alloc($1, $3, $5); }
|
||||
| expr '<' expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr '>' expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr opGE expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr opLE expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr opEQ expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr opNE expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr opOR expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr opSHL expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr opSHR expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr opAND expr
|
||||
{ $$ = IntBinaryExprNode::alloc($2, $1, $3); }
|
||||
| expr opSTREQ expr
|
||||
{ $$ = StreqExprNode::alloc($1, $3, true); }
|
||||
| expr opSTRNE expr
|
||||
{ $$ = StreqExprNode::alloc($1, $3, false); }
|
||||
| expr '@' expr
|
||||
{ $$ = StrcatExprNode::alloc($1, $3, $2); }
|
||||
| '!' expr
|
||||
{ $$ = IntUnaryExprNode::alloc($1, $2); }
|
||||
| '~' expr
|
||||
{ $$ = IntUnaryExprNode::alloc($1, $2); }
|
||||
| TAGATOM
|
||||
{ $$ = StrConstNode::alloc($1, true); }
|
||||
| FLTCONST
|
||||
{ $$ = FloatNode::alloc($1); }
|
||||
| INTCONST
|
||||
{ $$ = IntNode::alloc($1); }
|
||||
| rwBREAK
|
||||
{ $$ = ConstantNode::alloc(StringTable->insert("break")); }
|
||||
| slot_acc
|
||||
{ $$ = SlotAccessNode::alloc($1.object, $1.array, $1.slotName); }
|
||||
| IDENT
|
||||
{ $$ = ConstantNode::alloc($1); }
|
||||
| STRATOM
|
||||
{ $$ = StrConstNode::alloc($1, false); }
|
||||
| VAR
|
||||
{ $$ = (ExprNode*)VarNode::alloc($1, NULL); }
|
||||
| VAR '[' aidx_expr ']'
|
||||
{ $$ = (ExprNode*)VarNode::alloc($1, $3); }
|
||||
;
|
||||
|
||||
slot_acc
|
||||
: expr '.' IDENT
|
||||
{ $$.object = $1; $$.slotName = $3; $$.array = NULL; }
|
||||
| expr '.' IDENT '[' aidx_expr ']'
|
||||
{ $$.object = $1; $$.slotName = $3; $$.array = $5; }
|
||||
;
|
||||
|
||||
class_name_expr
|
||||
: IDENT
|
||||
{ $$ = ConstantNode::alloc($1); }
|
||||
| '(' expr ')'
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
assign_op_struct
|
||||
: opPLUSPLUS
|
||||
{ $$.token = '+'; $$.expr = FloatNode::alloc(1); }
|
||||
| opMINUSMINUS
|
||||
{ $$.token = '-'; $$.expr = FloatNode::alloc(1); }
|
||||
| opPLASN expr
|
||||
{ $$.token = '+'; $$.expr = $2; }
|
||||
| opMIASN expr
|
||||
{ $$.token = '-'; $$.expr = $2; }
|
||||
| opMLASN expr
|
||||
{ $$.token = '*'; $$.expr = $2; }
|
||||
| opDVASN expr
|
||||
{ $$.token = '/'; $$.expr = $2; }
|
||||
| opMODASN expr
|
||||
{ $$.token = '%'; $$.expr = $2; }
|
||||
| opANDASN expr
|
||||
{ $$.token = '&'; $$.expr = $2; }
|
||||
| opXORASN expr
|
||||
{ $$.token = '^'; $$.expr = $2; }
|
||||
| opORASN expr
|
||||
{ $$.token = '|'; $$.expr = $2; }
|
||||
| opSLASN expr
|
||||
{ $$.token = opSHL; $$.expr = $2; }
|
||||
| opSRASN expr
|
||||
{ $$.token = opSHR; $$.expr = $2; }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: funcall_expr
|
||||
{ $$ = $1; }
|
||||
| object_decl
|
||||
{ $$ = $1; }
|
||||
| VAR '=' expr
|
||||
{ $$ = AssignExprNode::alloc($1, NULL, $3); }
|
||||
| VAR '[' aidx_expr ']' '=' expr
|
||||
{ $$ = AssignExprNode::alloc($1, $3, $6); }
|
||||
| VAR assign_op_struct
|
||||
{ $$ = AssignOpExprNode::alloc($1, NULL, $2.expr, $2.token); }
|
||||
| VAR '[' aidx_expr ']' assign_op_struct
|
||||
{ $$ = AssignOpExprNode::alloc($1, $3, $5.expr, $5.token); }
|
||||
| slot_acc assign_op_struct
|
||||
{ $$ = SlotAssignOpNode::alloc($1.object, $1.slotName, $1.array, $2.token, $2.expr); }
|
||||
| slot_acc '=' expr
|
||||
{ $$ = SlotAssignNode::alloc($1.object, $1.array, $1.slotName, $3); }
|
||||
| slot_acc '=' '{' expr_list '}'
|
||||
{ $$ = SlotAssignNode::alloc($1.object, $1.array, $1.slotName, $4); }
|
||||
;
|
||||
|
||||
funcall_expr
|
||||
: IDENT '(' expr_list_decl ')'
|
||||
{ $$ = FuncCallExprNode::alloc($1, NULL, $3, false); }
|
||||
| IDENT opCOLONCOLON IDENT '(' expr_list_decl ')'
|
||||
{ $$ = FuncCallExprNode::alloc($3, $1, $5, false); }
|
||||
| expr '.' IDENT '(' expr_list_decl ')'
|
||||
{ $1->append($5); $$ = FuncCallExprNode::alloc($3, NULL, $1, true); }
|
||||
;
|
||||
|
||||
expr_list_decl
|
||||
:
|
||||
{ $$ = NULL; }
|
||||
| expr_list
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
expr_list
|
||||
: expr
|
||||
{ $$ = $1; }
|
||||
| expr_list ',' expr
|
||||
{ ($1)->append($3); $$ = $1; }
|
||||
;
|
||||
|
||||
slot_assign_list
|
||||
: slot_assign
|
||||
{ $$ = $1; }
|
||||
| slot_assign_list slot_assign
|
||||
{ $1->append($2); $$ = $1; }
|
||||
;
|
||||
|
||||
slot_assign
|
||||
: IDENT '=' expr ';'
|
||||
{ $$ = SlotAssignNode::alloc(NULL, NULL, $1, $3); }
|
||||
| rwDATABLOCK '=' expr ';'
|
||||
{ $$ = SlotAssignNode::alloc(NULL, NULL, StringTable->insert("datablock"), $3); }
|
||||
| IDENT '[' aidx_expr ']' '=' expr ';'
|
||||
{ $$ = SlotAssignNode::alloc(NULL, $3, $1, $6); }
|
||||
;
|
||||
|
||||
aidx_expr
|
||||
: expr
|
||||
{ $$ = $1; }
|
||||
| aidx_expr ',' expr
|
||||
{ $$ = CommaCatExprNode::alloc($1, $3); }
|
||||
;
|
||||
%%
|
||||
|
||||
79
console/objectTypes.h
Normal file
79
console/objectTypes.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _OBJECTTYPES_H_
|
||||
#define _OBJECTTYPES_H_
|
||||
|
||||
// Types used for SimObject type masks (SimObject::mTypeMask)
|
||||
//
|
||||
|
||||
/* NB! If a new object type is added, don't forget to add it to the
|
||||
* consoleInit function in simBase.cc
|
||||
*/
|
||||
|
||||
// SimObjectTypes
|
||||
|
||||
// Types used by the SceneObject class
|
||||
#define DefaultObjectType 0
|
||||
#define StaticObjectType (1<<0)
|
||||
|
||||
// Basic Engine Types
|
||||
#define EnvironmentObjectType (1<<1)
|
||||
#define TerrainObjectType (1<<2)
|
||||
#define InteriorObjectType (1<<3)
|
||||
#define WaterObjectType (1<<4)
|
||||
#define TriggerObjectType (1<<5)
|
||||
#define MarkerObjectType (1<<6)
|
||||
#define PathedObjectType (1<<7)
|
||||
#define ForceFieldObjectType (1<<8)
|
||||
#define DecalManagerObjectType (1<<9)
|
||||
|
||||
#define PlayerObjectType (1<<14)
|
||||
#define GuiControlObjectType (1<<25)
|
||||
#define StaticRenderedObjectType (1<<26)
|
||||
|
||||
|
||||
// Game Types
|
||||
#define GameBaseObjectType (1<<10)
|
||||
#define ShapeBaseObjectType (1<<11)
|
||||
#define CameraObjectType (1<<12)
|
||||
#define StaticShapeObjectType (1<<13)
|
||||
#define ItemObjectType (1<<15)
|
||||
#define VehicleObjectType (1<<16)
|
||||
#define MoveableObjectType (1<<17)
|
||||
#define ProjectileObjectType (1<<18)
|
||||
#define ExplosionObjectType (1<<19)
|
||||
#define CorpseObjectType (1<<20)
|
||||
#define TurretObjectType (1<<21)
|
||||
#define DebrisObjectType (1<<22)
|
||||
#define PhysicalZoneObjectType (1<<23)
|
||||
#define StaticTSObjectType (1<<24)
|
||||
|
||||
// The following are allowed types that can be set on datablocks for static shapes
|
||||
//
|
||||
#define DamagableItemObjectType (1<<27)
|
||||
#define SensorObjectType (1<<28)
|
||||
#define StationObjectType (1<<29)
|
||||
#define GeneratorObjectType (1<<30)
|
||||
|
||||
|
||||
#define STATIC_COLLISION_MASK ( TerrainObjectType | \
|
||||
InteriorObjectType | \
|
||||
ForceFieldObjectType | \
|
||||
StaticObjectType ) \
|
||||
|
||||
#define DAMAGEABLE_MASK ( PlayerObjectType | \
|
||||
VehicleObjectType | \
|
||||
MoveableObjectType | \
|
||||
StationObjectType | \
|
||||
GeneratorObjectType | \
|
||||
SensorObjectType | \
|
||||
PathedObjectType | \
|
||||
DamagableItemObjectType | \
|
||||
TurretObjectType ) \
|
||||
|
||||
#endif
|
||||
1560
console/scan.cc
Normal file
1560
console/scan.cc
Normal file
File diff suppressed because it is too large
Load diff
405
console/scan.l
Normal file
405
console/scan.l
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
%{
|
||||
#define YYLMAX 4096
|
||||
|
||||
#include "platform.h"
|
||||
#include "console.h"
|
||||
#include "ast.h"
|
||||
#include "gram.h"
|
||||
#include "stringTable.h"
|
||||
|
||||
static int Sc_ScanString(int ret);
|
||||
static int Sc_ScanNum();
|
||||
static int Sc_ScanVar();
|
||||
static int Sc_ScanHex();
|
||||
|
||||
#define FLEX_DEBUG 1
|
||||
|
||||
//#undef input
|
||||
//#undef unput
|
||||
#undef CMDgetc
|
||||
int CMDgetc();
|
||||
static int lineIndex;
|
||||
extern DataChunker consoleAllocator;
|
||||
|
||||
// Prototypes
|
||||
void SetScanBuffer(const char *sb, const char *fn);
|
||||
const char * CMDgetFileLine(int &lineNumber);
|
||||
void CMDerror(char * s, ...);
|
||||
|
||||
%}
|
||||
|
||||
DIGIT [0-9]
|
||||
INTEGER {DIGIT}+
|
||||
FLOAT ({INTEGER}\.{INTEGER})|({INTEGER}(\.{INTEGER})?[eE][+-]?{INTEGER})
|
||||
LETTER [A-Za-z_]
|
||||
FILECHAR [A-Za-z_\.]
|
||||
VARMID [:A-Za-z0-9_]
|
||||
IDTAIL [A-Za-z0-9_]
|
||||
VARTAIL {VARMID}*{IDTAIL}
|
||||
VAR [$%]{LETTER}{VARTAIL}*
|
||||
ID {LETTER}{IDTAIL}*
|
||||
ILID [$%]{DIGIT}+{LETTER}{VARTAIL}*
|
||||
FILENAME {FILECHAR}+
|
||||
SPACE [ \t\v\f]
|
||||
HEXDIGIT [a-fA-F0-9]
|
||||
|
||||
%%
|
||||
;
|
||||
{SPACE}+ { }
|
||||
"//"[^\n\r]* ;
|
||||
[\r] ;
|
||||
[\n] {lineIndex++;}
|
||||
\"(\\.|[^\\"\n\r])*\" { return(Sc_ScanString(STRATOM)); }
|
||||
\'(\\.|[^\\'\n\r])*\' { return(Sc_ScanString(TAGATOM)); }
|
||||
"==" return(CMDlval.i = opEQ);
|
||||
"!=" return(CMDlval.i = opNE);
|
||||
">=" return(CMDlval.i = opGE);
|
||||
"<=" return(CMDlval.i = opLE);
|
||||
"&&" return(CMDlval.i = opAND);
|
||||
"||" return(CMDlval.i = opOR);
|
||||
"::" return(CMDlval.i = opCOLONCOLON);
|
||||
"--" return(CMDlval.i = opMINUSMINUS);
|
||||
"++" return(CMDlval.i = opPLUSPLUS);
|
||||
"$=" return(CMDlval.i = opSTREQ);
|
||||
"!$=" return(CMDlval.i = opSTRNE);
|
||||
"<<" return(CMDlval.i = opSHL);
|
||||
">>" return(CMDlval.i = opSHR);
|
||||
"+=" return(CMDlval.i = opPLASN);
|
||||
"-=" return(CMDlval.i = opMIASN);
|
||||
"*=" return(CMDlval.i = opMLASN);
|
||||
"/=" return(CMDlval.i = opDVASN);
|
||||
"%=" return(CMDlval.i = opMODASN);
|
||||
"&=" return(CMDlval.i = opANDASN);
|
||||
"^=" return(CMDlval.i = opXORASN);
|
||||
"|=" return(CMDlval.i = opORASN);
|
||||
"<<=" return(CMDlval.i = opSLASN);
|
||||
">>=" return(CMDlval.i = opSRASN);
|
||||
"NL" {CMDlval.i = '\n'; return '@'; }
|
||||
"TAB" {CMDlval.i = '\t'; return '@'; }
|
||||
"SPC" {CMDlval.i = ' '; return '@'; }
|
||||
"@" {CMDlval.i = 0; return '@'; }
|
||||
"?" |
|
||||
"[" |
|
||||
"]" |
|
||||
"(" |
|
||||
")" |
|
||||
"+" |
|
||||
"-" |
|
||||
"*" |
|
||||
"/" |
|
||||
"<" |
|
||||
">" |
|
||||
"|" |
|
||||
"." |
|
||||
"!" |
|
||||
":" |
|
||||
";" |
|
||||
"{" |
|
||||
"}" |
|
||||
"," |
|
||||
"&" |
|
||||
"%" |
|
||||
"^" |
|
||||
"~" |
|
||||
"=" { return(CMDlval.i = CMDtext[0]); }
|
||||
"or" { CMDlval.i = lineIndex; return(rwCASEOR); }
|
||||
"break" { CMDlval.i = lineIndex; return(rwBREAK); }
|
||||
"return" { CMDlval.i = lineIndex; return(rwRETURN); }
|
||||
"else" { CMDlval.i = lineIndex; return(rwELSE); }
|
||||
"while" { CMDlval.i = lineIndex; return(rwWHILE); }
|
||||
"if" { CMDlval.i = lineIndex; return(rwIF); }
|
||||
"for" { CMDlval.i = lineIndex; return(rwFOR); }
|
||||
"continue" { CMDlval.i = lineIndex; return(rwCONTINUE); }
|
||||
"function" { CMDlval.i = lineIndex; return(rwDEFINE); }
|
||||
"new" { CMDlval.i = lineIndex; return(rwDECLARE); }
|
||||
"datablock" { CMDlval.i = lineIndex; return(rwDATABLOCK); }
|
||||
"case" { CMDlval.i = lineIndex; return(rwCASE); }
|
||||
"switch$" { CMDlval.i = lineIndex; return(rwSWITCHSTR); }
|
||||
"switch" { CMDlval.i = lineIndex; return(rwSWITCH); }
|
||||
"default" { CMDlval.i = lineIndex; return(rwDEFAULT); }
|
||||
"package" { CMDlval.i = lineIndex; return(rwPACKAGE); }
|
||||
"true" { CMDlval.i = 1; return INTCONST; }
|
||||
"false" { CMDlval.i = 0; return INTCONST; }
|
||||
{VAR} return(Sc_ScanVar());
|
||||
{ID} { CMDtext[CMDleng] = 0; CMDlval.s = StringTable->insert(CMDtext); return(IDENT); }
|
||||
0[xX]{HEXDIGIT}+ return(Sc_ScanHex());
|
||||
{INTEGER} { CMDtext[CMDleng] = 0; CMDlval.i = atoi(CMDtext); return INTCONST; }
|
||||
{FLOAT} return Sc_ScanNum();
|
||||
{ILID} return(ILLEGAL_TOKEN);
|
||||
. return(ILLEGAL_TOKEN);
|
||||
%%
|
||||
|
||||
/*
|
||||
* Scan character constant.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Scan identifier.
|
||||
*/
|
||||
|
||||
static const char *scanBuffer;
|
||||
static const char *fileName;
|
||||
static int scanIndex;
|
||||
|
||||
const char * CMDGetCurrentFile()
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
int CMDGetCurrentLine()
|
||||
{
|
||||
return lineIndex;
|
||||
}
|
||||
|
||||
extern bool gConsoleSyntaxError;
|
||||
|
||||
void CMDerror(char *, ...)
|
||||
{
|
||||
gConsoleSyntaxError = true;
|
||||
if(fileName)
|
||||
Con::errorf(ConsoleLogEntry::Script, "%s Line: %d - Syntax error.",
|
||||
fileName, lineIndex);
|
||||
else
|
||||
Con::errorf(ConsoleLogEntry::Script, "Syntax error in input.");
|
||||
}
|
||||
|
||||
void SetScanBuffer(const char *sb, const char *fn)
|
||||
{
|
||||
scanBuffer = sb;
|
||||
fileName = fn;
|
||||
scanIndex = 0;
|
||||
lineIndex = 1;
|
||||
}
|
||||
|
||||
int CMDgetc()
|
||||
{
|
||||
int ret = scanBuffer[scanIndex];
|
||||
if(ret)
|
||||
scanIndex++;
|
||||
else
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CMDwrap()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Sc_ScanVar()
|
||||
{
|
||||
CMDtext[CMDleng] = 0;
|
||||
CMDlval.s = StringTable->insert(CMDtext);
|
||||
return(VAR);
|
||||
}
|
||||
/*
|
||||
* Scan string constant.
|
||||
*/
|
||||
|
||||
static int charConv(int in)
|
||||
{
|
||||
switch(in)
|
||||
{
|
||||
case 'r':
|
||||
return '\r';
|
||||
case 'n':
|
||||
return '\n';
|
||||
case 't':
|
||||
return '\t';
|
||||
default:
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
static int getHexDigit(char c)
|
||||
{
|
||||
if(c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if(c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
if(c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int Sc_ScanString(int ret)
|
||||
{
|
||||
CMDtext[CMDleng - 1] = 0;
|
||||
if(!collapseEscape(CMDtext+1))
|
||||
return -1;
|
||||
CMDlval.str = (char *) consoleAllocator.alloc(dStrlen(CMDtext));
|
||||
dStrcpy(CMDlval.str, CMDtext + 1);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void expandEscape(char *dest, const char *src)
|
||||
{
|
||||
unsigned char c;
|
||||
while((c = (unsigned char) *src++) != 0)
|
||||
{
|
||||
if(c == '\"')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = '\"';
|
||||
}
|
||||
else if(c == '\\')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = '\\';
|
||||
}
|
||||
else if(c == '\r')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = 'r';
|
||||
}
|
||||
else if(c == '\n')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = 'n';
|
||||
}
|
||||
else if(c == '\t')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = 't';
|
||||
}
|
||||
else if(c == '\'')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = '\'';
|
||||
}
|
||||
else if((c >= 2 && c <= 8) ||
|
||||
(c >= 11 && c <= 12) ||
|
||||
(c >= 14 && c <= 15))
|
||||
{
|
||||
/* Remap around: \t = 0x9, \n = 0xa, \r = 0xd */
|
||||
static char expandRemap[15] = { 0x0,
|
||||
0x0,
|
||||
0x0,
|
||||
0x1,
|
||||
0x2,
|
||||
0x3,
|
||||
0x4,
|
||||
0x5,
|
||||
0x6,
|
||||
0x0,
|
||||
0x0,
|
||||
0x7,
|
||||
0x8,
|
||||
0x0,
|
||||
0x9 };
|
||||
|
||||
*dest++ = '\\';
|
||||
*dest++ = 'c';
|
||||
if(c == 15)
|
||||
*dest++ = 'r';
|
||||
else if(c == 16)
|
||||
*dest++ = 'p';
|
||||
else if(c == 17)
|
||||
*dest++ = 'o';
|
||||
else
|
||||
*dest++ = expandRemap[c] + '0';
|
||||
}
|
||||
else if(c < 32)
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = 'x';
|
||||
S32 dig1 = c >> 4;
|
||||
S32 dig2 = c & 0xf;
|
||||
if(dig1 < 10)
|
||||
dig1 += '0';
|
||||
else
|
||||
dig1 += 'A' - 10;
|
||||
if(dig2 < 10)
|
||||
dig2 += '0';
|
||||
else
|
||||
dig2 += 'A' - 10;
|
||||
*dest++ = dig1;
|
||||
*dest++ = dig2;
|
||||
}
|
||||
else
|
||||
*dest++ = c;
|
||||
}
|
||||
*dest = '\0';
|
||||
}
|
||||
|
||||
bool collapseEscape(char *buf)
|
||||
{
|
||||
int len = dStrlen(buf) + 1;
|
||||
for(int i = 0; i < len;)
|
||||
{
|
||||
if(buf[i] == '\\')
|
||||
{
|
||||
if(buf[i+1] == 'x')
|
||||
{
|
||||
int dig1 = getHexDigit(buf[i+2]);
|
||||
if(dig1 == -1)
|
||||
return false;
|
||||
|
||||
int dig2 = getHexDigit(buf[i+3]);
|
||||
if(dig2 == -1)
|
||||
return false;
|
||||
buf[i] = dig1 * 16 + dig2;
|
||||
dMemmove(buf + i + 1, buf + i + 4, len - i - 3);
|
||||
len -= 3;
|
||||
i++;
|
||||
}
|
||||
else if(buf[i+1] == 'c')
|
||||
{
|
||||
/* Remap around: \t = 0x9, \n = 0xa, \r = 0xd */
|
||||
static char collapseRemap[10] = { 0x2,
|
||||
0x3,
|
||||
0x4,
|
||||
0x5,
|
||||
0x6,
|
||||
0x7,
|
||||
0x8,
|
||||
0xb,
|
||||
0xc,
|
||||
0xe };
|
||||
|
||||
if(buf[i+2] == 'r')
|
||||
buf[i] = 15;
|
||||
else if(buf[i+2] == 'p')
|
||||
buf[i] = 16;
|
||||
else if(buf[i+2] == 'o')
|
||||
buf[i] = 17;
|
||||
else
|
||||
{
|
||||
int dig1 = buf[i+2] - '0';
|
||||
if(dig1 < 0 || dig1 > 9)
|
||||
return false;
|
||||
buf[i] = collapseRemap[dig1];
|
||||
}
|
||||
dMemmove(buf + i + 1, buf + i + 3, len - i - 2);
|
||||
len -= 2;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[i] = charConv(buf[i+1]);
|
||||
dMemmove(buf + i + 1, buf + i + 2, len - i - 1);
|
||||
len--;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int Sc_ScanNum()
|
||||
{
|
||||
CMDtext[CMDleng] = 0;
|
||||
CMDlval.f = atof(CMDtext);
|
||||
return(FLTCONST);
|
||||
}
|
||||
|
||||
static int Sc_ScanHex()
|
||||
{
|
||||
int val = 0;
|
||||
dSscanf(CMDtext, "%x", &val);
|
||||
CMDlval.i = val;
|
||||
return INTCONST;
|
||||
}
|
||||
|
||||
64
console/scriptObject.cc
Normal file
64
console/scriptObject.cc
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "Platform/platform.h"
|
||||
#include "console/simBase.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
class ScriptObject : public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
StringTableEntry mClassName;
|
||||
StringTableEntry mSuperClassName;
|
||||
public:
|
||||
ScriptObject();
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
DECLARE_CONOBJECT(ScriptObject);
|
||||
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
IMPLEMENT_CONOBJECT(ScriptObject);
|
||||
|
||||
void ScriptObject::initPersistFields()
|
||||
{
|
||||
addField("class", TypeString, Offset(mClassName, ScriptObject));
|
||||
addField("superClass", TypeString, Offset(mSuperClassName, ScriptObject));
|
||||
}
|
||||
|
||||
ScriptObject::ScriptObject()
|
||||
{
|
||||
mClassName = "";
|
||||
mSuperClassName = "";
|
||||
}
|
||||
|
||||
bool ScriptObject::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
if(mClassName[0])
|
||||
{
|
||||
if(mSuperClassName[0])
|
||||
{
|
||||
Con::linkNamespaces(mSuperClassName, mClassName);
|
||||
Con::linkNamespaces("ScriptObject", mSuperClassName);
|
||||
}
|
||||
else
|
||||
Con::linkNamespaces("ScriptObject", mClassName);
|
||||
|
||||
mNameSpace = Con::lookupNamespace(mClassName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptObject::onRemove()
|
||||
{
|
||||
Parent::onRemove();
|
||||
}
|
||||
1527
console/simBase.cc
Normal file
1527
console/simBase.cc
Normal file
File diff suppressed because it is too large
Load diff
599
console/simBase.h
Normal file
599
console/simBase.h
Normal file
|
|
@ -0,0 +1,599 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SIMBASE_H_
|
||||
#define _SIMBASE_H_
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "Core/tVector.h"
|
||||
#endif
|
||||
#ifndef _TALGORITHM_H_
|
||||
#include "Core/tAlgorithm.h"
|
||||
#endif
|
||||
#ifndef _BITSET_H_
|
||||
#include "Core/bitSet.h"
|
||||
#endif
|
||||
|
||||
#ifndef _CONSOLEOBJECT_H_
|
||||
#include "console/consoleObject.h"
|
||||
#endif
|
||||
#ifndef _SIMDICTIONARY_H_
|
||||
#include "console/simDictionary.h"
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
enum
|
||||
{
|
||||
DataBlockObjectIdFirst = 3,
|
||||
DataBlockObjectIdBitSize = 10,
|
||||
DataBlockObjectIdLast = DataBlockObjectIdFirst + (1 << DataBlockObjectIdBitSize) - 1,
|
||||
|
||||
DynamicObjectIdFirst = DataBlockObjectIdLast + 1,
|
||||
InvalidEventId = 0,
|
||||
RootGroupId = 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
class SimEvent;
|
||||
class SimObject;
|
||||
class SimGroup;
|
||||
class SimManager;
|
||||
class Namespace;
|
||||
class BitStream;
|
||||
class Stream;
|
||||
class LightManager;
|
||||
|
||||
typedef U32 SimTime;
|
||||
typedef U32 SimObjectId;
|
||||
|
||||
class SimObjectList: public VectorPtr<SimObject*>
|
||||
{
|
||||
static S32 QSORT_CALLBACK compareId(const void* a,const void* b);
|
||||
public:
|
||||
void pushBack(SimObject*);
|
||||
void pushBackForce(SimObject*);
|
||||
void pushFront(SimObject*);
|
||||
void remove(SimObject*);
|
||||
void removeStable(SimObject* pObject) { /* remove is stable at the moment */ remove(pObject); }
|
||||
void sortId();
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class SimEvent
|
||||
{
|
||||
public:
|
||||
SimEvent *nextEvent;
|
||||
SimTime time;
|
||||
U32 sequenceCount;
|
||||
SimObject *destObject;
|
||||
|
||||
SimEvent() { destObject = NULL; }
|
||||
virtual ~SimEvent() {} // dummy virtual destructor is required
|
||||
// so that subclasses can be deleted properly
|
||||
virtual void process(SimObject *object)=0;
|
||||
};
|
||||
|
||||
class SimConsoleEvent : public SimEvent
|
||||
{
|
||||
S32 mArgc;
|
||||
char **mArgv;
|
||||
bool mOnObject;
|
||||
public:
|
||||
SimConsoleEvent(S32 argc, const char **argv, bool onObject);
|
||||
~SimConsoleEvent();
|
||||
virtual void process(SimObject *object);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
class SimFieldDictionary
|
||||
{
|
||||
friend class SimFieldDictionaryIterator;
|
||||
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
StringTableEntry slotName;
|
||||
char *value;
|
||||
Entry *next;
|
||||
};
|
||||
private:
|
||||
enum
|
||||
{
|
||||
HashTableSize = 19
|
||||
};
|
||||
Entry *mHashTable[HashTableSize];
|
||||
|
||||
static Entry *mFreeList;
|
||||
static void freeEntry(Entry *entry);
|
||||
static Entry *allocEntry();
|
||||
public:
|
||||
SimFieldDictionary();
|
||||
~SimFieldDictionary();
|
||||
void setFieldValue(StringTableEntry slotName, const char *value);
|
||||
const char *getFieldValue(StringTableEntry slotName);
|
||||
void writeFields(SimObject *obj, Stream &strem, U32 tabStop);
|
||||
void printFields(SimObject *obj);
|
||||
void assignFrom(SimFieldDictionary *dict);
|
||||
};
|
||||
|
||||
class SimFieldDictionaryIterator
|
||||
{
|
||||
SimFieldDictionary * mDictionary;
|
||||
S32 mHashIndex;
|
||||
SimFieldDictionary::Entry * mEntry;
|
||||
|
||||
public:
|
||||
SimFieldDictionaryIterator(SimFieldDictionary*);
|
||||
SimFieldDictionary::Entry* operator++();
|
||||
SimFieldDictionary::Entry* operator*();
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
class SimObject: public ConsoleObject
|
||||
{
|
||||
typedef ConsoleObject Parent;
|
||||
|
||||
friend class SimManager;
|
||||
friend class SimGroup;
|
||||
friend class SimNameDictionary;
|
||||
friend class SimManagerNameDictionary;
|
||||
friend class SimIdDictionary;
|
||||
|
||||
//-------------------------------------- Structures and enumerations
|
||||
private:
|
||||
enum {
|
||||
Deleted = 1 << 0,
|
||||
Removed = 1 << 1,
|
||||
Added = 1 << 3,
|
||||
Selected = 1 << 4,
|
||||
Expanded = 1 << 5,
|
||||
ModStaticFields = 1 << 6, // can read/modify static fields
|
||||
ModDynamicFields = 1 << 7 // can read/modify dynamic fields
|
||||
};
|
||||
public:
|
||||
struct Notify {
|
||||
enum Type {
|
||||
ClearNotify,
|
||||
DeleteNotify,
|
||||
ObjectRef,
|
||||
Invalid
|
||||
} type;
|
||||
void *ptr;
|
||||
Notify *next;
|
||||
};
|
||||
enum WriteFlags {
|
||||
SelectedOnly = BIT(0)
|
||||
};
|
||||
|
||||
private:
|
||||
// dictionary information stored on the object
|
||||
StringTableEntry objectName;
|
||||
SimObject* nextNameObject;
|
||||
SimObject* nextManagerNameObject;
|
||||
SimObject* nextIdObject;
|
||||
|
||||
SimGroup* mGroup;
|
||||
BitSet32 mFlags;
|
||||
Notify* mNotifyList;
|
||||
|
||||
protected:
|
||||
SimObjectId mId;
|
||||
Namespace* mNameSpace;
|
||||
U32 mTypeMask;
|
||||
|
||||
protected:
|
||||
static SimObject::Notify *mNotifyFreeList;
|
||||
static SimObject::Notify *allocNotify();
|
||||
static void freeNotify(SimObject::Notify*);
|
||||
private:
|
||||
SimFieldDictionary *mFieldDictionary;
|
||||
|
||||
public:
|
||||
const char *getDataField(StringTableEntry slotName, const char *array);
|
||||
void setDataField(StringTableEntry slotName, const char *array, const char *value);
|
||||
SimFieldDictionary * getFieldDictionary() {return(mFieldDictionary);}
|
||||
|
||||
SimObject();
|
||||
virtual ~SimObject();
|
||||
virtual bool processArguments(S32 argc, const char **argv);
|
||||
|
||||
virtual bool onAdd();
|
||||
virtual void onRemove();
|
||||
virtual void onGroupAdd();
|
||||
virtual void onGroupRemove();
|
||||
virtual void onNameChange(const char *name);
|
||||
virtual void onStaticModified(const char* slotName);
|
||||
virtual void inspectPreApply();
|
||||
virtual void inspectPostApply();
|
||||
|
||||
virtual void onDeleteNotify(SimObject *object);
|
||||
|
||||
virtual void onEditorEnable(){};
|
||||
virtual void onEditorDisable(){};
|
||||
|
||||
virtual SimObject *findObject(const char *name); // find a named sub-object of this object
|
||||
|
||||
Notify *removeNotify(void *ptr, Notify::Type);
|
||||
void deleteNotify(SimObject* obj);
|
||||
void clearNotify(SimObject* obj);
|
||||
void clearAllNotifications();
|
||||
void processDeleteNotifies();
|
||||
void registerReference(SimObject **obj);
|
||||
void unregisterReference(SimObject **obj);
|
||||
|
||||
bool registerObject();
|
||||
bool registerObject(U32 id);
|
||||
bool registerObject(const char *name);
|
||||
bool registerObject(const char *name, U32 id);
|
||||
|
||||
void unregisterObject();
|
||||
void deleteObject();
|
||||
|
||||
SimObjectId getId() const { return mId; }
|
||||
const char* getIdString();
|
||||
U32 getType() const { return mTypeMask; }
|
||||
const char* getName() const { return objectName; };
|
||||
|
||||
void setId(SimObjectId id);
|
||||
void assignName(const char* name);
|
||||
SimGroup* getGroup() const { return mGroup; }
|
||||
bool isProperlyAdded() const { return mFlags.test(Added); }
|
||||
bool isDeleted() const { return mFlags.test(Deleted); }
|
||||
bool isRemoved() const { return mFlags.test(Deleted | Removed); }
|
||||
bool isLocked();
|
||||
void setLocked( bool b );
|
||||
bool isHidden();
|
||||
void setHidden(bool b);
|
||||
|
||||
bool addToSet(SimObjectId);
|
||||
bool addToSet(const char *);
|
||||
bool removeFromSet(SimObjectId);
|
||||
bool removeFromSet(const char *);
|
||||
|
||||
virtual void write(Stream &stream, U32 tabStop, U32 flags = 0);
|
||||
void writeFields(Stream &stream, U32 tabStop);
|
||||
void assignFieldsFrom(SimObject *obj);
|
||||
|
||||
Namespace* getNamespace() { return mNameSpace; }
|
||||
const char *tabComplete(const char *prevText, S32 baseLen, bool);
|
||||
|
||||
bool isSelected() const { return mFlags.test(Selected); }
|
||||
bool isExpanded() const { return mFlags.test(Expanded); }
|
||||
void setSelected(bool sel) { if(sel) mFlags.set(Selected); else mFlags.clear(Selected); }
|
||||
void setExpanded(bool exp) { if(exp) mFlags.set(Expanded); else mFlags.clear(Expanded); }
|
||||
void setModDynamicFields(bool dyn) { if(dyn) mFlags.set(ModDynamicFields); else mFlags.clear(ModDynamicFields); }
|
||||
void setModStaticFields(bool sta) { if(sta) mFlags.set(ModStaticFields); else mFlags.clear(ModStaticFields); }
|
||||
|
||||
virtual void registerLights(LightManager *, bool) {};
|
||||
|
||||
static void consoleInit();
|
||||
|
||||
DECLARE_CONOBJECT(SimObject);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
template <class T> class SimObjectPtr
|
||||
{
|
||||
private:
|
||||
SimObject *mObj;
|
||||
|
||||
public:
|
||||
SimObjectPtr() { mObj = 0; }
|
||||
SimObjectPtr(T* ptr)
|
||||
{
|
||||
mObj = ptr;
|
||||
if(mObj)
|
||||
mObj->registerReference(&mObj);
|
||||
}
|
||||
SimObjectPtr(const SimObjectPtr<T>& rhs)
|
||||
{
|
||||
mObj = const_cast<T*>(static_cast<const T*>(rhs));
|
||||
if(mObj)
|
||||
mObj->registerReference(&mObj);
|
||||
}
|
||||
SimObjectPtr<T>& operator=(const SimObjectPtr<T>& rhs)
|
||||
{
|
||||
if(this == &rhs)
|
||||
return(*this);
|
||||
if(mObj)
|
||||
mObj->unregisterReference(&mObj);
|
||||
mObj = const_cast<T*>(static_cast<const T*>(rhs));
|
||||
if(mObj)
|
||||
mObj->registerReference(&mObj);
|
||||
return(*this);
|
||||
}
|
||||
~SimObjectPtr()
|
||||
{
|
||||
if(mObj)
|
||||
mObj->unregisterReference(&mObj);
|
||||
}
|
||||
SimObjectPtr<T>& operator= (T *ptr)
|
||||
{
|
||||
if(mObj != (SimObject *) ptr)
|
||||
{
|
||||
if(mObj)
|
||||
mObj->unregisterReference(&mObj);
|
||||
mObj = (SimObject *) ptr;
|
||||
if (mObj)
|
||||
mObj->registerReference(&mObj);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
operator bool() const { return mObj != 0; }
|
||||
bool isNull() const { return mObj == 0; }
|
||||
T* operator->() { return static_cast<T*>(mObj); }
|
||||
T& operator*() { return *static_cast<T*>(mObj); }
|
||||
operator T*() { return static_cast<T*>(mObj)? static_cast<T*>(mObj) : 0; }
|
||||
const T* operator->() const { return static_cast<const T*>(mObj); }
|
||||
const T& operator*() const { return *static_cast<const T*>(mObj); }
|
||||
operator const T*() const { return static_cast<T*>(mObj) ? static_cast<const T*>(mObj) : 0; }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
class SimDataBlock: public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
|
||||
protected:
|
||||
S32 modifiedKey;
|
||||
|
||||
public:
|
||||
static SimObjectId sNextObjectId;
|
||||
static S32 sNextModifiedKey;
|
||||
|
||||
SimDataBlock();
|
||||
DECLARE_CONOBJECT(SimDataBlock);
|
||||
|
||||
static S32 getNextModifiedKey() { return sNextModifiedKey; }
|
||||
S32 getModifiedKey() const { return modifiedKey; }
|
||||
|
||||
bool onAdd();
|
||||
void onStaticModified(const char* slotName);
|
||||
void setLastError(const char*);
|
||||
void assignId();
|
||||
|
||||
virtual bool preload(bool server, char errorBuffer[256]);
|
||||
|
||||
//
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
class SimSet: public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
protected:
|
||||
SimObjectList objectList;
|
||||
|
||||
public:
|
||||
SimSet() {
|
||||
VECTOR_SET_ASSOCIATION(objectList);
|
||||
}
|
||||
|
||||
typedef SimObjectList::iterator iterator;
|
||||
typedef SimObjectList::value_type value;
|
||||
SimObject* front() { return objectList.front(); }
|
||||
SimObject* first() { return objectList.first(); }
|
||||
SimObject* last() { return objectList.last(); }
|
||||
bool empty() { return objectList.empty(); }
|
||||
S32 size() { return objectList.size(); }
|
||||
iterator begin() { return objectList.begin(); }
|
||||
iterator end() { return objectList.end(); }
|
||||
value operator[] (S32 index) { return objectList[U32(index)]; }
|
||||
|
||||
iterator find( iterator first, iterator last, SimObject *obj)
|
||||
{ return ::find(first, last, obj); }
|
||||
|
||||
bool reOrder( SimObject *obj, SimObject *target=0 );
|
||||
|
||||
virtual void onRemove();
|
||||
virtual void onDeleteNotify(SimObject *object);
|
||||
|
||||
virtual void addObject(SimObject*);
|
||||
virtual void removeObject(SimObject*);
|
||||
|
||||
virtual void pushObject(SimObject*);
|
||||
virtual void popObject();
|
||||
|
||||
void bringObjectToFront(SimObject* obj) { reOrder(obj, front()); }
|
||||
void pushObjectToBack(SimObject* obj) { reOrder(obj, NULL); }
|
||||
|
||||
void write(Stream &stream, U32 tabStop, U32 flags = 0);
|
||||
|
||||
virtual SimObject *findObject(const char *name); // find a named sub-object of this object
|
||||
|
||||
DECLARE_CONOBJECT(SimSet);
|
||||
};
|
||||
|
||||
class SimSetIterator
|
||||
{
|
||||
struct Entry {
|
||||
SimSet* set;
|
||||
SimSet::iterator itr;
|
||||
};
|
||||
class Stack: public Vector<Entry> {
|
||||
public:
|
||||
void push_back(SimSet*);
|
||||
};
|
||||
Stack stack;
|
||||
|
||||
public:
|
||||
SimSetIterator(SimSet*);
|
||||
SimObject* operator++();
|
||||
SimObject* operator*() {
|
||||
return stack.empty()? 0: *stack.last().itr;
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
class SimGroup: public SimSet
|
||||
{
|
||||
private:
|
||||
friend class SimManager;
|
||||
friend class SimObject;
|
||||
|
||||
typedef SimSet Parent;
|
||||
SimNameDictionary nameDictionary;
|
||||
|
||||
public:
|
||||
~SimGroup();
|
||||
|
||||
void addObject(SimObject*);
|
||||
void addObject(SimObject*, SimObjectId);
|
||||
void addObject(SimObject*, const char *name);
|
||||
void removeObject(SimObject*);
|
||||
void onRemove();
|
||||
|
||||
virtual SimObject* findObject(const char* name);
|
||||
|
||||
bool processArguments(S32 argc, const char **argv);
|
||||
|
||||
DECLARE_CONOBJECT(SimGroup);
|
||||
};
|
||||
|
||||
inline void SimGroup::addObject(SimObject* obj, SimObjectId id)
|
||||
{
|
||||
// AddObject will assign it whatever id it already has.
|
||||
// This should normally be done only with reserved id's.
|
||||
obj->mId = id;
|
||||
addObject( obj );
|
||||
}
|
||||
|
||||
inline void SimGroup::addObject(SimObject *obj, const char *name)
|
||||
{
|
||||
addObject( obj );
|
||||
obj->assignName(name);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class SimDataBlockGroup : public SimGroup
|
||||
{
|
||||
private:
|
||||
S32 mLastModifiedKey;
|
||||
|
||||
public:
|
||||
static S32 QSORT_CALLBACK compareModifiedKey(const void* a,const void* b);
|
||||
void sort();
|
||||
SimDataBlockGroup();
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// helper macros for named sets and groups in the manager:
|
||||
|
||||
#define DeclareNamedSet(set) extern SimSet *g##set;inline SimSet *get##set() { return g##set; }
|
||||
#define DeclareNamedGroup(set) extern SimGroup *g##set;inline SimGroup *get##set() { return g##set; }
|
||||
#define ImplementNamedSet(set) SimSet *g##set;
|
||||
#define ImplementNamedGroup(set) SimGroup *g##set;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
namespace Sim
|
||||
{
|
||||
DeclareNamedSet(ActiveActionMapSet)
|
||||
DeclareNamedSet(GhostAlwaysSet)
|
||||
DeclareNamedSet(LightSet)
|
||||
DeclareNamedSet(WayPointSet)
|
||||
DeclareNamedSet(ClientTargetSet)
|
||||
DeclareNamedSet(ServerTargetSet)
|
||||
DeclareNamedSet(FlareSet)
|
||||
DeclareNamedSet(MissileSet)
|
||||
DeclareNamedSet(CommandTargetSet)
|
||||
DeclareNamedSet(ScopeSensorVisibleSet)
|
||||
DeclareNamedGroup(ActionMapGroup)
|
||||
DeclareNamedGroup(ClientGroup)
|
||||
DeclareNamedGroup(GuiGroup)
|
||||
DeclareNamedGroup(GuiDataGroup)
|
||||
DeclareNamedGroup(TCPGroup)
|
||||
DeclareNamedGroup(ClientConnectionGroup)
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
SimDataBlockGroup *getDataBlockGroup();
|
||||
SimGroup* getRootGroup();
|
||||
|
||||
SimObject* findObject(SimObjectId);
|
||||
SimObject* findObject(const char* name);
|
||||
template<class T> inline bool findObject(SimObjectId id,T*&t)
|
||||
{
|
||||
t = dynamic_cast<T*>(findObject(id));
|
||||
return t != NULL;
|
||||
}
|
||||
template<class T> inline bool findObject(const char *objectName,T*&t)
|
||||
{
|
||||
t = dynamic_cast<T*>(findObject(objectName));
|
||||
return t != NULL;
|
||||
}
|
||||
|
||||
void advanceToTime(SimTime time);
|
||||
void advanceTime(SimTime delta);
|
||||
SimTime getCurrentTime();
|
||||
SimTime getTargetTime();
|
||||
|
||||
// a target time of 0 on an event means current event
|
||||
U32 postEvent(SimObject*, SimEvent*, U32 targetTime);
|
||||
|
||||
inline U32 postEvent(SimObjectId id,SimEvent*evt, U32 targetTime)
|
||||
{
|
||||
return postEvent(findObject(id), evt, targetTime);
|
||||
}
|
||||
inline U32 postEvent(const char *objectName,SimEvent*evt, U32 targetTime)
|
||||
{
|
||||
return postEvent(findObject(objectName), evt, targetTime);
|
||||
}
|
||||
inline U32 postCurrentEvent(SimObject*obj, SimEvent*evt)
|
||||
{
|
||||
return postEvent(obj,evt,getCurrentTime());
|
||||
}
|
||||
inline U32 postCurrentEvent(SimObjectId obj,SimEvent*evt)
|
||||
{
|
||||
return postEvent(obj,evt,getCurrentTime());
|
||||
}
|
||||
inline U32 postCurrentEvent(const char *obj,SimEvent*evt)
|
||||
{
|
||||
return postEvent(obj,evt,getCurrentTime());
|
||||
}
|
||||
|
||||
void cancelEvent(U32 eventId);
|
||||
bool isEventPending(U32 eventId);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#define IMPLEMENT_SETDATATYPE(T) \
|
||||
void setDataTypeDataBlockPtr##T(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32) \
|
||||
{ \
|
||||
volatile SimDataBlock* pConstraint = static_cast<SimDataBlock*>((T*)NULL); \
|
||||
\
|
||||
if (argc == 1) { \
|
||||
*reinterpret_cast<T**>(dptr) = NULL; \
|
||||
if (argv[0] && argv[0][0] && !Sim::findObject(argv[0],*reinterpret_cast<T**>(dptr))) \
|
||||
Con::printf("Object \"%s\" is not a member of the expected data block class", argv[0]); \
|
||||
} \
|
||||
else \
|
||||
Con::printf("Cannot set multiple args to a single pointer."); \
|
||||
}
|
||||
|
||||
#define IMPLEMENT_GETDATATYPE(T) \
|
||||
const char* getDataTypeDataBlockPtr##T(void *dptr, EnumTable *, BitSet32) \
|
||||
{ \
|
||||
volatile SimDataBlock* pConstraint = static_cast<SimDataBlock*>((T*)NULL); \
|
||||
\
|
||||
T** obj = reinterpret_cast<T**>(dptr); \
|
||||
return *obj ? (*obj)->getName() : ""; \
|
||||
}
|
||||
|
||||
#define REF_SETDATATYPE(T) setDataTypeDataBlockPtr##T
|
||||
#define REF_GETDATATYPE(T) getDataTypeDataBlockPtr##T
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
247
console/simDictionary.cc
Normal file
247
console/simDictionary.cc
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/simDictionary.h"
|
||||
#include "console/simBase.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
extern S32 HashPointer(StringTableEntry e);
|
||||
|
||||
SimNameDictionary::SimNameDictionary()
|
||||
{
|
||||
hashTable = NULL;
|
||||
}
|
||||
|
||||
SimNameDictionary::~SimNameDictionary()
|
||||
{
|
||||
delete[] hashTable;
|
||||
}
|
||||
|
||||
void SimNameDictionary::insert(SimObject* obj)
|
||||
{
|
||||
if(!obj->objectName)
|
||||
return;
|
||||
|
||||
if(!hashTable)
|
||||
{
|
||||
hashTable = new SimObject *[DefaultTableSize];
|
||||
hashTableSize = DefaultTableSize;
|
||||
hashEntryCount = 0;
|
||||
S32 i;
|
||||
for(i = 0; i < hashTableSize; i++)
|
||||
hashTable[i] = NULL;
|
||||
}
|
||||
S32 idx = HashPointer(obj->objectName) % hashTableSize;
|
||||
obj->nextNameObject = hashTable[idx];
|
||||
hashTable[idx] = obj;
|
||||
hashEntryCount++;
|
||||
if(hashEntryCount > hashTableSize)
|
||||
{
|
||||
// resize the hash table
|
||||
S32 i;
|
||||
SimObject *head = NULL, *walk, *temp;
|
||||
for(i = 0; i < hashTableSize; i++) {
|
||||
walk = hashTable[i];
|
||||
while(walk)
|
||||
{
|
||||
temp = walk->nextNameObject;
|
||||
walk->nextNameObject = head;
|
||||
head = walk;
|
||||
walk = temp;
|
||||
}
|
||||
}
|
||||
delete[] hashTable;
|
||||
hashTableSize = hashTableSize * 2 + 1;
|
||||
hashTable = new SimObject *[hashTableSize];
|
||||
|
||||
for(i = 0; i < hashTableSize;i++)
|
||||
hashTable[i] = NULL;
|
||||
while(head)
|
||||
{
|
||||
temp = head->nextNameObject;
|
||||
idx = HashPointer(head->objectName) % hashTableSize;
|
||||
head->nextNameObject = hashTable[idx];
|
||||
hashTable[idx] = head;
|
||||
head = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimObject* SimNameDictionary::find(StringTableEntry name)
|
||||
{
|
||||
// NULL is a valid lookup - it will always return NULL
|
||||
if(!hashTable)
|
||||
return NULL;
|
||||
|
||||
S32 idx = HashPointer(name) % hashTableSize;
|
||||
SimObject *walk = hashTable[idx];
|
||||
while(walk)
|
||||
{
|
||||
if(walk->objectName == name)
|
||||
return walk;
|
||||
walk = walk->nextNameObject;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SimNameDictionary::remove(SimObject* obj)
|
||||
{
|
||||
if(!obj->objectName)
|
||||
return;
|
||||
|
||||
SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize];
|
||||
while(*walk)
|
||||
{
|
||||
if(*walk == obj)
|
||||
{
|
||||
*walk = obj->nextNameObject;
|
||||
obj->nextNameObject = (SimObject*)-1;
|
||||
hashEntryCount--;
|
||||
return;
|
||||
}
|
||||
walk = &((*walk)->nextNameObject);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
SimManagerNameDictionary::SimManagerNameDictionary()
|
||||
{
|
||||
hashTable = new SimObject *[DefaultTableSize];
|
||||
hashTableSize = DefaultTableSize;
|
||||
hashEntryCount = 0;
|
||||
S32 i;
|
||||
for(i = 0; i < hashTableSize; i++)
|
||||
hashTable[i] = NULL;
|
||||
}
|
||||
|
||||
SimManagerNameDictionary::~SimManagerNameDictionary()
|
||||
{
|
||||
delete[] hashTable;
|
||||
}
|
||||
|
||||
void SimManagerNameDictionary::insert(SimObject* obj)
|
||||
{
|
||||
if(!obj->objectName)
|
||||
return;
|
||||
|
||||
S32 idx = HashPointer(obj->objectName) % hashTableSize;
|
||||
obj->nextManagerNameObject = hashTable[idx];
|
||||
hashTable[idx] = obj;
|
||||
hashEntryCount++;
|
||||
if(hashEntryCount > hashTableSize)
|
||||
{
|
||||
// resize the hash table
|
||||
S32 i;
|
||||
SimObject *head = NULL, *walk, *temp;
|
||||
for(i = 0; i < hashTableSize; i++) {
|
||||
walk = hashTable[i];
|
||||
while(walk)
|
||||
{
|
||||
temp = walk->nextManagerNameObject;
|
||||
walk->nextManagerNameObject = head;
|
||||
head = walk;
|
||||
walk = temp;
|
||||
}
|
||||
}
|
||||
delete[] hashTable;
|
||||
hashTableSize = hashTableSize * 2 + 1;
|
||||
hashTable = new SimObject *[hashTableSize];
|
||||
|
||||
for(i = 0; i < hashTableSize;i++)
|
||||
hashTable[i] = NULL;
|
||||
while(head)
|
||||
{
|
||||
temp = head->nextManagerNameObject;
|
||||
idx = HashPointer(head->objectName) % hashTableSize;
|
||||
head->nextManagerNameObject = hashTable[idx];
|
||||
hashTable[idx] = head;
|
||||
head = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimObject* SimManagerNameDictionary::find(StringTableEntry name)
|
||||
{
|
||||
// NULL is a valid lookup - it will always return NULL
|
||||
|
||||
S32 idx = HashPointer(name) % hashTableSize;
|
||||
SimObject *walk = hashTable[idx];
|
||||
while(walk)
|
||||
{
|
||||
if(walk->objectName == name)
|
||||
return walk;
|
||||
walk = walk->nextManagerNameObject;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SimManagerNameDictionary::remove(SimObject* obj)
|
||||
{
|
||||
if(!obj->objectName)
|
||||
return;
|
||||
|
||||
SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize];
|
||||
while(*walk)
|
||||
{
|
||||
if(*walk == obj)
|
||||
{
|
||||
*walk = obj->nextManagerNameObject;
|
||||
obj->nextManagerNameObject = (SimObject*)-1;
|
||||
hashEntryCount--;
|
||||
return;
|
||||
}
|
||||
walk = &((*walk)->nextManagerNameObject);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
SimIdDictionary::SimIdDictionary()
|
||||
{
|
||||
for(S32 i = 0; i < DefaultTableSize; i++)
|
||||
table[i] = NULL;
|
||||
}
|
||||
|
||||
SimIdDictionary::~SimIdDictionary()
|
||||
{
|
||||
}
|
||||
|
||||
void SimIdDictionary::insert(SimObject* obj)
|
||||
{
|
||||
S32 idx = obj->getId() & TableBitMask;
|
||||
obj->nextIdObject = table[idx];
|
||||
table[idx] = obj;
|
||||
}
|
||||
|
||||
SimObject* SimIdDictionary::find(S32 id)
|
||||
{
|
||||
S32 idx = id & TableBitMask;
|
||||
SimObject *walk = table[idx];
|
||||
while(walk)
|
||||
{
|
||||
if(walk->getId() == U32(id))
|
||||
return walk;
|
||||
walk = walk->nextIdObject;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SimIdDictionary::remove(SimObject* obj)
|
||||
{
|
||||
SimObject **walk = &table[obj->getId() & TableBitMask];
|
||||
while(*walk && *walk != obj)
|
||||
walk = &((*walk)->nextIdObject);
|
||||
if(*walk)
|
||||
*walk = obj->nextIdObject;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
84
console/simDictionary.h
Normal file
84
console/simDictionary.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SIMDICTIONARY_H_
|
||||
#define _SIMDICTIONARY_H_
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "Platform/platform.h"
|
||||
#endif
|
||||
#ifndef _STRINGTABLE_H_
|
||||
#include "Core/stringTable.h"
|
||||
#endif
|
||||
|
||||
class SimObject;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Map of Names to simObjects
|
||||
// Provides fast lookup for name->object and
|
||||
// for fast removal of an object given object*
|
||||
//
|
||||
class SimNameDictionary
|
||||
{
|
||||
enum
|
||||
{
|
||||
DefaultTableSize = 29
|
||||
};
|
||||
|
||||
SimObject **hashTable; // hash the pointers of the names...
|
||||
S32 hashTableSize;
|
||||
S32 hashEntryCount;
|
||||
public:
|
||||
void insert(SimObject* obj);
|
||||
void remove(SimObject* obj);
|
||||
SimObject* find(StringTableEntry name);
|
||||
|
||||
SimNameDictionary();
|
||||
~SimNameDictionary();
|
||||
};
|
||||
|
||||
class SimManagerNameDictionary
|
||||
{
|
||||
enum
|
||||
{
|
||||
DefaultTableSize = 29
|
||||
};
|
||||
|
||||
SimObject **hashTable; // hash the pointers of the names...
|
||||
S32 hashTableSize;
|
||||
S32 hashEntryCount;
|
||||
public:
|
||||
void insert(SimObject* obj);
|
||||
void remove(SimObject* obj);
|
||||
SimObject* find(StringTableEntry name);
|
||||
|
||||
SimManagerNameDictionary();
|
||||
~SimManagerNameDictionary();
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Map of ID's to simObjects
|
||||
// Provides fast lookup for ID->object and
|
||||
// for fast removal of an object given object*
|
||||
//
|
||||
class SimIdDictionary
|
||||
{
|
||||
enum
|
||||
{
|
||||
DefaultTableSize = 4096,
|
||||
TableBitMask = 4095
|
||||
};
|
||||
SimObject *table[DefaultTableSize];
|
||||
public:
|
||||
void insert(SimObject* obj);
|
||||
void remove(SimObject* obj);
|
||||
SimObject* find(S32 id);
|
||||
|
||||
SimIdDictionary();
|
||||
~SimIdDictionary();
|
||||
};
|
||||
|
||||
#endif //_SIMDICTIONARY_H_
|
||||
449
console/simManager.cc
Normal file
449
console/simManager.cc
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "Platform/platform.h"
|
||||
#include "console/simBase.h"
|
||||
#include "Core/stringTable.h"
|
||||
#include "console/console.h"
|
||||
#include "Core/fileStream.h"
|
||||
#include "Core/resManager.h"
|
||||
#include "Core/fileObject.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "Core/idGenerator.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
namespace Sim
|
||||
{
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// event queue variables:
|
||||
|
||||
SimTime gCurrentTime;
|
||||
SimTime gTargetTime;
|
||||
|
||||
SimEvent *gEventQueue;
|
||||
U32 gEventSequence;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// event queue init/shutdown
|
||||
|
||||
static void initEventQueue()
|
||||
{
|
||||
gCurrentTime = 0;
|
||||
gTargetTime = 0;
|
||||
gEventSequence = 1;
|
||||
gEventQueue = NULL;
|
||||
}
|
||||
|
||||
static void shutdownEventQueue()
|
||||
{
|
||||
// Delete all pending events
|
||||
SimEvent *walk = gEventQueue;
|
||||
while(walk)
|
||||
{
|
||||
SimEvent *temp = walk->nextEvent;
|
||||
delete walk;
|
||||
walk = temp;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// event post
|
||||
|
||||
U32 postEvent(SimObject *destObject, SimEvent* event,U32 time)
|
||||
{
|
||||
AssertFatal(time >= gCurrentTime,
|
||||
"Sim::postEvent: Cannot go back in time.");
|
||||
AssertFatal(destObject, "Destination object for event doesn't exist.");
|
||||
|
||||
event->time = time;
|
||||
event->destObject = destObject;
|
||||
|
||||
if(!destObject)
|
||||
{
|
||||
delete event;
|
||||
return InvalidEventId;
|
||||
}
|
||||
event->sequenceCount = gEventSequence++;
|
||||
SimEvent **walk = &gEventQueue;
|
||||
SimEvent *current;
|
||||
|
||||
while((current = *walk) != NULL && (current->time < event->time))
|
||||
walk = &(current->nextEvent);
|
||||
event->nextEvent = current;
|
||||
*walk = event;
|
||||
return event->sequenceCount;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// event cancellation
|
||||
|
||||
void cancelEvent(U32 eventSequence)
|
||||
{
|
||||
SimEvent **walk = &gEventQueue;
|
||||
SimEvent *current;
|
||||
|
||||
while((current = *walk) != NULL)
|
||||
{
|
||||
if(current->sequenceCount == eventSequence)
|
||||
{
|
||||
*walk = current->nextEvent;
|
||||
delete current;
|
||||
return;
|
||||
}
|
||||
else
|
||||
walk = &(current->nextEvent);
|
||||
}
|
||||
}
|
||||
|
||||
static void cancelPendingEvents(SimObject *obj)
|
||||
{
|
||||
SimEvent **walk = &gEventQueue;
|
||||
SimEvent *current;
|
||||
|
||||
while((current = *walk) != NULL)
|
||||
{
|
||||
if(current->destObject == obj)
|
||||
{
|
||||
*walk = current->nextEvent;
|
||||
delete current;
|
||||
}
|
||||
else
|
||||
walk = &(current->nextEvent);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// event pending test
|
||||
|
||||
bool isEventPending(U32 eventSequence)
|
||||
{
|
||||
for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
|
||||
if(walk->sequenceCount == eventSequence)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// event timing
|
||||
|
||||
void advanceToTime(SimTime targetTime)
|
||||
{
|
||||
AssertFatal(targetTime >= gCurrentTime, "EventQueue::process: cannot advance to time in the past.");
|
||||
|
||||
gTargetTime = targetTime;
|
||||
while(gEventQueue && gEventQueue->time <= targetTime)
|
||||
{
|
||||
SimEvent *event = gEventQueue;
|
||||
gEventQueue = gEventQueue->nextEvent;
|
||||
AssertFatal(event->time >= gCurrentTime,
|
||||
"SimEventQueue::pop: Cannot go back in time.");
|
||||
gCurrentTime = event->time;
|
||||
SimObject *obj = event->destObject;
|
||||
|
||||
if(!obj->isDeleted())
|
||||
event->process(obj);
|
||||
delete event;
|
||||
}
|
||||
gCurrentTime = targetTime;
|
||||
}
|
||||
|
||||
void advanceTime(SimTime delta)
|
||||
{
|
||||
advanceToTime(gCurrentTime + delta);
|
||||
}
|
||||
|
||||
U32 getCurrentTime()
|
||||
{
|
||||
return gCurrentTime;
|
||||
}
|
||||
|
||||
U32 getTargetTime()
|
||||
{
|
||||
return gTargetTime;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
SimGroup *gRootGroup = NULL;
|
||||
SimManagerNameDictionary *gNameDictionary;
|
||||
SimIdDictionary *gIdDictionary;
|
||||
U32 gNextObjectId;
|
||||
|
||||
static void initRoot()
|
||||
{
|
||||
gIdDictionary = new SimIdDictionary;
|
||||
gNameDictionary = new SimManagerNameDictionary;
|
||||
|
||||
gRootGroup = new SimGroup();
|
||||
gRootGroup->setId(RootGroupId);
|
||||
gRootGroup->assignName("RootGroup");
|
||||
gRootGroup->registerObject();
|
||||
|
||||
gNextObjectId = DynamicObjectIdFirst;
|
||||
}
|
||||
|
||||
static void shutdownRoot()
|
||||
{
|
||||
gRootGroup->deleteObject();
|
||||
|
||||
delete gNameDictionary;
|
||||
delete gIdDictionary;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
SimObject* findObject(const char* name)
|
||||
{
|
||||
SimObject *obj;
|
||||
char c = *name;
|
||||
if(c == '/')
|
||||
return gRootGroup->findObject(name + 1 );
|
||||
if(c >= '0' && c <= '9')
|
||||
{
|
||||
// it's an id group
|
||||
const char* temp = name + 1;
|
||||
for(;;)
|
||||
{
|
||||
c = *temp++;
|
||||
if(!c)
|
||||
return findObject(dAtoi(name));
|
||||
else if(c == '/')
|
||||
{
|
||||
obj = findObject(dAtoi(name));
|
||||
if(!obj)
|
||||
return NULL;
|
||||
return obj->findObject(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
S32 len;
|
||||
|
||||
for(len = 0; name[len] != 0 && name[len] != '/'; len++)
|
||||
;
|
||||
StringTableEntry stName = StringTable->lookupn(name, len);
|
||||
if(!stName)
|
||||
return NULL;
|
||||
obj = gNameDictionary->find(stName);
|
||||
if(!name[len])
|
||||
return obj;
|
||||
if(!obj)
|
||||
return NULL;
|
||||
return obj->findObject(name + len + 1);
|
||||
}
|
||||
|
||||
SimObject* findObject(SimObjectId id)
|
||||
{
|
||||
return gIdDictionary->find(id);
|
||||
}
|
||||
|
||||
SimGroup *getRootGroup()
|
||||
{
|
||||
return gRootGroup;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#define InstantiateNamedSet(set) g##set = new SimSet; g##set->registerObject(#set); gRootGroup->addObject(g##set)
|
||||
#define InstantiateNamedGroup(set) g##set = new SimGroup; g##set->registerObject(#set); gRootGroup->addObject(g##set)
|
||||
|
||||
SimDataBlockGroup *gDataBlockGroup;
|
||||
SimDataBlockGroup *getDataBlockGroup()
|
||||
{
|
||||
return gDataBlockGroup;
|
||||
}
|
||||
|
||||
|
||||
void init()
|
||||
{
|
||||
initEventQueue();
|
||||
initRoot();
|
||||
|
||||
InstantiateNamedSet(ActiveActionMapSet);
|
||||
InstantiateNamedSet(GhostAlwaysSet);
|
||||
InstantiateNamedSet(LightSet);
|
||||
InstantiateNamedSet(WayPointSet);
|
||||
InstantiateNamedSet(ClientTargetSet);
|
||||
InstantiateNamedSet(ServerTargetSet);
|
||||
InstantiateNamedSet(FlareSet);
|
||||
InstantiateNamedSet(MissileSet);
|
||||
InstantiateNamedSet(CommandTargetSet);
|
||||
InstantiateNamedSet(ScopeSensorVisibleSet);
|
||||
InstantiateNamedGroup(ActionMapGroup);
|
||||
InstantiateNamedGroup(ClientGroup);
|
||||
InstantiateNamedGroup(GuiGroup);
|
||||
InstantiateNamedGroup(GuiDataGroup);
|
||||
InstantiateNamedGroup(TCPGroup);
|
||||
InstantiateNamedGroup(ClientConnectionGroup);
|
||||
gDataBlockGroup = new SimDataBlockGroup();
|
||||
gDataBlockGroup->registerObject("DataBlockGroup");
|
||||
gRootGroup->addObject(gDataBlockGroup);
|
||||
}
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
shutdownRoot();
|
||||
shutdownEventQueue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SimDataBlockGroup::SimDataBlockGroup()
|
||||
{
|
||||
mLastModifiedKey = 0;
|
||||
}
|
||||
|
||||
S32 QSORT_CALLBACK SimDataBlockGroup::compareModifiedKey(const void* a,const void* b)
|
||||
{
|
||||
return (reinterpret_cast<const SimDataBlock* >(a))->getModifiedKey() -
|
||||
(reinterpret_cast<const SimDataBlock*>(b))->getModifiedKey();
|
||||
}
|
||||
|
||||
|
||||
void SimDataBlockGroup::sort()
|
||||
{
|
||||
if(mLastModifiedKey != SimDataBlock::getNextModifiedKey())
|
||||
{
|
||||
mLastModifiedKey = SimDataBlock::getNextModifiedKey();
|
||||
dQsort(objectList.address(),objectList.size(),sizeof(SimObject *),compareModifiedKey);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool SimObject::registerObject()
|
||||
{
|
||||
mFlags.clear(Deleted | Removed);
|
||||
|
||||
if(!mId)
|
||||
mId = Sim::gNextObjectId++;
|
||||
|
||||
Sim::gIdDictionary->insert(this);
|
||||
|
||||
Sim::gNameDictionary->insert(this);
|
||||
|
||||
// Notify object
|
||||
bool ret = onAdd();
|
||||
|
||||
if(!ret)
|
||||
unregisterObject();
|
||||
|
||||
AssertFatal(!ret || isProperlyAdded(), "Object did not call SimObject::onAdd()");
|
||||
return ret;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void SimObject::unregisterObject()
|
||||
{
|
||||
mFlags.set(Removed);
|
||||
|
||||
// Notify object first
|
||||
onRemove();
|
||||
|
||||
// Clear out any pending notifications before
|
||||
// we call our own, just in case they delete
|
||||
// something that we have referenced.
|
||||
clearAllNotifications();
|
||||
|
||||
// Notify all objects that are waiting for delete
|
||||
// messages
|
||||
if (getGroup())
|
||||
getGroup()->removeObject(this);
|
||||
|
||||
processDeleteNotifies();
|
||||
|
||||
//
|
||||
Sim::gNameDictionary->remove(this);
|
||||
Sim::gIdDictionary->remove(this);
|
||||
Sim::cancelPendingEvents(this);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void SimObject::deleteObject()
|
||||
{
|
||||
AssertFatal(mFlags.test(Added),
|
||||
"SimObject::deleteObject: Object not registered.");
|
||||
AssertFatal(!isDeleted(),"SimManger::deleteObject: "
|
||||
"Object has already been deleted");
|
||||
AssertFatal(!isRemoved(),"SimManger::deleteObject: "
|
||||
"Object in the process of being removed");
|
||||
mFlags.set(Deleted);
|
||||
|
||||
unregisterObject();
|
||||
delete this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
void SimObject::setId(SimObjectId newId)
|
||||
{
|
||||
if(!mFlags.test(Added))
|
||||
{
|
||||
mId = newId;
|
||||
return;
|
||||
}
|
||||
|
||||
// get this object out of the id dictionary if it's in it
|
||||
Sim::gIdDictionary->remove(this);
|
||||
|
||||
// Free current Id.
|
||||
// Assign new one.
|
||||
mId = newId ? newId : Sim::gNextObjectId++;
|
||||
Sim::gIdDictionary->insert(this);
|
||||
}
|
||||
|
||||
void SimObject::assignName(const char *name)
|
||||
{
|
||||
StringTableEntry newName = NULL;
|
||||
if(name[0])
|
||||
newName = StringTable->insert(name);
|
||||
|
||||
if(mGroup)
|
||||
mGroup->nameDictionary.remove(this);
|
||||
if(mFlags.test(Added))
|
||||
Sim::gNameDictionary->remove(this);
|
||||
|
||||
objectName = newName;
|
||||
|
||||
if(mGroup)
|
||||
mGroup->nameDictionary.insert(this);
|
||||
if(mFlags.test(Added))
|
||||
Sim::gNameDictionary->insert(this);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool SimObject::registerObject(U32 id)
|
||||
{
|
||||
setId(id);
|
||||
return registerObject();
|
||||
}
|
||||
|
||||
bool SimObject::registerObject(const char *name)
|
||||
{
|
||||
assignName(name);
|
||||
return registerObject();
|
||||
}
|
||||
|
||||
bool SimObject::registerObject(const char *name, U32 id)
|
||||
{
|
||||
setId(id);
|
||||
assignName(name);
|
||||
return registerObject();
|
||||
}
|
||||
256
console/telnetConsole.cc
Normal file
256
console/telnetConsole.cc
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "Platform/platform.h"
|
||||
#include "Platform/event.h"
|
||||
#include "console/telnetConsole.h"
|
||||
#include "Platform/gameInterface.h"
|
||||
|
||||
TelnetConsole *TelConsole = NULL;
|
||||
|
||||
void TelnetConsole::create()
|
||||
{
|
||||
TelConsole = new TelnetConsole;
|
||||
}
|
||||
|
||||
void TelnetConsole::destroy()
|
||||
{
|
||||
delete TelConsole;
|
||||
TelConsole = NULL;
|
||||
}
|
||||
|
||||
static void cTelnetSetParams(SimObject *, S32, const char **argv)
|
||||
{
|
||||
TelConsole->setTelnetParameters(dAtoi(argv[1]), argv[2], argv[3]);
|
||||
}
|
||||
|
||||
static void telnetCallback(ConsoleLogEntry::Level level, const char *consoleLine)
|
||||
{
|
||||
TelConsole->processConsoleLine(consoleLine);
|
||||
}
|
||||
|
||||
TelnetConsole::TelnetConsole()
|
||||
{
|
||||
Con::addConsumer(telnetCallback);
|
||||
Con::addCommand("telnetSetParameters", cTelnetSetParams, "telnetSetParameters(port,consolePass,listenPass)", 4, 4);
|
||||
|
||||
mAcceptSocket = InvalidSocket;
|
||||
mAcceptPort = -1;
|
||||
mClientList = NULL;
|
||||
}
|
||||
|
||||
TelnetConsole::~TelnetConsole()
|
||||
{
|
||||
Con::removeConsumer(telnetCallback);
|
||||
if(mAcceptSocket != InvalidSocket)
|
||||
Net::closeSocket(mAcceptSocket);
|
||||
TelnetClient *walk = mClientList, *temp;
|
||||
while(walk)
|
||||
{
|
||||
temp = walk->nextClient;
|
||||
if(walk->socket != InvalidSocket)
|
||||
Net::closeSocket(walk->socket);
|
||||
delete walk;
|
||||
walk = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void TelnetConsole::setTelnetParameters(S32 port, const char *telnetPassword, const char *listenPassword)
|
||||
{
|
||||
if(port == mAcceptPort)
|
||||
return;
|
||||
|
||||
if(mAcceptSocket != InvalidSocket)
|
||||
{
|
||||
Net::closeSocket(mAcceptSocket);
|
||||
mAcceptSocket = InvalidSocket;
|
||||
}
|
||||
mAcceptPort = port;
|
||||
if(mAcceptPort != -1 && mAcceptPort != 0)
|
||||
{
|
||||
mAcceptSocket = Net::openSocket();
|
||||
Net::bind(mAcceptSocket, mAcceptPort);
|
||||
Net::listen(mAcceptSocket, 4);
|
||||
|
||||
Net::setBlocking(mAcceptSocket, false);
|
||||
}
|
||||
dStrncpy(mTelnetPassword, telnetPassword, PasswordMaxLength);
|
||||
dStrncpy(mListenPassword, listenPassword, PasswordMaxLength);
|
||||
}
|
||||
|
||||
void TelnetConsole::processConsoleLine(const char *consoleLine)
|
||||
{
|
||||
// ok, spew this line out to all our subscribers...
|
||||
S32 len = dStrlen(consoleLine)+1;
|
||||
for(TelnetClient *walk = mClientList; walk; walk = walk->nextClient)
|
||||
{
|
||||
if(walk->state == FullAccessConnected || walk->state == ReadOnlyConnected)
|
||||
{
|
||||
Net::send(walk->socket, (const unsigned char*)consoleLine, len);
|
||||
Net::send(walk->socket, (const unsigned char*)"\r\n", 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TelnetConsole::process()
|
||||
{
|
||||
NetAddress address;
|
||||
|
||||
if(mAcceptSocket != InvalidSocket)
|
||||
{
|
||||
// ok, see if we have any new connections:
|
||||
NetSocket newConnection;
|
||||
newConnection = Net::accept(mAcceptSocket, &address);
|
||||
|
||||
if(newConnection != InvalidSocket)
|
||||
{
|
||||
Con::printf ("Telnet connection from %i.%i.%i.%i",
|
||||
address.netNum[0], address.netNum[1], address.netNum[2], address.netNum[3]);
|
||||
|
||||
TelnetClient *cl = new TelnetClient;
|
||||
cl->socket = newConnection;
|
||||
cl->curPos = 0;
|
||||
cl->state = PasswordTryOne;
|
||||
|
||||
Net::setBlocking(newConnection, false);
|
||||
|
||||
char *connectMessage = "Tribes 2 Telnet\r\n\r\nEnter Password:";
|
||||
|
||||
Net::send(cl->socket, (const unsigned char*)connectMessage, dStrlen(connectMessage)+1);
|
||||
cl->nextClient = mClientList;
|
||||
mClientList = cl;
|
||||
}
|
||||
}
|
||||
|
||||
char recvBuf[256];
|
||||
char reply[1024];
|
||||
|
||||
// see if we have any input to process...
|
||||
|
||||
for(TelnetClient *client = mClientList; client; client = client->nextClient)
|
||||
{
|
||||
S32 numBytes;
|
||||
Net::Error err = Net::recv(client->socket, (unsigned char*)recvBuf, sizeof(recvBuf), &numBytes);
|
||||
|
||||
if((err != Net::NoError && err != Net::WouldBlock) || numBytes == 0)
|
||||
{
|
||||
Net::closeSocket(client->socket);
|
||||
client->socket = InvalidSocket;
|
||||
continue;
|
||||
}
|
||||
|
||||
S32 replyPos = 0;
|
||||
for(S32 i = 0; i < numBytes;i++)
|
||||
{
|
||||
if(recvBuf[i] == '\r')
|
||||
continue;
|
||||
// execute the current command
|
||||
|
||||
if(recvBuf[i] == '\n')
|
||||
{
|
||||
reply[replyPos++] = '\r';
|
||||
reply[replyPos++] = '\n';
|
||||
|
||||
client->curLine[client->curPos] = 0;
|
||||
client->curPos = 0;
|
||||
|
||||
if(client->state == FullAccessConnected)
|
||||
{
|
||||
Net::send(client->socket, (const unsigned char*)reply, replyPos);
|
||||
replyPos = 0;
|
||||
|
||||
dStrcpy(mPostEvent.data, client->curLine);
|
||||
mPostEvent.size = ConsoleEventHeaderSize + dStrlen(client->curLine) + 1;
|
||||
Game->postEvent(mPostEvent);
|
||||
|
||||
// note - send prompt next
|
||||
const char *prompt = Con::getVariable("Con::Prompt");
|
||||
Net::send(client->socket, (const unsigned char*)prompt, dStrlen(prompt));
|
||||
}
|
||||
else if(client->state == ReadOnlyConnected)
|
||||
{
|
||||
Net::send(client->socket, (const unsigned char*)reply, replyPos);
|
||||
replyPos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
client->state++;
|
||||
if(!dStrncmp(client->curLine, mTelnetPassword, PasswordMaxLength))
|
||||
{
|
||||
Net::send(client->socket, (const unsigned char*)reply, replyPos);
|
||||
replyPos = 0;
|
||||
|
||||
// send prompt
|
||||
const char *prompt = Con::getVariable("Con::Prompt");
|
||||
Net::send(client->socket, (const unsigned char*)prompt, dStrlen(prompt));
|
||||
client->state = FullAccessConnected;
|
||||
}
|
||||
else if(!dStrncmp(client->curLine, mListenPassword, PasswordMaxLength))
|
||||
{
|
||||
Net::send(client->socket, (const unsigned char*)reply, replyPos);
|
||||
replyPos = 0;
|
||||
|
||||
// send prompt
|
||||
const char *listenConnected = "Connected.\r\n";
|
||||
Net::send(client->socket, (const unsigned char*)listenConnected, dStrlen(listenConnected));
|
||||
client->state = ReadOnlyConnected;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *sendStr;
|
||||
if(client->state == DisconnectThisDude)
|
||||
sendStr = "Too many tries... cya.";
|
||||
else
|
||||
sendStr = "Nope... try agian.\r\nEnter Password:";
|
||||
Net::send(client->socket, (const unsigned char*)sendStr, dStrlen(sendStr));
|
||||
if(client->state == DisconnectThisDude)
|
||||
{
|
||||
Net::closeSocket(client->socket);
|
||||
client->socket = InvalidSocket;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(recvBuf[i] == '\b')
|
||||
{
|
||||
// pull the old backspace manuever...
|
||||
if(client->curPos > 0)
|
||||
{
|
||||
client->curPos--;
|
||||
if(client->state == FullAccessConnected)
|
||||
{
|
||||
reply[replyPos++] = '\b';
|
||||
reply[replyPos++] = ' ';
|
||||
reply[replyPos++] = '\b';
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(client->curPos < Con::MaxLineLength-1)
|
||||
{
|
||||
client->curLine[client->curPos++] = recvBuf[i];
|
||||
// don't echo password chars...
|
||||
if(client->state == FullAccessConnected)
|
||||
reply[replyPos++] = recvBuf[i];
|
||||
}
|
||||
}
|
||||
if(replyPos)
|
||||
Net::send(client->socket, (const unsigned char*)reply, replyPos);
|
||||
}
|
||||
|
||||
TelnetClient ** walk = &mClientList;
|
||||
TelnetClient *cl;
|
||||
while((cl = *walk) != NULL)
|
||||
{
|
||||
if(cl->socket == InvalidSocket)
|
||||
{
|
||||
*walk = cl->nextClient;
|
||||
delete cl;
|
||||
}
|
||||
else
|
||||
walk = &cl->nextClient;
|
||||
}
|
||||
}
|
||||
60
console/telnetConsole.h
Normal file
60
console/telnetConsole.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TELNETCONSOLE_H_
|
||||
#define _TELNETCONSOLE_H_
|
||||
|
||||
#ifndef _CONSOLE_H_
|
||||
#include "console/console.h"
|
||||
#endif
|
||||
|
||||
class TelnetConsole
|
||||
{
|
||||
NetSocket mAcceptSocket;
|
||||
S32 mAcceptPort;
|
||||
|
||||
enum {
|
||||
PasswordMaxLength = 32
|
||||
};
|
||||
|
||||
char mTelnetPassword[PasswordMaxLength+1];
|
||||
char mListenPassword[PasswordMaxLength+1];
|
||||
ConsoleEvent mPostEvent;
|
||||
|
||||
enum State
|
||||
{
|
||||
PasswordTryOne,
|
||||
PasswordTryTwo,
|
||||
PasswordTryThree,
|
||||
DisconnectThisDude,
|
||||
FullAccessConnected,
|
||||
ReadOnlyConnected
|
||||
};
|
||||
|
||||
struct TelnetClient
|
||||
{
|
||||
NetSocket socket;
|
||||
char curLine[Con::MaxLineLength];
|
||||
S32 curPos;
|
||||
S32 state;
|
||||
TelnetClient *nextClient;
|
||||
};
|
||||
TelnetClient *mClientList;
|
||||
TelnetConsole();
|
||||
~TelnetConsole();
|
||||
public:
|
||||
static void create();
|
||||
static void destroy();
|
||||
void process();
|
||||
void setTelnetParameters(S32 port, const char *telnetPassword, const char *listenPassword);
|
||||
void processConsoleLine(const char *line);
|
||||
};
|
||||
|
||||
extern TelnetConsole *TelConsole;
|
||||
|
||||
#endif
|
||||
|
||||
557
console/telnetDebugger.cc
Normal file
557
console/telnetDebugger.cc
Normal file
|
|
@ -0,0 +1,557 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "Platform/platform.h"
|
||||
#include "console/console.h"
|
||||
#include "console/telnetDebugger.h"
|
||||
#include "Platform/event.h"
|
||||
#include "Core/stringTable.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "console/ast.h"
|
||||
#include "console/compiler.h"
|
||||
#include "Platform/gameInterface.h"
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
// debugger commands:
|
||||
// CEVAL console line - evaluate the console line
|
||||
// output: none
|
||||
// BRKVARSET varName passct expr
|
||||
// output: none
|
||||
// BRKVARCLR varName
|
||||
// output: none
|
||||
// BRKSET file line clear passct expr - set a breakpoint on the file,line
|
||||
// it must pass passct times for it to break and if clear is true, it
|
||||
// clears when hit
|
||||
// output: none
|
||||
// BRKCLR file line - clear a breakpoint on the file,line
|
||||
// output: none
|
||||
// BRKCLRALL - clear all breakpoints
|
||||
// output: none
|
||||
// CONTINUE - continue execution
|
||||
// output: RUNNING
|
||||
// STEPIN - run until next statement
|
||||
// output: RUNNING
|
||||
// STEPOVER - run until next break <= current frame
|
||||
// output: RUNNING
|
||||
// STEPOUT - run until next break <= current frame - 1
|
||||
// output: RUNNING
|
||||
// EVAL tag frame expr - evaluate the expr in the console, on the frame'th stack frame
|
||||
// output: EVALOUT tag exprResult
|
||||
// FILELIST - list script files loaded
|
||||
// output: FILELISTOUT file1 file2 file3 file4 ...
|
||||
// BREAKLIST file - get a list of breakpoint-able lines in the file
|
||||
// output: BREAKLISTOUT file skipBreakPairs skiplinecount breaklinecount skiplinecount breaklinecount ...
|
||||
//
|
||||
// other output:
|
||||
//
|
||||
// when the debugger hits a breakpoint, it lists out:
|
||||
// BREAK file1 line1 fn1 file2 line2 fn2 file3 line3 fn3 file4 line4 fn4 etc.
|
||||
// where file1 line1 fn1 ... etc is the current call stack.
|
||||
// COUT echo out a console line
|
||||
|
||||
static void cDebugSetParams(SimObject *, S32, const char **argv)
|
||||
{
|
||||
TelDebugger->setDebugParameters(dAtoi(argv[1]), argv[2]);
|
||||
}
|
||||
|
||||
static void debuggerConsumer(ConsoleLogEntry::Level level, const char *line)
|
||||
{
|
||||
TelDebugger->processConsoleLine(line);
|
||||
}
|
||||
|
||||
TelnetDebugger::TelnetDebugger()
|
||||
{
|
||||
Con::addCommand("dbgSetParameters", cDebugSetParams, "dbgSetParameters(port,pass);", 3, 3);
|
||||
Con::addConsumer(debuggerConsumer);
|
||||
|
||||
mAcceptPort = -1;
|
||||
mAcceptSocket = InvalidSocket;
|
||||
mDebugSocket = InvalidSocket;
|
||||
|
||||
mState = NotConnected;
|
||||
|
||||
mBreakpoints = NULL;
|
||||
mBreakOnNextStatement = false;
|
||||
mStackPopBreakIndex = -1;
|
||||
mProgramPaused = false;
|
||||
}
|
||||
|
||||
TelnetDebugger::Breakpoint **TelnetDebugger::findBreakpoint(StringTableEntry fileName, S32 lineNumber)
|
||||
{
|
||||
Breakpoint **walk = &mBreakpoints;
|
||||
Breakpoint *cur;
|
||||
while((cur = *walk) != NULL)
|
||||
{
|
||||
if(cur->code->name == fileName && cur->lineNumber == U32(lineNumber))
|
||||
return walk;
|
||||
walk = &cur->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
TelnetDebugger::~TelnetDebugger()
|
||||
{
|
||||
Con::removeConsumer(debuggerConsumer);
|
||||
|
||||
if(mAcceptSocket != InvalidSocket)
|
||||
Net::closeSocket(mAcceptSocket);
|
||||
if(mDebugSocket != InvalidSocket)
|
||||
Net::closeSocket(mDebugSocket);
|
||||
}
|
||||
|
||||
TelnetDebugger *TelDebugger = NULL;
|
||||
|
||||
void TelnetDebugger::create()
|
||||
{
|
||||
TelDebugger = new TelnetDebugger;
|
||||
}
|
||||
|
||||
void TelnetDebugger::destroy()
|
||||
{
|
||||
delete TelDebugger;
|
||||
TelDebugger = NULL;
|
||||
}
|
||||
|
||||
void TelnetDebugger::send(const char *str)
|
||||
{
|
||||
Net::send(mDebugSocket, (const unsigned char*)str, dStrlen(str));
|
||||
}
|
||||
|
||||
void TelnetDebugger::setDebugParameters(S32 port, const char *password)
|
||||
{
|
||||
if(port == mAcceptPort)
|
||||
return;
|
||||
|
||||
if(mAcceptSocket != InvalidSocket)
|
||||
{
|
||||
Net::closeSocket(mAcceptSocket);
|
||||
mAcceptSocket = InvalidSocket;
|
||||
}
|
||||
mAcceptPort = port;
|
||||
if(mAcceptPort != -1 && mAcceptPort != 0)
|
||||
{
|
||||
mAcceptSocket = Net::openSocket();
|
||||
Net::bind(mAcceptSocket, mAcceptPort);
|
||||
Net::listen(mAcceptSocket, 4);
|
||||
|
||||
Net::setBlocking(mAcceptSocket, false);
|
||||
}
|
||||
dStrncpy(mDebuggerPassword, password, PasswordMaxLength);
|
||||
}
|
||||
|
||||
void TelnetDebugger::processConsoleLine(const char *consoleLine)
|
||||
{
|
||||
if(mState == Connected)
|
||||
{
|
||||
send("COUT ");
|
||||
send(consoleLine);
|
||||
send("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void TelnetDebugger::process()
|
||||
{
|
||||
NetAddress address;
|
||||
|
||||
if(mAcceptSocket != InvalidSocket)
|
||||
{
|
||||
// ok, see if we have any new connections:
|
||||
NetSocket newConnection;
|
||||
newConnection = Net::accept(mAcceptSocket, &address);
|
||||
|
||||
if(newConnection != InvalidSocket && mDebugSocket == InvalidSocket)
|
||||
{
|
||||
Con::printf ("Debugger connection from %i.%i.%i.%i",
|
||||
address.netNum[0], address.netNum[1], address.netNum[2], address.netNum[3]);
|
||||
|
||||
mState = PasswordTry;
|
||||
mDebugSocket = newConnection;
|
||||
|
||||
Net::setBlocking(newConnection, false);
|
||||
}
|
||||
else if(newConnection != InvalidSocket)
|
||||
Net::closeSocket(newConnection);
|
||||
}
|
||||
// see if we have any input to process...
|
||||
|
||||
if(mDebugSocket == InvalidSocket)
|
||||
return;
|
||||
|
||||
checkDebugRecv();
|
||||
if(mDebugSocket == InvalidSocket)
|
||||
removeAllBreakpoints();
|
||||
}
|
||||
|
||||
void TelnetDebugger::checkDebugRecv()
|
||||
{
|
||||
S32 checked = false;
|
||||
for(;;) {
|
||||
// check for and recv one command:
|
||||
for(S32 i = 0; i < mCurPos; i++)
|
||||
{
|
||||
if(mLineBuffer[i] == '\r' || mLineBuffer[i] == '\n')
|
||||
{
|
||||
if(i == 0)
|
||||
{
|
||||
mCurPos--;
|
||||
dMemmove(mLineBuffer, mLineBuffer + 1, mCurPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLineBuffer[i] = '\n';
|
||||
processLineBuffer(i+1);
|
||||
mCurPos -= i + 1;
|
||||
dMemmove(mLineBuffer, mLineBuffer + i + 1, mCurPos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(mLineBuffer[i] == 0)
|
||||
mLineBuffer[i] = '_';
|
||||
}
|
||||
// found no <CR> or <LF>
|
||||
if(mCurPos == MaxCommandSize) // this shouldn't happen
|
||||
{
|
||||
Net::closeSocket(mDebugSocket);
|
||||
mDebugSocket = InvalidSocket;
|
||||
mState = NotConnected;
|
||||
return;
|
||||
}
|
||||
if(checked)
|
||||
return;
|
||||
checked = false;
|
||||
|
||||
S32 numBytes;
|
||||
Net::Error err = Net::recv(mDebugSocket, (unsigned char*)(mLineBuffer + mCurPos), MaxCommandSize - mCurPos, &numBytes);
|
||||
|
||||
if((err != Net::NoError && err != Net::WouldBlock) || numBytes == 0)
|
||||
{
|
||||
Net::closeSocket(mDebugSocket);
|
||||
mDebugSocket = InvalidSocket;
|
||||
mState = NotConnected;
|
||||
return;
|
||||
}
|
||||
if(err == Net::WouldBlock)
|
||||
return;
|
||||
|
||||
mCurPos += numBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void TelnetDebugger::executionStopped(CodeBlock *code, U32 lineNumber)
|
||||
{
|
||||
if(mProgramPaused)
|
||||
return;
|
||||
if(mBreakOnNextStatement)
|
||||
{
|
||||
// loop through all the codeblocks clearing the breaks
|
||||
for(CodeBlock *walk = codeBlockList; walk; walk = walk->nextFile)
|
||||
walk->clearAllBreaks();
|
||||
for(Breakpoint *w = mBreakpoints; w; w = w->next)
|
||||
w->code->setBreakpoint(w->lineNumber);
|
||||
breakProcess();
|
||||
return;
|
||||
}
|
||||
Breakpoint **bp = findBreakpoint(code->name, lineNumber);
|
||||
if(!bp)
|
||||
return;
|
||||
Breakpoint *brk = *bp;
|
||||
mProgramPaused = true;
|
||||
Con::evaluatef("$dbgResult = %s;", brk->testExpression);
|
||||
if(Con::getBoolVariable("$dbgResult"))
|
||||
{
|
||||
brk->curCount++;
|
||||
if(brk->curCount >= brk->passCount)
|
||||
{
|
||||
brk->curCount = 0;
|
||||
if(brk->clearOnHit)
|
||||
removeBreakpoint(code->name, lineNumber);
|
||||
breakProcess();
|
||||
}
|
||||
}
|
||||
mProgramPaused = false;
|
||||
}
|
||||
|
||||
void TelnetDebugger::popStackFrame()
|
||||
{
|
||||
if(mState == NotConnected)
|
||||
return;
|
||||
if(U32(mStackPopBreakIndex) == gEvalState.stack.size())
|
||||
breakOnNextStatement();
|
||||
}
|
||||
|
||||
void TelnetDebugger::breakProcess()
|
||||
{
|
||||
mProgramPaused = true;
|
||||
// echo out the break
|
||||
send("BREAK");
|
||||
char buffer[MaxCommandSize];
|
||||
|
||||
for(S32 i = (S32) gEvalState.stack.size() - 1; i >= 0; i--)
|
||||
{
|
||||
CodeBlock *code = gEvalState.stack[i]->code;
|
||||
U32 ip = gEvalState.stack[i]->ip;
|
||||
|
||||
const char *file = code->name;
|
||||
const char *scope = gEvalState.stack[i]->scopeName;
|
||||
if ((! file) || (! file[0]))
|
||||
file = "N/A";
|
||||
if ((! scope) || (! scope[0]))
|
||||
scope = "N/A";
|
||||
U32 line, inst;
|
||||
code->findBreakLine(ip, line, inst);
|
||||
dSprintf(buffer, MaxCommandSize, " %s %d %s", file, line, scope);
|
||||
send(buffer);
|
||||
}
|
||||
send("\r\n");
|
||||
while(mProgramPaused)
|
||||
{
|
||||
checkDebugRecv();
|
||||
if(mDebugSocket == InvalidSocket)
|
||||
{
|
||||
mProgramPaused = false;
|
||||
removeAllBreakpoints();
|
||||
debugContinue();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TelnetDebugger::processLineBuffer(S32 cmdLen)
|
||||
{
|
||||
if (mState == PasswordTry)
|
||||
{
|
||||
if(dStrncmp(mLineBuffer, mDebuggerPassword, cmdLen-1))
|
||||
{
|
||||
// failed password:
|
||||
send("PASS WrongPassword.\r\n");
|
||||
Net::closeSocket(mDebugSocket);
|
||||
mDebugSocket = InvalidSocket;
|
||||
mState = NotConnected;
|
||||
}
|
||||
else
|
||||
{
|
||||
send("PASS Connected.\r\n");
|
||||
mState = Connected;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char evalBuffer[MaxCommandSize];
|
||||
char varBuffer[MaxCommandSize];
|
||||
char fileBuffer[MaxCommandSize];
|
||||
char clear[MaxCommandSize];
|
||||
S32 passCount, line, frame;
|
||||
|
||||
if(dSscanf(mLineBuffer, "CEVAL %[^\n]", evalBuffer) == 1)
|
||||
{
|
||||
ConsoleEvent postEvent;
|
||||
dStrcpy(postEvent.data, evalBuffer);
|
||||
postEvent.size = ConsoleEventHeaderSize + dStrlen(evalBuffer) + 1;
|
||||
Game->postEvent(postEvent);
|
||||
}
|
||||
else if(dSscanf(mLineBuffer, "BRKVARSET %s %d %[^\n]", varBuffer, &passCount, evalBuffer) == 3)
|
||||
addVariableBreakpoint(varBuffer, passCount, evalBuffer);
|
||||
else if(dSscanf(mLineBuffer, "BRKVARCLR %s", varBuffer) == 1)
|
||||
removeVariableBreakpoint(varBuffer);
|
||||
else if(dSscanf(mLineBuffer, "BRKSET %s %d %s %d %[^\n]", fileBuffer,&line,&clear,&passCount,evalBuffer) == 5)
|
||||
addBreakpoint(fileBuffer, line, dAtob(clear), passCount, evalBuffer);
|
||||
else if(dSscanf(mLineBuffer, "BRKCLR %s %d", fileBuffer, &line) == 2)
|
||||
removeBreakpoint(fileBuffer, line);
|
||||
else if(!dStrncmp(mLineBuffer, "BRKCLRALL\n", cmdLen))
|
||||
removeAllBreakpoints();
|
||||
else if(!dStrncmp(mLineBuffer, "CONTINUE\n", cmdLen))
|
||||
debugContinue();
|
||||
else if(!dStrncmp(mLineBuffer, "STEPIN\n", cmdLen))
|
||||
debugStepIn();
|
||||
else if(!dStrncmp(mLineBuffer, "STEPOVER\n", cmdLen))
|
||||
debugStepOver();
|
||||
else if(!dStrncmp(mLineBuffer, "STEPOUT\n", cmdLen))
|
||||
debugStepOut();
|
||||
else if(dSscanf(mLineBuffer, "EVAL %s %d %[^\n]", varBuffer, &frame, evalBuffer) == 3)
|
||||
evaluateExpression(varBuffer, frame, evalBuffer);
|
||||
else if(!dStrncmp(mLineBuffer, "FILELIST\n", cmdLen))
|
||||
dumpFileList();
|
||||
else if(dSscanf(mLineBuffer, "BREAKLIST %s", fileBuffer) == 1)
|
||||
dumpBreakableList(fileBuffer);
|
||||
else
|
||||
{
|
||||
// invalid stuff.
|
||||
send("DBGERR Invalid command!\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TelnetDebugger::addVariableBreakpoint(const char*, S32, const char*)
|
||||
{
|
||||
send("addVariableBreakpoint\r\n");
|
||||
}
|
||||
|
||||
void TelnetDebugger::removeVariableBreakpoint(const char*)
|
||||
{
|
||||
send("removeVariableBreakpoint\r\n");
|
||||
}
|
||||
|
||||
void TelnetDebugger::addBreakpoint(const char *fileName, S32 line, bool clear, S32 passCount, const char *evalString)
|
||||
{
|
||||
fileName = StringTable->insert(fileName);
|
||||
Breakpoint **bp = findBreakpoint(fileName, line);
|
||||
|
||||
if(bp)
|
||||
{
|
||||
// trying to add the same breakpoint...
|
||||
Breakpoint *brk = *bp;
|
||||
dFree(brk->testExpression);
|
||||
brk->testExpression = dStrdup(evalString);
|
||||
brk->passCount = passCount;
|
||||
brk->clearOnHit = clear;
|
||||
brk->curCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
CodeBlock *code = CodeBlock::find(fileName);
|
||||
if(code)
|
||||
{
|
||||
Breakpoint *brk = new Breakpoint;
|
||||
brk->code = code;
|
||||
code->setBreakpoint(line);
|
||||
brk->lineNumber = line;
|
||||
brk->passCount = passCount;
|
||||
brk->clearOnHit = clear;
|
||||
brk->curCount = 0;
|
||||
brk->testExpression = dStrdup(evalString);
|
||||
brk->next = mBreakpoints;
|
||||
mBreakpoints = brk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TelnetDebugger::removeBreakpointsFromCode(CodeBlock *code)
|
||||
{
|
||||
Breakpoint **walk = &mBreakpoints;
|
||||
Breakpoint *cur;
|
||||
while((cur = *walk) != NULL)
|
||||
{
|
||||
if(cur->code == code)
|
||||
{
|
||||
dFree(cur->testExpression);
|
||||
*walk = cur->next;
|
||||
delete walk;
|
||||
}
|
||||
else
|
||||
walk = &cur->next;
|
||||
}
|
||||
}
|
||||
|
||||
void TelnetDebugger::removeBreakpoint(const char *fileName, S32 line)
|
||||
{
|
||||
fileName = StringTable->insert(fileName);
|
||||
Breakpoint **bp = findBreakpoint(fileName, line);
|
||||
if(bp)
|
||||
{
|
||||
Breakpoint *brk = *bp;
|
||||
*bp = brk->next;
|
||||
brk->code->clearBreakpoint(brk->lineNumber);
|
||||
dFree(brk->testExpression);
|
||||
delete brk;
|
||||
}
|
||||
}
|
||||
|
||||
void TelnetDebugger::removeAllBreakpoints()
|
||||
{
|
||||
Breakpoint *walk = mBreakpoints;
|
||||
while(walk)
|
||||
{
|
||||
Breakpoint *temp = walk->next;
|
||||
walk->code->clearBreakpoint(walk->lineNumber);
|
||||
dFree(walk->testExpression);
|
||||
delete walk;
|
||||
walk = temp;
|
||||
}
|
||||
mBreakpoints = NULL;
|
||||
}
|
||||
|
||||
void TelnetDebugger::debugContinue()
|
||||
{
|
||||
mBreakOnNextStatement = false;
|
||||
mStackPopBreakIndex = -1;
|
||||
mProgramPaused = false;
|
||||
send("RUNNING\r\n");
|
||||
}
|
||||
|
||||
void TelnetDebugger::breakOnNextStatement()
|
||||
{
|
||||
for(CodeBlock *walk = codeBlockList; walk; walk = walk->nextFile)
|
||||
walk->setAllBreaks();
|
||||
mBreakOnNextStatement = true;
|
||||
}
|
||||
|
||||
void TelnetDebugger::debugStepIn()
|
||||
{
|
||||
breakOnNextStatement();
|
||||
mStackPopBreakIndex = -1;
|
||||
mProgramPaused = false;
|
||||
send("RUNNING\r\n");
|
||||
}
|
||||
|
||||
void TelnetDebugger::debugStepOver()
|
||||
{
|
||||
mBreakOnNextStatement = false;
|
||||
mStackPopBreakIndex = gEvalState.stack.size();
|
||||
mProgramPaused = false;
|
||||
send("RUNNING\r\n");
|
||||
}
|
||||
|
||||
void TelnetDebugger::debugStepOut()
|
||||
{
|
||||
mBreakOnNextStatement = false;
|
||||
mStackPopBreakIndex = gEvalState.stack.size() - 1;
|
||||
mProgramPaused = false;
|
||||
send("RUNNING\r\n");
|
||||
}
|
||||
|
||||
void TelnetDebugger::evaluateExpression(const char *tag, S32, const char *evalBuffer)
|
||||
{
|
||||
char buffer[MaxCommandSize];
|
||||
Con::evaluatef("$dbgResult = %s;", evalBuffer);
|
||||
const char *result = Con::getVariable("$dbgResult");
|
||||
dSprintf(buffer, MaxCommandSize, "EVALOUT %s %s\r\n", tag, result[0] ? result : "\"\"");
|
||||
send(buffer);
|
||||
}
|
||||
|
||||
void TelnetDebugger::dumpFileList()
|
||||
{
|
||||
send("FILELISTOUT ");
|
||||
for(CodeBlock *walk = codeBlockList; walk; walk = walk->nextFile)
|
||||
{
|
||||
send(walk->name);
|
||||
if(walk->nextFile)
|
||||
send(" ");
|
||||
}
|
||||
send("\r\n");
|
||||
}
|
||||
|
||||
void TelnetDebugger::dumpBreakableList(const char *fileName)
|
||||
{
|
||||
fileName = StringTable->insert(fileName);
|
||||
CodeBlock *file = CodeBlock::find(fileName);
|
||||
char buffer[MaxCommandSize];
|
||||
if(file)
|
||||
{
|
||||
dSprintf(buffer, MaxCommandSize, "BREAKLISTOUT %s %d", fileName, file->breakListSize >> 1);
|
||||
send(buffer);
|
||||
for(U32 i = 0; i < file->breakListSize; i += 2)
|
||||
{
|
||||
dSprintf(buffer, MaxCommandSize, " %d %d", file->breakList[i], file->breakList[i+1]);
|
||||
send(buffer);
|
||||
}
|
||||
send("\r\n");
|
||||
}
|
||||
else
|
||||
send("DBGERR No Such file!");
|
||||
}
|
||||
90
console/telnetDebugger.h
Normal file
90
console/telnetDebugger.h
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TELNETDEBUGGER_H_
|
||||
#define _TELNETDEBUGGER_H_
|
||||
|
||||
class CodeBlock;
|
||||
|
||||
class TelnetDebugger
|
||||
{
|
||||
S32 mAcceptPort;
|
||||
NetSocket mAcceptSocket;
|
||||
NetSocket mDebugSocket;
|
||||
|
||||
enum {
|
||||
PasswordMaxLength = 32,
|
||||
MaxCommandSize = 2048
|
||||
};
|
||||
|
||||
char mDebuggerPassword[PasswordMaxLength+1];
|
||||
enum State
|
||||
{
|
||||
NotConnected,
|
||||
PasswordTry,
|
||||
Connected
|
||||
};
|
||||
S32 mState;
|
||||
char mLineBuffer[MaxCommandSize];
|
||||
S32 mCurPos;
|
||||
|
||||
TelnetDebugger();
|
||||
~TelnetDebugger();
|
||||
|
||||
struct Breakpoint
|
||||
{
|
||||
CodeBlock *code;
|
||||
U32 lineNumber;
|
||||
S32 passCount;
|
||||
S32 curCount;
|
||||
char *testExpression;
|
||||
bool clearOnHit;
|
||||
Breakpoint *next;
|
||||
};
|
||||
Breakpoint *mBreakpoints;
|
||||
|
||||
Breakpoint **findBreakpoint(StringTableEntry fileName, S32 lineNumber);
|
||||
|
||||
bool mProgramPaused;
|
||||
bool mBreakOnNextStatement;
|
||||
S32 mStackPopBreakIndex;
|
||||
|
||||
void addVariableBreakpoint(const char *varName, S32 passCount, const char *evalString);
|
||||
void removeVariableBreakpoint(const char *varName);
|
||||
void addBreakpoint(const char *fileName, S32 line, bool clear, S32 passCount, const char *evalString);
|
||||
void removeBreakpoint(const char *fileName, S32 line);
|
||||
void removeAllBreakpoints();
|
||||
|
||||
void debugContinue();
|
||||
void debugStepIn();
|
||||
void debugStepOver();
|
||||
void debugStepOut();
|
||||
void evaluateExpression(const char *tag, S32 frame, const char *evalBuffer);
|
||||
void dumpFileList();
|
||||
void dumpBreakableList(const char *fileName);
|
||||
void removeBreakpointsFromCode(CodeBlock *code);
|
||||
|
||||
void checkDebugRecv();
|
||||
void processLineBuffer(S32);
|
||||
void breakProcess();
|
||||
void breakOnNextStatement();
|
||||
public:
|
||||
static void create();
|
||||
static void destroy();
|
||||
|
||||
void process();
|
||||
void popStackFrame();
|
||||
|
||||
virtual void executionStopped(CodeBlock *code, U32 lineNumber);
|
||||
void send(const char *s);
|
||||
void setDebugParameters(S32 port, const char *password);
|
||||
void processConsoleLine(const char *consoleLine);
|
||||
};
|
||||
|
||||
extern TelnetDebugger *TelDebugger;
|
||||
|
||||
#endif
|
||||
72
console/typeValidators.cc
Normal file
72
console/typeValidators.cc
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "console/console.h"
|
||||
#include "console/consoleObject.h"
|
||||
#include "console/typeValidators.h"
|
||||
#include "console/simBase.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
void TypeValidator::consoleError(SimObject *object, const char *format, ...)
|
||||
{
|
||||
char buffer[1024];
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
dVsprintf(buffer, sizeof(buffer), format, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
AbstractClassRep *rep = object->getClassRep();
|
||||
AbstractClassRep::Field &fld = rep->mFieldList[fieldIndex];
|
||||
const char *objectName = object->getName();
|
||||
if(!objectName)
|
||||
objectName = "unnamed";
|
||||
|
||||
|
||||
Con::warnf("%s - %s(%d) - invalid value for %s: %s",
|
||||
rep->getClassName(), objectName, object->getId(), fld.pFieldname, buffer);
|
||||
}
|
||||
|
||||
void FRangeValidator::validateType(SimObject *object, void *typePtr)
|
||||
{
|
||||
F32 *v = (F32 *) typePtr;
|
||||
if(*v < minV || *v > maxV)
|
||||
{
|
||||
consoleError(object, "Must be between %g and %g", minV, maxV);
|
||||
if(*v < minV)
|
||||
*v = minV;
|
||||
else if(*v > maxV)
|
||||
*v = maxV;
|
||||
}
|
||||
}
|
||||
|
||||
void IRangeValidator::validateType(SimObject *object, void *typePtr)
|
||||
{
|
||||
S32 *v = (S32 *) typePtr;
|
||||
if(*v < minV || *v > maxV)
|
||||
{
|
||||
consoleError(object, "Must be between %d and %d", minV, maxV);
|
||||
if(*v < minV)
|
||||
*v = minV;
|
||||
else if(*v > maxV)
|
||||
*v = maxV;
|
||||
}
|
||||
}
|
||||
|
||||
void IRangeValidatorScaled::validateType(SimObject *object, void *typePtr)
|
||||
{
|
||||
S32 *v = (S32 *) typePtr;
|
||||
*v /= factor;
|
||||
if(*v < minV || *v > maxV)
|
||||
{
|
||||
consoleError(object, "Scaled value must be between %d and %d", minV, maxV);
|
||||
if(*v < minV)
|
||||
*v = minV;
|
||||
else if(*v > maxV)
|
||||
*v = maxV;
|
||||
}
|
||||
}
|
||||
72
console/typeValidators.h
Normal file
72
console/typeValidators.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TYPEVALIDATORS_H_
|
||||
#define _TYPEVALIDATORS_H_
|
||||
|
||||
class TypeValidator
|
||||
{
|
||||
public:
|
||||
S32 fieldIndex;
|
||||
|
||||
// prints a console error message, prefaces it with:
|
||||
// className objectName (objectId) - invalid value for fieldName: msg
|
||||
void consoleError(SimObject *object, const char *format, ...);
|
||||
|
||||
// validateType is called for each assigned value on the field this
|
||||
// validator is attached to
|
||||
virtual void validateType(SimObject *object, void *typePtr) = 0;
|
||||
};
|
||||
|
||||
|
||||
// Floating point min/max range validator
|
||||
|
||||
class FRangeValidator : public TypeValidator
|
||||
{
|
||||
F32 minV, maxV;
|
||||
public:
|
||||
FRangeValidator(F32 minValue, F32 maxValue)
|
||||
{
|
||||
minV = minValue;
|
||||
maxV = maxValue;
|
||||
}
|
||||
void validateType(SimObject *object, void *typePtr);
|
||||
};
|
||||
|
||||
// signed integer min/max range validator
|
||||
|
||||
class IRangeValidator : public TypeValidator
|
||||
{
|
||||
S32 minV, maxV;
|
||||
public:
|
||||
IRangeValidator(S32 minValue, S32 maxValue)
|
||||
{
|
||||
minV = minValue;
|
||||
maxV = maxValue;
|
||||
}
|
||||
void validateType(SimObject *object, void *typePtr);
|
||||
};
|
||||
|
||||
// scaled integer field validator - !note! should
|
||||
// NOT be used on a field that gets exported -
|
||||
// field is only converted once on initial assignment
|
||||
|
||||
class IRangeValidatorScaled : public TypeValidator
|
||||
{
|
||||
S32 minV, maxV;
|
||||
S32 factor;
|
||||
public:
|
||||
IRangeValidatorScaled(S32 scaleFactor, S32 minValueScaled, S32 maxValueScaled)
|
||||
{
|
||||
minV = minValueScaled;
|
||||
maxV = maxValueScaled;
|
||||
factor = scaleFactor;
|
||||
}
|
||||
void validateType(SimObject *object, void *typePtr);
|
||||
};
|
||||
|
||||
#endif
|
||||
627
console/yylex.c
Normal file
627
console/yylex.c
Normal file
|
|
@ -0,0 +1,627 @@
|
|||
/*
|
||||
* Copyright 1988, 1992 by Mortice Kern Systems Inc. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Header: /cvs/torque/torque/engine/console/yylex.c,v 1.1 2001/05/17 02:16:20 timg Exp $
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#if __STDC__
|
||||
#define YY_ARGS(args) args
|
||||
#else
|
||||
#define YY_ARGS(args) ()
|
||||
#endif
|
||||
|
||||
#ifdef LEX_WINDOWS
|
||||
#include <windows.h>
|
||||
|
||||
/*
|
||||
* define, if not already defined
|
||||
* the flag YYEXIT, which will allow
|
||||
* graceful exits from yylex()
|
||||
* without resorting to calling exit();
|
||||
*/
|
||||
|
||||
#ifndef YYEXIT
|
||||
#define YYEXIT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* the following is the handle to the current
|
||||
* instance of a windows program. The user
|
||||
* program calling yylex must supply this!
|
||||
*/
|
||||
|
||||
#ifdef STRICT
|
||||
extern HINSTANCE hInst;
|
||||
#else
|
||||
extern HANDLE hInst;
|
||||
#endif
|
||||
|
||||
#endif /* LEX_WINDOWS */
|
||||
|
||||
/*
|
||||
* Define m_textmsg() to an appropriate function for internationalized messages
|
||||
* or custom processing.
|
||||
*/
|
||||
#ifndef I18N
|
||||
#define m_textmsg(id, str, cls) (str)
|
||||
#else /*I18N*/
|
||||
extern char* m_textmsg YY_ARGS((int id, const char* str, char* cls));
|
||||
#endif/*I18N*/
|
||||
|
||||
/*
|
||||
* Include string.h to get definition of memmove() and size_t.
|
||||
* If you do not have string.h or it does not declare memmove
|
||||
* or size_t, you will have to declare them here.
|
||||
*/
|
||||
#include <string.h>
|
||||
/* Uncomment next line if memmove() is not declared in string.h */
|
||||
/*extern char * memmove();*/
|
||||
/* Uncomment next line if size_t is not available in stdio.h or string.h */
|
||||
/*typedef unsigned size_t;*/
|
||||
/* Drop this when LATTICE provides memmove */
|
||||
#ifdef LATTICE
|
||||
#define memmove memcopy
|
||||
#endif
|
||||
|
||||
/*
|
||||
* YY_STATIC determines the scope of variables and functions
|
||||
* declared by the lex scanner. It must be set with a -DYY_STATIC
|
||||
* option to the compiler (it cannot be defined in the lex program).
|
||||
*/
|
||||
#ifdef YY_STATIC
|
||||
/* define all variables as static to allow more than one lex scanner */
|
||||
#define YY_DECL static
|
||||
#else
|
||||
/* define all variables as global to allow other modules to access them */
|
||||
#define YY_DECL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* You can redefine yygetc. For YACC Tracing, compile this code
|
||||
* with -DYYTRACE to get input from yt_getc
|
||||
*/
|
||||
#ifdef YYTRACE
|
||||
extern int yt_getc YY_ARGS((void));
|
||||
#define yygetc() yt_getc()
|
||||
#else
|
||||
#define yygetc() getc(yyin) /* yylex input source */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* the following can be redefined by the user.
|
||||
*/
|
||||
#ifdef YYEXIT
|
||||
#define YY_FATAL(msg) { fprintf(yyout, "yylex: %s\n", msg); yyLexFatal = 1; }
|
||||
#else /* YYEXIT */
|
||||
#define YY_FATAL(msg) { fprintf(stderr, "yylex: %s\n", msg); exit(1); }
|
||||
#endif /* YYEXIT */
|
||||
|
||||
#undef ECHO
|
||||
#define ECHO fputs(yytext, yyout)
|
||||
|
||||
#define output(c) putc((c), yyout) /* yylex sink for unmatched chars */
|
||||
#define YY_INTERACTIVE 1 /* save micro-seconds if 0 */
|
||||
|
||||
#define BEGIN yy_start =
|
||||
#define REJECT goto yy_reject
|
||||
#define NLSTATE (yy_lastc = YYNEWLINE)
|
||||
#define YY_INIT \
|
||||
(yy_start = yyleng = yy_end = 0, yy_lastc = YYNEWLINE)
|
||||
#define yymore() goto yy_more
|
||||
#define yyless(n) if ((n) < 0 || (n) > yy_end) ; \
|
||||
else { YY_SCANNER; yyleng = (n); YY_USER; }
|
||||
|
||||
YY_DECL void yy_reset YY_ARGS((void));
|
||||
YY_DECL int input YY_ARGS((void));
|
||||
YY_DECL int unput YY_ARGS((int c));
|
||||
|
||||
/* functions defined in libl.lib */
|
||||
extern int yywrap YY_ARGS((void));
|
||||
extern void yyerror YY_ARGS((char *fmt, ...));
|
||||
extern void yycomment YY_ARGS((char *term));
|
||||
extern int yymapch YY_ARGS((int delim, int escape));
|
||||
|
||||
@ GLOBAL DECLARATIONS @
|
||||
|
||||
#ifndef YYLMAX
|
||||
#define YYLMAX 100 /* token and pushback buffer size */
|
||||
#endif /* YYLMAX */
|
||||
|
||||
/*
|
||||
* If %array is used (or defaulted), yytext[] contains the token.
|
||||
* If %pointer is used, yytext is a pointer to yy_tbuf[].
|
||||
*/
|
||||
@aYY_DECL char yytext[YYLMAX+1];
|
||||
@pYY_DECL char yy_tbuf[YYLMAX+1];
|
||||
|
||||
@pYY_DECL char * yytext = yy_tbuf;
|
||||
#ifdef YY_DEBUG
|
||||
#undef YY_DEBUG
|
||||
#define YY_DEBUG(fmt, a1, a2) fprintf(stderr, fmt, a1, a2)
|
||||
#else
|
||||
#define YY_DEBUG(fmt, a1, a2)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The declaration for the lex scanner can be changed by
|
||||
* redefining YYLEX or YYDECL. This must be done if you have
|
||||
* more than one scanner in a program.
|
||||
*/
|
||||
#ifndef YYLEX
|
||||
#define YYLEX yylex /* name of lex scanner */
|
||||
#endif
|
||||
|
||||
#ifndef YYDECL
|
||||
#define YYDECL int YYLEX YY_ARGS((void)) /* declaration for lex scanner */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* stdin and stdout may not neccessarily be constants.
|
||||
* If stdin and stdout are constant, and you want to save a few cycles, then
|
||||
* #define YY_STATIC_STDIO 1 in this file or on the commandline when
|
||||
* compiling this file
|
||||
*/
|
||||
#ifndef YY_STATIC_STDIO
|
||||
#define YY_STATIC_STDIO 0
|
||||
#endif
|
||||
|
||||
#if YY_STATIC_STDIO
|
||||
YY_DECL FILE *yyin = stdin;
|
||||
YY_DECL FILE *yyout = stdout;
|
||||
#else
|
||||
YY_DECL FILE *yyin = (FILE *)0;
|
||||
YY_DECL FILE *yyout = (FILE *)0;
|
||||
#endif
|
||||
YY_DECL int yylineno = 1; /* line number */
|
||||
|
||||
/* yy_sbuf[0:yyleng-1] contains the states corresponding to yytext.
|
||||
* yytext[0:yyleng-1] contains the current token.
|
||||
* yytext[yyleng:yy_end-1] contains pushed-back characters.
|
||||
* When the user action routine is active,
|
||||
* yy_save contains yytext[yyleng], which is set to '\0'.
|
||||
* Things are different when YY_PRESERVE is defined.
|
||||
*/
|
||||
static yy_state_t yy_sbuf [YYLMAX+1]; /* state buffer */
|
||||
static int yy_end = 0; /* end of pushback */
|
||||
static int yy_start = 0; /* start state */
|
||||
static int yy_lastc = YYNEWLINE; /* previous char */
|
||||
YY_DECL int yyleng = 0; /* yytext token length */
|
||||
#ifdef YYEXIT
|
||||
static int yyLexFatal;
|
||||
#endif /* YYEXIT */
|
||||
|
||||
#ifndef YY_PRESERVE /* the efficient default push-back scheme */
|
||||
|
||||
static char yy_save; /* saved yytext[yyleng] */
|
||||
|
||||
#define YY_USER { /* set up yytext for user */ \
|
||||
yy_save = yytext[yyleng]; \
|
||||
yytext[yyleng] = 0; \
|
||||
}
|
||||
#define YY_SCANNER { /* set up yytext for scanner */ \
|
||||
yytext[yyleng] = yy_save; \
|
||||
}
|
||||
|
||||
#else /* not-so efficient push-back for yytext mungers */
|
||||
|
||||
static char yy_save [YYLMAX];
|
||||
static char *yy_push = yy_save+YYLMAX;
|
||||
|
||||
#define YY_USER { \
|
||||
size_t n = yy_end - yyleng; \
|
||||
yy_push = yy_save+YYLMAX - n; \
|
||||
if (n > 0) \
|
||||
memmove(yy_push, yytext+yyleng, n); \
|
||||
yytext[yyleng] = 0; \
|
||||
}
|
||||
#define YY_SCANNER { \
|
||||
size_t n = yy_save+YYLMAX - yy_push; \
|
||||
if (n > 0) \
|
||||
memmove(yytext+yyleng, yy_push, n); \
|
||||
yy_end = yyleng + n; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LEX_WINDOWS
|
||||
|
||||
/*
|
||||
* When using the windows features of lex,
|
||||
* it is necessary to load in the resources being
|
||||
* used, and when done with them, the resources must
|
||||
* be freed up, otherwise we have a windows app that
|
||||
* is not following the rules. Thus, to make yylex()
|
||||
* behave in a windows environment, create a new
|
||||
* yylex() which will call the original yylex() as
|
||||
* another function call. Observe ...
|
||||
*/
|
||||
|
||||
/*
|
||||
* The actual lex scanner (usually yylex(void)).
|
||||
* NOTE: you should invoke yy_init() if you are calling yylex()
|
||||
* with new input; otherwise old lookaside will get in your way
|
||||
* and yylex() will die horribly.
|
||||
*/
|
||||
static int win_yylex(); /* prototype for windows yylex handler */
|
||||
|
||||
YYDECL {
|
||||
int wReturnValue;
|
||||
HANDLE hRes_table;
|
||||
unsigned short far *old_yy_la_act; /* remember previous pointer values */
|
||||
short far *old_yy_final;
|
||||
yy_state_t far *old_yy_begin;
|
||||
yy_state_t far *old_yy_next;
|
||||
yy_state_t far *old_yy_check;
|
||||
yy_state_t far *old_yy_default;
|
||||
short far *old_yy_base;
|
||||
|
||||
/*
|
||||
* the following code will load the required
|
||||
* resources for a Windows based parser.
|
||||
*/
|
||||
|
||||
hRes_table = LoadResource (hInst,
|
||||
FindResource (hInst, "UD_RES_yyLEX", "yyLEXTBL"));
|
||||
|
||||
/*
|
||||
* return an error code if any
|
||||
* of the resources did not load
|
||||
*/
|
||||
|
||||
if (hRes_table == NULL)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* the following code will lock the resources
|
||||
* into fixed memory locations for the scanner
|
||||
* (and remember previous pointer locations)
|
||||
*/
|
||||
|
||||
old_yy_la_act = yy_la_act;
|
||||
old_yy_final = yy_final;
|
||||
old_yy_begin = yy_begin;
|
||||
old_yy_next = yy_next;
|
||||
old_yy_check = yy_check;
|
||||
old_yy_default = yy_default;
|
||||
old_yy_base = yy_base;
|
||||
|
||||
yy_la_act = (unsigned short far *)LockResource (hRes_table);
|
||||
yy_final = (short far *)(yy_la_act + Sizeof_yy_la_act);
|
||||
yy_begin = (yy_state_t far *)(yy_final + Sizeof_yy_final);
|
||||
yy_next = (yy_state_t far *)(yy_begin + Sizeof_yy_begin);
|
||||
yy_check = (yy_state_t far *)(yy_next + Sizeof_yy_next);
|
||||
yy_default = (yy_state_t far *)(yy_check + Sizeof_yy_check);
|
||||
yy_base = (yy_state_t far *)(yy_default + Sizeof_yy_default);
|
||||
|
||||
|
||||
/*
|
||||
* call the standard yylex() code
|
||||
*/
|
||||
|
||||
wReturnValue = win_yylex();
|
||||
|
||||
/*
|
||||
* unlock the resources
|
||||
*/
|
||||
|
||||
UnlockResource (hRes_table);
|
||||
|
||||
/*
|
||||
* and now free the resource
|
||||
*/
|
||||
|
||||
FreeResource (hRes_table);
|
||||
|
||||
/*
|
||||
* restore previously saved pointers
|
||||
*/
|
||||
|
||||
yy_la_act = old_yy_la_act;
|
||||
yy_final = old_yy_final;
|
||||
yy_begin = old_yy_begin;
|
||||
yy_next = old_yy_next;
|
||||
yy_check = old_yy_check;
|
||||
yy_default = old_yy_default;
|
||||
yy_base = old_yy_base;
|
||||
|
||||
return (wReturnValue);
|
||||
} /* end function */
|
||||
|
||||
static int win_yylex() {
|
||||
|
||||
#else /* LEX_WINDOWS */
|
||||
|
||||
/*
|
||||
* The actual lex scanner (usually yylex(void)).
|
||||
* NOTE: you should invoke yy_init() if you are calling yylex()
|
||||
* with new input; otherwise old lookaside will get in your way
|
||||
* and yylex() will die horribly.
|
||||
*/
|
||||
YYDECL {
|
||||
|
||||
#endif /* LEX_WINDOWS */
|
||||
|
||||
register int c, i, yybase;
|
||||
unsigned yyst; /* state */
|
||||
int yyfmin, yyfmax; /* yy_la_act indices of final states */
|
||||
int yyoldi, yyoleng; /* base i, yyleng before look-ahead */
|
||||
int yyeof; /* 1 if eof has already been read */
|
||||
@ LOCAL DECLARATIONS @
|
||||
|
||||
|
||||
#if !YY_STATIC_STDIO
|
||||
if (yyin == (FILE *)0)
|
||||
yyin = stdin;
|
||||
if (yyout == (FILE *)0)
|
||||
yyout = stdout;
|
||||
#endif
|
||||
|
||||
#ifdef YYEXIT
|
||||
yyLexFatal = 0;
|
||||
#endif /* YYEXIT */
|
||||
|
||||
yyeof = 0;
|
||||
i = yyleng;
|
||||
YY_SCANNER;
|
||||
|
||||
yy_again:
|
||||
yyleng = i;
|
||||
/* determine previous char. */
|
||||
if (i > 0)
|
||||
yy_lastc = yytext[i-1];
|
||||
/* scan previously accepted token adjusting yylineno */
|
||||
while (i > 0)
|
||||
if (yytext[--i] == YYNEWLINE)
|
||||
yylineno++;
|
||||
/* adjust pushback */
|
||||
yy_end -= yyleng;
|
||||
if (yy_end > 0)
|
||||
memmove(yytext, yytext+yyleng, (size_t) yy_end);
|
||||
i = 0;
|
||||
|
||||
yy_contin:
|
||||
yyoldi = i;
|
||||
|
||||
/* run the state machine until it jams */
|
||||
yyst = yy_begin[yy_start + ((yy_lastc == YYNEWLINE) ? 1 : 0)];
|
||||
yy_sbuf[i] = (yy_state_t) yyst;
|
||||
do {
|
||||
YY_DEBUG(m_textmsg(1547, "<state %d, i = %d>\n", "I num1 num2"), yyst, i);
|
||||
if (i >= YYLMAX) {
|
||||
YY_FATAL(m_textmsg(1548, "Token buffer overflow", "E"));
|
||||
#ifdef YYEXIT
|
||||
if (yyLexFatal)
|
||||
return -2;
|
||||
#endif /* YYEXIT */
|
||||
} /* endif */
|
||||
|
||||
/* get input char */
|
||||
if (i < yy_end)
|
||||
c = yytext[i]; /* get pushback char */
|
||||
else if (!yyeof && (c = yygetc()) != EOF) {
|
||||
yy_end = i+1;
|
||||
yytext[i] = (char) c;
|
||||
} else /* c == EOF */ {
|
||||
c = EOF; /* just to make sure... */
|
||||
if (i == yyoldi) { /* no token */
|
||||
yyeof = 0;
|
||||
if (yywrap())
|
||||
return 0;
|
||||
else
|
||||
goto yy_again;
|
||||
} else {
|
||||
yyeof = 1; /* don't re-read EOF */
|
||||
break;
|
||||
}
|
||||
}
|
||||
YY_DEBUG(m_textmsg(1549, "<input %d = 0x%02x>\n", "I num hexnum"), c, c);
|
||||
|
||||
/* look up next state */
|
||||
while ((yybase = yy_base[yyst]+(unsigned char)c) > yy_nxtmax
|
||||
|| yy_check[yybase] != (yy_state_t) yyst) {
|
||||
if (yyst == yy_endst)
|
||||
goto yy_jammed;
|
||||
yyst = yy_default[yyst];
|
||||
}
|
||||
yyst = yy_next[yybase];
|
||||
yy_jammed: ;
|
||||
yy_sbuf[++i] = (yy_state_t) yyst;
|
||||
} while (!(yyst == yy_endst || YY_INTERACTIVE && yy_base[yyst] > yy_nxtmax && yy_default[yyst] == yy_endst));
|
||||
YY_DEBUG(m_textmsg(1550, "<stopped %d, i = %d>\n", "I num1 num2"), yyst, i);
|
||||
if (yyst != yy_endst)
|
||||
++i;
|
||||
|
||||
yy_search:
|
||||
/* search backward for a final state */
|
||||
while (--i > yyoldi) {
|
||||
yyst = yy_sbuf[i];
|
||||
if ((yyfmin = yy_final[yyst]) < (yyfmax = yy_final[yyst+1]))
|
||||
goto yy_found; /* found final state(s) */
|
||||
}
|
||||
/* no match, default action */
|
||||
i = yyoldi + 1;
|
||||
output(yytext[yyoldi]);
|
||||
goto yy_again;
|
||||
|
||||
yy_found:
|
||||
YY_DEBUG(m_textmsg(1551, "<final state %d, i = %d>\n", "I num1 num2"), yyst, i);
|
||||
yyoleng = i; /* save length for REJECT */
|
||||
|
||||
/* pushback look-ahead RHS */
|
||||
if ((c = (int)(yy_la_act[yyfmin]>>9) - 1) >= 0) { /* trailing context? */
|
||||
unsigned char *bv = yy_look + c*YY_LA_SIZE;
|
||||
static unsigned char bits [8] = {
|
||||
1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7
|
||||
};
|
||||
while (1) {
|
||||
if (--i < yyoldi) { /* no / */
|
||||
i = yyoleng;
|
||||
break;
|
||||
}
|
||||
yyst = yy_sbuf[i];
|
||||
if (bv[(unsigned)yyst/8] & bits[(unsigned)yyst%8])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* perform action */
|
||||
yyleng = i;
|
||||
YY_USER;
|
||||
switch (yy_la_act[yyfmin] & 0777) {
|
||||
@ ACTION CODE @
|
||||
}
|
||||
YY_SCANNER;
|
||||
i = yyleng;
|
||||
goto yy_again; /* action fell though */
|
||||
|
||||
yy_reject:
|
||||
YY_SCANNER;
|
||||
i = yyoleng; /* restore original yytext */
|
||||
if (++yyfmin < yyfmax)
|
||||
goto yy_found; /* another final state, same length */
|
||||
else
|
||||
goto yy_search; /* try shorter yytext */
|
||||
|
||||
yy_more:
|
||||
YY_SCANNER;
|
||||
i = yyleng;
|
||||
if (i > 0)
|
||||
yy_lastc = yytext[i-1];
|
||||
goto yy_contin;
|
||||
}
|
||||
/*
|
||||
* Safely switch input stream underneath LEX
|
||||
*/
|
||||
typedef struct yy_save_block_tag {
|
||||
FILE * oldfp;
|
||||
int oldline;
|
||||
int oldend;
|
||||
int oldstart;
|
||||
int oldlastc;
|
||||
int oldleng;
|
||||
char savetext[YYLMAX+1];
|
||||
yy_state_t savestate[YYLMAX+1];
|
||||
} YY_SAVED;
|
||||
|
||||
void
|
||||
yy_reset()
|
||||
{
|
||||
YY_INIT;
|
||||
yylineno = 1; /* line number */
|
||||
}
|
||||
|
||||
#if 0
|
||||
YY_SAVED *
|
||||
yySaveScan(fp)
|
||||
FILE * fp;
|
||||
{
|
||||
YY_SAVED * p;
|
||||
|
||||
if ((p = (YY_SAVED *) malloc(sizeof(*p))) == NULL)
|
||||
return p;
|
||||
|
||||
p->oldfp = yyin;
|
||||
p->oldline = yylineno;
|
||||
p->oldend = yy_end;
|
||||
p->oldstart = yy_start;
|
||||
p->oldlastc = yy_lastc;
|
||||
p->oldleng = yyleng;
|
||||
(void) memcpy(p->savetext, yytext, sizeof yytext);
|
||||
(void) memcpy((char *) p->savestate, (char *) yy_sbuf,
|
||||
sizeof yy_sbuf);
|
||||
|
||||
yyin = fp;
|
||||
yylineno = 1;
|
||||
YY_INIT;
|
||||
|
||||
return p;
|
||||
}
|
||||
/*f
|
||||
* Restore previous LEX state
|
||||
*/
|
||||
void
|
||||
yyRestoreScan(p)
|
||||
YY_SAVED * p;
|
||||
{
|
||||
if (p == NULL)
|
||||
return;
|
||||
yyin = p->oldfp;
|
||||
yylineno = p->oldline;
|
||||
yy_end = p->oldend;
|
||||
yy_start = p->oldstart;
|
||||
yy_lastc = p->oldlastc;
|
||||
yyleng = p->oldleng;
|
||||
|
||||
(void) memcpy(yytext, p->savetext, sizeof yytext);
|
||||
(void) memcpy((char *) yy_sbuf, (char *) p->savestate,
|
||||
sizeof yy_sbuf);
|
||||
free(p);
|
||||
}
|
||||
/*
|
||||
* User-callable re-initialization of yylex()
|
||||
*/
|
||||
/* get input char with pushback */
|
||||
YY_DECL int
|
||||
input()
|
||||
{
|
||||
int c;
|
||||
#ifndef YY_PRESERVE
|
||||
if (yy_end > yyleng) {
|
||||
yy_end--;
|
||||
memmove(yytext+yyleng, yytext+yyleng+1,
|
||||
(size_t) (yy_end-yyleng));
|
||||
c = yy_save;
|
||||
YY_USER;
|
||||
#else
|
||||
if (yy_push < yy_save+YYLMAX) {
|
||||
c = *yy_push++;
|
||||
#endif
|
||||
} else
|
||||
c = yygetc();
|
||||
yy_lastc = c;
|
||||
if (c == YYNEWLINE)
|
||||
yylineno++;
|
||||
if (c == EOF) /* yygetc() can set c=EOF vsc4 wants c==EOF to return 0 */
|
||||
return 0;
|
||||
else
|
||||
return c;
|
||||
}
|
||||
|
||||
/*f
|
||||
* pushback char
|
||||
*/
|
||||
YY_DECL int
|
||||
unput(c)
|
||||
int c;
|
||||
{
|
||||
#ifndef YY_PRESERVE
|
||||
if (yy_end >= YYLMAX) {
|
||||
YY_FATAL(m_textmsg(1552, "Push-back buffer overflow", "E"));
|
||||
} else {
|
||||
if (yy_end > yyleng) {
|
||||
yytext[yyleng] = yy_save;
|
||||
memmove(yytext+yyleng+1, yytext+yyleng,
|
||||
(size_t) (yy_end-yyleng));
|
||||
yytext[yyleng] = 0;
|
||||
}
|
||||
yy_end++;
|
||||
yy_save = (char) c;
|
||||
#else
|
||||
if (yy_push <= yy_save) {
|
||||
YY_FATAL(m_textmsg(1552, "Push-back buffer overflow", "E"));
|
||||
} else {
|
||||
*--yy_push = c;
|
||||
#endif
|
||||
if (c == YYNEWLINE)
|
||||
yylineno--;
|
||||
} /* endif */
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ end of yylex.c @
|
||||
918
console/yyparse.c
Normal file
918
console/yyparse.c
Normal file
|
|
@ -0,0 +1,918 @@
|
|||
#ifdef YYTRACE
|
||||
#define YYDEBUG 1
|
||||
#else
|
||||
#ifndef YYDEBUG
|
||||
#define YYDEBUG $Y
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
* Portable way of defining ANSI C prototypes
|
||||
*/
|
||||
#ifndef YY_ARGS
|
||||
#ifdef __STDC__
|
||||
#define YY_ARGS(x) x
|
||||
#else
|
||||
#define YY_ARGS(x) ()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef YACC_WINDOWS
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/*
|
||||
* the following is the handle to the current
|
||||
* instance of a windows program. The user
|
||||
* program calling yyparse must supply this!
|
||||
*/
|
||||
|
||||
#ifdef STRICT
|
||||
extern HINSTANCE hInst;
|
||||
#else
|
||||
extern HANDLE hInst;
|
||||
#endif
|
||||
|
||||
#endif /* YACC_WINDOWS */
|
||||
|
||||
#if YYDEBUG
|
||||
typedef struct yyNamedType_tag { /* Tokens */
|
||||
char * name; /* printable name */
|
||||
short token; /* token # */
|
||||
short type; /* token type */
|
||||
} yyNamedType;
|
||||
typedef struct yyTypedRules_tag { /* Typed rule table */
|
||||
char * name; /* compressed rule string */
|
||||
short type; /* rule result type */
|
||||
} yyTypedRules;
|
||||
|
||||
#endif
|
||||
|
||||
$@
|
||||
#if YYDEBUG
|
||||
/*
|
||||
* Package up YACC context for tracing
|
||||
*/
|
||||
typedef struct yyTraceItems_tag {
|
||||
int state, lookahead, errflag, done;
|
||||
int rule, npop;
|
||||
short * states;
|
||||
int nstates;
|
||||
YYSTYPE * values;
|
||||
int nvalues;
|
||||
short * types;
|
||||
} yyTraceItems;
|
||||
#endif
|
||||
|
||||
$L#line 2 "$P"
|
||||
|
||||
/*
|
||||
* Copyright 1985, 1990 by Mortice Kern Systems Inc. All rights reserved.
|
||||
*
|
||||
* Automaton to interpret LALR(1) tables.
|
||||
*
|
||||
* Macros:
|
||||
* yyclearin - clear the lookahead token.
|
||||
* yyerrok - forgive a pending error
|
||||
* YYERROR - simulate an error
|
||||
* YYACCEPT - halt and return 0
|
||||
* YYABORT - halt and return 1
|
||||
* YYRETURN(value) - halt and return value. You should use this
|
||||
* instead of return(value).
|
||||
* YYREAD - ensure yychar contains a lookahead token by reading
|
||||
* one if it does not. See also YYSYNC.
|
||||
* YYRECOVERING - 1 if syntax error detected and not recovered
|
||||
* yet; otherwise, 0.
|
||||
*
|
||||
* Preprocessor flags:
|
||||
* YYDEBUG - includes debug code if 1. The parser will print
|
||||
* a travelogue of the parse if this is defined as 1
|
||||
* and yydebug is non-zero.
|
||||
* yacc -t sets YYDEBUG to 1, but not yydebug.
|
||||
* YYTRACE - turn on YYDEBUG, and undefine default trace functions
|
||||
* so that the interactive functions in 'ytrack.c' will
|
||||
* be used.
|
||||
* YYSSIZE - size of state and value stacks (default 150).
|
||||
* YYSTATIC - By default, the state stack is an automatic array.
|
||||
* If this is defined, the stack will be static.
|
||||
* In either case, the value stack is static.
|
||||
* YYALLOC - Dynamically allocate both the state and value stacks
|
||||
* by calling malloc() and free().
|
||||
* YYDYNAMIC - Dynamically allocate (and reallocate, if necessary)
|
||||
* both the state and value stacks by calling malloc(),
|
||||
* realloc(), and free().
|
||||
* YYSYNC - if defined, yacc guarantees to fetch a lookahead token
|
||||
* before any action, even if it doesnt need it for a decision.
|
||||
* If YYSYNC is defined, YYREAD will never be necessary unless
|
||||
* the user explicitly sets yychar = -1
|
||||
*
|
||||
* Copyright (c) 1983, by the University of Waterloo
|
||||
*/
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
|
||||
extern int yylex YY_ARGS((void));
|
||||
extern void yyerror YY_ARGS((char *, ...));
|
||||
|
||||
#if YYDEBUG
|
||||
|
||||
#include <stdlib.h> /* common prototypes */
|
||||
#include <string.h>
|
||||
|
||||
extern char * yyValue YY_ARGS((YYSTYPE, int)); /* print yylval */
|
||||
extern void yyShowState YY_ARGS((yyTraceItems *));
|
||||
extern void yyShowReduce YY_ARGS((yyTraceItems *));
|
||||
extern void yyShowGoto YY_ARGS((yyTraceItems *));
|
||||
extern void yyShowShift YY_ARGS((yyTraceItems *));
|
||||
extern void yyShowErrRecovery YY_ARGS((yyTraceItems *));
|
||||
extern void yyShowErrDiscard YY_ARGS((yyTraceItems *));
|
||||
|
||||
extern void yyShowRead YY_ARGS((int));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If YYDEBUG defined and yydebug set,
|
||||
* tracing functions will be called at appropriate times in yyparse()
|
||||
* Pass state of YACC parse, as filled into yyTraceItems yyx
|
||||
* If yyx.done is set by the tracing function, yyparse() will terminate
|
||||
* with a return value of -1
|
||||
*/
|
||||
#define YY_TRACE(fn) { \
|
||||
yyx.state = yystate; yyx.lookahead = yychar; yyx.errflag =yyerrflag; \
|
||||
yyx.states = yys+1; yyx.nstates = yyps-yys; \
|
||||
yyx.values = yyv+1; yyx.nvalues = yypv-yyv; \
|
||||
yyx.types = yytypev+1; yyx.done = 0; \
|
||||
yyx.rule = yyi; yyx.npop = yyj; \
|
||||
fn(&yyx); \
|
||||
if (yyx.done) YYRETURN(-1); }
|
||||
|
||||
#ifndef I18N
|
||||
#define m_textmsg(id, str, cls) (str)
|
||||
#else /*I18N*/
|
||||
#include <m_nls.h>
|
||||
#endif/*I18N*/
|
||||
|
||||
#ifndef YYSSIZE
|
||||
# define YYSSIZE 150
|
||||
#endif
|
||||
|
||||
#ifdef YYDYNAMIC
|
||||
#define YYALLOC
|
||||
char *getenv();
|
||||
int atoi();
|
||||
int yysinc = -1; /* stack size increment, <0 = double, 0 = none, >0 = fixed */
|
||||
#endif
|
||||
|
||||
#ifdef YYALLOC
|
||||
int yyssize = YYSSIZE;
|
||||
#endif
|
||||
|
||||
#define YYERROR goto yyerrlabel
|
||||
#define yyerrok yyerrflag = 0
|
||||
#if YYDEBUG
|
||||
#define yyclearin { if (yydebug) yyShowRead(-1); yychar = -1; }
|
||||
#else
|
||||
#define yyclearin yychar = -1
|
||||
#endif
|
||||
#define YYACCEPT YYRETURN(0)
|
||||
#define YYABORT YYRETURN(1)
|
||||
#define YYRECOVERING() (yyerrflag != 0)
|
||||
#ifdef YYALLOC
|
||||
#define YYRETURN(val) { retval = (val); goto yyReturn; }
|
||||
#else
|
||||
#define YYRETURN(val) return(val);
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
/* The if..else makes this macro behave exactly like a statement */
|
||||
# define YYREAD if (yychar < 0) { \
|
||||
if ((yychar = yylex()) < 0) { \
|
||||
if (yychar == -2) YYABORT; \
|
||||
yychar = 0; \
|
||||
} /* endif */ \
|
||||
if (yydebug) \
|
||||
yyShowRead(yychar); \
|
||||
} else
|
||||
#else
|
||||
# define YYREAD if (yychar < 0) { \
|
||||
if ((yychar = yylex()) < 0) { \
|
||||
if (yychar == -2) YYABORT; \
|
||||
yychar = 0; \
|
||||
} /* endif */ \
|
||||
} else
|
||||
#endif
|
||||
|
||||
#define YYERRCODE $e /* value of `error' */
|
||||
#define YYTOKEN_BASE 256
|
||||
#define YYQYYP yyq[yyq-yyp]
|
||||
|
||||
/*
|
||||
* Simulate bitwise negation as if was done on a two's complement machine.
|
||||
* This makes the generated code portable to machines with different
|
||||
* representations of integers (ie. signed magnitude).
|
||||
*/
|
||||
#define yyneg(s) (-((s)+1))
|
||||
|
||||
YYSTYPE yyval; /* $$ */
|
||||
YYSTYPE *yypvt; /* $n */
|
||||
YYSTYPE yylval; /* yylex() sets this */
|
||||
|
||||
int yychar, /* current token */
|
||||
yyerrflag, /* error flag */
|
||||
yynerrs; /* error count */
|
||||
|
||||
#if YYDEBUG
|
||||
int yydebug = 0; /* debug if this flag is set */
|
||||
extern char *yysvar[]; /* table of non-terminals (aka 'variables') */
|
||||
extern yyNamedType yyTokenTypes[]; /* table of terminals & their types */
|
||||
extern short yyrmap[], yysmap[]; /* map internal rule/states */
|
||||
extern int yynstate, yynvar, yyntoken, yynrule;
|
||||
|
||||
extern int yyGetType YY_ARGS((int)); /* token type */
|
||||
extern char *yyptok YY_ARGS((int)); /* printable token string */
|
||||
extern int yyExpandName YY_ARGS((int, int, char *, int));
|
||||
/* expand yyRules[] or yyStates[] */
|
||||
static char * yygetState YY_ARGS((int));
|
||||
|
||||
#define yyassert(condition, msg, arg) \
|
||||
if (!(condition)) { \
|
||||
printf(m_textmsg(2824, "\nyacc bug: ", "E")); \
|
||||
printf(msg, arg); \
|
||||
YYABORT; }
|
||||
#else /* !YYDEBUG */
|
||||
#define yyassert(condition, msg, arg)
|
||||
#endif
|
||||
|
||||
$T
|
||||
|
||||
#ifdef YACC_WINDOWS
|
||||
|
||||
/*
|
||||
* the following is the yyparse() function that will be
|
||||
* callable by a windows type program. It in turn will
|
||||
* load all needed resources, obtain pointers to these
|
||||
* resources, and call a statically defined function
|
||||
* win_yyparse(), which is the original yyparse() fn
|
||||
* When win_yyparse() is complete, it will return a
|
||||
* value to the new yyparse(), where it will be stored
|
||||
* away temporarily, all resources will be freed, and
|
||||
* that return value will be given back to the caller
|
||||
* yyparse(), as expected.
|
||||
*/
|
||||
|
||||
static int win_yyparse(); /* prototype */
|
||||
|
||||
int yyparse()
|
||||
{
|
||||
int wReturnValue;
|
||||
HANDLE hRes_table; /* handle of resource after loading */
|
||||
short far *old_yydef; /* the following are used for saving */
|
||||
short far *old_yyex; /* the current pointers */
|
||||
short far *old_yyact;
|
||||
short far *old_yypact;
|
||||
short far *old_yygo;
|
||||
short far *old_yypgo;
|
||||
short far *old_yyrlen;
|
||||
|
||||
/*
|
||||
* the following code will load the required
|
||||
* resources for a Windows based parser.
|
||||
*/
|
||||
|
||||
hRes_table = LoadResource (hInst,
|
||||
FindResource (hInst, "UD_RES_yyYACC", "yyYACCTBL"));
|
||||
|
||||
/*
|
||||
* return an error code if any
|
||||
* of the resources did not load
|
||||
*/
|
||||
|
||||
if (hRes_table == NULL)
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* the following code will lock the resources
|
||||
* into fixed memory locations for the parser
|
||||
* (also, save the current pointer values first)
|
||||
*/
|
||||
|
||||
old_yydef = yydef;
|
||||
old_yyex = yyex;
|
||||
old_yyact = yyact;
|
||||
old_yypact = yypact;
|
||||
old_yygo = yygo;
|
||||
old_yypgo = yypgo;
|
||||
old_yyrlen = yyrlen;
|
||||
|
||||
yydef = (short far *)LockResource (hRes_table);
|
||||
yyex = (short far *)(yydef + Sizeof_yydef);
|
||||
yyact = (short far *)(yyex + Sizeof_yyex);
|
||||
yypact = (short far *)(yyact + Sizeof_yyact);
|
||||
yygo = (short far *)(yypact + Sizeof_yypact);
|
||||
yypgo = (short far *)(yygo + Sizeof_yygo);
|
||||
yyrlen = (short far *)(yypgo + Sizeof_yypgo);
|
||||
|
||||
/*
|
||||
* call the official yyparse() function
|
||||
*/
|
||||
|
||||
wReturnValue = win_yyparse();
|
||||
|
||||
/*
|
||||
* unlock the resources
|
||||
*/
|
||||
|
||||
UnlockResource (hRes_table);
|
||||
|
||||
/*
|
||||
* and now free the resource
|
||||
*/
|
||||
|
||||
FreeResource (hRes_table);
|
||||
|
||||
/*
|
||||
* restore previous pointer values
|
||||
*/
|
||||
|
||||
yydef = old_yydef;
|
||||
yyex = old_yyex;
|
||||
yyact = old_yyact;
|
||||
yypact = old_yypact;
|
||||
yygo = old_yygo;
|
||||
yypgo = old_yypgo;
|
||||
yyrlen = old_yyrlen;
|
||||
|
||||
return (wReturnValue);
|
||||
} /* end yyparse */
|
||||
|
||||
static int win_yyparse()
|
||||
|
||||
#else /* YACC_WINDOWS */
|
||||
|
||||
/*
|
||||
* we are not compiling a windows resource
|
||||
* based parser, so call yyparse() the old
|
||||
* standard way.
|
||||
*/
|
||||
|
||||
int yyparse()
|
||||
|
||||
#endif /* YACC_WINDOWS */
|
||||
|
||||
{
|
||||
#ifdef YACC_WINDOWS
|
||||
register short far *yyp; /* for table lookup */
|
||||
register short far *yyq;
|
||||
#else
|
||||
register short *yyp; /* for table lookup */
|
||||
register short *yyq;
|
||||
#endif /* YACC_WINDOWS */
|
||||
register short yyi;
|
||||
register short *yyps; /* top of state stack */
|
||||
register short yystate; /* current state */
|
||||
register YYSTYPE *yypv; /* top of value stack */
|
||||
register int yyj;
|
||||
#if YYDEBUG
|
||||
yyTraceItems yyx; /* trace block */
|
||||
short * yytp;
|
||||
int yyruletype = 0;
|
||||
#endif
|
||||
#ifdef YYSTATIC
|
||||
static short yys[YYSSIZE + 1];
|
||||
static YYSTYPE yyv[YYSSIZE + 1];
|
||||
#if YYDEBUG
|
||||
static short yytypev[YYSSIZE+1]; /* type assignments */
|
||||
#endif
|
||||
#else /* ! YYSTATIC */
|
||||
#ifdef YYALLOC
|
||||
YYSTYPE *yyv;
|
||||
short *yys;
|
||||
#if YYDEBUG
|
||||
short *yytypev;
|
||||
#endif
|
||||
YYSTYPE save_yylval;
|
||||
YYSTYPE save_yyval;
|
||||
YYSTYPE *save_yypvt;
|
||||
int save_yychar, save_yyerrflag, save_yynerrs;
|
||||
int retval; /* return value holder */
|
||||
#else
|
||||
short yys[YYSSIZE + 1];
|
||||
static YYSTYPE yyv[YYSSIZE + 1]; /* historically static */
|
||||
#if YYDEBUG
|
||||
short yytypev[YYSSIZE+1]; /* mirror type table */
|
||||
#endif
|
||||
#endif /* ! YYALLOC */
|
||||
#endif /* ! YYSTATIC */
|
||||
#ifdef YYDYNAMIC
|
||||
char *envp;
|
||||
#endif
|
||||
|
||||
$A
|
||||
#ifdef YYDYNAMIC
|
||||
if ((envp = getenv("YYSTACKSIZE")) != (char *)0) {
|
||||
yyssize = atoi(envp);
|
||||
if (yyssize <= 0)
|
||||
yyssize = YYSSIZE;
|
||||
}
|
||||
if ((envp = getenv("YYSTACKINC")) != (char *)0)
|
||||
yysinc = atoi(envp);
|
||||
#endif
|
||||
#ifdef YYALLOC
|
||||
yys = (short *) malloc((yyssize + 1) * sizeof(short));
|
||||
yyv = (YYSTYPE *) malloc((yyssize + 1) * sizeof(YYSTYPE));
|
||||
#if YYDEBUG
|
||||
yytypev = (short *) malloc((yyssize + 1) * sizeof(short));
|
||||
#endif
|
||||
if (yys == (short *)0 || yyv == (YYSTYPE *)0
|
||||
#if YYDEBUG
|
||||
|| yytypev == (short *) 0
|
||||
#endif
|
||||
) {
|
||||
yyerror(m_textmsg(4967, "Not enough space for parser stacks",
|
||||
"E"));
|
||||
return 1;
|
||||
}
|
||||
save_yylval = yylval;
|
||||
save_yyval = yyval;
|
||||
save_yypvt = yypvt;
|
||||
save_yychar = yychar;
|
||||
save_yyerrflag = yyerrflag;
|
||||
save_yynerrs = yynerrs;
|
||||
#endif
|
||||
|
||||
yynerrs = 0;
|
||||
yyerrflag = 0;
|
||||
yyclearin;
|
||||
yyps = yys;
|
||||
yypv = yyv;
|
||||
*yyps = yystate = YYS0; /* start state */
|
||||
#if YYDEBUG
|
||||
yytp = yytypev;
|
||||
yyi = yyj = 0; /* silence compiler warnings */
|
||||
#endif
|
||||
|
||||
yyStack:
|
||||
yyassert((unsigned)yystate < yynstate, m_textmsg(587, "state %d\n", ""), yystate);
|
||||
#ifdef YYDYNAMIC
|
||||
if (++yyps > &yys[yyssize]) {
|
||||
int yynewsize;
|
||||
int yysindex = yyps - yys;
|
||||
int yyvindex = yypv - yyv;
|
||||
#if YYDEBUG
|
||||
int yytindex = yytp - yytypev;
|
||||
#endif
|
||||
if (yysinc == 0) { /* no increment */
|
||||
yyerror(m_textmsg(4968, "Parser stack overflow", "E"));
|
||||
YYABORT;
|
||||
} else if (yysinc < 0) /* binary-exponential */
|
||||
yynewsize = yyssize * 2;
|
||||
else /* fixed increment */
|
||||
yynewsize = yyssize + yysinc;
|
||||
if (yynewsize < yyssize) {
|
||||
yyerror(m_textmsg(4967,
|
||||
"Not enough space for parser stacks",
|
||||
"E"));
|
||||
YYABORT;
|
||||
}
|
||||
yyssize = yynewsize;
|
||||
yys = (short *) realloc(yys, (yyssize + 1) * sizeof(short));
|
||||
yyps = yys + yysindex;
|
||||
yyv = (YYSTYPE *) realloc(yyv, (yyssize + 1) * sizeof(YYSTYPE));
|
||||
yypv = yyv + yyvindex;
|
||||
#if YYDEBUG
|
||||
yytypev = (short *)realloc(yytypev,(yyssize + 1)*sizeof(short));
|
||||
yytp = yytypev + yytindex;
|
||||
#endif
|
||||
if (yys == (short *)0 || yyv == (YYSTYPE *)0
|
||||
#if YYDEBUG
|
||||
|| yytypev == (short *) 0
|
||||
#endif
|
||||
) {
|
||||
yyerror(m_textmsg(4967,
|
||||
"Not enough space for parser stacks",
|
||||
"E"));
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (++yyps > &yys[YYSSIZE]) {
|
||||
yyerror(m_textmsg(4968, "Parser stack overflow", "E"));
|
||||
YYABORT;
|
||||
}
|
||||
#endif /* !YYDYNAMIC */
|
||||
*yyps = yystate; /* stack current state */
|
||||
*++yypv = yyval; /* ... and value */
|
||||
#if YYDEBUG
|
||||
*++yytp = yyruletype; /* ... and type */
|
||||
|
||||
if (yydebug)
|
||||
YY_TRACE(yyShowState)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Look up next action in action table.
|
||||
*/
|
||||
yyEncore:
|
||||
#ifdef YYSYNC
|
||||
YYREAD;
|
||||
#endif
|
||||
|
||||
#ifdef YACC_WINDOWS
|
||||
if (yystate >= Sizeof_yypact) /* simple state */
|
||||
#else /* YACC_WINDOWS */
|
||||
if (yystate >= sizeof yypact/sizeof yypact[0]) /* simple state */
|
||||
#endif /* YACC_WINDOWS */
|
||||
yyi = yystate - YYDELTA; /* reduce in any case */
|
||||
else {
|
||||
if(*(yyp = &yyact[yypact[yystate]]) >= 0) {
|
||||
/* Look for a shift on yychar */
|
||||
#ifndef YYSYNC
|
||||
YYREAD;
|
||||
#endif
|
||||
yyq = yyp;
|
||||
yyi = yychar;
|
||||
while (yyi < *yyp++)
|
||||
;
|
||||
if (yyi == yyp[-1]) {
|
||||
yystate = yyneg(YYQYYP);
|
||||
#if YYDEBUG
|
||||
if (yydebug) {
|
||||
yyruletype = yyGetType(yychar);
|
||||
YY_TRACE(yyShowShift)
|
||||
}
|
||||
#endif
|
||||
yyval = yylval; /* stack what yylex() set */
|
||||
yyclearin; /* clear token */
|
||||
if (yyerrflag)
|
||||
yyerrflag--; /* successful shift */
|
||||
goto yyStack;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fell through - take default action
|
||||
*/
|
||||
|
||||
#ifdef YACC_WINDOWS
|
||||
if (yystate >= Sizeof_yydef)
|
||||
#else /* YACC_WINDOWS */
|
||||
if (yystate >= sizeof yydef /sizeof yydef[0])
|
||||
#endif /* YACC_WINDOWS */
|
||||
goto yyError;
|
||||
if ((yyi = yydef[yystate]) < 0) { /* default == reduce? */
|
||||
/* Search exception table */
|
||||
#ifdef YACC_WINDOWS
|
||||
yyassert((unsigned)yyneg(yyi) < Sizeof_yyex,
|
||||
m_textmsg(2825, "exception %d\n", "I num"), yystate);
|
||||
#else /* YACC_WINDOWS */
|
||||
yyassert((unsigned)yyneg(yyi) < sizeof yyex/sizeof yyex[0],
|
||||
m_textmsg(2825, "exception %d\n", "I num"), yystate);
|
||||
#endif /* YACC_WINDOWS */
|
||||
yyp = &yyex[yyneg(yyi)];
|
||||
#ifndef YYSYNC
|
||||
YYREAD;
|
||||
#endif
|
||||
while((yyi = *yyp) >= 0 && yyi != yychar)
|
||||
yyp += 2;
|
||||
yyi = yyp[1];
|
||||
yyassert(yyi >= 0,
|
||||
m_textmsg(2826, "Ex table not reduce %d\n", "I num"), yyi);
|
||||
}
|
||||
}
|
||||
|
||||
yyassert((unsigned)yyi < yynrule, m_textmsg(2827, "reduce %d\n", "I num"), yyi);
|
||||
yyj = yyrlen[yyi];
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
YY_TRACE(yyShowReduce)
|
||||
yytp -= yyj;
|
||||
#endif
|
||||
yyps -= yyj; /* pop stacks */
|
||||
yypvt = yypv; /* save top */
|
||||
yypv -= yyj;
|
||||
yyval = yypv[1]; /* default action $$ = $1 */
|
||||
#if YYDEBUG
|
||||
yyruletype = yyRules[yyrmap[yyi]].type;
|
||||
#endif
|
||||
|
||||
switch (yyi) { /* perform semantic action */
|
||||
$A
|
||||
$L#line 314 "$P"
|
||||
case YYrACCEPT:
|
||||
YYACCEPT;
|
||||
case YYrERROR:
|
||||
goto yyError;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up next state in goto table.
|
||||
*/
|
||||
|
||||
yyp = &yygo[yypgo[yyi]];
|
||||
yyq = yyp++;
|
||||
yyi = *yyps;
|
||||
while (yyi < *yyp++)
|
||||
;
|
||||
|
||||
yystate = yyneg(yyi == *--yyp? YYQYYP: *yyq);
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
YY_TRACE(yyShowGoto)
|
||||
#endif
|
||||
goto yyStack;
|
||||
|
||||
yyerrlabel: ; /* come here from YYERROR */
|
||||
/*
|
||||
#pragma used yyerrlabel
|
||||
*/
|
||||
yyerrflag = 1;
|
||||
if (yyi == YYrERROR) {
|
||||
yyps--;
|
||||
yypv--;
|
||||
#if YYDEBUG
|
||||
yytp--;
|
||||
#endif
|
||||
}
|
||||
|
||||
yyError:
|
||||
switch (yyerrflag) {
|
||||
|
||||
case 0: /* new error */
|
||||
yynerrs++;
|
||||
yyi = yychar;
|
||||
yyerror(m_textmsg(4969, "Syntax error", "E"));
|
||||
if (yyi != yychar) {
|
||||
/* user has changed the current token */
|
||||
/* try again */
|
||||
yyerrflag++; /* avoid loops */
|
||||
goto yyEncore;
|
||||
}
|
||||
|
||||
case 1: /* partially recovered */
|
||||
case 2:
|
||||
yyerrflag = 3; /* need 3 valid shifts to recover */
|
||||
|
||||
/*
|
||||
* Pop states, looking for a
|
||||
* shift on `error'.
|
||||
*/
|
||||
|
||||
for ( ; yyps > yys; yyps--, yypv--
|
||||
#if YYDEBUG
|
||||
, yytp--
|
||||
#endif
|
||||
) {
|
||||
#ifdef YACC_WINDOWS
|
||||
if (*yyps >= Sizeof_yypact)
|
||||
#else /* YACC_WINDOWS */
|
||||
if (*yyps >= sizeof yypact/sizeof yypact[0])
|
||||
#endif /* YACC_WINDOWS */
|
||||
continue;
|
||||
yyp = &yyact[yypact[*yyps]];
|
||||
yyq = yyp;
|
||||
do {
|
||||
if (YYERRCODE == *yyp) {
|
||||
yyp++;
|
||||
yystate = yyneg(YYQYYP);
|
||||
goto yyStack;
|
||||
}
|
||||
} while (*yyp++ > YYTOKEN_BASE);
|
||||
|
||||
/* no shift in this state */
|
||||
#if YYDEBUG
|
||||
if (yydebug && yyps > yys+1)
|
||||
YY_TRACE(yyShowErrRecovery)
|
||||
#endif
|
||||
/* pop stacks; try again */
|
||||
}
|
||||
/* no shift on error - abort */
|
||||
break;
|
||||
|
||||
case 3:
|
||||
/*
|
||||
* Erroneous token after
|
||||
* an error - discard it.
|
||||
*/
|
||||
|
||||
if (yychar == 0) /* but not EOF */
|
||||
break;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
YY_TRACE(yyShowErrDiscard)
|
||||
#endif
|
||||
yyclearin;
|
||||
goto yyEncore; /* try again in same state */
|
||||
}
|
||||
YYABORT;
|
||||
|
||||
#ifdef YYALLOC
|
||||
yyReturn:
|
||||
yylval = save_yylval;
|
||||
yyval = save_yyval;
|
||||
yypvt = save_yypvt;
|
||||
yychar = save_yychar;
|
||||
yyerrflag = save_yyerrflag;
|
||||
yynerrs = save_yynerrs;
|
||||
free((char *)yys);
|
||||
free((char *)yyv);
|
||||
#if YYDEBUG
|
||||
free((char *)yytypev);
|
||||
#endif
|
||||
return(retval);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if YYDEBUG
|
||||
/*
|
||||
* Return type of token
|
||||
*/
|
||||
int
|
||||
yyGetType(tok)
|
||||
int tok;
|
||||
{
|
||||
yyNamedType * tp;
|
||||
for (tp = &yyTokenTypes[yyntoken-1]; tp > yyTokenTypes; tp--)
|
||||
if (tp->token == tok)
|
||||
return tp->type;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Print a token legibly.
|
||||
*/
|
||||
char *
|
||||
yyptok(tok)
|
||||
int tok;
|
||||
{
|
||||
yyNamedType * tp;
|
||||
for (tp = &yyTokenTypes[yyntoken-1]; tp > yyTokenTypes; tp--)
|
||||
if (tp->token == tok)
|
||||
return tp->name;
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Read state 'num' from YYStatesFile
|
||||
*/
|
||||
#ifdef YYTRACE
|
||||
|
||||
static char *
|
||||
yygetState(num)
|
||||
int num;
|
||||
{
|
||||
int size;
|
||||
static FILE *yyStatesFile = (FILE *) 0;
|
||||
static char yyReadBuf[YYMAX_READ+1];
|
||||
|
||||
if (yyStatesFile == (FILE *) 0
|
||||
&& (yyStatesFile = fopen(YYStatesFile, "r")) == (FILE *) 0)
|
||||
return "yyExpandName: cannot open states file";
|
||||
|
||||
if (num < yynstate - 1)
|
||||
size = (int)(yyStates[num+1] - yyStates[num]);
|
||||
else {
|
||||
/* length of last item is length of file - ptr(last-1) */
|
||||
if (fseek(yyStatesFile, 0L, 2) < 0)
|
||||
goto cannot_seek;
|
||||
size = (int) (ftell(yyStatesFile) - yyStates[num]);
|
||||
}
|
||||
if (size < 0 || size > YYMAX_READ)
|
||||
return "yyExpandName: bad read size";
|
||||
if (fseek(yyStatesFile, yyStates[num], 0) < 0) {
|
||||
cannot_seek:
|
||||
return "yyExpandName: cannot seek in states file";
|
||||
}
|
||||
|
||||
(void) fread(yyReadBuf, 1, size, yyStatesFile);
|
||||
yyReadBuf[size] = '\0';
|
||||
return yyReadBuf;
|
||||
}
|
||||
#endif /* YYTRACE */
|
||||
/*
|
||||
* Expand encoded string into printable representation
|
||||
* Used to decode yyStates and yyRules strings.
|
||||
* If the expansion of 's' fits in 'buf', return 1; otherwise, 0.
|
||||
*/
|
||||
int
|
||||
yyExpandName(num, isrule, buf, len)
|
||||
int num, isrule;
|
||||
char * buf;
|
||||
int len;
|
||||
{
|
||||
int i, n, cnt, type;
|
||||
char * endp, * cp;
|
||||
char *s;
|
||||
|
||||
if (isrule)
|
||||
s = yyRules[num].name;
|
||||
else
|
||||
#ifdef YYTRACE
|
||||
s = yygetState(num);
|
||||
#else
|
||||
s = "*no states*";
|
||||
#endif
|
||||
|
||||
for (endp = buf + len - 8; *s; s++) {
|
||||
if (buf >= endp) { /* too large: return 0 */
|
||||
full: (void) strcpy(buf, " ...\n");
|
||||
return 0;
|
||||
} else if (*s == '%') { /* nonterminal */
|
||||
type = 0;
|
||||
cnt = yynvar;
|
||||
goto getN;
|
||||
} else if (*s == '&') { /* terminal */
|
||||
type = 1;
|
||||
cnt = yyntoken;
|
||||
getN:
|
||||
if (cnt < 100)
|
||||
i = 2;
|
||||
else if (cnt < 1000)
|
||||
i = 3;
|
||||
else
|
||||
i = 4;
|
||||
for (n = 0; i-- > 0; )
|
||||
n = (n * 10) + *++s - '0';
|
||||
if (type == 0) {
|
||||
if (n >= yynvar)
|
||||
goto too_big;
|
||||
cp = yysvar[n];
|
||||
} else if (n >= yyntoken) {
|
||||
too_big:
|
||||
cp = "<range err>";
|
||||
} else
|
||||
cp = yyTokenTypes[n].name;
|
||||
|
||||
if ((i = strlen(cp)) + buf > endp)
|
||||
goto full;
|
||||
(void) strcpy(buf, cp);
|
||||
buf += i;
|
||||
} else
|
||||
*buf++ = *s;
|
||||
}
|
||||
*buf = '\0';
|
||||
return 1;
|
||||
}
|
||||
#ifndef YYTRACE
|
||||
/*
|
||||
* Show current state of yyparse
|
||||
*/
|
||||
void
|
||||
yyShowState(tp)
|
||||
yyTraceItems * tp;
|
||||
{
|
||||
short * p;
|
||||
YYSTYPE * q;
|
||||
|
||||
printf(
|
||||
m_textmsg(2828, "state %d (%d), char %s (%d)\n", "I num1 num2 char num3"),
|
||||
yysmap[tp->state], tp->state,
|
||||
yyptok(tp->lookahead), tp->lookahead);
|
||||
}
|
||||
/*
|
||||
* show results of reduction
|
||||
*/
|
||||
void
|
||||
yyShowReduce(tp)
|
||||
yyTraceItems * tp;
|
||||
{
|
||||
printf("reduce %d (%d), pops %d (%d)\n",
|
||||
yyrmap[tp->rule], tp->rule,
|
||||
tp->states[tp->nstates - tp->npop],
|
||||
yysmap[tp->states[tp->nstates - tp->npop]]);
|
||||
}
|
||||
void
|
||||
yyShowRead(val)
|
||||
int val;
|
||||
{
|
||||
printf(m_textmsg(2829, "read %s (%d)\n", "I token num"), yyptok(val), val);
|
||||
}
|
||||
void
|
||||
yyShowGoto(tp)
|
||||
yyTraceItems * tp;
|
||||
{
|
||||
printf(m_textmsg(2830, "goto %d (%d)\n", "I num1 num2"), yysmap[tp->state], tp->state);
|
||||
}
|
||||
void
|
||||
yyShowShift(tp)
|
||||
yyTraceItems * tp;
|
||||
{
|
||||
printf(m_textmsg(2831, "shift %d (%d)\n", "I num1 num2"), yysmap[tp->state], tp->state);
|
||||
}
|
||||
void
|
||||
yyShowErrRecovery(tp)
|
||||
yyTraceItems * tp;
|
||||
{
|
||||
short * top = tp->states + tp->nstates - 1;
|
||||
|
||||
printf(
|
||||
m_textmsg(2832, "Error recovery pops state %d (%d), uncovers %d (%d)\n", "I num1 num2 num3 num4"),
|
||||
yysmap[*top], *top, yysmap[*(top-1)], *(top-1));
|
||||
}
|
||||
void
|
||||
yyShowErrDiscard(tp)
|
||||
yyTraceItems * tp;
|
||||
{
|
||||
printf(m_textmsg(2833, "Error recovery discards %s (%d), ", "I token num"),
|
||||
yyptok(tp->lookahead), tp->lookahead);
|
||||
}
|
||||
#endif /* ! YYTRACE */
|
||||
#endif /* YYDEBUG */
|
||||
Loading…
Add table
Add a link
Reference in a new issue