Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
script_variables.cpp
Go to the documentation of this file.
1 /*
2  * Vega Strike
3  * Copyright (C) 2001-2002 Daniel Horn
4  *
5  * http://vegastrike.sourceforge.net/
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 /*
23  * xml Mission Scripting written by Alexander Rawass <alexannika@users.sourceforge.net>
24  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <ctype.h>
31 #include <assert.h>
32 #ifndef WIN32
33 //this file isn't available on my system (all win32 machines?) i dun even know what it has or if we need it as I can compile without it
34 #include <unistd.h>
35 #endif
36 
37 #include <expat.h>
38 #include "xml_support.h"
39 
40 #include "vegastrike.h"
41 
42 #include "cmd/unit_generic.h"
43 #include "mission.h"
44 #include "easydom.h"
45 
46 #include "vs_globals.h"
47 #include "config_xml.h"
48 
49 using std::cout;
50 using std::cerr;
51 using std::endl;
52 
53 /* *********************************************************** */
54 
55 bool Mission::checkVarType( varInst *var, enum var_type check_type )
56 {
57  if (var->type == check_type)
58  return true;
59  return false;
60 }
61 
62 /* *********************************************************** */
63 
64 bool Mission::doBooleanVar( missionNode *node, int mode )
65 {
66  varInst *var = doVariable( node, mode );
67 
68  bool ok = checkVarType( var, VAR_BOOL );
69  if (!ok) {
70  fatalError( node, mode, "expected a bool variable - got a different type" );
71  assert( 0 );
72  }
73  deleteVarInst( var );
74 
75  return var->bool_val;
76 }
77 /* *********************************************************** */
78 
79 double Mission::doFloatVar( missionNode *node, int mode )
80 {
81  varInst *var = doVariable( node, mode );
82 
83  bool ok = checkVarType( var, VAR_FLOAT );
84  if (!ok) {
85  fatalError( node, mode, "expected a float variable - got a different type" );
86  assert( 0 );
87  }
88  deleteVarInst( var );
89  return var->float_val;
90 }
91 
92 /* *********************************************************** */
93 
94 int Mission::doIntVar( missionNode *node, int mode )
95 {
96  varInst *var = doVariable( node, mode );
97 
98  bool ok = checkVarType( var, VAR_INT );
99  if (!ok) {
100  fatalError( node, mode, "expected a int variable - got a different type" );
101  assert( 0 );
102  }
103  deleteVarInst( var );
104  return var->int_val;
105 }
106 
107 /* *********************************************************** */
108 
109 varInst* Mission::doObjectVar( missionNode *node, int mode )
110 {
111  varInst *var = doVariable( node, mode );
112 
113  bool ok = checkVarType( var, VAR_OBJECT );
114 
115  debug( 3, node, mode, "doObjectVar got variable :" );
116  printVarInst( 3, var );
117  if (!ok) {
118  fatalError( node, mode, "expected a object variable - got a different type" );
119  assert( 0 );
120  }
121  return var;
122 }
123 
124 /* *********************************************************** */
125 
126 varInst* Mission::lookupLocalVariable( missionNode *asknode )
127 {
128  contextStack *cstack = runtime.cur_thread->exec_stack.back();
129  varInst *defnode = NULL;
130  //slow search/name lookup
131  for (unsigned int i = 0; i < cstack->contexts.size() && defnode == NULL; i++) {
132  scriptContext *context = cstack->contexts[i];
133  varInstMap *map = context->varinsts;
134  defnode = (*map)[asknode->script.name];
135  if (defnode != NULL)
136  debug( 5, defnode->defvar_node, SCRIPT_RUN, "FOUND local variable defined in that node" );
137  }
138 #if 0
139  //fast index lookup
140  varInst *defnode2 = NULL;
141  if (asknode->script.context_id == -1 || asknode->script.varId == -1)
142  printf( "ERROR: no local variable with fast lookup\n" );
143  scriptContext *context = cstack->contexts[asknode->script.context_id];
144  varInstMap *map2 = context->varinsts;
145  defnode2 = map2->varVec[asknode->script.varId];
146  if (defnode2 != defnode)
147  printf( "ERROR: wrong local variable lookup\n" );
148 #endif
149  if (defnode == NULL)
150  return NULL;
151  return defnode;
152 }
153 
154 /* *********************************************************** */
155 
156 varInst* Mission::lookupModuleVariable( string mname, missionNode *asknode )
157 {
158  //only when runtime
159  missionNode *module_node = runtime.modules[mname];
160  if (module_node == NULL) {
161  fatalError( asknode, SCRIPT_RUN, "no such module named "+mname );
162  assert( 0 );
163  return NULL;
164  }
165  vector< easyDomNode* >::const_iterator siter;
166  for (siter = module_node->subnodes.begin(); siter != module_node->subnodes.end(); siter++) {
167  missionNode *varnode = (missionNode*) *siter;
168  if (varnode->script.name == asknode->script.name) {
169  char buffer[200];
170  sprintf( buffer, "FOUND module variable %s in that node", varnode->script.name.c_str() );
171  debug( 4, varnode, SCRIPT_RUN, buffer );
172  printVarInst( varnode->script.varinst );
173 
174  return varnode->script.varinst;
175  }
176  }
177  return NULL;
178 }
179 
180 /* *********************************************************** */
181 
182 varInst* Mission::lookupClassVariable( string modulename, string varname, unsigned int classid )
183 {
184  missionNode *module = runtime.modules[modulename];
185  string mname = module->script.name;
186  if (classid == 0)
187  //no class instance
188  return NULL;
189  if ( classid >= module->script.classvars.size() ) {
190  fatalError( module, SCRIPT_RUN, "illegal classvar nr." );
191  assert( 0 );
192  }
193  varInstMap *cvmap = module->script.classvars[classid];
194 
195  varInst *var = (*cvmap)[varname];
196  return var;
197 }
198 
200 {
201  missionNode *module = runtime.cur_thread->module_stack.back();
202  unsigned int classid = runtime.cur_thread->classid_stack.back();
203  string mname = module->script.name;
204  string varname = asknode->script.name;
205  if (classid == 0)
206  //no class instance
207  return NULL;
208  if ( classid >= module->script.classvars.size() ) {
209  fatalError( asknode, SCRIPT_RUN, "illegal classvar nr." );
210  assert( 0 );
211  }
212  varInstMap *cvmap = module->script.classvars[classid];
213 
214  varInst *var = (*cvmap)[varname];
215  return var;
216 }
217 
218 varInst* Mission::lookupModuleVariable( missionNode *asknode )
219 {
220  //only when runtime
221  missionNode *module = runtime.cur_thread->module_stack.back();
222 
223  string mname = module->script.name;
224 
225  varInst *var = lookupModuleVariable( mname, asknode );
226 
227  return var;
228 }
229 
230 /* *********************************************************** */
231 
232 varInst* Mission::lookupGlobalVariable( missionNode *asknode )
233 {
234  missionNode *varnode = runtime.global_variables[asknode->script.name];
235  if (varnode == NULL)
236  return NULL;
237  return varnode->script.varinst;
238 }
239 
240 /* *********************************************************** */
241 
242 void Mission::doGlobals( missionNode *node, int mode )
243 {
244  if ( mode == SCRIPT_RUN || (mode == SCRIPT_PARSE && parsemode == PARSE_FULL) )
245  //nothing to do
246  return;
247  debug( 3, node, mode, "doing global variables" );
248 
249  vector< easyDomNode* >::const_iterator siter;
250  for (siter = node->subnodes.begin(); siter != node->subnodes.end() && !have_return( mode ); siter++) {
251  missionNode *snode = (missionNode*) *siter;
252  if (snode->tag == DTAG_DEFVAR) {
253  doDefVar( snode, mode, true );
254  } else {
255  fatalError( node, mode, "only defvars allowed below globals node" );
256  assert( 0 );
257  }
258  }
259 }
260 
261 /* *********************************************************** */
262 
263 varInst* Mission::doVariable( missionNode *node, int mode )
264 {
265  if (mode == SCRIPT_RUN) {
266  varInst *var = lookupLocalVariable( node );
267  if (var == NULL) {
268  var = lookupClassVariable( node );
269  if (var != NULL) {
270  }
271  if (var == NULL) {
272  //search in module namespace
273  var = lookupModuleVariable( node );
274  if (var == NULL) {
275  //search in global namespace
276  var = lookupGlobalVariable( node );
277  if (var == NULL) {
278  fatalError( node, mode, "did not find variable" );
279  assert( 0 );
280  }
281  }
282  }
283  }
284  return var;
285  } else {
286  //SCRIPT_PARSE
287  node->script.name = node->attr_value( "name" );
288  if ( node->script.name.empty() ) {
289  fatalError( node, mode, "you have to give a variable name" );
290  assert( 0 );
291  }
292  varInst *vi = searchScopestack( node->script.name );
293  if (vi == NULL) {
294  missionNode *global_var = runtime.global_variables[node->script.name];
295  if (global_var == NULL) {
296  fatalError( node, mode, "no variable "+node->script.name+" found on the scopestack (dovariable)" );
297  assert( 0 );
298  }
299  vi = global_var->script.varinst;
300  }
301  return vi;
302  }
303 }
304 
305 /* *********************************************************** */
306 
307 void Mission::doDefVar( missionNode *node, int mode, bool global_var )
308 {
309  if (mode == SCRIPT_RUN) {
310  missionNode *scope = node->script.context_block_node;
311  if (scope->tag == DTAG_MODULE) {
312  //this is a module variable - it has been initialized at parse time
313  debug( 0, node, mode, "defined module variable "+node->script.name );
314  return;
315  }
316  debug( 5, node, mode, "defining context variable "+node->script.name );
317 
318  contextStack *stack = runtime.cur_thread->exec_stack.back();
319  scriptContext *context = stack->contexts.back();
320 
321  varInstMap *vmap = context->varinsts;
322 
323  varInst *vi = newVarInst( VI_LOCAL );
324  vi->defvar_node = node;
325  vi->block_node = scope;
326  vi->type = node->script.vartype;
327  vi->name = node->script.name;
328 
329  (*vmap)[node->script.name] = vi;
330 
331  printRuntime();
332 
333  return;
334  }
335  //SCRIPT_PARSE
336 
337  node->script.name = node->attr_value( "name" );
338  if ( node->script.name.empty() ) {
339  fatalError( node, mode, "you have to give a variable name" );
340  assert( 0 );
341  }
342  string value = node->attr_value( "initvalue" );
343 
344  debug( 5, node, mode, "defining variable "+node->script.name );
345 
346  string type = node->attr_value( "type" );
347 
348  node->script.vartype = vartypeFromString( type );
349 
350  missionNode *scope = NULL;
351  int scope_id = -1;
352  if (global_var == false) {
353  scope = scope_stack.back();
354  scope_id = scope_stack.size()-1;
355  }
356  varInst *vi = NULL;
357  if (global_var)
358  vi = newVarInst( VI_GLOBAL );
359  else if (scope->tag == DTAG_MODULE)
360  vi = newVarInst( VI_MODULE );
361  else
362  vi = newVarInst( VI_LOCAL );
363  vi->defvar_node = node;
364  vi->block_node = scope;
365  vi->type = node->script.vartype;
366  vi->name = node->script.name;
367  if (global_var || scope->tag == DTAG_MODULE) {
368  if ( !value.empty() ) {
369  debug( 4, node, mode, "setting init for "+node->script.name );
370  if (vi->type == VAR_FLOAT) {
371  vi->float_val = strtod( value.c_str(), NULL );
372  } else if (vi->type == VAR_INT) {
373  vi->int_val = atoi( value.c_str() );
374  } else if (vi->type == VAR_BOOL) {
375  if (value == "true") {
376  vi->bool_val = true;
377  } else if (value == "false") {
378  vi->bool_val = false;
379  } else {
380  fatalError( node, mode, "wrong bool value" );
381  assert( 0 );
382  }
383  } else {
384  fatalError( node, mode, "this datatype can;t be initialized" );
385  assert( 0 );
386  }
387  printVarInst( vi );
388  }
389  } else
390  //local variable
391  if ( !value.empty() ) {
392  fatalError( node, mode, "initvalue is not allowed for a local variable" );
393  assert( 0 );
394  }
395  node->script.varinst = vi; //FIXME (not for local var)
396  node->script.context_id = -1;
397  node->script.varId = -1;
398 
399  int varId = -1;
400  if (global_var) {
401  //global var
402  debug( 3, node, mode, "defining global variable" );
403  runtime.global_variables[node->script.name] = node;
404  varId = runtime.global_varvec.addVar( vi );
405  printGlobals( 3 );
406  } else {
407  //module, class or local var
408  string classvar = node->attr_value( "classvar" );
409  if (classvar == "true") {
410  //class var
411  missionNode *module_node = scope_stack.back();
412  if (module_node->script.classvars.size() != 1) {
413  fatalError( node, mode, "no module node with classvars" );
414  assert( 0 );
415  }
416  varInstMap *vmap = module_node->script.classvars[0];
417  (*vmap)[node->script.name] = vi;
418 
419  varId = vmap->varVec.addVar( vi );
420  } else {
421  //module or local var
422  scope->script.variables[node->script.name] = vi;
423 
424  varId = scope->script.variables.varVec.addVar( vi );
425  }
426  node->script.context_block_node = scope;
427  node->script.context_id = scope_id;
428 
429  debug( 5, scope, mode, "defined variable in that scope" );
430  }
431  node->script.varId = varId;
432 }
433 
434 /* *********************************************************** */
435 
436 void Mission::doSetVar( missionNode *node, int mode )
437 {
438  trace( node, mode );
439  if (mode == SCRIPT_PARSE) {
440  node->script.name = node->attr_value( "name" );
441  if ( node->script.name.empty() )
442  fatalError( node, mode, "you have to give a variable name" );
443  }
444  debug( 3, node, mode, "trying to set variable "+node->script.name );
445  if (node->subnodes.size() != 1) {
446  fatalError( node, mode, "setvar takes exactly one argument" );
447  assert( 0 );
448  }
449  missionNode *expr = (missionNode*) node->subnodes[0];
450  if (mode == SCRIPT_PARSE) {
451  varInst *vi = searchScopestack( node->script.name );
452  if (vi == NULL) {
453  missionNode *global_var = runtime.global_variables[node->script.name];
454  if (global_var == NULL) {
455  fatalError( node, mode, "no variable "+node->script.name+" found on the scopestack (setvar)" );
456  assert( 0 );
457  }
458  vi = global_var->script.varinst;
459  }
460  if (vi->type == VAR_BOOL) { //FIXME I can't imagine the purpose of these these... --chuck_starchaser
461  bool res = checkBoolExpr( expr, mode ); //FIXME ???!
462  } else if (vi->type == VAR_FLOAT) {
463  double res = checkFloatExpr( expr, mode ); //FIXME ???!
464  } else if (vi->type == VAR_INT) {
465  float res = checkIntExpr( expr, mode ); //FIXME ???!
466  } else if (vi->type == VAR_OBJECT) {
467  debug( 3, node, mode, "setvar object" );
468  varInst *ovi = checkObjectExpr( expr, mode );
469  deleteVarInst( ovi );
470  } else {
471  fatalError( node, mode, "unsupported type in setvar" );
472  assert( 0 );
473  }
474  }
475  if (mode == SCRIPT_RUN) {
476  varInst *var_inst = doVariable( node, mode ); //lookup variable instance
477  if (var_inst == NULL) {
478  fatalError( node, mode, "variable lookup failed for "+node->script.name );
479  printRuntime();
480  assert( 0 );
481  }
482  if (var_inst->type == VAR_BOOL) {
483  bool res = checkBoolExpr( expr, mode );
484  var_inst->bool_val = res;
485  } else if (var_inst->type == VAR_FLOAT) {
486  double res = checkFloatExpr( expr, mode );
487  var_inst->float_val = res;
488  } else if (var_inst->type == VAR_INT) {
489  int res = checkIntExpr( expr, mode );
490  var_inst->int_val = res;
491  } else if (var_inst->type == VAR_OBJECT) {
492  debug( 3, node, mode, "setvar object (before)" );
493  varInst *ovi = checkObjectExpr( expr, mode );
494  assignVariable( var_inst, ovi );
495  debug( 3, node, mode, "setvar object left,right" );
496  printVarInst( 3, var_inst );
497  printVarInst( 3, ovi );
498  deleteVarInst( ovi );
499  } else {
500  fatalError( node, mode, "unsupported datatype" );
501  assert( 0 );
502  }
503  }
504 }
505 
506 /* *********************************************************** */
507 
508 varInst* Mission::doConst( missionNode *node, int mode )
509 {
510  if (mode == SCRIPT_PARSE) {
511  string typestr = node->attr_value( "type" );
512  string valuestr = node->attr_value( "value" );
513  if ( typestr.empty() ) {
514  fatalError( node, mode, "no valid const declaration" );
515  assert( 0 );
516  }
517  debug( 5, node, mode, "parsed const value "+valuestr );
518 
519  varInst *vi = newVarInst( VI_CONST );
520  if (typestr == "float") {
521  node->script.vartype = VAR_FLOAT;
522  vi->float_val = atof( valuestr.c_str() );
523  } else if (typestr == "int") {
524  node->script.vartype = VAR_INT;
525  vi->int_val = atoi( valuestr.c_str() );
526  } else if (typestr == "bool") {
527  node->script.vartype = VAR_BOOL;
528  if (valuestr == "true") {
529  vi->bool_val = true;
530  } else if (valuestr == "false") {
531  vi->bool_val = false;
532  } else {
533  fatalError( node, mode, "wrong bool value" );
534  assert( 0 );
535  }
536  } else if (typestr == "object") {
537  string objecttype = node->attr_value( "object" );
538  if (objecttype == "string") {
539  varInst *svi = call_string_new( node, mode, valuestr );
540  vi->type = VAR_OBJECT;
541  assignVariable( vi, svi );
542  vi->type = VAR_OBJECT;
543  node->script.vartype = VAR_OBJECT;
544  deleteVarInst( svi );
545  } else {
546  fatalError( node, mode, "you cant have a const object" );
547  assert( 0 );
548  }
549  } else {
550  fatalError( node, mode, "unknown variable type" );
551  assert( 0 );
552  }
553  vi->type = node->script.vartype;
554 
555  node->script.varinst = vi;
556  }
557  return node->script.varinst;
558 }
559 
560 /* *********************************************************** */
561 
562 void Mission::assignVariable( varInst *v1, varInst *v2 )
563 {
564  if (v1->type != v2->type && v1->type != VAR_ANY) {
565  fatalError( NULL, SCRIPT_RUN, "wrong types in assignvariable" );
566  saveVarInst( v1, cout );
567  saveVarInst( v2, cout );
568  assert( 0 );
569  }
570  if (v1->type == VAR_OBJECT) {
571  if ( v1->objectname.empty() ) {
572  //the object has not been set
573  //we set it below
574  } else if ( v2->objectname.empty() ) {
575  //printf("WARNING: assignVariable v2==empty\n"); FIXME ??
576  } else if (v1->objectname != v2->objectname) {
577  fatalError( NULL, SCRIPT_RUN, "wrong object types in assignment ("+v1->objectname+" , "+v2->objectname );
578  assert( 0 );
579  }
580  }
581  if (v1->type == VAR_ANY)
582  v1->type = v2->type;
583  v1->float_val = v2->float_val;
584  v1->int_val = v2->int_val;
585  v1->bool_val = v2->bool_val;
586  if ( !( v2->objectname.empty() ) )
587  v1->objectname = v2->objectname;
588  v1->object = v2->object;
589 }
590 
591 /* *********************************************************** */
592 
593 var_type Mission::vartypeFromString( string type )
594 {
595  var_type vartype;
596  if (type == "float") {
597  vartype = VAR_FLOAT;
598  } else if (type == "bool") {
599  vartype = VAR_BOOL;
600  } else if (type == "int") {
601  vartype = VAR_INT;
602  } else if (type == "object") {
603  vartype = VAR_OBJECT;
604  } else {
605  fatalError( NULL, SCRIPT_PARSE, "unknown var type "+type );
606  vartype = VAR_FAILURE;
607  }
608  return vartype;
609 }
610 
611 /* *********************************************************** */
612 
613 void Mission::saveVariables( const ostream &out ) {}
614 
615 /* *********************************************************** */
616 
617 void Mission::saveVarInst( varInst *vi, ostream &aa_out )
618 {
619  char buffer[100];
620  if (vi == NULL) {} else {
621  if (vi->type == VAR_BOOL) {
622  sprintf( buffer, "type=\"bool\" value=\"%d\" ", vi->bool_val );
623  } else if (vi->type == VAR_FLOAT) {
624  sprintf( buffer, "type=\"float\" value=\"%f\" ", vi->float_val );
625  } else if (vi->type == VAR_INT) {
626  sprintf( buffer, "type=\"int\" value=\"%d\" ", vi->int_val );
627  } else if (vi->type == VAR_OBJECT) {
628  if (vi->objectname == "string") {
629  string *sptr = (string*) vi->object;
630  sprintf( buffer, "type=\"object\" object=\"%s\" value=\"%s\" >\n ", vi->objectname.c_str(), sptr->c_str() );
631  } else {
632  sprintf( buffer, "type=\"object\" object=\"%s\" value=\"0x%p\" >\n ", vi->objectname.c_str(), vi->object );
633 
634  string modname = "_"+vi->objectname;
635 
636  doCall_toxml( modname, vi );
637  }
638  }
639  }
640 }
641