/
ScryMUD/mud/
ScryMUD/mud/grrmud/Boards/
ScryMUD/mud/grrmud/Help/
ScryMUD/mud/grrmud/Pfiles/
ScryMUD/mud/grrmud/PlayerSacks/
ScryMUD/mud/grrmud/PlayerShops/
ScryMUD/mud/grrmud/help_filter/
ScryMUD/mud/hegemon/
ScryMUD/mud/hegemon/data/
ScryMUD/mud/hegemon/data/help/battle/
ScryMUD/mud/hegemon/data/help/client/
ScryMUD/mud/hegemon/data/help/communications/
ScryMUD/mud/hegemon/data/help/skills/
ScryMUD/mud/hegemon/data/help/spells/
ScryMUD/mud/include/
ScryMUD/mud/lib/
ScryMUD/mud/lib/bitfield/
ScryMUD/mud/lib/log/
ScryMUD/mud/lib/string2/
// $Id: code_gen.cc,v 1.9.2.1 1999/07/29 04:41:26 greear Exp $
// $Revision: 1.9.2.1 $  $Author: greear $ $Date: 1999/07/29 04:41:26 $

//
//ScryMUD Server Code
//Copyright (C) 1998  Ben Greear
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// To contact the Author, Ben Greear:  greear@cyberhighway.net, (preferred)
//                                     greearb@agcs.com
//


#include <stdio.h>
#include <string2.h>
#include <string.h>
#include "code_gen.h"
#include <fstream.h>
#include <PtrArray.h>

LogStream mudlog("/tmp/code_gen.log", 65535);
int __node_cnt;
int __list_cnt;
int __cell_cnt;

char* header =
"//
//ScryMUD Server Code
//Copyright (C) 1998  Ben Greear
//
// NOTE:  This code was autogenerated by the code_gen.cc program.  If you
// need to make modifications, do it there! --BLG
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// To contact the Author, Ben Greear:  greear@cyberhighway.net, (preferred)
//                                     greearb@agcs.com
//
//
// NOTE:  This code was autogenerated by the code_gen.cc program.  If you
// need to make modifications, do it there! --BLG

";

int core_dump(const char* msg) {
   cerr << "ERROR:  " << msg << endl;
   exit(1);
}

LanguageEntry::LanguageEntry(const LanguageEntry& src)
      : enum_name(src.enum_name) {
   Cell<LVPair*> cll(src.vals);
   LVPair* ptr;
   while ((ptr = cll.next())) {
      vals.append(new LVPair(*ptr));
   }
}//copy constructor


void LanguageEntry::clear() {
   enum_name = "";
   clear_ptr_list(vals);
}//clear

int LanguageEntry::read(ifstream& dafile) {
   char junk[200];
   String tmp_lang(50);
   String tmp_val;

   clear();

   // Grab comments, if there are any.
   while (TRUE) {
      dafile >> enum_name;
      if (!dafile)
         return -1; //EOF
      if (enum_name.charAt(0) == '#') {
         dafile.getline(junk, 200);
      }
      else {
         break;
      }
   }//while
   
   dafile >> tmp_lang; //Language type
   while (tmp_lang != "~") {

      if (!dafile)
         return -1; //EOF

      tmp_val.Clear();
      if (tmp_val.readToken('\"', dafile, TRUE) < 0) {
         cerr << "ERROR: trying to read token: -:" << tmp_val
              << ":-  Exiting." << endl;
         exit(2);
      }//if
      vals.append(new LVPair(tmp_lang, tmp_val));
      
      dafile >> tmp_lang;
   }//while
   return 0;
}//read


String LanguageEntry::getConstArray() const {
   String retval(500);
   String translations[NUM_LANGUAGES];
/*
enum LanguageE {
   English,
   Spanish,
   Portugues,
   Italian,
   LastLanguage
};
*/
   retval = "   {\n      ";
   int slen;

   // NOTE:  To add a new language, modify the while loop below
   // to contain the ones you want to support.  Then make additions
   // to the translation.spec file.
   Cell<LVPair*> cll(vals);
   LVPair* ptr;
   int found_one;
   while ((ptr = cll.next())) {
      slen = ptr->lang.Strlen();
      found_one = FALSE;
      for (int i = 0; i<NUM_LANGUAGES; i++) {
         if (strncasecmp(ptr->lang, languages[i], slen) == 0) {
            translations[i] = ptr->val;
            found_one = TRUE;
            break;
         }
      }
      if (!found_one) {
         cerr << "WARNING: Unknown language: -:" << ptr->lang << ":-" << endl;
      }
   }//while

   for (int i = 0; i<NUM_LANGUAGES; i++) {
      if (translations[i].Strlen()) {
         retval += translations[i];
         if ((i + 1) != NUM_LANGUAGES)
            retval += ",\n      ";
         else
            retval += "\n";
      }
      else {
         if ((i + 1) != NUM_LANGUAGES)
            retval += "NULL,\n      ";
         else
            retval += "NULL\n";
      }//else
   }//for

   retval += "   }";

   return retval;
}//getConstArray


