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; }
void XeTeX::write_document_tex_file () { // Settings. extern Settings * settings; ProjectConfiguration *projectconfig = settings->projectconfig(settings->genconfig.project_get()); // Style sheet. extern Styles * styles; Stylesheet * sheet = styles->stylesheet (stylesheet_get_actual ()); document_tex.push_back (_("% Configuration file created by Bibledit-Gtk")); document_tex.push_back (_("% You can modify it to suit your needs")); document_tex.push_back (_("% After modification, run the following command in this directory:")); document_tex.push_back (_("% xetex document.tex")); document_tex.push_back (_("% After that look carefully at the output")); document_tex.push_back (_("% If it says that a re-run is required, repeat this command")); document_tex.push_back (""); document_tex.push_back (_("% Include the ptx2pdf macros")); document_tex.push_back ("\\input paratext2.tex"); document_tex.push_back (""); document_tex.push_back (_("% Paper size")); document_tex.push_back ("\\PaperWidth=" + convert_to_string (settings->genconfig.paper_width_get()) + "cm"); document_tex.push_back ("\\PaperHeight=" + convert_to_string (settings->genconfig.paper_height_get()) + "cm"); if (settings->session.print_crop_marks){ document_tex.push_back (""); document_tex.push_back (_("% Crop marks")); document_tex.push_back ("\\CropMarkstrue"); } document_tex.push_back (""); document_tex.push_back (_("% The basic unit for the margins; changing this will alter them all")); document_tex.push_back ("\\MarginUnit=1cm"); document_tex.push_back (""); document_tex.push_back (_("% Relative sizes of margins, based on the unit above")); document_tex.push_back ("\\def\\TopMarginFactor{" + convert_to_string (settings->genconfig.paper_top_margin_get()) + "}"); document_tex.push_back ("\\def\\BottomMarginFactor{" + convert_to_string (settings->genconfig.paper_bottom_margin_get()) + "}"); document_tex.push_back ("\\def\\SideMarginFactor{" + convert_to_string (settings->genconfig.paper_outside_margin_get()) + "}"); if (settings->genconfig.paper_inside_margin_get() != settings->genconfig.paper_outside_margin_get()) { document_tex.push_back (""); document_tex.push_back (_("% Extra margin for the gutter on the binding side")); document_tex.push_back ("\\BindingGuttertrue"); document_tex.push_back ("\\BindingGutter=" + convert_to_string (settings->genconfig.paper_inside_margin_get() - settings->genconfig.paper_outside_margin_get()) + "cm"); document_tex.push_back (""); document_tex.push_back (_("% Double sided printing")); document_tex.push_back ("\\DoubleSidedtrue"); } if (!projectconfig->editor_font_default_get()) { PangoFontDescription *font_desc = pango_font_description_from_string(projectconfig->editor_font_name_get().c_str()); if (font_desc){ // Assemble the string for the font mapping. ustring font_mapping = projectconfig->xetex_font_mapping_file_get(); if (!font_mapping.empty()) { if (g_str_has_suffix (font_mapping.c_str(), ".tec")) { font_mapping = gw_path_get_basename (font_mapping); // Remove the .tec suffix. font_mapping.erase (font_mapping.length() - 4, 4); // Insert the mapping command. font_mapping.insert (0, "mapping="); } else { gw_warning (_("Font mapping file ") + font_mapping + _(" should have the .tec suffix - ignoring this file")); font_mapping.clear(); } } // Assemble the string for the shaping engine. ustring shaping_engine; switch (XeTeXScriptingEngineType (projectconfig->xetex_shaping_engine_get())) { case xtxsetGeneric: break; case xtxsetArab: shaping_engine = "script=arab"; break; } // Assemble the addition to the font. ustring font_addition; if (!font_mapping.empty()) { if (font_addition.empty()) font_addition.append (":"); else font_addition.append (";"); font_addition.append (font_mapping); } if (!shaping_engine.empty()) { if (font_addition.empty()) font_addition.append (":"); else font_addition.append (";"); font_addition.append (shaping_engine); } ustring font_family = pango_font_description_get_family (font_desc); document_tex.push_back (""); document_tex.push_back (_("% Fonts to use for \"plain\", \"bold\", \"italic\", and \"bold italic\" from the stylesheet")); document_tex.push_back (_("% (they need not really be italic, etc.)")); document_tex.push_back (_("% Add e.g. \":mapping=farsidigits\" to get digits in Farsi, provided the farsidigits.tec TECkit mapping is available")); document_tex.push_back (_("% Add e.g. \":script=arab\" to use the arab shaping engine instead of the generic one")); document_tex.push_back ("\\def\\regular{\"" + font_family + font_addition + "\"}"); document_tex.push_back ("\\def\\bold{\"" + font_family + "/B" + font_addition + "\"}"); document_tex.push_back ("\\def\\italic{\"" + font_family + "/I" + font_addition + "\"}"); document_tex.push_back ("\\def\\bolditalic{\"" + font_family + "/BI" + font_addition + + "\"}"); pango_font_description_free(font_desc); } } if (projectconfig->right_to_left_get()) { document_tex.push_back (""); document_tex.push_back (_("% Right-to-left layout mode")); document_tex.push_back ("\\RTLtrue"); } document_tex.push_back (""); document_tex.push_back (_("% The unit for font sizes in the stylesheet; changing this will scale all text proportionately")); document_tex.push_back ("\\FontSizeUnit=1pt"); document_tex.push_back (""); document_tex.push_back (_("% Scaling factor used to adjust line spacing, relative to font size")); double line_spacing_factor = 1.0; double vertical_space_factor = 1.0; if (!projectconfig->editor_font_default_get()){ line_spacing_factor = projectconfig->text_line_height_get() / 100; vertical_space_factor = projectconfig->text_line_height_get() / 100; } document_tex.push_back ("\\def\\LineSpacingFactor{" + convert_to_string (line_spacing_factor) + "}"); document_tex.push_back ("\\def\\VerticalSpaceFactor{" + convert_to_string (vertical_space_factor) + "}"); document_tex.push_back (""); document_tex.push_back (_("% Information to include in the running header (at top of pages, except first)")); document_tex.push_back (_("% We set the items to print at left/center/right of odd and even pages separately")); document_tex.push_back (_("% Possible contents:")); document_tex.push_back (_("% \\rangeref = Scripture reference of the range of text on the page;")); document_tex.push_back (_("% \\firstref = reference of the first verse on the page)")); document_tex.push_back (_("% \\lastref = reference of the last verse on the page)")); document_tex.push_back (_("% \\pagenumber = the page number")); document_tex.push_back (_("% \\empty = print nothing in this position")); document_tex.push_back ("\\def\\RHoddleft{\\empty}"); document_tex.push_back ("\\def\\RHoddcenter{\\empty}"); document_tex.push_back ("\\def\\RHoddright{\\rangeref}"); document_tex.push_back (""); document_tex.push_back ("\\def\\RHevenleft{\\rangeref}"); document_tex.push_back ("\\def\\RHevencenter{\\empty}"); document_tex.push_back ("\\def\\RHevenright{\\empty}"); document_tex.push_back (""); document_tex.push_back ("\\def\\RHtitleleft{\\empty}"); document_tex.push_back ("\\def\\RHtitlecenter{\\empty}"); document_tex.push_back ("\\def\\RHtitleright{\\empty}"); document_tex.push_back (""); document_tex.push_back ("\\def\\RFoddcenter{\\pagenumber}"); document_tex.push_back ("\\def\\RFevencenter{\\pagenumber}"); document_tex.push_back ("\\def\\RFtitlecenter{\\pagenumber}"); document_tex.push_back (""); document_tex.push_back (_("% Whether to include verse number in running head, or only chapter")); document_tex.push_back ("\\VerseRefstrue"); document_tex.push_back (""); document_tex.push_back (_("% Whether to skip printing verse number 1 at start of chapter")); document_tex.push_back ("\\OmitVerseNumberOnetrue"); document_tex.push_back (""); document_tex.push_back (_("% Whether to use paragraph indent at drop-cap chapter numbers")); document_tex.push_back (_("% \\IndentAtChaptertrue")); // Go through the stylesheet looking for note markers. for (unsigned int i = 0; i < sheet->styles.size(); i++) { bool retrieve_note_data = false; StyleV2 * style = sheet->styles[i]; if (style->type == stFootEndNote) { if ((style->subtype == fentFootnote) || (style->subtype == fentEndnote)) { retrieve_note_data = true; } } if ((style->type == stFootEndNote) || (style->type == stCrossreference)) { if (style->subtype == ctCrossreference) { retrieve_note_data = true; } } if (retrieve_note_data) { ustring marker = style->marker; document_tex.push_back (""); document_tex.push_back (_("% Reformat \\") + marker + " notes as a single paragraph"); document_tex.push_back ("\\ParagraphedNotes{" + marker + "}"); document_tex.push_back (""); NoteNumberingType note_numbering = NoteNumberingType (style->userint1); switch (note_numbering) { case nntNumerical: document_tex.push_back (_("% Numerical callers for \\") + marker + _(" notes")); document_tex.push_back ("\\NumericCallers{" + marker + "}"); break; case nntAlphabetical: document_tex.push_back (_("% Alphabetical callers for \\") + marker + _(" notes")); document_tex.push_back ("\\AutoCallers{" + marker+ "}{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}"); break; case nntUserDefined: ustring autocallers; for (unsigned int i = 0; i < style->userstring1.size(); i++) { if (i) autocallers.append (","); autocallers.append (style->userstring1.substr (i, 1)); } if (!autocallers.empty()) { document_tex.push_back (_("% Special caller sequence for \\") + marker + " notes"); document_tex.push_back ("\\AutoCallers{" + marker+ "}{" + autocallers + "}"); } break; } document_tex.push_back (""); NoteNumberingRestartType note_restart = NoteNumberingRestartType (style->userint2); switch (note_restart) { case nnrtNever: break; case nnrtBook: break; case nnrtChapter: break; } document_tex.push_back (_("% Reset callers every page for \\") + marker + _(" notes")); document_tex.push_back ("\\PageResetCallers{" + marker + "}"); document_tex.push_back (""); document_tex.push_back (_("% Omit callers in the note for \\") + marker + _(" notes")); document_tex.push_back (_("% \\OmitCallerInNote{") + marker + "}"); } } document_tex.push_back (""); document_tex.push_back (_("% The number of columns")); document_tex.push_back ("\\TitleColumns=1"); document_tex.push_back ("\\IntroColumns=1"); document_tex.push_back ("\\BodyColumns=2"); document_tex.push_back (""); document_tex.push_back (_("% The gutter between double cols, relative to font size")); document_tex.push_back ("\\def\\ColumnGutterFactor{15}"); // Define the Paratext stylesheet to be used as a basis for formatting write_stylesheet (); // Write the data and add their filenames. for (unsigned int i = 0; i < book_ids.size(); i++) { ustring filename = convert_to_string (book_ids[i]) + " " + books_id_to_english(book_ids[i]) + ".usfm"; replace_text (filename, " ", "_"); write_lines (gw_build_filename (working_directory, filename), book_data[i]); document_tex.push_back ("\\ptxfile{" + filename + "}"); } // End of document input. document_tex.push_back ("\\end"); // Write document.text to file. write_lines (gw_build_filename (working_directory, "document.tex"), document_tex); }