Example #1
0
void WindowMerge::copy_master_to_edited_all()
{
  {
    vector <unsigned int> books = project_get_books(current_master_project);
    ProgressWindow progresswindow(_("Copying..."), false);
    progresswindow.set_iterate(0, 1, books.size());
    for (unsigned int bk = 0; bk < books.size(); bk++) {
      progresswindow.iterate();
      vector < unsigned int >chapters = project_get_chapters(current_master_project, books[bk]);
      for (unsigned int ch = 0; ch < chapters.size(); ch++) {
        copy_master_to_edited_chapter(books[bk], chapters[ch], false);
      }
    }
  }
  ustring message = _("All chapters of project ") + current_master_project + _(" were copied to project ") + current_edited_project;
  gtkw_dialog_info(NULL, message.c_str());
}
Example #2
0
void NotesTransferDialog::on_okbutton()
{
  // Get the project.
  extern Settings *settings;
  ustring project = settings->genconfig.project_get();

  // Progress.
  ProgressWindow progresswindow(_("Transferring text to notes"), false);

  // Get the category into which to insert notes.
  ustring category = combobox_get_active_string(combobox1);

  // Go through the books in the project.
  vector < unsigned int >books = project_get_books(project);
  for (unsigned int bk = 0; bk < books.size(); bk++) {

    // Progress.
    progresswindow.set_text(books_id_to_english(books[bk]));

    // Go through the chapters in this book. Progress.
    vector < unsigned int >chapters = project_get_chapters(project, books[bk]);
    progresswindow.set_iterate(0, 1, chapters.size());
    for (unsigned int ch = 0; ch < chapters.size(); ch++) {
      progresswindow.iterate();

      // Go through the verses in this chapter.
      vector < ustring > verses = project_get_verses(project, books[bk], chapters[ch]);
      for (unsigned int vs = 0; vs < verses.size(); vs++) {

        // Retrieve each verse and insert it into the notes.
        ustring text = project_retrieve_verse(project, books[bk], chapters[ch], verses[vs]);
        clean_note(text);
        if (!text.empty()) {
          transfer_note(project, books[bk], chapters[ch], verses[vs], text, category);
        }

      }
    }
  }
}
void view_parallel_bible_pdf()
{
  // Log.
  gw_message(_("Printing Parallel Bible"));

  // Configuration
  extern Settings *settings;

  // Get the chapters and check them.
  vector < unsigned int >chapters = project_get_chapters(settings->genconfig.project_get(), settings->genconfig.book_get());
  if (chapters.empty()) {
    gtkw_dialog_info(NULL, books_id_to_english(settings->genconfig.book_get()) + _("does not exist in this project"));
    return;
  }
  // Progress system.
  ProgressWindow progresswindow(_("Parallel Bible"), true);
  progresswindow.set_text(_("Collecting verses"));
  progresswindow.set_iterate(0, 1, chapters.size());

  // Messages to be printed first.
  vector < ustring > messages;

  // All the projects to be put in this parallel Bible.
  // If the book exists in the project, add it, else give message.
  vector <ustring> project_s_raw;
  {
    vector <ustring> bibles = settings->genconfig.parallel_bible_projects_get();
    vector <bool> enabled = settings->genconfig.parallel_bible_enabled_get();
    if (bibles.size () == enabled.size()) {
      for (unsigned int i = 0; i < enabled.size(); i++) {
        if (enabled[i]) {
          project_s_raw.push_back (bibles[i]);
        }
      }
    }
  }
  vector < ustring > project_names;
  for (unsigned int i = 0; i < project_s_raw.size(); i++) {
    if (project_book_exists(project_s_raw[i], settings->genconfig.book_get())) {
      project_names.push_back(project_s_raw[i]);
    } else {
      messages.push_back(_("Project ") + project_s_raw[i] + _(" was requested to be included, but it does not contain ") + books_id_to_english(settings->genconfig.book_get()) + _(". It was left out."));
    }
  }

  // References to print.
  vector < Reference > references;

  // Portion selection.
  WithinReferencesRange inrange;
  {
    vector < unsigned int >portions_chapter_from, portions_chapter_to;
    vector < ustring > portions_verse_from, portions_verse_to;
    select_portion_get_values(settings->genconfig.project_get(), settings->genconfig.book_get(), settings->genconfig.parallel_bible_chapters_verses_get(), portions_chapter_from, portions_verse_from, portions_chapter_to, portions_verse_to);
    inrange.add_portion(settings->genconfig.book_get(), portions_chapter_from, portions_verse_from, portions_chapter_to, portions_verse_to);
    inrange.set_book(settings->genconfig.book_get());
  }

  // Go through the chapters.
  for (unsigned int ch = 0; ch < chapters.size(); ch++) {

    progresswindow.iterate();

    inrange.set_chapter(chapters[ch]);

    // Go through the verse numbers in this chapter.
    vector < ustring > verses = project_get_verses(settings->genconfig.project_get(), settings->genconfig.book_get(), chapters[ch]);
    for (unsigned int vs = 0; vs < verses.size(); vs++) {

      inrange.set_verse(verses[vs]);
      if (!inrange.in_range())
        continue;

      // See whether to print verses zero.
      if (!settings->genconfig.parallel_bible_include_verse_zero_get())
        if (verses[vs] == "0")
          continue;

      // Store the reference.
      Reference reference(settings->genconfig.book_get(), chapters[ch], verses[vs]);
      references.push_back(reference);
    }
  }

  // Hide progeressbar.
  progresswindow.hide();

  // Do the printing.
  ProjectMemory projectmemory(settings->genconfig.project_get(), true);
  view_parallel_references_pdf(projectmemory, &project_names, references, settings->genconfig.parallel_bible_keep_verses_together_get(), &messages, false);

  // Log: ready.
  gw_message(_("Ready printing the Parallel Bible"));
}
Example #4
0
void search_string_basic(const ustring & project, bool use_book_selection, unsigned int currentchapter, vector <Reference> &results)
/*
Basic search for a string in the text.
project: project to search.
use_book_selection: whether to limit searches to the selected books only.
chapter: currently opened chapter in the editor.
results: will contain the search results.
*/
{
  // Settings.
  extern Settings *settings;
  // Case sensitive
  bool casesensitive = settings->session.search_case_sensitive;
  // The string to search for. 
  // We need to normalize the search expression when comparing strings.
  ustring localsearchword(settings->session.searchword);
  localsearchword = localsearchword.normalize();
  if (!casesensitive)
    localsearchword = localsearchword.casefold();
  // Book and chapter selection.
  bool search_current_chapter = settings->session.search_current_chapter;
  set <unsigned int> selectedbooks = settings->session.selected_books;
  // Get all books.
  vector <unsigned int> books = project_get_books(project);
  // Progress.
  ProgressWindow progresswindow(_("Searching"), false);
  progresswindow.set_iterate(0, 1, books.size());
  // Go through all books.
  for (unsigned int bk = 0; bk < books.size(); bk++) {
    progresswindow.iterate();
    unsigned int book = books[bk];
    // Handle possible case of book selection.
    if (use_book_selection) {
      if (selectedbooks.find(book) == selectedbooks.end()) {
        continue;
      }
    }
    // Get all chapters and go through them.
    vector <unsigned int> chapters = project_get_chapters(project, book);
    for (unsigned int ch = 0; ch < chapters.size(); ch++) {
      unsigned int chapter = chapters[ch];
      // Do we search this chapter?
      if (search_current_chapter) {
        if (chapter != currentchapter)
          continue;
      }
      // Take a quick peek at the chapter if the word is there.
      ustring chapterfilename = project_data_filename_chapter(project, book, chapter, false);
      gchar *quickcontent;
      bool wordfound = false;
      if (g_file_get_contents(chapterfilename.c_str(), &quickcontent, NULL, NULL)) {
        gchar *foundlocation;
        if (casesensitive) {
          foundlocation = g_strrstr(quickcontent, localsearchword.c_str());
        } else {
          gchar *casefoldedcontent = g_utf8_casefold(quickcontent, -1);
          foundlocation = g_strrstr(casefoldedcontent, localsearchword.c_str());
          if (casefoldedcontent)
            g_free(casefoldedcontent);
        }
        if (foundlocation)
          wordfound = true;
      }
      if (quickcontent)
        g_free(quickcontent);
      if (wordfound) {
        ReadText rt(chapterfilename, true, false);
        CategorizeChapterVerse ccv(rt.lines);
        for (unsigned int i = 0; i < ccv.verse.size(); i++) {
          if (!casesensitive)
            ccv.line[i] = ccv.line[i].casefold();
          if (ccv.line[i].find(localsearchword) != string::npos) {
            Reference reference(book, chapter, ccv.verse[i]);
            results.push_back(reference);
          }
        }
      }
    }
  }
}
Example #5
0
vector < Reference > search_in_bibledit()
// Advanced searching in Bibledit.
{
  // Configuration / session
  extern Settings *settings;
  // Set some variables in memory for higher speed.
  bool casesensitive = settings->session.search_case_sensitive;
  bool search_current_book = settings->session.search_current_book;
  bool search_current_chapter = settings->session.search_current_chapter;
  bool search_globbing = settings->session.search_globbing;
  bool search_start_word_match = settings->session.search_start_word_match;
  bool search_end_word_match = settings->session.search_end_word_match;
  set < unsigned int >selected_books = settings->session.selected_books;
  AreaType areatype = settings->session.area_type;
  bool area_id = settings->session.area_id;
  bool area_intro = settings->session.area_intro;
  bool area_heading = settings->session.area_heading;
  bool area_chapter = settings->session.area_chapter;
  bool area_study = settings->session.area_study;
  bool area_notes = settings->session.area_notes;
  bool area_xref = settings->session.area_xref;
  bool area_verse = settings->session.area_verse;

  // Progress information.
  ProgressWindow progresswindow(_("Searching"), true);

  // The string to search for. 
  // Note any apostrophies need to be doubled for SQLite.
  // We need to normalize the search expression when comparing strings.
  ustring localsearchword(settings->session.searchword.normalize());
  if (!casesensitive)
    localsearchword = localsearchword.casefold();
  ustring localsearchword2(localsearchword);

  // Storage for references: search results.
  vector < Reference > results;

  // Get our position in the text.
  ustring project = settings->genconfig.project_get();
  ustring book = books_id_to_english(settings->genconfig.book_get());
  unsigned int chapter = convert_to_int(settings->genconfig.chapter_get());

  // Go through each book in the project. Progress information.
  vector < unsigned int >availablebooks = project_get_books(project);
  progresswindow.set_iterate(0, 1, availablebooks.size());
  for (unsigned int bk = 0; bk < availablebooks.size(); bk++) {
    progresswindow.iterate();
    if (progresswindow.cancel) {
      return results;
    }
    // If the book is not to be searched, skip it.
    if (search_current_book)
      if (book != books_id_to_english(availablebooks[bk]))
        continue;
    if (selected_books.find(availablebooks[bk]) == selected_books.end())
      continue;

    try {
      // Go through each chapter in the book.
      vector < unsigned int >chapters = project_get_chapters(project, availablebooks[bk]);
      for (unsigned int ch = 0; ch < chapters.size(); ch++) {

        // Do we search this chapter?
        if (search_current_chapter)
          if (chapter != chapters[ch])
            continue;

        // Read the chapter.
        vector < ustring > lines = project_retrieve_chapter(project, availablebooks[bk], chapters[ch]);
        CategorizeChapterVerse ccv(lines);

        // Go through the verses.
        for (unsigned int i = 0; i < ccv.verse.size(); i++) {

          // Verse number.
          ustring verse = ccv.verse[i];

          // Handle casesensitive and area selection.
          // Assemble text to search through.
          ustring input(ccv.line[i]);
          if (!casesensitive)
            input = input.casefold();
          ustring text = search_in_bibledit_assemble_line(input, areatype, area_id, area_intro, area_heading, area_chapter, area_study, area_notes, area_xref, area_verse);

          // Use glob-style pattern matching or straight match.
          if (search_globbing) {
            ustring patternword = "*" + localsearchword + "*";
            if (!g_pattern_match_simple(patternword.c_str(), text.c_str()))
              continue;
          } else {
            if (text.find(localsearchword) == string::npos)
              continue;
          }

          // Do the word boundary matching.
          if (!search_in_bibledit_word_boundaries_match(text, localsearchword, search_start_word_match, search_end_word_match, search_globbing))
            continue;

          // This verse "passed" all tests: a search result.  
          Reference reference(availablebooks[bk], chapters[ch], verse);
          results.push_back(reference);
        }
      }
    }
    catch(exception & ex) {
      gw_critical(ex.what());
    }
  }

  // Give the results.
  return results;
}
Example #6
0
void ImportAssistant::on_assistant_apply ()
{
  // Take action depending on the type of import.
  switch (get_type()) {
    case itBible:
    {
      switch (get_bible_type()) {
        case ibtUsfm:
        {
	  ProgressWindow progresswindow(_("Importing files"), false);
        	progresswindow.set_iterate(0, 1, files_names.size());
        	for (unsigned int i = 0; i < files_names.size(); i++) {
        	  	progresswindow.iterate();
        	    import_usfm_file (files_names[i], files_book_ids[i], bible_name, summary_messages);
        	}
          break;
        }
        case ibtBibleWorks:
        {
          import_bibleworks_text_file (files_names[0], bible_name, summary_messages);
          break;
        }
        case ibtOnlineBible:
        {
          import_online_bible (my_windows_outpost, combobox_get_active_string (combobox_online_bible_bible), bible_name, summary_messages);
          break;
        }
        case ibtRawText:
        {
          summary_messages.push_back (_("Importing raw text is a manual process. The online help provides more information on that."));
          break;
        }
      }
      break;
    }
    case itReferences:
    {
      summary_messages.push_back (_("Importing references is done in the references window."));
      summary_messages.push_back (_("In that window, click on [actions], then click on \"Import a list of references\"."));
      break;
    }
    case itStylesheet:
    {
      if (my_styles_window) {
        my_styles_window->on_stylesheet_import();
      }
      break;
    }
    case itNotes:
    {
      summary_messages.push_back (_("After this window closes an opportunity will be offered to import notes."));
      import_notes = true;
      break;
    }
    case itKeyterms:
    {
      summary_messages.push_back (_("After this window closes an opportunity will be offered to import keyterms."));
      import_keyterms = true;
      break;
    }
  }
}
void view_parallel_references_pdf(ProjectMemory & main_project, vector < ustring > *extra_projects, vector < Reference > references, bool keep_verses_together_within_page, vector < ustring > *remarks, bool highlight)
/*
 Formats the references in "references", and highlights all words in
 "session->highlights*" and shows them in a pdf viewer.
 There is a pointer to a list of "remarks". Any remarks will be printed first.
 */
{
  // Log.
  gw_message(_("Printing parallel references"));

  // Progress system.
  ProgressWindow progresswindow(_("Printing Parallel References"), false);
  progresswindow.set_iterate(0, 1, references.size());

  // Configuration
  extern Settings *settings;
  ProjectConfiguration *projectconfig = settings->projectconfig(main_project.name);
  ustring stylesheet = stylesheet_get_actual ();

  // Store the additional projects to print.
  vector < ustring > additional_projects;
  if (extra_projects)
    additional_projects = *extra_projects;
  settings->session.additional_printing_projects = additional_projects;

  // Prepare for mapping.
  Mapping mapping(projectconfig->versification_get(), 0);

  // The converter.
  Text2Pdf text2pdf(gw_build_filename(Directories->get_temp(), "document.pdf"), settings->genconfig.print_engine_use_intermediate_text_get());

  // Page.
  text2pdf.page_size_set(settings->genconfig.paper_width_get(), settings->genconfig.paper_height_get());
  text2pdf.page_margins_set(settings->genconfig.paper_inside_margin_get(), settings->genconfig.paper_outside_margin_get(), settings->genconfig.paper_top_margin_get(), settings->genconfig.paper_bottom_margin_get());
  text2pdf.page_one_column_only();

  // Headers.
  if (settings->genconfig.printdate_get()) {
    text2pdf.print_date_in_header();
  }
  // Font, etc., of main project.
  ustring main_font = projectconfig->editor_font_name_get();
  unsigned int main_line_spacing = projectconfig->text_line_height_get();
  if (projectconfig->editor_font_default_get()) {
    main_font.clear();
    main_line_spacing = 100;
  }
  text2pdf.set_font(main_font);
  text2pdf.set_line_spacing(main_line_spacing);
  bool main_right_to_left = projectconfig->right_to_left_get();
  text2pdf.set_right_to_left(main_right_to_left);

  // Start off with inserting any remarks.
  if (remarks) {
    for (unsigned int r = 0; r < remarks->size(); r++) {
      text2pdf.open_paragraph();
      text2pdf.paragraph_set_column_count(1);
      text2pdf.add_text(remarks->at(r));
      text2pdf.close_paragraph();
    }
  }
  // Some variables to avoid excessive session access during highlighting.
  vector < bool > highlight_casesensitives;
  vector < ustring > highlight_words;
  if (highlight) {
    for (unsigned int hl = 0; hl < settings->session.highlights.size(); hl++) {
      highlight_casesensitives.push_back(settings->session.highlights[hl].casesensitive);
      highlight_words.push_back(settings->session.highlights[hl].word);
    }
  }
  // All the projects to be put in this parallel Bible, together with
  // their related information, like mapping, fonts.
  vector < ustring > project_names;
  vector < ProjectMemory > project_memories;
  vector < Mapping > mapping_s;
  vector < ustring > fonts;
  vector < unsigned int >line_spacings;
  vector < bool > right_to_lefts;
  if (extra_projects) {
    vector < ustring > project_s_raw = *extra_projects;
    for (unsigned int i = 0; i < project_s_raw.size(); i++) {
      ProjectMemory projectmemory(project_s_raw[i], true);
      project_memories.push_back(projectmemory);
      ProjectConfiguration *projectconfig = settings->projectconfig(project_s_raw[i]);
      project_names.push_back(project_s_raw[i]);
      Mapping mapping(projectconfig->versification_get(), 0);
      mapping_s.push_back(mapping);
      ustring font = projectconfig->editor_font_name_get();
      unsigned int line_spacing = projectconfig->text_line_height_get();
      if (projectconfig->editor_font_default_get()) {
        font.clear();
        line_spacing = 100;
      }
      fonts.push_back(font);
      line_spacings.push_back(line_spacing);
      right_to_lefts.push_back(projectconfig->right_to_left_get());
    }
  }
  // Produce chunks for all references.
  for (unsigned int rf = 0; rf < references.size(); rf++) {

    // Update progress bar.
    progresswindow.iterate();

    // Whether to keep things on one page.    
    if (keep_verses_together_within_page) {
      text2pdf.open_keep_together();
    }
    // Set main font, etc.
    text2pdf.set_font(main_font);
    text2pdf.set_line_spacing(main_line_spacing);
    text2pdf.set_right_to_left(main_right_to_left);

    // Add the reference to the text.
    text2pdf.add_text(references[rf].human_readable(""));

    // Map this verse to the original, that is, to Hebrew or Greek.
    vector <int> hebrew_greek_chapters;
    vector <int> hebrew_greek_verses;
    mapping.book_change(references[rf].book);
    mapping.me_to_original(references[rf].chapter, references[rf].verse, hebrew_greek_chapters, hebrew_greek_verses);
    // Get verse text for each version.
    for (unsigned int vsn = 0; vsn <= project_names.size(); vsn++) {

      // Add the font, etc., for each project.
      ustring font(main_font);
      unsigned int line_spacing = main_line_spacing;
      bool right_to_left = main_right_to_left;
      if (vsn > 0) {
        font = fonts[vsn - 1];
        line_spacing = line_spacings[vsn - 1];
        right_to_left = right_to_lefts[vsn - 1];
      }
      text2pdf.set_font(font);
      text2pdf.set_line_spacing(line_spacing);
      text2pdf.set_right_to_left(right_to_left);

      // Get the verse text.
      ustring line;
      if (vsn == 0) {
        // First version.
        ProjectBook *projectbook = main_project.get_book_pointer(references[rf].book);
        if (projectbook) {
          ProjectChapter *projectchapter = projectbook->get_chapter_pointer(references[rf].chapter);
          if (projectchapter) {
            ProjectVerse *projectverse = projectchapter->get_verse_pointer(references[rf].verse);
            if (projectverse) {
              line = projectverse->data;
            }
          }
        }
      } else {
        // Other versions. 
        // Get mapped chapters / verses.
        line.clear();
        vector <int> mychapters;
        vector <int> myverses;
        mapping_s[vsn - 1].book_change(references[rf].book);
        mapping_s[vsn - 1].original_to_me(hebrew_greek_chapters, hebrew_greek_verses, mychapters, myverses);
        // Get text of any of the mapped verses.
        for (unsigned int mp = 0; mp < mychapters.size(); mp++) {
          // Get the verse and add it to the usfm code.
          ProjectBook *projectbook = project_memories[vsn - 1].get_book_pointer(references[rf].book);
          if (projectbook) {
            ProjectChapter *projectchapter = projectbook->get_chapter_pointer(mychapters[mp]);
            if (projectchapter) {
              ProjectVerse *projectverse = projectchapter->get_verse_pointer(convert_to_string(myverses[mp]));
              if (projectverse) {
                if (!line.empty()) 
                  line.append (" ");
                line.append (projectverse->data);
              }
            }
          }
        }
      }

      // Add the project name if there are more than one.
      if (!project_names.empty()) {
        ustring project;
        if (vsn == 0)
          project = main_project.name;
        else
          project = project_names[vsn - 1];
        text2pdf.open_paragraph();
        text2pdf.inline_set_font_size_percentage(65);
        text2pdf.add_text(project);
        text2pdf.inline_clear_font_size_percentage();
        text2pdf.add_text(" ");
      } else {
        text2pdf.open_paragraph();
      }

      // Do text replacement.
      text_replacement(line);

      // Positions in the line, and lengths to highlight.
      vector < size_t > highlight_positions;
      vector < size_t > highlight_lengths;

      // Go through all the words to highlight.
      for (unsigned int i2 = 0; i2 < highlight_casesensitives.size(); i2++) {
        // Word to highlight
        ustring highlightword;
        if (highlight_casesensitives[i2])
          highlightword = highlight_words[i2];
        else
          highlightword = highlight_words[i2].casefold();
        // Variabele s holds a shadow string.
        ustring s;
        if (highlight_casesensitives[i2])
          s = line;
        else
          s = line.casefold();
        // Find positions for highlighting.
        size_t offposition = s.find(highlightword);
        while (offposition != string::npos) {
          // Store position and length.
          highlight_positions.push_back(offposition);
          highlight_lengths.push_back(highlightword.length());
          // Look for possible next word to highlight.
          offposition = offposition + highlightword.length() + 1;
          // There is something like a bug in s.find. If the offposition
          // is greater than the length of s, then s.find will return
          // a value below offposition, instead of string::npos as is
          // expected. Workaround.
          if (offposition > s.length())
            break;
          offposition = s.find(highlightword, offposition);
        }
      }
      // Sort the positions from small to bigger.
      xml_sort_positions(highlight_positions, highlight_lengths);
      // Combine overlapping positions.
      xml_combine_overlaps(highlight_positions, highlight_lengths);

      // Insert the code for highlighting.
      for (int i = highlight_positions.size () - 1; i >= 0; i--) {
        for (int i2 = highlight_lengths.size() - 1; i2 >= 0; i2--) {
          line.insert (highlight_positions[i] + i2, INSERTION_FLAG);
        }
      }

      // Add usfm converter to the layout engine, and set various things.
      Usfm2Text usfm2text(&text2pdf, false);
      usfm2text.add_styles(usfm2xslfo_read_stylesheet(stylesheet));

      usfm2text.no_bold();
      usfm2text.no_space_before_or_after();
      usfm2text.no_new_page();
      usfm2text.add_usfm_code(line);
      usfm2text.process();
    }

    // Add a bit of space.
    text2pdf.close_paragraph();
    text2pdf.add_text(" ");
    text2pdf.close_paragraph();

    // Whether to close code keeping things on one page.    
    if (keep_verses_together_within_page) {
      text2pdf.close_keep_together();
    }
  }

  // Hide progeressbar.
  progresswindow.hide();

  // Process the data.
  text2pdf.run();

  // Display the pdf file.
  text2pdf.view();

  // Log: ready.
  gw_message(_("Ready printing the parallel references"));
}
Example #8
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);
  }
}