lyx_mirror/src/insets/ExternalSupport.cpp
Christian Ridderström e30f3d76d2 Bulk cleanup/fix incorrect annotation at the end of namespaces.
This commit does a bulk fix of incorrect annotations (comments) at the
end of namespaces.

The commit was generated by initially running clang-format, and then
from the diff of the result extracting the hunks corresponding to
fixes of namespace comments. The changes being applied and all the
results have been manually reviewed. The source code successfully
builds on macOS.

Further details on the steps below, in case they're of interest to
someone else in the future.

1. Checkout a fresh and up to date version of src/

    git pull && git checkout -- src && git status src

2. Ensure there's a suitable .clang-format in place, i.e. with options
   to fix the comment at the end of namespaces, including:

    FixNamespaceComments:                           true
    SpacesBeforeTrailingComments:                   1

and that clang-format is >= 5.0.0, by doing e.g.:

    clang-format -dump-config | grep Comments:
    clang-format --version

3. Apply clang-format to the source:

    clang-format -i $(find src -name "*.cpp" -or -name "*.h")

4. Create and filter out hunks related to fixing the namespace

    git diff -U0 src > tmp.patch
    grepdiff '^} // namespace' --output-matching=hunk tmp.patch  > fix_namespace.patch

5. Filter out hunks corresponding to simple fixes into to a separate patch:

    pcregrep -M -e '^diff[^\n]+\nindex[^\n]+\n--- [^\n]+\n\+\+\+ [^\n]+\n'  \
        -e '^@@ -[0-9]+ \+[0-9]+ @@[^\n]*\n-\}[^\n]*\n\+\}[^\n]*\n'         \
        fix_namespace.patch > fix_namespace_simple.patch

6. Manually review the simple patch and then apply it, after first
   restoring the source.

    git checkout -- src
    patch -p1 < fix_namespace_simple.path

7. Manually review the (simple) changes and then stage the changes

    git diff src
    git add src

8. Again apply clang-format and filter out hunks related to any
   remaining fixes to the namespace, this time filter with more
   context. There will be fewer hunks as all the simple cases have
   already been handled:

    clang-format -i $(find src -name "*.cpp" -or -name "*.h")
    git diff src > tmp.patch
    grepdiff '^} // namespace' --output-matching=hunk tmp.patch  > fix_namespace2.patch

9. Manually review/edit the resulting patch file to remove hunks for files
   which need to be dealt with manually, noting the file names and
   line numbers. Then restore files to as before applying clang-format
   and apply the patch:

    git checkout src
    patch -p1 < fix_namespace2.patch

10. Manually fix the files noted in the previous step. Stage files,
    review changes and commit.
2017-07-23 13:11:54 +02:00

561 lines
16 KiB
C++

