]> git.lyx.org Git - lyx.git/blob - src/tex2lyx/preamble.C
Georg's minipage patch
[lyx.git] / src / tex2lyx / preamble.C
1 /**
2  * \file preamble.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 // {[(
12
13 #include <config.h>
14
15 #include "tex2lyx.h"
16
17 #include "layout.h"
18 #include "lyxtextclass.h"
19 #include "lyxlex.h"
20 #include "support/filetools.h"
21
22 #include <algorithm>
23 #include <iostream>
24 #include <sstream>
25 #include <string>
26 #include <vector>
27 #include <map>
28
29 using std::istringstream;
30 using std::ostream;
31 using std::ostringstream;
32 using std::string;
33 using std::vector;
34 using std::cerr;
35 using std::endl;
36
37 using lyx::support::LibFileSearch;
38
39 // special columntypes
40 extern std::map<char, int> special_columns;
41
42 namespace {
43
44 const char * known_languages[] = { "austrian", "babel", "bahasa", "basque",
45 "breton", "british", "bulgarian", "catalan", "croatian", "czech", "danish",
46 "dutch", "english", "esperanto", "estonian", "finnish", "francais",
47 "frenchb", "galician", "german", "germanb", "greek", "hebcal", "hebfont",
48 "hebrew", "hebrew_newcode", "hebrew_oldcode", "hebrew_p", "hyphen",
49 "icelandic", "irish", "italian", "latin", "lgrcmr", "lgrcmro", "lgrcmss",
50 "lgrcmtt", "lgrenc", "lgrlcmss", "lgrlcmtt", "lheclas", "lhecmr",
51 "lhecmss", "lhecmtt", "lhecrml", "lheenc", "lhefr", "lheredis", "lheshold",
52 "lheshscr", "lheshstk", "lsorbian", "magyar", "naustrian", "ngermanb",
53 "ngerman", "norsk", "polish", "portuges", "rlbabel", "romanian",
54 "russianb", "samin", "scottish", "serbian", "slovak", "slovene", "spanish",
55 "swedish", "turkish", "ukraineb", "usorbian", "welsh", 0};
56
57 char const * known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
58
59 // some ugly stuff
60 ostringstream h_preamble;
61 string h_textclass               = "article";
62 string h_options                 = string();
63 string h_language                = "english";
64 string h_inputencoding           = "latin1";
65 string h_fontscheme              = "default";
66 string h_graphics                = "default";
67 string h_paperfontsize           = "default";
68 string h_spacing                 = "single";
69 // Match the entry in ../src/tex-strings.C. Why not "default"?
70 string h_papersize               = "Default";
71 string h_paperpackage            = "default";
72 string h_use_geometry            = "0";
73 string h_use_amsmath             = "0";
74 string h_use_natbib              = "0";
75 string h_use_numerical_citations = "0";
76 string h_paperorientation        = "portrait";
77 string h_secnumdepth             = "3";
78 string h_tocdepth                = "3";
79 string h_paragraph_separation    = "indent";
80 string h_defskip                 = "medskip";
81 string h_quotes_language         = "english";
82 string h_quotes_times            = "2";
83 string h_papercolumns            = "1";
84 string h_papersides              = string();
85 string h_paperpagestyle          = "default";
86 string h_tracking_changes        = "0";
87
88
89 void handle_opt(vector<string> & opts, char const ** what, string & target)
90 {
91         if (opts.empty())
92                 return;
93
94         for ( ; *what; ++what) {
95                 vector<string>::iterator it = find(opts.begin(), opts.end(), *what);
96                 if (it != opts.end()) {
97                         //cerr << "### found option '" << *what << "'\n";
98                         target = *what;
99                         opts.erase(it);
100                         return;
101                 }
102         }
103 }
104
105
106 void handle_package(string const & name, string const & options)
107 {
108         //cerr << "handle_package: '" << name << "'\n";
109         if (name == "a4wide") {
110                 h_papersize = "a4paper";
111                 h_paperpackage = "widemarginsa4";
112         } else if (name == "ae")
113                 h_fontscheme = "ae";
114         else if (name == "aecompl")
115                 h_fontscheme = "ae";
116         else if (name == "amsmath")
117                 h_use_amsmath = "1";
118         else if (name == "amssymb")
119                 h_use_amsmath = "1";
120         else if (name == "babel")
121                 ; // ignore this
122         else if (name == "fontenc")
123                 ; // ignore this
124         else if (name == "inputenc")
125                 h_inputencoding = options;
126         else if (name == "makeidx")
127                 ; // ignore this
128         else if (name == "verbatim")
129                 ; // ignore this
130         else if (is_known(name, known_languages)) {
131                 h_language = name;
132                 h_quotes_language = name;
133         } else {
134                 if (!options.empty())
135                         h_preamble << "\\usepackage[" << options << "]{" << name << "}\n";
136                 else
137                         h_preamble << "\\usepackage{" << name << "}\n";
138         }
139 }
140
141
142
143 void end_preamble(ostream & os, LyXTextClass const & /*textclass*/)
144 {
145         os << "#LyX file created by  tex2lyx 0.1.2 \n"
146            << "\\lyxformat 228\n"
147            << "\\textclass " << h_textclass << "\n"
148            << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n";
149         if (!h_options.empty())
150            os << "\\options " << h_options << "\n";
151         os << "\\language " << h_language << "\n"
152            << "\\inputencoding " << h_inputencoding << "\n"
153            << "\\fontscheme " << h_fontscheme << "\n"
154            << "\\graphics " << h_graphics << "\n"
155            << "\\paperfontsize " << h_paperfontsize << "\n"
156            << "\\spacing " << h_spacing << "\n"
157            << "\\papersize " << h_papersize << "\n"
158            << "\\paperpackage " << h_paperpackage << "\n"
159            << "\\use_geometry " << h_use_geometry << "\n"
160            << "\\use_amsmath " << h_use_amsmath << "\n"
161            << "\\use_natbib " << h_use_natbib << "\n"
162            << "\\use_numerical_citations " << h_use_numerical_citations << "\n"
163            << "\\paperorientation " << h_paperorientation << "\n"
164            << "\\secnumdepth " << h_secnumdepth << "\n"
165            << "\\tocdepth " << h_tocdepth << "\n"
166            << "\\paragraph_separation " << h_paragraph_separation << "\n"
167            << "\\defskip " << h_defskip << "\n"
168            << "\\quotes_language " << h_quotes_language << "\n"
169            << "\\quotes_times " << h_quotes_times << "\n"
170            << "\\papercolumns " << h_papercolumns << "\n"
171            << "\\papersides " << h_papersides << "\n"
172            << "\\paperpagestyle " << h_paperpagestyle << "\n"
173            << "\\tracking_changes " << h_tracking_changes << "\n"
174            << "\\end_header\n";
175         // clear preamble for subdocuments
176         h_preamble.str("");
177 }
178
179 } // anonymous namespace
180
181 LyXTextClass const parse_preamble(Parser & p, ostream & os, string const & forceclass)
182 {
183         // initialize fixed types
184         special_columns['D'] = 3;
185         bool is_full_document = false;
186
187         // determine wether this is a full document or a fragment for inclusion
188         while (p.good()) {
189                 Token const & t = p.get_token();
190
191                 if (t.cat() == catEscape && t.cs() == "documentclass") {
192                         is_full_document = true;
193                         break;
194                 }
195         }
196         p.reset();
197
198         while (is_full_document && p.good()) {
199                 Token const & t = p.get_token();
200
201 #ifdef FILEDEBUG
202                 cerr << "t: " << t << "\n";
203 #endif
204
205                 //
206                 // cat codes
207                 //
208                 if (t.cat() == catLetter ||
209                           t.cat() == catSuper ||
210                           t.cat() == catSub ||
211                           t.cat() == catOther ||
212                           t.cat() == catMath ||
213                           t.cat() == catActive ||
214                           t.cat() == catBegin ||
215                           t.cat() == catEnd ||
216                           t.cat() == catAlign ||
217                           t.cat() == catParameter)
218                 h_preamble << t.character();
219
220                 else if (t.cat() == catSpace || t.cat() == catNewline)
221                         h_preamble << t.asInput();
222
223                 else if (t.cat() == catComment)
224                         h_preamble << t.asInput();
225
226                 else if (t.cs() == "pagestyle")
227                         h_paperpagestyle = p.verbatim_item();
228
229                 else if (t.cs() == "makeatletter") {
230                         p.setCatCode('@', catLetter);
231                         h_preamble << "\\makeatletter";
232                 }
233
234                 else if (t.cs() == "makeatother") {
235                         p.setCatCode('@', catOther);
236                         h_preamble << "\\makeatother";
237                 }
238
239                 else if (t.cs() == "newcommand" || t.cs() == "renewcommand"
240                             || t.cs() == "providecommand") {
241                         bool star = false;
242                         if (p.next_token().character() == '*') {
243                                 p.get_token();
244                                 star = true;
245                         }
246                         string const name = p.verbatim_item();
247                         string const opts = p.getOpt();
248                         string const body = p.verbatim_item();
249                         // only non-lyxspecific stuff
250                         if (   name != "\\noun"
251                             && name != "\\tabularnewline"
252                             && name != "\\LyX"
253                             && name != "\\lyxline"
254                             && name != "\\lyxaddress"
255                             && name != "\\lyxrightaddress"
256                             && name != "\\boldsymbol"
257                             && name != "\\lyxarrow") {
258                                 ostringstream ss;
259                                 ss << '\\' << t.cs();
260                                 if (star)
261                                         ss << '*';
262                                 ss << '{' << name << '}' << opts << '{' << body << "}";
263                                 h_preamble << ss.str();
264 /*
265                                 ostream & out = in_preamble ? h_preamble : os;
266                                 out << "\\" << t.cs() << "{" << name << "}"
267                                     << opts << "{" << body << "}";
268 */
269                         }
270                 }
271
272                 else if (t.cs() == "documentclass") {
273                         vector<string> opts;
274                         split(p.getArg('[', ']'), opts, ',');
275                         handle_opt(opts, known_languages, h_language);
276                         handle_opt(opts, known_fontsizes, h_paperfontsize);
277                         h_quotes_language = h_language;
278                         h_options = join(opts, ",");
279                         h_textclass = p.getArg('{', '}');
280                 }
281
282                 else if (t.cs() == "usepackage") {
283                         string const options = p.getArg('[', ']');
284                         string const name = p.getArg('{', '}');
285                         if (options.empty() && name.find(',')) {
286                                 vector<string> vecnames;
287                                 split(name, vecnames, ',');
288                                 vector<string>::const_iterator it  = vecnames.begin();
289                                 vector<string>::const_iterator end = vecnames.end();
290                                 for (; it != end; ++it)
291                                         handle_package(trim(*it), string());
292                         } else {
293                                 handle_package(name, options);
294                         }
295                 }
296
297                 else if (t.cs() == "newenvironment") {
298                         string const name = p.getArg('{', '}');
299                         ostringstream ss;
300                         ss << "\\newenvironment{" << name << "}";
301                         ss << p.getOpt();
302                         ss << p.getOpt();
303                         ss << '{' << p.verbatim_item() << '}';
304                         ss << '{' << p.verbatim_item() << '}';
305                         if (name != "lyxcode" && name != "lyxlist"
306                                         && name != "lyxrightadress" && name != "lyxaddress")
307                                 h_preamble << ss.str();
308                 }
309
310                 else if (t.cs() == "def") {
311                         string name = p.get_token().cs();
312                         while (p.next_token().cat() != catBegin)
313                                 name += p.get_token().asString();
314                         h_preamble << "\\def\\" << name << '{' << p.verbatim_item() << "}";
315                 }
316
317                 else if (t.cs() == "newcolumntype") {
318                         string const name = p.getArg('{', '}');
319                         trim(name);
320                         int nargs = 0;
321                         string opts = p.getOpt();
322                         if (!opts.empty()) {
323                                 istringstream is(string(opts, 1));
324                                 //cerr << "opt: " << is.str() << "\n";
325                                 is >> nargs;
326                         }
327                         special_columns[name[0]] = nargs;
328                         h_preamble << "\\newcolumntype{" << name << "}";
329                         if (nargs)
330                                 h_preamble << "[" << nargs << "]";
331                         h_preamble << "{" << p.verbatim_item() << "}";
332                 }
333
334                 else if (t.cs() == "setcounter") {
335                         string const name = p.getArg('{', '}');
336                         string const content = p.getArg('{', '}');
337                         if (name == "secnumdepth")
338                                 h_secnumdepth = content;
339                         else if (name == "tocdepth")
340                                 h_tocdepth = content;
341                         else
342                                 h_preamble << "\\setcounter{" << name << "}{" << content << "}";
343                 }
344
345                 else if (t.cs() == "setlength") {
346                         string const name = p.verbatim_item();
347                         string const content = p.verbatim_item();
348                         // Is this correct?
349                         if (name == "parskip")
350                                 h_paragraph_separation = "skip";
351                         else if (name == "parindent")
352                                 h_paragraph_separation = "skip";
353                         else
354                                 h_preamble << "\\setlength{" << name << "}{" << content << "}";
355                 }
356
357                 else if (t.cs() == "begin") {
358                         string const name = p.getArg('{', '}');
359                         if (name == "document")
360                                 break;
361                         h_preamble << "\\begin{" << name << "}";
362                 }
363
364                 else if (!t.cs().empty())
365                         h_preamble << '\\' << t.cs();
366         }
367         p.skip_spaces();
368
369         // Force textclass if the user wanted it
370         if (!forceclass.empty()) {
371                 h_textclass = forceclass;
372         }
373         string layoutfilename = LibFileSearch("layouts", h_textclass, "layout");
374         if (layoutfilename.empty()) {
375                 cerr << "Error: Could not find layout file for textclass \"" << h_textclass << "\"." << endl;
376                 exit(1);
377         }
378         LyXTextClass textclass;
379         textclass.Read(layoutfilename);
380         if (h_papersides.empty()) {
381                 ostringstream ss;
382                 ss << textclass.sides();
383                 h_papersides = ss.str();
384         }
385         end_preamble(os, textclass);
386         return textclass;
387 }
388
389 // }])