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