do not hardcode packages loaded by external insets

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@40491 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Georg Baum 2011-12-13 19:40:05 +00:00
parent d2e8a5b8eb
commit 9b8773826c
6 changed files with 358 additions and 335 deletions

View File

@ -25,319 +25,12 @@
#include "support/lassert.h"
#include <cstring>
using namespace std;
using namespace lyx::support;
namespace lyx {
namespace {
/// used to return numeric values in parsing vspace
double number[4] = { 0, 0, 0, 0 };
/// used to return unit types in parsing vspace
Length::UNIT unit[4] = {
Length::UNIT_NONE,
Length::UNIT_NONE,
Length::UNIT_NONE,
Length::UNIT_NONE
};
/// the current position in the number array
int number_index;
/// the current position in the unit array
int unit_index;
/// skip n characters of input
inline void lyx_advance(string & data, size_t n)
{
data.erase(0, n);
}
/// return true when the input is at the end
inline bool isEndOfData(string const & data)
{
return ltrim(data).empty();
}
/**
* nextToken - return the next token in the input
* @param data input string
* @return a char representing the type of token returned
*
* The possible return values are :
* + stretch indicator for glue length
* - shrink indicator for glue length
* n a numeric value (stored in number array)
* u a unit type (stored in unit array)
* E parse error
*/
char nextToken(string & data)
{
data = ltrim(data);
if (data.empty())
return '\0';
if (data[0] == '+') {
lyx_advance(data, 1);
return '+';
}
if (prefixIs(data, "plus")) {
lyx_advance(data, 4);
return '+';
}
if (data[0] == '-') {
lyx_advance(data, 1);
return '-';
}
if (prefixIs(data, "minus")) {
lyx_advance(data, 5);
return '-';
}
size_t i = data.find_first_not_of("0123456789.");
if (i != 0) {
if (number_index > 3)
return 'E';
string buffer;
// we have found some number
if (i == string::npos) {
buffer = data;
i = data.size() + 1;
} else {
buffer = data.substr(0, i);
}
lyx_advance(data, i);
if (isStrDbl(buffer)) {
number[number_index] = convert<double>(buffer);
++number_index;
return 'n';
}
return 'E';
}
i = data.find_first_not_of("abcdefghijklmnopqrstuvwxyz%");
if (i != 0) {
if (unit_index > 3)
return 'E';
string buffer;
// we have found some alphabetical string
if (i == string::npos) {
buffer = data;
i = data.size() + 1;
} else {
buffer = data.substr(0, i);
}
// possibly we have "mmplus" string or similar
if (buffer.size() > 5 &&
(buffer.substr(2, 4) == string("plus") ||
buffer.substr(2, 5) == string("minus")))
{
lyx_advance(data, 2);
unit[unit_index] = unitFromString(buffer.substr(0, 2));
} else {
lyx_advance(data, i);
unit[unit_index] = unitFromString(buffer);
}
if (unit[unit_index] != Length::UNIT_NONE) {
++unit_index;
return 'u';
}
return 'E'; // Error
}
return 'E'; // Error
}
/// latex representation of a vspace
struct LaTeXLength {
char const * pattern;
int plus_val_index;
int minus_val_index;
int plus_uni_index;
int minus_uni_index;
};
/// the possible formats for a vspace string
LaTeXLength table[] = {
{ "nu", 0, 0, 0, 0 },
{ "nu+nu", 2, 0, 2, 0 },
{ "nu+nu-nu", 2, 3, 2, 3 },
{ "nu+-nu", 2, 2, 2, 2 },
{ "nu-nu", 0, 2, 0, 2 },
{ "nu-nu+nu", 3, 2, 3, 2 },
{ "nu-+nu", 2, 2, 2, 2 },
{ "n+nu", 2, 0, 1, 0 },
{ "n+n-nu", 2, 3, 1, 1 },
{ "n+-nu", 2, 2, 1, 1 },
{ "n-nu", 0, 2, 0, 1 },
{ "n-n+nu", 3, 2, 1, 1 },
{ "n-+nu", 2, 2, 1, 1 },
{ "", 0, 0, 0, 0 } // sentinel, must be empty
};
} // namespace anon
const char * stringFromUnit(int unit)
{
if (unit < 0 || unit > num_units)
return 0;
return unit_name[unit];
}
bool isValidGlueLength(string const & data, GlueLength * result)
{
// This parser is table-driven. First, it constructs a "pattern"
// that describes the sequence of tokens in "data". For example,
// "n-nu" means: number, minus sign, number, unit. As we go along,
// numbers and units are stored into static arrays. Then, "pattern"
// is searched in the "table". If it is found, the associated
// table entries tell us which number and unit should go where
// in the Length structure. Example: if "data" has the "pattern"
// "nu+nu-nu", the associated table entries are "2, 3, 2, 3".
// That means, "plus_val" is the second number that was seen
// in the input, "minus_val" is the third number, and "plus_uni"
// and "minus_uni" are the second and third units, respectively.
// ("val" and "uni" are always the first items seen in "data".)
// This is the most elegant solution I could find -- a straight-
// forward approach leads to very long, tedious code that would be
// much harder to understand and maintain. (AS)
if (data.empty())
return true;
string buffer = ltrim(data);
// To make isValidGlueLength recognize negative values as
// the first number this little hack is needed:
int val_sign = 1; // positive as default
switch (buffer[0]) {
case '-':
lyx_advance(buffer, 1);
val_sign = -1;
break;
case '+':
lyx_advance(buffer, 1);
break;
default:
break;
}
// end of hack
number_index = unit_index = 1; // entries at index 0 are sentinels
// construct "pattern" from "data"
size_t const pattern_max_size = 20;
string pattern;
while (!isEndOfData(buffer)) {
if (pattern.size() > pattern_max_size)
return false;
char const c = nextToken(buffer);
if (c == 'E')
return false;
pattern.push_back(c);
}
// search "pattern" in "table"
size_t table_index = 0;
while (pattern != table[table_index].pattern) {
++table_index;
if (!*table[table_index].pattern)
return false;
}
// Get the values from the appropriate places. If an index
// is zero, the corresponding array value is zero or UNIT_NONE,
// so we needn't check this.
if (result) {
result->len_.value (number[1] * val_sign);
result->len_.unit (unit[1]);
result->plus_.value (number[table[table_index].plus_val_index]);
result->plus_.unit (unit [table[table_index].plus_uni_index]);
result->minus_.value(number[table[table_index].minus_val_index]);
result->minus_.unit (unit [table[table_index].minus_uni_index]);
}
return true;
}
bool isValidLength(string const & data, Length * result)
{
// This is a trimmed down version of isValidGlueLength.
// The parser may seem overkill for lengths without
// glue, but since we already have it, using it is
// easier than writing something from scratch.
if (data.empty())
return true;
string buffer = data;
int pattern_index = 0;
char pattern[3];
// To make isValidLength recognize negative values
// this little hack is needed:
int val_sign = 1; // positive as default
switch (buffer[0]) {
case '-':
lyx_advance(buffer, 1);
val_sign = -1;
break;
case '+':
lyx_advance(buffer, 1);
// fall through
default:
// no action
break;
}
// end of hack
number_index = unit_index = 1; // entries at index 0 are sentinels
// construct "pattern" from "data"
while (!isEndOfData(buffer)) {
if (pattern_index > 2)
return false;
pattern[pattern_index] = nextToken(buffer);
if (pattern[pattern_index] == 'E')
return false;
++pattern_index;
}
pattern[pattern_index] = '\0';
// only the most basic pattern is accepted here
if (strcmp(pattern, "nu") != 0)
return false;
// It _was_ a correct length string.
// Store away the values we found.
if (result) {
result->val_ = number[1] * val_sign;
result->unit_ = unit[1];
}
return true;
}
//
// VSpace class
//

View File

@ -12,12 +12,19 @@
#include <config.h>
#include "support/gettext.h"
#include "Length.h"
#include "support/convert.h"
#include "support/gettext.h"
#include "support/lassert.h"
#include "support/lstrings.h"
#include <cstring>
#include <string>
using namespace std;
using namespace lyx::support;
namespace lyx {
@ -49,4 +56,308 @@ Length::UNIT unitFromString(string const & data)
}
namespace {
/// used to return numeric values in parsing vspace
double number[4] = { 0, 0, 0, 0 };
/// used to return unit types in parsing vspace
Length::UNIT unit[4] = {
Length::UNIT_NONE,
Length::UNIT_NONE,
Length::UNIT_NONE,
Length::UNIT_NONE
};
/// the current position in the number array
int number_index;
/// the current position in the unit array
int unit_index;
/// skip n characters of input
inline void lyx_advance(string & data, size_t n)
{
data.erase(0, n);
}
/// return true when the input is at the end
inline bool isEndOfData(string const & data)
{
return ltrim(data).empty();
}
/**
* nextToken - return the next token in the input
* @param data input string
* @return a char representing the type of token returned
*
* The possible return values are :
* + stretch indicator for glue length
* - shrink indicator for glue length
* n a numeric value (stored in number array)
* u a unit type (stored in unit array)
* E parse error
*/
char nextToken(string & data)
{
data = ltrim(data);
if (data.empty())
return '\0';
if (data[0] == '+') {
lyx_advance(data, 1);
return '+';
}
if (prefixIs(data, "plus")) {
lyx_advance(data, 4);
return '+';
}
if (data[0] == '-') {
lyx_advance(data, 1);
return '-';
}
if (prefixIs(data, "minus")) {
lyx_advance(data, 5);
return '-';
}
size_t i = data.find_first_not_of("0123456789.");
if (i != 0) {
if (number_index > 3)
return 'E';
string buffer;
// we have found some number
if (i == string::npos) {
buffer = data;
i = data.size() + 1;
} else {
buffer = data.substr(0, i);
}
lyx_advance(data, i);
if (isStrDbl(buffer)) {
number[number_index] = convert<double>(buffer);
++number_index;
return 'n';
}
return 'E';
}
i = data.find_first_not_of("abcdefghijklmnopqrstuvwxyz%");
if (i != 0) {
if (unit_index > 3)
return 'E';
string buffer;
// we have found some alphabetical string
if (i == string::npos) {
buffer = data;
i = data.size() + 1;
} else {
buffer = data.substr(0, i);
}
// possibly we have "mmplus" string or similar
if (buffer.size() > 5 &&
(buffer.substr(2, 4) == string("plus") ||
buffer.substr(2, 5) == string("minus")))
{
lyx_advance(data, 2);
unit[unit_index] = unitFromString(buffer.substr(0, 2));
} else {
lyx_advance(data, i);
unit[unit_index] = unitFromString(buffer);
}
if (unit[unit_index] != Length::UNIT_NONE) {
++unit_index;
return 'u';
}
return 'E'; // Error
}
return 'E'; // Error
}
/// latex representation of a vspace
struct LaTeXLength {
char const * pattern;
int plus_val_index;
int minus_val_index;
int plus_uni_index;
int minus_uni_index;
};
/// the possible formats for a vspace string
LaTeXLength table[] = {
{ "nu", 0, 0, 0, 0 },
{ "nu+nu", 2, 0, 2, 0 },
{ "nu+nu-nu", 2, 3, 2, 3 },
{ "nu+-nu", 2, 2, 2, 2 },
{ "nu-nu", 0, 2, 0, 2 },
{ "nu-nu+nu", 3, 2, 3, 2 },
{ "nu-+nu", 2, 2, 2, 2 },
{ "n+nu", 2, 0, 1, 0 },
{ "n+n-nu", 2, 3, 1, 1 },
{ "n+-nu", 2, 2, 1, 1 },
{ "n-nu", 0, 2, 0, 1 },
{ "n-n+nu", 3, 2, 1, 1 },
{ "n-+nu", 2, 2, 1, 1 },
{ "", 0, 0, 0, 0 } // sentinel, must be empty
};
} // namespace anon
const char * stringFromUnit(int unit)
{
if (unit < 0 || unit > num_units)
return 0;
return unit_name[unit];
}
bool isValidGlueLength(string const & data, GlueLength * result)
{
// This parser is table-driven. First, it constructs a "pattern"
// that describes the sequence of tokens in "data". For example,
// "n-nu" means: number, minus sign, number, unit. As we go along,
// numbers and units are stored into static arrays. Then, "pattern"
// is searched in the "table". If it is found, the associated
// table entries tell us which number and unit should go where
// in the Length structure. Example: if "data" has the "pattern"
// "nu+nu-nu", the associated table entries are "2, 3, 2, 3".
// That means, "plus_val" is the second number that was seen
// in the input, "minus_val" is the third number, and "plus_uni"
// and "minus_uni" are the second and third units, respectively.
// ("val" and "uni" are always the first items seen in "data".)
// This is the most elegant solution I could find -- a straight-
// forward approach leads to very long, tedious code that would be
// much harder to understand and maintain. (AS)
if (data.empty())
return true;
string buffer = ltrim(data);
// To make isValidGlueLength recognize negative values as
// the first number this little hack is needed:
int val_sign = 1; // positive as default
switch (buffer[0]) {
case '-':
lyx_advance(buffer, 1);
val_sign = -1;
break;
case '+':
lyx_advance(buffer, 1);
break;
default:
break;
}
// end of hack
number_index = unit_index = 1; // entries at index 0 are sentinels
// construct "pattern" from "data"
size_t const pattern_max_size = 20;
string pattern;
while (!isEndOfData(buffer)) {
if (pattern.size() > pattern_max_size)
return false;
char const c = nextToken(buffer);
if (c == 'E')
return false;
pattern.push_back(c);
}
// search "pattern" in "table"
size_t table_index = 0;
while (pattern != table[table_index].pattern) {
++table_index;
if (!*table[table_index].pattern)
return false;
}
// Get the values from the appropriate places. If an index
// is zero, the corresponding array value is zero or UNIT_NONE,
// so we needn't check this.
if (result) {
result->len_.value (number[1] * val_sign);
result->len_.unit (unit[1]);
result->plus_.value (number[table[table_index].plus_val_index]);
result->plus_.unit (unit [table[table_index].plus_uni_index]);
result->minus_.value(number[table[table_index].minus_val_index]);
result->minus_.unit (unit [table[table_index].minus_uni_index]);
}
return true;
}
bool isValidLength(string const & data, Length * result)
{
// This is a trimmed down version of isValidGlueLength.
// The parser may seem overkill for lengths without
// glue, but since we already have it, using it is
// easier than writing something from scratch.
if (data.empty())
return true;
string buffer = data;
int pattern_index = 0;
char pattern[3];
// To make isValidLength recognize negative values
// this little hack is needed:
int val_sign = 1; // positive as default
switch (buffer[0]) {
case '-':
lyx_advance(buffer, 1);
val_sign = -1;
break;
case '+':
lyx_advance(buffer, 1);
// fall through
default:
// no action
break;
}
// end of hack
number_index = unit_index = 1; // entries at index 0 are sentinels
// construct "pattern" from "data"
while (!isEndOfData(buffer)) {
if (pattern_index > 2)
return false;
pattern[pattern_index] = nextToken(buffer);
if (pattern[pattern_index] == 'E')
return false;
++pattern_index;
}
pattern[pattern_index] = '\0';
// only the most basic pattern is accepted here
if (strcmp(pattern, "nu") != 0)
return false;
// It _was_ a correct length string.
// Store away the values we found.
if (result) {
result->val_ = number[1] * val_sign;
result->unit_ = unit[1];
}
return true;
}
} // namespace lyx

