]> git.lyx.org Git - lyx.git/blob - src/buffer.C
add boost
[lyx.git] / src / buffer.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2000 The LyX Team.
8  *
9  *           This file is Copyright 1996-1999
10  *           Lars Gullik Bjønnes
11  *
12  * ====================================================== 
13  */
14
15 #include <config.h>
16
17 #include <fstream>
18 #include <iomanip>
19 #include <map>
20
21 #include <cstdlib>
22 #include <cmath>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <utime.h>
26
27 #include <algorithm>
28
29 #ifdef HAVE_LOCALE
30 #include <locale>
31 #endif
32
33 #ifdef __GNUG__
34 #pragma implementation "buffer.h"
35 #endif
36
37 #include "buffer.h"
38 #include "bufferlist.h"
39 #include "lyx_main.h"
40 #include "lyx_gui_misc.h"
41 #include "LyXAction.h"
42 #include "lyxrc.h"
43 #include "lyxlex.h"
44 #include "tex-strings.h"
45 #include "layout.h"
46 #include "bufferview_funcs.h"
47 #include "minibuffer.h"
48 #include "lyxfont.h"
49 #include "version.h"
50 #include "mathed/formulamacro.h"
51 #include "insets/lyxinset.h"
52 #include "insets/inseterror.h"
53 #include "insets/insetlabel.h"
54 #include "insets/insetref.h"
55 #include "insets/inseturl.h"
56 #include "insets/insetinfo.h"
57 #include "insets/insetquotes.h"
58 #include "insets/insetlatexaccent.h"
59 #include "insets/insetbib.h" 
60 #include "insets/insetcite.h" 
61 #include "insets/insetexternal.h"
62 #include "insets/insetindex.h" 
63 #include "insets/insetinclude.h"
64 #include "insets/insettoc.h"
65 #include "insets/insetparent.h"
66 #include "insets/insetspecialchar.h"
67 #include "insets/figinset.h"
68 #include "insets/insettext.h"
69 #include "insets/insetert.h"
70 #include "insets/insetgraphics.h"
71 #include "insets/insetfoot.h"
72 #include "insets/insetmarginal.h"
73 #include "insets/insetminipage.h"
74 #include "insets/insetfloat.h"
75 #include "insets/insetlist.h"
76 #include "insets/insettabular.h"
77 #include "insets/insettheorem.h"
78 #include "insets/insetcaption.h"
79 #include "support/filetools.h"
80 #include "support/path.h"
81 #include "LaTeX.h"
82 #include "Chktex.h"
83 #include "LyXView.h"
84 #include "debug.h"
85 #include "LaTeXFeatures.h"
86 #include "support/syscall.h"
87 #include "support/lyxlib.h"
88 #include "support/FileInfo.h"
89 #include "support/lyxmanip.h"
90 #include "lyxtext.h"
91 #include "gettext.h"
92 #include "language.h"
93 #include "lyx_gui_misc.h"       // WarnReadonly()
94 #include "frontends/Dialogs.h"
95 #include "encoding.h"
96 #include "exporter.h"
97 #include "Lsstream.h"
98 #include "converter.h"
99
100 using std::stringstream;
101 using std::ostream;
102 using std::ofstream;
103 using std::ifstream;
104 using std::fstream;
105 using std::ios;
106 using std::setw;
107 using std::endl;
108 using std::pair;
109 using std::make_pair;
110 using std::vector;
111 using std::map;
112 using std::max;
113 using std::set;
114
115 // all these externs should eventually be removed.
116 extern BufferList bufferlist;
117
118 extern LyXAction lyxaction;
119
120
121 static const int LYX_FORMAT = 218;
122
123 extern int tex_code_break_column;
124
125
126 Buffer::Buffer(string const & file, bool ronly)
127 {
128         lyxerr[Debug::INFO] << "Buffer::Buffer()" << endl;
129         filename = file;
130         filepath = OnlyPath(file);
131         paragraph = 0;
132         lyx_clean = true;
133         bak_clean = true;
134         dep_clean = 0;
135         read_only = ronly;
136         unnamed = false;
137         users = 0;
138         lyxvc.buffer(this);
139         if (read_only || (lyxrc.use_tempdir)) {
140                 tmppath = CreateBufferTmpDir();
141         } else tmppath.erase();
142 }
143
144
145 Buffer::~Buffer()
146 {
147         lyxerr[Debug::INFO] << "Buffer::~Buffer()" << endl;
148         // here the buffer should take care that it is
149         // saved properly, before it goes into the void.
150
151         // make sure that views using this buffer
152         // forgets it.
153         if (users)
154                 users->buffer(0);
155         
156         if (!tmppath.empty()) {
157                 DestroyBufferTmpDir(tmppath);
158         }
159         
160         LyXParagraph * par = paragraph;
161         LyXParagraph * tmppar;
162 #ifndef NEW_INSETS
163         while (par) {
164                 tmppar = par->next_;
165                 delete par;
166                 par = tmppar;
167         }
168 #else
169         while (par) {
170                 tmppar = par->next();
171                 delete par;
172                 par = tmppar;
173         }
174 #endif
175         paragraph = 0;
176 }
177
178
179 string const Buffer::getLatexName(bool no_path) const
180 {
181         if (no_path)
182                 return OnlyFilename(ChangeExtension(MakeLatexName(filename), 
183                                                     ".tex"));
184         else
185                 return ChangeExtension(MakeLatexName(filename), 
186                                        ".tex"); 
187 }
188
189
190 pair<Buffer::LogType, string> const Buffer::getLogName(void) const
191 {
192         string const filename = getLatexName(false);
193
194         if (filename.empty())
195                 return make_pair(Buffer::latexlog, string());
196
197         string path = OnlyPath(filename);
198
199         if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1))
200                 path = tmppath;
201
202         string const fname = AddName(path,
203                                      OnlyFilename(ChangeExtension(filename,
204                                                                   ".log")));
205         string const bname =
206                 AddName(path, OnlyFilename(
207                         ChangeExtension(filename,
208                                         formats.Extension("literate") + ".out")));
209
210         // If no Latex log or Build log is newer, show Build log
211
212         FileInfo const f_fi(fname);
213         FileInfo const b_fi(bname);
214
215         if (b_fi.exist() &&
216             (!f_fi.exist() || f_fi.getModificationTime() < b_fi.getModificationTime())) {
217                 lyxerr[Debug::FILES] << "Log name calculated as : " << bname << endl;
218                 return make_pair(Buffer::buildlog, bname);
219         }
220         lyxerr[Debug::FILES] << "Log name calculated as : " << fname << endl;
221         return make_pair(Buffer::latexlog, fname);
222 }
223
224
225 void Buffer::setReadonly(bool flag)
226 {
227         if (read_only != flag) {
228                 read_only = flag; 
229                 updateTitles();
230                 users->owner()->getDialogs()->updateBufferDependent(false);
231         }
232         if (read_only) {
233                 WarnReadonly(filename);
234         }
235 }
236
237
238 bool Buffer::saveParamsAsDefaults() // const
239 {
240         string const fname = AddName(AddPath(user_lyxdir, "templates/"),
241                                "defaults.lyx");
242         Buffer defaults = Buffer(fname);
243         
244         // Use the current buffer's parameters as default
245         defaults.params = params;
246         
247         // add an empty paragraph. Is this enough?
248         defaults.paragraph = new LyXParagraph;
249
250         return defaults.writeFile(defaults.filename, false);
251 }
252
253
254 /// Update window titles of all users
255 // Should work on a list
256 void Buffer::updateTitles() const
257 {
258         if (users) users->owner()->updateWindowTitle();
259 }
260
261
262 /// Reset autosave timer of all users
263 // Should work on a list
264 void Buffer::resetAutosaveTimers() const
265 {
266         if (users) users->owner()->resetAutosaveTimer();
267 }
268
269
270 void Buffer::setFileName(string const & newfile)
271 {
272         filename = MakeAbsPath(newfile);
273         filepath = OnlyPath(filename);
274         setReadonly(IsFileWriteable(filename) == 0);
275         updateTitles();
276 }
277
278
279 // candidate for move to BufferView
280 // (at least some parts in the beginning of the func)
281 //
282 // Uwe C. Schroeder
283 // changed to be public and have one parameter
284 // if par = 0 normal behavior
285 // else insert behavior
286 // Returns false if "\the_end" is not read for formats >= 2.13. (Asger)
287 bool Buffer::readLyXformat2(LyXLex & lex, LyXParagraph * par)
288 {
289         int pos = 0;
290         char depth = 0; // signed or unsigned?
291 #ifndef NEW_INSETS
292         LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
293         LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
294 #endif
295         bool the_end_read = false;
296
297         LyXParagraph * return_par = 0;
298         LyXFont font(LyXFont::ALL_INHERIT, params.language);
299         if (file_format < 216 && params.language->lang() == "hebrew")
300                 font.setLanguage(default_language);
301         // If we are inserting, we cheat and get a token in advance
302         bool has_token = false;
303         string pretoken;
304
305         if (!par) {
306                 par = new LyXParagraph;
307         } else {
308                 users->text->BreakParagraph(users);
309                 return_par = users->text->FirstParagraph();
310                 pos = 0;
311                 markDirty();
312                 // We don't want to adopt the parameters from the
313                 // document we insert, so we skip until the text begins:
314                 while (lex.IsOK()) {
315                         lex.nextToken();
316                         pretoken = lex.GetString();
317                         if (pretoken == "\\layout") {
318                                 has_token = true;
319                                 break;
320                         }
321                 }
322         }
323
324         while (lex.IsOK()) {
325                 if (has_token) {
326                         has_token = false;
327                 } else {
328                         lex.nextToken();
329                         pretoken = lex.GetString();
330                 }
331
332                 if (pretoken.empty()) continue;
333                 
334                 the_end_read =
335                         parseSingleLyXformat2Token(lex, par, return_par,
336                                                    pretoken, pos, depth,
337                                                    font
338 #ifndef NEW_INSETS
339                                                    , footnoteflag,
340                                                    footnotekind
341 #endif
342                                 );
343         }
344    
345         if (!return_par)
346                 return_par = par;
347
348         paragraph = return_par;
349         
350         return the_end_read;
351 }
352
353
354 // We'll remove this later. (Lgb)
355 static string last_inset_read;
356
357
358 bool
359 Buffer::parseSingleLyXformat2Token(LyXLex & lex, LyXParagraph *& par,
360                                    LyXParagraph *& return_par,
361                                    string const & token, int & pos,
362                                    char & depth, LyXFont & font
363 #ifndef NEW_INSETS
364                                    , LyXParagraph::footnote_flag & footnoteflag,
365                                    LyXParagraph::footnote_kind & footnotekind
366 #endif
367         )
368 {
369 #ifdef NEW_INSETS
370         // This is super temporary but is needed to get the compability
371         // mode for minipages work correctly together with new tabulars.
372         static int call_depth = 0;
373         ++call_depth;
374 #endif
375         bool the_end_read = false;
376         
377         if (token[0] != '\\') {
378                 for (string::const_iterator cit = token.begin();
379                      cit != token.end(); ++cit) {
380                         par->InsertChar(pos, (*cit), font);
381                         ++pos;
382                 }
383         } else if (token == "\\i") {
384                 Inset * inset = new InsetLatexAccent;
385                 inset->Read(this, lex);
386                 par->InsertInset(pos, inset, font);
387                 ++pos;
388         } else if (token == "\\layout") {
389 #ifndef NEW_INSETS
390                 if (!return_par) 
391                         return_par = par;
392                 else {
393                         par->fitToSize();
394                         par = new LyXParagraph(par);
395                 }
396                 pos = 0;
397                 lex.EatLine();
398                 string const layoutname = lex.GetString();
399                 pair<bool, LyXTextClass::LayoutList::size_type> pp
400                         = textclasslist.NumberOfLayout(params.textclass,
401                                                        layoutname);
402                 if (pp.first) {
403                         par->layout = pp.second;
404                 } else { // layout not found
405                         // use default layout "Standard" (0)
406                         par->layout = 0;
407                 }
408                 // Test whether the layout is obsolete.
409                 LyXLayout const & layout =
410                         textclasslist.Style(params.textclass,
411                                             par->layout); 
412                 if (!layout.obsoleted_by().empty())
413                         par->layout = 
414                                 textclasslist.NumberOfLayout(params.textclass, 
415                                                              layout.obsoleted_by()).second;
416                 par->footnoteflag = footnoteflag;
417                 par->footnotekind = footnotekind;
418                 par->params.depth(depth);
419                 font = LyXFont(LyXFont::ALL_INHERIT, params.language);
420                 if (file_format < 216 && params.language->lang() == "hebrew")
421                         font.setLanguage(default_language);
422 #else
423                 lex.EatLine();
424                 string const layoutname = lex.GetString();
425                 pair<bool, LyXTextClass::LayoutList::size_type> pp
426                         = textclasslist.NumberOfLayout(params.textclass,
427                                                        layoutname);
428
429 #ifdef USE_CAPTION
430                 // The is the compability reading of layout caption.
431                 // It can be removed in LyX version 1.3.0. (Lgb)
432                 if (compare_no_case(layoutname, "caption") == 0) {
433                         // We expect that the par we are now working on is
434                         // really inside a InsetText inside a InsetFloat.
435                         // We also know that captions can only be
436                         // one paragraph. (Lgb)
437                         
438                         // We should now read until the next "\layout"
439                         // is reached.
440                         // This is probably not good enough, what if the
441                         // caption is the last par in the document (Lgb)
442                         istream & ist = lex.getStream();
443                         stringstream ss;
444                         string line;
445                         int begin = 0;
446                         while (true) {
447                                 getline(ist, line);
448                                 if (prefixIs(line, "\\layout")) {
449                                         lex.pushToken(line);
450                                         break;
451                                 }
452                                 if (prefixIs(line, "\\begin_inset"))
453                                         ++begin;
454                                 if (prefixIs(line, "\\end_inset")) {
455                                         if (begin)
456                                                 --begin;
457                                         else {
458                                                 lex.pushToken(line);
459                                                 break;
460                                         }
461                                 }
462                                 
463                                 ss << line << '\n';
464                         }
465                         // Now we should have the whole layout in ss
466                         // we should now be able to give this to the
467                         // caption inset.
468                         ss << "\\end_inset\n";
469                         
470                         // This seems like a bug in stringstream.
471                         // We really should be able to use ss
472                         // directly. (Lgb)
473                         istringstream is(ss.str());
474                         LyXLex tmplex(0, 0);
475                         tmplex.setStream(is);
476                         Inset * inset = new InsetCaption;
477                         inset->Read(this, tmplex);
478                         par->InsertInset(pos, inset, font);
479                         ++pos;
480                 } else {
481 #endif
482 #ifndef NO_PEXTRA_REALLY
483                         // BEGIN pextra_minipage compability
484                         // This should be removed in 1.3.x (Lgb)
485                         
486                         // This compability code is not perfect. In a couple
487                         // of rand cases it fails. When the minipage par is
488                         // the first par in the document, and when there are
489                         // none or only one regular paragraphs after the
490                         // minipage. Currently I am not investing any effort
491                         // in fixing those cases.
492                         static LyXParagraph * minipar = 0;
493                         //lyxerr << "Call depth: " << call_depth << endl;
494                         if (call_depth == 1) {
495                                 
496                         if (minipar
497                             && par->params.pextraType() == LyXParagraph::PEXTRA_MINIPAGE) {
498                                 lyxerr << "minipages in a row" << endl;
499                                 if (par->params.pextraStartMinipage()) {
500                                         lyxerr << "start new minipage" << endl;
501                                         // minipages in a row
502                                         par->previous()->next(0);
503                                         par->previous(minipar->previous());
504                                         minipar->previous()->next(par);
505                                         minipar->previous(0);
506                                         
507                                         // Before we insert the list of
508                                         // minipages into the inset we have
509                                         // to clean up a bit.
510                                         // This is not quite correct yet since
511                                         // we do want to use some of these
512                                         // parameters to set options in the
513                                         // minipage inset.
514                                         InsetMinipage::Position imp = static_cast<InsetMinipage::Position>(minipar->params.pextraAlignment());
515                                         LyXParagraph * tmp = minipar;
516                                         while (tmp) {
517                                                 tmp->params.pextraType(0);
518                                                 tmp->params.pextraWidth(string());
519                                                 tmp->params.pextraWidthp(string());
520                                                 tmp->params.pextraAlignment(0);
521                                                 tmp->params.pextraHfill(false);
522                                                 tmp->params.pextraStartMinipage(false);
523                                                 tmp = tmp->next();
524                                         }
525                                         
526                                         InsetMinipage * mini = new InsetMinipage;
527                                         mini->pos(imp);
528                                         mini->inset->par = minipar;
529                                         // Insert the minipage last in the
530                                         // previous paragraph.
531                                         par->previous()->InsertInset(par->previous()->size(), mini);
532                                         minipar = par;
533                                 } else {
534                                         lyxerr << "new minipage par" << endl;
535                                         //nothing to do just continue reading
536                                 }
537                                 
538                         } else if (minipar) {
539                                 lyxerr << "last minipage par read" << endl;
540                                 // The last paragraph read was not part of a
541                                 // minipage but the par linked list is...
542                                 // So we need to remove the last par from the
543                                 // rest, insert the rest of the paragraphs into
544                                 // a InsetMinipage, insert this minipage into
545                                 // prevpar, append the current par to prevpar
546                                 // and continue...
547
548                                 LyXParagraph * lp = minipar;
549                                 int pcount = 0;
550                                 while (lp) {
551                                         ++pcount;
552                                         lp = lp->next();
553                                 }
554                                 lyxerr << "Minipar count: " << pcount << endl;
555                                 lyxerr << "Par: " << (void*)par << endl;
556                                 lyxerr << "Par->prev: " << (void*)par->previous() << endl;
557
558                                 if (par->previous())
559                                         par->previous()->next(0);
560                                 par->previous(minipar->previous());
561                                 minipar->previous()->next(par);
562                                 minipar->previous(0);
563                                 
564                                 // Before we insert the list of
565                                 // minipages into the inset we have
566                                 // to clean up a bit.
567                                 // This is not quite correct yet since we
568                                 // do want to use some of these parameters
569                                 // to set options in the minipage inset.
570                                 InsetMinipage::Position imp = static_cast<InsetMinipage::Position>(minipar->params.pextraAlignment());
571                                 LyXParagraph * tmp = minipar;
572                                 while (tmp) {
573                                         tmp->params.pextraType(0);
574                                         tmp->params.pextraWidth(string());
575                                         tmp->params.pextraWidthp(string());
576                                         tmp->params.pextraAlignment(0);
577                                         tmp->params.pextraHfill(false);
578                                         tmp->params.pextraStartMinipage(false);
579                                         tmp = tmp->next();
580                                 }
581                                 
582                                 InsetMinipage * mini = new InsetMinipage;
583                                 mini->pos(imp);
584                                 mini->inset->par = minipar;
585                                 par->previous()->InsertInset(par->previous()->size(), mini);
586                                 minipar = 0;
587                         } else if (par->params.pextraType() == LyXParagraph::PEXTRA_MINIPAGE) {
588                                 
589                                 // par is the first paragraph in a minipage
590                                 lyxerr << "begin minipage" << endl;
591                                 minipar = par;
592                                 
593                         }
594                         }
595                         
596                         // End of pextra_minipage compability
597 #endif  
598                         if (!return_par)
599                                 return_par = par;
600                         else {
601                                 par->fitToSize();
602                                 par = new LyXParagraph(par);
603                         }
604                         pos = 0;
605                         if (pp.first) {
606                                 par->layout = pp.second;
607                         } else {
608                                 // layout not found
609                                 // use default layout "Standard" (0)
610                                 par->layout = 0;
611                         }
612                         // Test whether the layout is obsolete.
613                         LyXLayout const & layout =
614                                 textclasslist.Style(params.textclass,
615                                                     par->layout);
616                         if (!layout.obsoleted_by().empty())
617                                 par->layout = textclasslist
618                                         .NumberOfLayout(params.textclass,
619                                                         layout.obsoleted_by())
620                                         .second;
621                         par->params.depth(depth);
622                         font = LyXFont(LyXFont::ALL_INHERIT, params.language);
623                         if (file_format < 216
624                             && params.language->lang() == "hebrew")
625                                 font.setLanguage(default_language);
626 #if USE_CAPTION
627                 }
628 #endif
629 #endif
630 #ifndef NEW_INSETS
631         } else if (token == "\\end_float") {
632                 if (!return_par) 
633                         return_par = par;
634                 else {
635                         par->fitToSize();
636                         par = new LyXParagraph(par);
637                 }
638                 footnotekind = LyXParagraph::FOOTNOTE;
639                 footnoteflag = LyXParagraph::NO_FOOTNOTE;
640                 pos = 0;
641                 lex.EatLine();
642                 par->layout = LYX_DUMMY_LAYOUT;
643                 font = LyXFont(LyXFont::ALL_INHERIT, params.language);
644                 if (file_format < 216 && params.language->lang() == "hebrew")
645                         font.setLanguage(default_language);
646         } else if (token == "\\begin_float") {
647                 int tmpret = lex.FindToken(string_footnotekinds);
648                 if (tmpret == -1) ++tmpret;
649                 if (tmpret != LYX_LAYOUT_DEFAULT) 
650                         footnotekind = static_cast<LyXParagraph::footnote_kind>(tmpret); // bad
651                 if (footnotekind == LyXParagraph::FOOTNOTE
652                     || footnotekind == LyXParagraph::MARGIN)
653                         footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
654                 else 
655                         footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
656 #else
657         } else if (token == "\\begin_float") {
658                 // This is the compability reader. It can be removed in
659                 // LyX version 1.3.0. (Lgb)
660                 lex.next();
661                 string const tmptok = lex.GetString();
662                 //lyxerr << "old float: " << tmptok << endl;
663                 
664                 Inset * inset = 0;
665                 stringstream old_float;
666                 
667                 if (tmptok == "footnote") {
668                         inset = new InsetFoot;
669                 } else if (tmptok == "margin") {
670                         inset = new InsetMarginal;
671                 } else if (tmptok == "fig") {
672                         inset = new InsetFloat("figure");
673                         old_float << "placement htbp\n";
674                 } else if (tmptok == "tab") {
675                         inset = new InsetFloat("table");
676                         old_float << "placement htbp\n";
677                 } else if (tmptok == "alg") {
678                         inset = new InsetFloat("algorithm");
679                         old_float << "placement htbp\n";
680                 } else if (tmptok == "wide-fig") {
681                         InsetFloat * tmp = new InsetFloat("figure");
682                         tmp->wide(true);
683                         inset = tmp;
684                         old_float << "placement htbp\n";
685                 } else if (tmptok == "wide-tab") {
686                         InsetFloat * tmp = new InsetFloat("table");
687                         tmp->wide(true);
688                         inset = tmp;
689                         old_float << "placement htbp\n";
690                 }
691
692                 if (!inset) {
693                         --call_depth;
694                         return false; // no end read yet
695                 }
696                 
697                 old_float << "collapsed true\n";
698
699                 // Here we need to check for \end_deeper and handle that
700                 // before we do the footnote parsing.
701                 // This _is_ a hack! (Lgb)
702                 while (true) {
703                         lex.next();
704                         string const tmp = lex.GetString();
705                         if (tmp == "\\end_deeper") {
706                                 //lyxerr << "\\end_deeper caught!" << endl;
707                                 if (!depth) {
708                                         lex.printError("\\end_deeper: "
709                                                        "depth is already null");
710                                 } else
711                                         --depth;
712                                 
713                         } else {
714                                 old_float << tmp << ' ';
715                                 break;
716                         }
717                 }
718                 
719                 old_float << lex.getLongString("\\end_float")
720                           << "\n\\end_inset\n";
721                 //lyxerr << "Float Body:\n" << old_float.str() << endl;
722                 // That this does not work seems like a bug
723                 // in stringstream. (Lgb)
724                 istringstream istr(old_float.str());
725                 LyXLex nylex(0, 0);
726                 nylex.setStream(istr);
727                 inset->Read(this, nylex);
728                 par->InsertInset(pos, inset, font);
729                 ++pos;
730 #endif
731         } else if (token == "\\begin_deeper") {
732                 ++depth;
733         } else if (token == "\\end_deeper") {
734                 if (!depth) {
735                         lex.printError("\\end_deeper: "
736                                        "depth is already null");
737                 }
738                 else
739                         --depth;
740         } else if (token == "\\begin_preamble") {
741                 params.readPreamble(lex);
742         } else if (token == "\\textclass") {
743                 lex.EatLine();
744                 pair<bool, LyXTextClassList::size_type> pp = 
745                         textclasslist.NumberOfClass(lex.GetString());
746                 if (pp.first) {
747                         params.textclass = pp.second;
748                 } else {
749                         WriteAlert(string(_("Textclass error")), 
750                                 string(_("The document uses an unknown textclass \"")) + 
751                                 lex.GetString() + string("\"."),
752                                 string(_("LyX will not be able to produce output correctly.")));
753                         params.textclass = 0;
754                 }
755                 if (!textclasslist.Load(params.textclass)) {
756                                 // if the textclass wasn't loaded properly
757                                 // we need to either substitute another
758                                 // or stop loading the file.
759                                 // I can substitute but I don't see how I can
760                                 // stop loading... ideas??  ARRae980418
761                         WriteAlert(_("Textclass Loading Error!"),
762                                    string(_("Can't load textclass ")) +
763                                    textclasslist.NameOfClass(params.textclass),
764                                    _("-- substituting default"));
765                         params.textclass = 0;
766                 }
767         } else if (token == "\\options") {
768                 lex.EatLine();
769                 params.options = lex.GetString();
770         } else if (token == "\\language") {
771                 params.readLanguage(lex);    
772         } else if (token == "\\fontencoding") {
773                 lex.EatLine();
774         } else if (token == "\\inputencoding") {
775                 lex.EatLine();
776                 params.inputenc = lex.GetString();
777         } else if (token == "\\graphics") {
778                 params.readGraphicsDriver(lex);
779         } else if (token == "\\fontscheme") {
780                 lex.EatLine();
781                 params.fonts = lex.GetString();
782         } else if (token == "\\noindent") {
783                 par->params.noindent(true);
784         } else if (token == "\\fill_top") {
785                 par->params.spaceTop(VSpace(VSpace::VFILL));
786         } else if (token == "\\fill_bottom") {
787                 par->params.spaceBottom(VSpace(VSpace::VFILL));
788         } else if (token == "\\line_top") {
789                 par->params.lineTop(true);
790         } else if (token == "\\line_bottom") {
791                 par->params.lineBottom(true);
792         } else if (token == "\\pagebreak_top") {
793                 par->params.pagebreakTop(true);
794         } else if (token == "\\pagebreak_bottom") {
795                 par->params.pagebreakBottom(true);
796         } else if (token == "\\start_of_appendix") {
797                 par->params.startOfAppendix(true);
798         } else if (token == "\\paragraph_separation") {
799                 int tmpret = lex.FindToken(string_paragraph_separation);
800                 if (tmpret == -1) ++tmpret;
801                 if (tmpret != LYX_LAYOUT_DEFAULT) 
802                         params.paragraph_separation =
803                                 static_cast<BufferParams::PARSEP>(tmpret);
804         } else if (token == "\\defskip") {
805                 lex.nextToken();
806                 params.defskip = VSpace(lex.GetString());
807         } else if (token == "\\epsfig") { // obsolete
808                 // Indeed it is obsolete, but we HAVE to be backwards
809                 // compatible until 0.14, because otherwise all figures
810                 // in existing documents are irretrivably lost. (Asger)
811                 params.readGraphicsDriver(lex);
812         } else if (token == "\\quotes_language") {
813                 int tmpret = lex.FindToken(string_quotes_language);
814                 if (tmpret == -1) ++tmpret;
815                 if (tmpret != LYX_LAYOUT_DEFAULT) {
816                         InsetQuotes::quote_language tmpl = 
817                                 InsetQuotes::EnglishQ;
818                         switch (tmpret) {
819                         case 0:
820                                 tmpl = InsetQuotes::EnglishQ;
821                                 break;
822                         case 1:
823                                 tmpl = InsetQuotes::SwedishQ;
824                                 break;
825                         case 2:
826                                 tmpl = InsetQuotes::GermanQ;
827                                 break;
828                         case 3:
829                                 tmpl = InsetQuotes::PolishQ;
830                                 break;
831                         case 4:
832                                 tmpl = InsetQuotes::FrenchQ;
833                                 break;
834                         case 5:
835                                 tmpl = InsetQuotes::DanishQ;
836                                 break;  
837                         }
838                         params.quotes_language = tmpl;
839                 }
840         } else if (token == "\\quotes_times") {
841                 lex.nextToken();
842                 switch (lex.GetInteger()) {
843                 case 1: 
844                         params.quotes_times = InsetQuotes::SingleQ; 
845                         break;
846                 case 2: 
847                         params.quotes_times = InsetQuotes::DoubleQ; 
848                         break;
849                 }
850         } else if (token == "\\papersize") {
851                 int tmpret = lex.FindToken(string_papersize);
852                 if (tmpret == -1)
853                         ++tmpret;
854                 else
855                         params.papersize2 = tmpret;
856         } else if (token == "\\paperpackage") {
857                 int tmpret = lex.FindToken(string_paperpackages);
858                 if (tmpret == -1) {
859                         ++tmpret;
860                         params.paperpackage = BufferParams::PACKAGE_NONE;
861                 } else
862                         params.paperpackage = tmpret;
863         } else if (token == "\\use_geometry") {
864                 lex.nextToken();
865                 params.use_geometry = lex.GetInteger();
866         } else if (token == "\\use_amsmath") {
867                 lex.nextToken();
868                 params.use_amsmath = lex.GetInteger();
869         } else if (token == "\\paperorientation") {
870                 int tmpret = lex.FindToken(string_orientation);
871                 if (tmpret == -1) ++tmpret;
872                 if (tmpret != LYX_LAYOUT_DEFAULT) 
873                         params.orientation = static_cast<BufferParams::PAPER_ORIENTATION>(tmpret);
874         } else if (token == "\\paperwidth") {
875                 lex.next();
876                 params.paperwidth = lex.GetString();
877         } else if (token == "\\paperheight") {
878                 lex.next();
879                 params.paperheight = lex.GetString();
880         } else if (token == "\\leftmargin") {
881                 lex.next();
882                 params.leftmargin = lex.GetString();
883         } else if (token == "\\topmargin") {
884                 lex.next();
885                 params.topmargin = lex.GetString();
886         } else if (token == "\\rightmargin") {
887                 lex.next();
888                 params.rightmargin = lex.GetString();
889         } else if (token == "\\bottommargin") {
890                 lex.next();
891                 params.bottommargin = lex.GetString();
892         } else if (token == "\\headheight") {
893                 lex.next();
894                 params.headheight = lex.GetString();
895         } else if (token == "\\headsep") {
896                 lex.next();
897                 params.headsep = lex.GetString();
898         } else if (token == "\\footskip") {
899                 lex.next();
900                 params.footskip = lex.GetString();
901         } else if (token == "\\paperfontsize") {
902                 lex.nextToken();
903                 params.fontsize = strip(lex.GetString());
904         } else if (token == "\\papercolumns") {
905                 lex.nextToken();
906                 params.columns = lex.GetInteger();
907         } else if (token == "\\papersides") {
908                 lex.nextToken();
909                 switch (lex.GetInteger()) {
910                 default:
911                 case 1: params.sides = LyXTextClass::OneSide; break;
912                 case 2: params.sides = LyXTextClass::TwoSides; break;
913                 }
914         } else if (token == "\\paperpagestyle") {
915                 lex.nextToken();
916                 params.pagestyle = strip(lex.GetString());
917         } else if (token == "\\bullet") {
918                 lex.nextToken();
919                 int const index = lex.GetInteger();
920                 lex.nextToken();
921                 int temp_int = lex.GetInteger();
922                 params.user_defined_bullets[index].setFont(temp_int);
923                 params.temp_bullets[index].setFont(temp_int);
924                 lex.nextToken();
925                 temp_int = lex.GetInteger();
926                 params.user_defined_bullets[index].setCharacter(temp_int);
927                 params.temp_bullets[index].setCharacter(temp_int);
928                 lex.nextToken();
929                 temp_int = lex.GetInteger();
930                 params.user_defined_bullets[index].setSize(temp_int);
931                 params.temp_bullets[index].setSize(temp_int);
932                 lex.nextToken();
933                 string const temp_str = lex.GetString();
934                 if (temp_str != "\\end_bullet") {
935                                 // this element isn't really necessary for
936                                 // parsing but is easier for humans
937                                 // to understand bullets. Put it back and
938                                 // set a debug message?
939                         lex.printError("\\end_bullet expected, got" + temp_str);
940                                 //how can I put it back?
941                 }
942         } else if (token == "\\bulletLaTeX") {
943                 lex.nextToken();
944                 int const index = lex.GetInteger();
945                 lex.next();
946                 string temp_str = lex.GetString();
947                 string sum_str;
948                 while (temp_str != "\\end_bullet") {
949                                 // this loop structure is needed when user
950                                 // enters an empty string since the first
951                                 // thing returned will be the \\end_bullet
952                                 // OR
953                                 // if the LaTeX entry has spaces. Each element
954                                 // therefore needs to be read in turn
955                         sum_str += temp_str;
956                         lex.next();
957                         temp_str = lex.GetString();
958                 }
959                 params.user_defined_bullets[index].setText(sum_str);
960                 params.temp_bullets[index].setText(sum_str);
961         } else if (token == "\\secnumdepth") {
962                 lex.nextToken();
963                 params.secnumdepth = lex.GetInteger();
964         } else if (token == "\\tocdepth") {
965                 lex.nextToken();
966                 params.tocdepth = lex.GetInteger();
967         } else if (token == "\\spacing") {
968                 lex.next();
969                 string const tmp = strip(lex.GetString());
970                 Spacing::Space tmp_space = Spacing::Default;
971                 float tmp_val = 0.0;
972                 if (tmp == "single") {
973                         tmp_space = Spacing::Single;
974                 } else if (tmp == "onehalf") {
975                         tmp_space = Spacing::Onehalf;
976                 } else if (tmp == "double") {
977                         tmp_space = Spacing::Double;
978                 } else if (tmp == "other") {
979                         lex.next();
980                         tmp_space = Spacing::Other;
981                         tmp_val = lex.GetFloat();
982                 } else {
983                         lex.printError("Unknown spacing token: '$$Token'");
984                 }
985                 // Small hack so that files written with klyx will be
986                 // parsed correctly.
987                 if (return_par) {
988                         par->params.spacing(Spacing(tmp_space, tmp_val));
989                 } else {
990                         params.spacing.set(tmp_space, tmp_val);
991                 }
992         } else if (token == "\\paragraph_spacing") {
993                 lex.next();
994                 string const tmp = strip(lex.GetString());
995                 if (tmp == "single") {
996                         par->params.spacing(Spacing(Spacing::Single));
997                 } else if (tmp == "onehalf") {
998                         par->params.spacing(Spacing(Spacing::Onehalf));
999                 } else if (tmp == "double") {
1000                         par->params.spacing(Spacing(Spacing::Double));
1001                 } else if (tmp == "other") {
1002                         lex.next();
1003                         par->params.spacing(Spacing(Spacing::Other,
1004                                          lex.GetFloat()));
1005                 } else {
1006                         lex.printError("Unknown spacing token: '$$Token'");
1007                 }
1008         } else if (token == "\\float_placement") {
1009                 lex.nextToken();
1010                 params.float_placement = lex.GetString();
1011         } else if (token == "\\family") { 
1012                 lex.next();
1013                 font.setLyXFamily(lex.GetString());
1014         } else if (token == "\\series") {
1015                 lex.next();
1016                 font.setLyXSeries(lex.GetString());
1017         } else if (token == "\\shape") {
1018                 lex.next();
1019                 font.setLyXShape(lex.GetString());
1020         } else if (token == "\\size") {
1021                 lex.next();
1022                 font.setLyXSize(lex.GetString());
1023         } else if (token == "\\latex") {
1024                 lex.next();
1025                 string const tok = lex.GetString();
1026                 // This is dirty, but gone with LyX3. (Asger)
1027                 if (tok == "no_latex")
1028                         font.setLatex(LyXFont::OFF);
1029                 else if (tok == "latex")
1030                         font.setLatex(LyXFont::ON);
1031                 else if (tok == "default")
1032                         font.setLatex(LyXFont::INHERIT);
1033                 else
1034                         lex.printError("Unknown LaTeX font flag "
1035                                        "`$$Token'");
1036         } else if (token == "\\lang") {
1037                 lex.next();
1038                 string const tok = lex.GetString();
1039                 Language const * lang = languages.getLanguage(tok);
1040                 if (lang) {
1041                         font.setLanguage(lang);
1042                 } else {
1043                         font.setLanguage(params.language);
1044                         lex.printError("Unknown language `$$Token'");
1045                 }
1046         } else if (token == "\\numeric") {
1047                 lex.next();
1048                 font.setNumber(font.setLyXMisc(lex.GetString()));
1049         } else if (token == "\\emph") {
1050                 lex.next();
1051                 font.setEmph(font.setLyXMisc(lex.GetString()));
1052         } else if (token == "\\bar") {
1053                 lex.next();
1054                 string const tok = lex.GetString();
1055                 // This is dirty, but gone with LyX3. (Asger)
1056                 if (tok == "under")
1057                         font.setUnderbar(LyXFont::ON);
1058                 else if (tok == "no")
1059                         font.setUnderbar(LyXFont::OFF);
1060                 else if (tok == "default")
1061                         font.setUnderbar(LyXFont::INHERIT);
1062                 else
1063                         lex.printError("Unknown bar font flag "
1064                                        "`$$Token'");
1065         } else if (token == "\\noun") {
1066                 lex.next();
1067                 font.setNoun(font.setLyXMisc(lex.GetString()));
1068         } else if (token == "\\color") {
1069                 lex.next();
1070                 font.setLyXColor(lex.GetString());
1071         } else if (token == "\\align") {
1072                 int tmpret = lex.FindToken(string_align);
1073                 if (tmpret == -1) ++tmpret;
1074                 if (tmpret != LYX_LAYOUT_DEFAULT) { // tmpret != 99 ???
1075                         int const tmpret2 = int(pow(2.0, tmpret));
1076                         //lyxerr << "Tmpret2 = " << tmpret2 << endl;
1077                         par->params.align(LyXAlignment(tmpret2));
1078                 }
1079         } else if (token == "\\added_space_top") {
1080                 lex.nextToken();
1081                 par->params.spaceTop(VSpace(lex.GetString()));
1082         } else if (token == "\\added_space_bottom") {
1083                 lex.nextToken();
1084                 par->params.spaceBottom(VSpace(lex.GetString()));
1085 #ifndef NO_PEXTRA_REALLY
1086         } else if (token == "\\pextra_type") {
1087                 lex.nextToken();
1088                 par->params.pextraType(lex.GetInteger());
1089         } else if (token == "\\pextra_width") {
1090                 lex.nextToken();
1091                 par->params.pextraWidth(lex.GetString());
1092         } else if (token == "\\pextra_widthp") {
1093                 lex.nextToken();
1094                 par->params.pextraWidthp(lex.GetString());
1095         } else if (token == "\\pextra_alignment") {
1096                 lex.nextToken();
1097                 par->params.pextraAlignment(lex.GetInteger());
1098         } else if (token == "\\pextra_hfill") {
1099                 lex.nextToken();
1100                 par->params.pextraHfill(lex.GetInteger());
1101         } else if (token == "\\pextra_start_minipage") {
1102                 lex.nextToken();
1103                 par->params.pextraStartMinipage(lex.GetInteger());
1104 #endif
1105         } else if (token == "\\labelwidthstring") {
1106                 lex.EatLine();
1107                 par->params.labelWidthString(lex.GetString());
1108                 // do not delete this token, it is still needed!
1109         } else if (token == "\\end_inset") {
1110                 lyxerr << "Solitary \\end_inset. Missing \\begin_inset?.\n"
1111                        << "Last inset read was: " << last_inset_read
1112                        << endl;
1113                 // Simply ignore this. The insets do not have
1114                 // to read this.
1115                 // But insets should read it, it is a part of
1116                 // the inset isn't it? Lgb.
1117         } else if (token == "\\begin_inset") {
1118                 readInset(lex, par, pos, font);
1119         } else if (token == "\\SpecialChar") {
1120                 LyXLayout const & layout =
1121                         textclasslist.Style(params.textclass, 
1122                                             par->GetLayout());
1123
1124                 // Insets don't make sense in a free-spacing context! ---Kayvan
1125                 if (layout.free_spacing) {
1126                         if (lex.IsOK()) {
1127                                 lex.next();
1128                                 string next_token = lex.GetString();
1129                                 if (next_token == "\\-") {
1130                                         par->InsertChar(pos, '-', font);
1131                                 } else if (next_token == "\\protected_separator"
1132                                         || next_token == "~") {
1133                                         par->InsertChar(pos, ' ', font);
1134                                 } else {
1135                                         lex.printError("Token `$$Token' "
1136                                                        "is in free space "
1137                                                        "paragraph layout!");
1138                                         --pos;
1139                                 }
1140                         }
1141                 } else {
1142                         Inset * inset = new InsetSpecialChar;
1143                         inset->Read(this, lex);
1144                         par->InsertInset(pos, inset, font);
1145                 }
1146                 ++pos;
1147         } else if (token == "\\newline") {
1148                 par->InsertChar(pos, LyXParagraph::META_NEWLINE, font);
1149                 ++pos;
1150         } else if (token == "\\LyXTable") {
1151                 Inset * inset = new InsetTabular(*this);
1152                 inset->Read(this, lex);
1153                 par->InsertInset(pos, inset, font);
1154                 ++pos;
1155         } else if (token == "\\hfill") {
1156                 par->InsertChar(pos, LyXParagraph::META_HFILL, font);
1157                 ++pos;
1158         } else if (token == "\\protected_separator") { // obsolete
1159                 // This is a backward compability thingie. (Lgb)
1160                 // Remove it later some time...introduced with fileformat
1161                 // 2.16. (Lgb)
1162                 LyXLayout const & layout =
1163                         textclasslist.Style(params.textclass, 
1164                                             par->GetLayout());
1165
1166                 if (layout.free_spacing) {
1167                         par->InsertChar(pos, ' ', font);
1168                 } else {
1169                         Inset * inset = new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1170                         par->InsertInset(pos, inset, font);
1171                 }
1172                 ++pos;
1173         } else if (token == "\\bibitem") {  // ale970302
1174                 if (!par->bibkey) {
1175                         InsetCommandParams p("bibitem", "dummy");
1176                         par->bibkey = new InsetBibKey(p);
1177                 }
1178                 par->bibkey->Read(this, lex);                   
1179         } else if (token == "\\backslash") {
1180                 par->InsertChar(pos, '\\', font);
1181                 ++pos;
1182         } else if (token == "\\the_end") {
1183                 the_end_read = true;
1184         } else {
1185                 // This should be insurance for the future: (Asger)
1186                 lex.printError("Unknown token `$$Token'. "
1187                                "Inserting as text.");
1188                 string::const_iterator cit = token.begin();
1189                 string::const_iterator end = token.end();
1190                 for (; cit != end; ++cit) {
1191                         par->InsertChar(pos, (*cit), font);
1192                         ++pos;
1193                 }
1194         }
1195         --call_depth;
1196         return the_end_read;
1197 }
1198
1199
1200 void Buffer::readInset(LyXLex & lex, LyXParagraph *& par,
1201                        int & pos, LyXFont & font)
1202 {
1203         // consistency check
1204         if (lex.GetString() != "\\begin_inset") {
1205                 lyxerr << "Buffer::readInset: Consistency check failed."
1206                        << endl;
1207         }
1208         
1209         Inset * inset = 0;
1210
1211         lex.next();
1212         string const tmptok = lex.GetString();
1213         last_inset_read = tmptok;
1214
1215         // test the different insets
1216         if (tmptok == "LatexCommand") {
1217                 InsetCommandParams inscmd;
1218                 inscmd.Read(lex);
1219
1220                 if (inscmd.getCmdName() == "cite") {
1221                         inset = new InsetCitation(inscmd);
1222                 } else if (inscmd.getCmdName() == "bibitem") {
1223                         lex.printError("Wrong place for bibitem");
1224                         inset = new InsetBibKey(inscmd);
1225                 } else if (inscmd.getCmdName() == "BibTeX") {
1226                         inset = new InsetBibtex(inscmd);
1227                 } else if (inscmd.getCmdName() == "index") {
1228                         inset = new InsetIndex(inscmd);
1229                 } else if (inscmd.getCmdName() == "include") {
1230                         inset = new InsetInclude(inscmd, *this);
1231                 } else if (inscmd.getCmdName() == "label") {
1232                         inset = new InsetLabel(inscmd);
1233                 } else if (inscmd.getCmdName() == "url"
1234                            || inscmd.getCmdName() == "htmlurl") {
1235                         inset = new InsetUrl(inscmd);
1236                 } else if (inscmd.getCmdName() == "ref"
1237                            || inscmd.getCmdName() == "pageref"
1238                            || inscmd.getCmdName() == "vref"
1239                            || inscmd.getCmdName() == "vpageref"
1240                            || inscmd.getCmdName() == "prettyref") {
1241                         if (!inscmd.getOptions().empty()
1242                             || !inscmd.getContents().empty()) {
1243                                 inset = new InsetRef(inscmd, *this);
1244                         }
1245                 } else if (inscmd.getCmdName() == "tableofcontents"
1246                            || inscmd.getCmdName() == "listofalgorithms"
1247                            || inscmd.getCmdName() == "listoffigures"
1248                            || inscmd.getCmdName() == "listoftables") {
1249                         inset = new InsetTOC(inscmd);
1250                 } else if (inscmd.getCmdName() == "printindex") {
1251                         inset = new InsetPrintIndex(inscmd);
1252                 } else if (inscmd.getCmdName() == "lyxparent") {
1253                         inset = new InsetParent(inscmd, *this);
1254                 }
1255         } else {
1256                 if (tmptok == "Quotes") {
1257                         inset = new InsetQuotes;
1258                 } else if (tmptok == "External") {
1259                         inset = new InsetExternal;
1260                 } else if (tmptok == "FormulaMacro") {
1261                         inset = new InsetFormulaMacro;
1262                 } else if (tmptok == "Formula") {
1263                         inset = new InsetFormula;
1264                 } else if (tmptok == "Figure") {
1265                         inset = new InsetFig(100, 100, *this);
1266                 } else if (tmptok == "Info") {
1267                         inset = new InsetInfo;
1268                 } else if (tmptok == "Include") {
1269                         InsetCommandParams p( "Include" );
1270                         inset = new InsetInclude(p, *this);
1271                 } else if (tmptok == "ERT") {
1272                         inset = new InsetERT;
1273                 } else if (tmptok == "Tabular") {
1274                         inset = new InsetTabular(*this);
1275                 } else if (tmptok == "Text") {
1276                         inset = new InsetText;
1277                 } else if (tmptok == "Foot") {
1278                         inset = new InsetFoot;
1279                 } else if (tmptok == "Marginal") {
1280                         inset = new InsetMarginal;
1281                 } else if (tmptok == "Minipage") {
1282                         inset = new InsetMinipage;
1283                 } else if (tmptok == "Float") {
1284                         lex.next();
1285                         string tmptok = lex.GetString();
1286                         inset = new InsetFloat(tmptok);
1287                 } else if (tmptok == "List") {
1288                         inset = new InsetList;
1289                 } else if (tmptok == "Theorem") {
1290                         inset = new InsetList;
1291                 } else if (tmptok == "Caption") {
1292                         inset = new InsetCaption;
1293                 } else if (tmptok == "GRAPHICS") {
1294                         inset = new InsetGraphics;
1295                 }
1296                 
1297                 if (inset) inset->Read(this, lex);
1298         }
1299         
1300         if (inset) {
1301                 par->InsertInset(pos, inset, font);
1302                 ++pos;
1303         }
1304 }
1305
1306
1307 bool Buffer::readFile(LyXLex & lex, LyXParagraph * par)
1308 {
1309         if (lex.IsOK()) {
1310                 lex.next();
1311                 string const token(lex.GetString());
1312                 if (token == "\\lyxformat") { // the first token _must_ be...
1313                         lex.EatLine();
1314                         string tmp_format = lex.GetString();
1315                         //lyxerr << "LyX Format: `" << tmp_format << "'" << endl;
1316                         // if present remove ".," from string.
1317                         string::size_type dot = tmp_format.find_first_of(".,");
1318                         //lyxerr << "           dot found at " << dot << endl;
1319                         if (dot != string::npos)
1320                                 tmp_format.erase(dot, 1);
1321                         file_format = strToInt(tmp_format);
1322                         if (file_format == LYX_FORMAT) {
1323                                 // current format
1324                         } else if (file_format > LYX_FORMAT) {
1325                                 // future format
1326                                 WriteAlert(_("Warning!"),
1327                                            _("LyX file format is newer that what"),
1328                                            _("is supported in this LyX version. Expect some problems."));
1329                                 
1330                         } else if (file_format < LYX_FORMAT) {
1331                                 // old formats
1332                                 if (file_format < 200) {
1333                                         WriteAlert(_("ERROR!"),
1334                                                    _("Old LyX file format found. "
1335                                                      "Use LyX 0.10.x to read this!"));
1336                                         return false;
1337                                 }
1338                         }
1339                         bool the_end = readLyXformat2(lex, par);
1340                         setPaperStuff();
1341                         // the_end was added in 213
1342                         if (file_format < 213)
1343                                 the_end = true;
1344
1345                         if (!the_end)
1346                                 WriteAlert(_("Warning!"),
1347                                            _("Reading of document is not complete"),
1348                                            _("Maybe the document is truncated"));
1349                         return true;
1350                 } else { // "\\lyxformat" not found
1351                         WriteAlert(_("ERROR!"), _("Not a LyX file!"));
1352                 }
1353         } else
1354                 WriteAlert(_("ERROR!"), _("Unable to read file!"));
1355         return false;
1356 }
1357                     
1358
1359
1360 // Should probably be moved to somewhere else: BufferView? LyXView?
1361 bool Buffer::save() const
1362 {
1363         // We don't need autosaves in the immediate future. (Asger)
1364         resetAutosaveTimers();
1365
1366         // make a backup
1367         string s;
1368         if (lyxrc.make_backup) {
1369                 s = fileName() + '~';
1370                 if (!lyxrc.backupdir_path.empty())
1371                         s = AddName(lyxrc.backupdir_path,
1372                                     subst(CleanupPath(s),'/','!'));
1373
1374                 // Rename is the wrong way of making a backup,
1375                 // this is the correct way.
1376                 /* truss cp fil fil2:
1377                    lstat("LyXVC3.lyx", 0xEFFFF898)                 Err#2 ENOENT
1378                    stat("LyXVC.lyx", 0xEFFFF688)                   = 0
1379                    open("LyXVC.lyx", O_RDONLY)                     = 3
1380                    open("LyXVC3.lyx", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 4
1381                    fstat(4, 0xEFFFF508)                            = 0
1382                    fstat(3, 0xEFFFF508)                            = 0
1383                    read(3, " # T h i s   f i l e   w".., 8192)     = 5579
1384                    write(4, " # T h i s   f i l e   w".., 5579)    = 5579
1385                    read(3, 0xEFFFD4A0, 8192)                       = 0
1386                    close(4)                                        = 0
1387                    close(3)                                        = 0
1388                    chmod("LyXVC3.lyx", 0100644)                    = 0
1389                    lseek(0, 0, SEEK_CUR)                           = 46440
1390                    _exit(0)
1391                 */
1392
1393                 // Should proabaly have some more error checking here.
1394                 // Should be cleaned up in 0.13, at least a bit.
1395                 // Doing it this way, also makes the inodes stay the same.
1396                 // This is still not a very good solution, in particular we
1397                 // might loose the owner of the backup.
1398                 FileInfo finfo(fileName());
1399                 if (finfo.exist()) {
1400                         mode_t fmode = finfo.getMode();
1401                         struct utimbuf times = {
1402                                 finfo.getAccessTime(),
1403                                 finfo.getModificationTime() };
1404
1405                         ifstream ifs(fileName().c_str());
1406                         ofstream ofs(s.c_str(), ios::out|ios::trunc);
1407                         if (ifs && ofs) {
1408                                 ofs << ifs.rdbuf();
1409                                 ifs.close();
1410                                 ofs.close();
1411                                 ::chmod(s.c_str(), fmode);
1412                                 
1413                                 if (::utime(s.c_str(), &times)) {
1414                                         lyxerr << "utime error." << endl;
1415                                 }
1416                         } else {
1417                                 lyxerr << "LyX was not able to make "
1418                                         "backupcopy. Beware." << endl;
1419                         }
1420                 }
1421         }
1422         
1423         if (writeFile(fileName(), false)) {
1424                 markLyxClean();
1425                 removeAutosaveFile(fileName());
1426         } else {
1427                 // Saving failed, so backup is not backup
1428                 if (lyxrc.make_backup) {
1429                         lyx::rename(s, fileName());
1430                 }
1431                 return false;
1432         }
1433         return true;
1434 }
1435
1436
1437 // Returns false if unsuccesful
1438 bool Buffer::writeFile(string const & fname, bool flag) const
1439 {
1440         // if flag is false writeFile will not create any GUI
1441         // warnings, only cerr.
1442         // Needed for autosave in background or panic save (Matthias 120496)
1443
1444         if (read_only && (fname == filename)) {
1445                 // Here we should come with a question if we should
1446                 // perform the write anyway.
1447                 if (flag)
1448                         lyxerr << _("Error! Document is read-only: ")
1449                                << fname << endl;
1450                 else
1451                         WriteAlert(_("Error! Document is read-only: "),
1452                                    fname);
1453                 return false;
1454         }
1455
1456         FileInfo finfo(fname);
1457         if (finfo.exist() && !finfo.writable()) {
1458                 // Here we should come with a question if we should
1459                 // try to do the save anyway. (i.e. do a chmod first)
1460                 if (flag)
1461                         lyxerr << _("Error! Cannot write file: ")
1462                                << fname << endl;
1463                 else
1464                         WriteFSAlert(_("Error! Cannot write file: "),
1465                                      fname);
1466                 return false;
1467         }
1468
1469         ofstream ofs(fname.c_str());
1470         if (!ofs) {
1471                 if (flag)
1472                         lyxerr << _("Error! Cannot open file: ")
1473                                << fname << endl;
1474                 else
1475                         WriteFSAlert(_("Error! Cannot open file: "),
1476                                      fname);
1477                 return false;
1478         }
1479
1480 #ifdef HAVE_LOCALE
1481         // Use the standard "C" locale for file output.
1482         ofs.imbue(std::locale::classic());
1483 #endif
1484
1485         // The top of the file should not be written by params.
1486
1487         // write out a comment in the top of the file
1488         ofs << '#' << LYX_DOCVERSION 
1489             << " created this file. For more info see http://www.lyx.org/\n"
1490             << "\\lyxformat " << LYX_FORMAT << "\n";
1491
1492         // now write out the buffer paramters.
1493         params.writeFile(ofs);
1494
1495         char footnoteflag = 0;
1496         char depth = 0;
1497
1498         // this will write out all the paragraphs
1499         // using recursive descent.
1500         paragraph->writeFile(this, ofs, params, footnoteflag, depth);
1501
1502         // Write marker that shows file is complete
1503         ofs << "\n\\the_end" << endl;
1504
1505         ofs.close();
1506
1507         // how to check if close went ok?
1508         // Following is an attempt... (BE 20001011)
1509         
1510         // good() returns false if any error occured, including some
1511         //        formatting error.
1512         // bad()  returns true if something bad happened in the buffer,
1513         //        which should include file system full errors.
1514
1515         bool status = true;
1516         if (!ofs.good()) {
1517                 status = false;
1518 #if 0
1519                 if (ofs.bad()) {
1520                         lyxerr << "Buffer::writeFile: BAD ERROR!" << endl;
1521                 } else {
1522                         lyxerr << "Buffer::writeFile: NOT SO BAD ERROR!"
1523                                << endl;
1524                 }
1525 #endif
1526         }
1527         
1528         return status;
1529 }
1530
1531
1532 string const Buffer::asciiParagraph(LyXParagraph const * par,
1533                                     unsigned int linelen) const
1534 {
1535         ostringstream buffer;
1536         LyXFont font1;
1537         LyXFont font2;
1538         Inset const * inset;
1539         char c;
1540 #ifndef NEW_INSETS
1541         LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
1542 #endif
1543         char depth = 0;
1544         int ltype = 0;
1545         int ltype_depth = 0;
1546         unsigned int currlinelen = 0;
1547         bool ref_printed = false;
1548
1549         int noparbreak = 0;
1550         int islatex = 0;
1551 #ifndef NEW_INSETS
1552         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE ||
1553             !par->previous_
1554             || par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE) {
1555                 /* begins a footnote environment ? */ 
1556                 if (footnoteflag != par->footnoteflag) {
1557                         footnoteflag = par->footnoteflag;
1558                         if (footnoteflag) {
1559                                 size_t const j = strlen(string_footnotekinds[par->footnotekind]) + 4;
1560                                 if ((linelen > 0) &&
1561                                     ((currlinelen + j) > linelen)) {
1562                                         buffer << "\n";
1563                                         currlinelen = 0;
1564                                 }
1565                                 buffer << "(["
1566                                        << string_footnotekinds[par->footnotekind]
1567                                        << "] ";
1568                                 currlinelen += j;
1569                         }
1570                 }
1571 #else
1572                 if (!par->previous()) {
1573 #endif
1574                 /* begins or ends a deeper area ?*/ 
1575                 if (depth != par->params.depth()) {
1576                         if (par->params.depth() > depth) {
1577                                 while (par->params.depth() > depth) {
1578                                         ++depth;
1579                                 }
1580                         } else {
1581                                 while (par->params.depth() < depth) {
1582                                         --depth;
1583                                 }
1584                         }
1585                 }
1586                 
1587                 /* First write the layout */
1588                 string const tmp = textclasslist.NameOfLayout(params.textclass, par->layout);
1589                 if (tmp == "Itemize") {
1590                         ltype = 1;
1591                         ltype_depth = depth + 1;
1592                 } else if (tmp == "Enumerate") {
1593                         ltype = 2;
1594                         ltype_depth = depth + 1;
1595                 } else if (strstr(tmp.c_str(), "ection")) {
1596                         ltype = 3;
1597                         ltype_depth = depth + 1;
1598                 } else if (strstr(tmp.c_str(), "aragraph")) {
1599                         ltype = 4;
1600                         ltype_depth = depth + 1;
1601                 } else if (tmp == "Description") {
1602                         ltype = 5;
1603                         ltype_depth = depth + 1;
1604                 } else if (tmp == "Abstract") {
1605                         ltype = 6;
1606                         ltype_depth = 0;
1607                 } else if (tmp == "Bibliography") {
1608                         ltype = 7;
1609                         ltype_depth = 0;
1610                 } else {
1611                         ltype = 0;
1612                         ltype_depth = 0;
1613                 }
1614                 
1615                 /* maybe some vertical spaces */ 
1616                 
1617                 /* the labelwidthstring used in lists */ 
1618                 
1619                 /* some lines? */ 
1620                 
1621                 /* some pagebreaks? */ 
1622                 
1623                 /* noindent ? */ 
1624                 
1625                 /* what about the alignment */ 
1626         } else {
1627 #ifndef NEW_INSETS
1628                 /* dummy layout, that means a footnote ended */ 
1629                 footnoteflag = LyXParagraph::NO_FOOTNOTE;
1630                 buffer << ") ";
1631                 noparbreak = 1;
1632 #else
1633                 lyxerr << "Should this ever happen?" << endl;
1634 #endif
1635         }
1636       
1637         font1 = LyXFont(LyXFont::ALL_INHERIT, params.language);
1638         for (LyXParagraph::size_type i = 0; i < par->size(); ++i) {
1639                 if (!i &&
1640 #ifndef NEW_INSETS
1641                     !footnoteflag &&
1642 #endif
1643                     !noparbreak) {
1644                         if (linelen > 0)
1645                                 buffer << "\n\n";
1646                         for (char j = 0; j < depth; ++j)
1647                                 buffer << "  ";
1648                         currlinelen = depth * 2;
1649                         switch (ltype) {
1650                         case 0: /* Standard */
1651                         case 4: /* (Sub)Paragraph */
1652                         case 5: /* Description */
1653                                 break;
1654                         case 6: /* Abstract */
1655                                 if (linelen > 0)
1656                                         buffer << "Abstract\n\n";
1657                                 else
1658                                         buffer << "Abstract: ";
1659                                 break;
1660                         case 7: /* Bibliography */
1661                                 if (!ref_printed) {
1662                                         if (linelen > 0)
1663                                                 buffer << "References\n\n";
1664                                         else
1665                                                 buffer << "References: ";
1666                                         ref_printed = true;
1667                                 }
1668                                 break;
1669                         default:
1670                                 buffer << par->params.labelString() << " ";
1671                                 break;
1672                         }
1673                         if (ltype_depth > depth) {
1674                                 for (char j = ltype_depth - 1; j > depth; --j)
1675                                         buffer << "  ";
1676                                 currlinelen += (ltype_depth-depth)*2;
1677                         }
1678                 }
1679                 font2 = par->GetFontSettings(params, i);
1680                 if (font1.latex() != font2.latex()) {
1681                         if (font2.latex() == LyXFont::OFF)
1682                                 islatex = 0;
1683                         else
1684                                 islatex = 1;
1685                 } else {
1686                         islatex = 0;
1687                 }
1688                 c = par->GetUChar(params, i);
1689                 if (islatex)
1690                         continue;
1691                 switch (c) {
1692                 case LyXParagraph::META_INSET:
1693                         if ((inset = par->GetInset(i))) {
1694                                 if (!inset->Ascii(this, buffer)) {
1695                                         string dummy;
1696                                         string s = rsplit(buffer.str().c_str(),
1697                                                           dummy, '\n');
1698                                         currlinelen += s.length();
1699                                 } else {
1700                                         // to be sure it breaks paragraph
1701                                         currlinelen += linelen;
1702                                 }
1703                         }
1704                         break;
1705                 case LyXParagraph::META_NEWLINE:
1706                         if (linelen > 0) {
1707                                 buffer << "\n";
1708                                 for (char j = 0; j < depth; ++j)
1709                                         buffer << "  ";
1710                         }
1711                         currlinelen = depth * 2;
1712                         if (ltype_depth > depth) {
1713                                 for (char j = ltype_depth;
1714                                     j > depth; --j)
1715                                         buffer << "  ";
1716                                 currlinelen += (ltype_depth - depth) * 2;
1717                         }
1718                         break;
1719                 case LyXParagraph::META_HFILL: 
1720                         buffer << "\t";
1721                         break;
1722                 case '\\':
1723                         buffer << "\\";
1724                         break;
1725                 default:
1726                         if ((linelen > 0) && (currlinelen > (linelen - 10)) &&
1727                             (c == ' ') && ((i + 2) < par->size()))
1728                         {
1729                                 buffer << "\n";
1730                                 for (char j = 0; j < depth; ++j)
1731                                         buffer << "  ";
1732                                 currlinelen = depth * 2;
1733                                 if (ltype_depth > depth) {
1734                                         for (char j = ltype_depth;
1735                                             j > depth; --j)
1736                                                 buffer << "  ";
1737                                         currlinelen += (ltype_depth-depth)*2;
1738                                 }
1739                         } else if (c != '\0')
1740                                 buffer << c;
1741                         else if (c == '\0')
1742                                 lyxerr.debug() << "writeAsciiFile: NULL char in structure." << endl;
1743                         ++currlinelen;
1744                         break;
1745                 }
1746         }
1747         return buffer.str().c_str();
1748 }
1749
1750
1751 void Buffer::writeFileAscii(string const & fname, int linelen) 
1752 {
1753         ofstream ofs(fname.c_str());
1754         if (!ofs) {
1755                 WriteFSAlert(_("Error: Cannot write file:"), fname);
1756                 return;
1757         }
1758         writeFileAscii(ofs, linelen);
1759 }
1760
1761
1762 void Buffer::writeFileAscii(ostream & ofs, int linelen) 
1763 {
1764         LyXParagraph * par = paragraph;
1765         while (par) {
1766                 ofs << asciiParagraph(par, linelen);
1767                 par = par->next();
1768         }
1769         ofs << "\n";
1770 }
1771
1772 bool use_babel;
1773
1774 void Buffer::makeLaTeXFile(string const & fname, 
1775                            string const & original_path,
1776                            bool nice, bool only_body)
1777 {
1778         lyxerr[Debug::LATEX] << "makeLaTeXFile..." << endl;
1779         
1780         niceFile = nice; // this will be used by Insetincludes.
1781
1782         tex_code_break_column = lyxrc.ascii_linelen;
1783
1784         LyXTextClass const & tclass =
1785                 textclasslist.TextClass(params.textclass);
1786
1787         ofstream ofs(fname.c_str());
1788         if (!ofs) {
1789                 WriteFSAlert(_("Error: Cannot open file: "), fname);
1790                 return;
1791         }
1792         
1793         // validate the buffer.
1794         lyxerr[Debug::LATEX] << "  Validating buffer..." << endl;
1795         LaTeXFeatures features(params, tclass.numLayouts());
1796         validate(features);
1797         lyxerr[Debug::LATEX] << "  Buffer validation done." << endl;
1798         
1799         texrow.reset();
1800         // The starting paragraph of the coming rows is the 
1801         // first paragraph of the document. (Asger)
1802         texrow.start(paragraph, 0);
1803
1804         if (!only_body && nice) {
1805                 ofs << "%% " LYX_DOCVERSION " created this file.  "
1806                         "For more info, see http://www.lyx.org/.\n"
1807                         "%% Do not edit unless you really know what "
1808                         "you are doing.\n";
1809                 texrow.newline();
1810                 texrow.newline();
1811         }
1812         lyxerr.debug() << "lyx header finished" << endl;
1813         // There are a few differences between nice LaTeX and usual files:
1814         // usual is \batchmode and has a 
1815         // special input@path to allow the including of figures
1816         // with either \input or \includegraphics (what figinsets do).
1817         // batchmode is not set if there is a tex_code_break_column.
1818         // In this case somebody is interested in the generated LaTeX,
1819         // so this is OK. input@path is set when the actual parameter
1820         // original_path is set. This is done for usual tex-file, but not
1821         // for nice-latex-file. (Matthias 250696)
1822         if (!only_body) {
1823                 if (!nice){
1824                         // code for usual, NOT nice-latex-file
1825                         ofs << "\\batchmode\n"; // changed
1826                         // from \nonstopmode
1827                         texrow.newline();
1828                 }
1829                 if (!original_path.empty()) {
1830                         ofs << "\\makeatletter\n"
1831                             << "\\def\\input@path{{"
1832                             << original_path << "/}}\n"
1833                             << "\\makeatother\n";
1834                         texrow.newline();
1835                         texrow.newline();
1836                         texrow.newline();
1837                 }
1838                 
1839                 ofs << "\\documentclass";
1840                 
1841                 string options; // the document class options.
1842                 
1843                 if (tokenPos(tclass.opt_fontsize(),
1844                              '|', params.fontsize) >= 0) {
1845                         // only write if existing in list (and not default)
1846                         options += params.fontsize;
1847                         options += "pt,";
1848                 }
1849                 
1850                 
1851                 if (!params.use_geometry &&
1852                     (params.paperpackage == BufferParams::PACKAGE_NONE)) {
1853                         switch (params.papersize) {
1854                         case BufferParams::PAPER_A4PAPER:
1855                                 options += "a4paper,";
1856                                 break;
1857                         case BufferParams::PAPER_USLETTER:
1858                                 options += "letterpaper,";
1859                                 break;
1860                         case BufferParams::PAPER_A5PAPER:
1861                                 options += "a5paper,";
1862                                 break;
1863                         case BufferParams::PAPER_B5PAPER:
1864                                 options += "b5paper,";
1865                                 break;
1866                         case BufferParams::PAPER_EXECUTIVEPAPER:
1867                                 options += "executivepaper,";
1868                                 break;
1869                         case BufferParams::PAPER_LEGALPAPER:
1870                                 options += "legalpaper,";
1871                                 break;
1872                         }
1873                 }
1874
1875                 // if needed
1876                 if (params.sides != tclass.sides()) {
1877                         switch (params.sides) {
1878                         case LyXTextClass::OneSide:
1879                                 options += "oneside,";
1880                                 break;
1881                         case LyXTextClass::TwoSides:
1882                                 options += "twoside,";
1883                                 break;
1884                         }
1885
1886                 }
1887
1888                 // if needed
1889                 if (params.columns != tclass.columns()) {
1890                         if (params.columns == 2)
1891                                 options += "twocolumn,";
1892                         else
1893                                 options += "onecolumn,";
1894                 }
1895
1896                 if (!params.use_geometry 
1897                     && params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
1898                         options += "landscape,";
1899                 
1900                 // language should be a parameter to \documentclass
1901                 use_babel = false;
1902                 string language_options;
1903                 if (params.language->babel() == "hebrew"
1904                     && default_language->babel() != "hebrew")
1905                          // This seems necessary
1906                         features.UsedLanguages.insert(default_language);
1907
1908                 if (lyxrc.language_use_babel ||
1909                     params.language->lang() != lyxrc.default_language ||
1910                     !features.UsedLanguages.empty()) {
1911                         use_babel = true;
1912                         for (LaTeXFeatures::LanguageList::const_iterator cit =
1913                                      features.UsedLanguages.begin();
1914                              cit != features.UsedLanguages.end(); ++cit)
1915                                 language_options += (*cit)->babel() + ',';
1916                         language_options += params.language->babel();
1917                         if (lyxrc.language_global_options)
1918                                 options += language_options + ',';
1919                 }
1920
1921                 // the user-defined options
1922                 if (!params.options.empty()) {
1923                         options += params.options + ',';
1924                 }
1925                 
1926                 if (!options.empty()){
1927                         options = strip(options, ',');
1928                         ofs << '[' << options << ']';
1929                 }
1930                 
1931                 ofs << '{'
1932                     << textclasslist.LatexnameOfClass(params.textclass)
1933                     << "}\n";
1934                 texrow.newline();
1935                 // end of \documentclass defs
1936                 
1937                 // font selection must be done before loading fontenc.sty
1938                 // The ae package is not needed when using OT1 font encoding.
1939                 if (params.fonts != "default" &&
1940                     (params.fonts != "ae" || lyxrc.fontenc != "default")) {
1941                         ofs << "\\usepackage{" << params.fonts << "}\n";
1942                         texrow.newline();
1943                         if (params.fonts == "ae") {
1944                                 ofs << "\\usepackage{aecompl}\n";
1945                                 texrow.newline();
1946                         }
1947                 }
1948                 // this one is not per buffer
1949                 if (lyxrc.fontenc != "default") {
1950                         ofs << "\\usepackage[" << lyxrc.fontenc
1951                             << "]{fontenc}\n";
1952                         texrow.newline();
1953                 }
1954
1955                 if (params.inputenc == "auto") {
1956                         string const doc_encoding =
1957                                 params.language->encoding()->LatexName();
1958
1959                         // Create a list with all the input encodings used 
1960                         // in the document
1961                         set<string> encodings;
1962                         for (LaTeXFeatures::LanguageList::const_iterator it =
1963                                      features.UsedLanguages.begin();
1964                              it != features.UsedLanguages.end(); ++it)
1965                                 if ((*it)->encoding()->LatexName() != doc_encoding)
1966                                         encodings.insert((*it)->encoding()->LatexName());
1967
1968                         ofs << "\\usepackage[";
1969                         std::copy(encodings.begin(), encodings.end(),
1970                                   std::ostream_iterator<string>(ofs, ","));
1971                         ofs << doc_encoding << "]{inputenc}\n";
1972                         texrow.newline();
1973                 } else if (params.inputenc != "default") {
1974                         ofs << "\\usepackage[" << params.inputenc
1975                             << "]{inputenc}\n";
1976                         texrow.newline();
1977                 }
1978
1979                 // At the very beginning the text parameters.
1980                 if (params.paperpackage != BufferParams::PACKAGE_NONE) {
1981                         switch (params.paperpackage) {
1982                         case BufferParams::PACKAGE_A4:
1983                                 ofs << "\\usepackage{a4}\n";
1984                                 texrow.newline();
1985                                 break;
1986                         case BufferParams::PACKAGE_A4WIDE:
1987                                 ofs << "\\usepackage{a4wide}\n";
1988                                 texrow.newline();
1989                                 break;
1990                         case BufferParams::PACKAGE_WIDEMARGINSA4:
1991                                 ofs << "\\usepackage[widemargins]{a4}\n";
1992                                 texrow.newline();
1993                                 break;
1994                         }
1995                 }
1996                 if (params.use_geometry) {
1997                         ofs << "\\usepackage{geometry}\n";
1998                         texrow.newline();
1999                         ofs << "\\geometry{verbose";
2000                         if (params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
2001                                 ofs << ",landscape";
2002                         switch (params.papersize2) {
2003                         case BufferParams::VM_PAPER_CUSTOM:
2004                                 if (!params.paperwidth.empty())
2005                                         ofs << ",paperwidth="
2006                                             << params.paperwidth;
2007                                 if (!params.paperheight.empty())
2008                                         ofs << ",paperheight="
2009                                             << params.paperheight;
2010                                 break;
2011                         case BufferParams::VM_PAPER_USLETTER:
2012                                 ofs << ",letterpaper";
2013                                 break;
2014                         case BufferParams::VM_PAPER_USLEGAL:
2015                                 ofs << ",legalpaper";
2016                                 break;
2017                         case BufferParams::VM_PAPER_USEXECUTIVE:
2018                                 ofs << ",executivepaper";
2019                                 break;
2020                         case BufferParams::VM_PAPER_A3:
2021                                 ofs << ",a3paper";
2022                                 break;
2023                         case BufferParams::VM_PAPER_A4:
2024                                 ofs << ",a4paper";
2025                                 break;
2026                         case BufferParams::VM_PAPER_A5:
2027                                 ofs << ",a5paper";
2028                                 break;
2029                         case BufferParams::VM_PAPER_B3:
2030                                 ofs << ",b3paper";
2031                                 break;
2032                         case BufferParams::VM_PAPER_B4:
2033                                 ofs << ",b4paper";
2034                                 break;
2035                         case BufferParams::VM_PAPER_B5:
2036                                 ofs << ",b5paper";
2037                                 break;
2038                         default:
2039                                 // default papersize ie BufferParams::VM_PAPER_DEFAULT
2040                                 switch (lyxrc.default_papersize) {
2041                                 case BufferParams::PAPER_DEFAULT: // keep compiler happy
2042                                 case BufferParams::PAPER_USLETTER:
2043                                         ofs << ",letterpaper";
2044                                         break;
2045                                 case BufferParams::PAPER_LEGALPAPER:
2046                                         ofs << ",legalpaper";
2047                                         break;
2048                                 case BufferParams::PAPER_EXECUTIVEPAPER:
2049                                         ofs << ",executivepaper";
2050                                         break;
2051                                 case BufferParams::PAPER_A3PAPER:
2052                                         ofs << ",a3paper";
2053                                         break;
2054                                 case BufferParams::PAPER_A4PAPER:
2055                                         ofs << ",a4paper";
2056                                         break;
2057                                 case BufferParams::PAPER_A5PAPER:
2058                                         ofs << ",a5paper";
2059                                         break;
2060                                 case BufferParams::PAPER_B5PAPER:
2061                                         ofs << ",b5paper";
2062                                         break;
2063                                 }
2064                         }
2065                         if (!params.topmargin.empty())
2066                                 ofs << ",tmargin=" << params.topmargin;
2067                         if (!params.bottommargin.empty())
2068                                 ofs << ",bmargin=" << params.bottommargin;
2069                         if (!params.leftmargin.empty())
2070                                 ofs << ",lmargin=" << params.leftmargin;
2071                         if (!params.rightmargin.empty())
2072                                 ofs << ",rmargin=" << params.rightmargin;
2073                         if (!params.headheight.empty())
2074                                 ofs << ",headheight=" << params.headheight;
2075                         if (!params.headsep.empty())
2076                                 ofs << ",headsep=" << params.headsep;
2077                         if (!params.footskip.empty())
2078                                 ofs << ",footskip=" << params.footskip;
2079                         ofs << "}\n";
2080                         texrow.newline();
2081                 }
2082                 if (features.amsstyle
2083                     && !tclass.provides(LyXTextClass::amsmath)) {
2084                         ofs << "\\usepackage{amsmath}\n";
2085                         texrow.newline();
2086                 }
2087
2088                 if (tokenPos(tclass.opt_pagestyle(),
2089                              '|', params.pagestyle) >= 0) {
2090                         if (params.pagestyle == "fancy") {
2091                                 ofs << "\\usepackage{fancyhdr}\n";
2092                                 texrow.newline();
2093                         }
2094                         ofs << "\\pagestyle{" << params.pagestyle << "}\n";
2095                         texrow.newline();
2096                 }
2097
2098                 // We try to load babel late, in case it interferes
2099                 // with other packages.
2100                 if (use_babel) {
2101                         string tmp = lyxrc.language_package;
2102                         if (!lyxrc.language_global_options
2103                             && tmp == "\\usepackage{babel}")
2104                                 tmp = "\\usepackage[" +
2105                                         language_options + "]{babel}";
2106                         ofs << tmp << "\n";
2107                         texrow.newline();
2108                 }
2109
2110                 if (params.secnumdepth != tclass.secnumdepth()) {
2111                         ofs << "\\setcounter{secnumdepth}{"
2112                             << params.secnumdepth
2113                             << "}\n";
2114                         texrow.newline();
2115                 }
2116                 if (params.tocdepth != tclass.tocdepth()) {
2117                         ofs << "\\setcounter{tocdepth}{"
2118                             << params.tocdepth
2119                             << "}\n";
2120                         texrow.newline();
2121                 }
2122                 
2123                 if (params.paragraph_separation) {
2124                         switch (params.defskip.kind()) {
2125                         case VSpace::SMALLSKIP: 
2126                                 ofs << "\\setlength\\parskip{\\smallskipamount}\n";
2127                                 break;
2128                         case VSpace::MEDSKIP:
2129                                 ofs << "\\setlength\\parskip{\\medskipamount}\n";
2130                                 break;
2131                         case VSpace::BIGSKIP:
2132                                 ofs << "\\setlength\\parskip{\\bigskipamount}\n";
2133                                 break;
2134                         case VSpace::LENGTH:
2135                                 ofs << "\\setlength\\parskip{"
2136                                     << params.defskip.length().asLatexString()
2137                                     << "}\n";
2138                                 break;
2139                         default: // should never happen // Then delete it.
2140                                 ofs << "\\setlength\\parskip{\\medskipamount}\n";
2141                                 break;
2142                         }
2143                         texrow.newline();
2144                         
2145                         ofs << "\\setlength\\parindent{0pt}\n";
2146                         texrow.newline();
2147                 }
2148
2149                 // Now insert the LyX specific LaTeX commands...
2150
2151                 // The optional packages;
2152                 string preamble(features.getPackages());
2153
2154                 // this might be useful...
2155                 preamble += "\n\\makeatletter\n";
2156
2157                 // Some macros LyX will need
2158                 string tmppreamble(features.getMacros());
2159
2160                 if (!tmppreamble.empty()) {
2161                         preamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2162                                 "LyX specific LaTeX commands.\n"
2163                                 + tmppreamble + '\n';
2164                 }
2165
2166                 // the text class specific preamble 
2167                 tmppreamble = features.getTClassPreamble();
2168                 if (!tmppreamble.empty()) {
2169                         preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2170                                 "Textclass specific LaTeX commands.\n"
2171                                 + tmppreamble + '\n';
2172                 }
2173
2174                 /* the user-defined preamble */
2175                 if (!params.preamble.empty()) {
2176                         preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2177                                 "User specified LaTeX commands.\n"
2178                                 + params.preamble + '\n';
2179                 }
2180
2181                 preamble += "\\makeatother\n";
2182
2183                 // Itemize bullet settings need to be last in case the user
2184                 // defines their own bullets that use a package included
2185                 // in the user-defined preamble -- ARRae
2186                 // Actually it has to be done much later than that
2187                 // since some packages like frenchb make modifications
2188                 // at \begin{document} time -- JMarc 
2189                 string bullets_def;
2190                 for (int i = 0; i < 4; ++i) {
2191                         if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
2192                                 if (bullets_def.empty())
2193                                         bullets_def="\\AtBeginDocument{\n";
2194                                 bullets_def += "  \\renewcommand{\\labelitemi";
2195                                 switch (i) {
2196                                 // `i' is one less than the item to modify
2197                                 case 0:
2198                                         break;
2199                                 case 1:
2200                                         bullets_def += 'i';
2201                                         break;
2202                                 case 2:
2203                                         bullets_def += "ii";
2204                                         break;
2205                                 case 3:
2206                                         bullets_def += 'v';
2207                                         break;
2208                                 }
2209                                 bullets_def += "}{" + 
2210                                   params.user_defined_bullets[i].getText() 
2211                                   + "}\n";
2212                         }
2213                 }
2214
2215                 if (!bullets_def.empty())
2216                   preamble += bullets_def + "}\n\n";
2217
2218                 for (int j = countChar(preamble, '\n'); j-- ;) {
2219                         texrow.newline();
2220                 }
2221
2222                 ofs << preamble;
2223
2224                 // make the body.
2225                 ofs << "\\begin{document}\n";
2226                 texrow.newline();
2227         } // only_body
2228         lyxerr.debug() << "preamble finished, now the body." << endl;
2229
2230         if (!lyxrc.language_auto_begin) {
2231                 ofs << subst(lyxrc.language_command_begin, "$$lang",
2232                              params.language->babel())
2233                     << endl;
2234                 texrow.newline();
2235         }
2236         
2237         latexParagraphs(ofs, paragraph, 0, texrow);
2238
2239         // add this just in case after all the paragraphs
2240         ofs << endl;
2241         texrow.newline();
2242
2243         if (!lyxrc.language_auto_end) {
2244                 ofs << subst(lyxrc.language_command_end, "$$lang",
2245                              params.language->babel())
2246                     << endl;
2247                 texrow.newline();
2248         }
2249
2250         if (!only_body) {
2251                 ofs << "\\end{document}\n";
2252                 texrow.newline();
2253         
2254                 lyxerr[Debug::LATEX] << "makeLaTeXFile...done" << endl;
2255         } else {
2256                 lyxerr[Debug::LATEX] << "LaTeXFile for inclusion made."
2257                                      << endl;
2258         }
2259
2260         // Just to be sure. (Asger)
2261         texrow.newline();
2262
2263         // tex_code_break_column's value is used to decide
2264         // if we are in batchmode or not (within mathed_write()
2265         // in math_write.C) so we must set it to a non-zero
2266         // value when we leave otherwise we save incorrect .lyx files.
2267         tex_code_break_column = lyxrc.ascii_linelen;
2268
2269         ofs.close();
2270         if (ofs.fail()) {
2271                 lyxerr << "File was not closed properly." << endl;
2272         }
2273         
2274         lyxerr.debug() << "Finished making latex file." << endl;
2275 }
2276
2277
2278 //
2279 // LaTeX all paragraphs from par to endpar, if endpar == 0 then to the end
2280 //
2281 void Buffer::latexParagraphs(ostream & ofs, LyXParagraph * par,
2282                              LyXParagraph * endpar, TexRow & texrow) const
2283 {
2284         bool was_title = false;
2285         bool already_title = false;
2286         std::ostringstream ftnote;
2287         TexRow ft_texrow;
2288         int ftcount = 0;
2289
2290         // if only_body
2291         while (par != endpar) {
2292 #ifndef NEW_INSETS
2293                 if (par->IsDummy())
2294                         lyxerr[Debug::LATEX] << "Error in latexParagraphs."
2295                                              << endl;
2296 #endif
2297                 LyXLayout const & layout =
2298                         textclasslist.Style(params.textclass,
2299                                             par->layout);
2300             
2301                 if (layout.intitle) {
2302                         if (already_title) {
2303                                 lyxerr <<"Error in latexParagraphs: You"
2304                                         " should not mix title layouts"
2305                                         " with normal ones." << endl;
2306                         } else
2307                                 was_title = true;
2308                 } else if (was_title && !already_title) {
2309                         ofs << "\\maketitle\n";
2310                         texrow.newline();
2311                         already_title = true;
2312                         was_title = false;                  
2313                 }
2314                 // We are at depth 0 so we can just use
2315                 // ordinary \footnote{} generation
2316                 // flag this with ftcount
2317                 ftcount = -1;
2318                 if (layout.isEnvironment()
2319 #ifndef NEW_INSETS
2320                     || par->params.pextraType() != LyXParagraph::PEXTRA_NONE
2321 #endif
2322                         ) {
2323                         par = par->TeXEnvironment(this, params, ofs, texrow
2324 #ifndef NEW_INSETS
2325                                                   ,ftnote, ft_texrow, ftcount
2326 #endif
2327                                 );
2328                 } else {
2329                         par = par->TeXOnePar(this, params, ofs, texrow, false
2330 #ifndef NEW_INSETS
2331                                              ,
2332                                              ftnote, ft_texrow, ftcount
2333 #endif
2334                                 );
2335                 }
2336
2337                 // Write out what we've generated...
2338                 if (ftcount >= 1) {
2339                         if (ftcount > 1) {
2340                                 ofs << "\\addtocounter{footnote}{-"
2341                                     << ftcount - 1
2342                                     << '}';
2343                         }
2344                         ofs << ftnote.str();
2345                         texrow += ft_texrow;
2346
2347                         // The extra .c_str() is needed when we use
2348                         // lyxstring instead of the STL string class. 
2349                         ftnote.str(string().c_str());
2350                         ft_texrow.reset();
2351                         ftcount = 0;
2352                 }
2353         }
2354         // It might be that we only have a title in this document
2355         if (was_title && !already_title) {
2356                 ofs << "\\maketitle\n";
2357                 texrow.newline();
2358         }
2359 }
2360
2361
2362 bool Buffer::isLatex() const
2363 {
2364         return textclasslist.TextClass(params.textclass).outputType() == LATEX;
2365 }
2366
2367
2368 bool Buffer::isLinuxDoc() const
2369 {
2370         return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC;
2371 }
2372
2373
2374 bool Buffer::isLiterate() const
2375 {
2376         return textclasslist.TextClass(params.textclass).outputType() == LITERATE;
2377 }
2378
2379
2380 bool Buffer::isDocBook() const
2381 {
2382         return textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2383 }
2384
2385
2386 bool Buffer::isSGML() const
2387 {
2388         return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC ||
2389                textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2390 }
2391
2392
2393 void Buffer::sgmlOpenTag(ostream & os, int depth,
2394                          string const & latexname) const
2395 {
2396         if (latexname != "!-- --")
2397                 os << string(depth, ' ') << "<" << latexname << ">\n";
2398 }
2399
2400
2401 void Buffer::sgmlCloseTag(ostream & os, int depth,
2402                           string const & latexname) const
2403 {
2404         if (latexname != "!-- --")
2405                 os << string(depth, ' ') << "</" << latexname << ">\n";
2406 }
2407
2408
2409 void Buffer::makeLinuxDocFile(string const & fname, bool nice, bool body_only)
2410 {
2411         LyXParagraph * par = paragraph;
2412
2413         niceFile = nice; // this will be used by Insetincludes.
2414
2415         string top_element = textclasslist.LatexnameOfClass(params.textclass);
2416         string environment_stack[10];
2417         string item_name;
2418
2419         int depth = 0; // paragraph depth
2420
2421         ofstream ofs(fname.c_str());
2422
2423         if (!ofs) {
2424                 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2425                 return;
2426         }
2427
2428         LyXTextClass const & tclass =
2429                 textclasslist.TextClass(params.textclass);
2430
2431         LaTeXFeatures features(params, tclass.numLayouts());
2432         validate(features);
2433
2434         //if (nice)
2435         tex_code_break_column = lyxrc.ascii_linelen;
2436         //else
2437         //tex_code_break_column = 0;
2438
2439         texrow.reset();
2440
2441         if (!body_only) {
2442                 string sgml_includedfiles=features.getIncludedFiles(fname);
2443
2444                 if (params.preamble.empty() && sgml_includedfiles.empty()) {
2445                         ofs << "<!doctype linuxdoc system>\n\n";
2446                 } else {
2447                         ofs << "<!doctype linuxdoc system [ "
2448                             << params.preamble << sgml_includedfiles << " \n]>\n\n";
2449                 }
2450
2451                 if (params.options.empty())
2452                         sgmlOpenTag(ofs, 0, top_element);
2453                 else {
2454                         string top = top_element;
2455                         top += " ";
2456                         top += params.options;
2457                         sgmlOpenTag(ofs, 0, top);
2458                 }
2459         }
2460
2461         ofs << "<!-- "  << LYX_DOCVERSION 
2462             << " created this file. For more info see http://www.lyx.org/"
2463             << " -->\n";
2464
2465         while (par) {
2466                 int desc_on = 0; // description mode
2467                 LyXLayout const & style =
2468                         textclasslist.Style(params.textclass,
2469                                             par->layout);
2470
2471                 // treat <toc> as a special case for compatibility with old code
2472                 if (par->GetChar(0) == LyXParagraph::META_INSET) {
2473                         Inset * inset = par->GetInset(0);
2474                         Inset::Code lyx_code = inset->LyxCode();
2475                         if (lyx_code == Inset::TOC_CODE){
2476                                 string const temp = "toc";
2477                                 sgmlOpenTag(ofs, depth, temp);
2478
2479 #ifndef NEW_INSETS
2480                                 par = par->next_;
2481                                 linuxDocHandleFootnote(ofs, par, depth);
2482 #else
2483                                 par = par->next();
2484 #endif
2485                                 continue;
2486                         }
2487                 }
2488
2489                 // environment tag closing
2490                 for (; depth > par->params.depth(); --depth) {
2491                         sgmlCloseTag(ofs, depth, environment_stack[depth]);
2492                         environment_stack[depth].erase();
2493                 }
2494
2495                 // write opening SGML tags
2496                 switch (style.latextype) {
2497                 case LATEX_PARAGRAPH:
2498                         if (depth == par->params.depth() 
2499                            && !environment_stack[depth].empty()) {
2500                                 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2501                                 environment_stack[depth].erase();
2502                                 if (depth) 
2503                                         --depth;
2504                                 else
2505                                         ofs << "</p>";
2506                         }
2507                         sgmlOpenTag(ofs, depth, style.latexname());
2508                         break;
2509
2510                 case LATEX_COMMAND:
2511                         if (depth!= 0)
2512                                 LinuxDocError(par, 0,
2513                                               _("Error : Wrong depth for"
2514                                                 " LatexType Command.\n"));
2515
2516                         if (!environment_stack[depth].empty()){
2517                                 sgmlCloseTag(ofs, depth,
2518                                              environment_stack[depth]);
2519                                 ofs << "</p>";
2520                         }
2521
2522                         environment_stack[depth].erase();
2523                         sgmlOpenTag(ofs, depth, style.latexname());
2524                         break;
2525
2526                 case LATEX_ENVIRONMENT:
2527                 case LATEX_ITEM_ENVIRONMENT:
2528                         if (depth == par->params.depth() 
2529                            && environment_stack[depth] != style.latexname()
2530                            && !environment_stack[depth].empty()) {
2531
2532                                 sgmlCloseTag(ofs, depth,
2533                                              environment_stack[depth]);
2534                                 environment_stack[depth].erase();
2535                         }
2536                         if (depth < par->params.depth()) {
2537                                depth = par->params.depth();
2538                                environment_stack[depth].erase();
2539                         }
2540                         if (environment_stack[depth] != style.latexname()) {
2541                                 if (depth == 0) {
2542                                         string const temp = "p";
2543                                         sgmlOpenTag(ofs, depth, temp);
2544                                 }
2545                                 environment_stack[depth] = style.latexname();
2546                                 sgmlOpenTag(ofs, depth,
2547                                             environment_stack[depth]);
2548                         }
2549                         if (style.latextype == LATEX_ENVIRONMENT) break;
2550
2551                         desc_on = (style.labeltype == LABEL_MANUAL);
2552
2553                         if (desc_on)
2554                                 item_name = "tag";
2555                         else
2556                                 item_name = "item";
2557
2558                         sgmlOpenTag(ofs, depth + 1, item_name);
2559                         break;
2560                 default:
2561                         sgmlOpenTag(ofs, depth, style.latexname());
2562                         break;
2563                 }
2564
2565 #ifndef NEW_INSETS
2566                 do {
2567                         SimpleLinuxDocOnePar(ofs, par, desc_on, depth);
2568                         
2569                         par = par->next_;
2570                         linuxDocHandleFootnote(ofs, par, depth);
2571                 }
2572                 while(par && par->IsDummy());
2573 #else
2574                         SimpleLinuxDocOnePar(ofs, par, desc_on, depth);
2575
2576                         par = par->next();
2577 #endif
2578
2579                 ofs << "\n";
2580                 // write closing SGML tags
2581                 switch (style.latextype) {
2582                 case LATEX_COMMAND:
2583                 case LATEX_ENVIRONMENT:
2584                 case LATEX_ITEM_ENVIRONMENT:
2585                         break;
2586                 default:
2587                         sgmlCloseTag(ofs, depth, style.latexname());
2588                         break;
2589                 }
2590         }
2591    
2592         // Close open tags
2593         for (; depth > 0; --depth)
2594                 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2595
2596         if (!environment_stack[depth].empty())
2597                 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2598
2599         if (!body_only) {
2600                 ofs << "\n\n";
2601                 sgmlCloseTag(ofs, 0, top_element);
2602         }
2603
2604         ofs.close();
2605         // How to check for successful close
2606 }
2607
2608
2609 #ifndef NEW_INSETS
2610 void Buffer::linuxDocHandleFootnote(ostream & os, LyXParagraph * & par,
2611                                     int depth)
2612 {
2613         string const tag = "footnote";
2614
2615         while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2616                 sgmlOpenTag(os, depth + 1, tag);
2617                 SimpleLinuxDocOnePar(os, par, 0, depth + 1);
2618                 sgmlCloseTag(os, depth + 1, tag);
2619                 par = par->next_;
2620         }
2621 }
2622 #endif
2623
2624
2625 void Buffer::DocBookHandleCaption(ostream & os, string & inner_tag,
2626                                   int depth, int desc_on,
2627                                   LyXParagraph * & par)
2628 {
2629         LyXParagraph * tpar = par;
2630 #ifndef NEW_INSETS
2631         while (tpar
2632                && (tpar->footnoteflag != LyXParagraph::NO_FOOTNOTE)
2633                && (tpar->layout != textclasslist.NumberOfLayout(params.textclass,
2634                                                              "Caption").second))
2635                 tpar = tpar->next_;
2636 #else
2637         while (tpar
2638                && (tpar->layout != textclasslist.NumberOfLayout(params.textclass,
2639                                                                 "Caption").second))
2640                 tpar = tpar->next();
2641 #endif
2642         if (tpar &&
2643             tpar->layout == textclasslist.NumberOfLayout(params.textclass,
2644                                                          "Caption").second) {
2645                 sgmlOpenTag(os, depth + 1, inner_tag);
2646                 string extra_par;
2647                 SimpleDocBookOnePar(os, extra_par, tpar,
2648                                     desc_on, depth + 2);
2649                 sgmlCloseTag(os, depth+1, inner_tag);
2650                 if (!extra_par.empty())
2651                         os << extra_par;
2652         }
2653 }
2654
2655
2656 #ifndef NEW_INSETS
2657 void Buffer::DocBookHandleFootnote(ostream & os, LyXParagraph * & par,
2658                                    int depth)
2659 {
2660         string tag, inner_tag;
2661         string tmp_par, extra_par;
2662         bool inner_span = false;
2663         int desc_on = 4;
2664
2665         // Someone should give this enum a proper name (Lgb)
2666         enum SOME_ENUM {
2667                 NO_ONE,
2668                 FOOTNOTE_LIKE,
2669                 MARGIN_LIKE,
2670                 FIG_LIKE,
2671                 TAB_LIKE
2672         };
2673         SOME_ENUM last = NO_ONE;
2674         SOME_ENUM present = FOOTNOTE_LIKE;
2675
2676         while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2677                 if (last == present) {
2678                         if (inner_span) {
2679                                 if (!tmp_par.empty()) {
2680                                         os << tmp_par;
2681                                         tmp_par.erase();
2682                                         sgmlCloseTag(os, depth + 1, inner_tag);
2683                                         sgmlOpenTag(os, depth + 1, inner_tag);
2684                                 }
2685                         } else {
2686                                 os << "\n";
2687                         }
2688                 } else {
2689                         os << tmp_par;
2690                         if (!inner_tag.empty()) sgmlCloseTag(os, depth + 1,
2691                                                             inner_tag);
2692                         if (!extra_par.empty()) os << extra_par;
2693                         if (!tag.empty()) sgmlCloseTag(os, depth, tag);
2694                         extra_par.erase();
2695
2696                         switch (par->footnotekind) {
2697                         case LyXParagraph::FOOTNOTE:
2698                         case LyXParagraph::ALGORITHM:
2699                                 tag = "footnote";
2700                                 inner_tag = "para";
2701                                 present = FOOTNOTE_LIKE;
2702                                 inner_span = true;
2703                                 break;
2704                         case LyXParagraph::MARGIN:
2705                                 tag = "sidebar";
2706                                 inner_tag = "para";
2707                                 present = MARGIN_LIKE;
2708                                 inner_span = true;
2709                                 break;
2710                         case LyXParagraph::FIG:
2711                         case LyXParagraph::WIDE_FIG:
2712                                 tag = "figure";
2713                                 inner_tag = "title";
2714                                 present = FIG_LIKE;
2715                                 inner_span = false;
2716                                 break;
2717                         case LyXParagraph::TAB:
2718                         case LyXParagraph::WIDE_TAB:
2719                                 tag = "table";
2720                                 inner_tag = "title";
2721                                 present = TAB_LIKE;
2722                                 inner_span = false;
2723                                 break;
2724                         }
2725                         sgmlOpenTag(os, depth, tag);
2726                         if ((present == TAB_LIKE) || (present == FIG_LIKE)) {
2727                                 DocBookHandleCaption(os, inner_tag, depth,
2728                                                      desc_on, par);
2729                                 inner_tag.erase();
2730                         } else {
2731                                 sgmlOpenTag(os, depth + 1, inner_tag);
2732                         }
2733                 }
2734                 // ignore all caption here, we processed them above!!!
2735                 if (par->layout != textclasslist
2736                     .NumberOfLayout(params.textclass,
2737                                     "Caption").second) {
2738                         std::ostringstream ost;
2739                         SimpleDocBookOnePar(ost, extra_par, par,
2740                                             desc_on, depth + 2);
2741                         tmp_par += ost.str().c_str();
2742                 }
2743                 tmp_par = frontStrip(strip(tmp_par));
2744
2745                 last = present;
2746                 par = par->next_;
2747         }
2748         os << tmp_par;
2749         if (!inner_tag.empty()) sgmlCloseTag(os, depth + 1, inner_tag);
2750         if (!extra_par.empty()) os << extra_par;
2751         if (!tag.empty()) sgmlCloseTag(os, depth, tag);
2752 }
2753 #endif
2754
2755
2756 // push a tag in a style stack
2757 void Buffer::push_tag(ostream & os, string const & tag,
2758                       int & pos, char stack[5][3])
2759 {
2760 #ifdef WITH_WARNINGS
2761 #warning Use a real stack! (Lgb)
2762 #endif
2763         // pop all previous tags
2764         for (int j = pos; j >= 0; --j)
2765                 os << "</" << stack[j] << ">";
2766
2767         // add new tag
2768         sprintf(stack[++pos], "%s", tag.c_str());
2769
2770         // push all tags
2771         for (int i = 0; i <= pos; ++i)
2772                 os << "<" << stack[i] << ">";
2773 }
2774
2775
2776 void Buffer::pop_tag(ostream & os, string const & tag,
2777                      int & pos, char stack[5][3])
2778 {
2779 #ifdef WITH_WARNINGS
2780 #warning Use a real stack! (Lgb)
2781 #endif
2782         // Please, Lars, do not remove the global variable. I already
2783         // had to reintroduce it twice! (JMarc)
2784         // but...but... I'll remove it anyway. (well not quite) (Lgb)
2785 #if 0
2786         int j;
2787         
2788         // pop all tags till specified one
2789         for (j = pos; (j >= 0) && tag != stack[j]; --j)
2790                 os << "</" << stack[j] << ">";
2791
2792         // closes the tag
2793         os << "</" << tag << ">";
2794         
2795         // push all tags, but the specified one
2796         for (j = j + 1; j <= pos; ++j) {
2797                 os << "<" << stack[j] << ">";
2798                 strcpy(stack[j - 1], stack[j]);
2799         }
2800         --pos;
2801 #else
2802         // pop all tags till specified one
2803         int j = pos;
2804         for (int j = pos; (j >= 0) && tag != stack[j]; --j)
2805                 os << "</" << stack[j] << ">";
2806
2807         // closes the tag
2808         os << "</" << tag << ">";
2809         
2810         // push all tags, but the specified one
2811         for (int i = j + 1; i <= pos; ++i) {
2812                 os << "<" << stack[i] << ">";
2813                 strcpy(stack[i - 1], stack[i]);
2814         }
2815         --pos;
2816 #endif
2817 }
2818
2819
2820 // Handle internal paragraph parsing -- layout already processed.
2821
2822 // checks, if newcol chars should be put into this line
2823 // writes newline, if necessary.
2824 static
2825 void linux_doc_line_break(ostream & os, string::size_type & colcount,
2826                           string::size_type newcol)
2827 {
2828         colcount += newcol;
2829         if (colcount > lyxrc.ascii_linelen) {
2830                 os << "\n";
2831                 colcount = newcol; // assume write after this call
2832         }
2833 }
2834
2835
2836 void Buffer::SimpleLinuxDocOnePar(ostream & os, LyXParagraph * par,
2837                                   int desc_on, int /*depth*/)
2838 {
2839         LyXFont font1;
2840         char c;
2841         Inset * inset;
2842         LyXParagraph::size_type main_body;
2843         int j;
2844         LyXLayout const & style = textclasslist.Style(params.textclass,
2845                                                       par->GetLayout());
2846
2847         char family_type = 0;               // family font flag 
2848         bool is_bold     = false;           // series font flag 
2849         char shape_type  = 0;               // shape font flag 
2850         bool is_em = false;                 // emphasis (italic) font flag 
2851
2852         int stack_num = -1;          // style stack position
2853         // Can this be rewritten to use a std::stack, please. (Lgb)
2854         char stack[5][3];            // style stack 
2855         string::size_type char_line_count = 5;     // Heuristic choice ;-) 
2856
2857         if (style.labeltype != LABEL_MANUAL)
2858                 main_body = 0;
2859         else
2860                 main_body = par->BeginningOfMainBody();
2861
2862         // gets paragraph main font
2863         if (main_body > 0)
2864                 font1 = style.labelfont;
2865         else
2866                 font1 = style.font;
2867
2868   
2869         // parsing main loop
2870         for (LyXParagraph::size_type i = 0;
2871              i < par->size(); ++i) {
2872
2873                 // handle quote tag
2874                 if (i == main_body
2875 #ifndef NEW_INSETS
2876                     && !par->IsDummy()
2877 #endif
2878                         ) {
2879                         if (main_body > 0)
2880                                 font1 = style.font;
2881                 }
2882
2883                 LyXFont const font2 = par->getFont(params, i);
2884
2885                 if (font1.family() != font2.family()) {
2886                         switch (family_type) {
2887                         case 0:
2888                                 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2889                                         push_tag(os, "tt", stack_num, stack);
2890                                         family_type = 1;
2891                                 }
2892                                 else if (font2.family() == LyXFont::SANS_FAMILY) {
2893                                         push_tag(os, "sf", stack_num, stack);
2894                                         family_type = 2;
2895                                 }
2896                                 break;
2897                         case 1:
2898                                 pop_tag(os, "tt", stack_num, stack);
2899                                 if (font2.family() == LyXFont::SANS_FAMILY) {
2900                                         push_tag(os, "sf", stack_num, stack);
2901                                         family_type = 2;
2902                                 } else {
2903                                         family_type = 0;
2904                                 }
2905                                 break;
2906                         case 2:
2907                                 pop_tag(os, "sf", stack_num, stack);
2908                                 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2909                                         push_tag(os, "tt", stack_num, stack);
2910                                         family_type = 1;
2911                                 } else {
2912                                         family_type = 0;
2913                                 }
2914                         }
2915                 }
2916
2917                 // handle bold face
2918                 if (font1.series() != font2.series()) {
2919                         if (font2.series() == LyXFont::BOLD_SERIES) {
2920                                 push_tag(os, "bf", stack_num, stack);
2921                                 is_bold = true;
2922                         } else if (is_bold) {
2923                                 pop_tag(os, "bf", stack_num, stack);
2924                                 is_bold = false;
2925                         }
2926                 }
2927
2928                 // handle italic and slanted fonts
2929                 if (font1.shape() != font2.shape()) {
2930                         switch (shape_type) {
2931                         case 0:
2932                                 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2933                                         push_tag(os, "it", stack_num, stack);
2934                                         shape_type = 1;
2935                                 } else if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2936                                         push_tag(os, "sl", stack_num, stack);
2937                                         shape_type = 2;
2938                                 }
2939                                 break;
2940                         case 1:
2941                                 pop_tag(os, "it", stack_num, stack);
2942                                 if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2943                                         push_tag(os, "sl", stack_num, stack);
2944                                         shape_type = 2;
2945                                 } else {
2946                                         shape_type = 0;
2947                                 }
2948                                 break;
2949                         case 2:
2950                                 pop_tag(os, "sl", stack_num, stack);
2951                                 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2952                                         push_tag(os, "it", stack_num, stack);
2953                                         shape_type = 1;
2954                                 } else {
2955                                         shape_type = 0;
2956                                 }
2957                         }
2958                 }
2959                 // handle <em> tag
2960                 if (font1.emph() != font2.emph()) {
2961                         if (font2.emph() == LyXFont::ON) {
2962                                 push_tag(os, "em", stack_num, stack);
2963                                 is_em = true;
2964                         } else if (is_em) {
2965                                 pop_tag(os, "em", stack_num, stack);
2966                                 is_em = false;
2967                         }
2968                 }
2969
2970                 c = par->GetChar(i);
2971
2972                 if (c == LyXParagraph::META_INSET) {
2973                         inset = par->GetInset(i);
2974                         inset->Linuxdoc(this, os);
2975                 }
2976
2977                 if (font2.latex() == LyXFont::ON) {
2978                         // "TeX"-Mode on == > SGML-Mode on.
2979                         if (c != '\0')
2980                                 os << c; // see LaTeX-Generation...
2981                         ++char_line_count;
2982                 } else {
2983                         string sgml_string;
2984                         if (par->linuxDocConvertChar(c, sgml_string)
2985                             && !style.free_spacing) { // in freespacing
2986                                                      // mode, spaces are
2987                                                      // non-breaking characters
2988                                 // char is ' '
2989                                 if (desc_on == 1) {
2990                                         ++char_line_count;
2991                                         linux_doc_line_break(os, char_line_count, 6);
2992                                         os << "</tag>";
2993                                         desc_on = 2;
2994                                 } else  {
2995                                         linux_doc_line_break(os, char_line_count, 1);
2996                                         os << c;
2997                                 }
2998                         } else {
2999                                 os << sgml_string;
3000                                 char_line_count += sgml_string.length();
3001                         }
3002                 }
3003                 font1 = font2;
3004         }
3005
3006         // needed if there is an optional argument but no contents
3007         if (main_body > 0 && main_body == par->size()) {
3008                 font1 = style.font;
3009         }
3010
3011         // pop all defined Styles
3012         for (j = stack_num; j >= 0; --j) {
3013                 linux_doc_line_break(os, 
3014                                      char_line_count, 
3015                                      3 + strlen(stack[j]));
3016                 os << "</" << stack[j] << ">";
3017         }
3018
3019         // resets description flag correctly
3020         switch (desc_on){
3021         case 1:
3022                 // <tag> not closed...
3023                 linux_doc_line_break(os, char_line_count, 6);
3024                 os << "</tag>";
3025                 break;
3026         case 2:
3027                 // fprintf(file, "</p>");
3028                 break;
3029         }
3030 }
3031
3032
3033 // Print an error message.
3034 void Buffer::LinuxDocError(LyXParagraph * par, int pos,
3035                            string const & message) 
3036 {
3037         // insert an error marker in text
3038         InsetError * new_inset = new InsetError(message);
3039         par->InsertInset(pos, new_inset);
3040 }
3041
3042 // This constant defines the maximum number of 
3043 // environment layouts that can be nesteded.
3044 // The same applies for command layouts.
3045 // These values should be more than enough.
3046 //           José Matos (1999/07/22)
3047
3048 enum { MAX_NEST_LEVEL = 25};
3049
3050 void Buffer::makeDocBookFile(string const & fname, bool nice, bool only_body)
3051 {
3052         LyXParagraph * par = paragraph;
3053
3054         niceFile = nice; // this will be used by Insetincludes.
3055
3056         string top_element= textclasslist.LatexnameOfClass(params.textclass);
3057         // Please use a real stack.
3058         string environment_stack[MAX_NEST_LEVEL];
3059         string environment_inner[MAX_NEST_LEVEL];
3060         // Please use a real stack.
3061         string command_stack[MAX_NEST_LEVEL];
3062         bool command_flag= false;
3063         int command_depth= 0, command_base= 0, cmd_depth= 0;
3064
3065         string item_name, command_name;
3066         string c_depth, c_params, tmps;
3067
3068         int depth = 0; // paragraph depth
3069         LyXTextClass const & tclass =
3070                 textclasslist.TextClass(params.textclass);
3071
3072         LaTeXFeatures features(params, tclass.numLayouts());
3073         validate(features);
3074
3075         //if (nice)
3076         tex_code_break_column = lyxrc.ascii_linelen;
3077         //else
3078         //tex_code_break_column = 0;
3079
3080         ofstream ofs(fname.c_str());
3081         if (!ofs) {
3082                 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
3083                 return;
3084         }
3085    
3086         texrow.reset();
3087
3088         if (!only_body) {
3089                 string sgml_includedfiles=features.getIncludedFiles(fname);
3090
3091                 ofs << "<!doctype " << top_element
3092                     << " public \"-//OASIS//DTD DocBook V3.1//EN\"";
3093
3094                 if (params.preamble.empty() && sgml_includedfiles.empty())
3095                         ofs << ">\n\n";
3096                 else
3097                         ofs << "\n [ " << params.preamble 
3098                             << sgml_includedfiles << " \n]>\n\n";
3099         }
3100
3101         string top = top_element;       
3102         top += " lang=\"";
3103         top += params.language->code();
3104         top += "\"";
3105
3106         if (!params.options.empty()) {
3107                 top += " ";
3108                 top += params.options;
3109         }
3110         sgmlOpenTag(ofs, 0, top);
3111
3112         ofs << "<!-- DocBook file was created by " << LYX_DOCVERSION 
3113             << "\n  See http://www.lyx.org/ for more information -->\n";
3114
3115         while (par) {
3116                 int desc_on = 0; // description mode
3117                 LyXLayout const & style =
3118                         textclasslist.Style(params.textclass,
3119                                             par->layout);
3120
3121                 // environment tag closing
3122                 for (; depth > par->params.depth(); --depth) {
3123                         if (environment_inner[depth] != "!-- --") {
3124                                 item_name= "listitem";
3125                                 sgmlCloseTag(ofs, command_depth + depth,
3126                                              item_name);
3127                                 if (environment_inner[depth] == "varlistentry")
3128                                         sgmlCloseTag(ofs, depth+command_depth,
3129                                                      environment_inner[depth]);
3130                         }
3131                         sgmlCloseTag(ofs, depth + command_depth,
3132                                      environment_stack[depth]);
3133                         environment_stack[depth].erase();
3134                         environment_inner[depth].erase();
3135                 }
3136
3137                 if (depth == par->params.depth()
3138                    && environment_stack[depth] != style.latexname()
3139                    && !environment_stack[depth].empty()) {
3140                         if (environment_inner[depth] != "!-- --") {
3141                                 item_name= "listitem";
3142                                 sgmlCloseTag(ofs, command_depth+depth,
3143                                              item_name);
3144                                 if (environment_inner[depth] == "varlistentry")
3145                                         sgmlCloseTag(ofs,
3146                                                      depth + command_depth,
3147                                                      environment_inner[depth]);
3148                         }
3149                         
3150                         sgmlCloseTag(ofs, depth + command_depth,
3151                                      environment_stack[depth]);
3152                         
3153                         environment_stack[depth].erase();
3154                         environment_inner[depth].erase();
3155                 }
3156
3157                 // Write opening SGML tags.
3158                 switch (style.latextype) {
3159                 case LATEX_PARAGRAPH:
3160                         sgmlOpenTag(ofs, depth+command_depth, style.latexname());
3161                         break;
3162
3163                 case LATEX_COMMAND:
3164                         if (depth!= 0)
3165                                 LinuxDocError(par, 0,
3166                                               _("Error : Wrong depth for "
3167                                                 "LatexType Command.\n"));
3168                         
3169                         command_name = style.latexname();
3170                         
3171                         tmps = style.latexparam();
3172                         c_params = split(tmps, c_depth,'|');
3173                         
3174                         cmd_depth= lyx::atoi(c_depth);
3175                         
3176                         if (command_flag) {
3177                                 if (cmd_depth<command_base) {
3178                                         for (int j = command_depth;
3179                                             j >= command_base; --j)
3180                                                 if (!command_stack[j].empty())
3181                                                         sgmlCloseTag(ofs, j, command_stack[j]);
3182                                         command_depth= command_base= cmd_depth;
3183                                 } else if (cmd_depth <= command_depth) {
3184                                         for (int j = command_depth;
3185                                             j >= cmd_depth; --j)
3186
3187                                                 if (!command_stack[j].empty())
3188                                                         sgmlCloseTag(ofs, j, command_stack[j]);
3189                                         command_depth= cmd_depth;
3190                                 } else
3191                                         command_depth= cmd_depth;
3192                         } else {
3193                                 command_depth = command_base = cmd_depth;
3194                                 command_flag = true;
3195                         }
3196                         command_stack[command_depth]= command_name;
3197
3198                         // treat label as a special case for
3199                         // more WYSIWYM handling.
3200                         if (par->GetChar(0) == LyXParagraph::META_INSET) {
3201                                 Inset * inset = par->GetInset(0);
3202                                 Inset::Code lyx_code = inset->LyxCode();
3203                                 if (lyx_code == Inset::LABEL_CODE){
3204                                         command_name += " id=\"";
3205                                         command_name += (static_cast<InsetCommand *>(inset))->getContents();
3206                                         command_name += "\"";
3207                                         desc_on = 3;
3208                                 }
3209                         }
3210
3211                         sgmlOpenTag(ofs, depth + command_depth, command_name);
3212                         if (c_params.empty())
3213                                 item_name = "title";
3214                         else
3215                                 item_name = c_params;
3216                         sgmlOpenTag(ofs, depth + 1 + command_depth, item_name);
3217                         break;
3218
3219                 case LATEX_ENVIRONMENT:
3220                 case LATEX_ITEM_ENVIRONMENT:
3221                         if (depth < par->params.depth()) {
3222                                 depth = par->params.depth();
3223                                 environment_stack[depth].erase();
3224                         }
3225
3226                         if (environment_stack[depth] != style.latexname()) {
3227                                 environment_stack[depth] = style.latexname();
3228                                 environment_inner[depth] = "!-- --";
3229                                 sgmlOpenTag(ofs, depth + command_depth,
3230                                             environment_stack[depth]);
3231                         } else {
3232                                 if (environment_inner[depth] != "!-- --") {
3233                                         item_name= "listitem";
3234                                         sgmlCloseTag(ofs,
3235                                                      command_depth + depth,
3236                                                      item_name);
3237                                         if (environment_inner[depth] == "varlistentry")
3238                                                 sgmlCloseTag(ofs,
3239                                                              depth + command_depth,
3240                                                              environment_inner[depth]);
3241                                 }
3242                         }
3243                         
3244                         if (style.latextype == LATEX_ENVIRONMENT) {
3245                                 if (!style.latexparam().empty()) {
3246                                         if(style.latexparam() == "CDATA")
3247                                                 ofs << "<![ CDATA [";
3248                                         else
3249                                                 sgmlOpenTag(ofs, depth + command_depth,
3250                                                             style.latexparam());
3251                                 }
3252                                 break;
3253                         }
3254
3255                         desc_on = (style.labeltype == LABEL_MANUAL);
3256
3257                         if (desc_on)
3258                                 environment_inner[depth]= "varlistentry";
3259                         else
3260                                 environment_inner[depth]= "listitem";
3261
3262                         sgmlOpenTag(ofs, depth + 1 + command_depth,
3263                                     environment_inner[depth]);
3264
3265                         if (desc_on) {
3266                                 item_name= "term";
3267                                 sgmlOpenTag(ofs, depth + 1 + command_depth,
3268                                             item_name);
3269                         } else {
3270                                 item_name= "para";
3271                                 sgmlOpenTag(ofs, depth + 1 + command_depth,
3272                                             item_name);
3273                         }
3274                         break;
3275                 default:
3276                         sgmlOpenTag(ofs, depth + command_depth,
3277                                     style.latexname());
3278                         break;
3279                 }
3280
3281 #ifndef NEW_INSETS
3282                 do {
3283                         string extra_par;
3284                         SimpleDocBookOnePar(ofs, extra_par, par, desc_on,
3285                                             depth + 1 + command_depth);
3286                         par = par->next_;
3287                         DocBookHandleFootnote(ofs, par,
3288                                               depth + 1 + command_depth);
3289                 } while(par && par->IsDummy());
3290 #else
3291                 string extra_par;
3292                 SimpleDocBookOnePar(ofs, extra_par, par, desc_on,
3293                                     depth + 1 + command_depth);
3294                 par = par->next();
3295 #endif
3296                 string end_tag;
3297                 // write closing SGML tags
3298                 switch (style.latextype) {
3299                 case LATEX_COMMAND:
3300                         if (c_params.empty())
3301                                 end_tag = "title";
3302                         else
3303                                 end_tag = c_params;
3304                         sgmlCloseTag(ofs, depth + command_depth, end_tag);
3305                         break;
3306                 case LATEX_ENVIRONMENT:
3307                         if (!style.latexparam().empty()) {
3308                                 if(style.latexparam() == "CDATA")
3309                                         ofs << "]]>";
3310                                 else
3311                                         sgmlCloseTag(ofs, depth + command_depth,
3312                                                      style.latexparam());
3313                         }
3314                         break;
3315                 case LATEX_ITEM_ENVIRONMENT:
3316                         if (desc_on == 1) break;
3317                         end_tag= "para";
3318                         sgmlCloseTag(ofs, depth + 1 + command_depth, end_tag);
3319                         break;
3320                 case LATEX_PARAGRAPH:
3321                         sgmlCloseTag(ofs, depth + command_depth, style.latexname());
3322                         break;
3323                 default:
3324                         sgmlCloseTag(ofs, depth + command_depth, style.latexname());
3325                         break;
3326                 }
3327         }
3328
3329         // Close open tags
3330         for (; depth >= 0; --depth) {
3331                 if (!environment_stack[depth].empty()) {
3332                         if (environment_inner[depth] != "!-- --") {
3333                                 item_name= "listitem";
3334                                 sgmlCloseTag(ofs, command_depth + depth,
3335                                              item_name);
3336                                if (environment_inner[depth] == "varlistentry")
3337                                        sgmlCloseTag(ofs, depth + command_depth,
3338                                                     environment_inner[depth]);
3339                         }
3340                         
3341                         sgmlCloseTag(ofs, depth + command_depth,
3342                                      environment_stack[depth]);
3343                 }
3344         }
3345         
3346         for (int j = command_depth; j >= command_base; --j)
3347                 if (!command_stack[j].empty())
3348                         sgmlCloseTag(ofs, j, command_stack[j]);
3349
3350         ofs << "\n\n";
3351         sgmlCloseTag(ofs, 0, top_element);
3352
3353         ofs.close();
3354         // How to check for successful close
3355 }
3356
3357
3358 void Buffer::SimpleDocBookOnePar(ostream & os, string & extra,
3359                                  LyXParagraph * par, int & desc_on,
3360                                  int depth) const
3361 {
3362         bool emph_flag = false;
3363
3364         LyXLayout const & style = textclasslist.Style(params.textclass,
3365                                                       par->GetLayout());
3366
3367         LyXParagraph::size_type main_body;
3368         if (style.labeltype != LABEL_MANUAL)
3369                 main_body = 0;
3370         else
3371                 main_body = par->BeginningOfMainBody();
3372
3373         // gets paragraph main font
3374         LyXFont font1 = main_body > 0 ? style.labelfont : style.font;
3375         
3376         int char_line_count = depth;
3377         if (!style.free_spacing)
3378                 for (int j = 0; j < depth; ++j)
3379                         os << ' ';
3380
3381         // parsing main loop
3382         for (LyXParagraph::size_type i = 0;
3383              i < par->size(); ++i) {
3384                 LyXFont font2 = par->getFont(params, i);
3385
3386                 // handle <emphasis> tag
3387                 if (font1.emph() != font2.emph() && i) {
3388                         if (font2.emph() == LyXFont::ON) {
3389                                 os << "<emphasis>";
3390                                 emph_flag = true;
3391                         }else {
3392                                 os << "</emphasis>";
3393                                 emph_flag = false;
3394                         }
3395                 }
3396       
3397                 char c = par->GetChar(i);
3398
3399                 if (c == LyXParagraph::META_INSET) {
3400                         Inset * inset = par->GetInset(i);
3401                         std::ostringstream ost;
3402                         inset->DocBook(this, ost);
3403                         string tmp_out = ost.str().c_str();
3404
3405                         //
3406                         // This code needs some explanation:
3407                         // Two insets are treated specially
3408                         //   label if it is the first element in a command paragraph
3409                         //         desc_on == 3
3410                         //   graphics inside tables or figure floats can't go on
3411                         //   title (the equivalente in latex for this case is caption
3412                         //   and title should come first
3413                         //         desc_on == 4
3414                         //
3415                         if (desc_on!= 3 || i!= 0) {
3416                                 if (!tmp_out.empty() && tmp_out[0] == '@') {
3417                                         if (desc_on == 4)
3418                                                 extra += frontStrip(tmp_out, '@');
3419                                         else
3420                                                 os << frontStrip(tmp_out, '@');
3421                                 }
3422                                 else
3423                                         os << tmp_out;
3424                         }
3425                 } else if (font2.latex() == LyXFont::ON) {
3426                         // "TeX"-Mode on ==> SGML-Mode on.
3427                         if (c != '\0')
3428                                 os << c;
3429                         ++char_line_count;
3430                 } else {
3431                         string sgml_string;
3432                         if (par->linuxDocConvertChar(c, sgml_string)
3433                             && !style.free_spacing) { // in freespacing
3434                                                      // mode, spaces are
3435                                                      // non-breaking characters
3436                                 // char is ' '
3437                                 if (desc_on == 1) {
3438                                         ++char_line_count;
3439                                         os << "\n</term><listitem><para>";
3440                                         desc_on = 2;
3441                                 } else {
3442                                         os << c;
3443                                 }
3444                         } else {
3445                                 os << sgml_string;
3446                         }
3447                 }
3448                 font1 = font2;
3449         }
3450
3451         // needed if there is an optional argument but no contents
3452         if (main_body > 0 && main_body == par->size()) {
3453                 font1 = style.font;
3454         }
3455         if (emph_flag) {
3456                 os << "</emphasis>";
3457         }
3458         
3459         // resets description flag correctly
3460         switch (desc_on){
3461         case 1:
3462                 // <term> not closed...
3463                 os << "</term>";
3464                 break;
3465         }
3466         os << '\n';
3467 }
3468
3469
3470 // This should be enabled when the Chktex class is implemented. (Asger)
3471 // chktex should be run with these flags disabled: 3, 22, 25, 30, 38(?)
3472 // Other flags: -wall -v0 -x
3473 int Buffer::runChktex()
3474 {
3475         if (!users->text) return 0;
3476
3477         ProhibitInput(users);
3478
3479         // get LaTeX-Filename
3480         string const name = getLatexName();
3481         string path = OnlyPath(filename);
3482
3483         string const org_path = path;
3484         if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3485                 path = tmppath;  
3486         }
3487
3488         Path p(path); // path to LaTeX file
3489         users->owner()->getMiniBuffer()->Set(_("Running chktex..."));
3490
3491         // Remove all error insets
3492         bool const removedErrorInsets = users->removeAutoInsets();
3493
3494         // Generate the LaTeX file if neccessary
3495         makeLaTeXFile(name, org_path, false);
3496
3497         TeXErrors terr;
3498         Chktex chktex(lyxrc.chktex_command, name, filepath);
3499         int res = chktex.run(terr); // run chktex
3500
3501         if (res == -1) {
3502                 WriteAlert(_("chktex did not work!"),
3503                            _("Could not run with file:"), name);
3504         } else if (res > 0) {
3505                 // Insert all errors as errors boxes
3506                 users->insertErrors(terr);
3507         }
3508
3509         // if we removed error insets before we ran chktex or if we inserted
3510         // error insets after we ran chktex, this must be run:
3511         if (removedErrorInsets || res){
3512                 users->redraw();
3513                 users->fitCursor(users->text);
3514         }
3515         AllowInput(users);
3516
3517         return res;
3518 }
3519
3520
3521 void Buffer::validate(LaTeXFeatures & features) const
3522 {
3523         LyXParagraph * par = paragraph;
3524         LyXTextClass const & tclass = 
3525                 textclasslist.TextClass(params.textclass);
3526     
3527         // AMS Style is at document level
3528     
3529         features.amsstyle = (params.use_amsmath ||
3530                              tclass.provides(LyXTextClass::amsmath));
3531     
3532         while (par) {
3533                 // We don't use "lyxerr.debug" because of speed. (Asger)
3534                 if (lyxerr.debugging(Debug::LATEX))
3535                         lyxerr << "Paragraph: " <<  par << endl;
3536
3537                 // Now just follow the list of paragraphs and run
3538                 // validate on each of them.
3539                 par->validate(features);
3540
3541                 // and then the next paragraph
3542 #ifndef NEW_INSETS
3543                 par = par->next_;
3544 #else
3545                 par = par->next();
3546 #endif
3547         }
3548
3549         // the bullet shapes are buffer level not paragraph level
3550         // so they are tested here
3551         for (int i = 0; i < 4; ++i) {
3552                 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
3553                         int const font = params.user_defined_bullets[i].getFont();
3554                         if (font == 0) {
3555                                 int const c = params
3556                                         .user_defined_bullets[i]
3557                                         .getCharacter();
3558                                 if (c == 16
3559                                    || c == 17
3560                                    || c == 25
3561                                    || c == 26
3562                                    || c == 31) {
3563                                         features.latexsym = true;
3564                                 }
3565                         } else if (font == 1) {
3566                                 features.amssymb = true;
3567                         } else if ((font >= 2 && font <= 5)) {
3568                                 features.pifont = true;
3569                         }
3570                 }
3571         }
3572         
3573         if (lyxerr.debugging(Debug::LATEX)) {
3574                 features.showStruct();
3575         }
3576 }
3577
3578
3579 void Buffer::setPaperStuff()
3580 {
3581         params.papersize = BufferParams::PAPER_DEFAULT;
3582         char const c1 = params.paperpackage;
3583         if (c1 == BufferParams::PACKAGE_NONE) {
3584                 char const c2 = params.papersize2;
3585                 if (c2 == BufferParams::VM_PAPER_USLETTER)
3586                         params.papersize = BufferParams::PAPER_USLETTER;
3587                 else if (c2 == BufferParams::VM_PAPER_USLEGAL)
3588                         params.papersize = BufferParams::PAPER_LEGALPAPER;
3589                 else if (c2 == BufferParams::VM_PAPER_USEXECUTIVE)
3590                         params.papersize = BufferParams::PAPER_EXECUTIVEPAPER;
3591                 else if (c2 == BufferParams::VM_PAPER_A3)
3592                         params.papersize = BufferParams::PAPER_A3PAPER;
3593                 else if (c2 == BufferParams::VM_PAPER_A4)
3594                         params.papersize = BufferParams::PAPER_A4PAPER;
3595                 else if (c2 == BufferParams::VM_PAPER_A5)
3596                         params.papersize = BufferParams::PAPER_A5PAPER;
3597                 else if ((c2 == BufferParams::VM_PAPER_B3) || (c2 == BufferParams::VM_PAPER_B4) ||
3598                          (c2 == BufferParams::VM_PAPER_B5))
3599                         params.papersize = BufferParams::PAPER_B5PAPER;
3600         } else if ((c1 == BufferParams::PACKAGE_A4) || (c1 == BufferParams::PACKAGE_A4WIDE) ||
3601                    (c1 == BufferParams::PACKAGE_WIDEMARGINSA4))
3602                 params.papersize = BufferParams::PAPER_A4PAPER;
3603 }
3604
3605
3606 // This function should be in Buffer because it's a buffer's property (ale)
3607 string const Buffer::getIncludeonlyList(char delim)
3608 {
3609         string lst;
3610         for (inset_iterator it = inset_iterator_begin();
3611             it != inset_iterator_end(); ++it) {
3612                 if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3613                         InsetInclude * insetinc = 
3614                                 static_cast<InsetInclude *>(*it);
3615                         if (insetinc->isIncludeOnly()) {
3616                                 if (!lst.empty())
3617                                         lst += delim;
3618                                 lst += insetinc->getRelFileBaseName();
3619                         }
3620                 }
3621         }
3622         lyxerr.debug() << "Includeonly(" << lst << ')' << endl;
3623         return lst;
3624 }
3625
3626
3627 vector<string> const Buffer::getLabelList()
3628 {
3629         /// if this is a child document and the parent is already loaded
3630         /// Use the parent's list instead  [ale990407]
3631         if (!params.parentname.empty()
3632             && bufferlist.exists(params.parentname)) {
3633                 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3634                 if (tmp)
3635                         return tmp->getLabelList();
3636         }
3637
3638         vector<string> label_list;
3639         for (inset_iterator it = inset_iterator_begin();
3640              it != inset_iterator_end(); ++it) {
3641                 vector<string> const l = (*it)->getLabelList();
3642                 label_list.insert(label_list.end(), l.begin(), l.end());
3643         }
3644         return label_list;
3645 }
3646
3647
3648 Buffer::Lists const Buffer::getLists() const
3649 {
3650         Lists l;
3651         LyXParagraph * par = paragraph;
3652 #ifdef NEW_INSETS
3653         bool found;
3654         LyXTextClassList::size_type cap;
3655         boost::tie(found, cap) = textclasslist
3656                 .NumberOfLayout(params.textclass, "Caption");
3657 #endif
3658
3659         while (par) {
3660 #ifndef NEW_INSETS
3661                 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3662                         if (textclasslist.Style(params.textclass, 
3663                                                 par->GetLayout()).labeltype
3664                             == LABEL_SENSITIVE) {
3665                                 string type;
3666                                 switch (par->footnotekind) {
3667                                 case LyXParagraph::FIG:
3668                                 case LyXParagraph::WIDE_FIG:
3669                                         type = "LOF";
3670                                         break;
3671                                 case LyXParagraph::TAB:
3672                                 case LyXParagraph::WIDE_TAB:
3673                                         type = "LOT";
3674                                         break;
3675                                 case LyXParagraph::ALGORITHM:
3676                                         type = "LOA";
3677                                         break;
3678                                 case LyXParagraph::FOOTNOTE:
3679                                 case LyXParagraph::MARGIN:
3680                                         break;
3681                                 }
3682                                 if (!type.empty()) {
3683                                         SingleList & item = l[type];
3684                                         string const str =
3685                                                 tostr(item.size()+1) + ". " + par->String(this, false);
3686                                         item.push_back(TocItem(par, 0, str));
3687                                 }
3688                         }
3689                 } else if (!par->IsDummy()) {
3690 #endif
3691                         char const labeltype =
3692                                 textclasslist.Style(params.textclass, 
3693                                                     par->GetLayout()).labeltype;
3694       
3695                         if (labeltype >= LABEL_COUNTER_CHAPTER
3696                             && labeltype <= LABEL_COUNTER_CHAPTER + params.tocdepth) {
3697                                 // insert this into the table of contents
3698                                 SingleList & item = l["TOC"];
3699                                 int depth = max(0,
3700                                                 labeltype - 
3701                                                 textclasslist.TextClass(params.textclass).maxcounter());
3702                                 item.push_back(TocItem(par, depth, par->String(this, true)));
3703                         }
3704 #ifdef NEW_INSETS
3705                         // For each paragrph, traverse its insets and look for
3706                         // FLOAT_CODE
3707                         
3708                         if (found) {
3709                                 LyXParagraph::inset_iterator it =
3710                                         par->inset_iterator_begin();
3711                                 LyXParagraph::inset_iterator end =
3712                                         par->inset_iterator_end();
3713
3714                                 for (; it != end; ++it) {
3715                                         if ((*it)->LyxCode() == Inset::FLOAT_CODE) {
3716                                                 InsetFloat * il =
3717                                                         static_cast<InsetFloat*>(*it);
3718                                                 
3719                                                 string const type = il->type();
3720                                                 
3721                                                 // Now find the caption in the float...
3722                                                 // We now tranverse the paragraphs of
3723                                                 // the inset...
3724                                                 LyXParagraph * tmp = il->inset->par;
3725                                                 while (tmp) {
3726                                                         if (tmp->layout == cap) {
3727                                                                 SingleList & item = l[type];
3728                                                                 string const str =
3729                                                                         tostr(item.size()+1) + ". " + tmp->String(this, false);
3730                                                                 item.push_back(TocItem(tmp, 0 , str));
3731                                                         }
3732                                                         tmp = tmp->next();
3733                                                 }
3734                                         }
3735                                 }
3736                         } else {
3737                                 lyxerr << "caption not found" << endl;
3738                         }
3739                         
3740 #endif
3741 #ifndef NEW_INSETS
3742                 }
3743                 par = par->next_;
3744 #else
3745                 par = par->next();
3746 #endif
3747         }
3748         return l;
3749 }
3750
3751
3752 // This is also a buffer property (ale)
3753 vector<pair<string, string> > const Buffer::getBibkeyList()
3754 {
3755         /// if this is a child document and the parent is already loaded
3756         /// Use the parent's list instead  [ale990412]
3757         if (!params.parentname.empty() && bufferlist.exists(params.parentname)) {
3758                 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3759                 if (tmp)
3760                         return tmp->getBibkeyList();
3761         }
3762
3763         vector<pair<string, string> > keys;
3764         LyXParagraph * par = paragraph;
3765         while (par) {
3766                 if (par->bibkey)
3767                         keys.push_back(pair<string, string>(par->bibkey->getContents(),
3768                                                            par->String(this, false)));
3769 #ifndef NEW_INSETS
3770                 par = par->next_;
3771 #else
3772                 par = par->next();
3773 #endif
3774         }
3775
3776         // Might be either using bibtex or a child has bibliography
3777         if (keys.empty()) {
3778                 for (inset_iterator it = inset_iterator_begin();
3779                         it != inset_iterator_end(); ++it) {
3780                         // Search for Bibtex or Include inset
3781                         if ((*it)->LyxCode() == Inset::BIBTEX_CODE) {
3782                                 vector<pair<string,string> > tmp =
3783                                         static_cast<InsetBibtex*>(*it)->getKeys(this);
3784                                 keys.insert(keys.end(), tmp.begin(), tmp.end());
3785                         } else if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3786                                 vector<pair<string,string> > const tmp =
3787                                         static_cast<InsetInclude*>(*it)->getKeys();
3788                                 keys.insert(keys.end(), tmp.begin(), tmp.end());
3789                         }
3790                 }
3791         }
3792  
3793         return keys;
3794 }
3795
3796
3797 bool Buffer::isDepClean(string const & name) const
3798 {
3799         DEPCLEAN * item = dep_clean;
3800         while (item && item->master != name)
3801                 item = item->next;
3802         if (!item) return true;
3803         return item->clean;
3804 }
3805
3806
3807 void Buffer::markDepClean(string const & name)
3808 {
3809         if (!dep_clean) {
3810                 dep_clean = new DEPCLEAN;
3811                 dep_clean->clean = true;
3812                 dep_clean->master = name;
3813                 dep_clean->next = 0;
3814         } else {
3815                 DEPCLEAN * item = dep_clean;
3816                 while (item && item->master != name)
3817                         item = item->next;
3818                 if (item) {
3819                         item->clean = true;
3820                 } else {
3821                         item = new DEPCLEAN;
3822                         item->clean = true;
3823                         item->master = name;
3824                         item->next = 0;
3825                 }
3826         }
3827 }
3828
3829
3830 bool Buffer::Dispatch(string const & command)
3831 {
3832         // Split command string into command and argument
3833         string cmd;
3834         string line = frontStrip(command);
3835         string const arg = strip(frontStrip(split(line, cmd, ' ')));
3836
3837         return Dispatch(lyxaction.LookupFunc(cmd), arg);
3838 }
3839
3840
3841 bool Buffer::Dispatch(int action, string const & argument)
3842 {
3843         bool dispatched = true;
3844         switch (action) {
3845                 case LFUN_EXPORT: 
3846                         Exporter::Export(this, argument, false);
3847                         break;
3848
3849                 default:
3850                         dispatched = false;
3851         }
3852         return dispatched;
3853 }
3854
3855
3856 void Buffer::resize()
3857 {
3858         /// resize the BufferViews!
3859         if (users)
3860                 users->resize();
3861 }
3862
3863
3864 void Buffer::resizeInsets(BufferView * bv)
3865 {
3866         /// then remove all LyXText in text-insets
3867         LyXParagraph * par = paragraph;
3868 #ifndef NEW_INSETS
3869         for (; par; par = par->next_) {
3870             par->resizeInsetsLyXText(bv);
3871         }
3872 #else
3873         for (; par; par = par->next()) {
3874             par->resizeInsetsLyXText(bv);
3875         }
3876 #endif
3877 }
3878
3879
3880 void Buffer::ChangeLanguage(Language const * from, Language const * to)
3881 {
3882
3883         LyXParagraph * par = paragraph;
3884         while (par) {
3885                 par->ChangeLanguage(params, from, to);
3886 #ifndef NEW_INSETS
3887                 par = par->next_;
3888 #else
3889                 par = par->next();
3890 #endif
3891         }
3892 }
3893
3894
3895 bool Buffer::isMultiLingual()
3896 {
3897         LyXParagraph * par = paragraph;
3898         while (par) {
3899                 if (par->isMultiLingual(params))
3900                         return true;
3901 #ifndef NEW_INSETS
3902                 par = par->next_;
3903 #else
3904                 par = par->next();
3905 #endif
3906         }
3907         return false;
3908 }
3909
3910
3911 Buffer::inset_iterator::inset_iterator(LyXParagraph * paragraph,
3912                                        LyXParagraph::size_type pos)
3913         : par(paragraph)
3914 {
3915         it = par->InsetIterator(pos);
3916         if (it == par->inset_iterator_end()) {
3917 #ifndef NEW_INSETS
3918                 par = par->next_;
3919 #else
3920                 par = par->next();
3921 #endif
3922                 SetParagraph();
3923         }
3924 }
3925
3926
3927 void Buffer::inset_iterator::SetParagraph()
3928 {
3929         while (par) {
3930                 it = par->inset_iterator_begin();
3931                 if (it != par->inset_iterator_end())
3932                         return;
3933 #ifndef NEW_INSETS
3934                 par = par->next_;
3935 #else
3936                 par = par->next();
3937 #endif
3938         }
3939         //it = 0;
3940         // We maintain an invariant that whenever par = 0 then it = 0
3941 }