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