View File

@ -12,9 +12,10 @@ project(${_tex2lyx})
set(LINKED_sources ${TOP_SRC_DIR}/src/lengthcommon.cpp)
set(LINKED_headers)
foreach(_src insets/InsetLayout Author Color Counters
Encoding FloatList Floating FontInfo LaTeXPackages
Layout LayoutFile LayoutModuleList Lexer ModuleList TextClass
foreach(_src graphics/GraphicsParams insets/ExternalTemplate
insets/ExternalTransforms insets/InsetLayout Author Color Counters
Encoding FloatList Floating FontInfo LaTeXPackages Layout
LayoutFile LayoutModuleList Length Lexer ModuleList TextClass
Spacing version)
list(APPEND LINKED_sources ${TOP_SRC_DIR}/src/${_src}.cpp)
list(APPEND LINKED_headers ${TOP_SRC_DIR}/src/${_src}.h)

View File

@ -36,17 +36,20 @@ LINKED_FILES = \
../FloatList.cpp \
../Floating.cpp \
../FontInfo.cpp \
../graphics/GraphicsParams.cpp \
../insets/ExternalTemplate.cpp \
../insets/ExternalTransforms.cpp \
../insets/InsetLayout.cpp \
../LaTeXPackages.cpp \
../Layout.cpp \
../LayoutFile.cpp \
../LayoutModuleList.cpp \
../Length.cpp \
../lengthcommon.cpp \
../Lexer.cpp \
../ModuleList.cpp \
../Spacing.cpp \
../TextClass.cpp \
../TextClass.h \
../version.cpp
BUILT_SOURCES = $(PCH_FILE)

View File

@ -171,6 +171,12 @@ const char * const known_xetex_packages[] = {"arabxetex", "fixlatvian",
"fontbook", "fontwrap", "mathspec", "philokalia", "polyglossia", "unisugar",
"xeCJK", "xecolor", "xecyr", "xeindex", "xepersian", "xunicode", 0};
/// packages that are automatically skipped if loaded by LyX
const char * const known_lyx_packages[] = {"array", "booktabs", "calc",
"color", "float", "graphicx", "hhline", "ifthen", "longtable", "makeidx",
"multirow", "nomencl", "pdfpages", "rotfloat", "splitidx", "setspace",
"subscript", "textcomp", "ulem", "url", "varioref", "verbatim", "wrapfig", 0};
// codes used to remove packages that are loaded automatically by LyX.
// Syntax: package_beg_sep<name>package_mid_sep<package loading code>package_end_sep
const char package_beg_sep = '\001';
@ -715,31 +721,19 @@ void Preamble::handle_package(Parser &p, string const & name,
else if (name == "prettyref")
; // ignore this FIXME: Use the package separator mechanism instead
else if (name == "pdfpages")
; // ignore this FIXME: Use the package separator mechanism instead
else if (name == "lyxskak") {
// ignore this and its options
if (!options.empty())
options.clear();
const char * const o[] = {"ps", "mover", 0};
delete_opt(options, o);
}
else if (name == "array" || name == "booktabs" || name == "calc" ||
name == "color" || name == "float" || name == "hhline" ||
name == "ifthen" || name == "longtable" || name == "makeidx" ||
name == "multirow" || name == "nomencl" || name == "rotfloat" ||
name == "splitidx" || name == "setspace" || name == "subscript" ||
name == "textcomp" || name == "ulem" || name == "url" ||
name == "varioref" || name == "verbatim" || name == "wrapfig") {
else if (is_known(name, known_lyx_packages) && options.empty()) {
if (!in_lyx_preamble)
h_preamble << package_beg_sep << name
<< package_mid_sep << "\\usepackage{"
<< name << "}\n" << package_end_sep;
}
else if (name == "graphicx")
; // ignore this FIXME: Use the package separator mechanism instead
else if (name == "geometry")
handle_geometry(options);

View File

@ -24,6 +24,8 @@
#include "Length.h"
#include "Preamble.h"
#include "insets/ExternalTemplate.h"
#include "support/lassert.h"
#include "support/convert.h"
#include "support/FileName.h"
@ -1899,6 +1901,28 @@ void parse_macro(Parser & p, ostream & os, Context & context)
handle_ert(os, command + ert, context);
}
void registerExternalTemplatePackages(string const & name)
{
external::TemplateManager const & etm = external::TemplateManager::get();
external::Template const * const et = etm.getTemplateByName(name);
if (!et)
return;
external::Template::Formats::const_iterator cit = et->formats.end();
if (pdflatex)
cit = et->formats.find("PDFLaTeX");
if (cit == et->formats.end())
// If the template has not specified a PDFLaTeX output,
// we try the LaTeX format.
cit = et->formats.find("LaTeX");
if (cit == et->formats.end())
return;
vector<string>::const_iterator qit = cit->second.requirements.begin();
vector<string>::const_iterator qend = cit->second.requirements.end();
for (; qit != qend; ++qit)
preamble.registerAutomaticallyLoadedPackage(*qit);
}
} // anonymous namespace
@ -2375,14 +2399,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
macro = false;
// register the packages that are automatically reloaded
// by the Gnumeric template
// Fixme: InsetExternal.cpp should give us that list
preamble.registerAutomaticallyLoadedPackage("array");
preamble.registerAutomaticallyLoadedPackage("calc");
preamble.registerAutomaticallyLoadedPackage("color");
preamble.registerAutomaticallyLoadedPackage("hhline");
preamble.registerAutomaticallyLoadedPackage("ifthen");
preamble.registerAutomaticallyLoadedPackage("longtable");
preamble.registerAutomaticallyLoadedPackage("multirow");
registerExternalTemplatePackages("GnumericSpreadsheet");
}
}
}
@ -2719,6 +2736,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
// Warn about invalid options.
// Check whether some option was given twice.
end_inset(os);
preamble.registerAutomaticallyLoadedPackage("graphicx");
}
else if (t.cs() == "footnote" ||
@ -3584,6 +3602,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
begin_inset(os, "External\n");
os << "\ttemplate XFig\n"
<< "\tfilename " << outname << '\n';
registerExternalTemplatePackages("XFig");
} else {
begin_command_inset(os, "include", name);
os << "preview false\n"
@ -4006,6 +4025,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
os << "\tkeepAspectRatio\n";
end_inset(os);
context.check_layout(os);
registerExternalTemplatePackages("PDFPages");
}
else if (t.cs() == "loadgame") {
@ -4037,6 +4057,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
// after a \loadgame follows a \showboard
if (p.get_token().asInput() == "showboard")
p.get_token();
registerExternalTemplatePackages("ChessDiagram");
}
else {