ucxt.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 /*
00020   ucxt: Ultima 7 usecode dump/disassembly/convert-to-something-more-readable utility
00021     Based heavily on ucdump created and maintained by:
00022       Maxim S. Shatskih aka Moscow Dragon (maxim__s@mtu-net.ru)
00023   
00024   Maintainter:
00025     Patrick Burke (takhisisii@yahoo.com.au)
00026   
00027   Original ucdump history, credits and stuff moved to Docs/ucxtread.txt
00028   
00029   $LBClueless = TRUE;
00030 */
00031 
00032 /* TODO:
00033 */
00034 
00035 #ifdef HAVE_CONFIG_H
00036 #  include <config.h>
00037 #endif
00038 
00039 #include <cstdio>
00040 #include <cstdlib>
00041 #include <cstring>
00042 #include <string>
00043 #include <iomanip>
00044 #include <vector>
00045 #include <stack>
00046 #include <map>
00047 
00048 #include "ucc.h"
00049 #include "ops.h"
00050 #include "ucdata.h"
00051 #include "ucfunc.h"
00052 #include "files/utils.h"
00053 
00054 // include xml configuration stuff
00055 #include "Configuration.h"
00056 #include "exult_constants.h"
00057 const std::string c_empty_string; // Ob for exult_constants.h
00058 
00059 /* Functions */
00060 void usage();
00061 void open_usecode_file(UCData &uc, const Configuration &config);
00062 
00063 UCData uc;
00064 
00065 using std::setw;
00066 using std::cerr;
00067 using std::cout;
00068 using std::ios;
00069 using std::string;
00070 using std::endl;
00071 
00072 int main(int argc, char** argv)
00073 {
00074   // Tends to make life easier
00075   cout << std::setfill('0') << std::setbase(16);
00076   cout.setf(ios::uppercase);
00077 
00078   // get the parameters
00079   uc.parse_params(argc, argv);
00080   if(uc.options.verbose) cout << "Parameters parsed..." << endl;
00081 
00082   Configuration config;
00083   
00084   // attempt to find an exult.cfg file... _somewhere_
00085   if(uc.options.noconf == false)
00086   {
00087     if(uc.options.verbose) cout << "Loading exult configuration file..." << endl;
00088     if(config.read_config_file("exult.cfg") == false)
00089     {
00090       cout << "Failed to locate exult.cfg. Run exult before running ucxt or use the -nc switch. Exiting." << endl;
00091       exit(1);
00092     }
00093   }
00094   
00095   // init the run time tables
00096   if(uc.options.verbose) cout << "Initing runtime tables..." << endl;
00097   
00098   ucxtInit init;
00099   init.init(config, uc.options);
00100   
00101   #if 0
00102   {
00103     cout << "<opcodes>" << endl;
00104     
00105     for(typeof(opcode_table_data.begin()) i=opcode_table_data.begin(); i!=opcode_table_data.end(); i++)
00106     {
00107       if(i->opcode!=0 && i->name!="NULL")
00108       {
00109         cout << "\t<0x" << setw(2) << i->opcode << '>' << endl;
00110       
00111         cout << "\t\t<name> " << i->name << " </>" << endl;
00112         cout << "\t\t<asm_nmo> `" << i->asm_nmo << "` </>" << endl;
00113         cout << "\t\t<asm_comment> `" << i->asm_comment << "` </>" << endl;
00114         cout << "\t\t<ucs_nmo> `" << i->ucs_nmo << "` </>" << endl;
00115         cout << "\t\t<num_bytes> " << i->num_bytes << " </>" << endl;
00116         
00117         cout << "\t\t<param_types> {";
00118         for(typeof(i->param_types.begin()) j=i->param_types.begin(); j!=i->param_types.end(); j++)
00119           cout << *j << ',';
00120         cout << "} </>" << endl;
00121         
00122         cout << "\t\t<num_pop> " << i->num_pop << " </>" << endl;
00123         cout << "\t\t<num_push> " << i->num_push << " </>" << endl;
00124         cout << "\t\t<call_effect> " << i->call_effect << " </>" << endl;
00125         if(i->flag_return) cout << "\t\t<return/>" << endl;
00126         if(i->flag_paren) cout << "\t\t<paren/>" << endl;
00127         if(i->flag_indent_inc) cout << "\t\t<indent_inc/>" << endl;
00128         if(i->flag_indent_dec) cout << "\t\t<indent_dec/>" << endl;
00129         if(i->flag_indent_tmpinc) cout << "\t\t<indent_tmpinc/>" << endl;
00130         if(i->flag_indent_tmpdec) cout << "\t\t<indent_tmpdec/>" << endl;
00131         
00132         cout << "\t</>" << endl;
00133       }
00134     }
00135     cout << "</>" << endl;
00136   }
00137   #endif
00138   
00139   // ICK! Don't try this at home kids...
00140   // done because for some reason it started crashing upon piping or redirection to file... wierd.
00141   // yes, it's a hack to fix an eldritch bug I could't find... it seems appropriate
00142   // FIXME: Problem nolonger exists. Probably should put some 'nice' code in it's place.
00143   std::ofstream outputstream;
00144   std::streambuf *coutbuf=0;
00145   if(uc.output_redirect().size())
00146   {
00147     U7open(outputstream, uc.output_redirect().c_str(), false);
00148     if(outputstream.fail())
00149     {
00150       cout << "error. failed to open " << uc.output_redirect() << " for writing. exiting." << endl;
00151       exit(1);
00152     }
00153     coutbuf = cout.rdbuf();
00154     cout.rdbuf(outputstream.rdbuf());
00155   }
00156   // you may now uncover your eyes <grin>
00157 
00158   open_usecode_file(uc, config);
00159 
00160   if(uc.opt().output_extern_header)
00161   {
00162     uc.output_extern_header(cout);
00163   }
00164   else if     ( uc.options.mode_dis || uc.options.mode_all )
00165   {
00166     uc.disassamble();
00167   }
00168   else if( uc.options.output_flag )
00169   {
00170     uc.dump_flags(cout);
00171   }
00172   else
00173     usage();
00174 
00175   // now we clean up the <ick>y ness from before
00176   if(uc.output_redirect().size())
00177   {
00178     cout.rdbuf(coutbuf);
00179   }
00180   
00181   return 0;
00182 }
00183 
00184 void open_usecode_file(UCData &uc, const Configuration &config)
00185 {
00186   string bgpath;
00187   if(uc.options.noconf == false) config.value("config/disk/game/blackgate/path", bgpath);
00188   string sipath;
00189   if(uc.options.noconf == false) config.value("config/disk/game/serpentisle/path", sipath);
00190   string u8path;
00191   if(uc.options.noconf == false) config.value("config/disk/game/pagan/path", u8path);
00192   
00193   /* ok, to find the usecode file we search: (where $PATH=bgpath or sipath)
00194     $PATH/static/usecode
00195     $PATH/STATIC/usecode
00196     $PATH/static/USECODE
00197     $PATH/STATIC/USECODE
00198     ./ultima7/static/usecode || ./serpent/static/usecode
00199     ./ultima7/STATIC/usecode || ./serpent/STATIC/usecode
00200     ./ultima7/static/USECODE || ./serpent/static/USECODE
00201     ./ultima7/STATIC/USECODE || ./serpent/STATIC/USECODE
00202     ./ULTIMA7/static/usecode || ./SERPENT/static/usecode
00203     ./ULTIMA7/STATIC/usecode || ./SERPENT/STATIC/usecode
00204     ./ULTIMA7/static/USECODE || ./SERPENT/static/USECODE
00205     ./ULTIMA7/STATIC/USECODE || ./SERPENT/STATIC/USECODE
00206     ./static/usecode
00207     ./STATIC/usecode
00208     ./static/USECODE
00209     ./STATIC/USECODE
00210     ./usecode.bg || ./usecode.si
00211     ./USECODE
00212     ./usecode
00213     
00214     Anything I'm missing? <queryfluff>
00215   */
00216   
00217   /* The capitilisation configurations: (yes, going overkill, typos are BAD!) */
00218   
00219   // These 4 are only specific to BG && SI
00220   string mucc_sl("static");
00221   string mucc_sc("STATIC");
00222   string mucc_ul("usecode");
00223   string mucc_uc("USECODE");
00224   
00225   const string mucc_bgl("ultima7");
00226   const string mucc_bgc("ULTIMA7");
00227   const string mucc_sil("serpent");
00228   const string mucc_sic("SERPENT");
00229   const string mucc_u8l("pagan");
00230   const string mucc_u8c("PAGAN");
00231   
00232   string path, ucspecial, mucc_l, mucc_c;
00233   if(uc.options.game_bg())
00234   {
00235     if(uc.options.verbose) cout << "Configuring for bg." << endl;
00236     path      = bgpath;
00237     ucspecial = "usecode.bg";
00238     mucc_l  = mucc_bgl;
00239     mucc_c  = mucc_bgc;
00240   }
00241   else if(uc.options.game_si())
00242   {
00243     if(uc.options.verbose) cout << "Configuring for si." << endl;
00244     path      = sipath;
00245     ucspecial = "usecode.si";
00246     mucc_l  = mucc_sil;
00247     mucc_c  = mucc_sic;
00248   }
00249   else if(uc.options.game_u8())
00250   {
00251     if(uc.options.verbose) cout << "Configuring for u8." << endl;
00252     path      = u8path;
00253     ucspecial = "usecode.u8";
00254     mucc_l  = mucc_u8l;
00255     mucc_c  = mucc_u8c;
00256     mucc_sl = "usecode";
00257     mucc_sc = "USECODE";
00258     mucc_ul = "eusecode.flx";
00259     mucc_uc = "EUSECODE.FLX";
00260   }
00261   else
00262   {
00263     cerr << "Error: uc.game() was not set to GAME_U7 or GAME_SI or GAME_U8 this can't happen" << endl;
00264     assert(false); exit(1); // just incase someone decides to compile without asserts;
00265   }
00266   
00267   /* The four mystical usecode configurations: */
00268   
00269   const string mucc_ll(string("/") + mucc_sl + "/" + mucc_ul);
00270   const string mucc_cl(string("/") + mucc_sc + "/" + mucc_ul);
00271   const string mucc_lc(string("/") + mucc_sl + "/" + mucc_uc);
00272   const string mucc_cc(string("/") + mucc_sc + "/" + mucc_uc);
00273   
00274   // an icky exception chain for those who don't use .exult.cfg
00275   if(uc.input_usecode_file().size())
00276     uc.open_usecode(uc.input_usecode_file());
00277   else if(uc.options.noconf==false)
00278   {
00279     uc.open_usecode(path + mucc_ll);
00280     if(uc.fail())
00281       uc.open_usecode(path + mucc_cl);
00282     if(uc.fail())
00283       uc.open_usecode(path + mucc_lc);
00284     if(uc.fail())
00285       uc.open_usecode(path + mucc_cc);
00286     if(uc.fail())
00287       uc.open_usecode(mucc_l + mucc_ll);
00288   }
00289   else
00290     uc.open_usecode(mucc_l + mucc_ll);
00291     
00292   if(uc.fail())
00293     uc.open_usecode(mucc_l + mucc_cl);
00294   if(uc.fail())
00295     uc.open_usecode(mucc_l + mucc_lc);
00296   if(uc.fail())
00297     uc.open_usecode(mucc_l + mucc_cc);
00298   if(uc.fail())
00299     uc.open_usecode(mucc_c + mucc_ll);
00300   if(uc.fail())
00301     uc.open_usecode(mucc_c + mucc_cl);
00302   if(uc.fail())
00303     uc.open_usecode(mucc_c + mucc_lc);
00304   if(uc.fail())
00305     uc.open_usecode(mucc_c + mucc_cc);
00306   if(uc.fail())
00307     uc.open_usecode(mucc_ll);
00308   if(uc.fail())
00309     uc.open_usecode(mucc_cl);
00310   if(uc.fail())
00311     uc.open_usecode(mucc_lc);
00312   if(uc.fail())
00313     uc.open_usecode(mucc_cc);
00314   if(uc.fail())
00315     uc.open_usecode(ucspecial);
00316   if(uc.fail())
00317     uc.open_usecode(mucc_uc);
00318   if(uc.fail())
00319     uc.open_usecode(mucc_ul);
00320 
00321   // if we get through all this, usecode can't be installed anywhere sane
00322   if(uc.fail())
00323   {
00324     cout << "Failed to locate usecode file. Exiting." << endl;
00325     exit(1);
00326   }
00327 }
00328 
00329 void usage()
00330 {
00331   cout << "Ultima 7/8 usecode disassembler v0.6.3" << endl
00332   #ifdef HAVE_CONFIG_H
00333        << "    compiled with " << PACKAGE << " " << VERSION << endl
00334   #endif
00335        << endl;
00336   
00337   cout << "Usage:" << endl
00338        << "\tucxt [options] -a" << endl
00339        << "\t\t- prints all of the functions" << endl
00340        << "\tucxt [options] <hex function number>" << endl
00341        << "\t\t- disassembles single function to stdout" << endl
00342 //       << "\tucdump -c - scans the whole usecode file for unknown opcodes" << endl
00343 //       << "\tucdump -o <hex number> - prints list of functions which use "
00344 //       << "the given opcode" << endl
00345 //       << "\tucdump -i <hex number> - prints list of functions which use "
00346 //       << "the given intrinsic function\n" << endl
00347 //       << "\tucxt -f - prints list of all flags x functions" << endl
00348        << endl
00349        << "\tMisc Flags (any/all of these):" << endl
00350        << "\t\t-nc\t- don't look for exult's .xml config file" << endl
00351        << "\t\t-v \t- turns on verbose output mode" << endl
00352        << "\t\t-ofile\t- output to the specified file" << endl
00353        << "\t\t-ifile\t- load the usecode file specified by the filename" << endl
00354        << "\t\t-ro\t- output the raw opcodes in addition to the -f format" << endl
00355        << "\t\t-ac\t- output automatically generated comments" << endl
00356        << "\t\t-uc\t- output automatically generated 'useless' comments" << endl
00357        << "\t\t-b\t- only do 'basic' optimisations" << endl
00358        << "\t\t-dbg\t- output debugging information if present in USECODE." << endl
00359        << "\t\t-ext32\t- 'convert' function to ext32 format if not already." << endl
00360        << "\tGame Specifier Flags (only one of these):" << endl
00361        << "\t\t-bg\t- select the black gate usecode file" << endl
00362        << "\t\t-si\t- select the serpent isle usecode file" << endl
00363        << "\t\t-u8\t- select the ultima 8/pagan usecode file (experimental)" << endl
00364        << "\tOutput Format Flags (only one of these):" << endl
00365        << "\t\t-fl\t- output using brief \"list\" format" << endl
00366        << "\t\t-fa\t- output using \"assembler\" format (default)" << endl
00367        << "\t\t-fs\t- output using \"exult script\" format" << endl
00368        << "\t\t-fz\t- output using \"exult script\" format" << endl
00369        << "\t\t-ftt\t- output using the translation table xml format" << endl
00370        << "\t\t-ff\t- outputs all flags referenced in the usecode file" << endl
00371        << "\t\t\t  sorted both by \"flags within a function\" and" << endl
00372        << "\t\t\t  \"functions using flag\"" << endl
00373        ;
00374   exit(1);
00375 }
00376 
00377 
00378 
00379 
00380 
00381 
00382 
00383 
00384 
00385 
00386 
00387 
00388 
00389 
00390 
00391 
00392 
00393 
00394 
00395 
00396 
00397 
00398 
00399 
00400 
00401 

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