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