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