]> git.lyx.org Git - lyx.git/blob - src/tex2lyx/tex2lyx.C
back out again
[lyx.git] / src / tex2lyx / tex2lyx.C
1
2 /** The .tex to .lyx converter
3     \author André Pönitz (2003)
4  */
5
6 #include <config.h>
7
8 #include <algorithm>
9 #include <cctype>
10 #include <fstream>
11 #include <iostream>
12 #include <sstream>
13 #include <stack>
14 #include <string>
15 #include <vector>
16
17 using std::atoi;
18 using std::cout;
19 using std::cerr;
20 using std::endl;
21 using std::fill;
22 using std::getline;
23 using std::ios;
24 using std::ifstream;
25 using std::istream;
26 using std::istringstream;
27 using std::ostream;
28 using std::ostringstream;
29 using std::stack;
30 using std::string;
31 using std::vector;
32
33
34 namespace {
35
36 char const OPEN = '<';
37 char const CLOSE = '>';
38
39 const char * known_languages[] = { "austrian", "babel", "bahasa",
40 "basque", "breton", "bulgarian", "catalan", "croatian", "czech", "danish",
41 "dutch", "english", "esperanto", "estonian", "finnish", "francais",
42 "frenchb", "galician", "germanb", "greek", "hebcal", "hebfont", "hebrew",
43 "hebrew_newcode", "hebrew_oldcode", "hebrew_p", "hyphen", "icelandic",
44 "irish", "italian", "latin", "lgrcmr", "lgrcmro", "lgrcmss", "lgrcmtt",
45 "lgrenc", "lgrlcmss", "lgrlcmtt", "lheclas", "lhecmr", "lhecmss",
46 "lhecmtt", "lhecrml", "lheenc", "lhefr", "lheredis", "lheshold",
47 "lheshscr", "lheshstk", "lsorbian", "magyar", "naustrian", "ngermanb",
48 "ngerman", "norsk", "polish", "portuges", "rlbabel", "romanian",
49 "russianb", "samin", "scottish", "serbian", "slovak", "slovene", "spanish",
50 "swedish", "turkish", "ukraineb", "usorbian", "welsh", 0};
51
52 const char * known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
53
54
55 // some ugly stuff
56 string h_preamble;
57 string h_textclass               = "FIXME";
58 string h_options                 = "FIXME";
59 string h_language                = "FIXME";
60 string h_inputencoding           = "FIXME";
61 string h_fontscheme              = "FIXME";
62 string h_graphics                = "default";
63 string h_paperfontsize           = "FIXME";
64 string h_spacing                 = "single";
65 string h_papersize               = "FIXME";
66 string h_paperpackage            = "FIXME";
67 string h_use_geometry            = "0";
68 string h_use_amsmath             = "0";
69 string h_use_natbib              = "0";
70 string h_use_numerical_citations = "0";
71 string h_paperorientation        = "portrait";
72 string h_secnumdepth             = "3";
73 string h_tocdepth                = "3";
74 string h_paragraph_separation    = "indent";
75 string h_defskip                 = "medskip";
76 string h_quotes_language         = "2";
77 string h_quotes_times            = "1";
78 string h_papercolumns            = "1";
79 string h_papersides              = "1";
80 string h_paperpagestyle          = "default";
81 string h_tracking_changes        = "0";
82
83 // indicates whether we are in the preamble
84 bool in_preamble = true;
85
86 // current stack of nested environments
87 stack<string> active_environments;
88
89
90
91 void split(string const & s, vector<string> & result, char delim)
92 {
93         istringstream is(s);    
94         string t;
95         while (getline(is, t, delim))
96                 result.push_back(t);
97 }
98
99
100 string join(vector<string> const & input, char delim)
101 {
102         ostringstream os;
103         for (size_t i = 0; i != input.size(); ++i) {
104                 if (i)
105                         os << delim;    
106                 os << input[i]; 
107         }
108         return os.str();
109 }
110
111
112 void handle_opt(vector<string> & opts, char const ** what, string & target)
113 {
114         for ( ; what; ++what) {
115                 vector<string>::iterator it = find(opts.begin(), opts.end(), *what);
116                 if (it != opts.end()) {
117                         //cerr << "### found option '" << *what << "'\n";
118                         target = *what;
119                         opts.erase(it);
120                         return;
121                 }
122         }
123 }
124
125
126 void handle_ert(ostream & os, string const & s)
127 {
128         os << "\n\\begin_inset ERT\nstatus Collapsed\n\n\\layout Standard\n\n";
129         os << s;
130         os << "\n\\end_inset\n";
131 }
132
133
134 string wrap(string const & cmd, string const & str)
135 {
136         return OPEN + cmd + ' ' + str + CLOSE;
137 }
138
139
140 string wrap(string const & cmd, string const & str, string const & str2)
141 {
142         return OPEN + cmd + ' ' + str + ' ' + str2 + CLOSE;
143 }
144
145
146 enum mode_type {UNDECIDED_MODE, TEXT_MODE, MATH_MODE};
147
148 mode_type asMode(mode_type oldmode, string const & str)
149 {
150         if (str == "mathmode")
151                 return MATH_MODE;
152         if (str == "textmode" || str == "forcetext")
153                 return TEXT_MODE;
154         return oldmode;
155 }
156
157
158 // These are TeX's catcodes
159 enum CatCode {
160         catEscape,     // 0    backslash
161         catBegin,      // 1    {
162         catEnd,        // 2    }
163         cat,       // 3    $
164         catAlign,      // 4    &
165         catNewline,    // 5    ^^M
166         catParameter,  // 6    #
167         catSuper,      // 7    ^
168         catSub,        // 8    _
169         catIgnore,     // 9
170         catSpace,      // 10   space
171         catLetter,     // 11   a-zA-Z
172         catOther,      // 12   none of the above
173         catActive,     // 13   ~
174         catComment,    // 14   %
175         catInvalid     // 15   <delete>
176 };
177
178 CatCode theCatcode[256];
179
180
181 inline CatCode catcode(unsigned char c)
182 {
183         return theCatcode[c];
184 }
185
186
187 enum {
188         FLAG_BRACE_LAST = 1 << 1,  //  last closing brace ends the parsing
189         FLAG_RIGHT      = 1 << 2,  //  next \\right ends the parsing process
190         FLAG_END        = 1 << 3,  //  next \\end ends the parsing process
191         FLAG_BRACK_LAST = 1 << 4,  //  next closing bracket ends the parsing
192         FLAG_TEXTMODE   = 1 << 5,  //  we are in a box
193         FLAG_ITEM       = 1 << 6,  //  read a (possibly braced token)
194         FLAG_LEAVE      = 1 << 7,  //  leave the loop at the end
195         FLAG_SIMPLE     = 1 << 8,  //  next $ leaves the loop
196         FLAG_EQUATION   = 1 << 9,  //  next \] leaves the loop
197         FLAG_SIMPLE2    = 1 << 10, //  next \) leaves the loop
198         FLAG_OPTION     = 1 << 11, //  read [...] style option
199         FLAG_BRACED     = 1 << 12  //  read {...} style argument
200 };
201
202
203 void catInit()
204 {
205         fill(theCatcode, theCatcode + 256, catOther);
206         fill(theCatcode + 'a', theCatcode + 'z' + 1, catLetter);
207         fill(theCatcode + 'A', theCatcode + 'Z' + 1, catLetter);
208
209         theCatcode['\\'] = catEscape;
210         theCatcode['{']  = catBegin;
211         theCatcode['}']  = catEnd;
212         theCatcode['$']  = cat;
213         theCatcode['&']  = catAlign;
214         theCatcode['\n'] = catNewline;
215         theCatcode['#']  = catParameter;
216         theCatcode['^']  = catSuper;
217         theCatcode['_']  = catSub;
218         theCatcode['\7f'] = catIgnore;
219         theCatcode[' ']  = catSpace;
220         theCatcode['\t'] = catSpace;
221         theCatcode['\r'] = catNewline;
222         theCatcode['~']  = catActive;
223         theCatcode['%']  = catComment;
224 }
225
226
227
228 //
229 // Helper class for parsing
230 //
231
232 class Token {
233 public:
234         ///
235         Token() : cs_(), char_(0), cat_(catIgnore) {}
236         ///
237         Token(char c, CatCode cat) : cs_(), char_(c), cat_(cat) {}
238         ///
239         Token(string const & cs) : cs_(cs), char_(0), cat_(catIgnore) {}
240
241         ///
242         string const & cs() const { return cs_; }
243         ///
244         CatCode cat() const { return cat_; }
245         ///
246         char character() const { return char_; }
247         ///
248         string asString() const { return cs_.size() ? cs_ : string(1, char_); }
249
250 private:
251         ///
252         string cs_;
253         ///
254         char char_;
255         ///
256         CatCode cat_;
257 };
258
259 ostream & operator<<(ostream & os, Token const & t)
260 {
261         if (t.cs().size())
262                 os << '\\' << t.cs();
263         else
264                 os << '[' << t.character() << ',' << t.cat() << ']';
265         return os;
266 }
267
268
269 class Parser {
270
271 public:
272         ///
273         Parser(istream & is);
274
275         ///
276         string parse();
277         ///
278         string parse(unsigned flags, mode_type mode);
279         ///
280         int lineno() const { return lineno_; }
281         ///
282         void putback();
283         /// dump contents to screen
284         void dump() const;
285
286 private:
287         ///
288         string getArg(char left, char right);
289         ///
290         char getChar();
291         ///
292         void error(string const & msg);
293         ///
294         void tokenize(istream & is);
295         ///
296         void tokenize(string const & s);
297         ///
298         void skipSpaceTokens(istream & is, char c);
299         ///
300         void push_back(Token const & t);
301         ///
302         void pop_back();
303         ///
304         Token const & prevToken() const;
305         ///
306         Token const & nextToken() const;
307         ///
308         Token const & getToken();
309         /// skips spaces if any
310         void skipSpaces();
311         ///
312         void lex(string const & s);
313         ///
314         bool good() const;
315         ///
316         string parse_verbatim_item();
317         ///
318         string parse_verbatim_option();
319
320         ///
321         int lineno_;
322         ///
323         vector<Token> tokens_;
324         ///
325         unsigned pos_;
326 };
327
328
329 Parser::Parser(istream & is)
330         : lineno_(0), pos_(0)
331 {
332         tokenize(is);
333 }
334
335
336 void Parser::push_back(Token const & t)
337 {
338         tokens_.push_back(t);
339 }
340
341
342 void Parser::pop_back()
343 {
344         tokens_.pop_back();
345 }
346
347
348 Token const & Parser::prevToken() const
349 {
350         static const Token dummy;
351         return pos_ > 0 ? tokens_[pos_ - 1] : dummy;
352 }
353
354
355 Token const & Parser::nextToken() const
356 {
357         static const Token dummy;
358         return good() ? tokens_[pos_] : dummy;
359 }
360
361
362 Token const & Parser::getToken()
363 {
364         static const Token dummy;
365         //cerr << "looking at token " << tokens_[pos_] << " pos: " << pos_ << '\n';
366         return good() ? tokens_[pos_++] : dummy;
367 }
368
369
370 void Parser::skipSpaces()
371 {
372         while (nextToken().cat() == catSpace || nextToken().cat() == catNewline)
373                 getToken();
374 }
375
376
377 void Parser::putback()
378 {
379         --pos_;
380 }
381
382
383 bool Parser::good() const
384 {
385         return pos_ < tokens_.size();
386 }
387
388
389 char Parser::getChar()
390 {
391         if (!good())
392                 error("The input stream is not well...");
393         return tokens_[pos_++].character();
394 }
395
396
397 string Parser::getArg(char left, char right)
398 {
399         skipSpaces();
400
401         string result;
402         char c = getChar();
403
404         if (c != left)
405                 putback();
406         else
407                 while ((c = getChar()) != right && good())
408                         result += c;
409
410         return result;
411 }
412
413
414 void Parser::skipSpaceTokens(istream & is, char c)
415 {
416         // skip trailing spaces
417         while (catcode(c) == catSpace || catcode(c) == catNewline)
418                 if (!is.get(c))
419                         break;
420         //cerr << "putting back: " << c << "\n";
421         is.putback(c);
422 }
423
424
425 void Parser::tokenize(istream & is)
426 {
427         // eat everything up to the next \end_inset or end of stream
428         // and store it in s for further tokenization
429         string s;
430         char c;
431         while (is.get(c)) {
432                 s += c;
433                 if (s.size() >= 10 && s.substr(s.size() - 10) == "\\end_inset") {
434                         s = s.substr(0, s.size() - 10);
435                         break;
436                 }
437         }
438         // Remove the space after \end_inset
439         if (is.get(c) && c != ' ')
440                 is.unget();
441
442         // tokenize buffer
443         tokenize(s);
444 }
445
446
447 void Parser::tokenize(string const & buffer)
448 {
449         static bool init_done = false;
450
451         if (!init_done) {
452                 catInit();
453                 init_done = true;
454         }
455
456         istringstream is(buffer.c_str(), ios::in | ios::binary);
457
458         char c;
459         while (is.get(c)) {
460                 //cerr << "reading c: " << c << "\n";
461
462                 switch (catcode(c)) {
463                         case catNewline: {
464                                 ++lineno_;
465                                 is.get(c);
466                                 if (catcode(c) == catNewline)
467                                         push_back(Token("par"));
468                                 else {
469                                         push_back(Token('\n', catNewline));
470                                         is.putback(c);
471                                 }
472                                 break;
473                         }
474
475 /*
476                         case catComment: {
477                                 while (is.get(c) && catcode(c) != catNewline)
478                                         ;
479                                 ++lineno_;
480                                 break;
481                         }
482 */
483
484                         case catEscape: {
485                                 is.get(c);
486                                 if (!is) {
487                                         error("unexpected end of input");
488                                 } else {
489                                         string s(1, c);
490                                         if (catcode(c) == catLetter) {
491                                                 // collect letters
492                                                 while (is.get(c) && catcode(c) == catLetter)
493                                                         s += c;
494                                                 skipSpaceTokens(is, c);
495                                         }
496                                         push_back(Token(s));
497                                 }
498                                 break;
499                         }
500
501                         case catSuper:
502                         case catSub: {
503                                 push_back(Token(c, catcode(c)));
504                                 is.get(c);
505                                 skipSpaceTokens(is, c);
506                                 break;
507                         }
508
509                         case catIgnore: {
510                                 cerr << "ignoring a char: " << int(c) << "\n";
511                                 break;
512                         }
513
514                         default:
515                                 push_back(Token(c, catcode(c)));
516                 }
517         }
518
519 #ifdef FILEDEBUG
520         dump();
521 #endif
522 }
523
524
525 void Parser::dump() const
526 {
527         cerr << "\nTokens: ";
528         for (unsigned i = 0; i < tokens_.size(); ++i) {
529                 if (i == pos_)
530                         cerr << " <#> ";
531                 cerr << tokens_[i];
532         }
533         cerr << " pos: " << pos_ << "\n";
534 }
535
536
537 void Parser::error(string const & msg)
538 {
539         cerr << "Line ~" << lineno_ << ":  parse error: " << msg << endl;
540         dump();
541         //exit(1);
542 }
543
544
545 string Parser::parse()
546 {
547         skipSpaces();
548         return parse(0, UNDECIDED_MODE);
549 }
550
551
552 string Parser::parse_verbatim_option()
553 {
554         string res;
555         if (nextToken().character() == '[') {
556                 Token t = getToken();
557                 for (Token t = getToken(); t.character() != ']' && good(); t = getToken()) {
558                         if (t.cat() == catBegin) {
559                                 putback();
560                                 res += '{' + parse_verbatim_item() + '}';
561                         } else
562                                 res += t.asString();
563                 }
564         }
565         return res;
566 }
567
568
569 string Parser::parse_verbatim_item()
570 {
571         string res;
572         if (nextToken().cat() == catBegin) {
573                 Token t = getToken();
574                 for (Token t = getToken(); t.cat() != catEnd && good(); t = getToken()) {
575                         if (t.cat() == catBegin) {
576                                 putback();
577                                 res += '{' + parse_verbatim_item() + '}';
578                         }
579                         else
580                                 res += t.asString();
581                 }
582         }
583         return res;
584 }
585
586
587 string Parser::parse(unsigned flags, mode_type mode)
588 {
589         //int limits = 0;
590
591         ostringstream result;
592         while (good()) {
593                 Token const & t = getToken();
594
595 #ifdef FILEDEBUG
596                 cerr << "t: " << t << " flags: " << flags << "\n";
597                 cell->dump();
598                 cerr << "\n";
599 #endif
600
601                 if (flags & FLAG_ITEM) {
602                         if (t.cat() == catSpace)
603                                 continue;
604
605                         flags &= ~FLAG_ITEM;
606                         if (t.cat() == catBegin) {
607                                 // skip the brace and collect everything to the next matching
608                                 // closing brace
609                                 flags |= FLAG_BRACE_LAST;
610                                 continue;
611                         }
612
613                         // handle only this single token, leave the loop if done
614                         flags |= FLAG_LEAVE;
615                 }
616
617
618                 if (flags & FLAG_BRACED) {
619                         if (t.cat() == catSpace)
620                                 continue;
621
622                         if (t.cat() != catBegin) {
623                                 error("opening brace expected");
624                                 return result.str();
625                         }
626
627                         // skip the brace and collect everything to the next matching
628                         // closing brace
629                         flags = FLAG_BRACE_LAST;
630                 }
631
632
633                 if (flags & FLAG_OPTION) {
634                         if (t.cat() == catOther && t.character() == '[') {
635                                 result << parse(FLAG_BRACK_LAST, mode);
636                         } else {
637                                 // no option found, put back token and we are done
638                                 putback();
639                         }
640                         return result.str();
641                 }
642
643                 //
644                 // cat codes
645                 //
646                 if (t.cat() == cat) {
647                         if (mode != MATH_MODE) {
648                                 // we are inside some text mode thingy, so opening new math is allowed
649                                 Token const & n = getToken();
650                                 if (n.cat() == cat) {
651                                         // TeX's $$...$$ syntax for displayed math
652                                         result << wrap("equation", parse(FLAG_SIMPLE, MATH_MODE));
653                                         getToken(); // skip the second '$' token
654                                 } else {
655                                         // simple $...$  stuff
656                                         putback();
657                                         result << wrap("simple", parse(FLAG_SIMPLE, MATH_MODE));
658                                 }
659                         }
660
661                         else if (flags & FLAG_SIMPLE) {
662                                 // this is the end of the formula
663                                 return result.str();
664                         }
665
666                         else {
667                                 error("something strange in the parser\n");
668                                 break;
669                         }
670                 }
671
672                 else if (t.cat() == catLetter)
673                         result << t.character();
674
675                 else if (t.cat() == catSpace && mode != MATH_MODE) {
676                         //if (result.empty() || result[result.size() - 1] != ' ')
677                                 result << t.character();
678                 }
679
680                 else if (t.cat() == catNewline && mode != MATH_MODE)
681                         result << t.character();
682
683                 else if (t.cat() == catParameter) {
684                         Token const & n = getToken();
685                         result << wrap("macroarg", string(1, n.character()));
686                 }
687
688                 else if (t.cat() == catActive)
689                         result << wrap("active", string(1, t.character()));
690
691                 else if (t.cat() == catBegin)
692                         result << wrap("braced", parse(FLAG_BRACE_LAST, mode));
693
694                 else if (t.cat() == catEnd) {
695                         if (flags & FLAG_BRACE_LAST)
696                                 return result.str();
697                         error("found '}' unexpectedly");
698                         //lyx::Assert(0);
699                         //add(cell, '}', LM_TC_TEX);
700                 }
701
702 /*
703                 else if (t.cat() == catAlign) {
704                         ++cellcol;
705                         //cerr << " column now " << cellcol << " max: " << grid.ncols() << "\n";
706                         if (cellcol == grid.ncols()) {
707                                 //cerr << "adding column " << cellcol << "\n";
708                                 grid.addCol(cellcol - 1);
709                         }
710                         cell = &grid.cell(grid.index(cellrow, cellcol));
711                 }
712 */
713
714                 else if (t.character() == ']' && (flags & FLAG_BRACK_LAST)) {
715                         //cerr << "finished reading option\n";
716                         return result.str();
717                 }
718
719                 else if (t.cat() == catOther)
720                         result << string(1, t.character());
721
722                 else if (t.cat() == catComment) {
723                         string s;
724                         while (good()) {
725                                 Token const & t = getToken();
726                                 if (t.cat() == catNewline)
727                                         break;
728                                 s += t.asString();
729                         }
730                         //result << wrap("comment", s);
731                         skipSpaces();
732                 }
733
734                 //
735                 // control sequences
736                 //
737
738                 else if (t.cs() == "lyxlock") {
739                         // ignored;
740                 }
741
742                 else if (t.cs() == "newcommand" || t.cs() == "providecommand") {
743                         string const name = parse_verbatim_item();
744                         string const opts = getArg('[', ']');
745                         string const body = parse_verbatim_item();
746                         // only non-lyxspecific stuff
747                         if (name != "noun" && name != "tabularnewline") {
748                                 h_preamble += "\\" + t.cs() + "{" + name + "}";
749                                 if (opts.size()) 
750                                         h_preamble += "[" + opts + "]";
751                                 h_preamble += "{" + body + "}\n";
752                         }
753                 }
754
755                 else if (t.cs() == "(") 
756                         result << wrap("simple", parse(FLAG_SIMPLE2, MATH_MODE));
757
758                 else if (t.cs() == "[")
759                         result << wrap("equation", parse(FLAG_EQUATION, MATH_MODE));
760
761                 else if (t.cs() == "protect")
762                         // ignore \\protect, will hopefully be re-added during output
763                         ;
764
765                 else if (t.cs() == "end") {
766                         if (flags & FLAG_END) {
767                                 // eat environment name
768                                 string const name = getArg('{', '}');
769                                 if (name != active_environments.top())
770                                         error("\\end{" + name + "} does not match \\begin{"
771                                                 + active_environments.top() + "}");
772                                 active_environments.pop();
773                                 return result.str();
774                         }
775                         error("found 'end' unexpectedly");
776                 }
777
778                 else if (t.cs() == ")") {
779                         if (flags & FLAG_SIMPLE2)
780                                 return result.str();
781                         error("found '\\)' unexpectedly");
782                 }
783
784                 else if (t.cs() == "]") {
785                         if (flags & FLAG_EQUATION)
786                                 return result.str();
787                         error("found '\\]' unexpectedly");
788                 }
789
790 /*
791                 else if (t.cs() == "\\") {
792                         grid.vcrskip(LyXLength(getArg('[', ']')), cellrow);
793                         ++cellrow;
794                         cellcol = 0;
795                         if (cellrow == grid.nrows())
796                                 grid.addRow(cellrow - 1);
797                         if (grid.asHullstring())
798                                 grid.asHullstring()->numbered(cellrow, numbered);
799                         cell = &grid.cell(grid.index(cellrow, cellcol));
800                 }
801 */
802                 else if (t.cs() == "documentclass") {
803                         vector<string> opts;
804                         split(getArg('[', ']'), opts, ',');
805                         handle_opt(opts, known_languages, h_language); 
806                         handle_opt(opts, known_fontsizes, h_paperfontsize); 
807                         h_options = join(opts, ',');
808                         h_textclass = getArg('{', '}');
809                 }
810
811                 else if (t.cs() == "usepackage") {
812                         string const options = getArg('[', ']');
813                         string const name = getArg('{', '}');
814                         if (name == "a4wide") {
815                                 h_papersize = "a4";
816                                 h_paperpackage = "widemarginsa4";
817                         } else if (name == "ae") 
818                                 h_fontscheme = "ae";
819                         else if (name == "aecompl") 
820                                 h_fontscheme = "ae";
821                         else if (name == "amsmath") 
822                                 h_use_amsmath = "1";
823                         else if (name == "amssymb") 
824                                 h_use_amsmath = "1";
825                         else if (name == "babel") 
826                                 ; // ignore this
827                         else if (name == "fontenc") 
828                                 ; // ignore this
829                         else if (name == "inputenc") 
830                                 h_inputencoding = options;
831                         else if (name == "makeidx") 
832                                 ; // ignore this
833                         else if (name == "verbatim") 
834                                 ; // ignore this
835                         else {
836                                 if (options.size())
837                                         h_preamble += "\\usepackage[" + options + "]{" + name + "}\n";
838                                 else
839                                         h_preamble += "\\usepackage{" + name + "}\n";
840                         }
841                 }
842
843                 else if (t.cs() == "newenvironment") {
844                         string const name = getArg('{', '}');
845                         skipSpaces();
846                         string const begin = parse_verbatim_item();
847                         skipSpaces();
848                         string const end = parse_verbatim_item();
849                         // ignore out mess
850                         if (name != "lyxcode") 
851                                 result << wrap("newenvironment", begin + end); 
852                 }
853
854                 else if (t.cs() == "def") {
855                         string const name = getToken().cs();
856                         string res;
857                         while (nextToken().cat() != catBegin)
858                                 res += getToken().asString();
859                         handle_ert(result, "\\def" + res + '{' + parse_verbatim_item() + '}');
860                 }
861
862                 else if (t.cs() == "setcounter") {
863                         string const name = getArg('{', '}');
864                         string const content = getArg('{', '}');
865                         if (name == "secnumdepth") 
866                                 h_secnumdepth = content;
867                         else if (name == "tocdepth") 
868                                 h_tocdepth = content;
869                         else
870                                 h_preamble += "\\setcounter{" + name + "}{" + content + "}\n";
871                 }
872
873                 else if (t.cs() == "setlength") {
874                         string const name = getToken().cs();
875                         string const content = getArg('{', '}');
876                         if (name == "parskip")
877                                 h_paragraph_separation = "skip";
878                         else if (name == "parindent")
879                                 h_paragraph_separation = "skip";
880                         else
881                                 h_preamble += "\\setcounter{" + name + "}{" + content + "}\n";
882                 }
883         
884                 else if (t.cs() == "par") {
885                         if (!active_environments.empty())       
886                                 result << "\n\\layout " << active_environments.top() << "\n\n";
887                 }
888
889                 else if (t.cs() == "title")
890                         result << "\\layout Title\n\n" + parse_verbatim_item();
891
892                 else if (t.cs() == "author")
893                         result << "\\layout Author\n\n" + parse_verbatim_item();
894
895                 else if (t.cs() == "abstract")
896                         result << "\\layout Abstract\n\n" + parse_verbatim_item();
897
898                 else if (t.cs() == "begin") {
899                         string const name = getArg('{', '}');
900                         active_environments.push(name);
901                         result << parse(FLAG_END, mode);
902                 }
903
904                 if (flags & FLAG_LEAVE) {
905                         flags &= ~FLAG_LEAVE;
906                         break;
907                 }
908         }
909
910         return result.str();
911 }
912
913
914 } // anonymous namespace
915
916
917 int main(int argc, char * argv[])
918 {
919         if (argc <= 1) {
920                 cerr << "Usage: " << argv[0] << " <infile.tex>" << endl;
921                 return 2;
922         }
923
924         string t;
925         ifstream is(argv[1]);
926         Parser p(is);
927         //p.dump();
928         string s = p.parse();
929         cout << "# tex2lyx 0.0.2 created this file\n"
930              << "\\lyxformat 222\n"
931              << "\\textclass " << h_textclass << "\n"
932              << "\\begin_preamble\n" << h_preamble << "\\end_preamble\n"
933              << "\\options " << h_options << "\n"
934              << "\\language " << h_language << "\n"
935              << "\\inputencoding " << h_inputencoding << "\n"
936              << "\\fontscheme " << h_fontscheme << "\n"
937              << "\\graphics " << h_graphics << "\n"
938              << "\\paperfontsize " << h_paperfontsize << "\n"
939              << "\\spacing " << h_spacing << "\n"
940              << "\\papersize " << h_papersize << "\n"
941              << "\\paperpackage " << h_paperpackage << "\n"
942              << "\\use_geometry " << h_use_geometry << "\n"
943              << "\\use_amsmath " << h_use_amsmath << "\n"
944              << "\\use_natbib " << h_use_natbib << "\n"
945              << "\\use_numerical_citations " << h_use_numerical_citations << "\n"
946              << "\\paperorientation " << h_paperorientation << "\n"
947              << "\\secnumdepth " << h_secnumdepth << "\n"
948              << "\\tocdepth " << h_tocdepth << "\n"
949              << "\\paragraph_separation " << h_paragraph_separation << "\n"
950              << "\\defskip " << h_defskip << "\n"
951              << "\\quotes_language " << h_quotes_language << "\n"
952              << "\\quotes_times " << h_quotes_times << "\n"
953              << "\\papercolumns " << h_papercolumns << "\n"
954              << "\\papersides " << h_papersides << "\n"
955              << "\\paperpagestyle " << h_paperpagestyle << "\n"
956              << "\\tracking_changes " << h_tracking_changes << "\n"
957              << s << "\n"
958              << "\\the_end";
959
960         return 0;       
961 }