/** @file sample for call of an external executable
 *
 * Last CVS checkin:
 * $Date: $
 * $Author: scheff $
 */

/**************************************************************************/

// standard C/C++ header:
#include <iostream>
#include <string>
#include <vector>

// Gnome header:
#include <glibmm/miscutils.h>
#include <glibmm/spawn.h>

using namespace std;

/**************************************************************************/

/** provides an output operator for vector<string>.
 *
 * @param out the output stream
 * @param strv the string vector
 * @return the output stream
 */
ostream& operator << (ostream &out, const vector<string> &strv)
{
  if (!strv.empty()) {
    vector<string>::const_iterator it;
    for (it = strv.begin();;) {
      out << *it; ++it; if (it != strv.end()) out << ' '; else break;
    }
  }
  return out;
}

/** waits for user confirm.
 *
 * @param action text with next action
 */
static void pause(const char *action)
{
  cerr << "spawn: Press [ENTER] to " << action << ": " << flush;
  string str; getline(cin, str);
}

/** provides the main function of application.
 *
 * @param argc number of command line arguments
 * @param argv pointer to array of pointers to strings with command line
 *        arguments
 * @return 0 ... application exited regularly\n
 *         else ... execution of application aborted
 */
int main(int argc, char *argv[])
{
  cout << "spawn: start" << endl;
  // build file path
#ifdef WIN32
  string file;
  { gchar *dir = g_win32_get_package_installation_directory_of_module(0);
    file = Glib::build_filename(dir, "test-spawn.exe");
    g_free(dir);
  }
#else // WIN32
  string file
    = Glib::build_filename(Glib::get_current_dir(), "test-spawn");
#endif // WIN32
  // spawn regular
  { vector<string> args;
    args.push_back(file);
    // spawn
    cout << "spawn: spawn_sync(" << args << "):" << endl;
    try {
      Glib::spawn_sync(".", args,
        Glib::SPAWN_CHILD_INHERITS_STDIN);
    } catch (const Glib::SpawnError &error) {
      cerr << "spawn: ERROR: " << error.what() << endl;
    }
  }
  pause("continue");
  // spawn with missing app.
  { vector<string> args;
    // spawn
    cout << "spawn: spawn_sync(" << args << "):" << endl;
    try {
      Glib::spawn_sync(".", args,
        Glib::SPAWN_CHILD_INHERITS_STDIN);
    } catch (const Glib::SpawnError &error) {
      cerr << "spawn: ERROR: " << error.what() << endl;
    }
  }
  pause("continue");
  // spawn with error return
  { vector<string> args;
    args.push_back(file); args.push_back("-return"); args.push_back("1");
    // spawn
    cout << "spawn: spawn_sync(" << args << "):" << endl;
    try {
      int exitCode;
      Glib::spawn_sync(".", args,
        Glib::SPAWN_CHILD_INHERITS_STDIN,
        sigc::slot<void>(), 0, 0, &exitCode);
      cout << "spawn: Received exit code: " << exitCode << endl;
    } catch (const Glib::SpawnError &error) {
      cerr << "spawn: ERROR: " << error.what() << endl;
    }
  }
  pause("continue");
  // spawn with exception
  { vector<string> args;
    args.push_back(file); args.push_back("-throw");
    // spawn
    cout << "spawn: spawn_sync(" << args << "):" << endl;
    try {
      int exitCode;
      Glib::spawn_sync(".", args,
        Glib::SPAWN_CHILD_INHERITS_STDIN,
        sigc::slot<void>(), 0, 0, &exitCode);
      cout << "spawn: Received exit code: " << exitCode << endl;
    } catch (const Glib::SpawnError &error) {
      cerr << "spawn: ERROR: " << error.what() << endl;
    }
  }
  pause("continue");
  // spawn with standard channels
  { vector<string> args;
    args.push_back(file); args.push_back("-nopause");
    // spawn
    cout << "spawn: spawn_sync(" << args << "):" << endl;
    try {
      string output, error; int exitCode;
      Glib::spawn_sync(".", args,
        Glib::SpawnFlags(0),
        sigc::slot<void>(), &output, &error, &exitCode);
      cout << "spawn: Received on standard output:" << endl
	<< output << endl;
      cout << "spawn: Received on standard error:" << endl
	<< error << endl;
      cout << "spawn: Received exit code: " << exitCode << endl;
    } catch (const Glib::SpawnError &error) {
      cerr << "spawn: ERROR: " << error.what() << endl;
    }
  }
#if 0 // This problem isn't solved, satisfying!
  pause("continue");
  // spawn with merged standard output and error
  { vector<string> args;
    args.push_back(file);
    try {
      string output; int exitCode = 0;
      /* This doesn't work:
      Glib::spawn_sync(".", args, Glib::SpawnFlags(0),
        sigc::slot<void>(), &output, &output, &exitCode);
       * Var. output receives only error channel!
       * Output channel gets lost.
       */
      /* This doesn't work, also:
      Glib::spawn_sync(".", args, Glib::SpawnFlags(0),
        sigc::slot<void>(), &output, 0, &exitCode);
       * Var. output receives only output channel!
       * Error channel goes to console.
       */
      cout << "spawn: Received on standard output:" << endl
        << output << endl;
      cout << "spawn: Received exit code: " << exitCode << endl;
    } catch (const Glib::SpawnError &error) {
      cerr << "spawn: ERROR: " << error.what() << endl;
    }
  }
#endif // 0
  // done
  pause("finish");
  return 0;
}