void GenCmdInput::clear() {
   for (int i = 0; i<ALIASES_ARRAY_LEN; i++) {
      aliases[i].Clear();
   }
   help.Clear();
   cmd.Clear();
}

void GenCmdInput::print() { 
   cout << "ALIAS: ";
   for (int i = 0; i<ALIASES_ARRAY_LEN; i++) {
      if (aliases[i].Strlen()) {
         cout << "[" << aliases[i] << "] ";
      }
   }
   cout << "\nHELP: [" << help << "]\n";
   cout << "CMD: [" << cmd << "]\n";
}

int GenCmdInput::read(ifstream& dafile) {
   clear();

   char ch_buf[200];
   String tmp;
   int idx = 0;

   while (TRUE) {
      dafile >> tmp;
      if ((tmp.Strlen() == 0) || (tmp == "~")) {
         // first was a ~, so we are at EOF
         return -1;
      }

      if ((tmp == "#") || (tmp.charAt(0) == '#')) {
         dafile.getline(ch_buf, 199);
         continue;
      }
      else {
         break;
      }
   }//while, read and junk comments

   // no comments allowed within entries.
   while (tmp != "~") {
      //cout << "In while loop, tmp -:" << tmp << ":- idx: " << idx << endl;
      aliases[idx] = tmp;
      idx++;
      dafile >> tmp;
   }

   //cout << "Done with while loop, idx: " << idx << endl;
   if (idx > 1) {
      // last one is the help
      //cout << "Using last one for help.." << endl;
      help = aliases[idx - 1];
      aliases[idx - 1].Clear();
   }
   else if (idx == 1) {
      //cout << "Using first one for help." << endl;
      help = aliases[0]; //default to the first one is the help too
   }
   else {
      return -1; //all done, I spose!
   }

   // junk the first, it's the end of the line of aliases
   cmd.Getline(dafile, 200);

   cmd.Getline(dafile, 200);
   return 0;
}//read


int main(int argc, char** argv) {
   const char* usage = "code_gen -[CL] [input_file_name ...] [out.cc] [out.h]\n";

   if (argc < 5) {
      cerr << usage << endl;
      cerr << "ERROR:  argc should be >= 5, but was: " << argc << endl;
      exit(1);
   }
   
   if (strcasecmp(argv[1], "-C") == 0) {
      // Then create some commands
      return code_gen_commands(argv, argc);
   }
   else if (strcasecmp(argv[1], "-L") == 0) {
      // Create the language array and code
      return code_gen_language(argv, argc);
   }
   else {
      cerr << usage << endl;
      exit(1);
   }
}//main


