ops.cc

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2001-2002  The Exult Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #ifdef HAVE_CONFIG_H
00020   #include <config.h>
00021 #endif
00022 
00023 #include "ops.h"
00024 #include "files/utils.h"
00025 #include "exceptions.h"
00026 #include <cstdlib>
00027 #include <iomanip>
00028 #include <fstream>
00029 #include <stack>
00030 #ifdef HAVE_SSTREAM
00031 #include <sstream>
00032 using std::stringstream;
00033 #endif
00034 
00035 
00036 /*** head2data
00037 #ifndef __STRING
00038   #if defined __STDC__ && __STDC__
00039     #define __STRING(x) #x
00040   #else
00041     #define __STRING(x) "x"
00042   #endif
00043 #endif
00044 */
00045 
00046 using std::vector;
00047 using std::ifstream;
00048 using std::cout;
00049 using std::endl;
00050 using std::string;
00051 using std::cerr;
00052 using std::ends;
00053 using std::setw;
00054 using std::setfill;
00055 using std::setbase;
00056 using std::pair;
00057 using std::map;
00058 
00059 #define MAX_NO_OPCODES 512
00060 vector<UCOpcodeData> opcode_table_data(MAX_NO_OPCODES);
00061 
00062 vector<pair<unsigned int, unsigned int> > opcode_jumps;
00063 
00064 map<unsigned int, string> uc_intrinsics;
00065 
00066 map<string, pair<unsigned int, bool> > type_size_map;
00067 
00068 void ucxtInit::init(const Configuration &config, const UCOptions &options)
00069 {
00070   datadir = get_datadir(config, options);
00071   
00072   misc_data = "u7misc.data";
00073   misc_root = "misc";
00074   
00075   opcodes_data = "u7opcodes.data";
00076   opcodes_root = "opcodes";
00077   
00078   bg_intrinsics_data = "u7bgintrinsics.data";
00079   bg_intrinsics_root = "intrinsics";
00080   
00081   si_intrinsics_data = "u7siintrinsics.data";
00082   si_intrinsics_root = "intrinsics";
00083   
00084   if(options.verbose) cout << "Initing misc..." << endl;
00085   misc();
00086   
00087   if(options.verbose) cout << "Initing opcodes..." << endl;
00088   opcodes();
00089   
00090   if(options.verbose) cout << "Initing intrinsics..." << endl;
00091   if(options.game_bg())
00092     intrinsics(bg_intrinsics_data, bg_intrinsics_root);
00093   else if(options.game_si())
00094     intrinsics(si_intrinsics_data, si_intrinsics_root);
00095 }
00096 
00097 string ucxtInit::get_datadir(const Configuration &config, const UCOptions &options)
00098 {
00099   string datadir;
00100   
00101   // just to handle if people are going to compile with makefile.unix, unsupported, but occasionally useful
00102   #ifdef HAVE_CONFIG_H
00103   if(options.noconf == false) config.value("config/ucxt/root", datadir, EXULT_DATADIR);
00104   #else
00105   if(options.noconf == false) config.value("config/ucxt/root", datadir, "data/");
00106   #endif
00107   
00108   if(datadir.size() && datadir[datadir.size()-1]!='/' && datadir[datadir.size()-1]!='\\') datadir+='/';
00109   if(options.verbose) cout << "datadir: " << datadir << endl;
00110 
00111   return datadir;
00112 }
00113 
00114 void ucxtInit::misc()
00115 {
00116   Configuration miscdata(datadir + misc_data, misc_root);
00117 
00118   Configuration::KeyTypeList om;
00119   miscdata.getsubkeys(om, misc_root + "/offset_munge");
00120   
00121   Configuration::KeyTypeList st;
00122   miscdata.getsubkeys(st, misc_root + "/size_type");
00123   
00124   // For each size type (small/long/byte/etc.)
00125   for(typeof(st.begin()) k=st.begin(); k!=st.end(); ++k)
00126   {
00127     bool munge_offset=false;
00128     
00129     const string tmpstr(k->first + "/");
00130     
00131     /* ... we need to find out if we should munge it's parameter
00132       that is, it's some sort of goto target (like offset) or such */
00133     for(typeof(om.begin()) m=om.begin(); m!=om.end(); ++m)
00134       if(m->first.size()-1==k->first.size())
00135         if(m->first==tmpstr)
00136 //        if(m->first.compare(0, m->first.size()-1, k->first, 0, k->first.size())==0)
00137           munge_offset=true;
00138     
00139     // once we've got it, add it to the map
00140     pair<unsigned int, bool> tsm_tmp(strtol(k->second.c_str(), 0, 0), munge_offset);
00141     type_size_map.insert(pair<string, pair<unsigned int, bool> >(k->first, tsm_tmp));
00142   }
00143 }
00144 
00145 /* constructs the usecode tables from datafiles in the /ucxt hierachy */
00146 void ucxtInit::opcodes()
00147 {
00148   Configuration opdata(datadir + opcodes_data, opcodes_root);
00149   
00150   vector<string> keys = opdata.listkeys(opcodes_root);
00151     
00152   #if 1
00153   for(vector<string>::iterator key=keys.begin(); key!=keys.end(); ++key)
00154   {
00155     if((*key)[0]!='!')
00156     {
00157       Configuration::KeyTypeList ktl;
00158     
00159       opdata.getsubkeys(ktl, *key);
00160     
00161       if(ktl.size())
00162       {
00163         unsigned int i = strtol(key->substr(key->find_first_of("0")).c_str(), 0, 0);
00164         opcode_table_data[i] = UCOpcodeData(i, ktl);
00165       }
00166     }
00167   }
00168   
00169   #else
00170   
00171   string ucxtroot(datadir + "opcodes.txt");
00172 
00173   std::ifstream file;
00174 
00175   try
00176   {
00177     U7open(file, ucxtroot.c_str(), true);
00178   } catch (const file_open_exception& e)
00179   {
00180     cerr << e.what() << ". exiting." << endl;
00181     exit(1);
00182   }
00183   
00184   std::string s;
00185   while(!file.eof())
00186   {
00187     getline(file, s);
00188     if(s.size() && s[0]=='>')
00189     {
00190       UCOpcodeData uco(str2vec(s));
00191       assert(uco.opcode<MAX_NO_OPCODES);
00192       opcode_table_data[uco.opcode] = uco;
00193     } 
00194   }
00195   file.close();
00196   #endif
00197   
00198   /* Create an {opcode, parameter_index} array of all opcodes that
00199     execute a 'jump' statement */
00200   for(std::vector<UCOpcodeData>::iterator op=opcode_table_data.begin(); op!=opcode_table_data.end(); op++)
00201   {
00202     for(unsigned int i=0; i<op->param_sizes.size(); i++)
00203     {
00204       if(op->param_sizes[i].second==true) // this is a calculated offset
00205       {
00206         opcode_jumps.push_back(std::pair<unsigned int, unsigned int>(op->opcode, i+1)); // parameters are stored as base 1
00207       }
00208     }
00209   }
00210   
00211   #if 0
00212   std::cout << "Calculated Opcode pairs:" << std::endl;
00213   for(std::vector<std::pair<unsigned int, unsigned int> >::iterator i=opcode_jumps.begin(); i!=opcode_jumps.end(); i++)
00214     std::cout << setw(4) << i->first << '\t' << setw(4) << i->second << std::endl;
00215   #endif
00216 }
00217 
00218 void ucxtInit::intrinsics(const string &intrinsic_data, const string &intrinsic_root)
00219 {
00220   Configuration intdata(datadir + intrinsic_data, intrinsic_root);
00221   
00222   Configuration::KeyTypeList ktl;
00223     
00224   intdata.getsubkeys(ktl, intrinsic_root);
00225   
00226   for(Configuration::KeyTypeList::iterator k=ktl.begin(); k!=ktl.end(); k++)
00227     uc_intrinsics.insert(pair<unsigned int, string>(strtol(k->first.c_str(), 0, 0), k->second));
00228 }
00229 
00230 /* To be depricated when I get the complex std::vector<std::string> splitter online */
00231 std::vector<std::string> qnd_ocsplit(const std::string &s)
00232 {
00233   assert((s[0]=='{') && (s[s.size()-1]=='}'));
00234 
00235   std::vector<std::string> vs;
00236   std::string tstr;
00237 
00238   for(std::string::const_iterator i=s.begin(); i!=s.end(); ++i)
00239   {
00240     if(*i==',')
00241     {
00242       vs.push_back(tstr);
00243       tstr="";
00244     }
00245     else if(*i=='{' || *i=='}')
00246     { /* nothing */ }
00247     else
00248       tstr+=*i;
00249   }
00250   if(tstr.size())
00251     vs.push_back(tstr);
00252 
00253   return vs;
00254 }
00255 
00256 std::vector<std::string> str2vec(const std::string &s)
00257 {
00258   std::vector<std::string> vs;
00259   unsigned int lasti=0;
00260 
00261   // if it's empty return null
00262   if(s.size()==0) return vs;
00263 
00264   bool indquote=false;
00265   for(unsigned int i=0; i<s.size(); i++)
00266   {
00267     if(s[i]=='"')
00268       indquote = !indquote;
00269     else if(isspace(s[i]) && (!indquote))
00270     {
00271       if(lasti!=i)
00272       {
00273         if((s[lasti]=='"') && (s[i-1]=='"'))
00274         {
00275           if((lasti+1)!=(lasti-1))
00276             vs.push_back(s.substr(lasti+1, i-lasti-2));
00277         }
00278         else
00279           vs.push_back(s.substr(lasti, i-lasti));
00280       }
00281 
00282       lasti=i+1;
00283     }
00284     if(i==s.size()-1)
00285     {
00286       if((s[lasti]=='"') && (s[i]=='"'))
00287       {
00288         if((lasti+1)!=(lasti-1))
00289           vs.push_back(s.substr(lasti+1, i-lasti-2));
00290       }
00291       else
00292         vs.push_back(s.substr(lasti, i-lasti+1));
00293     }
00294   }
00295 
00296   #if 0 //test
00297   for(unsigned int i=0; i<vs.size(); i++)
00298     std::cout << "\t\"" << vs[i] << "\"" << std::endl;
00299   #endif 
00300 
00301   return vs;
00302 }
00303 
00304 void map_type_size(const std::vector<std::string> &param_types, std::vector<std::pair<unsigned int, bool> > &param_sizes)
00305 {
00306   for(std::vector<std::string>::const_iterator s=param_types.begin(); s!=param_types.end(); ++s)
00307   {
00308     map<string, pair<unsigned int, bool> >::iterator tsm(type_size_map.find(*s));
00309     if(tsm==type_size_map.end())
00310     {
00311       cerr << "error: No size type `" << *s << "`" << endl;
00312       assert(tsm!=type_size_map.end());
00313     }
00314     
00315     param_sizes.push_back(std::pair<unsigned int, bool>(tsm->second.first, tsm->second.second));
00316   }
00317 }
00318 
00319 /*std::vector<std::string> str2vec(const std::string &s)
00320 {
00321   std::vector<std::string> vs; // the resulting strings
00322   stack<char> vbound; // the "bounding" chars used to deonte collections of characters
00323   unsigned int lasti=0;
00324   std::string currstr; // the current string, gets appended to vs
00325 
00326   // if it's empty return null
00327   if(s.size()==0) return vs;
00328 
00329   for(unsigned int i=0; i<s.size(); i++)
00330   {
00331     bool pushback=false; // do we push the currstr onto the vector now?
00332     char c = s[i];
00333     switch(c)
00334     {*/
00335       // let's start with the openings...
00336       /* the general pricipal, since we strip the outermost enclosures,
00337          is to only append the "bounding" characters if they're NOT the
00338          outer most.
00339          NOTE: A subtle exception is the boundaries on the outermost set of
00340          bounding chars has the same effect as isspace(), YHBW */
00341 /*      case '{':  if(vs.size()) currstr+=c; vbound.push('}');  break;
00342       //case '[': if(vs.size()) currstr+=c; vbound.push(']'); break;
00343       //case '(': if(vs.size()) currstr+=c; vbound.push(')'); break;
00344       //case '<': if(vs.size()) currstr+=c; vbound.push('>'); break;
00345 
00346       // now the closures...
00347       case '}':
00348         if(vbound.top()=='}') vbound.pop();
00349         if(vbound.size()==0)  pushback=true;
00350         else                  currstr+=c;
00351         break;
00352       //case ']':
00353       //  break;
00354       //case ')':
00355       //  break;
00356       //case '>':
00357       //  break;
00358 
00359       // now the ones that have the pretentiousness of being both
00360       // opening and closing causes
00361       case '\"': if(vs.size()) currstr+=c; vbound.push('\"'); break;
00362       case '\'': if(vs.size()) currstr+=c; vbound.push('\''); break;
00363       case '\"':
00364         if(vbound.top()=='\"')    vbound.pop();
00365         else                   vbound.push('\"');
00366         if(vbound.size()==0) pushback=true;
00367         else                   currstr+=c;
00368         break;
00369       case '\'':
00370         if(vbound.top()=='\'') vbound.pop();
00371         if(vbound.size()==0)   pushback=true;
00372         else                   currstr+=c;
00373         break;
00374       
00375       // not to emulate isspace();
00376       case ' ':  // ze space
00377       case '\f': // form-feed
00378       case '\n': // newline
00379       case '\r': // carriage return
00380       case '\t': // horizontal tab
00381       case '\v': // vertical tab
00382         pushback=true;
00383         break;
00384     }
00385 
00386     if(pushback)
00387     {
00388       if(currstr.size())
00389         vs.push_back(currstr);
00390       currstr="";
00391     }
00392   }
00393 
00394   #if 1 //test
00395   for(unsigned int i=0; i<vs.size(); i++)
00396     std::cout << "\t\"" << vs[i] << "\"" << std::endl;
00397   #endif ///test
00398 
00399   return vs;
00400 }*/

Generated on Mon Jul 9 14:42:52 2007 for ExultEngine by  doxygen 1.5.1