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