Пример #1
0
void WindowMerge::approval_approve(GtkButton * button)
// Handles the user's approval of a change.
{
  // Go through the approval buttons to find the one clicked.
  for (unsigned int i = 0; i < approve_buttons.size(); i++) {
    if (button == approve_buttons[i].button) {

      // Write a new patch file to disk.
      vector < ustring > lines;
      ustring s;
      s = convert_to_string(approve_buttons[i].patch.linenumber);
      if (approve_buttons[i].patch.addition)
        s.append("a");
      else
        s.append("d");
      s.append("0");
      lines.push_back(s);
      if (approve_buttons[i].patch.addition)
        s = ">";
      else
        s = "<";
      lines.push_back(s + " " + approve_buttons[i].patch.change);
      write_lines(approve_patch_file, lines);

      // Apply the patch to master.
      ustring command = "patch" + shell_quote_space(approve_master_file) + shell_quote_space(approve_patch_file);
      if (system(command.c_str())) ; // This one could use GwSpawn, but it was not tested.

      // Show the new differences after the change has been accepted.
      approval_show_diff();

    }
  }
}
Пример #2
0
void shell_pipe_file_append(const ustring & inputfile, const ustring & outputfile)
// cat inputfile >> outputfile.
{
  ustring command;
#ifdef WIN32
  command.append("type");
#else
  command.append("cat");
#endif
  command.append(shell_quote_space(inputfile));
  command.append(">>");
  command.append(shell_quote_space(outputfile));
  if (system(command.c_str())) ; // This one does not work with GwSpawn because pipes used.
}
Пример #3
0
void OpenDocument::zip(const ustring filename)
{
  ustring command = "cd ";
  command.append(shell_quote_space(workingdirectory));
#ifdef WIN32
  command.append(" && ");
  gchar *path;
  path = g_find_program_in_path("zip.exe");
  if (path) {
    command.append(path);
    g_free(path);
    command.append(" -r ");
  }
#else
  command.append("; zip -r");
#endif
  command.append(shell_quote_space(filename));
  command.append(" *");
  if (system(command.c_str())) ; // This one does not work with GwSpawn because of the wildcards used.
}
Пример #4
0
void OpenDocument::unpack_template()
{
  // Clear working directory.
  unix_rmdir(workingdirectory);
  gw_mkdir_with_parents(workingdirectory);
  // Copy template there.
  // Note: To create the template use zip -r template.odt *
#ifdef WIN32
  ustring command = "unzip -o ";
  command.append(gw_build_filename(Directories->get_package_data(), "template.odt"));
  command.append(" -d ");
  command.append(shell_quote_space(workingdirectory));
#else
  ustring command = "cd";
  command.append(shell_quote_space(workingdirectory));
  command.append("; cp ");
  command.append(gw_build_filename(Directories->get_package_data(), "template.odt"));
  command.append(" .; unzip *; rm *.odt");
#endif
  if (system(command.c_str())) ; // This one does not work with GwSpawn because of the wildcards used.
}
Пример #5
0
void GwSpawn::arg(ustring value)
// Add one arguments to the arguments for running the program.
// This function can be repeated as many times as desired.
{
#ifdef WIN32
  // Quote the argument.
  value = shell_quote_space(value);
#else
  // Escape any '.
  replace_text(value, "'", "\\'");
  // We do not shell_quote_space this argument because 
  // we are not executing this through a shell. GwSpawnpawn::run
  // passes arguments directly through argv[].
#endif
  // Save argument.
  myarguments.push_back(value);
}
Пример #6
0
// Same as above, but takes ustring
GwSpawn::GwSpawn(const ustring &program)
{
#ifdef WIN32
  // Quote the command in case it has path like 
  // C:\Program Files\... with a space in it.
  myprogram = shell_quote_space(program);
#else 
	myprogram = program;
#endif
  myasync = false;
  mydevnull = false;
  myread = false;
  myprogress = false;
  myallowcancel = false;
  myhide = false;
  cancelled = false;
  exitstatus = 0;
  pid = 0;
}
Пример #7
0
ustring script_filter(const ustring & scriptname, bool straightthrough, const ustring & inputfile, const ustring & outputfile)
/*
 Runs the filter "scriptname".
 Input text in "inputfile", and the output text goes in "outputfile".
 If everything is okay, it returns nothing.
 If there were errors, it returns these.
 */
{
  // Remove any previous output.
  unlink(outputfile.c_str());
  unlink(script_temporal_error_file().c_str());

  // Handle straight through.
  if (straightthrough) {
    unix_cp(inputfile, outputfile);
    return "";
  }
  // Get the filename and the type of the script.
  ScriptType scripttype;
  ustring scriptfile = script_get_path(scriptname, &scripttype, true);

  // If the rules file does not exist, or the script is of an unknown type, pass it straight through.
  if (!g_file_test(scriptfile.c_str(), G_FILE_TEST_IS_REGULAR) || (scripttype == stEnd)) {
    unix_cp(inputfile, outputfile);
    gw_warning(_("Error in script ") + scriptname);
    return "";
  }
  // Encode the input usfm file.
  ustring encodedinputfile = script_temporal_input_file();
  if (inputfile != encodedinputfile) {
    unix_cp(inputfile, encodedinputfile);
  }
  script_encode_usfm_file(encodedinputfile);

  // Run filter.
  ustring command;
  ustring error;
  switch (scripttype) {
  case stSed:
    {
      command.append(script_sed_binary());
      command.append(" -f");
      command.append(shell_quote_space(scriptfile));
      command.append("<");
      command.append(shell_quote_space(encodedinputfile));
      command.append(">");
      command.append(shell_quote_space(outputfile));
      break;
    }
  case stTECkit:
    {
      command.append(script_teckit_txtconverter());
      command.append(" -i");
      command.append(shell_quote_space(encodedinputfile));
      command.append(" -o");
      command.append(shell_quote_space(outputfile));
      command.append(" -t");
      command.append(shell_quote_space(scriptfile));
      command.append(" -nobom");
      break;
    }
  case stFree:
    {
      // Text of the script.
      ustring scriptdata;
      {
        // Read script.
        gchar *contents;
        g_file_get_contents(scriptfile.c_str(), &contents, NULL, NULL);
        if (contents) {
          scriptdata = contents;
          g_free(contents);
        } else {
          error = _("Can't read script file");
          gw_warning(error);
          return error;
        }
      }
      // Check for and insert the input filename.
      if (scriptdata.find(script_free_input_identifier()) == string::npos) {
        error = _("Can't find where to put input file");
        gw_warning(error);
        return error;
      }
      replace_text(scriptdata, script_free_input_identifier(), shell_quote_space(encodedinputfile));
      // Check for and insert the output filename.
      if (scriptdata.find(script_free_output_identifier()) == string::npos) {
        error = _("Can't find where to put output file");
        gw_warning(error);
        return error;
      }
      replace_text(scriptdata, script_free_output_identifier(), shell_quote_space(outputfile));
      // Write temporal script.
      g_file_set_contents(script_temporal_script_file().c_str(), scriptdata.c_str(), -1, NULL);
      // Assemble command to run.
      command.append("sh");
      command.append(shell_quote_space(script_temporal_script_file()));
      break;
    }
  case stEnd:
    {
      break;
    }
  }

  // Add the error file to the command, and run it.
  command.append(" 2> ");
  command.append(script_temporal_error_file());
  int result = system(command.c_str()); // This one is too unpredictable to be used with GwSpawn.

  // The filters are so much beyond any control that we never can be sure that 
  // their output is in the UTF-8 encoding.
  // Sed would give UTF-8, but as TECkit can also give legacy encodings.
  // We can't know what free scripts will do, it could be anything.
  // So here check the UTF-8 encoding. 
  // If UTF-8 validation fails, we copy the input straight to the output.
  {
    gchar *contents;
    g_file_get_contents(outputfile.c_str(), &contents, NULL, NULL);
    if (contents) {
      if (!g_utf8_validate(contents, -1, NULL)) {
        unix_cp(inputfile, outputfile);
        error = _("UTF-8 validation failure");
        gw_warning(error);
      }
      g_free(contents);
      if (!error.empty())
        return error;
    }
  }

  // Decode the output file.
  script_decode_usfm_file(outputfile);

  // Handle OK.
  if (result == 0)
    return "";

  // Handle error.
  gchar *contents;
  g_file_get_contents(script_temporal_error_file().c_str(), &contents, NULL, NULL);
  if (contents) {
    error = contents;
    g_free(contents);
    gw_warning(error);
  }
  return error;
}
Пример #8
0
void WindowMerge::approval_show_diff()
// Looks for the differences and shows them in the GUI.
{
  // Create a patch file by running a diff.
  approve_patch_file = gw_build_filename(workingdirectory, "patch");
  ustring command = "diff" + shell_quote_space(approve_master_file) + shell_quote_space(approve_merge_file) + ">" + shell_quote_space(approve_patch_file);
  if (system(command.c_str())) ; // This one does not work with GwSpawn because of the pipes used.

  // Clear items.
  gtk_text_buffer_set_text(approve_buffer, "", 0);
  approve_buttons.clear();

  // Read the patch.
  vector < Patch > patches = merge_read_patch(approve_patch_file);

  // Show the master file in the textview, with buttons for approval of patches.
  ReadText rt(approve_master_file, true, false);
  for (unsigned int i = 0; i < rt.lines.size(); i++) {

    // Text iterator.
    GtkTextIter iter;

    // Handle new line.
    string s = merge_new_line_indicator();
    if (rt.lines[i].find(trim(s)) != string::npos) {
      gtk_text_buffer_get_end_iter(approve_buffer, &iter);
      gtk_text_buffer_insert(approve_buffer, &iter, "\n", -1);
      continue;
    }
    // Skip verse indicators.
    if (rt.lines[i].find(merge_verse_indicator()) != string::npos) {
      continue;
    }
    // Insert normal text.
    gtk_text_buffer_get_end_iter(approve_buffer, &iter);
    gtk_text_buffer_insert(approve_buffer, &iter, rt.lines[i].c_str(), -1);

    // If there's a patch here, show it.
    for (unsigned int i2 = 0; i2 < patches.size(); i2++) {
      if (i + 1 == patches[i2].linenumber) {    // (diff starts at line 1, but we start at line 0).

        // Add a space before the button.
        gtk_text_buffer_get_end_iter(approve_buffer, &iter);
        gtk_text_buffer_insert(approve_buffer, &iter, " ", 1);

        // Insert a button with the patch.
        gtk_text_buffer_get_end_iter(approve_buffer, &iter);
        GtkTextChildAnchor *childanchor = gtk_text_buffer_create_child_anchor(approve_buffer, &iter);
        GtkWidget *button = gtk_button_new();

        GtkWidget *alignment;
        alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
        gtk_widget_show(alignment);
        gtk_container_add(GTK_CONTAINER(button), alignment);

        GtkWidget *hbox;
        hbox = gtk_hbox_new(FALSE, 2);
        gtk_widget_show(hbox);
        gtk_container_add(GTK_CONTAINER(alignment), hbox);

        GtkWidget *image;
        if (patches[i2].addition)
          image = gtk_image_new_from_stock("gtk-add", GTK_ICON_SIZE_BUTTON);
        else
          image = gtk_image_new_from_stock("gtk-remove", GTK_ICON_SIZE_BUTTON);
        gtk_widget_show(image);
        gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);

        GtkWidget *label;
        label = gtk_label_new_with_mnemonic(patches[i2].change.c_str());
        gtk_widget_show(label);
        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);

        gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(textview_approval), button, childanchor);
        gtk_widget_show_all(button);
        g_signal_connect((gpointer) button, "clicked", G_CALLBACK(on_button_approve_clicked), gpointer(this));

        // Store button and patch.
        ApproveButton approvebutton(0);
        approvebutton.button = GTK_BUTTON(button);
        approvebutton.patch = patches[i2];
        approve_buttons.push_back(approvebutton);

      }
    }

    // Add space after the text.
    gtk_text_buffer_get_end_iter(approve_buffer, &iter);
    gtk_text_buffer_insert(approve_buffer, &iter, " ", 1);

  }
}
Пример #9
0
void GwSpawn::run()
/*
On Windows the normal routines of glib cannot be used well, because they show
a console window when running certain commands like mkdir, ping, etc.
Therefore this version of run() uses Windows specific system calls.
These calls allow one to hide the console window.
*/
{
  describe();
  // Working directory.
  const gchar *workingdirectory = NULL;
  if (!myworkingdirectory.empty())
    workingdirectory = myworkingdirectory.c_str();
  /*
     The trick to running a console window silent is in the STARTUPINFO 
     structure that we pass into the CreateProcess function. 
     STARTUPINFO specifies the main window properties. 
     There are many items in the STARTUPINFO structure that we don't care about. 
     The ones that are of interest are:
     * DWORD cb
     * DWORD dwFlags
     * WORD wShowWindow
   */
  // The STARTUPINFO is instantiated.
  STARTUPINFO StartupInfo;
  PROCESS_INFORMATION ProcessInfo;
  // The memory is cleared for the length of the structure.
  memset(&StartupInfo, 0, sizeof(StartupInfo));
  // Fill the structure with the relevant code 
  // that will tell the console window to start up without showing itself.
  StartupInfo.cb = sizeof(STARTUPINFO);
  StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  StartupInfo.wShowWindow = SW_HIDE;

  // Arguments to the program.
  char Args[4096];
  Args[0] = 0;

  // Environment.
  char *pEnvCMD = NULL;
  char const *pDefaultCMD = "CMD.EXE";
  // gwrappers.cpp: In member function 'void GwSpawn::run()':
  // gwrappers.cpp:420:23: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
  pEnvCMD = getenv("COMSPEC");

  if (pEnvCMD) {
    strcpy(Args, pEnvCMD);
  } else {
    strcpy(Args, pDefaultCMD);
  }

  // The "/c" option - Do the command then terminate the command window.
  strcat(Args, " /c ");
  // The application you would like to run from the command window.
  strcat(Args, myprogram.c_str());
  // The parameters passed to the application being run from the command window.
  // The arguments have been quoted and spaced already.
  for (unsigned int i = 0; i < myarguments.size(); i++) {
    strcat(Args, myarguments[i].c_str());
  }

  // Get the suffix for the files to be piped. It has the seconds and 
  // microseconds in them, to allow for parallel usage of these pipes.
  ustring pipe_suffix;
  if ((!mydevnull) || (!mywrite.empty())) {
    GTimeVal gtimeval;
    g_get_current_time(&gtimeval);
    pipe_suffix = convert_to_string((long unsigned int)gtimeval.tv_sec) + convert_to_string((long unsigned int)gtimeval.tv_usec);
  }
  // If there is standard input, create the file to be piped.
  // Write the text into that file. Add the file to the arguments.
  if (!mywrite.empty()) {
    ustring pipe_in = gw_build_filename(Directories->get_temp(), "stdin" + pipe_suffix);
    WriteText wt(pipe_in);
    wt.text(mywrite);
    strcat(Args, " <");
    strcat(Args, shell_quote_space(pipe_in).c_str());
  }
  // If the output is not sent to "nul", then create piped files.
  ustring pipe_out;
  ustring pipe_err;
  if (!mydevnull) {
    pipe_out = gw_build_filename(Directories->get_temp(), "stdout" + pipe_suffix);
    pipe_err = gw_build_filename(Directories->get_temp(), "stderr" + pipe_suffix);
    ustring pout = shell_quote_space(pipe_out);
    ustring perr = shell_quote_space(pipe_err);
    strcat(Args, " >");
    strcat(Args, pout.c_str());
    strcat(Args, " 2>");
    strcat(Args, perr.c_str());
  }
  // Start the process.
  result = CreateProcess(NULL, Args, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, workingdirectory, &StartupInfo, &ProcessInfo);
  if (!result) {
    exitstatus = GetLastError();
    ustring message = myprogram;
    message.append(_(" didn't spawn"));
    gw_critical(message);
    return;
  }
  // Handle progress function.
  if (myprogress) {
    ProgressWindow progresswindow(mytext, myallowcancel);
    // Time passed to WaitForSingleObject is in milliseconds.
    while ((WaitForSingleObject(ProcessInfo.hProcess, 500) >= 500)
           || (WaitForSingleObject(ProcessInfo.hThread, 500) >= 500)) {
      progresswindow.pulse();
      if (progresswindow.cancel) {
// todo        unix_kill (pid);
        cancelled = true;
      }
    }
  }
  // Handle sync mode.
  if (!myasync) {
    // Wait for it to finish.
    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
    WaitForSingleObject(ProcessInfo.hThread, INFINITE);
  }
  // Get the exit code.
  ULONG rc;
  if (!GetExitCodeProcess(ProcessInfo.hProcess, &rc))
    rc = 0;
  exitstatus = rc;

  // Close handles.
  CloseHandle(ProcessInfo.hThread);
  CloseHandle(ProcessInfo.hProcess);

  // Read the pipe files if we don't sent the output to "nul".
  if (!mydevnull) {
    gchar *standard_output;
    g_file_get_contents(pipe_out.c_str(), &standard_output, NULL, NULL);
    gchar *standard_error;
    g_file_get_contents(pipe_err.c_str(), &standard_error, NULL, NULL);
    // Handle case we read the output. Else dump it to stdout/err.
    if (myread) {
      if (standard_output) {
        ParseLine parse_out(standard_output);
        standardout = parse_out.lines;
      }
      if (standard_error) {
        ParseLine parse_err(standard_error);
        standarderr = parse_err.lines;
      }
    } else {
      if (standard_output)
        tiny_spawn_write(1, standard_output);
      if (standard_error)
        tiny_spawn_write(2, standard_error);
    }
    // Free data.
    if (standard_output)
      g_free(standard_output);
    if (standard_error)
      g_free(standard_error);
  }
}