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