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