/**
* \file ExternalSupport.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Asger Alstrup Nielsen
* \author Angus Leeming
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "ExternalSupport.h"
#include "ExternalTemplate.h"
#include "ExternalTransforms.h"
#include "InsetExternal.h"
#include "Buffer.h"
#include "Converter.h"
#include "ErrorList.h"
#include "Exporter.h"
#include "Format.h"
#include "Mover.h"
#include "texstream.h"
#include "frontends/alert.h"
#include "support/debug.h"
#include "support/filetools.h"
#include "support/gettext.h"
#include "support/lstrings.h"
#include "support/lyxalgo.h"
#include "support/os.h"
#include "support/Package.h"
#include <algorithm>
using namespace std;
using namespace lyx::support;
namespace lyx {
namespace external {
Template const * getTemplatePtr(InsetExternalParams const & params)
{
TemplateManager const & etm = TemplateManager::get();
return etm.getTemplateByName(params.templatename());
}
void editExternal(InsetExternalParams const & params, Buffer const & buffer)
{
theFormats().edit(buffer, params.filename,
theFormats().getFormatFromFile(params.filename));
}
namespace {
string const subst_path(string const & input,
string const & placeholder,
string const & path,
bool use_latex_path,
latex_path_extension ext = PROTECT_EXTENSION,
latex_path_dots dots = LEAVE_DOTS)
{
if (input.find(placeholder) == string::npos)
return input;
// Don't use external_path here when use_latex_path is false, as the
// path will be compared with another one in internal style later
// in Converters::move.
string const path2 = use_latex_path ?
latex_path(path, ext, dots) : path;
return subst(input, placeholder, path2);
}
} // namespace
string const doSubstitution(InsetExternalParams const & params,
Buffer const & buffer, string const & s,
bool use_latex_path,
bool external_in_tmpdir,
Substitute what)
{
string result = s;
if (what != PATHS && contains(result, "$$pngOrjpg")) {
// This is for raster images and pdflatex:
// Since pdflatex supports both jpg and png, we choose the best format:
// jpg if the original file is jpg to retain the compression, else png.
string format = theFormats().getFormatFromFile(params.filename);
if (format == "jpg")
result = subst(result, "$$pngOrjpg", "jpg");
else
result = subst(result, "$$pngOrjpg", "png");
}
if (what == FORMATS)
return result;
Buffer const * masterBuffer = buffer.masterBuffer();
string const parentpath = external_in_tmpdir ?
masterBuffer->temppath() :
buffer.filePath();
string const filename = external_in_tmpdir ?
params.filename.mangledFileName() :
params.filename.outputFileName(parentpath);
string const basename = changeExtension(
onlyFileName(filename), string());
string const absname = makeAbsPath(filename, parentpath).absFileName();
if (what != ALL_BUT_PATHS) {
string const filepath = onlyPath(filename);
string const abspath = onlyPath(absname);
string const masterpath = external_in_tmpdir ?
masterBuffer->temppath() :
masterBuffer->filePath();
// FIXME UNICODE
string relToMasterPath = onlyPath(
to_utf8(makeRelPath(from_utf8(absname),
from_utf8(masterpath))));
if (relToMasterPath == "./")
relToMasterPath.clear();
// FIXME UNICODE
string relToParentPath = onlyPath(
to_utf8(makeRelPath(from_utf8(absname),
from_utf8(parentpath))));
if (relToParentPath == "./")
relToParentPath.clear();
result = subst_path(result, "$$FPath", filepath,
use_latex_path,
PROTECT_EXTENSION,
ESCAPE_DOTS);
result = subst_path(result, "$$AbsPath", abspath,
use_latex_path,
PROTECT_EXTENSION,
ESCAPE_DOTS);
result = subst_path(result, "$$RelPathMaster",
relToMasterPath, use_latex_path,
PROTECT_EXTENSION,
ESCAPE_DOTS);
result = subst_path(result, "$$RelPathParent",
relToParentPath, use_latex_path,
PROTECT_EXTENSION,
ESCAPE_DOTS);
if (FileName::isAbsolute(filename)) {
result = subst_path(result, "$$AbsOrRelPathMaster",
abspath, use_latex_path,
PROTECT_EXTENSION,
ESCAPE_DOTS);
result = subst_path(result, "$$AbsOrRelPathParent",
abspath, use_latex_path,
PROTECT_EXTENSION,
ESCAPE_DOTS);
} else {
result = subst_path(result, "$$AbsOrRelPathMaster",
relToMasterPath, use_latex_path,
PROTECT_EXTENSION,
ESCAPE_DOTS);
result = subst_path(result, "$$AbsOrRelPathParent",
relToParentPath, use_latex_path,
PROTECT_EXTENSION,
ESCAPE_DOTS);
}
}
if (what == PATHS)
return result;
result = subst_path(result, "$$FName", filename, use_latex_path,
EXCLUDE_EXTENSION);
result = subst_path(result, "$$Basename", basename, use_latex_path,
PROTECT_EXTENSION, ESCAPE_DOTS);
result = subst_path(result, "$$Extension",
'.' + getExtension(filename), use_latex_path);
result = subst_path(result, "$$Tempname", params.tempname().absFileName(), use_latex_path);
result = subst_path(result, "$$Sysdir",
package().system_support().absFileName(), use_latex_path);
// Handle the $$Contents(filename) syntax
if (contains(result, "$$Contents(\"")) {
// Since use_latex_path may be true we must extract the file
// name from s instead of result and do the substitutions
// again, this time with use_latex_path false.
size_t const spos = s.find("$$Contents(\"");
size_t const send = s.find("\")", spos);
string const file_template = s.substr(spos + 12, send - (spos + 12));
string const file = doSubstitution(params, buffer,
file_template, false,
external_in_tmpdir, what);
string contents;
FileName const absfile(
makeAbsPath(file, masterBuffer->temppath()));
if (absfile.isReadableFile())
// FIXME UNICODE
contents = to_utf8(absfile.fileContents("UTF-8"));
size_t const pos = result.find("$$Contents(\"");
size_t const end = result.find("\")", pos);
result.replace(pos, end + 2- pos, contents);
}
return result;
}
namespace {
/** update the file represented by the template.
If \p external_in_tmpdir == true, then the generated file is
placed in the buffer's temporary directory.
*/
void updateExternal(InsetExternalParams const & params,
string const & format,
Buffer const & buffer,
ExportData & exportdata,
bool external_in_tmpdir,
bool dryrun)
{
Template const * const et_ptr = getTemplatePtr(params);
if (!et_ptr)
return; // FAILURE
Template const & et = *et_ptr;
if (!et.automaticProduction)
return; // NOT_NEEDED
Template::Formats::const_iterator cit = et.formats.find(format);
if (cit == et.formats.end())
return; // FAILURE
Template::Format const & outputFormat = cit->second;
if (outputFormat.updateResult.empty())
return; // NOT_NEEDED
string from_format = et.inputFormat;
if (from_format.empty())
return; // NOT_NEEDED
if (from_format == "*") {
if (params.filename.empty())
return; // NOT_NEEDED
// Try and ascertain the file format from its contents.
from_format = theFormats().getFormatFromFile(params.filename);
if (from_format.empty())
return; // FAILURE
}
string const to_format = doSubstitution(params, buffer,
outputFormat.updateFormat, false, external_in_tmpdir, FORMATS);
if (to_format.empty())
return; // NOT_NEEDED
// The master buffer. This is useful when there are multiple levels
// of include files
Buffer const * masterBuffer = buffer.masterBuffer();
// We copy the source file to the temp dir and do the conversion
// there if necessary
bool const isDir = params.filename.isDirectory();
FileName const temp_file(
makeAbsPath(params.filename.mangledFileName(),
masterBuffer->temppath()));
if (!params.filename.empty() && !isDir) {
unsigned long const from_checksum = params.filename.checksum();
unsigned long const temp_checksum = temp_file.checksum();
if (from_checksum != temp_checksum) {
Mover const & mover = getMover(from_format);
if (!mover.copy(params.filename, temp_file)) {
LYXERR(Debug::EXTERNAL, "external::updateExternal. "
<< "Unable to copy " << params.filename << " to " << temp_file);
return; // FAILURE
}
}
}
// the generated file (always in the temp dir)
string const to_file = doSubstitution(params, buffer,
outputFormat.updateResult,
false, true);
FileName const abs_to_file(
makeAbsPath(to_file, masterBuffer->temppath()));
if (!dryrun) {
// Record the referenced files for the exporter.
// The exporter will copy them to the export dir.
typedef Template::Format::FileMap FileMap;
FileMap::const_iterator rit = outputFormat.referencedFiles.begin();
FileMap::const_iterator rend = outputFormat.referencedFiles.end();
for (; rit != rend; ++rit) {
vector<string>::const_iterator fit = rit->second.begin();
vector<string>::const_iterator fend = rit->second.end();
for (; fit != fend; ++fit) {
FileName const source(makeAbsPath(
doSubstitution(params, buffer, *fit,
false, true),
masterBuffer->temppath()));
// The path of the referenced file is never the
// temp path, but the filename may be the mangled
// or the real name. Therefore we substitute the
// paths and names separately.
string file = subst(*fit, "$$FName",
"$$FPath$$Basename$$Extension");
file = doSubstitution(params, buffer, file, false, false,
PATHS);
file = doSubstitution(params, buffer, file,
false, external_in_tmpdir,
ALL_BUT_PATHS);
// if file is a relative name, it is interpreted
// relative to the master document.
if (makeAbsPath(file, masterBuffer->filePath()) !=
params.filename.absFileName())
exportdata.addExternalFile(rit->first, source, file);
}
}
}
// Do we need to perform the conversion?
// Yes if to_file does not exist or if from_file is newer than to_file
// or if from_file is a directory (bug 9925)
if (!isDir && compare_timestamps(temp_file, abs_to_file) < 0)
return; // SUCCESS
// FIXME (Abdel 12/08/06): Is there a need to show these errors?
ErrorList el;
bool const success =
theConverters().convert(&buffer, temp_file, abs_to_file,
params.filename, from_format, to_format, el,
Converters::try_default | Converters::try_cache);
if (!success) {
LYXERR(Debug::EXTERNAL, "external::updateExternal. "
<< "Unable to convert from " << from_format << " to " << to_format);
}
// return success
}
string const substituteCommands(InsetExternalParams const & params,
string const & input, string const & format);
string const substituteOptions(InsetExternalParams const & params,
string const & input, string const & format);
} // namespace
void writeExternal(InsetExternalParams const & params,
string const & format,
Buffer const & buffer, otexstream & os,
ExportData & exportdata,
bool external_in_tmpdir,
bool dryrun)
{
Template const * const et_ptr = getTemplatePtr(params);
if (!et_ptr)
return;
Template const & et = *et_ptr;
Template::Formats::const_iterator cit = et.formats.find(format);
if (cit == et.formats.end()) {
LYXERR(Debug::EXTERNAL, "External template format '" << format
<< "' not specified in template " << params.templatename());
return;
}
if (!dryrun || contains(cit->second.product, "$$Contents"))
updateExternal(params, format, buffer, exportdata,
external_in_tmpdir, dryrun);
bool const use_latex_path = format == "LaTeX";
string str = doSubstitution(params, buffer, cit->second.product,
use_latex_path, external_in_tmpdir);
string const absname = makeAbsPath(
params.filename.outputFileName(buffer.filePath()), buffer.filePath()).absFileName();
if (!dryrun && !external_in_tmpdir) {
if (!isValidLaTeXFileName(absname)) {
lyx::frontend::Alert::warning(_("Invalid filename"),
_("The following filename will cause troubles "
"when running the exported file through LaTeX: ") +
from_utf8(absname));
}
if (!isValidDVIFileName(absname)) {
lyx::frontend::Alert::warning(_("Problematic filename for DVI"),
_("The following filename can cause troubles "
"when running the exported file through LaTeX "
"and opening the resulting DVI: ") +
from_utf8(absname), true);
}
}
str = substituteCommands(params, str, format);
str = substituteOptions(params, str, format);
// FIXME UNICODE
os << from_utf8(str);
return;
}
namespace {
// Empty template, specialised below.
template <typename TransformType>
string const substituteIt(string const &,
TransformID,
string const &,
Template::Format const &,
InsetExternalParams const &);
template <>
string const substituteIt<TransformCommand>(string const & input,
TransformID id,
string const & /* formatname */,
Template::Format const & format,
InsetExternalParams const & params)
{
typedef map<TransformID, TransformStore> Transformers;
Transformers::const_iterator it = format.command_transformers.find(id);
if (it == format.command_transformers.end())
return input;
TransformStore const & store = it->second;
TransformCommand::ptr_type ptr;
if (id == Rotate)
ptr = store.getCommandTransformer(params.rotationdata);
else if (id == Resize)
ptr = store.getCommandTransformer(params.resizedata);
if (!ptr)
return input;
string result =
subst(input, ptr->front_placeholder(), ptr->front());
return subst(result, ptr->back_placeholder(), ptr->back());
}
template <>
string const substituteIt<TransformOption>(string const & input,
TransformID id,
string const & fname,
Template::Format const & format,
InsetExternalParams const & params)
{
typedef map<TransformID, TransformStore> Transformers;
Transformers::const_iterator it = format.option_transformers.find(id);
if (it == format.option_transformers.end())
return input;
TransformStore const & store = it->second;
TransformOption::ptr_type ptr;
switch (id) {
case Clip:
ptr = store.getOptionTransformer(params.clipdata);
break;
case Extra:
ptr = store.getOptionTransformer(params.extradata.get(fname));
break;
case Rotate:
ptr = store.getOptionTransformer(params.rotationdata);
break;
case Resize:
ptr = store.getOptionTransformer(params.resizedata);
break;
}
if (!ptr)
return input;
return subst(input, ptr->placeholder(), ptr->option());
}
template <typename TransformerType>
string const transformIt(InsetExternalParams const & params,
string const & s, string const & formatname)
{
Template const * const et = getTemplatePtr(params);
if (!et || et->transformIds.empty())
return s;
Template::Formats::const_iterator fit = et->formats.find(formatname);
if (fit == et->formats.end())
return s;
string result = s;
Template::Format const & format = fit->second;
typedef vector<TransformID> TransformsIDs;
TransformsIDs::const_iterator it = et->transformIds.begin();
TransformsIDs::const_iterator end = et->transformIds.end();
for (; it != end; ++it) {
result = substituteIt<TransformerType>(result, *it, formatname,
format, params);
}
return result;
}
string const substituteCommands(InsetExternalParams const & params,
string const & input, string const & format)
{
return transformIt<TransformCommand>(params, input, format);
}
string const substituteOption(InsetExternalParams const & params,
string const & input, string const & format)
{
string opt = transformIt<TransformOption>(params, input, format);
if (format == "LaTeX" || format == "PDFLaTeX")
return sanitizeLatexOption(opt);
if (format == "DocBook")
return sanitizeDocBookOption(opt);
return opt;
}
string const substituteOptions(InsetExternalParams const & params,
string const & input, string const & format)
{
string output = input;
Template const * const et = getTemplatePtr(params);
if (!et || et->transformIds.empty())
return output;
Template::Formats::const_iterator fit = et->formats.find(format);
if (fit == et->formats.end() || fit->second.options.empty())
return output;
typedef vector<Template::Option> Options;
Options const & options = fit->second.options;
Options::const_iterator it = options.begin();
Options::const_iterator end = options.end();
for (; it != end; ++it) {
string const opt = substituteOption(params, it->option, format);
string const placeholder = "$$" + it->name;
output = subst(output, placeholder, opt);
}
return output;
}
} // namespace
} // namespace external
} // namespace lyx