p3dMainObject.cxx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. // Filename: p3dMainObject.cxx
  2. // Created by: drose (10Jul09)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) Carnegie Mellon University. All rights reserved.
  8. //
  9. // All use of this software is subject to the terms of the revised BSD
  10. // license. You should have received a copy of this license along
  11. // with this source code in a file named "LICENSE."
  12. //
  13. ////////////////////////////////////////////////////////////////////
  14. #include "p3dMainObject.h"
  15. #include "p3dInstance.h"
  16. #include "p3dSession.h"
  17. #include "p3dStringObject.h"
  18. #include "p3dInstanceManager.h"
  19. ////////////////////////////////////////////////////////////////////
  20. // Function: P3DMainObject::Constructor
  21. // Access: Public
  22. // Description:
  23. ////////////////////////////////////////////////////////////////////
  24. P3DMainObject::
  25. P3DMainObject() :
  26. _pyobj(NULL),
  27. _inst(NULL),
  28. _unauth_play(false)
  29. {
  30. }
  31. ////////////////////////////////////////////////////////////////////
  32. // Function: P3DMainObject::Destructor
  33. // Access: Public, Virtual
  34. // Description:
  35. ////////////////////////////////////////////////////////////////////
  36. P3DMainObject::
  37. ~P3DMainObject() {
  38. set_pyobj(NULL);
  39. // Clear the local properties.
  40. Properties::const_iterator pi;
  41. for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
  42. P3D_object *value = (*pi).second;
  43. P3D_OBJECT_DECREF(value);
  44. }
  45. _properties.clear();
  46. }
  47. ////////////////////////////////////////////////////////////////////
  48. // Function: P3DMainObject::get_type
  49. // Access: Public, Virtual
  50. // Description: Returns the fundamental type of this kind of object.
  51. ////////////////////////////////////////////////////////////////////
  52. P3D_object_type P3DMainObject::
  53. get_type() {
  54. return P3D_OT_object;
  55. }
  56. ////////////////////////////////////////////////////////////////////
  57. // Function: P3DMainObject::get_bool
  58. // Access: Public, Virtual
  59. // Description: Returns the object value coerced to a boolean, if
  60. // possible.
  61. ////////////////////////////////////////////////////////////////////
  62. bool P3DMainObject::
  63. get_bool() {
  64. return true;
  65. }
  66. ////////////////////////////////////////////////////////////////////
  67. // Function: P3DMainObject::get_int
  68. // Access: Public, Virtual
  69. // Description: Returns the object value coerced to an integer, if
  70. // possible.
  71. ////////////////////////////////////////////////////////////////////
  72. int P3DMainObject::
  73. get_int() {
  74. return 0;
  75. }
  76. ////////////////////////////////////////////////////////////////////
  77. // Function: P3DMainObject::get_float
  78. // Access: Public, Virtual
  79. // Description: Returns the object value coerced to a floating-point
  80. // value, if possible.
  81. ////////////////////////////////////////////////////////////////////
  82. double P3DMainObject::
  83. get_float() {
  84. return 0.0;
  85. }
  86. ////////////////////////////////////////////////////////////////////
  87. // Function: P3DMainObject::make_string
  88. // Access: Public, Virtual
  89. // Description: Fills the indicated C++ string object with the value
  90. // of this object coerced to a string.
  91. ////////////////////////////////////////////////////////////////////
  92. void P3DMainObject::
  93. make_string(string &value) {
  94. if (_pyobj == NULL) {
  95. value = "P3DMainObject";
  96. } else {
  97. int size = P3D_OBJECT_GET_STRING(_pyobj, NULL, 0);
  98. char *buffer = new char[size];
  99. P3D_OBJECT_GET_STRING(_pyobj, buffer, size);
  100. value = string(buffer, size);
  101. delete[] buffer;
  102. }
  103. }
  104. ////////////////////////////////////////////////////////////////////
  105. // Function: P3DMainObject::get_property
  106. // Access: Public, Virtual
  107. // Description: Returns the named property element in the object. The
  108. // return value is a new-reference P3D_object, or NULL
  109. // on error.
  110. ////////////////////////////////////////////////////////////////////
  111. P3D_object *P3DMainObject::
  112. get_property(const string &property) {
  113. if (_pyobj == NULL) {
  114. // Without a pyobj, we just report whatever's been stored locally.
  115. Properties::const_iterator pi;
  116. pi = _properties.find(property);
  117. if (pi != _properties.end()) {
  118. P3D_object *result = (*pi).second;
  119. P3D_OBJECT_INCREF(result);
  120. return result;
  121. }
  122. return NULL;
  123. }
  124. // With a pyobj, we pass the query down to it.
  125. return P3D_OBJECT_GET_PROPERTY(_pyobj, property.c_str());
  126. }
  127. ////////////////////////////////////////////////////////////////////
  128. // Function: P3DMainObject::set_property
  129. // Access: Public, Virtual
  130. // Description: Modifies (or deletes, if value is NULL) the named
  131. // property element in the object. Returns true on
  132. // success, false on failure.
  133. ////////////////////////////////////////////////////////////////////
  134. bool P3DMainObject::
  135. set_property(const string &property, bool needs_response, P3D_object *value) {
  136. // First, we set the property locally.
  137. if (value != NULL) {
  138. Properties::iterator pi;
  139. pi = _properties.insert(Properties::value_type(property, NULL)).first;
  140. assert(pi != _properties.end());
  141. P3D_object *orig_value = (*pi).second;
  142. if (orig_value != value) {
  143. P3D_OBJECT_XDECREF(orig_value);
  144. (*pi).second = value;
  145. P3D_OBJECT_INCREF(value);
  146. }
  147. } else {
  148. // (Or delete the property locally.)
  149. Properties::iterator pi;
  150. pi = _properties.find(property);
  151. if (pi != _properties.end()) {
  152. P3D_object *orig_value = (*pi).second;
  153. P3D_OBJECT_DECREF(orig_value);
  154. _properties.erase(pi);
  155. }
  156. }
  157. if (_pyobj == NULL) {
  158. // Without a pyobj, that's all we do.
  159. return true;
  160. }
  161. // With a pyobj, we also pass this request down.
  162. return P3D_OBJECT_SET_PROPERTY(_pyobj, property.c_str(), needs_response, value);
  163. }
  164. ////////////////////////////////////////////////////////////////////
  165. // Function: P3DMainObject::has_method
  166. // Access: Public, Virtual
  167. // Description: Returns true if the named method exists on this
  168. // object, false otherwise.
  169. ////////////////////////////////////////////////////////////////////
  170. bool P3DMainObject::
  171. has_method(const string &method_name) {
  172. // Some special-case methods implemented in-place.
  173. if (method_name == "play") {
  174. return true;
  175. } else if (method_name == "read_game_log") {
  176. return true;
  177. } else if (method_name == "read_system_log") {
  178. return true;
  179. } else if (method_name == "read_log") {
  180. return true;
  181. } else if (method_name == "uninstall") {
  182. return true;
  183. }
  184. if (_pyobj == NULL) {
  185. // No methods until we get our pyobj.
  186. return false;
  187. }
  188. return P3D_OBJECT_HAS_METHOD(_pyobj, method_name.c_str());
  189. }
  190. ////////////////////////////////////////////////////////////////////
  191. // Function: P3DMainObject::call
  192. // Access: Public, Virtual
  193. // Description: Invokes the named method on the object, passing the
  194. // indicated parameters. If the method name is empty,
  195. // invokes the object itself.
  196. //
  197. // If needs_response is true, the return value is a
  198. // new-reference P3D_object on success, or NULL on
  199. // failure. If needs_response is false, the return
  200. // value is always NULL, and there is no way to
  201. // determine success or failure.
  202. ////////////////////////////////////////////////////////////////////
  203. P3D_object *P3DMainObject::
  204. call(const string &method_name, bool needs_response,
  205. P3D_object *params[], int num_params) {
  206. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
  207. if (method_name == "play") {
  208. return call_play(params, num_params);
  209. } else if (method_name == "read_game_log") {
  210. return call_read_game_log(params, num_params);
  211. } else if (method_name == "read_system_log") {
  212. return call_read_system_log(params, num_params);
  213. } else if (method_name == "read_log") {
  214. return call_read_log(params, num_params);
  215. } else if (method_name == "uninstall") {
  216. return call_uninstall(params, num_params);
  217. }
  218. if (_pyobj == NULL) {
  219. // No methods until we get our pyobj.
  220. return NULL;
  221. }
  222. return P3D_OBJECT_CALL(_pyobj, method_name.c_str(), needs_response,
  223. params, num_params);
  224. }
  225. ////////////////////////////////////////////////////////////////////
  226. // Function: P3DMainObject::output
  227. // Access: Public, Virtual
  228. // Description: Writes a formatted representation of the value to the
  229. // indicated string. This is intended for developer
  230. // assistance.
  231. ////////////////////////////////////////////////////////////////////
  232. void P3DMainObject::
  233. output(ostream &out) {
  234. out << "P3DMainObject";
  235. }
  236. ////////////////////////////////////////////////////////////////////
  237. // Function: P3DMainObject::set_pyobj
  238. // Access: Public
  239. // Description: Changes the internal pyobj pointer. This is the
  240. // P3D_object that references the actual PyObject held
  241. // within the child process, corresponding to the true
  242. // main object there. The new object's reference
  243. // count is incremented, and the previous object's is
  244. // decremented.
  245. ////////////////////////////////////////////////////////////////////
  246. void P3DMainObject::
  247. set_pyobj(P3D_object *pyobj) {
  248. if (_pyobj != pyobj) {
  249. P3D_OBJECT_XDECREF(_pyobj);
  250. _pyobj = pyobj;
  251. if (_pyobj != NULL) {
  252. P3D_OBJECT_INCREF(_pyobj);
  253. // Now that we have a pyobj, we have to transfer down all of the
  254. // properties we'd set locally.
  255. Properties::const_iterator pi;
  256. for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
  257. const string &property_name = (*pi).first;
  258. P3D_object *value = (*pi).second;
  259. P3D_OBJECT_SET_PROPERTY(_pyobj, property_name.c_str(), false, value);
  260. }
  261. }
  262. }
  263. }
  264. ////////////////////////////////////////////////////////////////////
  265. // Function: P3DMainObject::get_pyobj
  266. // Access: Public
  267. // Description: Returns the internal pyobj pointer, or NULL if it has
  268. // not yet been set.
  269. ////////////////////////////////////////////////////////////////////
  270. P3D_object *P3DMainObject::
  271. get_pyobj() const {
  272. return _pyobj;
  273. }
  274. ////////////////////////////////////////////////////////////////////
  275. // Function: P3DMainObject::set_instance
  276. // Access: Public
  277. // Description: Sets a callback pointer to the instance that owns
  278. // this object. When this instance destructs, it clears
  279. // this pointer to NULL.
  280. ////////////////////////////////////////////////////////////////////
  281. void P3DMainObject::
  282. set_instance(P3DInstance *inst) {
  283. if (_inst != NULL) {
  284. // Save the game log filename of the instance just before it goes
  285. // away, in case JavaScript asks for it later.
  286. _game_log_pathname = _inst->get_log_pathname();
  287. }
  288. _inst = inst;
  289. }
  290. ////////////////////////////////////////////////////////////////////
  291. // Function: P3DMainObject::call_play
  292. // Access: Private
  293. // Description: Starts the process remotely, as if the play button
  294. // had been clicked. If the application has not yet
  295. // been validated, this pops up the validation dialog.
  296. //
  297. // Only applicable if the application was in the ready
  298. // state, or the unauth state. Returns true if the
  299. // application is now started, false otherwise.
  300. //
  301. // This may be invoked from the unauth state only once.
  302. // If the user chooses not to authorize the plugin at
  303. // that time, it may not be invoked automatically again.
  304. ////////////////////////////////////////////////////////////////////
  305. P3D_object *P3DMainObject::
  306. call_play(P3D_object *params[], int num_params) {
  307. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
  308. if (_inst == NULL) {
  309. return inst_mgr->new_bool_object(false);
  310. }
  311. // I guess there's no harm in allowing JavaScript to call play(),
  312. // with or without explicit scripting authorization.
  313. nout << "play() called from JavaScript\n";
  314. if (!_inst->is_trusted()) {
  315. // Requires authorization. We allow this only once; beyond that,
  316. // and you're only annoying the user.
  317. if (!_unauth_play) {
  318. _unauth_play = true;
  319. _inst->splash_button_clicked_main_thread();
  320. }
  321. } else if (!_inst->is_started()) {
  322. // We allow calling play() from a ready state without limit, but
  323. // probably only once will be necessary.
  324. _inst->splash_button_clicked_main_thread();
  325. }
  326. return inst_mgr->new_bool_object(_inst->is_started());
  327. }
  328. ////////////////////////////////////////////////////////////////////
  329. // Function: P3DMainObject::call_read_game_log
  330. // Access: Private
  331. // Description: Reads the entire logfile as a string, and returns it
  332. // to the calling JavaScript process.
  333. ////////////////////////////////////////////////////////////////////
  334. P3D_object *P3DMainObject::
  335. call_read_game_log(P3D_object *params[], int num_params) {
  336. if (_inst != NULL) {
  337. string log_pathname = _inst->get_log_pathname();
  338. return read_log(log_pathname, params, num_params);
  339. }
  340. if (!_game_log_pathname.empty()) {
  341. // The instance has already finished, but we saved its log
  342. // filename.
  343. return read_log(_game_log_pathname, params, num_params);
  344. }
  345. // No log available for us.
  346. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
  347. return inst_mgr->new_undefined_object();
  348. }
  349. ////////////////////////////////////////////////////////////////////
  350. // Function: P3DMainObject::call_read_system_log
  351. // Access: Private
  352. // Description: As above, but reads the system log, the logfile for
  353. // the installation process.
  354. ////////////////////////////////////////////////////////////////////
  355. P3D_object *P3DMainObject::
  356. call_read_system_log(P3D_object *params[], int num_params) {
  357. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
  358. string log_pathname = inst_mgr->get_log_pathname();
  359. return read_log(log_pathname, params, num_params);
  360. }
  361. ////////////////////////////////////////////////////////////////////
  362. // Function: P3DMainObject::call_read_log
  363. // Access: Private
  364. // Description: Reads a named logfile. The filename must end
  365. // in ".log" and must not contain any slashes or colons
  366. // (it must be found within the log directory).
  367. ////////////////////////////////////////////////////////////////////
  368. P3D_object *P3DMainObject::
  369. call_read_log(P3D_object *params[], int num_params) {
  370. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
  371. if (num_params < 1) {
  372. return inst_mgr->new_undefined_object();
  373. }
  374. int size = P3D_OBJECT_GET_STRING(params[0], NULL, 0);
  375. char *buffer = new char[size];
  376. P3D_OBJECT_GET_STRING(params[0], buffer, size);
  377. string log_filename = string(buffer, size);
  378. delete[] buffer;
  379. if (log_filename.size() < 4 || log_filename.substr(log_filename.size() - 4) != string(".log")) {
  380. // Wrong filename extension.
  381. return inst_mgr->new_undefined_object();
  382. }
  383. size_t slash = log_filename.find('/');
  384. if (slash != string::npos) {
  385. // No slashes allowed.
  386. return inst_mgr->new_undefined_object();
  387. }
  388. slash = log_filename.find('\\');
  389. if (slash != string::npos) {
  390. // Nor backslashes.
  391. return inst_mgr->new_undefined_object();
  392. }
  393. size_t colon = log_filename.find(':');
  394. if (colon != string::npos) {
  395. // Nor colons, for that matter.
  396. return inst_mgr->new_undefined_object();
  397. }
  398. string log_pathname = inst_mgr->get_log_directory() + log_filename;
  399. return read_log(log_pathname, params + 1, num_params - 1);
  400. }
  401. ////////////////////////////////////////////////////////////////////
  402. // Function: P3DMainObject::read_log
  403. // Access: Private
  404. // Description: log-reader meta function that handles reading
  405. // previous log files in addition to the present one
  406. ////////////////////////////////////////////////////////////////////
  407. P3D_object *P3DMainObject::
  408. read_log(const string &log_pathname, P3D_object *params[], int num_params) {
  409. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
  410. string log_directory = inst_mgr->get_log_directory();
  411. ostringstream log_data;
  412. // Check the first parameter, if any--if given, it specifies the
  413. // last n bytes to retrieve.
  414. size_t tail_bytes = 0;
  415. if (num_params > 0) {
  416. tail_bytes = (size_t)max(P3D_OBJECT_GET_INT(params[0]), 0);
  417. }
  418. // Check the second parameter, if any--if given, it specifies the
  419. // first n bytes to retrieve.
  420. size_t head_bytes = 0;
  421. if (num_params > 1) {
  422. head_bytes = (size_t)max(P3D_OBJECT_GET_INT(params[1]), 0);
  423. }
  424. // Check the third parameter, if any--if given, it specifies the
  425. // last n bytes to retrieve from previous copies of this file.
  426. size_t tail_bytes_prev = 0;
  427. if (num_params > 2) {
  428. tail_bytes_prev = (size_t)max(P3D_OBJECT_GET_INT(params[2]), 0);
  429. }
  430. // Read the log data from the primary file
  431. read_log_file(log_pathname, tail_bytes, head_bytes, log_data);
  432. // Read data from previous logs if requested
  433. if (tail_bytes_prev > 0) {
  434. // Determine the base of the log file names
  435. string log_basename = log_pathname;
  436. size_t slash = log_basename.rfind('/');
  437. if (slash != string::npos) {
  438. log_basename = log_basename.substr(slash + 1);
  439. }
  440. #ifdef _WIN32
  441. slash = log_basename.rfind('\\');
  442. if (slash != string::npos) {
  443. log_basename = log_basename.substr(slash + 1);
  444. }
  445. #endif // _WIN32
  446. string log_basename_primary = log_basename;
  447. int dash = log_basename.rfind("-");
  448. if (dash != string::npos) {
  449. log_basename = log_basename.substr(0, dash+1);
  450. } else {
  451. int dotLog = log_basename.rfind(".log");
  452. if (dotLog != string::npos) {
  453. log_basename = log_basename.substr(0, dotLog);
  454. log_basename += "-";
  455. }
  456. }
  457. // Find matching files
  458. vector<string> all_logs;
  459. inst_mgr->scan_directory(log_directory, all_logs);
  460. for (int i=(int)all_logs.size()-1; i>=0; --i) {
  461. if ((all_logs[i].find(log_basename) == 0) &&
  462. (all_logs[i] != log_basename_primary) &&
  463. (all_logs[i].size() > 4) &&
  464. (all_logs[i].substr(all_logs[i].size() - 4) == string(".log"))) {
  465. read_log_file((log_directory+all_logs[i]), tail_bytes_prev, 0, log_data);
  466. }
  467. }
  468. }
  469. P3D_object *result = new P3DStringObject(log_data.str().c_str(), log_data.tellp());
  470. return result;
  471. }
  472. ////////////////////////////////////////////////////////////////////
  473. // Function: P3DMainObject::read_log_file
  474. // Access: Private
  475. // Description: The generic log-reader function.
  476. ////////////////////////////////////////////////////////////////////
  477. void P3DMainObject::
  478. read_log_file(const string &log_pathname,
  479. size_t tail_bytes, size_t head_bytes,
  480. ostringstream &log_data) {
  481. // Get leaf name
  482. string log_leafname = log_pathname;
  483. size_t slash = log_leafname.rfind('/');
  484. if (slash != string::npos) {
  485. log_leafname = log_leafname.substr(slash + 1);
  486. }
  487. #ifdef _WIN32
  488. slash = log_leafname.rfind('\\');
  489. if (slash != string::npos) {
  490. log_leafname = log_leafname.substr(slash + 1);
  491. }
  492. #endif // _WIN32
  493. // load file
  494. ifstream log(log_pathname.c_str(), ios::in);
  495. if (!log) {
  496. return;
  497. }
  498. // Get the size of the file.
  499. log.seekg(0, ios::end);
  500. size_t file_size = (size_t)log.tellg();
  501. nout << "read_log: " << log_pathname << " is " << file_size
  502. << " bytes, tail_bytes = " << tail_bytes << ", head_bytes = "
  503. << head_bytes << "\n";
  504. // Check if we are getting the full file
  505. size_t full_bytes = 0;
  506. if (file_size <= head_bytes + tail_bytes) {
  507. // We will return the entire log.
  508. full_bytes = file_size;
  509. head_bytes = 0;
  510. tail_bytes = 0;
  511. }
  512. // Allocate a temp buffer to hold file data
  513. size_t buffer_bytes = full_bytes + head_bytes + tail_bytes + 1;
  514. nout << "allocating " << buffer_bytes << " bytes to read from file.\n";
  515. char *buffer = new char[buffer_bytes];
  516. if (buffer == NULL) {
  517. return;
  518. }
  519. // Render log file header to log_data
  520. log_data << "=======================================";
  521. log_data << "=======================================" << "\n";
  522. log_data << "== PandaLog-" << log_pathname << "\n";
  523. // Render log data if full file is to be fetched
  524. if (full_bytes > 0) {
  525. log.seekg(0, ios::beg);
  526. log.read(buffer, full_bytes);
  527. buffer[log.gcount()] = NULL;
  528. log_data << "== PandaLog-" << "Full Start";
  529. log_data << " " << "(" << log_leafname << ")" << "\n";
  530. log_data << buffer;
  531. log_data << "== PandaLog-" << "Full End";
  532. log_data << " " << "(" << log_leafname << ")" << "\n";
  533. }
  534. // Render log data if head bytes are to be fetched
  535. if (head_bytes > 0) {
  536. log.seekg(0, ios::beg);
  537. log.read(buffer, head_bytes);
  538. buffer[log.gcount()] = NULL;
  539. log_data << "== PandaLog-" << "Head Start";
  540. log_data << " " << "(" << log_leafname << ")" << "\n";
  541. log_data << buffer << "\n";
  542. log_data << "== PandaLog-" << "Head End";
  543. log_data << " " << "(" << log_leafname << ")" << "\n";
  544. }
  545. // Render separator if head & tail bytes are to be fetched
  546. if ((head_bytes > 0) && (tail_bytes > 0)) {
  547. log_data << "== PandaLog-" << "truncated";
  548. log_data << " " << "(" << log_leafname << ")" << "\n";
  549. }
  550. // Render log data if tail bytes are to be fetched
  551. if (tail_bytes > 0) {
  552. log.seekg(file_size - tail_bytes, ios::beg);
  553. log.read(buffer, tail_bytes);
  554. buffer[log.gcount()] = NULL;
  555. log_data << "== PandaLog-" << "Tail Start";
  556. log_data << " " << "(" << log_leafname << ")" << "\n";
  557. log_data << buffer;
  558. log_data << "== PandaLog-" << "Tail End";
  559. log_data << " " << "(" << log_leafname << ")" << "\n";
  560. }
  561. // Render log file footer to log_data
  562. //log_data << "=======================================";
  563. //log_data << "=======================================" << "\n";
  564. // cleanup
  565. delete[] buffer;
  566. buffer = NULL;
  567. }
  568. ////////////////////////////////////////////////////////////////////
  569. // Function: P3DMainObject::call_uninstall
  570. // Access: Private
  571. // Description: Implements the uninstall() plugin method, which
  572. // removes all Panda installed files for a particular
  573. // host, or referenced by a particular p3d file.
  574. ////////////////////////////////////////////////////////////////////
  575. P3D_object *P3DMainObject::
  576. call_uninstall(P3D_object *params[], int num_params) {
  577. P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
  578. // Get the first parameter, the uninstall mode.
  579. string mode;
  580. if (num_params > 0) {
  581. int size = P3D_OBJECT_GET_STRING(params[0], NULL, 0);
  582. char *buffer = new char[size];
  583. P3D_OBJECT_GET_STRING(params[0], buffer, size);
  584. mode = string(buffer, size);
  585. delete[] buffer;
  586. }
  587. if (mode == "all") {
  588. nout << "uninstall all\n";
  589. inst_mgr->uninstall_all();
  590. return inst_mgr->new_bool_object(true);
  591. }
  592. if (_inst != NULL) {
  593. nout << "uninstall " << mode << " for " << _inst << "\n";
  594. if (mode == "host") {
  595. _inst->uninstall_host();
  596. } else {
  597. _inst->uninstall_packages();
  598. }
  599. return inst_mgr->new_bool_object(true);
  600. }
  601. nout << "couldn't uninstall; no instance.\n";
  602. return inst_mgr->new_bool_object(false);
  603. }