doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Script_Program.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "../Game_local.h"
33 
34 // simple types. function types are dynamically allocated
35 idTypeDef type_void( ev_void, &def_void, "void", 0, NULL );
36 idTypeDef type_scriptevent( ev_scriptevent, &def_scriptevent, "scriptevent", sizeof( void * ), NULL );
37 idTypeDef type_namespace( ev_namespace, &def_namespace, "namespace", sizeof( void * ), NULL );
39 idTypeDef type_float( ev_float, &def_float, "float", sizeof( float ), NULL );
40 idTypeDef type_vector( ev_vector, &def_vector, "vector", sizeof( idVec3 ), NULL );
41 idTypeDef type_entity( ev_entity, &def_entity, "entity", sizeof( int * ), NULL ); // stored as entity number pointer
42 idTypeDef type_field( ev_field, &def_field, "field", sizeof( void * ), NULL );
43 idTypeDef type_function( ev_function, &def_function, "function", sizeof( void * ), &type_void );
44 idTypeDef type_virtualfunction( ev_virtualfunction, &def_virtualfunction, "virtual function", sizeof( int ), NULL );
45 idTypeDef type_pointer( ev_pointer, &def_pointer, "pointer", sizeof( void * ), NULL );
46 idTypeDef type_object( ev_object, &def_object, "object", sizeof( int * ), NULL ); // stored as entity number pointer
47 idTypeDef type_jumpoffset( ev_jumpoffset, &def_jumpoffset, "<jump>", sizeof( int ), NULL ); // only used for jump opcodes
48 idTypeDef type_argsize( ev_argsize, &def_argsize, "<argsize>", sizeof( int ), NULL ); // only used for function call and thread opcodes
49 idTypeDef type_boolean( ev_boolean, &def_boolean, "boolean", sizeof( int ), NULL );
50 
63 idVarDef def_jumpoffset( &type_jumpoffset ); // only used for jump opcodes
66 
67 /***********************************************************************
68 
69  function_t
70 
71 ***********************************************************************/
72 
73 /*
74 ================
75 function_t::function_t
76 ================
77 */
79  Clear();
80 }
81 
82 /*
83 ================
84 function_t::Allocated
85 ================
86 */
87 size_t function_t::Allocated( void ) const {
88  return name.Allocated() + parmSize.Allocated();
89 }
90 
91 /*
92 ================
93 function_t::SetName
94 ================
95 */
96 void function_t::SetName( const char *name ) {
97  this->name = name;
98 }
99 
100 /*
101 ================
102 function_t::Name
103 ================
104 */
105 const char *function_t::Name( void ) const {
106  return name;
107 }
108 
109 /*
110 ================
111 function_t::Clear
112 ================
113 */
114 void function_t::Clear( void ) {
115  eventdef = NULL;
116  def = NULL;
117  type = NULL;
118  firstStatement = 0;
119  numStatements = 0;
120  parmTotal = 0;
121  locals = 0;
122  filenum = 0;
123  name.Clear();
124  parmSize.Clear();
125 }
126 
127 /***********************************************************************
128 
129  idTypeDef
130 
131 ***********************************************************************/
132 
133 /*
134 ================
135 idTypeDef::idTypeDef
136 ================
137 */
138 idTypeDef::idTypeDef( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ) {
139  name = ename;
140  type = etype;
141  def = edef;
142  size = esize;
143  auxType = aux;
144 
148 }
149 
150 /*
151 ================
152 idTypeDef::idTypeDef
153 ================
154 */
156  *this = other;
157 }
158 
159 /*
160 ================
161 idTypeDef::operator=
162 ================
163 */
164 void idTypeDef::operator=( const idTypeDef& other ) {
165  type = other.type;
166  def = other.def;
167  name = other.name;
168  size = other.size;
169  auxType = other.auxType;
170  parmTypes = other.parmTypes;
171  parmNames = other.parmNames;
172  functions = other.functions;
173 }
174 
175 /*
176 ================
177 idTypeDef::Allocated
178 ================
179 */
180 size_t idTypeDef::Allocated( void ) const {
181  size_t memsize;
182  int i;
183 
184  memsize = name.Allocated() + parmTypes.Allocated() + parmNames.Allocated() + functions.Allocated();
185  for( i = 0; i < parmTypes.Num(); i++ ) {
186  memsize += parmNames[ i ].Allocated();
187  }
188 
189  return memsize;
190 }
191 
192 /*
193 ================
194 idTypeDef::Inherits
195 
196 Returns true if basetype is an ancestor of this type.
197 ================
198 */
199 bool idTypeDef::Inherits( const idTypeDef *basetype ) const {
200  idTypeDef *superType;
201 
202  if ( type != ev_object ) {
203  return false;
204  }
205 
206  if ( this == basetype ) {
207  return true;
208  }
209  for( superType = auxType; superType != NULL; superType = superType->auxType ) {
210  if ( superType == basetype ) {
211  return true;
212  }
213  }
214 
215  return false;
216 }
217 
218 /*
219 ================
220 idTypeDef::MatchesType
221 
222 Returns true if both types' base types and parameters match
223 ================
224 */
225 bool idTypeDef::MatchesType( const idTypeDef &matchtype ) const {
226  int i;
227 
228  if ( this == &matchtype ) {
229  return true;
230  }
231 
232  if ( ( type != matchtype.type ) || ( auxType != matchtype.auxType ) ) {
233  return false;
234  }
235 
236  if ( parmTypes.Num() != matchtype.parmTypes.Num() ) {
237  return false;
238  }
239 
240  for( i = 0; i < matchtype.parmTypes.Num(); i++ ) {
241  if ( parmTypes[ i ] != matchtype.parmTypes[ i ] ) {
242  return false;
243  }
244  }
245 
246  return true;
247 }
248 
249 /*
250 ================
251 idTypeDef::MatchesVirtualFunction
252 
253 Returns true if both functions' base types and parameters match
254 ================
255 */
256 bool idTypeDef::MatchesVirtualFunction( const idTypeDef &matchfunc ) const {
257  int i;
258 
259  if ( this == &matchfunc ) {
260  return true;
261  }
262 
263  if ( ( type != matchfunc.type ) || ( auxType != matchfunc.auxType ) ) {
264  return false;
265  }
266 
267  if ( parmTypes.Num() != matchfunc.parmTypes.Num() ) {
268  return false;
269  }
270 
271  if ( parmTypes.Num() > 0 ) {
272  if ( !parmTypes[ 0 ]->Inherits( matchfunc.parmTypes[ 0 ] ) ) {
273  return false;
274  }
275  }
276 
277  for( i = 1; i < matchfunc.parmTypes.Num(); i++ ) {
278  if ( parmTypes[ i ] != matchfunc.parmTypes[ i ] ) {
279  return false;
280  }
281  }
282 
283  return true;
284 }
285 
286 /*
287 ================
288 idTypeDef::AddFunctionParm
289 
290 Adds a new parameter for a function type.
291 ================
292 */
293 void idTypeDef::AddFunctionParm( idTypeDef *parmtype, const char *name ) {
294  if ( type != ev_function ) {
295  throw idCompileError( "idTypeDef::AddFunctionParm : tried to add parameter on non-function type" );
296  }
297 
298  parmTypes.Append( parmtype );
299  idStr &parmName = parmNames.Alloc();
300  parmName = name;
301 }
302 
303 /*
304 ================
305 idTypeDef::AddField
306 
307 Adds a new field to an object type.
308 ================
309 */
310 void idTypeDef::AddField( idTypeDef *fieldtype, const char *name ) {
311  if ( type != ev_object ) {
312  throw idCompileError( "idTypeDef::AddField : tried to add field to non-object type" );
313  }
314 
315  parmTypes.Append( fieldtype );
316  idStr &parmName = parmNames.Alloc();
317  parmName = name;
318 
319  if ( fieldtype->FieldType()->Inherits( &type_object ) ) {
320  size += type_object.Size();
321  } else {
322  size += fieldtype->FieldType()->Size();
323  }
324 }
325 
326 /*
327 ================
328 idTypeDef::SetName
329 ================
330 */
331 void idTypeDef::SetName( const char *newname ) {
332  name = newname;
333 }
334 
335 /*
336 ================
337 idTypeDef::Name
338 ================
339 */
340 const char *idTypeDef::Name( void ) const {
341  return name;
342 }
343 
344 /*
345 ================
346 idTypeDef::Type
347 ================
348 */
349 etype_t idTypeDef::Type( void ) const {
350  return type;
351 }
352 
353 /*
354 ================
355 idTypeDef::Size
356 ================
357 */
358 int idTypeDef::Size( void ) const {
359  return size;
360 }
361 
362 /*
363 ================
364 idTypeDef::SuperClass
365 
366 If type is an object, then returns the object's superclass
367 ================
368 */
370  if ( type != ev_object ) {
371  throw idCompileError( "idTypeDef::SuperClass : tried to get superclass of a non-object type" );
372  }
373 
374  return auxType;
375 }
376 
377 /*
378 ================
379 idTypeDef::ReturnType
380 
381 If type is a function, then returns the function's return type
382 ================
383 */
385  if ( type != ev_function ) {
386  throw idCompileError( "idTypeDef::ReturnType: tried to get return type on non-function type" );
387  }
388 
389  return auxType;
390 }
391 
392 /*
393 ================
394 idTypeDef::SetReturnType
395 
396 If type is a function, then sets the function's return type
397 ================
398 */
399 void idTypeDef::SetReturnType( idTypeDef *returntype ) {
400  if ( type != ev_function ) {
401  throw idCompileError( "idTypeDef::SetReturnType: tried to set return type on non-function type" );
402  }
403 
404  auxType = returntype;
405 }
406 
407 /*
408 ================
409 idTypeDef::FieldType
410 
411 If type is a field, then returns it's type
412 ================
413 */
415  if ( type != ev_field ) {
416  throw idCompileError( "idTypeDef::FieldType: tried to get field type on non-field type" );
417  }
418 
419  return auxType;
420 }
421 
422 /*
423 ================
424 idTypeDef::SetFieldType
425 
426 If type is a field, then sets the function's return type
427 ================
428 */
429 void idTypeDef::SetFieldType( idTypeDef *fieldtype ) {
430  if ( type != ev_field ) {
431  throw idCompileError( "idTypeDef::SetFieldType: tried to set return type on non-function type" );
432  }
433 
434  auxType = fieldtype;
435 }
436 
437 /*
438 ================
439 idTypeDef::PointerType
440 
441 If type is a pointer, then returns the type it points to
442 ================
443 */
445  if ( type != ev_pointer ) {
446  throw idCompileError( "idTypeDef::PointerType: tried to get pointer type on non-pointer" );
447  }
448 
449  return auxType;
450 }
451 
452 /*
453 ================
454 idTypeDef::SetPointerType
455 
456 If type is a pointer, then sets the pointer's type
457 ================
458 */
459 void idTypeDef::SetPointerType( idTypeDef *pointertype ) {
460  if ( type != ev_pointer ) {
461  throw idCompileError( "idTypeDef::SetPointerType: tried to set type on non-pointer" );
462  }
463 
464  auxType = pointertype;
465 }
466 
467 /*
468 ================
469 idTypeDef::NumParameters
470 ================
471 */
472 int idTypeDef::NumParameters( void ) const {
473  return parmTypes.Num();
474 }
475 
476 /*
477 ================
478 idTypeDef::GetParmType
479 ================
480 */
481 idTypeDef *idTypeDef::GetParmType( int parmNumber ) const {
482  assert( parmNumber >= 0 );
483  assert( parmNumber < parmTypes.Num() );
484  return parmTypes[ parmNumber ];
485 }
486 
487 /*
488 ================
489 idTypeDef::GetParmName
490 ================
491 */
492 const char *idTypeDef::GetParmName( int parmNumber ) const {
493  assert( parmNumber >= 0 );
494  assert( parmNumber < parmTypes.Num() );
495  return parmNames[ parmNumber ];
496 }
497 
498 /*
499 ================
500 idTypeDef::NumFunctions
501 ================
502 */
503 int idTypeDef::NumFunctions( void ) const {
504  return functions.Num();
505 }
506 
507 /*
508 ================
509 idTypeDef::GetFunctionNumber
510 ================
511 */
512 int idTypeDef::GetFunctionNumber( const function_t *func ) const {
513  int i;
514 
515  for( i = 0; i < functions.Num(); i++ ) {
516  if ( functions[ i ] == func ) {
517  return i;
518  }
519  }
520  return -1;
521 }
522 
523 /*
524 ================
525 idTypeDef::GetFunction
526 ================
527 */
528 const function_t *idTypeDef::GetFunction( int funcNumber ) const {
529  assert( funcNumber >= 0 );
530  assert( funcNumber < functions.Num() );
531  return functions[ funcNumber ];
532 }
533 
534 /*
535 ================
536 idTypeDef::AddFunction
537 ================
538 */
539 void idTypeDef::AddFunction( const function_t *func ) {
540  int i;
541 
542  for( i = 0; i < functions.Num(); i++ ) {
543  if ( !strcmp( functions[ i ]->def->Name(), func->def->Name() ) ) {
544  if ( func->def->TypeDef()->MatchesVirtualFunction( *functions[ i ]->def->TypeDef() ) ) {
545  functions[ i ] = func;
546  return;
547  }
548  }
549  }
550  functions.Append( func );
551 }
552 
553 /***********************************************************************
554 
555  idVarDef
556 
557 ***********************************************************************/
558 
559 /*
560 ================
561 idVarDef::idVarDef()
562 ================
563 */
565  typeDef = typeptr;
566  num = 0;
567  scope = NULL;
568  numUsers = 0;
570  memset( &value, 0, sizeof( value ) );
571  name = NULL;
572  next = NULL;
573 }
574 
575 /*
576 ============
577 idVarDef::~idVarDef
578 ============
579 */
581  if ( name ) {
582  name->RemoveDef( this );
583  }
584 }
585 
586 /*
587 ============
588 idVarDef::Name
589 ============
590 */
591 const char *idVarDef::Name( void ) const {
592  return name->Name();
593 }
594 
595 /*
596 ============
597 idVarDef::GlobalName
598 ============
599 */
600 const char *idVarDef::GlobalName( void ) const {
601  if ( scope != &def_namespace ) {
602  return va( "%s::%s", scope->GlobalName(), name->Name() );
603  } else {
604  return name->Name();
605  }
606 }
607 
608 /*
609 ============
610 idVarDef::DepthOfScope
611 ============
612 */
613 int idVarDef::DepthOfScope( const idVarDef *otherScope ) const {
614  const idVarDef *def;
615  int depth;
616 
617  depth = 1;
618  for( def = otherScope; def != NULL; def = def->scope ) {
619  if ( def == scope ) {
620  return depth;
621  }
622  depth++;
623  }
624 
625  return 0;
626 }
627 
628 /*
629 ============
630 idVarDef::SetFunction
631 ============
632 */
634  assert( typeDef );
636  assert( typeDef->Type() == ev_function );
637  value.functionPtr = func;
638 }
639 
640 /*
641 ============
642 idVarDef::SetObject
643 ============
644 */
646  assert( typeDef );
649  *value.objectPtrPtr = object;
650 }
651 
652 /*
653 ============
654 idVarDef::SetValue
655 ============
656 */
657 void idVarDef::SetValue( const eval_t &_value, bool constant ) {
658  assert( typeDef );
659  if ( constant ) {
661  } else {
663  }
664 
665  switch( typeDef->Type() ) {
666  case ev_pointer :
667  case ev_boolean :
668  case ev_field :
669  *value.intPtr = _value._int;
670  break;
671 
672  case ev_jumpoffset :
673  value.jumpOffset = _value._int;
674  break;
675 
676  case ev_argsize :
677  value.argSize = _value._int;
678  break;
679 
680  case ev_entity :
681  *value.entityNumberPtr = _value.entity;
682  break;
683 
684  case ev_string :
685  idStr::Copynz( value.stringPtr, _value.stringPtr, MAX_STRING_LEN );
686  break;
687 
688  case ev_float :
689  *value.floatPtr = _value._float;
690  break;
691 
692  case ev_vector :
693  value.vectorPtr->x = _value.vector[ 0 ];
694  value.vectorPtr->y = _value.vector[ 1 ];
695  value.vectorPtr->z = _value.vector[ 2 ];
696  break;
697 
698  case ev_function :
699  value.functionPtr = _value.function;
700  break;
701 
702  case ev_virtualfunction :
703  value.virtualFunction = _value._int;
704  break;
705 
706  case ev_object :
707  *value.entityNumberPtr = _value.entity;
708  break;
709 
710  default :
711  throw idCompileError( va( "weird type on '%s'", Name() ) );
712  break;
713  }
714 }
715 
716 /*
717 ============
718 idVarDef::SetString
719 ============
720 */
721 void idVarDef::SetString( const char *string, bool constant ) {
722  if ( constant ) {
724  } else {
726  }
727 
728  assert( typeDef && ( typeDef->Type() == ev_string ) );
729  idStr::Copynz( value.stringPtr, string, MAX_STRING_LEN );
730 }
731 
732 /*
733 ============
734 idVarDef::PrintInfo
735 ============
736 */
737 void idVarDef::PrintInfo( idFile *file, int instructionPointer ) const {
738  statement_t *jumpst;
739  int jumpto;
740  etype_t etype;
741  int i;
742  int len;
743  const char *ch;
744 
745  if ( initialized == initializedConstant ) {
746  file->Printf( "const " );
747  }
748 
749  etype = typeDef->Type();
750  switch( etype ) {
751  case ev_jumpoffset :
752  jumpto = instructionPointer + value.jumpOffset;
753  jumpst = &gameLocal.program.GetStatement( jumpto );
754  file->Printf( "address %d [%s(%d)]", jumpto, gameLocal.program.GetFilename( jumpst->file ), jumpst->linenumber );
755  break;
756 
757  case ev_function :
758  if ( value.functionPtr->eventdef ) {
759  file->Printf( "event %s", GlobalName() );
760  } else {
761  file->Printf( "function %s", GlobalName() );
762  }
763  break;
764 
765  case ev_field :
766  file->Printf( "field %d", value.ptrOffset );
767  break;
768 
769  case ev_argsize:
770  file->Printf( "args %d", value.argSize );
771  break;
772 
773  default:
774  file->Printf( "%s ", typeDef->Name() );
775  if ( initialized == initializedConstant ) {
776  switch( etype ) {
777  case ev_string :
778  file->Printf( "\"" );
779  len = strlen( value.stringPtr );
780  ch = value.stringPtr;
781  for( i = 0; i < len; i++, ch++ ) {
782  if ( idStr::CharIsPrintable( *ch ) ) {
783  file->Printf( "%c", *ch );
784  } else if ( *ch == '\n' ) {
785  file->Printf( "\\n" );
786  } else {
787  file->Printf( "\\x%.2x", static_cast<int>( *ch ) );
788  }
789  }
790  file->Printf( "\"" );
791  break;
792 
793  case ev_vector :
794  file->Printf( "'%s'", value.vectorPtr->ToString() );
795  break;
796 
797  case ev_float :
798  file->Printf( "%f", *value.floatPtr );
799  break;
800 
801  case ev_virtualfunction :
802  file->Printf( "vtable[ %d ]", value.virtualFunction );
803  break;
804 
805  default :
806  file->Printf( "%d", *value.intPtr );
807  break;
808  }
809  } else if ( initialized == stackVariable ) {
810  file->Printf( "stack[%d]", value.stackOffset );
811  } else {
812  file->Printf( "global[%d]", num );
813  }
814  break;
815  }
816 }
817 
818 /***********************************************************************
819 
820  idVarDef
821 
822 ***********************************************************************/
823 
824 /*
825 ============
826 idVarDefName::AddDef
827 ============
828 */
830  assert( def->next == NULL );
831  def->name = this;
832  def->next = defs;
833  defs = def;
834 }
835 
836 /*
837 ============
838 idVarDefName::RemoveDef
839 ============
840 */
842  if ( defs == def ) {
843  defs = def->next;
844  } else {
845  for ( idVarDef *d = defs; d->next != NULL; d = d->next ) {
846  if ( d->next == def ) {
847  d->next = def->next;
848  break;
849  }
850  }
851  }
852  def->next = NULL;
853  def->name = NULL;
854 }
855 
856 /***********************************************************************
857 
858  idScriptObject
859 
860 ***********************************************************************/
861 
862 /*
863 ============
864 idScriptObject::idScriptObject
865 ============
866 */
868  data = NULL;
869  type = &type_object;
870 }
871 
872 /*
873 ============
874 idScriptObject::~idScriptObject
875 ============
876 */
878  Free();
879 }
880 
881 /*
882 ============
883 idScriptObject::Free
884 ============
885 */
886 void idScriptObject::Free( void ) {
887  if ( data ) {
888  Mem_Free( data );
889  }
890 
891  data = NULL;
892  type = &type_object;
893 }
894 
895 /*
896 ================
897 idScriptObject::Save
898 ================
899 */
900 void idScriptObject::Save( idSaveGame *savefile ) const {
901  size_t size;
902 
903  if ( type == &type_object && data == NULL ) {
904  // Write empty string for uninitialized object
905  savefile->WriteString( "" );
906  } else {
907  savefile->WriteString( type->Name() );
908  size = type->Size();
909  savefile->WriteInt( size );
910  savefile->Write( data, size );
911  }
912 }
913 
914 /*
915 ================
916 idScriptObject::Restore
917 ================
918 */
920  idStr typeName;
921  size_t size;
922 
923  savefile->ReadString( typeName );
924 
925  // Empty string signals uninitialized object
926  if ( typeName.Length() == 0 ) {
927  return;
928  }
929 
930  if ( !SetType( typeName ) ) {
931  savefile->Error( "idScriptObject::Restore: failed to restore object of type '%s'.", typeName.c_str() );
932  }
933 
934  savefile->ReadInt( (int &)size );
935  if ( size != type->Size() ) {
936  savefile->Error( "idScriptObject::Restore: size of object '%s' doesn't match size in save game.", typeName.c_str() );
937  }
938 
939  savefile->Read( data, size );
940 }
941 
942 /*
943 ============
944 idScriptObject::SetType
945 
946 Allocates an object and initializes memory.
947 ============
948 */
949 bool idScriptObject::SetType( const char *typeName ) {
950  size_t size;
951  idTypeDef *newtype;
952 
953  // lookup the type
954  newtype = gameLocal.program.FindType( typeName );
955 
956  // only allocate memory if the object type changes
957  if ( newtype != type ) {
958  Free();
959  if ( !newtype ) {
960  gameLocal.Warning( "idScriptObject::SetType: Unknown type '%s'", typeName );
961  return false;
962  }
963 
964  if ( !newtype->Inherits( &type_object ) ) {
965  gameLocal.Warning( "idScriptObject::SetType: Can't create object of type '%s'. Must be an object type.", newtype->Name() );
966  return false;
967  }
968 
969  // set the type
970  type = newtype;
971 
972  // allocate the memory
973  size = type->Size();
974  data = ( byte * )Mem_Alloc( size );
975  }
976 
977  // init object memory
978  ClearObject();
979 
980  return true;
981 }
982 
983 /*
984 ============
985 idScriptObject::ClearObject
986 
987 Resets the memory for the script object without changing its type.
988 ============
989 */
991  size_t size;
992 
993  if ( type != &type_object ) {
994  // init object memory
995  size = type->Size();
996  memset( data, 0, size );
997  }
998 }
999 
1000 /*
1001 ============
1002 idScriptObject::HasObject
1003 ============
1004 */
1005 bool idScriptObject::HasObject( void ) const {
1006  return ( type != &type_object );
1007 }
1008 
1009 /*
1010 ============
1011 idScriptObject::GetTypeDef
1012 ============
1013 */
1015  return type;
1016 }
1017 
1018 /*
1019 ============
1020 idScriptObject::GetTypeName
1021 ============
1022 */
1023 const char *idScriptObject::GetTypeName( void ) const {
1024  return type->Name();
1025 }
1026 
1027 /*
1028 ============
1029 idScriptObject::GetConstructor
1030 ============
1031 */
1033  const function_t *func;
1034 
1035  func = GetFunction( "init" );
1036  return func;
1037 }
1038 
1039 /*
1040 ============
1041 idScriptObject::GetDestructor
1042 ============
1043 */
1045  const function_t *func;
1046 
1047  func = GetFunction( "destroy" );
1048  return func;
1049 }
1050 
1051 /*
1052 ============
1053 idScriptObject::GetFunction
1054 ============
1055 */
1056 const function_t *idScriptObject::GetFunction( const char *name ) const {
1057  const function_t *func;
1058 
1059  if ( type == &type_object ) {
1060  return NULL;
1061  }
1062 
1063  func = gameLocal.program.FindFunction( name, type );
1064  return func;
1065 }
1066 
1067 /*
1068 ============
1069 idScriptObject::GetVariable
1070 ============
1071 */
1072 byte *idScriptObject::GetVariable( const char *name, etype_t etype ) const {
1073  int i;
1074  int pos;
1075  const idTypeDef *t;
1076  const idTypeDef *parm;
1077 
1078  if ( type == &type_object ) {
1079  return NULL;
1080  }
1081 
1082  t = type;
1083  do {
1084  if ( t->SuperClass() != &type_object ) {
1085  pos = t->SuperClass()->Size();
1086  } else {
1087  pos = 0;
1088  }
1089  for( i = 0; i < t->NumParameters(); i++ ) {
1090  parm = t->GetParmType( i );
1091  if ( !strcmp( t->GetParmName( i ), name ) ) {
1092  if ( etype != parm->FieldType()->Type() ) {
1093  return NULL;
1094  }
1095  return &data[ pos ];
1096  }
1097 
1098  if ( parm->FieldType()->Inherits( &type_object ) ) {
1099  pos += type_object.Size();
1100  } else {
1101  pos += parm->FieldType()->Size();
1102  }
1103  }
1104  t = t->SuperClass();
1105  } while( t && ( t != &type_object ) );
1106 
1107  return NULL;
1108 }
1109 
1110 /***********************************************************************
1111 
1112  idProgram
1113 
1114 ***********************************************************************/
1115 
1116 /*
1117 ============
1118 idProgram::AllocType
1119 ============
1120 */
1122  idTypeDef *newtype;
1123 
1124  newtype = new idTypeDef( type );
1125  types.Append( newtype );
1126 
1127  return newtype;
1128 }
1129 
1130 /*
1131 ============
1132 idProgram::AllocType
1133 ============
1134 */
1135 idTypeDef *idProgram::AllocType( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ) {
1136  idTypeDef *newtype;
1137 
1138  newtype = new idTypeDef( etype, edef, ename, esize, aux );
1139  types.Append( newtype );
1140 
1141  return newtype;
1142 }
1143 
1144 /*
1145 ============
1146 idProgram::GetType
1147 
1148 Returns a preexisting complex type that matches the parm, or allocates
1149 a new one and copies it out.
1150 ============
1151 */
1153  int i;
1154 
1155  //FIXME: linear search == slow
1156  for( i = types.Num() - 1; i >= 0; i-- ) {
1157  if ( types[ i ]->MatchesType( type ) && !strcmp( types[ i ]->Name(), type.Name() ) ) {
1158  return types[ i ];
1159  }
1160  }
1161 
1162  if ( !allocate ) {
1163  return NULL;
1164  }
1165 
1166  // allocate a new one
1167  return AllocType( type );
1168 }
1169 
1170 /*
1171 ============
1172 idProgram::FindType
1173 
1174 Returns a preexisting complex type that matches the name, or returns NULL if not found
1175 ============
1176 */
1178  idTypeDef *check;
1179  int i;
1180 
1181  for( i = types.Num() - 1; i >= 0; i-- ) {
1182  check = types[ i ];
1183  if ( !strcmp( check->Name(), name ) ) {
1184  return check;
1185  }
1186  }
1187 
1188  return NULL;
1189 }
1190 
1191 /*
1192 ============
1193 idProgram::GetDefList
1194 ============
1195 */
1196 idVarDef *idProgram::GetDefList( const char *name ) const {
1197  int i, hash;
1198 
1199  hash = varDefNameHash.GenerateKey( name, true );
1200  for ( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) ) {
1201  if ( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 ) {
1202  return varDefNames[i]->GetDefs();
1203  }
1204  }
1205  return NULL;
1206 }
1207 
1208 /*
1209 ============
1210 idProgram::AddDefToNameList
1211 ============
1212 */
1213 void idProgram::AddDefToNameList( idVarDef *def, const char *name ) {
1214  int i, hash;
1215 
1216  hash = varDefNameHash.GenerateKey( name, true );
1217  for ( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) ) {
1218  if ( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 ) {
1219  break;
1220  }
1221  }
1222  if ( i == -1 ) {
1223  i = varDefNames.Append( new idVarDefName( name ) );
1224  varDefNameHash.Add( hash, i );
1225  }
1226  varDefNames[i]->AddDef( def );
1227 }
1228 
1229 /*
1230 ============
1231 idProgram::AllocDef
1232 ============
1233 */
1234 idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scope, bool constant ) {
1235  idVarDef *def;
1236  idStr element;
1237  idVarDef *def_x;
1238  idVarDef *def_y;
1239  idVarDef *def_z;
1240 
1241  // allocate a new def
1242  def = new idVarDef( type );
1243  def->scope = scope;
1244  def->numUsers = 1;
1245  def->num = varDefs.Append( def );
1246 
1247  // add the def to the list with defs with this name and set the name pointer
1248  AddDefToNameList( def, name );
1249 
1250  if ( ( type->Type() == ev_vector ) || ( ( type->Type() == ev_field ) && ( type->FieldType()->Type() == ev_vector ) ) ) {
1251  //
1252  // vector
1253  //
1254  if ( !strcmp( name, RESULT_STRING ) ) {
1255  // <RESULT> vector defs don't need the _x, _y and _z components
1256  assert( scope->Type() == ev_function );
1257  def->value.stackOffset = scope->value.functionPtr->locals;
1259  scope->value.functionPtr->locals += type->Size();
1260  } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
1261  idTypeDef newtype( ev_field, NULL, "float field", 0, &type_float );
1262  idTypeDef *type = GetType( newtype, true );
1263 
1264  // set the value to the variable's position in the object
1265  def->value.ptrOffset = scope->TypeDef()->Size();
1266 
1267  // make automatic defs for the vectors elements
1268  // origin can be accessed as origin_x, origin_y, and origin_z
1269  sprintf( element, "%s_x", def->Name() );
1270  def_x = AllocDef( type, element, scope, constant );
1271 
1272  sprintf( element, "%s_y", def->Name() );
1273  def_y = AllocDef( type, element, scope, constant );
1274  def_y->value.ptrOffset = def_x->value.ptrOffset + type_float.Size();
1275 
1276  sprintf( element, "%s_z", def->Name() );
1277  def_z = AllocDef( type, element, scope, constant );
1278  def_z->value.ptrOffset = def_y->value.ptrOffset + type_float.Size();
1279  } else {
1280  // make automatic defs for the vectors elements
1281  // origin can be accessed as origin_x, origin_y, and origin_z
1282  sprintf( element, "%s_x", def->Name() );
1283  def_x = AllocDef( &type_float, element, scope, constant );
1284 
1285  sprintf( element, "%s_y", def->Name() );
1286  def_y = AllocDef( &type_float, element, scope, constant );
1287 
1288  sprintf( element, "%s_z", def->Name() );
1289  def_z = AllocDef( &type_float, element, scope, constant );
1290 
1291  // point the vector def to the x coordinate
1292  def->value = def_x->value;
1293  def->initialized = def_x->initialized;
1294  }
1295  } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
1296  //
1297  // object variable
1298  //
1299  // set the value to the variable's position in the object
1300  def->value.ptrOffset = scope->TypeDef()->Size();
1301  } else if ( scope->Type() == ev_function ) {
1302  //
1303  // stack variable
1304  //
1305  // since we don't know how many local variables there are,
1306  // we have to have them go backwards on the stack
1307  def->value.stackOffset = scope->value.functionPtr->locals;
1309 
1310  if ( type->Inherits( &type_object ) ) {
1311  // objects only have their entity number on the stack, not the entire object
1312  scope->value.functionPtr->locals += type_object.Size();
1313  } else {
1314  scope->value.functionPtr->locals += type->Size();
1315  }
1316  } else {
1317  //
1318  // global variable
1319  //
1320  def->value.bytePtr = &variables[ numVariables ];
1321  numVariables += def->TypeDef()->Size();
1322  if ( numVariables > sizeof( variables ) ) {
1323  throw idCompileError( va( "Exceeded global memory size (%d bytes)", sizeof( variables ) ) );
1324  }
1325 
1326  memset( def->value.bytePtr, 0, def->TypeDef()->Size() );
1327  }
1328 
1329  return def;
1330 }
1331 
1332 /*
1333 ============
1334 idProgram::GetDef
1335 
1336 If type is NULL, it will match any type
1337 ============
1338 */
1339 idVarDef *idProgram::GetDef( const idTypeDef *type, const char *name, const idVarDef *scope ) const {
1340  idVarDef *def;
1341  idVarDef *bestDef;
1342  int bestDepth;
1343  int depth;
1344 
1345  bestDepth = 0;
1346  bestDef = NULL;
1347  for( def = GetDefList( name ); def != NULL; def = def->Next() ) {
1348  if ( def->scope->Type() == ev_namespace ) {
1349  depth = def->DepthOfScope( scope );
1350  if ( !depth ) {
1351  // not in the same namespace
1352  continue;
1353  }
1354  } else if ( def->scope != scope ) {
1355  // in a different function
1356  continue;
1357  } else {
1358  depth = 1;
1359  }
1360 
1361  if ( !bestDef || ( depth < bestDepth ) ) {
1362  bestDepth = depth;
1363  bestDef = def;
1364  }
1365  }
1366 
1367  // see if the name is already in use for another type
1368  if ( bestDef && type && ( bestDef->TypeDef() != type ) ) {
1369  throw idCompileError( va( "Type mismatch on redeclaration of %s", name ) );
1370  }
1371 
1372  return bestDef;
1373 }
1374 
1375 /*
1376 ============
1377 idProgram::FreeDef
1378 ============
1379 */
1380 void idProgram::FreeDef( idVarDef *def, const idVarDef *scope ) {
1381  idVarDef *e;
1382  int i;
1383 
1384  if ( def->Type() == ev_vector ) {
1385  idStr name;
1386 
1387  sprintf( name, "%s_x", def->Name() );
1388  e = GetDef( NULL, name, scope );
1389  if ( e ) {
1390  FreeDef( e, scope );
1391  }
1392 
1393  sprintf( name, "%s_y", def->Name() );
1394  e = GetDef( NULL, name, scope );
1395  if ( e ) {
1396  FreeDef( e, scope );
1397  }
1398 
1399  sprintf( name, "%s_z", def->Name() );
1400  e = GetDef( NULL, name, scope );
1401  if ( e ) {
1402  FreeDef( e, scope );
1403  }
1404  }
1405 
1406  varDefs.RemoveIndex( def->num );
1407  for( i = def->num; i < varDefs.Num(); i++ ) {
1408  varDefs[ i ]->num = i;
1409  }
1410 
1411  delete def;
1412 }
1413 
1414 /*
1415 ============
1416 idProgram::FindFreeResultDef
1417 ============
1418 */
1420  idVarDef *def;
1421 
1422  for( def = GetDefList( name ); def != NULL; def = def->Next() ) {
1423  if ( def == a || def == b ) {
1424  continue;
1425  }
1426  if ( def->TypeDef() != type ) {
1427  continue;
1428  }
1429  if ( def->scope != scope ) {
1430  continue;
1431  }
1432  if ( def->numUsers <= 1 ) {
1433  continue;
1434  }
1435  return def;
1436  }
1437 
1438  return AllocDef( type, name, scope, false );
1439 }
1440 
1441 /*
1442 ================
1443 idProgram::FindFunction
1444 
1445 Searches for the specified function in the currently loaded script. A full namespace should be
1446 specified if not in the global namespace.
1447 
1448 Returns 0 if function not found.
1449 Returns >0 if function found.
1450 ================
1451 */
1452 function_t *idProgram::FindFunction( const char *name ) const {
1453  int start;
1454  int pos;
1455  idVarDef *namespaceDef;
1456  idVarDef *def;
1457 
1458  assert( name );
1459 
1460  idStr fullname = name;
1461  start = 0;
1462  namespaceDef = &def_namespace;
1463  do {
1464  pos = fullname.Find( "::", true, start );
1465  if ( pos < 0 ) {
1466  break;
1467  }
1468 
1469  idStr namespaceName = fullname.Mid( start, pos - start );
1470  def = GetDef( NULL, namespaceName, namespaceDef );
1471  if ( !def ) {
1472  // couldn't find namespace
1473  return NULL;
1474  }
1475  namespaceDef = def;
1476 
1477  // skip past the ::
1478  start = pos + 2;
1479  } while( def->Type() == ev_namespace );
1480 
1481  idStr funcName = fullname.Right( fullname.Length() - start );
1482  def = GetDef( NULL, funcName, namespaceDef );
1483  if ( !def ) {
1484  // couldn't find function
1485  return NULL;
1486  }
1487 
1488  if ( ( def->Type() == ev_function ) && ( def->value.functionPtr->eventdef == NULL ) ) {
1489  return def->value.functionPtr;
1490  }
1491 
1492  // is not a function, or is an eventdef
1493  return NULL;
1494 }
1495 
1496 /*
1497 ================
1498 idProgram::FindFunction
1499 
1500 Searches for the specified object function in the currently loaded script.
1501 
1502 Returns 0 if function not found.
1503 Returns >0 if function found.
1504 ================
1505 */
1506 function_t *idProgram::FindFunction( const char *name, const idTypeDef *type ) const {
1507  const idVarDef *tdef;
1508  const idVarDef *def;
1509 
1510  // look for the function
1511  def = NULL;
1512  for( tdef = type->def; tdef != &def_object; tdef = tdef->TypeDef()->SuperClass()->def ) {
1513  def = GetDef( NULL, name, tdef );
1514  if ( def ) {
1515  return def->value.functionPtr;
1516  }
1517  }
1518 
1519  return NULL;
1520 }
1521 
1522 /*
1523 ================
1524 idProgram::AllocFunction
1525 ================
1526 */
1528  if ( functions.Num() >= functions.Max() ) {
1529  throw idCompileError( va( "Exceeded maximum allowed number of functions (%d)", functions.Max() ) );
1530  }
1531 
1532  // fill in the dfunction
1533  function_t &func = *functions.Alloc();
1534  func.eventdef = NULL;
1535  func.def = def;
1536  func.type = def->TypeDef();
1537  func.firstStatement = 0;
1538  func.numStatements = 0;
1539  func.parmTotal = 0;
1540  func.locals = 0;
1541  func.filenum = filenum;
1542  func.parmSize.SetGranularity( 1 );
1543  func.SetName( def->GlobalName() );
1544 
1545  def->SetFunction( &func );
1546 
1547  return func;
1548 }
1549 
1550 /*
1551 ================
1552 idProgram::SetEntity
1553 ================
1554 */
1555 void idProgram::SetEntity( const char *name, idEntity *ent ) {
1556  idVarDef *def;
1557  idStr defName( "$" );
1558 
1559  defName += name;
1560 
1561  def = GetDef( &type_entity, defName, &def_namespace );
1562  if ( def && ( def->initialized != idVarDef::stackVariable ) ) {
1563  // 0 is reserved for NULL entity
1564  if ( !ent ) {
1565  *def->value.entityNumberPtr = 0;
1566  } else {
1567  *def->value.entityNumberPtr = ent->entityNumber + 1;
1568  }
1569  }
1570 }
1571 
1572 /*
1573 ================
1574 idProgram::AllocStatement
1575 ================
1576 */
1578  if ( statements.Num() >= statements.Max() ) {
1579  throw idCompileError( va( "Exceeded maximum allowed number of statements (%d)", statements.Max() ) );
1580  }
1581  return statements.Alloc();
1582 }
1583 
1584 /*
1585 ==============
1586 idProgram::BeginCompilation
1587 
1588 called before compiling a batch of files, clears the pr struct
1589 ==============
1590 */
1592  statement_t *statement;
1593 
1594  FreeData();
1595 
1596  try {
1597  // make the first statement a return for a "NULL" function
1598  statement = AllocStatement();
1599  statement->linenumber = 0;
1600  statement->file = 0;
1601  statement->op = OP_RETURN;
1602  statement->a = NULL;
1603  statement->b = NULL;
1604  statement->c = NULL;
1605 
1606  // define NULL
1607  //AllocDef( &type_void, "<NULL>", &def_namespace, true );
1608 
1609  // define the return def
1610  returnDef = AllocDef( &type_vector, "<RETURN>", &def_namespace, false );
1611 
1612  // define the return def for strings
1613  returnStringDef = AllocDef( &type_string, "<RETURN>", &def_namespace, false );
1614 
1615  // define the sys object
1616  sysDef = AllocDef( &type_void, "sys", &def_namespace, true );
1617  }
1618 
1619  catch( idCompileError &err ) {
1620  gameLocal.Error( "%s", err.error );
1621  }
1622 }
1623 
1624 /*
1625 ==============
1626 idProgram::DisassembleStatement
1627 ==============
1628 */
1629 void idProgram::DisassembleStatement( idFile *file, int instructionPointer ) const {
1630  opcode_t *op;
1631  const statement_t *statement;
1632 
1633  statement = &statements[ instructionPointer ];
1634  op = &idCompiler::opcodes[ statement->op ];
1635  file->Printf( "%20s(%d):\t%6d: %15s\t", fileList[ statement->file ].c_str(), statement->linenumber, instructionPointer, op->opname );
1636 
1637  if ( statement->a ) {
1638  file->Printf( "\ta: " );
1639  statement->a->PrintInfo( file, instructionPointer );
1640  }
1641 
1642  if ( statement->b ) {
1643  file->Printf( "\tb: " );
1644  statement->b->PrintInfo( file, instructionPointer );
1645  }
1646 
1647  if ( statement->c ) {
1648  file->Printf( "\tc: " );
1649  statement->c->PrintInfo( file, instructionPointer );
1650  }
1651 
1652  file->Printf( "\n" );
1653 }
1654 
1655 /*
1656 ==============
1657 idProgram::Disassemble
1658 ==============
1659 */
1660 void idProgram::Disassemble( void ) const {
1661  int i;
1662  int instructionPointer;
1663  const function_t *func;
1664  idFile *file;
1665 
1666  file = fileSystem->OpenFileByMode( "script/disasm.txt", FS_WRITE );
1667 
1668  for( i = 0; i < functions.Num(); i++ ) {
1669  func = &functions[ i ];
1670  if ( func->eventdef ) {
1671  // skip eventdefs
1672  continue;
1673  }
1674 
1675  file->Printf( "\nfunction %s() %d stack used, %d parms, %d locals {\n", func->Name(), func->locals, func->parmTotal, func->locals - func->parmTotal );
1676 
1677  for( instructionPointer = 0; instructionPointer < func->numStatements; instructionPointer++ ) {
1678  DisassembleStatement( file, func->firstStatement + instructionPointer );
1679  }
1680 
1681  file->Printf( "}\n" );
1682  }
1683 
1684  fileSystem->CloseFile( file );
1685 }
1686 
1687 /*
1688 ==============
1689 idProgram::FinishCompilation
1690 
1691 Called after all files are compiled to check for errors
1692 ==============
1693 */
1695  int i;
1696 
1698  top_statements = statements.Num();
1699  top_types = types.Num();
1700  top_defs = varDefs.Num();
1701  top_files = fileList.Num();
1702 
1705 
1706  for( i = 0; i < numVariables; i++ ) {
1707  variableDefaults[ i ] = variables[ i ];
1708  }
1709 }
1710 
1711 /*
1712 ==============
1713 idProgram::CompileStats
1714 
1715 called after all files are compiled to report memory usage.
1716 ==============
1717 */
1719  int memused;
1720  int memallocated;
1721  int numdefs;
1722  int stringspace;
1723  int funcMem;
1724  int i;
1725 
1726  gameLocal.Printf( "---------- Compile stats ----------\n" );
1727  gameLocal.DPrintf( "Files loaded:\n" );
1728 
1729  stringspace = 0;
1730  for( i = 0; i < fileList.Num(); i++ ) {
1731  gameLocal.DPrintf( " %s\n", fileList[ i ].c_str() );
1732  stringspace += fileList[ i ].Allocated();
1733  }
1734  stringspace += fileList.Size();
1735 
1736  numdefs = varDefs.Num();
1737  memused = varDefs.Num() * sizeof( idVarDef );
1738  memused += types.Num() * sizeof( idTypeDef );
1739  memused += stringspace;
1740 
1741  for( i = 0; i < types.Num(); i++ ) {
1742  memused += types[ i ]->Allocated();
1743  }
1744 
1745  funcMem = functions.MemoryUsed();
1746  for( i = 0; i < functions.Num(); i++ ) {
1747  funcMem += functions[ i ].Allocated();
1748  }
1749 
1750  memallocated = funcMem + memused + sizeof( idProgram );
1751 
1752  memused += statements.MemoryUsed();
1753  memused += functions.MemoryUsed(); // name and filename of functions are shared, so no need to include them
1754  memused += sizeof( variables );
1755 
1756  gameLocal.Printf( "\nMemory usage:\n" );
1757  gameLocal.Printf( " Strings: %d, %d bytes\n", fileList.Num(), stringspace );
1758  gameLocal.Printf( " Statements: %d, %d bytes\n", statements.Num(), statements.MemoryUsed() );
1759  gameLocal.Printf( " Functions: %d, %d bytes\n", functions.Num(), funcMem );
1760  gameLocal.Printf( " Variables: %d bytes\n", numVariables );
1761  gameLocal.Printf( " Mem used: %d bytes\n", memused );
1762  gameLocal.Printf( " Static data: %d bytes\n", sizeof( idProgram ) );
1763  gameLocal.Printf( " Allocated: %d bytes\n", memallocated );
1764  gameLocal.Printf( " Thread size: %d bytes\n\n", sizeof( idThread ) );
1765 }
1766 
1767 /*
1768 ================
1769 idProgram::CompileText
1770 ================
1771 */
1772 bool idProgram::CompileText( const char *source, const char *text, bool console ) {
1773  idCompiler compiler;
1774  int i;
1775  idVarDef *def;
1776  idStr ospath;
1777 
1778  // use a full os path for GetFilenum since it calls OSPathToRelativePath to convert filenames from the parser
1779  ospath = fileSystem->RelativePathToOSPath( source );
1780  filenum = GetFilenum( ospath );
1781 
1782  try {
1783  compiler.CompileFile( text, filename, console );
1784 
1785  // check to make sure all functions prototyped have code
1786  for( i = 0; i < varDefs.Num(); i++ ) {
1787  def = varDefs[ i ];
1788  if ( ( def->Type() == ev_function ) && ( ( def->scope->Type() == ev_namespace ) || def->scope->TypeDef()->Inherits( &type_object ) ) ) {
1789  if ( !def->value.functionPtr->eventdef && !def->value.functionPtr->firstStatement ) {
1790  throw idCompileError( va( "function %s was not defined\n", def->GlobalName() ) );
1791  }
1792  }
1793  }
1794  }
1795 
1796  catch( idCompileError &err ) {
1797  if ( console ) {
1798  gameLocal.Printf( "%s\n", err.error );
1799  return false;
1800  } else {
1801  gameLocal.Error( "%s\n", err.error );
1802  }
1803  };
1804 
1805  if ( !console ) {
1806  CompileStats();
1807  }
1808 
1809  return true;
1810 }
1811 
1812 /*
1813 ================
1814 idProgram::CompileFunction
1815 ================
1816 */
1817 const function_t *idProgram::CompileFunction( const char *functionName, const char *text ) {
1818  bool result;
1819 
1820  result = CompileText( functionName, text, false );
1821 
1822  if ( g_disasm.GetBool() ) {
1823  Disassemble();
1824  }
1825 
1826  if ( !result ) {
1827  gameLocal.Error( "Compile failed." );
1828  }
1829 
1830  return FindFunction( functionName );
1831 }
1832 
1833 /*
1834 ================
1835 idProgram::CompileFile
1836 ================
1837 */
1838 void idProgram::CompileFile( const char *filename ) {
1839  char *src;
1840  bool result;
1841 
1842  if ( fileSystem->ReadFile( filename, ( void ** )&src, NULL ) < 0 ) {
1843  gameLocal.Error( "Couldn't load %s\n", filename );
1844  }
1845 
1846  result = CompileText( filename, src, false );
1847 
1848  fileSystem->FreeFile( src );
1849 
1850  if ( g_disasm.GetBool() ) {
1851  Disassemble();
1852  }
1853 
1854  if ( !result ) {
1855  gameLocal.Error( "Compile failed in file %s.", filename );
1856  }
1857 }
1858 
1859 /*
1860 ================
1861 idProgram::FreeData
1862 ================
1863 */
1864 void idProgram::FreeData( void ) {
1865  int i;
1866 
1867  // free the defs
1868  varDefs.DeleteContents( true );
1869  varDefNames.DeleteContents( true );
1870  varDefNameHash.Free();
1871 
1872  returnDef = NULL;
1874  sysDef = NULL;
1875 
1876  // free any special types we've created
1877  types.DeleteContents( true );
1878 
1879  filenum = 0;
1880 
1881  numVariables = 0;
1882  memset( variables, 0, sizeof( variables ) );
1883 
1884  // clear all the strings in the functions so that it doesn't look like we're leaking memory.
1885  for( i = 0; i < functions.Num(); i++ ) {
1886  functions[ i ].Clear();
1887  }
1888 
1889  filename.Clear();
1890  fileList.Clear();
1891  statements.Clear();
1892  functions.Clear();
1893 
1894  top_functions = 0;
1895  top_statements = 0;
1896  top_types = 0;
1897  top_defs = 0;
1898  top_files = 0;
1899 
1900  filename = "";
1901 }
1902 
1903 /*
1904 ================
1905 idProgram::Startup
1906 ================
1907 */
1908 void idProgram::Startup( const char *defaultScript ) {
1909  gameLocal.Printf( "Initializing scripts\n" );
1910 
1911  // make sure all data is freed up
1913 
1914  // get ready for loading scripts
1915  BeginCompilation();
1916 
1917  // load the default script
1918  if ( defaultScript && *defaultScript ) {
1919  CompileFile( defaultScript );
1920  }
1921 
1923 }
1924 
1925 /*
1926 ================
1927 idProgram::Save
1928 ================
1929 */
1930 void idProgram::Save( idSaveGame *savefile ) const {
1931  int i;
1932  int currentFileNum = top_files;
1933 
1934  savefile->WriteInt( (fileList.Num() - currentFileNum) );
1935  while ( currentFileNum < fileList.Num() ) {
1936  savefile->WriteString( fileList[ currentFileNum ] );
1937  currentFileNum++;
1938  }
1939 
1940  for ( i = 0; i < variableDefaults.Num(); i++ ) {
1941  if ( variables[i] != variableDefaults[i] ) {
1942  savefile->WriteInt( i );
1943  savefile->WriteByte( variables[i] );
1944  }
1945  }
1946  // Mark the end of the diff with default variables with -1
1947  savefile->WriteInt( -1 );
1948 
1949  savefile->WriteInt( numVariables );
1950  for ( i = variableDefaults.Num(); i < numVariables; i++ ) {
1951  savefile->WriteByte( variables[i] );
1952  }
1953 
1954  int checksum = CalculateChecksum();
1955  savefile->WriteInt( checksum );
1956 }
1957 
1958 /*
1959 ================
1960 idProgram::Restore
1961 ================
1962 */
1964  int i, num, index;
1965  bool result = true;
1966  idStr scriptname;
1967 
1968  savefile->ReadInt( num );
1969  for ( i = 0; i < num; i++ ) {
1970  savefile->ReadString( scriptname );
1971  CompileFile( scriptname );
1972  }
1973 
1974  savefile->ReadInt( index );
1975  while( index >= 0 ) {
1976  savefile->ReadByte( variables[index] );
1977  savefile->ReadInt( index );
1978  }
1979 
1980  savefile->ReadInt( num );
1981  for ( i = variableDefaults.Num(); i < num; i++ ) {
1982  savefile->ReadByte( variables[i] );
1983  }
1984 
1985  int saved_checksum, checksum;
1986 
1987  savefile->ReadInt( saved_checksum );
1988  checksum = CalculateChecksum();
1989 
1990  if ( saved_checksum != checksum ) {
1991  result = false;
1992  }
1993 
1994  return result;
1995 }
1996 
1997 /*
1998 ================
1999 idProgram::CalculateChecksum
2000 ================
2001 */
2002 int idProgram::CalculateChecksum( void ) const {
2003  int i, result;
2004 
2005  typedef struct {
2006  unsigned short op;
2007  int a;
2008  int b;
2009  int c;
2010  unsigned short linenumber;
2011  unsigned short file;
2012  } statementBlock_t;
2013 
2014  statementBlock_t *statementList = new statementBlock_t[ statements.Num() ];
2015 
2016  memset( statementList, 0, ( sizeof(statementBlock_t) * statements.Num() ) );
2017 
2018  // Copy info into new list, using the variable numbers instead of a pointer to the variable
2019  for( i = 0; i < statements.Num(); i++ ) {
2020  statementList[i].op = statements[i].op;
2021 
2022  if ( statements[i].a ) {
2023  statementList[i].a = statements[i].a->num;
2024  } else {
2025  statementList[i].a = -1;
2026  }
2027  if ( statements[i].b ) {
2028  statementList[i].b = statements[i].b->num;
2029  } else {
2030  statementList[i].b = -1;
2031  }
2032  if ( statements[i].c ) {
2033  statementList[i].c = statements[i].c->num;
2034  } else {
2035  statementList[i].c = -1;
2036  }
2037 
2038  statementList[i].linenumber = statements[i].linenumber;
2039  statementList[i].file = statements[i].file;
2040  }
2041 
2042  result = MD4_BlockChecksum( statementList, ( sizeof(statementBlock_t) * statements.Num() ) );
2043 
2044  delete [] statementList;
2045 
2046  return result;
2047 }
2048 
2049 /*
2050 ==============
2051 idProgram::Restart
2052 
2053 Restores all variables to their initial value
2054 ==============
2055 */
2056 void idProgram::Restart( void ) {
2057  int i;
2058 
2060 
2061  //
2062  // since there may have been a script loaded by the map or the user may
2063  // have typed "script" from the console, free up any types and vardefs that
2064  // have been allocated after the initial startup
2065  //
2066  for( i = top_types; i < types.Num(); i++ ) {
2067  delete types[ i ];
2068  }
2069  types.SetNum( top_types, false );
2070 
2071  for( i = top_defs; i < varDefs.Num(); i++ ) {
2072  delete varDefs[ i ];
2073  }
2074  varDefs.SetNum( top_defs, false );
2075 
2076  for( i = top_functions; i < functions.Num(); i++ ) {
2077  functions[ i ].Clear();
2078  }
2080 
2081  statements.SetNum( top_statements );
2082  fileList.SetNum( top_files, false );
2083  filename.Clear();
2084 
2085  // reset the variables to their default values
2087  for( i = 0; i < numVariables; i++ ) {
2088  variables[ i ] = variableDefaults[ i ];
2089  }
2090 }
2091 
2092 /*
2093 ================
2094 idProgram::GetFilenum
2095 ================
2096 */
2097 int idProgram::GetFilenum( const char *name ) {
2098  if ( filename == name ) {
2099  return filenum;
2100  }
2101 
2102  idStr strippedName;
2103  strippedName = fileSystem->OSPathToRelativePath( name );
2104  if ( !strippedName.Length() ) {
2105  // not off the base path so just use the full path
2106  filenum = fileList.AddUnique( name );
2107  } else {
2108  filenum = fileList.AddUnique( strippedName );
2109  }
2110 
2111  // save the unstripped name so that we don't have to strip the incoming name every time we call GetFilenum
2112  filename = name;
2113 
2114  return filenum;
2115 }
2116 
2117 /*
2118 ================
2119 idProgram::idProgram
2120 ================
2121 */
2123  FreeData();
2124 }
2125 
2126 /*
2127 ================
2128 idProgram::~idProgram
2129 ================
2130 */
2132  FreeData();
2133 }
2134 
2135 /*
2136 ================
2137 idProgram::ReturnEntity
2138 ================
2139 */
2141  if ( ent ) {
2143  } else {
2145  }
2146 }
idList< int > parmSize
void SetName(const char *newname)
idStr filename
#define strcmp
Definition: Str.h:41
int * entityNumberPtr
GLsizei const GLfloat * value
Definition: glext.h:3614
byte * GetVariable(const char *name, etype_t etype) const
bool CompileText(const char *source, const char *text, bool console)
idVarDef * GetDefList(const char *name) const
void WriteString(const char *string)
Definition: SaveGame.cpp:231
idVarDef def_entity
idCVar g_disasm("g_disasm","0", CVAR_GAME|CVAR_BOOL,"disassemble script into base/script/disasm.txt on the local drive when script is compiled")
idVarDef def_object
assert(prefInfo.fullscreenBtn)
idVarDef def_string & type_string
idVarDef def_vector
int Cmp(const char *text) const
Definition: Str.h:652
etype_t Type(void) const
static opcode_t opcodes[]
idTypeDef * auxType
size_t Allocated(void) const
int Next(const int index) const
Definition: HashIndex.h:247
idTypeDef * GetTypeDef(void) const
int DepthOfScope(const idVarDef *otherScope) const
etype_t Type(void) const
void Printf(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:699
statement_t * AllocStatement(void)
idVarDef * sysDef
const char * stringPtr
bool SetType(const char *typeName)
etype_t
void Save(idSaveGame *savefile) const
const char * GetTypeName(void) const
statement_t & GetStatement(int index)
idVarDef * GetDef(const idTypeDef *type, const char *name, const idVarDef *scope) const
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
idList< idVarDefName * > varDefNames
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
void operator=(const idTypeDef &other)
int Length(void) const
Definition: Str.h:702
void void void void void Error(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:783
void Disassemble(void) const
function_t * functionPtr
idTypeDef(const idTypeDef &other)
bool HasObject(void) const
void FreeData(void)
void Write(const void *buffer, int len)
Definition: SaveGame.cpp:159
varEval_t value
const idEventDef * eventdef
idVarDef def_object & type_object
type * Alloc(void)
Definition: StaticList.h:291
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
void SetGranularity(int newgranularity)
Definition: List.h:305
int Max(void) const
Definition: StaticList.h:171
idVarDef def_field & type_field
int GetFilenum(const char *name)
Definition: Vector.h:316
void SetPointerType(idTypeDef *type)
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glext.h:2878
#define MAX_STRING_LEN
idVarDef def_namespace & type_namespace
void PrintInfo(idFile *file, int instructionPointer) const
void CompileFile(const char *filename)
void Clear(void)
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
void AddDef(idVarDef *def)
idStrList fileList
GLuint src
Definition: glext.h:5390
idVarDef def_scriptevent & type_scriptevent
GLenum GLsizei len
Definition: glext.h:3472
int NumParameters(void) const
idVarDef * a
int i
Definition: process.py:33
virtual void FreeFile(void *buffer)=0
const char * Name(void) const
GLuint GLuint num
Definition: glext.h:5390
Boolean result
const char * Name(void) const
void RemoveDef(idVarDef *def)
void Free(void)
Definition: HashIndex.cpp:75
void FinishCompilation(void)
int First(const int key) const
Definition: HashIndex.h:238
idVarDef def_void & type_void
idProgram program
Definition: Game_local.h:293
void ClearObject(void)
idConsole * console
Definition: Console.cpp:122
unsigned short op
const char * GlobalName(void) const
void FreeDef(idVarDef *d, const idVarDef *scope)
size_t Allocated(void) const
const function_t * GetFunction(int funcNumber) const
idStaticList< function_t, MAX_FUNCS > functions
idVarDef def_field
idVarDef def_vector & type_vector
idList< idVarDef * > varDefs
void void void Warning(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:735
float vector[3]
Definition: File.h:50
GLsizei GLsizei GLcharARB * source
Definition: glext.h:3633
idHashIndex varDefNameHash
void SetString(const char *string, bool constant)
const char * GetFilename(int num)
byte * bytePtr
int Size(void) const
const char * GetParmName(int parmNumber) const
idTypeDef * TypeDef(void) const
const idTypeDef * type
void SetReturnType(idTypeDef *type)
idVarDef def_scriptevent
GLuint index
Definition: glext.h:3476
const GLubyte * c
Definition: glext.h:4677
type & Alloc(void)
Definition: List.h:624
idVarDef def_virtualfunction
idVarDef * defs
void void Read(void *buffer, int len)
Definition: SaveGame.cpp:913
void SetNum(int newnum)
Definition: StaticList.h:213
int GetFunctionNumber(const function_t *func) const
const function_t * CompileFunction(const char *functionName, const char *text)
idVarDef def_float & type_float
const char * Name(void) const
idVarDef def_boolean & type_boolean
bool MatchesType(const idTypeDef &matchtype) const
idVarDef * AllocDef(idTypeDef *type, const char *name, idVarDef *scope, bool constant)
idTypeDef * ReturnType(void) const
#define NULL
Definition: Lib.h:88
void Clear(void)
Definition: StaticList.h:119
void void DPrintf(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:715
void AddFunction(const function_t *func)
virtual idFile * OpenFileByMode(const char *relativePath, fsMode_t mode)=0
idList< idTypeDef * > parmTypes
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
int top_statements
size_t MemoryUsed(void) const
Definition: StaticList.h:201
idVarDef * def
size_t Size(void) const
Definition: List.h:242
void SetEntity(const char *name, idEntity *ent)
static void Copynz(char *dest, const char *src, int destsize)
Definition: Str.cpp:1376
initialized_t initialized
idVarDef def_entity & type_entity
int NumFunctions(void) const
size_t Allocated(void) const
Definition: List.h:230
etype_t type
void CompileStats(void)
bool MatchesVirtualFunction(const idTypeDef &matchfunc) const
void DeleteContents(bool clear)
Definition: List.h:207
const char * opname
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
unsigned long MD4_BlockChecksum(const void *data, int length)
Definition: MD4.cpp:247
void AddField(idTypeDef *fieldtype, const char *name)
void Clear(void)
Definition: Str.h:724
const char * Right(int len, idStr &result) const
Definition: Str.h:896
void AddDefToNameList(idVarDef *def, const char *name)
idVarDef def_virtualfunction & type_virtualfunction
int Find(const char c, int start=0, int end=-1) const
Definition: Str.h:874
const function_t * GetConstructor(void) const
idTypeDef * GetParmType(int parmNumber) const
idGameLocal gameLocal
Definition: Game_local.cpp:64
idVarDef def_string
int firstStatement
idVarDef * c
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
void Error(const char *fmt,...) id_attribute((format(printf
Definition: SaveGame.cpp:878
idTypeDef * SuperClass(void) const
idVarDef def_pointer & type_pointer
byte variables[MAX_GLOBALS]
void ReturnEntity(idEntity *ent)
void SetFieldType(idTypeDef *type)
void Restart(void)
idVarDef def_boolean
bool Inherits(const idTypeDef *basetype) const
void WriteInt(const int value)
Definition: SaveGame.cpp:168
idStaticList< statement_t, MAX_STATEMENTS > statements
virtual const char * RelativePathToOSPath(const char *relativePath, const char *basePath="fs_devpath")=0
int GenerateKey(const char *string, bool caseSensitive=true) const
Definition: HashIndex.h:379
idTypeDef * AllocType(idTypeDef &type)
idTypeDef * GetType(idTypeDef &type, bool allocate)
GLubyte GLubyte b
Definition: glext.h:4662
void CompileFile(const char *text, const char *filename, bool console)
void SetName(const char *name)
idVarDef * FindFreeResultDef(idTypeDef *type, const char *name, idVarDef *scope, const idVarDef *a, const idVarDef *b)
idVarDef def_pointer
idList< const function_t * > functions
int Append(const type &obj)
Definition: List.h:646
idVarDef def_jumpoffset
idVarDef * def
const char * Mid(int start, int len, idStr &result) const
Definition: Str.cpp:603
static WindowRef ValidModeCallbackProc inCallback OSStatus err
idVarDef def_function & type_function
unsigned short linenumber
idTypeDef * FindType(const char *name)
void SetValue(const eval_t &value, bool constant)
int AddUnique(const type &obj)
Definition: List.h:742
bool GetBool(void) const
Definition: CVarSystem.h:142
idVarDef * next
static void Restart(void)
float _float
int Num(void) const
Definition: List.h:265
char error[MAX_STRING_CHARS]
Definition: Lib.h:152
bool RemoveIndex(int index)
Definition: List.h:849
void DisassembleStatement(idFile *file, int instructionPointer) const
unsigned char byte
Definition: Lib.h:75
idVarDef * b
idVarDef * returnDef
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
const function_t * GetFunction(const char *name) const
idVarDef def_argsize
const function_t * GetDestructor(void) const
void AddFunctionParm(idTypeDef *parmtype, const char *name)
Definition: Str.h:116
unsigned short file
idVarDef * Next(void) const
void WriteByte(const byte value)
Definition: SaveGame.cpp:195
idVarDef def_argsize & type_argsize
const char * c_str(void) const
Definition: Str.h:487
idVarDef def_function
idVarDef * returnStringDef
void Startup(const char *defaultScript)
idVarDef def_jumpoffset & type_jumpoffset
idTypeDef * typeDef
idList< idTypeDef * > types
function_t * FindFunction(const char *name) const
idTypeDef * PointerType(void) const
void Add(const int key, const int index)
Definition: HashIndex.h:193
size_t Allocated(void) const
Definition: StaticList.h:181
idVarDefName * name
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
int CalculateChecksum(void) const
char * va(const char *fmt,...)
Definition: Str.cpp:1568
function_t & AllocFunction(idVarDef *def)
virtual void CloseFile(idFile *f)=0
const char *const RESULT_STRING
virtual const char * OSPathToRelativePath(const char *OSPath)=0
idVarDef * scope
int entityNumber
Definition: Entity.h:111
idTypeDef * type
idVarDef(idTypeDef *typeptr=NULL)
void BeginCompilation(void)
idVarDef def_void
int Num(void) const
Definition: StaticList.h:159
idStrList parmNames
void Restore(idRestoreGame *savefile)
void Save(idSaveGame *savefile) const
idVarDef def_namespace
bool Restore(idRestoreGame *savefile)
void ReadString(idStr &string)
Definition: SaveGame.cpp:985
function_t * function
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
void SetFunction(function_t *func)
void ReadInt(int &value)
Definition: SaveGame.cpp:922
idVarDef def_float
int entity
virtual int Printf(const char *fmt,...) id_attribute((format(printf
Definition: File.cpp:260
idStaticList< byte, MAX_GLOBALS > variableDefaults
GLuint start
Definition: glext.h:2845
int num
Definition: List.h:135
void ReadByte(byte &value)
Definition: SaveGame.cpp:949
void SetObject(idScriptObject *object)
idTypeDef * FieldType(void) const
GLdouble GLdouble t
Definition: glext.h:2943
void Clear(void)
Definition: List.h:184
static bool CharIsPrintable(int c)
Definition: Str.h:1003