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