00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00032
00033 #ifndef GROOVX_TCL_SCRIPTAPP_CC_UTC20050628162421_DEFINED
00034 #define GROOVX_TCL_SCRIPTAPP_CC_UTC20050628162421_DEFINED
00035
00036 #include "tcl/scriptapp.h"
00037
00038 #include "nub/objfactory.h"
00039
00040 #include "rutz/sfmt.h"
00041
00042 #include "tcl/list.h"
00043 #include "tcl/eventloop.h"
00044 #include "tcl/pkg.h"
00045 #include "tcl/interp.h"
00046
00047 #include <cstring>
00048 #include <iostream>
00049 #include <signal.h>
00050 #include <sstream>
00051 #include <tk.h>
00052
00053 #include "rutz/debug.h"
00054 GVX_DBG_REGISTER
00055 #include "rutz/trace.h"
00056
00057 namespace
00058 {
00059
00060 bool havearg(char** args, const char* arg)
00061 {
00062 for ( ; *args != 0; ++args)
00063 if (strcmp(*args, arg) == 0)
00064 return true;
00065
00066 return false;
00067 }
00068
00069 std::string centerline(unsigned int totallen,
00070 const char* pfx, const char* sfx,
00071 std::string txt)
00072 {
00073 if (strlen(pfx) + strlen(sfx) >= totallen)
00074 {
00075
00076
00077 std::string out(pfx);
00078 out += txt;
00079 out += sfx;
00080 return out;
00081 }
00082
00083 unsigned int midlen = totallen - strlen(pfx) - strlen(sfx);
00084
00085 std::string out(pfx);
00086
00087 if (txt.length() < midlen)
00088 {
00089 int c = midlen - txt.length();
00090 while (--c >= 0)
00091 { if (c % 2) txt += ' '; else out += ' '; }
00092 }
00093
00094 out += txt;
00095 out += sfx;
00096
00097 return out;
00098 }
00099
00100 std::string wrapstring(unsigned int totallen,
00101 const char* pfx, const char* sfx,
00102 const std::string& s)
00103 {
00104 GVX_ASSERT(strlen(pfx) + strlen(sfx) < totallen);
00105 unsigned int len = totallen - strlen(pfx) - strlen(sfx);
00106
00107 std::istringstream strm(s);
00108 std::string out;
00109 std::string line;
00110 std::string word;
00111 while (strm >> word)
00112 {
00113 if (word.length() + line.length() + 1 <= len)
00114 {
00115 if (line.length() > 0)
00116 line += ' ';
00117 line += word;
00118 }
00119 else
00120 {
00121 out += line;
00122 out += '\n';
00123 line = word;
00124 }
00125 }
00126
00127 out += line;
00128
00129 return out;
00130 }
00131
00132 std::string centerlines(unsigned int totallen,
00133 const char* pfx, const char* sfx,
00134 std::string ss)
00135 {
00136 if (ss.length() == 0)
00137 {
00138 return centerline(totallen, pfx, sfx, ss);
00139 }
00140
00141 std::istringstream strm(ss);
00142 std::string line;
00143 std::string out;
00144 bool first = true;
00145 while (getline(strm, line))
00146 {
00147 if (!first) out += '\n';
00148 first = false;
00149 out += centerline(totallen, pfx, sfx, line);
00150 }
00151
00152 return out;
00153 }
00154
00155 std::string wrapcenterlines(unsigned int totallen,
00156 const char* pfx, const char* sfx,
00157 std::string ss, std::string emptyline)
00158 {
00159 std::istringstream strm(ss);
00160 std::string line;
00161 std::string out;
00162 while (getline(strm, line))
00163 {
00164 if (line.length() == 0)
00165 {
00166 out += emptyline;
00167 out += '\n';
00168 }
00169 else
00170 {
00171 out += centerlines(totallen, pfx, sfx,
00172 wrapstring(totallen, pfx, sfx, line));
00173 out += '\n';
00174 }
00175 }
00176
00177 return out;
00178 }
00179
00180
00181
00182
00183
00184
00185 void factory_pkg_loader(const rutz::fstring& type)
00186 {
00187 dbg_eval_nl(3, type);
00188
00189 tcl::pkg::lookup(tcl::event_loop::interp(), type.c_str());
00190 }
00191
00192 void sig_handler(int signum)
00193 {
00194 switch (signum)
00195 {
00196 case SIGSEGV: GVX_PANIC("Segmentation fault (SIGSEGV)");
00197 case SIGFPE: GVX_PANIC("Floating point exception (SIGFPE)");
00198 case SIGBUS: GVX_PANIC("Bus error (SIGBUS)");
00199 }
00200 GVX_ASSERT(0);
00201 }
00202
00203 }
00204
00205 void tcl::script_app::init_in_macro_only()
00206 {
00207 signal(SIGSEGV, &sig_handler);
00208 signal(SIGFPE, &sig_handler);
00209 signal(SIGBUS, &sig_handler);
00210 }
00211
00212 void tcl::script_app::handle_exception_in_macro_only
00213 (const std::exception* e)
00214 {
00215 if (e != 0)
00216 std::cerr << "caught in main: ("
00217 << rutz::demangled_name(typeid(*e))
00218 << "): " << e->what() << '\n';
00219 else
00220 std::cerr << "caught in main: (an exception of unknown type)\n";
00221 }
00222
00223 tcl::script_app::script_app(const char* appname,
00224 int argc_, char** argv_) throw()
00225 :
00226 m_appname(appname),
00227 m_script_argc(0),
00228 m_script_argv(new char*[argc_+1]),
00229 m_minimal(false),
00230 m_nowindow(false),
00231 m_splashmsg(),
00232 m_pkgdir(),
00233 m_pkgs(0),
00234 m_exitcode(0)
00235 {
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 for (int i = 0; i < argc_; ++i)
00246 {
00247 if (strcmp(argv_[i], "-dbglevel") == 0)
00248 {
00249 ++i;
00250 if (argv_[i] != 0)
00251 rutz::debug::set_global_level( atoi(argv_[i]) );
00252 }
00253 else if (strcmp(argv_[i], "-gtrace") == 0)
00254 {
00255 rutz::trace::set_global_trace(true);
00256 }
00257 else if (strcmp(argv_[i], "-showinit") == 0)
00258 {
00259 tcl::pkg::verbose_init(true);
00260 }
00261 else if (strcmp(argv_[i], "-minimal") == 0)
00262 {
00263 this->m_minimal = true;
00264 }
00265 else if (strcmp(argv_[i], "-nw") == 0)
00266 {
00267 this->m_nowindow = true;
00268 }
00269 else
00270 {
00271
00272
00273 m_script_argv[m_script_argc++] = argv_[i];
00274 }
00275 }
00276
00277
00278 m_script_argv[m_script_argc] = 0;
00279 }
00280
00281 tcl::script_app::~script_app() throw()
00282 {
00283 delete [] m_script_argv;
00284 }
00285
00286 void tcl::script_app::run()
00287 {
00288 tcl::event_loop tclmain(this->m_script_argc,
00289 this->m_script_argv, this->m_nowindow);
00290
00291 if (tcl::event_loop::is_interactive())
00292 {
00293 const char* const pfx = "### ";
00294 const char* const sfx = " ###";
00295 const unsigned int linelen = 75;
00296 std::string hashes(linelen, '#');
00297
00298 std::cerr << hashes
00299 << '\n'
00300 << wrapcenterlines(linelen, pfx, sfx,
00301 m_splashmsg.c_str(), hashes)
00302 << hashes << '\n' << '\n';
00303 }
00304
00305 tcl::interpreter& interp = tclmain.interp();
00306
00307 nub::obj_factory::instance().set_fallback(&factory_pkg_loader);
00308 nub::set_default_ref_vis(nub::PUBLIC);
00309
00310 const rutz::time ru1 = rutz::time::user_rusage();
00311 const rutz::time rs1 = rutz::time::sys_rusage();
00312 const rutz::time wc1 = rutz::time::wall_clock_now();
00313
00314 package_info IMMEDIATE_PKGS[] =
00315 {
00316 { "Tcl", Tcl_Init, "", false },
00317 { "Tk", Tk_Init, "", true },
00318 };
00319
00320 for (size_t i = 0; i < sizeof(IMMEDIATE_PKGS)/sizeof(package_info); ++i)
00321 {
00322 if (m_nowindow && IMMEDIATE_PKGS[i].requires_gui)
00323 continue;
00324
00325 int result = IMMEDIATE_PKGS[i].init_proc(interp.intp());
00326 if (result != TCL_OK)
00327 {
00328 std::cerr << "fatal initialization error (package '"
00329 << IMMEDIATE_PKGS[i].name << "'):\n";
00330 rutz::fstring msg = interp.get_result<const char*>();
00331 if ( !msg.is_empty() )
00332 std::cerr << '\t' << msg << '\n';
00333 interp.reset_result();
00334
00335 this->m_exitcode = 2; return;
00336 }
00337 }
00338
00339 if (tcl::event_loop::is_interactive())
00340 {
00341 const rutz::time ru = rutz::time::user_rusage() - ru1;
00342 const rutz::time rs = rutz::time::sys_rusage() - rs1;
00343 const rutz::time wc = rutz::time::wall_clock_now() - wc1;
00344
00345 fprintf(stderr, "\tstartup time (%6s) "
00346 "%6.3fs (user) %6.3fs (sys) %6.3fs (wall)\n",
00347 "tcl+tk", ru.sec(), rs.sec(), wc.sec());
00348 }
00349
00350 const rutz::time ru2 = rutz::time::user_rusage();
00351 const rutz::time rs2 = rutz::time::sys_rusage();
00352 const rutz::time wc2 = rutz::time::wall_clock_now();
00353
00354 for (const package_info* pkg = m_pkgs; pkg->name != 0; ++pkg)
00355 {
00356 Tcl_StaticPackage(static_cast<Tcl_Interp*>(0),
00357
00358
00359
00360 pkg->name,
00361 pkg->init_proc,
00362 0);
00363
00364 const rutz::fstring ifneededcmd =
00365 rutz::sfmt("package ifneeded %s %s {load {} %s }",
00366 pkg->name, pkg->version, pkg->name);
00367
00368 interp.eval(ifneededcmd);
00369 }
00370
00371 if (!m_minimal)
00372 {
00373 for (const package_info* pkg = m_pkgs; pkg->name != 0; ++pkg)
00374 {
00375 if (m_nowindow && pkg->requires_gui)
00376 continue;
00377
00378 const char* ver =
00379 Tcl_PkgRequire(interp.intp(), pkg->name, pkg->version, 0);
00380
00381 if (ver == 0)
00382 {
00383 std::cerr << "initialization error (package '"
00384 << pkg->name << "'):\n";
00385 rutz::fstring msg = interp.get_result<const char*>();
00386 if ( !msg.is_empty() )
00387 std::cerr << '\t' << msg << '\n';
00388 interp.reset_result();
00389 }
00390 }
00391 }
00392
00393 if (tcl::event_loop::is_interactive())
00394 {
00395 const rutz::time ru = rutz::time::user_rusage() - ru2;
00396 const rutz::time rs = rutz::time::sys_rusage() - rs2;
00397 const rutz::time wc = rutz::time::wall_clock_now() - wc2;
00398
00399 fprintf(stderr, "\tstartup time (%6s) "
00400 "%6.3fs (user) %6.3fs (sys) %6.3fs (wall)\n",
00401 m_appname.c_str(), ru.sec(), rs.sec(), wc.sec());
00402 }
00403
00404 tcl::list path = interp.get_global_var<tcl::list>("auto_path");
00405
00406 if (m_pkgdir.length() > 0)
00407 path.append(m_pkgdir);
00408
00409 interp.set_global_var("auto_path", path.as_obj());
00410
00411
00412 interp.set_global_var("tcl_rcFileName",
00413 tcl::convert_from("./groovx_startup.tcl"));
00414
00415 tclmain.run();
00416 }
00417
00418 static const char __attribute__((used)) vcid_groovx_tcl_scriptapp_cc_utc20050628162421[] = "$Id: scriptapp.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00419 #endif // !GROOVX_TCL_SCRIPTAPP_CC_UTC20050628162421_DEFINED