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