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