int code_gen_language(char** argv, int argc) {
   // First, lets parse the incomming file and make sure it's OK.
   PtrArray<LanguageEntry> language_entries;
   LanguageEntry le;

   ofstream of_cc(argv[argc - 2]);
   if (!of_cc) {
      cerr << "ERROR:  could not open output .cc file." << endl;
      exit(1);
   }

   ofstream of_h(argv[argc - 1]);
   if (!of_h) {
      cerr << "ERROR:  could not open output .h file." << endl;
      exit(1);
   }

   int cnt = 0;
   for (int i = 2; i<(argc - 2); i++) {
      ifstream input_file(argv[i]);
      if (!input_file) {
         cerr << "ERROR:  could not open input_file: " << argv[i] << endl;
         exit(1);
      }
      else {
         cout << "Processing spec file: " << argv[i] << endl;
      }
      // If there is a read or parse error, the program will exit
      // inside the le.read() call.
      while (le.read(input_file) >= 0) {
         cnt++;
         language_entries.appendShallowCopy(new LanguageEntry(le));
      }
   }//for

   // If we got to here, then we were able to parse and read the file.

   //First, get the headers out of the way
   of_h << header;

   // NOTE:  If you change the language enum below, you will need to
   // modify the LanguageEntry code, especially the NUM_LANGUAGES #define
   // and the getConstArray() method. --BEN
   of_h << "
#ifndef __INCLUDE_AUTOGEN_LANGUAGE_H__
#define __INCLUDE_AUTOGEN_LANGUAGE_H__

#include <string2.h>

// I expect this may grow.
enum LanguageE {\n";
   for (int j = 0; j<NUM_LANGUAGES; j++) {
      of_h << "   " << languages[j] << "," << endl;
   }
   
   of_h <<"   LastLanguage\n};\n\n";

   // If the ENUM above changes, change this 3 to be equal to
   // the number of languages.
   of_h << "#define LS_PER_ENTRY " << NUM_LANGUAGES 
        << "  /* same as LastLanguage */" << endl;
   of_h << "#define LS_ENTRIES " << cnt 
        << " /* Number of Translation groupings */\n\n";
   of_h << "extern const char* language_strings[LS_ENTRIES][LS_PER_ENTRY];\n";

   of_h << "\nenum CSentryE {\n";

   for (int i = 0; i<cnt; i++) {
      of_h << "   " << language_entries[i]->getEnumName();
      if ((i + 1) != cnt)
         of_h << "," << endl;
      else
         of_h << endl;
   }

   of_h << "};//CSentryE enum\n\n";
   of_h << "
class CSHandler {
public:
   static const char* getString(CSentryE which_string, LanguageE language);
};


#endif\n";
   of_h << flush;

   // Done with .h file, lets start on the .cc file
   of_cc << header;
   of_cc << "

#include \"lang_strings.h\"

const char* language_strings[LS_ENTRIES][LS_PER_ENTRY] = {\n";

   for (int i = 0; i<cnt; i++) {
      of_cc << " /* " << language_entries[i]->getEnumName() << " */" << endl;
      of_cc << language_entries[i]->getConstArray();
      if ((i + 1) != cnt)
         of_cc << ",\n\n";
      else
         of_cc << endl;
   }//for
   
   of_cc << "}; //language_strings\n\n";

   of_cc << "
const char* CSHandler::getString(CSentryE which_string, LanguageE language) {
   const char* retval = language_strings[(int)(which_string)][(int)(language)];
   if (retval) {
      return retval;
   }
   else {
      // Default to English...
      // TODO:  Be smarter here, ie Portuguese defaults to Spanish??
      return language_strings[(int)(which_string)][0];
   }//else
}//getString\n\n";

   of_cc << flush;

   return 0;
}//code_gen_language


   
int code_gen_commands(char** argv, int argc) {
   String buf(200);
   String tmp(200);
   String cmd_enum(1000);
   String cmd_instantiations(10000);
   String exe_cmds(5000);
   String cmd_array(1000);

   // add the starting stuff.
   cmd_enum.Append("enum CmdId {\n");
   cmd_instantiations.Append("#define ADD_NEW_CMD cmds_collection.addCmdSpecifierNoCreate

void initCmdsCollection() { \n");

   exe_cmds.Append("//Add a few #defines to cut down on the huge file size!\n\n");
   exe_cmds.Append("
#define CODE_GEN_EXE_HEADER \
String& str1, String& str2, String& str3, String& str4, \
String& str5, int i, int j, int k, int l, int m, int n,\
int& is_dead, critter& pc, critter* c_script_owner, \
room* r_script_owner, String* cooked_strs, int* cooked_ints, \
int do_sub, int sanity, int was_ordered
\n");

   // Hopefully, a smart compiler will get rid of this test.  It's
   // here to keep the compiler from complaining about un-used variables.
   // --BLG
   exe_cmds.Append("
#define CODE_GEN_VAR_TEST_IF \
1 || &str1 || &str2 || &str3 || &str4 || &str5 || i || j || k || l \
|| m || n || is_dead || &pc ||c_script_owner || r_script_owner \
|| cooked_strs || cooked_ints || do_sub || sanity || was_ordered\n\n");


   exe_cmds.Append("
class ExeCmd {
public:
   virtual int execute(CODE_GEN_EXE_HEADER) = 0; //pure virtual
};\n");


   cmd_array.Append("void initCmdsArray() {\n");


   ofstream of_cc(argv[argc - 2]);
   if (!of_cc) {
      cerr << "ERROR:  could not open output .cc file." << endl;
      exit(1);
   }

   ofstream of_h(argv[argc - 1]);
   if (!of_h) {
      cerr << "ERROR:  could not open output .h file." << endl;
      exit(1);
   }

   //TODO:  Never tested w/two spec files...I fear blowup!! --BEN
   int cmd_count = 0;
   int done_exe_already = FALSE;
   for (int i = 2; i<(argc - 2); i++) {
      ifstream input_file(argv[i]);
      if (!input_file) {
         cerr << "ERROR:  could not open input_file: " << argv[i] << endl;
         exit(1);
      }
      else {
         cout << "Processing spec file: " << argv[i] << endl;
      }

      GenCmdInput cmd_input;
      while (input_file) {
         if (cmd_input.read(input_file) == -1) {
            // all done
            break;
         }

         // debugging
         //cmd_input.print();

         if (cmd_input.help.charAt(0) != '*') { // help only
            // create the commands, and the enum, and the ExeCmds
            Sprintf(tmp, "   ci_%S,\n", &(cmd_input.aliases[0]));
            cmd_enum.Append(tmp);
         }

         done_exe_already = FALSE;
         for (int i = 0; i<ALIASES_ARRAY_LEN; i++) {
            if (cmd_input.aliases[i].Strlen() == 0)
               break;

            if (cmd_input.help.charAt(0) == '*') { // help only
               Sprintf(tmp, "   ADD_NEW_CMD(new CmdSpecifier(\"%S\", %i, ci_HELP_ONLY, \"%s\"));\n",
                       &(cmd_input.aliases[i]), 
                       cmd_input.aliases[i].Strlen(),
                       ((const char*)(cmd_input.help)) + 1); //move past *
               cmd_instantiations.Append(tmp);
            }
            else {
               Sprintf(tmp, "   ADD_NEW_CMD(new CmdSpecifier(\"%S\", %i, ci_%S, \"%S\"));\n",
                       &(cmd_input.aliases[i]), cmd_input.aliases[i].Strlen(),
                       &(cmd_input.aliases[0]), &(cmd_input.help));
               cmd_instantiations.Append(tmp);

               if (!done_exe_already) {
                  cmd_count++;
                  Sprintf(tmp, "
class ExeCmd_%S : public ExeCmd {
public:
   int execute(CODE_GEN_EXE_HEADER) {
      if (CODE_GEN_VAR_TEST_IF) {
         %S
      } else return 0;
   }//execute
};//ExeCmd\n",
                          &(cmd_input.aliases[0]), &(cmd_input.cmd));

                  exe_cmds.Append(tmp);

                  // Now, lets add the code that will place this in an array.
                  
                  Sprintf(tmp, "   exe_cmd_array[(int)(ci_%S)] = new ExeCmd_%S;\n",
                          &(cmd_input.aliases[0]), &(cmd_input.aliases[0]));
                  cmd_array.Append(tmp);
                  
                  done_exe_already = TRUE;
               }//if not done_exe_already
            }//else
         }//for
      }//while
   }//for all spec files

   // Now, have read everything in..lets put the code together.

   of_h << header;
   of_h << "
#ifndef __INCLUDE_AUTOGEN_CMD_H__
#define __INCLUDE_AUTOGEN_CMD_H__

#include \"ar_skll.h\"
#include \"cr_skll.h\"
#include \"social2.h\"
#include \"ez_skll.h\"
#include \"dam_skll.h\"
#include \"misc.h\"
#include \"misc2.h\"
#include \"commands.h\"
#include \"command2.h\"
#include \"command3.h\"
#include \"command4.h\"
#include \"command5.h\"
#include \"spells.h\"
#include \"skills.h\"
#include \"olc.h\"
#include \"olc2.h\"
#include \"socials.h\"
#include \"classes.h\"
#include \"wep_skll.h\"
#include \"parse.h\"
#include \"script.h\"\n\n";

   of_cc << header;
   of_cc << "#include \"code_gen.h\"\n";
   of_cc << "#include \"parse.h\"\n";

   // Terminate the constructs.
   cmd_enum.Append("   ci_HELP_ONLY,\n");
   cmd_enum.Append("   ci_UNKNOWN,\n");
   cmd_enum.Append("   ci_MAX_VALUE\n};\n\n");
   cmd_instantiations.Append("}// initCmdsCollection\n\n");
   // exe_cmds should be fine
   cmd_array.Append("}//End of ExeCmd array assignment\n\n");

   // Lets do the .h file first.  Assume #includes already done.
   of_h << "class ExeCmd; //foward declaration\n\n";
   of_h << "\nextern ExeCmd* exe_cmd_array[" << cmd_count + 1 << "];\n\n";
   of_h << cmd_enum << endl;
   of_h << exe_cmds << endl;
   of_h << "\n\n#endif";

   // Now, the .cc file
   of_cc << "ExeCmd* exe_cmd_array[" << cmd_count + 1 << "];\n\n";
   of_cc << cmd_instantiations << endl;
   of_cc << cmd_array << endl;

   return 0;
}//code_gen_commands