Pol  Revision:e09f183
ecompile/ecompile.cpp
Go to the documentation of this file.
00001 /*
00002 History
00003 =======
00004 
00005 Notes
00006 =======
00007 
00008 */
00009 
00010 #include "../clib/xmain.h"
00011 #include "../clib/Program/ProgramConfig.h"
00012 #include "../clib/clib.h"
00013 #include "../clib/dirlist.h"
00014 #include "../clib/fileutil.h"
00015 #include "../clib/logfacility.h"
00016 #include "../clib/mdump.h"
00017 #include "../clib/timer.h"
00018 
00019 #include "../plib/pkg.h"
00020 #include "../plib/systemstate.h"
00021 
00022 #include "../bscript/compilercfg.h"
00023 #include "../bscript/filefmt.h"
00024 #include "../bscript/userfunc.h"
00025 #include "../bscript/compiler.h"
00026 #include "../bscript/escriptv.h"
00027 #include "../bscript/executor.h"
00028 #include "../bscript/userfunc.h"
00029 
00030 #include <cstring>
00031 #include <cstdio>
00032 #include <memory>
00033 #include <string>
00034 
00035 #include <stdexcept>
00036 
00037 #ifdef _MSC_VER
00038 #pragma warning(disable:4996) // deprecated POSIX getenv, strcpy warning
00039 #endif
00040 
00041 namespace Pol {
00042   namespace Bscript {
00043     ExecInstrFunc Executor::GetInstrFunc( const Token& /*token*/ )
00044     {
00045       return NULL;
00046     }
00047   }
00048 }
00049 
00050 namespace Pol {
00051   namespace Ecompile {
00052     using namespace Bscript;
00053 #if REFPTR_DEBUG
00054     unsigned int ref_counted::_ctor_calls;
00055 #endif
00056 
00057     int debug = 0;
00058     bool quiet = false;
00059     bool opt_generate_wordlist = false;
00060     bool keep_building = false;
00061     bool verbose = false;
00062     bool force_update = false;
00063     bool show_timing_details = false;
00064     bool timing_quiet_override = false;
00065     bool expect_compile_failure = false;
00066     bool dont_optimize_object_members = false;
00067     std::string EmPathEnv; // "ECOMPILE_PATH_EM=xxx"
00068     std::string IncPathEnv; // ECOMPILE_PATH_INC=yyy"
00069     std::string CfgPathEnv; // ECOMPILE_CFG_PATH=zzz"
00070 
00071     struct Summary
00072     {
00073       unsigned UpToDateScripts;
00074       unsigned CompiledScripts;
00075       unsigned ScriptsWithCompileErrors;
00076     } summary;
00077 
00078     void usage( void )
00079     {
00080       ERROR_PRINT << " Usage:\n"
00081         << "   " << "ECOMPILE [options] filespec [filespec ...]\n"
00082         << "   Output is : filespec.ecl\n"
00083         << "   Options: \n"
00084         << "       -a           compile *.asp pages also\n"
00085         << "       -A           automatically compile scripts in main and enabled packages\n"
00086         << "       -Au          (as '-A' but only compile updated files)\n"
00087         << "       -b           keep building other scripts after errors\n"
00088         << "       -C cfgpath   path to configuration (replaces ecompile.cfg)\n"
00089         << "       -d           display confusing compiler parse information\n"
00090         << "       -D           write dependency information\n"
00091         << "       -e           report error on successful compilation (used for testing)\n"
00092 #ifdef WIN32
00093         << "       -Ecfgpath    set or change the ECOMPILE_CFG_PATH Evironment Variable\n"
00094 #endif
00095         << "       -i           include intrusive debug info in .ecl file\n"
00096         << "       -l           generate listfile\n"
00097         << "       -m           don't optimize object members\n"
00098 #ifdef WIN32
00099         << "       -Pdir        set or change the EM and INC files Environment Variables\n"
00100 #endif
00101         << "       -q           quiet mode (suppress normal output)\n"
00102         << "       -r [dir]     recurse folder [from 'dir'] (defaults to current folder)\n"
00103         << "       -ri [dir]      (as '-r' but only compile .inc files)\n"
00104         << "         -t[v]      show timing/profiling information [override quiet mode]\n"
00105         << "         -u         compile only updated scripts (.src newer than .ecl)\n"
00106         << "           -f       force compile even if up-to-date\n"
00107         << "       -s           display summary if -q is not set\n"
00108         << "       -T           use threaded compilation\n"
00109         << "       -vN          verbosity level\n"
00110         << "       -w           display warnings\n"
00111         << "       -W           generate wordfile\n"
00112         << "       -y           treat warnings as errors\n"
00113         << "       -x           write external .dbg file\n"
00114         << "       -xt          write external .dbg.txt info file\n"
00115         << "\n"
00116         << " NOTE:\n"
00117         << "   If <filespec> are required after an empty -r[i] option, you MUST specify\n"
00118         << "   a literal [dir] of '.' (no quotes) or options will not parse correctly.\n";
00119       if ( Clib::Logging::global_logger )
00120         Clib::Logging::global_logger->wait_for_empty_queue();
00121     }
00122 
00123     void generate_wordlist()
00124     {
00125       INFO_PRINT << "Writing word list to wordlist.txt\n";
00126       std::ofstream ofs("wordlist.txt", std::ios::out | std::ios::trunc);
00127       Parser::write_words( ofs );
00128     }
00129 
00130     void compile_inc( const char* path )
00131     {
00132       if ( !quiet )
00133         INFO_PRINT << "Compiling: " << path << "\n";
00134 
00135       Compiler C;
00136 
00137       C.setQuiet( !debug );
00138       C.setIncludeCompileMode();
00139       int res = C.compileFile( path );
00140 
00141       if ( res )
00142           throw std::runtime_error("Error compiling file");
00143     }
00144 
00145     bool compile_file( const char *path )
00146     {
00147         std::string fname(path);
00148         std::string filename_src = fname, ext("");
00149 
00150         std::string::size_type pos = fname.rfind(".");
00151         if (pos != std::string::npos)
00152         ext = fname.substr( pos );
00153 
00154       if ( !ext.compare( ".inc" ) )
00155       {
00156         compile_inc( path );
00157         return true;
00158       }
00159 
00160       if ( ext.compare( ".src" ) != 0 &&
00161            ext.compare( ".hsr" ) != 0 &&
00162            ext.compare( ".asp" ) != 0 )
00163       {
00164         INFO_PRINT << "Didn't find '.src', '.hsr', or '.asp' extension on source filename '"
00165           << path << "'!\n";
00166         throw std::runtime_error("Error in source filename");
00167       }
00168       std::string filename_ecl = fname.replace(pos, 4, ".ecl");
00169       std::string filename_lst = fname.replace(pos, 4, ".lst");
00170       std::string filename_dep = fname.replace(pos, 4, ".dep");
00171       std::string filename_dbg = fname.replace(pos, 4, ".dbg");
00172 
00173       if ( compilercfg.OnlyCompileUpdatedScripts && !force_update )
00174       {
00175         bool all_old = true;
00176         unsigned int ecl_timestamp = Clib::GetFileTimestamp( filename_ecl.c_str() );
00177         if ( Clib::GetFileTimestamp( filename_src.c_str( ) ) >= ecl_timestamp )
00178         {
00179           if ( verbose )
00180             INFO_PRINT << filename_src << " is newer than " << filename_ecl << "\n";
00181           all_old = false;
00182         }
00183 
00184         if ( all_old )
00185         {
00186           std::ifstream ifs(filename_dep.c_str());
00187           // if the file doesn't exist, gotta build.
00188           if ( ifs.is_open() )
00189           {
00190             std::string depname;
00191             while ( getline( ifs, depname ) )
00192             {
00193               if ( Clib::GetFileTimestamp( depname.c_str( ) ) >= ecl_timestamp )
00194               {
00195                 if ( verbose )
00196                   INFO_PRINT << depname << " is newer than " << filename_ecl << "\n";
00197                 all_old = false;
00198                 break;
00199               }
00200             }
00201           }
00202           else
00203           {
00204             if ( verbose )
00205               INFO_PRINT << filename_dep << " does not exist." << "\n";
00206             all_old = false;
00207           }
00208         }
00209         if ( all_old )
00210         {
00211           if ( !quiet && compilercfg.DisplayUpToDateScripts )
00212             INFO_PRINT << filename_ecl << " is up-to-date." << "\n";
00213           return false;
00214         }
00215 
00216       }
00217 
00218       {
00219         if ( !quiet )
00220           INFO_PRINT << "Compiling: " << path << "\n";
00221 
00222         Compiler C;
00223 
00224         C.setQuiet( !debug );
00225         int res = C.compileFile( path );
00226 
00227         if ( expect_compile_failure )
00228         {
00229           if ( res )        // good, it failed
00230           {
00231             if ( !quiet )
00232               INFO_PRINT << "Compilation failed as expected." << "\n";
00233             return true;
00234           }
00235           else
00236           {
00237               throw std::runtime_error("Compilation succeeded (-e indicates failure was expected)");
00238           }
00239         }
00240 
00241         if ( res )
00242             throw std::runtime_error("Error compiling file");
00243 
00244 
00245 
00246         if ( !quiet )
00247           INFO_PRINT << "Writing:   " << filename_ecl << "\n";
00248 
00249         if ( C.write( filename_ecl.c_str() ) )
00250         {
00251             throw std::runtime_error("Error writing output file");
00252         }
00253 
00254         if ( compilercfg.GenerateListing )
00255         {
00256           if ( !quiet )
00257             INFO_PRINT << "Writing:   " << filename_lst << "\n";
00258           std::ofstream ofs(filename_lst.c_str());
00259           C.dump( ofs );
00260         }
00261         else if ( Clib::FileExists( filename_lst.c_str( ) ) )
00262         {
00263           if ( !quiet ) INFO_PRINT << "Deleting:  " << filename_lst << "\n";
00264           Clib::RemoveFile( filename_lst );
00265         }
00266 
00267         if ( compilercfg.GenerateDebugInfo )
00268         {
00269           if ( !quiet )
00270           {
00271             INFO_PRINT << "Writing:   " << filename_dbg << "\n";
00272             if ( compilercfg.GenerateDebugTextInfo )
00273               INFO_PRINT << "Writing:   " << filename_dbg << ".txt" << "\n";
00274           }
00275           C.write_dbg( filename_dbg.c_str(), compilercfg.GenerateDebugTextInfo );
00276         }
00277         else if ( Clib::FileExists( filename_dbg.c_str( ) ) )
00278         {
00279           if ( !quiet ) INFO_PRINT << "Deleting:  " << filename_dbg << "\n";
00280           Clib::RemoveFile( filename_dbg );
00281         }
00282 
00283         if ( compilercfg.GenerateDependencyInfo )
00284         {
00285           if ( !quiet )
00286             INFO_PRINT << "Writing:   " << filename_dep << "\n";
00287           C.writeIncludedFilenames( filename_dep.c_str() );
00288         }
00289         else if ( Clib::FileExists( filename_dep.c_str( ) ) )
00290         {
00291           if ( !quiet ) INFO_PRINT << "Deleting:  " << filename_dep << "\n";
00292           Clib::RemoveFile( filename_dep );
00293         }
00294 
00295       }
00296       return true;
00297     }
00298 
00299     void compile_file_wrapper( const char* path )
00300     {
00301       try
00302       {
00303         if ( compile_file( path ) )
00304           ++summary.CompiledScripts;
00305         else
00306           ++summary.UpToDateScripts;
00307       }
00308       catch ( std::exception& )
00309       {
00310         ++summary.CompiledScripts;
00311         ++summary.ScriptsWithCompileErrors;
00312         if ( !keep_building )
00313           throw;
00314       }
00315     }
00316 
00317     bool setting_value( const char* arg )
00318     {
00319       // format of arg is -C or -C-
00320       if ( arg[2] == '\0' )
00321         return true;
00322       else if ( arg[2] == '-' )
00323         return false;
00324       else if ( arg[2] == '+' )
00325         return true;
00326       else
00327         return true;
00328     }
00329 
00330 
00331     int readargs( int argc, char **argv )
00332     {
00333       bool unknown_opt = false;
00334 
00335       for ( int i = 1; i < argc; i++ )
00336       {
00337         const char* arg = argv[i];
00338 #ifdef __linux__
00339         if ( arg[0] == '-' )
00340 #else
00341         if ( arg[0] == '/' || arg[0] == '-' )
00342 #endif
00343         {
00344           switch ( arg[1] )
00345           {
00346             case 'A': // skip it at this point.
00347               break;
00348 
00349             case 'C': // skip it at this point.
00350               ++i; // and skip its parameter.
00351               break;
00352 
00353             case 'd':
00354               debug = 1;
00355               break;
00356 
00357             case 'D':
00358               compilercfg.GenerateDependencyInfo = setting_value( arg );
00359               break;
00360 
00361             case 'e':
00362               expect_compile_failure = true;
00363               break;
00364 
00365 #ifdef WIN32
00366             case 'E':
00367             {
00368                       std::string path = &argv[i][2];
00369                       CfgPathEnv = "ECOMPILE_CFG_PATH=" + path;
00370                       _putenv( CfgPathEnv.c_str() );
00371             }
00372               break;
00373 #endif
00374 
00375             case 'q':
00376               quiet = true;
00377               break;
00378 
00379             case 'w':
00380               compilercfg.DisplayWarnings = setting_value( arg );
00381               if ( argv[i][2] == 'P' )
00382                 compilercfg.ParanoiaWarnings = true;
00383               break;
00384             case 'y':
00385               compilercfg.ErrorOnWarning = setting_value( arg );
00386               break;
00387 
00388             case 'l':
00389               compilercfg.GenerateListing = setting_value( arg );
00390               break;
00391 
00392             case 'i':
00393               include_debug = 1;
00394               break;
00395 
00396             case 'r': // -r[i] [dir] is okay
00397               // Only suboption allowed is '-ri' (.inc recurse)
00398               if ( argv[i][2] && argv[i][2] != 'i' )
00399               {
00400                 // BZZZZT! *error*
00401                 unknown_opt = true;
00402                 break;
00403               }
00404 
00405               // Only skip next parameter if it's not an option!!
00406 #ifdef __linux__
00407               if ( i+1<argc && argv[i+1][0] != '-' )
00408 #else
00409               if ( i + 1 < argc && argv[i + 1][0] != '/' && argv[i + 1][0] != '-' )
00410 #endif                  
00411                 ++i;
00412               break;
00413 
00414             case 't':
00415               show_timing_details = true;
00416               if ( argv[i][2] == 'v' )
00417                 timing_quiet_override = true;
00418               break;
00419 
00420             case 's':
00421               // show_source = true;
00422               compilercfg.DisplaySummary = true;
00423               break;
00424 
00425             case 'W':
00426               opt_generate_wordlist = true;
00427               break;
00428 
00429             case 'a':
00430               compilercfg.CompileAspPages = setting_value( arg );
00431               break;
00432 
00433             case 'm':
00434               compilercfg.OptimizeObjectMembers = false;
00435               break;
00436 
00437             case 'b':
00438               keep_building = true;
00439               break;
00440 
00441             case 'u':
00442               compilercfg.OnlyCompileUpdatedScripts = setting_value( arg );
00443               if ( compilercfg.OnlyCompileUpdatedScripts )
00444                 compilercfg.GenerateDependencyInfo = true;
00445               break;
00446 
00447             case 'f':
00448               force_update = true;
00449               break;
00450 
00451             case 'v':
00452               verbose = true;
00453               int vlev;
00454               vlev = atoi( &argv[i][2] );
00455               if ( !vlev )
00456                 vlev = 1;
00457               Compiler::setVerbosityLevel( vlev );
00458               break;
00459 
00460             case 'x':
00461               compilercfg.GenerateDebugInfo = setting_value( arg );
00462               compilercfg.GenerateDebugTextInfo = ( argv[i][2] == 't' );
00463               break;
00464 
00465 #ifdef WIN32
00466             case 'P':
00467             {
00468                       std::string path = &argv[i][2];
00469                       EmPathEnv = "ECOMPILE_PATH_EM=" + path;
00470                       IncPathEnv = "ECOMPILE_PATH_INC=" + path;
00471                       _putenv( EmPathEnv.c_str() );
00472                       _putenv( IncPathEnv.c_str() );
00473             }
00474               break;
00475 #endif
00476             case 'T':
00477               compilercfg.ThreadedCompilation = true;
00478               break;
00479 
00480             default:
00481               unknown_opt = true;
00482               break;
00483           }
00484         }
00485 
00486         if ( unknown_opt )
00487         {
00488           ERROR_PRINT << "Unknown option: " << argv[i] << "\n";
00489           usage();
00490           return 1;
00491         }
00492       }
00493       return 0;
00494     }
00495 
00496     void recurse_compile(const std::string& basedir, std::vector<std::string>* files)
00497     {
00498       int s_compiled, s_uptodate, s_errors;
00499       clock_t start, finish;
00500 
00501       if ( !Clib::IsDirectory( basedir.c_str( ) ) )
00502         return;
00503 
00504       s_compiled = s_uptodate = s_errors = 0;
00505       start = clock();
00506       for ( Clib::DirList dl( basedir.c_str( ) ); !dl.at_end( ); dl.next( ) )
00507       {
00508           std::string name = dl.name(), ext;
00509         if ( name[0] == '.' ) continue;
00510 
00511         std::string::size_type pos = name.rfind(".");
00512         if (pos != std::string::npos)
00513           ext = name.substr( pos );
00514 
00515         try
00516         {
00517             if (pos != std::string::npos &&
00518                ( !ext.compare( ".src" ) ||
00519                !ext.compare( ".hsr" ) ||
00520                ( compilercfg.CompileAspPages && !ext.compare( ".asp" ) ) ) )
00521           {
00522             s_compiled++;
00523             if ( files == NULL )
00524             {
00525               if ( compile_file( ( basedir + name ).c_str() ) )
00526               {
00527                 ++summary.CompiledScripts;
00528               }
00529               else
00530               {
00531                 ++s_uptodate;
00532                 ++summary.UpToDateScripts;
00533               }
00534             }
00535             else
00536               files->push_back( ( basedir + name ) );
00537           }
00538           else
00539           {
00540             recurse_compile( basedir + name + "/", files );
00541           }
00542         }
00543         catch ( std::exception& )
00544         {
00545           ++summary.CompiledScripts;
00546           ++summary.ScriptsWithCompileErrors;
00547           if ( !keep_building )
00548             throw;
00549           s_errors++;
00550         }
00551       }
00552       if ( files == NULL )
00553         return;
00554       finish = clock();
00555 
00556       if ( ( !quiet || timing_quiet_override ) && show_timing_details && s_compiled > 0 && files == NULL )
00557       {
00558         INFO_PRINT << "Compiled " << s_compiled << " script" << ( s_compiled == 1 ? "" : "s" )
00559           << " in " << basedir
00560           << " in " << (int)( ( finish - start ) / CLOCKS_PER_SEC ) << " second(s)\n";
00561         if ( s_uptodate > 0 )
00562           INFO_PRINT << "    " << s_uptodate << " script" << ( s_uptodate == 1 ? " was" : "s were" )
00563           << " already up-to-date.\n";
00564         if ( s_errors > 0 )
00565           INFO_PRINT << "    " << s_errors << " script" << ( s_errors == 1 ? "" : "s" )
00566           << " had errors.\n";
00567       }
00568     }
00569     void recurse_compile_inc(const std::string& basedir, std::vector<std::string>* files)
00570     {
00571       for ( Clib::DirList dl( basedir.c_str( ) ); !dl.at_end( ); dl.next( ) )
00572       {
00573         std::string name = dl.name(), ext;
00574         if ( name[0] == '.' ) continue;
00575 
00576         std::string::size_type pos = name.rfind(".");
00577         if (pos != std::string::npos)
00578           ext = name.substr( pos );
00579 
00580         if (pos != std::string::npos && !ext.compare(".inc"))
00581         {
00582           if ( files == NULL )
00583             compile_file( ( basedir + name ).c_str() );
00584           else
00585             files->push_back( ( basedir + name ) );
00586         }
00587         else
00588         {
00589           recurse_compile( basedir + name + "/", files );
00590         }
00591       }
00592     }
00593 
00594     void parallel_compile(const std::vector<std::string> &files)
00595     {
00596       unsigned compiled_scripts = 0;
00597       unsigned uptodate_scripts = 0;
00598       unsigned error_scripts = 0;
00599       bool omp_keep_building = true;
00600 #pragma omp parallel for reduction(+ : compiled_scripts, uptodate_scripts, error_scripts) shared(omp_keep_building)
00601       for ( int i = 0; i < (int)files.size(); ++i )
00602       {
00603 #pragma omp flush(omp_keep_building)
00604         if ( omp_keep_building )
00605         {
00606           try
00607           {
00608             if ( compile_file( files[i].c_str() ) )
00609               ++compiled_scripts;
00610             else
00611               ++uptodate_scripts;
00612           }
00613           catch ( std::exception& e )
00614           {
00615             ++compiled_scripts;
00616             ++error_scripts;
00617             ERROR_PRINT << "failed to compile " << e.what() << "\n";
00618             if ( !keep_building )
00619             {
00620 #pragma omp critical(building_break)
00621               omp_keep_building = false;
00622               //Clib::force_backtrace();
00623             }
00624           }
00625           catch ( ... )
00626           {
00627 #pragma omp critical(building_break)
00628             omp_keep_building = false;
00629             Clib::force_backtrace( );
00630           }
00631 
00632         }
00633       }
00634       summary.CompiledScripts = compiled_scripts;
00635       summary.UpToDateScripts = uptodate_scripts;
00636       summary.ScriptsWithCompileErrors = error_scripts;
00637     }
00638 
00639     void AutoCompile()
00640     {
00641       bool save = compilercfg.OnlyCompileUpdatedScripts;
00642       compilercfg.OnlyCompileUpdatedScripts = compilercfg.UpdateOnlyOnAutoCompile;
00643       if ( compilercfg.ThreadedCompilation )
00644       {
00645           std::vector<std::string> files;
00646         recurse_compile( Clib::normalized_dir_form( compilercfg.PolScriptRoot ), &files );
00647         for ( const auto &pkg : Plib::systemstate.packages )
00648         {
00649           recurse_compile( Clib::normalized_dir_form( pkg->dir( ) ), &files );
00650         }
00651         parallel_compile( files );
00652       }
00653       else
00654       {
00655         recurse_compile( Clib::normalized_dir_form( compilercfg.PolScriptRoot ), NULL );
00656         for ( const auto &pkg : Plib::systemstate.packages )
00657         {
00658           recurse_compile( Clib::normalized_dir_form( pkg->dir() ), NULL );
00659         }
00660       }
00661       compilercfg.OnlyCompileUpdatedScripts = save;
00662     }
00663 
00664     bool run( int argc, char **argv )
00665     {
00666       for ( const auto &elem : compilercfg.PackageRoot )
00667       {
00668         Plib::load_packages( elem, true /* quiet */ );
00669       }
00670       Plib::replace_packages();
00671       Plib::check_package_deps();
00672 
00673       Tools::Timer<> timer;
00674       bool any = false;
00675 
00676       for ( int i = 1; i < argc; i++ )
00677       {
00678 #ifdef __linux__    
00679         if (argv[i][0] == '-')
00680 #else
00681         if ( argv[i][0] == '/' || argv[i][0] == '-' )
00682 #endif
00683         {
00684           // -r[i] [<dir>]
00685           if ( argv[i][1] == 'A' )
00686           {
00687             compilercfg.UpdateOnlyOnAutoCompile = ( argv[i][2] == 'u' );
00688             any = true;
00689 
00690             AutoCompile();
00691           }
00692           else if ( argv[i][1] == 'r' )
00693           {
00694             any = true;
00695             std::string dir(".");
00696             bool compile_inc = ( argv[i][2] == 'i' ); // compile .inc files
00697 
00698             ++i;
00699             if ( i < argc && argv[i] && argv[i][0] != '-' )
00700               dir.assign( argv[i] );
00701 
00702             if ( compilercfg.ThreadedCompilation )
00703             {
00704                 std::vector<std::string> files;
00705               if ( compile_inc )
00706                 recurse_compile_inc( Clib::normalized_dir_form( dir ), &files );
00707               else
00708                 recurse_compile( Clib::normalized_dir_form( dir ), &files );
00709               parallel_compile( files );
00710             }
00711             else
00712             {
00713               if ( compile_inc )
00714                 recurse_compile_inc( Clib::normalized_dir_form( dir ), NULL );
00715               else
00716                 recurse_compile( Clib::normalized_dir_form( dir ), NULL );
00717             }
00718           }
00719           else if ( argv[i][1] == 'C' )
00720           {
00721             ++i; // skip the config file pathname
00722           }
00723           // and skip any other option.
00724         }
00725         else
00726         {
00727           any = true;
00728 #ifdef _WIN32
00729           Clib::forspec( argv[i], compile_file_wrapper );
00730 #else
00731           compile_file_wrapper( argv[i] );
00732 #endif
00733         }
00734       }
00735 
00736       if ( !any && compilercfg.AutoCompileByDefault )
00737       {
00738         any = true;
00739         AutoCompile();
00740       }
00741 
00742       timer.stop();
00743 
00744       Plib::systemstate.deinitialize();
00745 
00746       if ( any && compilercfg.DisplaySummary && !quiet )
00747       {
00748         fmt::Writer tmp;
00749         tmp << "Compilation Summary:\n";
00750         if ( summary.CompiledScripts )
00751           tmp << "    Compiled " << summary.CompiledScripts << " script" << ( summary.CompiledScripts == 1 ? "" : "s" )
00752           << " in " << timer.ellapsed() << " ms.\n";
00753 
00754         if ( summary.ScriptsWithCompileErrors )
00755           tmp << "    " << summary.ScriptsWithCompileErrors << " of those script" << ( summary.ScriptsWithCompileErrors == 1 ? "" : "s" )
00756           << " had errors.\n";
00757 
00758         if ( summary.UpToDateScripts )
00759           tmp << "    " << summary.UpToDateScripts << " script" << ( summary.UpToDateScripts == 1 ? " was" : "s were" )
00760           << " already up-to-date.\n";
00761         INFO_PRINT << tmp.str();
00762       }
00763 
00764       return any;
00765     }
00766 
00767     void read_config_file( int argc, char* argv[] )
00768     {
00769       for ( int i = 1; i < argc; i++ )
00770       {
00771         if ( argv[i][0] == '/' || argv[i][0] == '-' )
00772         {
00773           // -C cfgpath
00774           if ( argv[i][1] == 'C' )
00775           {
00776             ++i;
00777             if ( i == argc )
00778                 throw std::runtime_error("-C specified without pathname");
00779 
00780             compilercfg.Read(std::string(argv[i]));
00781             return;
00782           }
00783         }
00784       }
00785 
00786       // check ECOMPILE_CFG_PATH environment variable
00787       const char* env_ecompile_cfg_path = getenv( "ECOMPILE_CFG_PATH" );
00788       if ( env_ecompile_cfg_path != NULL )
00789       {
00790           compilercfg.Read(std::string(env_ecompile_cfg_path));
00791         return;
00792       }
00793 
00794       // no -C arg, so use binary path (hope it's right..sigh.)
00795       std::string cfgpath = PROG_CONFIG::programDir() + "ecompile.cfg";
00796       if ( Clib::FileExists( "ecompile.cfg" ) )
00797       {
00798         compilercfg.Read( "ecompile.cfg" );
00799       }
00800       else if ( Clib::FileExists( cfgpath ) )
00801       {
00802         compilercfg.Read( cfgpath );
00803       }
00804       else
00805       {
00806         ERROR_PRINT << "Could not find " << cfgpath << "; using defaults.\n";
00807         compilercfg.SetDefaults();
00808       }
00809     }
00810   }
00811 
00812 
00813 
00814   int xmain( int argc, char *argv[] )
00815   {
00816     int progver = 1; //TODO: use a better solution here
00817 
00818 #ifdef _WIN32
00819     Clib::MiniDumper::Initialize();
00820 #endif
00821 
00822     Ecompile::read_config_file( argc, argv );
00823 
00824     int res = Ecompile::readargs( argc, argv );
00825     if ( res )
00826       return res;
00827 
00828     if ( !Ecompile::quiet )
00829     {
00830       // vX.YY
00831       double vernum = (double)progver + (double)( ESCRIPT_FILE_VER_CURRENT / 100.0f );
00832       ERROR_PRINT << "EScript Compiler v" << vernum << "\n"
00833         << "Copyright (C) 1993-2015 Eric N. Swanson\n\n";
00834     }
00835 
00836     if ( Ecompile::opt_generate_wordlist )
00837     {
00838       Ecompile::generate_wordlist( );
00839       return 0;
00840     }
00841 
00842     bool didanything = Ecompile::run( argc, argv );
00843 
00844     if ( !didanything )
00845     {
00846       Ecompile::usage( );
00847       return 1;
00848     }
00849     else
00850     {
00851       return 0;
00852     }
00853   }
00854 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines