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