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