]> git.lyx.org Git - lyx.git/blob - src/buffer.C
d7cd5a4c0699d7da544b107b708477667ef0bd0e
[lyx.git] / src / buffer.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-1999 The LyX Team.
8  *
9  *           This file is Copyright 1996-1999
10  *           Lars Gullik Bjønnes
11  *
12  * ======================================================
13  */
14
15 // Change Log:
16 // ===========
17 // 23/03/98   Heinrich Bauer (heinrich.bauer@t-mobil.de)
18 // Spots marked "changed Heinrich Bauer, 23/03/98" modified due to the
19 // following bug: dvi file export did not work after printing (or previewing)
20 // and vice versa as long as the same file was concerned. This happened
21 // every time the LyX-file was left unchanged between the two actions mentioned
22 // above.
23
24 #include <config.h>
25
26 #include <cstdlib>
27 #include <unistd.h>
28
29 #ifdef __GNUG__
30 #pragma implementation "buffer.h"
31 #endif
32
33 #include "definitions.h"
34 #include "buffer.h"
35 #include "bufferlist.h"
36 #include "lyx_main.h"
37 #include "lyx_gui_misc.h"
38 #include "lyxrc.h"
39 #include "lyxlex.h"
40 #include "tex-strings.h"
41 #include "layout.h"
42 #include "lyx_cb.h"
43 #include "minibuffer.h"
44 #include "lyxfont.h"
45 #include "mathed/formulamacro.h"
46 #include "insets/lyxinset.h"
47 #include "insets/inseterror.h"
48 #include "insets/insetlabel.h"
49 #include "insets/insetref.h"
50 #include "insets/inseturl.h"
51 #include "insets/insetinfo.h"
52 #include "insets/insetquotes.h"
53 #include "insets/insetlatex.h"
54 #include "insets/insetlatexaccent.h"
55 #include "insets/insetbib.h" 
56 #include "insets/insetindex.h" 
57 #include "insets/insetinclude.h"
58 #include "insets/insettoc.h"
59 #include "insets/insetlof.h"
60 #include "insets/insetlot.h"
61 #include "insets/insetloa.h"
62 #include "insets/insetparent.h"
63 #include "insets/insetspecialchar.h"
64 #include "insets/figinset.h"
65 #include "support/filetools.h"
66 #include "support/path.h"
67 #include "LaTeX.h"
68 #include "Literate.h"
69 #include "Chktex.h"
70 #include "LyXView.h"
71 #include "debug.h"
72 #include "LaTeXFeatures.h"
73 #include "support/syscall.h"
74 #include "support/lyxlib.h"
75 #include "support/FileInfo.h"
76 #include "lyxtext.h"
77 #include "gettext.h"
78
79 // Uncomment this line to enable a workaround for the weird behaviour
80 // of the cursor between a displayed inset and last character
81 // at the upper line. (Alejandro 20.9.96)
82 // #define BREAK_BEFORE_INSET
83
84 /* Lars, when changing this file sometime in the future to a list,
85  * please check out the figinsets-sideeffects described at the
86  * beginning of figinset.C    Matthias (04.07.1996)
87  */
88
89
90 // all these externs should eventually be removed.
91 extern BufferList bufferlist;
92 extern void SmallUpdate(signed char);
93 extern unsigned char GetCurrentTextClass();
94 extern void BeforeChange();
95
96 static const float LYX_FORMAT = 2.15;
97
98 extern int tex_code_break_column;
99
100 extern void FreeUpdateTimer();
101
102
103 Buffer::Buffer(string const & file, LyXRC *lyxrc, bool ronly)
104 {
105         filename = file;
106         filepath = OnlyPath(file);
107         paragraph = 0;
108         text = 0;
109         the_locking_inset = 0;
110         lyx_clean = true;
111         bak_clean = true;
112         dvi_clean_orgd = false;  // Heinrich Bauer, 23/03/98
113         dvi_clean_tmpd = false;  // Heinrich Bauer, 23/03/98
114         dep_clean = 0;
115         read_only = ronly;
116         inset_slept = false;
117         users = 0;
118         lyxvc.setBuffer(this);
119         lyxerr.debug() << "Buffer::Buffer()" << endl;
120         if (read_only || (lyxrc && lyxrc->use_tempdir)) {
121                 tmppath = CreateBufferTmpDir();
122         } else tmppath.clear();
123 }
124
125
126 Buffer::~Buffer()
127 {
128         lyxerr.debug() << "Buffer::~Buffer()" << endl;
129         // here the buffer should take care that it is
130         // saved properly, before it goes into the void.
131
132         // make sure that views using this buffer
133         // forgets it.
134         if (users)
135                 users->setBuffer(0);
136         
137         if (!tmppath.empty()) {
138                 DestroyBufferTmpDir(tmppath);
139         }
140         
141         LyXParagraph *par = paragraph;
142         LyXParagraph *tmppar;
143         while (par) {
144                 tmppar = par->next;
145                 delete par;
146                 par = tmppar;
147         }
148         paragraph = 0;
149         delete text;
150 }
151
152
153 bool Buffer::saveParamsAsDefaults()
154 {
155         string fname = AddName(AddPath(user_lyxdir, "templates/"),
156                                 "defaults.lyx");
157         Buffer defaults = Buffer(fname);
158         
159         // Use the current buffer's parameters as default
160         defaults.params.Copy(params);
161         // add an empty paragraph. Is this enough?
162         defaults.paragraph = new LyXParagraph();
163
164         return defaults.writeFile(defaults.filename,false);
165 }
166
167
168 /// Update window titles of all users
169 // Should work on a list
170 void Buffer::updateTitles()
171 {
172         if (users) users->getOwner()->updateWindowTitle();
173 }
174
175
176 /// Reset autosave timer of all users
177 // Should work on a list
178 void Buffer::resetAutosaveTimers()
179 {
180         if (users) users->getOwner()->resetAutosaveTimer();
181 }
182
183
184 void Buffer::setFileName(string const & newfile)
185 {
186         filename = MakeAbsPath(newfile);
187         filepath = OnlyPath(filename);
188         setReadonly(IsFileWriteable(filename) == 0);
189         updateTitles();
190 }
191
192 void Buffer::InsetUnlock()
193 {
194         if (the_locking_inset) {
195                 if (!inset_slept) the_locking_inset->InsetUnlock();
196                 the_locking_inset = 0;
197                 text->FinishUndo();
198                 inset_slept = false;
199         }
200 }
201
202
203 // Inserts a file into current document
204 bool Buffer::insertLyXFile(string const & filen)
205         //
206         // (c) CHT Software Service GmbH
207         // Uwe C. Schroeder
208         //
209         // Insert a Lyxformat - file into current buffer
210         //
211         // Moved from lyx_cb.C (Lgb)
212 {
213         if (filen.empty()) return false;
214
215         string filename = MakeAbsPath(filen);
216
217         // check if file exist
218         FileInfo fi(filename);
219
220         if (!fi.exist() || !fi.readable()) {
221                 WriteAlert(_("Error!"),
222                            _("Cannot open specified file:"),
223                            MakeDisplayPath(filename,50));
224                 return false;
225         }
226         
227         BeforeChange();
228
229         FilePtr myfile(filename, FilePtr::read);
230         if (!myfile()) {
231                 WriteAlert(_("Error!"),
232                            _("Cannot open specified file:"),
233                            MakeDisplayPath(filename,50));
234                 return false;
235         }
236         LyXLex lex(0, 0);
237         lex.setFile(myfile);
238         int c = fgetc(myfile());
239         ungetc(c, myfile);
240
241         bool res = true;
242
243         if (c=='#') {
244                 lyxerr.debug() << "Will insert file with header" << endl;
245                 res = readFile(lex, text->cursor.par);
246         } else {
247                 lyxerr.debug() << "Will insert file without header" << endl;
248                 res = readLyXformat2(lex, text->cursor.par);
249         }
250         resize();
251         return res;
252 }
253
254
255 //
256 // Uwe C. Schroeder
257 // changed to be public and have one parameter
258 // if par = 0 normal behavior
259 // else insert behavior
260 // Returns false if "\the_end" is not read for formats >= 2.13. (Asger)
261 bool Buffer::readLyXformat2(LyXLex &lex, LyXParagraph *par)
262 {
263         string tmptok;
264         Inset *inset = 0;
265         int pos = 0;
266         int tmpret, tmpret2;
267         char depth = 0; // signed or unsigned?
268         LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
269         LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
270         bool the_end_read = false;
271
272         LyXParagraph *return_par = 0;
273         LyXFont font = LyXFont(LyXFont::ALL_INHERIT);
274
275         // If we are inserting, we cheat and get a token in advance
276         bool has_token = false;
277         string pretoken;
278
279         if(!par) {
280                 par = new LyXParagraph();
281         } else {
282                 text->BreakParagraph();
283                 return_par = text->FirstParagraph();
284                 pos=0;
285                 markDirty();
286                 // We don't want to adopt the parameters from the
287                 // document we insert, so we skip until the text begins:
288                 while (lex.IsOK()) {
289                         lex.nextToken();
290                         pretoken = lex.GetString();
291                         if (pretoken == "\\layout") {
292                                 has_token = true;
293                                 break;
294                         }
295                 }
296         }
297
298         while (lex.IsOK()) {
299                 if (has_token) {
300                         has_token = false;
301                 } else {
302                         lex.nextToken();
303                         pretoken = lex.GetString();
304                 }
305
306                 // Profiling show this should give a lot: (Asger)
307                 string const token = pretoken;
308
309                 if (token.empty())
310                         continue;
311                 else if (token[0] != '\\') {
312                         int n = token.length();
313                         for (int i=0; i < n; i++) {
314                                 par->InsertChar(pos, token[i]);
315                                 par->SetFont(pos, font);
316                                 pos++;
317                         }
318                 } else if (token == "\\i") {
319                         inset = new InsetLatexAccent;
320                         inset->Read(lex);
321                         par->InsertChar(pos, LYX_META_INSET); 
322                         
323                         par->InsertInset(pos, inset);
324                         par->SetFont(pos, font);
325                         pos++;
326                 } else if (token == "\\layout") {
327                         if (!return_par) 
328                                 return_par = par;
329                         else 
330                                 par = new LyXParagraph(par);
331                         pos = 0;
332                         lex.EatLine();
333                         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 <<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 <<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 cerr.
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 << _("Error! Document is read-only: ")
1138                                << filename << endl;
1139                 else
1140                         WriteAlert(_("Error! Document is read-only: "), filename);
1141                 return false;
1142         }
1143
1144         FileInfo finfo(filename);
1145         if (finfo.exist() && !finfo.writable()) {
1146                 // Here we should come with a question if we should
1147                 // try to do the save anyway. (i.e. do a chmod first)
1148                 if (flag)
1149                         lyxerr << _("Error! Cannot write file: ")
1150                                << filename << endl;
1151                 else
1152                         WriteFSAlert(_("Error! Cannot write file: "), filename);
1153                 return false;
1154         }
1155
1156         FilePtr file(filename, FilePtr::truncate);
1157         if (!file()) {
1158                 if (flag)
1159                         lyxerr << _("Error! Cannot write file: ")
1160                                << filename << endl;
1161                 else
1162                         WriteFSAlert(_("Error! Cannot write file: "), filename);
1163                 return false;
1164         }
1165         // The top of the file should not be written by params.
1166         // collect some very important information
1167         string userName(getUserName()) ;
1168
1169         // write out a comment in the top of the file
1170         fprintf(file,
1171                 "#This file was created by <%s> %s",
1172                 userName.c_str(),(char*)date());
1173         fprintf(file,
1174                 "#LyX 1.0 (C) 1995-1999 Matthias Ettrich"
1175                 " and the LyX Team\n");
1176         
1177         // at the very beginning the used lyx format
1178         fprintf(file, "\\lyxformat %.2f\n", LYX_FORMAT);
1179
1180         // now write out the buffer parameters.
1181         params.writeFile(file);
1182
1183         char footnoteflag = 0;
1184         char depth = 0;
1185
1186         // this will write out all the paragraphs
1187         // using recursive descent.
1188         paragraph->writeFile(file, params, footnoteflag, depth);
1189
1190         // Write marker that shows file is complete
1191         fprintf(file, "\n\\the_end\n");
1192         if (file.close()) {
1193                 if (flag)
1194                         lyxerr << _("Error! Could not close file properly: ")
1195                                << filename << endl;
1196                 else
1197                         WriteFSAlert(_("Error! Could not close file properly: "),
1198                                      filename);
1199                 return false;
1200         }
1201         return true;
1202 }
1203
1204
1205 void Buffer::writeFileAscii(string const & filename, int linelen) 
1206 {
1207         FilePtr file(filename, FilePtr::write);
1208         LyXFont
1209                 font1, font2;
1210         Inset
1211                 *inset;
1212         LyXParagraph
1213                 *par = paragraph;
1214         char
1215                 c,
1216                 footnoteflag = 0,
1217                 depth = 0;
1218
1219         string
1220                 fname1,
1221                 tmp;
1222         
1223         int
1224                 i,j,h,
1225                 ltype=0,
1226                 ltype_depth=0,
1227                 noparbreak=0,
1228                 islatex=0,
1229                 *clen=0,
1230                 actcell=0,
1231                 actpos=0,
1232                 cell=0,
1233                 cells=0,
1234                 currlinelen=0;
1235         long
1236                 fpos=0;
1237         bool
1238                 ref_printed = false;
1239    
1240    
1241         if (!file()) {
1242                 WriteFSAlert(_("Error: Cannot write file:"), filename);
1243                 return;
1244         }
1245         fname1=TmpFileName();
1246         while (par) {
1247                 noparbreak = 0;
1248                 islatex = 0;
1249                 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE ||
1250                     !par->previous ||
1251                     par->previous->footnoteflag == LyXParagraph::NO_FOOTNOTE){
1252          
1253                         /* begins a footnote environment ? */ 
1254                         if (footnoteflag != par->footnoteflag) {
1255                                 footnoteflag = par->footnoteflag;
1256                                 if (footnoteflag) {
1257                                         j=strlen(string_footnotekinds[par->footnotekind])+4;
1258                                         if (currlinelen+j > linelen)
1259                                                 fprintf(file,"\n");
1260                                         fprintf(file, "([%s] ", 
1261                                                 string_footnotekinds[par->footnotekind]);
1262                                         currlinelen += j;
1263                                 }
1264                         }
1265          
1266                         /* begins or ends a deeper area ?*/ 
1267                         if (depth != par->depth) {
1268                                 if (par->depth > depth) {
1269                                         while (par->depth > depth) {
1270                                                 depth++;
1271                                         }
1272                                 }
1273                                 else {
1274                                         while (par->depth < depth) {
1275                                                 depth--;
1276                                         }
1277                                 }
1278                         }
1279          
1280                         /* First write the layout */
1281                         tmp = lyxstyle.NameOfLayout(params.textclass,par->layout);
1282                         if (tmp == "Itemize") {
1283                                 ltype = 1;
1284                                 ltype_depth = depth+1;
1285                         } else if (tmp =="Enumerate") {
1286                                 ltype = 2;
1287                                 ltype_depth = depth+1;
1288                         } else if (strstr(tmp.c_str(),"ection")) {
1289                                 ltype = 3;
1290                                 ltype_depth = depth+1;
1291                         } else if (strstr(tmp.c_str(),"aragraph")) {
1292                                 ltype = 4;
1293                                 ltype_depth = depth+1;
1294                         } else if (tmp == "Description") {
1295                                 ltype = 5;
1296                                 ltype_depth = depth+1;
1297                         } else if (tmp == "Abstract") {
1298                                 ltype = 6;
1299                                 ltype_depth = 0;
1300                         } else if (tmp == "Bibliography") {
1301                                 ltype = 7;
1302                                 ltype_depth = 0;
1303                         } else {
1304                                 ltype = 0;
1305                                 ltype_depth = 0;
1306                         }
1307          
1308                         /* maybe some vertical spaces */ 
1309
1310                         /* the labelwidthstring used in lists */ 
1311          
1312                         /* some lines? */ 
1313          
1314                         /* some pagebreaks? */ 
1315          
1316                         /* noindent ? */ 
1317          
1318                         /* what about the alignment */ 
1319                 }
1320                 else {
1321                         /* dummy layout, that means a footnote ended */ 
1322                         footnoteflag = LyXParagraph::NO_FOOTNOTE;
1323                         fprintf(file, ") ");
1324                         noparbreak = 1;
1325                 }
1326       
1327                 /* It might be a table */ 
1328                 if (par->table){
1329                         if (!lyxrc->ascii_roff_command.empty() &&
1330                             lyxrc->ascii_roff_command != "none") {
1331                                 RoffAsciiTable(file,par);
1332                                 par = par->next;
1333                                 continue;
1334                         }
1335                         cell = 1;
1336                         actcell = 0;
1337                         cells = par->table->columns;
1338                         clen = new int [cells];
1339                         memset(clen,0,sizeof(int)*cells);
1340                         for (i = 0, j = 0, h=1; i < par->last; i++, h++) {
1341                                 c = par->GetChar(i);
1342                                 if (c == LYX_META_INSET) {
1343                                         if ((inset = par->GetInset(i))) {
1344                                                 FilePtr fp(fname1,
1345                                                            FilePtr::write);
1346                                                 if (!fp()) {
1347                                                         WriteFSAlert(_("Error: Cannot open temporary file:"), fname1);
1348                                                         return;
1349                                                 }
1350                                                 inset->Latex(fp,-1);
1351                                                 h += ftell(fp) - 1;
1352                                                 remove(fname1.c_str());
1353                                         }
1354                                 } else if (c == LYX_META_NEWLINE) {
1355                                         if (clen[j] < h)
1356                                                 clen[j] = h;
1357                                         h = 0;
1358                                         j = (++j) % par->table->NumberOfCellsInRow(actcell);
1359                                         actcell++;
1360                                 }
1361                         }
1362                         if (clen[j] < h)
1363                                 clen[j] = h;
1364                 }
1365       
1366                 font1 = LyXFont(LyXFont::ALL_INHERIT);
1367                 actcell=0;
1368                 for (i = 0,actpos=1; i < par->last; i++, actpos++) {
1369                         if (!i && !footnoteflag && !noparbreak){
1370                                 fprintf(file, "\n\n");
1371                                 for(j=0; j<depth; j++)
1372                                         fprintf(file, "  ");
1373                                 currlinelen = depth*2;
1374                                 switch(ltype) {
1375                                 case 0: /* Standart */
1376                                 case 4: /* (Sub)Paragraph */
1377                                 case 5: /* Description */
1378                                         break;
1379                                 case 6: /* Abstract */
1380                                         fprintf(file, "Abstract\n\n");
1381                                         break;
1382                                 case 7: /* Bibliography */
1383                                         if (!ref_printed) {
1384                                                 fprintf(file, "References\n\n");
1385                                                 ref_printed = true;
1386                                         }
1387                                         break;
1388                                 default:
1389                                         fprintf(file,"%s ",par->labelstring.c_str());
1390                                         break;
1391                                 }
1392                                 if (ltype_depth > depth) {
1393                                         for(j=ltype_depth-1; j>depth; j--)
1394                                                 fprintf(file, "  ");
1395                                         currlinelen += (ltype_depth-depth)*2;
1396                                 }
1397                                 if (par->table) {
1398                                         for(j=0;j<cells;j++) {
1399                                                 fputc('+',file);
1400                                                 for(h=0; h<(clen[j]+1); h++)
1401                                                         fputc('-',file);
1402                                         }
1403                                         fprintf(file,"+\n");
1404                                         for(j=0; j<depth; j++)
1405                                                 fprintf(file, "  ");
1406                                         currlinelen = depth*2;
1407                                         if (ltype_depth > depth) {
1408                                                 for(j=ltype_depth; j>depth; j--)
1409                                                         fprintf(file, "  ");
1410                                                 currlinelen += (ltype_depth-depth)*2;
1411                                         }
1412                                         fprintf(file,"| ");
1413                                 }
1414                         }
1415                         font2 = par->GetFontSettings(i);
1416                         if (font1.latex() != font2.latex()) {
1417                                 if (font2.latex() == LyXFont::OFF)
1418                                         islatex = 0;
1419                                 else
1420                                         islatex = 1;
1421                         }
1422                         else {
1423                                 islatex = 0;
1424                         }
1425                         c = par->GetChar(i);
1426                         if (islatex)
1427                                 continue;
1428                         switch (c) {
1429                         case LYX_META_INSET:
1430                                 if ((inset = par->GetInset(i))) {
1431                                         fpos = ftell(file);
1432                                         inset->Latex(file,-1);
1433                                         currlinelen += (ftell(file) - fpos);
1434                                         actpos += (ftell(file) - fpos) - 1;
1435                                 }
1436                                 break;
1437                         case LYX_META_NEWLINE:
1438                                 if (par->table) {
1439                                         if (par->table->NumberOfCellsInRow(actcell) <= cell) {
1440                                                 for(j=actpos;j<clen[cell-1];j++)
1441                                                         fputc(' ',file);
1442                                                 fprintf(file," |\n");
1443                                                 for(j=0; j<depth; j++)
1444                                                         fprintf(file, "  ");
1445                                                 currlinelen = depth*2;
1446                                                 if (ltype_depth > depth) {
1447                                                         for(j=ltype_depth; j>depth; j--)
1448                                                                 fprintf(file, "  ");
1449                                                         currlinelen += (ltype_depth-depth)*2;
1450                                                 }
1451                                                 for(j=0;j<cells;j++) {
1452                                                         fputc('+',file);
1453                                                         for(h=0; h<(clen[j]+1); h++)
1454                                                                 fputc('-',file);
1455                                                 }
1456                                                 fprintf(file,"+\n");
1457                                                 for(j=0; j<depth; j++)
1458                                                         fprintf(file, "  ");
1459                                                 currlinelen = depth*2;
1460                                                 if (ltype_depth > depth) {
1461                                                         for(j=ltype_depth; j>depth; j--)
1462                                                                 fprintf(file, "  ");
1463                                                         currlinelen += (ltype_depth-depth)*2;
1464                                                 }
1465                                                 fprintf(file,"| ");
1466                                                 cell = 1;
1467                                         } else {
1468                                                 for(j=actpos; j<clen[cell-1]; j++)
1469                                                         fputc(' ',file);
1470                                                 fprintf(file, " | ");
1471                                                 cell++;
1472                                         }
1473                                         actcell++;
1474                                         currlinelen = actpos = 0;
1475                                 } else {
1476                                         fprintf(file, "\n");
1477                                         for(j=0; j<depth; j++)
1478                                                 fprintf(file, "  ");
1479                                         currlinelen = depth*2;
1480                                         if (ltype_depth > depth) {
1481                                                 for(j=ltype_depth; j>depth; j--)
1482                                                         fprintf(file, "  ");
1483                                                 currlinelen += (ltype_depth-depth)*2;
1484                                         }
1485                                 }
1486                                 break;
1487                         case LYX_META_HFILL: 
1488                                 fprintf(file, "\t");
1489                                 break;
1490                         case LYX_META_PROTECTED_SEPARATOR:
1491                                 fprintf(file, " ");
1492                                 break;
1493                         case '\\': 
1494                                 fprintf(file, "\\");
1495                                 break;
1496                         default:
1497                                 if (currlinelen > (linelen-10) \
1498                                     && c==' ' && (i+2 < par->last)) {
1499                                         fprintf(file, "\n");
1500                                         for(j=0; j<depth; j++)
1501                                                 fprintf(file, "  ");
1502                                         currlinelen = depth*2;
1503                                         if (ltype_depth > depth) {
1504                                                 for(j=ltype_depth; j>depth; j--)
1505                                                         fprintf(file, "  ");
1506                                                 currlinelen += (ltype_depth-depth)*2;
1507                                         }
1508                                 } else if (c != '\0')
1509                                         fprintf(file, "%c", c);
1510                                 else if (c == '\0')
1511                                         lyxerr.debug() << "writeAsciiFile: NULL char in structure." << endl;
1512                                 currlinelen++;
1513                                 break;
1514                         }
1515                 }
1516                 if (par->table) {
1517                         for(j=actpos;j<clen[cell-1];j++)
1518                                 fputc(' ',file);
1519                         fprintf(file," |\n");
1520                         for(j=0; j<depth; j++)
1521                                 fprintf(file, "  ");
1522                         currlinelen = depth*2;
1523                         if (ltype_depth > depth) {
1524                                 for(j=ltype_depth; j>depth; j--)
1525                                         fprintf(file, "  ");
1526                                 currlinelen += (ltype_depth-depth)*2;
1527                         }
1528                         for(j=0;j<cells;j++) {
1529                                 fputc('+',file);
1530                                 for(h=0; h<(clen[j]+1); h++)
1531                                         fputc('-',file);
1532                         }
1533                         fprintf(file,"+\n");
1534                         delete [] clen;    
1535                 }      
1536                 par = par->next;
1537         }
1538    
1539         fprintf(file, "\n");
1540 }
1541
1542
1543 void Buffer::makeLaTeXFile(string const & filename, 
1544                            string const & original_path,
1545                            bool nice, bool only_body)
1546 {
1547         lyxerr[Debug::LATEX] << "makeLaTeXFile..." << endl;
1548         params.textclass = GetCurrentTextClass();
1549         niceFile = nice; // this will be used by Insetincludes.
1550
1551         tex_code_break_column = lyxrc->ascii_linelen;
1552
1553         LyXTextClass *tclass = lyxstyle.TextClass(params.textclass);
1554   
1555         FilePtr file(filename, FilePtr::write);
1556         if (!file()) {
1557                 WriteFSAlert(_("Error: Cannot write file:"),filename);
1558                 return;
1559         }
1560
1561         // validate the buffer.
1562         lyxerr[Debug::LATEX] << "  Validating buffer..." << endl;
1563         LaTeXFeatures features(tclass->number_of_defined_layouts);
1564         validate(features);
1565         lyxerr[Debug::LATEX] << "  Buffer validation done." << endl;
1566         
1567         texrow.reset();
1568         // The starting paragraph of the coming rows is the 
1569         // first paragraph of the document. (Asger)
1570         texrow.start(paragraph, 0);
1571
1572         string userName(getUserName());
1573         string LFile;
1574         
1575         if (!only_body && nice) {
1576                 LFile += "%% This LaTeX-file was created by <";
1577                 LFile += userName + "> " + (char*)date();
1578                 LFile += "%% LyX 1.0 (C) 1995-1999 by Matthias Ettrich and the LyX Team\n";
1579                 LFile += "\n%% Do not edit this file unless you know what you are doing.\n";
1580                 texrow.newline();
1581                 texrow.newline();
1582                 texrow.newline();
1583                 texrow.newline();
1584         }
1585         lyxerr.debug() << "lyx header finished" << endl;
1586         // There are a few differences between nice LaTeX and usual files:
1587         // usual is \batchmode, uses \listfiles and has a 
1588         // special input@path to allow the including of figures
1589         // with either \input or \includegraphics (what figinsets do).
1590         // batchmode is not set if there is a tex_code_break_column.
1591         // In this case somebody is interested in the generated LaTeX,
1592         // so this is OK. input@path is set when the actual parameter
1593         // original_path is set. This is done for usual tex-file, but not
1594         // for nice-latex-file. (Matthias 250696)
1595         if (!only_body) {
1596                 if (!nice){
1597                         // code for usual, NOT nice-latex-file
1598                         LFile += "\\batchmode\n"; // changed
1599                         // from \nonstopmode
1600                         texrow.newline();
1601                         // We don't need listfiles anymore
1602                         //LFile += "\\listfiles\n";
1603                         //texrow.newline();
1604                 }
1605                 if (!original_path.empty()) {
1606                         LFile += "\\makeatletter\n";
1607                         texrow.newline();
1608                         LFile += "\\def\\input@path{{" + original_path
1609                                  + "/}}\n";
1610                         texrow.newline();
1611                         LFile += "\\makeatother\n";
1612                         texrow.newline();
1613                 }
1614                 
1615                 LFile += "\\documentclass";
1616                 
1617                 string options; // the document class options.
1618                 
1619                 if (tokenPos(tclass->opt_fontsize, '|',params.fontsize) >= 0) {
1620                         // only write if existing in list (and not default)
1621                         options += params.fontsize;
1622                         options += "pt,";
1623                 }
1624                 
1625                 
1626                 if (!params.use_geometry &&
1627                     (params.paperpackage == PACKAGE_NONE)) {
1628                         switch (params.papersize) {
1629                         case PAPER_A4PAPER:
1630                                 options += "a4paper,";
1631                                 break;
1632                         case PAPER_USLETTER:
1633                                 options += "letterpaper,";
1634                                 break;
1635                         case PAPER_A5PAPER:
1636                                 options += "a5paper,";
1637                                 break;
1638                         case PAPER_B5PAPER:
1639                                 options += "b5paper,";
1640                                 break;
1641                         case PAPER_EXECUTIVEPAPER:
1642                                 options += "executivepaper,";
1643                                 break;
1644                         case PAPER_LEGALPAPER:
1645                                 options += "legalpaper,";
1646                                 break;
1647                         }
1648                 }
1649
1650                 // if needed
1651                 if (params.sides != tclass->sides) {
1652                         if (params.sides == 2)
1653                                 options += "twoside,";
1654                         else
1655                                 options += "oneside,";
1656                 }
1657
1658                 // if needed
1659                 if (params.columns != tclass->columns) {
1660                         if (params.columns == 2)
1661                                 options += "twocolumn,";
1662                         else
1663                                 options += "onecolumn,";
1664                 }
1665
1666                 if (!params.use_geometry && params.orientation == ORIENTATION_LANDSCAPE)
1667                         options += "landscape,";
1668                 
1669                 // language should be a parameter to \documentclass
1670                 if (params.language != "default") {
1671                         options += params.language + ',';
1672                 }
1673                 
1674                 // the user-defined options
1675                 if (!params.options.empty()) {
1676                         options += params.options + ',';
1677                 }
1678                 
1679                 if (!options.empty()){
1680                         options = strip(options, ',');
1681                         LFile += '[';
1682                         LFile += options;
1683                         LFile += ']';
1684                 }
1685                 
1686                 LFile += '{';
1687                 LFile += lyxstyle.LatexnameOfClass(params.textclass);
1688                 LFile += "}\n";
1689                 texrow.newline();
1690                 // end of \documentclass defs
1691                 
1692                 // font selection must be done before loading fontenc.sty
1693                 if (params.fonts != "default") {
1694                         LFile += "\\usepackage{" + params.fonts + "}\n";
1695                         texrow.newline();
1696                 }
1697                 // this one is not per buffer
1698                 if (lyxrc->fontenc != "default") {
1699                         LFile += "\\usepackage[" + lyxrc->fontenc
1700                                  + "]{fontenc}\n";
1701                         texrow.newline();
1702                 }
1703                 if (params.inputenc != "default") {
1704                         LFile += "\\usepackage[" + params.inputenc
1705                                  + "]{inputenc}\n";
1706                         texrow.newline();
1707                 }
1708                 
1709                 /* at the very beginning the text parameters */
1710                 if (params.paperpackage != PACKAGE_NONE) {
1711                         switch (params.paperpackage) {
1712                         case PACKAGE_A4:
1713                                 LFile += "\\usepackage{a4}\n";
1714                                 texrow.newline();
1715                                 break;
1716                         case PACKAGE_A4WIDE:
1717                                 LFile += "\\usepackage{a4wide}\n";
1718                                 texrow.newline();
1719                                 break;
1720                         case PACKAGE_WIDEMARGINSA4:
1721                                 LFile += "\\usepackage[widemargins]{a4}\n";
1722                                 texrow.newline();
1723                                 break;
1724                         }
1725                 }
1726                 if (params.use_geometry) {
1727                         LFile += "\\usepackage{geometry}\n";
1728                         texrow.newline();
1729                         LFile += "\\geometry{verbose";
1730                         if (params.orientation == ORIENTATION_LANDSCAPE)
1731                                 LFile += ",landscape";
1732                         switch (params.papersize2) {
1733                         case VM_PAPER_CUSTOM:
1734                                 if (!params.paperwidth.empty())
1735                                         LFile += ",paperwidth="
1736                                                  + params.paperwidth;
1737                                 if (!params.paperheight.empty())
1738                                         LFile += ",paperheight="
1739                                                  + params.paperheight;
1740                                 break;
1741                         case VM_PAPER_USLETTER:
1742                                 LFile += ",letterpaper";
1743                                 break;
1744                         case VM_PAPER_USLEGAL:
1745                                 LFile += ",legalpaper";
1746                                 break;
1747                         case VM_PAPER_USEXECUTIVE:
1748                                 LFile += ",executivepaper";
1749                                 break;
1750                         case VM_PAPER_A3:
1751                                 LFile += ",a3paper";
1752                                 break;
1753                         case VM_PAPER_A4:
1754                                 LFile += ",a4paper";
1755                                 break;
1756                         case VM_PAPER_A5:
1757                                 LFile += ",a5paper";
1758                                 break;
1759                         case VM_PAPER_B3:
1760                                 LFile += ",b3paper";
1761                                 break;
1762                         case VM_PAPER_B4:
1763                                 LFile += ",b4paper";
1764                                 break;
1765                         case VM_PAPER_B5:
1766                                 LFile += ",b5paper";
1767                                 break;
1768                         default:
1769                                 // default papersize ie VM_PAPER_DEFAULT
1770                                 switch (lyxrc->default_papersize) {
1771                                 case PAPER_DEFAULT: // keep compiler happy
1772                                 case PAPER_USLETTER:
1773                                         LFile += ",letterpaper";
1774                                         break;
1775                                 case PAPER_LEGALPAPER:
1776                                         LFile += ",legalpaper";
1777                                         break;
1778                                 case PAPER_EXECUTIVEPAPER:
1779                                         LFile += ",executivepaper";
1780                                         break;
1781                                 case PAPER_A3PAPER:
1782                                         LFile += ",a3paper";
1783                                         break;
1784                                 case PAPER_A4PAPER:
1785                                         LFile += ",a4paper";
1786                                         break;
1787                                 case PAPER_A5PAPER:
1788                                         LFile += ",a5paper";
1789                                         break;
1790                                 case PAPER_B5PAPER:
1791                                         LFile += ",b5paper";
1792                                         break;
1793                                 }
1794                         }
1795                         if (!params.topmargin.empty())
1796                                 LFile += ",tmargin=" + params.topmargin;
1797                         if (!params.bottommargin.empty())
1798                                 LFile += ",bmargin=" + params.bottommargin;
1799                         if (!params.leftmargin.empty())
1800                                 LFile += ",lmargin=" + params.leftmargin;
1801                         if (!params.rightmargin.empty())
1802                                 LFile += ",rmargin=" + params.rightmargin;
1803                         if (!params.headheight.empty())
1804                                 LFile += ",headheight=" + params.headheight;
1805                         if (!params.headsep.empty())
1806                                 LFile += ",headsep=" + params.headsep;
1807                         if (!params.footskip.empty())
1808                                 LFile += ",footskip=" + params.footskip;
1809                         LFile += "}\n";
1810                         texrow.newline();
1811                 }
1812                 if (params.use_amsmath
1813                     && !prefixIs(lyxstyle.LatexnameOfClass(params.textclass), "ams")) {
1814                         LFile += "\\usepackage{amsmath}\n";
1815                 }
1816
1817                 if (tokenPos(tclass->opt_pagestyle, '|',params.pagestyle) >= 0) {
1818                         if (params.pagestyle == "fancy") {
1819                                 LFile += "\\usepackage{fancyhdr}\n";
1820                                 texrow.newline();
1821                         }
1822                         LFile += "\\pagestyle{" + params.pagestyle + "}\n";
1823                         texrow.newline();
1824                 }
1825
1826                 // We try to load babel late, in case it interferes
1827                 // with other packages.
1828                 if (params.language != "default") {
1829                         LFile += "\\usepackage{babel}\n";
1830                         texrow.newline();
1831                 }
1832
1833                 if (params.secnumdepth != tclass->secnumdepth) {
1834                         LFile += "\\setcounter{secnumdepth}{";
1835                         LFile += tostr(params.secnumdepth);
1836                         LFile += "}\n";
1837                         texrow.newline();
1838                 }
1839                 if (params.tocdepth != tclass->tocdepth) {
1840                         LFile += "\\setcounter{tocdepth}{";
1841                         LFile += tostr(params.tocdepth);
1842                         LFile += "}\n";
1843                         texrow.newline();
1844                 }
1845                 
1846                 if (params.paragraph_separation) {
1847                         switch (params.defskip.kind()) {
1848                         case VSpace::SMALLSKIP: 
1849                                 LFile += "\\setlength\\parskip{\\smallskipamount}\n";
1850                                 break;
1851                         case VSpace::MEDSKIP:
1852                                 LFile += "\\setlength\\parskip{\\medskipamount}\n";
1853                                 break;
1854                         case VSpace::BIGSKIP:
1855                                 LFile += "\\setlength\\parskip{\\bigskipamount}\n";
1856                                 break;
1857                         case VSpace::LENGTH:
1858                                 LFile += "\\setlength\\parskip{"
1859                                          + params.defskip.length().asLatexString()
1860                                          + "}\n";
1861                                 break;
1862                         default: // should never happen // Then delete it.
1863                                 LFile += "\\setlength\\parskip{\\medskipamount}\n";
1864                                 break;
1865                         }
1866                         texrow.newline();
1867                         
1868                         LFile += "\\setlength\\parindent{0pt}\n";
1869                         texrow.newline();
1870                 }
1871
1872                 // Write out what we've generated so far...and reset LFile
1873                 fwrite(LFile.c_str(), sizeof(char), LFile.length(), file);
1874                 LFile.clear(); 
1875
1876                 // Now insert the LyX specific LaTeX commands...
1877                 string preamble, tmppreamble;
1878
1879                 // The optional packages;
1880                 preamble = features.getPackages(params);
1881
1882                 // this might be useful...
1883                 preamble += "\n\\makeatletter\n\n";
1884
1885                 // Some macros LyX will need
1886                 tmppreamble = features.getMacros(params);
1887
1888                 if (!tmppreamble.empty()) {
1889                         preamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1890                                 "LyX specific LaTeX commands.\n"
1891                                 + tmppreamble + '\n';
1892                 }
1893
1894                 // the text class specific preamble 
1895                 tmppreamble = features.getTClassPreamble(params);
1896                 if (!tmppreamble.empty()) {
1897                         preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1898                                 "Textclass specific LaTeX commands.\n"
1899                                 + tmppreamble + '\n';
1900                 }
1901
1902                 /* the user-defined preamble */
1903                 if (!params.preamble.empty()) {
1904                         preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1905                                 "User specified LaTeX commands.\n"
1906                                 + params.preamble + '\n';
1907                 }
1908
1909                 preamble += "\\makeatother\n\n";
1910
1911                 // Itemize bullet settings need to be last in case the user
1912                 // defines their own bullets that use a package included
1913                 // in the user-defined preamble -- ARRae
1914                 for (int i = 0; i < 4; ++i) {
1915                         if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
1916                                 preamble += "\\renewcommand\\labelitemi";
1917                                 switch (i) {
1918                                         // `i' is one less than the item to modify
1919                                 case 0:
1920                                         break;
1921                                 case 1:
1922                                         preamble += 'i';
1923                                         break;
1924                                 case 2:
1925                                         preamble += "ii";
1926                                         break;
1927                                 case 3:
1928                                         preamble += 'v';
1929                                         break;
1930                                 }
1931                                 preamble += "[0]{" + params.user_defined_bullets[i].getText() + "}\n";
1932                         }
1933                 }
1934
1935                 for (int j = countChar(preamble, '\n'); j-- ;) {
1936                         texrow.newline();
1937                 }
1938
1939                 // A bit faster than printing a char at a time I think.
1940                 fwrite(preamble.c_str(), sizeof(char),
1941                        preamble.length(), file);
1942
1943                 // make the body.
1944                 LFile += "\\begin{document}\n\n";
1945                 texrow.newline();
1946                 texrow.newline();
1947         } // only_body
1948         lyxerr.debug() << "preamble finished, now the body." << endl;
1949         
1950         bool was_title = false;
1951         bool already_title = false;
1952         string ftnote;
1953         TexRow ft_texrow;
1954         int ftcount = 0;
1955         int loop_count = 0;
1956
1957         LyXParagraph *par = paragraph;
1958
1959         // if only_body
1960         while (par) {
1961                 ++loop_count;
1962                 if (par->IsDummy())
1963                         lyxerr[Debug::LATEX] << "Error in MakeLateXFile."
1964                                              << endl;
1965                 LyXLayout * layout = lyxstyle.Style(params.textclass,
1966                                                     par->layout);
1967             
1968                 if (layout->intitle) {
1969                         if (already_title) {
1970                                 lyxerr <<"Error in MakeLatexFile: You"
1971                                         " should not mix title layouts"
1972                                         " with normal ones." << endl;
1973                         } else
1974                                 was_title = true;
1975                 } else if (was_title && !already_title) {
1976                         LFile += "\\maketitle\n";
1977                         texrow.newline();
1978                         already_title = true;
1979                         was_title = false;                  
1980                 }
1981                 // We are at depth 0 so we can just use
1982                 // ordinary \footnote{} generation
1983                 // flag this with ftcount
1984                 ftcount = -1;
1985                 if (layout->isEnvironment()
1986                     || par->pextra_type != PEXTRA_NONE) {
1987                         par = par->TeXEnvironment(LFile, texrow,
1988                                                   ftnote, ft_texrow, ftcount);
1989                 } else {
1990                         par = par->TeXOnePar(LFile, texrow,
1991                                              ftnote, ft_texrow, ftcount);
1992                 }
1993
1994                 // Write out what we've generated...and reset LFile
1995                 if (ftcount >= 1) {
1996                         if (ftcount > 1) {
1997                                 LFile += "\\addtocounter{footnote}{-";
1998                                 LFile += tostr(ftcount - 1);
1999                                 LFile += '}';
2000                         }
2001                         LFile += ftnote;
2002                         texrow += ft_texrow;
2003                         ftnote.clear();
2004                         ft_texrow.reset();
2005                         ftcount = 0;
2006                 }
2007                 if (loop_count == 2) {
2008                         // fwrite()ing every second time through the loop
2009                         // gains a few extra % of speed; going higher than
2010                         // 2 will slow things down again.  I'll look at
2011                         // LFile.length() in a future revision.  ARRae
2012                         fwrite(LFile.c_str(), sizeof(char),
2013                                LFile.length(), file);
2014                         LFile.clear();
2015                         loop_count = 0;
2016                 }
2017         }
2018
2019         // It might be that we only have a title in this document
2020         if (was_title && !already_title) {
2021                 LFile += "\\maketitle\n";
2022                 texrow.newline();
2023         }
2024
2025         if (!only_body) {
2026                 LFile += "\\end{document}\n";
2027                 texrow.newline();
2028         
2029                 lyxerr[Debug::LATEX] << "makeLaTeXFile...done" << endl;
2030         } else {
2031                 lyxerr[Debug::LATEX] << "LaTeXFile for inclusion made."
2032                                      << endl;
2033         }
2034
2035         // Just to be sure. (Asger)
2036         texrow.newline();
2037
2038         // Write out what we've generated...and reset LFile
2039         fwrite(LFile.c_str(), sizeof(char), LFile.length(), file);
2040         LFile.clear();
2041
2042         // tex_code_break_column's value is used to decide
2043         // if we are in batchmode or not (within mathed_write()
2044         // in math_write.C) so we must set it to a non-zero
2045         // value when we leave otherwise we save incorrect .lyx files.
2046         tex_code_break_column = lyxrc->ascii_linelen;
2047
2048         if (file.close()) {
2049                 WriteFSAlert(_("Error! Could not close file properly:"), filename);
2050         }
2051         lyxerr.debug() << "Finished making latex file." << endl;
2052 }
2053
2054
2055 bool Buffer::isLatex()
2056 {
2057         return lyxstyle.TextClass(params.textclass)->output_type == LATEX;
2058 }
2059
2060
2061 bool Buffer::isLinuxDoc()
2062 {
2063         return lyxstyle.TextClass(params.textclass)->output_type == LINUXDOC;
2064 }
2065
2066
2067 bool Buffer::isLiterate()
2068 {
2069         return lyxstyle.TextClass(params.textclass)->output_type == LITERATE;
2070 }
2071
2072
2073 bool Buffer::isDocBook()
2074 {
2075         return lyxstyle.TextClass(params.textclass)->output_type == DOCBOOK;
2076 }
2077
2078
2079 bool Buffer::isSGML()
2080 {
2081         return lyxstyle.TextClass(params.textclass)->output_type == LINUXDOC ||
2082                lyxstyle.TextClass(params.textclass)->output_type == DOCBOOK;
2083 }
2084
2085
2086 void Buffer::sgmlOpenTag(FILE * file,int depth,string & latexname)
2087 {
2088         static char *space[] = {" ","  ","   ","    ","     ","      ","       ",
2089                          "        ","         ","          ","          "};
2090
2091         fprintf(file,"%s<%s>\n",space[depth],latexname.c_str());
2092 }
2093
2094
2095 void Buffer::sgmlCloseTag(FILE * file,int depth,string & latexname)
2096 {
2097         static char *space[] = {" ","  ","   ","    ","     ","      ","       ",
2098                          "        ","         ","          ","          "};
2099
2100         fprintf(file,"%s</%s>\n",space[depth],latexname.c_str());
2101 }
2102
2103
2104 void Buffer::makeLinuxDocFile(string const & filename, int column)
2105 {
2106         LyXParagraph *par = paragraph;
2107
2108         string top_element=lyxstyle.LatexnameOfClass(params.textclass);
2109         string environment_stack[10];
2110         string item_name;
2111
2112         int depth=0;              /* paragraph depth */
2113
2114         FilePtr file(filename, FilePtr::write);
2115         tex_code_break_column = column; 
2116
2117         if (!file()) {
2118                 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), filename);
2119                 return;
2120         }
2121    
2122         //ResetTexRow();
2123         texrow.reset();
2124    
2125         if (params.preamble.empty()) {
2126                 fprintf(file, "<!doctype linuxdoc system>\n\n");
2127         }
2128         else {
2129                 fprintf(file, "<!doctype linuxdoc system \n [ %s \n]>\n\n", 
2130                         params.preamble.c_str() );
2131         }
2132
2133         string userName(getUserName());
2134         fprintf(file, "<!-- LinuxDoc file was created by LyX 1.0 (C) 1995-1999 ");
2135         fprintf(file, "by <%s> %s -->\n", userName.c_str(), (char *)date());
2136
2137         if(params.options.empty())
2138                 sgmlOpenTag(file,0,top_element);
2139         else {
2140                 string top = top_element;
2141                 top += " ";
2142                 top += params.options;
2143                 sgmlOpenTag(file,0,top);
2144         }
2145
2146         while (par) {
2147                 int desc_on=0;            /* description mode*/
2148                 LyXLayout *style=lyxstyle.Style(GetCurrentTextClass(), par->layout);
2149                 par->AutoDeleteInsets();
2150
2151                 /* treat <toc> as a special case for compatibility with old code */
2152                 if (par->GetChar(0) == LYX_META_INSET) {
2153                         Inset *inset = par->GetInset(0);
2154                         char  lyx_code = inset->LyxCode();
2155                         if (lyx_code ==Inset::TOC_CODE){
2156                                 string temp= "toc";
2157                                 sgmlOpenTag(file, depth, temp);
2158
2159                                 par = par->next;
2160                                 linuxDocHandleFootnote(file, par, depth);
2161                                 continue;
2162                         }
2163                 }
2164
2165                 /* environment tag closing */
2166                 for( ;depth > par->depth; depth--) {
2167                         sgmlCloseTag(file,depth,environment_stack[depth]);
2168                         environment_stack[depth].clear();
2169                 }
2170
2171                 /* write opening SGML tags */
2172                 switch(style->latextype) {
2173                 case LATEX_PARAGRAPH:
2174                         if(depth == par->depth 
2175                            && !environment_stack[depth].empty()) {
2176                                 sgmlCloseTag(file,depth,environment_stack[depth]);
2177                                 environment_stack[depth].clear();
2178                                 if(depth) 
2179                                         depth--;
2180                                 else
2181                                         fprintf(file,"</p>");
2182                         }
2183                         sgmlOpenTag(file,depth,style->latexname);
2184                         break;
2185
2186                 case LATEX_COMMAND:
2187                         if (depth!=0)
2188                                 LinuxDocError(par, 0, _("Error : Wrong depth for LatexType Command.\n"));
2189
2190                         if (!environment_stack[depth].empty()){
2191                                 sgmlCloseTag(file,depth,environment_stack[depth]);
2192                                 fprintf(file, "</p>");
2193                         }
2194
2195                         environment_stack[depth].clear();
2196                         sgmlOpenTag(file,depth, style->latexname);
2197                         break;
2198
2199                 case LATEX_ENVIRONMENT:
2200                 case LATEX_ITEM_ENVIRONMENT:
2201                         if(depth == par->depth 
2202                            && environment_stack[depth]!=style->latexname 
2203                            && !environment_stack[depth].empty()) {
2204
2205                                 sgmlCloseTag(file,depth,environment_stack[depth]);
2206                                 environment_stack[depth].clear();
2207                         }
2208                         if (depth < par->depth) {
2209                                depth = par->depth;
2210                                environment_stack[depth].clear();
2211                         }
2212                         if (environment_stack[depth] != style->latexname) {
2213                                 if(depth==0) {
2214                                         string temp="p";
2215                                         sgmlOpenTag(file,depth,temp);
2216                                 }
2217                                 environment_stack[depth]= style->latexname;
2218                                 sgmlOpenTag(file,depth,environment_stack[depth]);
2219                         }
2220                         if(style->latextype == LATEX_ENVIRONMENT) break;
2221
2222                         desc_on =(style->labeltype == LABEL_MANUAL);
2223
2224                         if(desc_on)
2225                                 item_name="tag";
2226                         else
2227                                 item_name="item";
2228
2229                         sgmlOpenTag(file,depth+1,item_name);
2230                         break;
2231                 default:
2232                         sgmlOpenTag(file,depth,style->latexname);
2233                         break;
2234                 }
2235
2236                 do {
2237                         SimpleLinuxDocOnePar(file, par, desc_on, depth);
2238
2239                         par = par->next;
2240                         linuxDocHandleFootnote(file,par,depth);
2241                 }
2242                 while(par && par->IsDummy());
2243
2244                 fprintf(file,"\n");
2245                 /* write closing SGML tags */
2246                 switch(style->latextype) {
2247                 case LATEX_COMMAND:
2248                 case LATEX_ENVIRONMENT:
2249                 case LATEX_ITEM_ENVIRONMENT:
2250                         break;
2251                 default:
2252                         sgmlCloseTag(file,depth,style->latexname);
2253                         break;
2254                 }
2255
2256
2257         }
2258    
2259         
2260         /* Close open tags */
2261         for(;depth>0;depth--)
2262                 sgmlCloseTag(file,depth,environment_stack[depth]);
2263
2264         if(!environment_stack[depth].empty())
2265                 sgmlCloseTag(file,depth,environment_stack[depth]);
2266
2267         fprintf(file, "\n\n");
2268         sgmlCloseTag(file,0,top_element);
2269
2270         if (file.close()) {
2271                 WriteFSAlert(_("Error! Could not close file properly:"),
2272                              filename);
2273         }
2274 }
2275
2276
2277 void Buffer::linuxDocHandleFootnote(FILE *file,LyXParagraph* &par, int const depth)
2278 {
2279         string tag="footnote";
2280
2281         while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2282                 sgmlOpenTag(file,depth+1,tag);
2283                 SimpleLinuxDocOnePar(file, par, 0,depth+1);
2284                 sgmlCloseTag(file,depth+1,tag);
2285                 par = par->next;
2286         }
2287 }
2288
2289 void Buffer::DocBookHandleCaption(FILE *file, string &inner_tag,
2290                                   int const depth, int desc_on,
2291                                   LyXParagraph* &par)
2292 {
2293         LyXParagraph *tpar = par;
2294         string tmp_par, extra_par;
2295         while (tpar && (tpar->footnoteflag != LyXParagraph::NO_FOOTNOTE) &&
2296                (tpar->layout != lyxstyle.NumberOfLayout(params.textclass,"Caption")))
2297                 tpar = tpar->next;
2298         if (tpar &&
2299             tpar->layout==lyxstyle.NumberOfLayout(params.textclass,"Caption")) {
2300                 sgmlOpenTag(file,depth+1,inner_tag);
2301             SimpleDocBookOnePar(tmp_par,extra_par,tpar,desc_on,depth+2);
2302                tmp_par = strip(tmp_par);
2303                tmp_par = frontStrip(tmp_par);
2304                fprintf(file,"%s",tmp_par.c_str());
2305                sgmlCloseTag(file,depth+1,inner_tag);
2306                if(!extra_par.empty())
2307                        fprintf(file,"%s",extra_par.c_str());
2308        }
2309 }
2310
2311 void Buffer::DocBookHandleFootnote(FILE *file,LyXParagraph* &par, int const depth)
2312 {
2313         string tag,inner_tag;
2314         string tmp_par,extra_par;
2315         bool inner_span = false;
2316         int desc_on=4;
2317
2318         // This is not how I like to see enums. They should not be anonymous
2319         // and variables of its type should not be declared right after the
2320         // last brace. (Lgb)
2321         enum {
2322                 NO_ONE,
2323                 FOOTNOTE_LIKE,
2324                 MARGIN_LIKE,
2325                 FIG_LIKE,
2326                 TAB_LIKE
2327         } last=NO_ONE, present=FOOTNOTE_LIKE;
2328
2329         while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2330                 if(last==present) {
2331                         if(inner_span) {
2332                                 if(!tmp_par.empty()) {
2333                                         fprintf(file,"%s",tmp_par.c_str());
2334                                         tmp_par.clear();
2335                                         sgmlCloseTag(file,depth+1,inner_tag);
2336                                         sgmlOpenTag(file,depth+1,inner_tag);
2337                                 }
2338                         }
2339                         else
2340                                 fprintf(file,"\n");
2341                 } else {
2342                         fprintf(file,"%s",tmp_par.c_str());
2343                         if(!inner_tag.empty()) sgmlCloseTag(file,depth+1,inner_tag);
2344                         if(!extra_par.empty()) fprintf(file,"%s",extra_par.c_str());
2345                         if(!tag.empty()) sgmlCloseTag(file,depth,tag);
2346                         extra_par.clear();
2347
2348                         switch (par->footnotekind) {
2349                         case LyXParagraph::FOOTNOTE:
2350                         case LyXParagraph::ALGORITHM:
2351                                 tag="footnote";
2352                                 inner_tag="para";
2353                                 present=FOOTNOTE_LIKE;
2354                                 inner_span=true;
2355                                 break;
2356                         case LyXParagraph::MARGIN:
2357                                 tag="sidebar";
2358                                 inner_tag="para";
2359                                 present=MARGIN_LIKE;
2360                                 inner_span=true;
2361                                 break;
2362                         case LyXParagraph::FIG:
2363                         case LyXParagraph::WIDE_FIG:
2364                                 tag="figure";
2365                                 inner_tag="title";
2366                                 present=FIG_LIKE;
2367                                 inner_span=false;
2368                                 break;
2369                         case LyXParagraph::TAB:
2370                         case LyXParagraph::WIDE_TAB:
2371                                 tag="table";
2372                                 inner_tag="title";
2373                                 present=TAB_LIKE;
2374                                 inner_span=false;
2375                                 break;
2376                         }
2377                         sgmlOpenTag(file,depth,tag);
2378                         if ((present == TAB_LIKE) || (present == FIG_LIKE)) {
2379                                 DocBookHandleCaption(file, inner_tag, depth,
2380                                                      desc_on, par);
2381                                 inner_tag.clear();
2382                         } else {
2383                                 sgmlOpenTag(file,depth+1,inner_tag);
2384                         }
2385                 }
2386                 // ignore all caption here, we processed them above!!!
2387                 if (par->layout != lyxstyle.NumberOfLayout(params.textclass,
2388                                                            "Caption")) {
2389                         SimpleDocBookOnePar(tmp_par,extra_par,par,
2390                                             desc_on,depth+2);
2391                 }
2392                 tmp_par = frontStrip(strip(tmp_par));
2393
2394                 last=present;
2395                 par = par->next;
2396         }
2397         fprintf(file,"%s",tmp_par.c_str());
2398         if(!inner_tag.empty()) sgmlCloseTag(file,depth+1,inner_tag);
2399         if(!extra_par.empty()) fprintf(file,"%s",extra_par.c_str());
2400         if(!tag.empty()) sgmlCloseTag(file,depth,tag);
2401
2402 }
2403
2404
2405 /* push a tag in a style stack */
2406 void Buffer::push_tag(FILE *file, char const *tag,
2407                       int& pos, char stack[5][3])
2408 {
2409         int j;
2410
2411         /* pop all previous tags */
2412         for (j=pos; j>=0; j--)
2413                 fprintf(file, "</%s>", stack[j]); 
2414
2415         /* add new tag */
2416         sprintf(stack[++pos], "%s", tag);
2417
2418         /* push all tags */
2419         for (j=0; j<=pos; j++)
2420                 fprintf(file, "<%s>", stack[j]);
2421 }
2422
2423
2424 // pop a tag from a style stack
2425 void Buffer::pop_tag(FILE *file, char const * tag,
2426                      int& pos, char stack[5][3])
2427 {
2428         int j;
2429
2430         // pop all tags till specified one
2431         for (j=pos; (j>=0) && (strcmp(stack[j], tag)); j--)
2432                 fprintf(file, "</%s>", stack[j]);
2433
2434         // closes the tag
2435         fprintf(file, "</%s>", tag);
2436
2437         // push all tags, but the specified one
2438         for (j=j+1; j<=pos; j++) {
2439                 fprintf(file, "<%s>", stack[j]);
2440                 strcpy(stack[j-1], stack[j]);
2441         }
2442         pos --;
2443 }
2444
2445
2446 /* handle internal paragraph parsing -- layout already processed */
2447
2448 // checks, if newcol chars should be put into this line
2449 // writes newline, if necessary.
2450 static
2451 void linux_doc_line_break(FILE *file, unsigned int &colcount, const unsigned int newcol)
2452 {
2453         colcount += newcol;
2454         if (colcount > lyxrc->ascii_linelen) {
2455                 fprintf(file, "\n");
2456                 colcount = newcol; // assume write after this call
2457         }
2458 }
2459
2460
2461 void Buffer::SimpleLinuxDocOnePar(FILE *file, LyXParagraph *par, int desc_on, int const depth)
2462 {
2463         LyXFont font1,font2;
2464         char c;
2465         Inset *inset;
2466         int main_body, j;
2467         LyXLayout * style = lyxstyle.Style(params.textclass, par->GetLayout());
2468
2469         char family_type = 0;               // family font flag 
2470         bool is_bold     = false;           // series font flag 
2471         char shape_type  = 0;               // shape font flag 
2472         bool is_em = false;                 // emphasis (italic) font flag 
2473
2474         int stack_num = -1;          // style stack position 
2475         char stack[5][3];            // style stack 
2476         unsigned int char_line_count = 5;     // Heuristic choice ;-) 
2477
2478         if (style->labeltype != LABEL_MANUAL)
2479                 main_body = 0;
2480         else
2481                 main_body = par->BeginningOfMainBody();
2482
2483         /* gets paragraph main font */
2484         if (main_body > 0)
2485                 font1 = style->labelfont;
2486         else
2487                 font1 = style->font;
2488
2489   
2490         /* parsing main loop */
2491         for (int i = 0; i < par->last; i++) {
2492
2493                 /* handle quote tag */
2494                 if (i == main_body && !par->IsDummy()) {
2495                         if (main_body > 0)
2496                                 font1 = style->font;
2497                 }
2498
2499                 font2 = par->getFont(i);
2500
2501                 if (font1.family() != font2.family()) {
2502                         switch(family_type) {
2503                         case 0:
2504                                 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2505                                         push_tag(file, "tt", stack_num, stack);
2506                                         family_type=1;
2507                                 }
2508                                 else if (font2.family() == LyXFont::SANS_FAMILY) {
2509                                         push_tag(file, "sf", stack_num, stack);
2510                                         family_type=2;
2511                                 }
2512                                 break;
2513                         case 1:
2514                                 pop_tag(file, "tt", stack_num, stack);
2515                                 if (font2.family() == LyXFont::SANS_FAMILY) {
2516                                         push_tag(file, "sf", stack_num, stack);
2517                                         family_type=2;
2518                                 }
2519                                 else {
2520                                         family_type=0;
2521                                 }
2522                                 break;
2523                         case 2:
2524                                 pop_tag(file, "sf", stack_num, stack);
2525                                 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2526                                         push_tag(file, "tt", stack_num, stack);
2527                                         family_type=1;
2528                                 }
2529                                 else {
2530                                         family_type=0;
2531                                 }
2532                         }
2533                 }
2534
2535                 /* handle bold face */
2536                 if (font1.series() != font2.series()) {
2537                         if (font2.series() == LyXFont::BOLD_SERIES) {
2538                                 push_tag(file, "bf", stack_num, stack);
2539                                 is_bold = true;
2540                         }
2541                         else if (is_bold) {
2542                                 pop_tag(file, "bf", stack_num, stack);
2543                                 is_bold = false;
2544                         }
2545                 }
2546
2547                 /* handle italic and slanted fonts */
2548                 if (font1.shape() != font2.shape()) {
2549                         switch(shape_type) {
2550                         case 0:
2551                                 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2552                                         push_tag(file, "it", stack_num, stack);
2553                                         shape_type=1;
2554                                 }
2555                                 else if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2556                                         push_tag(file, "sl", stack_num, stack);
2557                                         shape_type=2;
2558                                 }
2559                                 break;
2560                         case 1:
2561                                 pop_tag(file, "it", stack_num, stack);
2562                                 if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2563                                         push_tag(file, "sl", stack_num, stack);
2564                                         shape_type=2;
2565                                 }
2566                                 else {
2567                                         shape_type=0;
2568                                 }
2569                                 break;
2570                         case 2:
2571                                 pop_tag(file, "sl", stack_num, stack);
2572                                 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2573                                         push_tag(file, "it", stack_num, stack);
2574                                         shape_type=1;
2575                                 }
2576                                 else {
2577                                         shape_type=0;
2578                                 }
2579                         }
2580                 }
2581                 /* handle <em> tag */
2582                 if (font1.emph() != font2.emph()) {
2583                         if (font2.emph() == LyXFont::ON) {
2584                                 push_tag(file, "em", stack_num, stack);
2585                                 is_em = true;
2586                         } else if (is_em) {
2587                                 pop_tag(file, "em", stack_num, stack);
2588                                 is_em = false;
2589                         }
2590                 }
2591
2592                 c = par->GetChar(i);
2593       
2594                 if (font2.latex() == LyXFont::ON) {
2595                         // "TeX"-Mode on ==> SGML-Mode on.
2596                         if (c!='\0')
2597                                 fprintf(file, "%c", c); // see LaTeX-Generation...
2598                         char_line_count++;
2599                 } else if (c == LYX_META_INSET) {
2600                         inset = par->GetInset(i);
2601                         string tmp_out;
2602                         inset->Linuxdoc(tmp_out);
2603                         fprintf(file,"%s",tmp_out.c_str());
2604                 }
2605                 else {
2606                         string sgml_string;
2607                         if (par->linuxDocConvertChar(c, sgml_string)
2608                             && !style->free_spacing) { // in freespacing
2609                                                      // mode, spaces are
2610                                                      // non-breaking characters
2611                                 // char is ' '
2612                                 if (desc_on == 1) {
2613                                         char_line_count++;
2614                                         linux_doc_line_break(file, char_line_count, 6);
2615                                         fprintf(file, "</tag>");
2616                                         desc_on = 2;
2617                                 }
2618                                 else  {
2619                                         linux_doc_line_break(file, char_line_count, 1);
2620                                         fprintf(file, "%c", c);
2621                                 }
2622                         }
2623                         else {
2624                                 fprintf(file, "%s", sgml_string.c_str());
2625                                 char_line_count += sgml_string.length();
2626                         }
2627                 }
2628                 font1 = font2;
2629         }
2630
2631         /* needed if there is an optional argument but no contents */ 
2632         if (main_body > 0 && main_body == par->last) {
2633                 font1 = style->font;
2634         }
2635
2636         /* pop all defined Styles */
2637         for (j=stack_num; j>=0; j--) {
2638                 linux_doc_line_break(file, 
2639                                      char_line_count, 
2640                                      3+strlen(stack[j]));
2641                 fprintf(file, "</%s>", stack[j]);
2642         }
2643
2644         /* resets description flag correctly */
2645         switch(desc_on){
2646         case 1:
2647                 /* <tag> not closed... */
2648                 linux_doc_line_break(file, char_line_count, 6);
2649                 fprintf(file, "</tag>");
2650                 break;
2651         case 2:
2652                 /* fprintf(file, "</p>");*/
2653                 break;
2654         }
2655 }
2656
2657
2658 /* print an error message */
2659 void Buffer::LinuxDocError(LyXParagraph *par, int pos,
2660                            char const *message) 
2661 {
2662         InsetError *new_inset;
2663
2664         /* insert an error marker in text */
2665         new_inset = new InsetError(message);
2666         par->InsertChar(pos, LYX_META_INSET);
2667         par->InsertInset(pos, new_inset);
2668 }
2669
2670 // This constant defines the maximum number of 
2671 // environment layouts that can be nesteded.
2672 // The same applies for command layouts.
2673 // These values should be more than enough.
2674 //           José Matos (1999/07/22)
2675
2676 enum { MAX_NEST_LEVEL = 25};
2677
2678 void Buffer::makeDocBookFile(string const & filename, int column)
2679 {
2680         LyXParagraph *par = paragraph;
2681
2682         string top_element=lyxstyle.LatexnameOfClass(params.textclass);
2683         string environment_stack[MAX_NEST_LEVEL];
2684         string environment_inner[MAX_NEST_LEVEL];
2685         string command_stack[MAX_NEST_LEVEL];
2686         bool command_flag=false;
2687         int command_depth=0,command_base=0,cmd_depth=0;
2688
2689         string item_name,command_name;
2690         string c_depth,c_params,tmps;
2691
2692         int depth=0;              /* paragraph depth */
2693
2694         FilePtr file(filename, FilePtr::write);
2695         tex_code_break_column = column; 
2696
2697         if (!file()) {
2698                 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), filename);
2699                 return;
2700         }
2701    
2702         //ResetTexRow();
2703         texrow.reset();
2704
2705         fprintf(file, "<!doctype %s public \"-//OASIS//DTD DocBook V3.1//EN\"",top_element.c_str());
2706
2707         if (params.preamble.empty())
2708                 fprintf(file, ">\n\n");
2709         else
2710                 fprintf(file, "\n [ %s \n]>\n\n",params.preamble.c_str() );
2711
2712         string userName(getUserName());
2713         fprintf(file,
2714                 "<!-- DocBook file was created by LyX 1.0 (C) 1995-1999\n");
2715         fprintf(file, "by <%s> %s -->\n", userName.c_str(), (char *)date());
2716
2717         if(params.options.empty())
2718                 sgmlOpenTag(file,0,top_element);
2719         else {
2720                 string top = top_element;
2721                 top += " ";
2722                 top += params.options;
2723                 sgmlOpenTag(file,0,top);
2724         }
2725
2726         while (par) {
2727                 int desc_on=0;            /* description mode*/
2728                 LyXLayout * style = lyxstyle.Style(GetCurrentTextClass(),
2729                                                    par->layout);
2730                 par->AutoDeleteInsets();
2731
2732                 /* environment tag closing */
2733                 for( ;depth > par->depth; depth--) {
2734                         if(environment_inner[depth] != "!-- --") {
2735                                 item_name="listitem";
2736                                 sgmlCloseTag(file,command_depth+depth,
2737                                              item_name);
2738                                 if( environment_inner[depth] == "varlistentry")
2739                                         sgmlCloseTag(file,depth+command_depth,
2740                                                      environment_inner[depth]);
2741                         }
2742                         sgmlCloseTag(file,depth+command_depth,
2743                                      environment_stack[depth]);
2744                         environment_stack[depth].clear();
2745                         environment_inner[depth].clear();
2746                 }
2747
2748                 if(depth == par->depth
2749                    && environment_stack[depth]!=style->latexname 
2750                    && !environment_stack[depth].empty()) {
2751                         if(environment_inner[depth] != "!-- --") {
2752                                 item_name="listitem";
2753                                 sgmlCloseTag(file,command_depth+depth,
2754                                              item_name);
2755                                 if( environment_inner[depth] == "varlistentry")
2756                                         sgmlCloseTag(file,depth+command_depth,
2757                                                      environment_inner[depth]);
2758                         }
2759                         
2760                         sgmlCloseTag(file,depth+command_depth,
2761                                      environment_stack[depth]);
2762                         
2763                         environment_stack[depth].clear();
2764                         environment_inner[depth].clear();
2765                 }
2766
2767                 // Write opening SGML tags.
2768                 switch(style->latextype) {
2769                 case LATEX_PARAGRAPH:
2770                         if(style->latexname != "dummy")
2771                                sgmlOpenTag(file, depth+command_depth,
2772                                            style->latexname);
2773                         break;
2774
2775                 case LATEX_COMMAND:
2776                         if (depth!=0)
2777                                 LinuxDocError(par, 0,
2778                                               _("Error : Wrong depth for "
2779                                                 "LatexType Command.\n"));
2780                         
2781                         command_name=style->latexname;
2782                         
2783                         tmps=style->latexparam;
2784                         c_params= split(tmps, c_depth,'|');
2785                         
2786                         cmd_depth=atoi(c_depth.c_str());
2787                         
2788                         if(command_flag) {
2789                                 if(cmd_depth<command_base) {
2790                                         for(int j = command_depth;
2791                                             j >= command_base; j--)
2792                                                 if(!command_stack[j].empty())
2793                                                         sgmlCloseTag(file,j,command_stack[j]);
2794                                         command_depth=command_base=cmd_depth;
2795                                 }
2796                                 else if(cmd_depth<=command_depth) {
2797                                         for(int j= command_depth;
2798                                             j >= cmd_depth; j--)
2799
2800                                                 if(!command_stack[j].empty())
2801                                                         sgmlCloseTag(file,j,command_stack[j]);
2802                                         command_depth=cmd_depth;
2803                                 }
2804                                 else
2805                                         command_depth=cmd_depth;
2806                         }
2807                         else {
2808                                 command_depth = command_base = cmd_depth;
2809                                 command_flag = true;
2810                         }
2811                         command_stack[command_depth]=command_name;
2812
2813                         // treat label as a special case for
2814                         // more WYSIWYM handling.
2815                         if (par->GetChar(0) == LYX_META_INSET) {
2816                                 Inset *inset = par->GetInset(0);
2817                                 char  lyx_code = inset->LyxCode();
2818                                 if (lyx_code ==Inset::LABEL_CODE){
2819                                         command_name+= " id=\"";
2820                                         command_name+=((InsetCommand *) inset)->getContents();
2821                                         command_name+="\"";
2822                                         desc_on=3;
2823                                 }
2824                         }
2825
2826                         sgmlOpenTag(file,depth+command_depth, command_name);
2827                         item_name="title";
2828                         sgmlOpenTag(file,depth+1+command_depth,item_name);
2829                         break;
2830
2831                 case LATEX_ENVIRONMENT:
2832                 case LATEX_ITEM_ENVIRONMENT:
2833                         if (depth < par->depth) {
2834                                 depth = par->depth;
2835                                 environment_stack[depth].clear();
2836                         }
2837
2838                         if (environment_stack[depth] != style->latexname) {
2839                                 environment_stack[depth]= style->latexname;
2840                                 environment_inner[depth]= "!-- --";
2841                                 sgmlOpenTag(file, depth + command_depth,
2842                                             environment_stack[depth]);
2843                         } else {
2844                                 if(environment_inner[depth] != "!-- --") {
2845                                         item_name="listitem";
2846                                         sgmlCloseTag(file,
2847                                                      command_depth + depth,
2848                                                      item_name);
2849                                         if (environment_inner[depth] == "varlistentry")
2850                                                 sgmlCloseTag(file,
2851                                                              depth+command_depth,
2852                                                              environment_inner[depth]);
2853                                 }
2854                         }
2855                         
2856                         if(style->latextype == LATEX_ENVIRONMENT) {
2857                                 if(!style->latexparam.empty())
2858                                         sgmlOpenTag(file, depth+command_depth,
2859                                                     style->latexparam);
2860                                 break;
2861                         }
2862
2863                         desc_on =(style->labeltype == LABEL_MANUAL);
2864
2865                         if(desc_on)
2866                                 environment_inner[depth]="varlistentry";
2867                         else
2868                                 environment_inner[depth]="listitem";
2869
2870                         sgmlOpenTag(file,depth+1+command_depth,
2871                                     environment_inner[depth]);
2872
2873                         if(desc_on) {
2874                                 item_name="term";
2875                                 sgmlOpenTag(file,depth+1+command_depth,
2876                                             item_name);
2877                         }
2878                         else {
2879                                 item_name="para";
2880                                 sgmlOpenTag(file,depth+1+command_depth,
2881                                             item_name);
2882                         }
2883                         break;
2884                 default:
2885                         sgmlOpenTag(file,depth+command_depth,style->latexname);
2886                         break;
2887                 }
2888
2889                 do {
2890                         string tmp_par,extra_par;
2891
2892                         SimpleDocBookOnePar(tmp_par,extra_par, par, desc_on,
2893                                             depth+1+command_depth);
2894                         fprintf(file,"%s",tmp_par.c_str());
2895
2896                         par = par->next;
2897                         DocBookHandleFootnote(file,par, depth+1+command_depth);
2898                 }
2899                 while(par && par->IsDummy());
2900
2901                 string end_tag;
2902                 /* write closing SGML tags */
2903                 switch(style->latextype) {
2904                 case LATEX_COMMAND:
2905                         end_tag="title";
2906                         sgmlCloseTag(file,depth+command_depth,end_tag);
2907                         break;
2908                 case LATEX_ENVIRONMENT:
2909                         if(!style->latexparam.empty())
2910                                 sgmlCloseTag(file,depth+command_depth,
2911                                              style->latexparam);
2912                         break;
2913                 case LATEX_ITEM_ENVIRONMENT:
2914                         if(desc_on==1) break;
2915                         end_tag="para";
2916                         sgmlCloseTag(file,depth+1+command_depth,end_tag);
2917                         break;
2918                 case LATEX_PARAGRAPH:
2919                         if( style->latexname != "dummy")
2920                                 sgmlCloseTag(file,depth+command_depth,
2921                                              style->latexname);
2922                         break;
2923                 default:
2924                         sgmlCloseTag(file,depth+command_depth,
2925                                      style->latexname);
2926                         break;
2927                 }
2928         }
2929
2930         // Close open tags
2931         for(;depth>=0;depth--) {
2932                 if(!environment_stack[depth].empty()) {
2933                         if(environment_inner[depth] != "!-- --") {
2934                                 item_name="listitem";
2935                                 sgmlCloseTag(file,command_depth+depth,
2936                                              item_name);
2937                                if( environment_inner[depth] == "varlistentry")
2938                                        sgmlCloseTag(file,depth+command_depth,
2939                                                     environment_inner[depth]);
2940                         }
2941                         
2942                         sgmlCloseTag(file,depth+command_depth,
2943                                      environment_stack[depth]);
2944                 }
2945         }
2946         
2947         for(int j=command_depth;j>=command_base;j--)
2948                 if(!command_stack[j].empty())
2949                         sgmlCloseTag(file,j,command_stack[j]);
2950
2951         fprintf(file, "\n\n");
2952         sgmlCloseTag(file,0,top_element);
2953
2954         if (file.close()) {
2955                 WriteFSAlert(_("Error! Could not close file properly:"),
2956                              filename);
2957         }
2958 }
2959
2960
2961 void Buffer::SimpleDocBookOnePar(string & file, string & extra,
2962                                  LyXParagraph * par, int & desc_on,
2963                                  int const depth) 
2964 {
2965         if (par->table) {
2966                 par->SimpleDocBookOneTablePar(file, extra, desc_on, depth);
2967                 return;
2968         }
2969         LyXFont font1,font2;
2970         char c;
2971         Inset *inset;
2972         int main_body, j;
2973         string emph="emphasis";
2974         bool emph_flag=false;
2975         int char_line_count=0;
2976
2977         LyXLayout * style = lyxstyle.Style(params.textclass, par->GetLayout());
2978
2979         if (style->labeltype != LABEL_MANUAL)
2980                 main_body = 0;
2981         else
2982                 main_body = par->BeginningOfMainBody();
2983
2984         /* gets paragraph main font */
2985         if (main_body > 0)
2986                 font1 = style->labelfont;
2987         else
2988                 font1 = style->font;
2989
2990         char_line_count = depth;
2991         if(!style->free_spacing)
2992                 for (j=0;j< depth;j++)
2993                         file += ' ';
2994
2995         /* parsing main loop */
2996         for (int i = 0; i < par->last; i++) {
2997
2998                 font2 = par->getFont(i);
2999
3000                 /* handle <emphasis> tag */
3001                 if (font1.emph() != font2.emph() && i) {
3002                         if (font2.emph() == LyXFont::ON) {
3003                                 file += "<emphasis>";
3004                                 emph_flag=true;
3005                         }else {
3006                                 file += "</emphasis>";
3007                                 emph_flag=false;
3008                         }
3009                 }
3010       
3011                 c = par->GetChar(i);
3012
3013                 if (c == LYX_META_INSET) {
3014                         inset = par->GetInset(i);
3015                         string tmp_out;
3016                         inset->DocBook(tmp_out);
3017                         //
3018                         // This code needs some explanation:
3019                         // Two insets are treated specially
3020                         //   label if it is the first element in a command paragraph
3021                         //         desc_on==3
3022                         //   graphics inside tables or figure floats can't go on
3023                         //   title (the equivalente in latex for this case is caption
3024                         //   and title should come first
3025                         //         desc_on==4
3026                         //
3027                         if(desc_on!=3 || i!=0) {
3028                                 if(tmp_out[0]=='@') {
3029                                         if(desc_on==4)
3030                                                 extra += frontStrip(tmp_out, '@');
3031                                         else
3032                                                 file += frontStrip(tmp_out, '@');
3033                                 }
3034                                 else
3035                                         file += tmp_out;
3036                         }
3037                 } else if (font2.latex() == LyXFont::ON) {
3038                         // "TeX"-Mode on ==> SGML-Mode on.
3039                         if (c!='\0')
3040                                 file += c;
3041                         char_line_count++;
3042                 }
3043                 else {
3044                         string sgml_string;
3045                         if (par->linuxDocConvertChar(c, sgml_string)
3046                             && !style->free_spacing) { // in freespacing
3047                                                      // mode, spaces are
3048                                                      // non-breaking characters
3049                                 // char is ' '
3050                                 if (desc_on == 1) {
3051                                         char_line_count++;
3052                                         file += '\n';
3053                                         file += "</term><listitem><para>";
3054                                         desc_on = 2;
3055                                 }
3056                                 else  {
3057                                         file += c;
3058                                 }
3059                         }
3060                         else {
3061                                 file += sgml_string;
3062                         }
3063                 }
3064                 font1 = font2;
3065         }
3066
3067         /* needed if there is an optional argument but no contents */ 
3068         if (main_body > 0 && main_body == par->last) {
3069                 font1 = style->font;
3070         }
3071
3072         if (emph_flag) {
3073                 file += "</emphasis>";
3074         }
3075         
3076         /* resets description flag correctly */
3077         switch(desc_on){
3078         case 1:
3079                 /* <term> not closed... */
3080                 file += "</term>";
3081                 break;
3082         }
3083         file += '\n';
3084 }
3085
3086
3087 bool Buffer::removeAutoInsets()
3088 {
3089         LyXParagraph *par = paragraph;
3090
3091         LyXCursor cursor = text->cursor;
3092         LyXCursor tmpcursor = cursor;
3093         cursor.par = tmpcursor.par->ParFromPos(tmpcursor.pos);
3094         cursor.pos = tmpcursor.par->PositionInParFromPos(tmpcursor.pos);
3095
3096         bool a = false;
3097         while (par) {
3098                 if (par->AutoDeleteInsets()){
3099                         a = true;
3100                         if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3101                                 /* this is possible now, since SetCursor takes
3102                                    care about footnotes */
3103                                 text->SetCursorIntern(par, 0);
3104                                 text->RedoParagraphs(text->cursor, text->cursor.par->Next());
3105                                 text->FullRebreak();
3106                         }
3107                 }
3108                 par = par->next;
3109         }
3110         /* avoid forbidden cursor positions caused by error removing */ 
3111         if (cursor.pos > cursor.par->Last())
3112                 cursor.pos = cursor.par->Last();
3113         text->SetCursorIntern(cursor.par, cursor.pos);
3114
3115         return a;
3116 }
3117
3118
3119 int Buffer::runLaTeX()
3120 {
3121         if (!text) return 0;
3122
3123         ProhibitInput();
3124
3125         // get LaTeX-Filename
3126         string name = SpaceLess(ChangeExtension (filename, ".tex", true));
3127
3128         string path = OnlyPath(filename);
3129
3130         string org_path = path;
3131         if (lyxrc->use_tempdir || (IsDirWriteable(path) < 1)) {
3132                 path = tmppath;  
3133         }
3134
3135         Path p(path); // path to LaTeX file
3136         users->getOwner()->getMiniBuffer()->Set(_("Running LaTeX..."));   
3137
3138         // Remove all error insets
3139         bool a = removeAutoInsets();
3140
3141         // generate the LaTeX file if necessary
3142         //if (!isDviClean() || a) {
3143         //      makeLaTeXFile(name, org_path, false);
3144         //      markDviDirty();
3145         //}
3146
3147         // Always generate the LaTeX file
3148         makeLaTeXFile(name, org_path, false);
3149         markDviDirty();
3150
3151         // do the LaTex run(s)
3152         TeXErrors terr;
3153         LaTeX latex(lyxrc->latex_command, name, filepath);
3154         int res = latex.run(terr,users->getOwner()->getMiniBuffer()); // running latex
3155
3156         // check return value from latex.run().
3157         if ((res & LaTeX::NO_LOGFILE)) {
3158                 WriteAlert(_("LaTeX did not work!"),
3159                            _("Missing log file:"), name);
3160         } else if ((res & LaTeX::ERRORS)) {
3161                 users->getOwner()->getMiniBuffer()->Set(_("Done"));
3162                 // Insert all errors as errors boxes
3163                 insertErrors(terr);
3164                 
3165                 // Dvi should also be kept dirty if the latex run
3166                 // ends up with errors. However it should be possible
3167                 // to view a dirty dvi too.
3168         } else {
3169                 //no errors or any other things to think about so:
3170                 users->getOwner()->getMiniBuffer()->Set(_("Done"));
3171                 markDviClean();
3172         }
3173
3174         // if we removed error insets before we ran LaTeX or if we inserted
3175         // error insets after we ran LaTeX this must be run:
3176         if (a || (res & LaTeX::ERRORS)){
3177                 users->redraw();
3178                 users->fitCursor();
3179                 users->updateScrollbar();
3180         }
3181         AllowInput();
3182  
3183         return latex.getNumErrors();
3184 }
3185
3186
3187 int Buffer::runLiterate()
3188 {
3189         if (!text) return 0;
3190
3191         ProhibitInput();
3192
3193         // get LaTeX-Filename
3194         string name = SpaceLess(ChangeExtension (filename, ".tex", true));
3195         // get Literate-Filename
3196         string lit_name = SpaceLess(ChangeExtension (filename, lyxrc->literate_extension, true));
3197
3198         string path = OnlyPath(filename);
3199
3200         string org_path = path;
3201         if (lyxrc->use_tempdir || (IsDirWriteable(path) < 1)) {
3202                 path = tmppath;  
3203         }
3204
3205         Path p(path); // path to Literate file
3206         users->getOwner()->getMiniBuffer()->Set(_("Running Literate..."));   
3207
3208         // Remove all error insets
3209         bool a = removeAutoInsets();
3210
3211         // generate the Literate file if necessary
3212         if (!isDviClean() || a) {
3213                 makeLaTeXFile(lit_name, org_path, false);
3214                 markDviDirty();
3215         }
3216
3217         TeXErrors terr;
3218         Literate literate(lyxrc->latex_command, name, filepath, 
3219                           lit_name,
3220                           lyxrc->literate_command, lyxrc->literate_error_filter,
3221                           lyxrc->build_command, lyxrc->build_error_filter);
3222         int res = literate.weave(terr,users->getOwner()->getMiniBuffer());
3223
3224         // check return value from literate.weave().
3225         if ((res & Literate::NO_LOGFILE)) {
3226                 WriteAlert(_("Literate command did not work!"),
3227                            _("Missing log file:"), name);
3228         } else if ((res & Literate::ERRORS)) {
3229                 users->getOwner()->getMiniBuffer()->Set(_("Done"));
3230                 // Insert all errors as errors boxes
3231                 insertErrors(terr);
3232                 
3233                 // Dvi should also be kept dirty if the latex run
3234                 // ends up with errors. However it should be possible
3235                 // to view a dirty dvi too.
3236         } else {
3237                 //no errors or any other things to think about so:
3238                 users->getOwner()->getMiniBuffer()->Set(_("Done"));
3239                 markDviClean();
3240         }
3241
3242         // if we removed error insets before we ran LaTeX or if we inserted
3243         // error insets after we ran LaTeX this must be run:
3244         if (a || (res & Literate::ERRORS)){
3245                 users->redraw();
3246                 users->fitCursor();
3247                 users->updateScrollbar();
3248         }
3249         AllowInput();
3250  
3251         return literate.getNumErrors();
3252 }
3253
3254
3255 int Buffer::buildProgram()
3256 {
3257         if (!text) return 0;
3258  
3259         ProhibitInput();
3260  
3261         // get LaTeX-Filename
3262         string name = SpaceLess(ChangeExtension (filename, ".tex", true));
3263         // get Literate-Filename
3264         string lit_name = SpaceLess(ChangeExtension (filename, lyxrc->literate_extension, true));
3265  
3266         string path = OnlyPath(filename);
3267  
3268         string org_path = path;
3269         if (lyxrc->use_tempdir || (IsDirWriteable(path) < 1)) {
3270                 path = tmppath;  
3271         }
3272  
3273         Path p(path); // path to Literate file
3274         users->getOwner()->getMiniBuffer()->Set(_("Building Program..."));   
3275  
3276         // Remove all error insets
3277         bool a = removeAutoInsets();
3278  
3279         // generate the LaTeX file if necessary
3280         if (!isNwClean() || a) {
3281                 makeLaTeXFile(lit_name, org_path, false);
3282                 markNwDirty();
3283         }
3284  
3285         TeXErrors terr;
3286         Literate literate(lyxrc->latex_command, name, filepath, 
3287                           lit_name,
3288                           lyxrc->literate_command, lyxrc->literate_error_filter,
3289                           lyxrc->build_command, lyxrc->build_error_filter);
3290         int res = literate.build(terr,users->getOwner()->getMiniBuffer());
3291  
3292         // check return value from literate.build().
3293         if ((res & Literate::NO_LOGFILE)) {
3294                 WriteAlert(_("Build did not work!"),
3295                            _("Missing log file:"), name);
3296         } else if ((res & Literate::ERRORS)) {
3297                 users->getOwner()->getMiniBuffer()->Set(_("Done"));
3298                 // Insert all errors as errors boxes
3299                 insertErrors(terr);
3300                 
3301                 // Literate files should also be kept dirty if the literate 
3302                 // command run ends up with errors.
3303         } else {
3304                 //no errors or any other things to think about so:
3305                 users->getOwner()->getMiniBuffer()->Set(_("Done"));
3306                 markNwClean();
3307         }
3308  
3309         // if we removed error insets before we ran Literate/Build or if we inserted
3310         // error insets after we ran Literate/Build this must be run:
3311         if (a || (res & Literate::ERRORS)){
3312                 users->redraw();
3313                 users->fitCursor();
3314                 users->updateScrollbar();
3315         }
3316         AllowInput();
3317
3318         return literate.getNumErrors();
3319 }
3320
3321
3322 // This should be enabled when the Chktex class is implemented. (Asger)
3323 // chktex should be run with these flags disabled: 3, 22, 25, 30, 38(?)
3324 // Other flags: -wall -v0 -x
3325 int Buffer::runChktex()
3326 {
3327         if (!text) return 0;
3328
3329         ProhibitInput();
3330
3331         // get LaTeX-Filename
3332         string name = SpaceLess(ChangeExtension (filename, ".tex", true));
3333         string path = OnlyPath(filename);
3334
3335         string org_path = path;
3336         if (lyxrc->use_tempdir || (IsDirWriteable(path) < 1)) {
3337                 path = tmppath;  
3338         }
3339
3340         Path p(path); // path to LaTeX file
3341         users->getOwner()->getMiniBuffer()->Set(_("Running chktex..."));
3342
3343         // Remove all error insets
3344         bool a = removeAutoInsets();
3345
3346         // Generate the LaTeX file if neccessary
3347         if (!isDviClean() || a) {
3348                 makeLaTeXFile(name, org_path, false);
3349                 markDviDirty();
3350         }
3351
3352         TeXErrors terr;
3353         Chktex chktex(lyxrc->chktex_command, name, filepath);
3354         int res = chktex.run(terr); // run chktex
3355
3356         if (res == -1) {
3357                 WriteAlert(_("chktex did not work!"),
3358                            _("Could not run with file:"), name);
3359         } else if (res > 0) {
3360                 // Insert all errors as errors boxes
3361                 insertErrors(terr);
3362         }
3363
3364         // if we removed error insets before we ran chktex or if we inserted
3365         // error insets after we ran chktex, this must be run:
3366         if (a || res){
3367                 users->redraw();
3368                 users->fitCursor();
3369                 users->updateScrollbar();
3370         }
3371         AllowInput();
3372
3373         return res;
3374 }
3375
3376
3377 extern void AllFloats(char, char);
3378
3379
3380 void Buffer::insertErrors(TeXErrors &terr)
3381 {
3382         // Save the cursor position
3383         LyXCursor cursor = text->cursor;
3384
3385         // Now traverse all the errors and insert them
3386         bool firsterror = true;
3387         bool more = true;
3388
3389         // This is drastic, but it's the only fix, I could find. (Asger)
3390         AllFloats(1,0);
3391         AllFloats(1,1);
3392
3393         while (more) {
3394                 string errortext;
3395                 int errorrow = 0;
3396
3397                 if (firsterror) {
3398                         more = terr.getFirstError(&errorrow, &errortext);
3399                         firsterror = false;
3400                 } else {
3401                         more = terr.getNextError(&errorrow, &errortext);
3402                 }
3403
3404                 if (!more)
3405                         break;
3406
3407                 // Insert error string for row number
3408                 int tmpid = -1; 
3409                 int tmppos = -1;
3410
3411                 texrow.getIdFromRow(errorrow, tmpid, tmppos);
3412
3413                 LyXParagraph* texrowpar;
3414
3415                 if (tmpid == -1) {
3416                         texrowpar = text->FirstParagraph();
3417                         tmppos = 0;
3418                 } else {
3419                         texrowpar = text->GetParFromID(tmpid);
3420                 }
3421
3422                 if (texrowpar == 0)
3423                         continue;
3424
3425                 InsetError *new_inset = new InsetError(errortext);
3426
3427                 text->SetCursorIntern(texrowpar, tmppos);
3428                 text->InsertInset(new_inset);
3429                 text->FullRebreak();
3430         }
3431         // Restore the cursor position
3432         text->SetCursorIntern(cursor.par, cursor.pos);
3433 }
3434
3435
3436 void Buffer::setCursorFromRow (int row)
3437 {
3438         int tmpid = -1; 
3439         int tmppos = -1;
3440
3441         texrow.getIdFromRow(row, tmpid, tmppos);
3442
3443         LyXParagraph* texrowpar;
3444
3445         if (tmpid == -1) {
3446                 texrowpar = text->FirstParagraph();
3447                 tmppos = 0;
3448         } else {
3449                 texrowpar = text->GetParFromID(tmpid);
3450         }
3451         text->SetCursor(texrowpar, tmppos);
3452 }
3453
3454
3455 void Buffer::RoffAsciiTable(FILE *file, LyXParagraph *par)
3456 {
3457         LyXFont
3458                 font1 =  LyXFont(LyXFont::ALL_INHERIT),
3459                 font2;
3460         Inset
3461                 *inset;
3462         int
3463                 i,j,
3464                 cell = 0;
3465         char
3466                 c;
3467         string
3468                 fname1,
3469                 fname2;
3470         FILE
3471                 *fp,*fp2;
3472         
3473         fname1 = TmpFileName(string(),"RAT1");
3474         fname2 = TmpFileName(string(),"RAT2");
3475         if (!(fp=fopen(fname1.c_str(),"w"))) {
3476                 WriteAlert(_("LYX_ERROR:"),
3477                            _("Cannot open temporary file:"), fname1);
3478                 return;
3479         }
3480         par->table->RoffEndOfCell(fp, -1);
3481         for (i = 0; i < par->last; i++) {
3482                 c = par->GetChar(i);
3483                 if (par->table->IsContRow(cell)) {
3484                         if (c == LYX_META_NEWLINE)
3485                                 cell++;
3486                         continue;
3487                 }
3488                 font2 = par->GetFontSettings(i);
3489                 if (font1.latex() != font2.latex()) {
3490                         if (font2.latex() != LyXFont::OFF)
3491                                 continue;
3492                 }
3493                 switch (c) {
3494                 case LYX_META_INSET:
3495                         if ((inset = par->GetInset(i))) {
3496                                 if (!(fp2=fopen(fname2.c_str(),"w+"))) {
3497                                         WriteAlert(_("LYX_ERROR:"),
3498                                                    _("Cannot open temporary file:"), fname2);
3499                                         fclose(fp);
3500                                         remove(fname1.c_str());
3501                                         return;
3502                                 }
3503                                 inset->Latex(fp2,-1);
3504                                 rewind(fp2);
3505                                 c = fgetc(fp2);
3506                                 while(!feof(fp2)) {
3507                                         if (c == '\\')
3508                                                 fprintf(fp,"\\\\");
3509                                         else
3510                                                 fputc(c,fp);
3511                                         c = fgetc(fp2);
3512                                 }
3513                                 fclose(fp2);
3514                         }
3515                         break;
3516                 case LYX_META_NEWLINE:
3517                         if (par->table->CellHasContRow(cell)>=0)
3518                                 par->RoffContTableRows(fp, i+1,cell);
3519                         par->table->RoffEndOfCell(fp, cell);
3520                         cell++;
3521                         break;
3522                 case LYX_META_HFILL: 
3523                         break;
3524                 case LYX_META_PROTECTED_SEPARATOR:
3525                         break;
3526                 case '\\': 
3527                         fprintf(fp, "\\\\");
3528                         break;
3529                 default:
3530                         if (c != '\0')
3531                                 fprintf(fp, "%c", c);
3532                         else if (c == '\0')
3533                                 lyxerr.debug()
3534                                         << "RoffAsciiTable:"
3535                                         " NULL char in structure." << endl;
3536                         break;
3537                 }
3538         }
3539         par->table->RoffEndOfCell(fp, cell);
3540         fclose(fp);
3541         string cmd = lyxrc->ascii_roff_command + " >" + fname2;
3542         cmd = subst(cmd, "$$FName", fname1);
3543         Systemcalls one(Systemcalls::System, cmd);
3544         if (!(lyxerr.debugging(Debug::ROFF))) {
3545                 remove(fname1.c_str());
3546         }
3547         if (!(fp=fopen(fname2.c_str(),"r"))) {
3548                 WriteFSAlert(_("Error! Can't open temporary file:"), fname2);
3549                 return;
3550         }
3551         // now output the produced file
3552         fprintf(file, "\n\n");
3553         c = fgetc(fp);
3554         if (feof(fp))
3555                 WriteAlert(_("Error!"),
3556                            _("Error executing *roff command on table"));
3557         // overread leading blank lines
3558         while(!feof(fp) && (c == '\n'))
3559                 c = fgetc(fp);
3560         while(!feof(fp)) {
3561                 for(j=0; j<par->depth; j++)
3562                         fprintf(file, "  ");
3563                 while(!feof(fp) && (c != '\n')) {
3564                         fputc(c,file);
3565                         c = fgetc(fp);
3566                 }
3567                 fputc('\n',file);
3568                 // overread trailing blank lines
3569                 while(!feof(fp) && (c == '\n'))
3570                         c = fgetc(fp);
3571         }
3572         fclose(fp);
3573         remove(fname2.c_str());
3574 }
3575
3576 /// changed Heinrich Bauer, 23/03/98
3577 bool Buffer::isDviClean()
3578 {
3579   if (lyxrc->use_tempdir)
3580     return dvi_clean_tmpd;
3581   else
3582     return dvi_clean_orgd;
3583 }
3584
3585 /// changed Heinrich Bauer, 23/03/98
3586 void Buffer::markDviClean()
3587 {
3588   if (lyxrc->use_tempdir)
3589     dvi_clean_tmpd = true;
3590   else
3591     dvi_clean_orgd = true;
3592 }
3593
3594 /// changed Heinrich Bauer, 23/03/98
3595 void Buffer::markDviDirty()
3596 {
3597   if (lyxrc->use_tempdir)
3598     dvi_clean_tmpd = false;
3599   else
3600     dvi_clean_orgd = false;
3601 }
3602
3603 void Buffer::update(signed char f)
3604 {
3605         if (!users) return;
3606         
3607         users->getOwner()->updateLayoutChoice();
3608
3609         if (!text->selection && f > -3)
3610                 text->sel_cursor = text->cursor;
3611         
3612         FreeUpdateTimer();
3613         text->FullRebreak();
3614         users->update();
3615
3616         if (f != 3 && f != -3) {
3617                 users->fitCursor();
3618                 users->updateScrollbar();
3619         }
3620
3621         if (f==1 || f==-1) {
3622                 if (isLyxClean()) {
3623                         markDirty();
3624                         users->getOwner()->getMiniBuffer()->setTimer(4);
3625                 } else {
3626                         markDirty();
3627                 }
3628         }
3629 }
3630
3631
3632 void Buffer::validate(LaTeXFeatures &features)
3633 {
3634         LyXParagraph *par = paragraph;
3635         LyXTextClass *tclass = lyxstyle.TextClass(params.textclass);
3636     
3637         // AMS Style is at document level
3638     
3639         features.amsstyle = (params.use_amsmath ||
3640                              tclass->provides_amsmath);
3641     
3642         while (par) {
3643                 // We don't use "lyxerr.debug" because of speed. (Asger)
3644                 if (lyxerr.debugging(Debug::LATEX))
3645                         lyxerr << "Paragraph: " <<  par << endl;
3646
3647                 // Now just follow the list of paragraphs and run
3648                 // validate on each of them.
3649                 par->validate(features);
3650
3651                 // and then the next paragraph
3652                 par = par->next;
3653         }
3654
3655         // the bullet shapes are buffer level not paragraph level
3656         // so they are tested here
3657         for (int i = 0; i < 4; ++i) {
3658                 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
3659                         int font = params.user_defined_bullets[i].getFont();
3660                         if (font == 0) {
3661                                 int c = params.user_defined_bullets[i].getCharacter();
3662                                 if (c == 16
3663                                    || c == 17
3664                                    || c == 25
3665                                    || c == 26
3666                                    || c == 31) {
3667                                         features.latexsym = true;
3668                                 }
3669                         }
3670                         if (font == 1) {
3671                                 features.amssymb = true;
3672                         }
3673                         else if ((font >= 2 && font <=5)) {
3674                                 features.pifont = true;
3675                         }
3676                 }
3677         }
3678         
3679         if (lyxerr.debugging(Debug::LATEX)) {
3680                 features.showStruct(params);
3681         }
3682 }
3683
3684
3685 void Buffer::setPaperStuff()
3686 {
3687         char c1, c2;
3688  
3689         params.papersize = PAPER_DEFAULT;
3690         c1 = params.paperpackage;
3691         if (c1 == PACKAGE_NONE) {
3692                 c2 = params.papersize2;
3693                 if (c2 == VM_PAPER_USLETTER)
3694                         params.papersize = PAPER_USLETTER;
3695                 else if (c2 == VM_PAPER_USLEGAL)
3696                         params.papersize = PAPER_LEGALPAPER;
3697                 else if (c2 == VM_PAPER_USEXECUTIVE)
3698                         params.papersize = PAPER_EXECUTIVEPAPER;
3699                 else if (c2 == VM_PAPER_A3)
3700                         params.papersize = PAPER_A3PAPER;
3701                 else if (c2 == VM_PAPER_A4)
3702                         params.papersize = PAPER_A4PAPER;
3703                 else if (c2 == VM_PAPER_A5)
3704                         params.papersize = PAPER_A5PAPER;
3705                 else if ((c2 == VM_PAPER_B3) || (c2 == VM_PAPER_B4) ||
3706                          (c2 == VM_PAPER_B5))
3707                         params.papersize = PAPER_B5PAPER;
3708         } else if ((c1 == PACKAGE_A4) || (c1 == PACKAGE_A4WIDE) ||
3709                    (c1 == PACKAGE_WIDEMARGINSA4))
3710                 params.papersize = PAPER_A4PAPER;
3711 }
3712
3713
3714 void Buffer::setOldPaperStuff()
3715 {
3716         char c;
3717
3718         c = params.papersize = params.papersize2;
3719         params.papersize2 = VM_PAPER_DEFAULT;
3720         params.paperpackage = PACKAGE_NONE;
3721         if (c == OLD_PAPER_A4PAPER)
3722                 params.papersize2 = VM_PAPER_A4;
3723         else if (c == OLD_PAPER_A4)
3724                 params.paperpackage = PACKAGE_A4;
3725         else if (c == OLD_PAPER_A4WIDE)
3726                 params.paperpackage = PACKAGE_A4WIDE;
3727         else if (c == OLD_PAPER_WIDEMARGINSA4)
3728                 params.paperpackage = PACKAGE_WIDEMARGINSA4;
3729         else if (c == OLD_PAPER_USLETTER)
3730                 params.papersize2 = VM_PAPER_USLETTER;
3731         else if (c == OLD_PAPER_A5PAPER)
3732                 params.papersize2 = VM_PAPER_A5;
3733         else if (c == OLD_PAPER_B5PAPER)
3734                 params.papersize2 = VM_PAPER_B5;
3735         else if (c == OLD_PAPER_EXECUTIVEPAPER)
3736                 params.papersize2 = VM_PAPER_USEXECUTIVE;
3737         else if (c == OLD_PAPER_LEGALPAPER)
3738                 params.papersize2 = VM_PAPER_USLEGAL;
3739         setPaperStuff();
3740 }
3741
3742
3743 void Buffer::insertInset(Inset *inset, string const &lout,
3744                          bool no_table)
3745 {
3746         // check for table/list in tables
3747         if (no_table && text->cursor.par->table){
3748                 WriteAlert(_("Impossible Operation!"),
3749                            _("Cannot insert table/list in table."),
3750                            _("Sorry."));
3751                 return;
3752         }
3753         // not quite sure if we want this...
3754         text->SetCursorParUndo();
3755         text->FreezeUndo();
3756         
3757         BeforeChange();
3758         if (!lout.empty()) {
3759                 update(-2);
3760                 text->BreakParagraph();
3761                 update(-1);
3762                 
3763                 if (text->cursor.par->Last()) {
3764                         text->CursorLeft();
3765                         
3766                         text->BreakParagraph();
3767                         update(-1);
3768                 }
3769
3770                 int lay = lyxstyle.NumberOfLayout(params.textclass, lout);
3771                 if (lay == -1) // layout not found
3772                         // use default layout "Standard" (0)
3773                         lay = 0;
3774                 
3775                 text->SetLayout(lay);
3776                 
3777                 text->SetParagraph(0, 0,
3778                                    0, 0,
3779                                    VSpace(VSpace::NONE), VSpace(VSpace::NONE),
3780                                    LYX_ALIGN_LAYOUT, 
3781                                    string(),
3782                                    0);
3783                 update(-1);
3784                 
3785                 text->current_font.setLatex(LyXFont::OFF);
3786         }
3787         
3788         text->InsertInset(inset);
3789         update(-1);
3790
3791 // Commenting these two lines fixes the problem with new display inset
3792 // inside a paragraph, not sure why. (ale 971117)
3793 //      if (inset->Display())
3794 //              text->CursorRight();
3795         
3796         text->UnFreezeUndo();   
3797 }
3798
3799
3800 // Open and lock an updatable inset
3801 void Buffer::open_new_inset(UpdatableInset* new_inset)
3802 {
3803         BeforeChange();
3804         text->FinishUndo();
3805         insertInset(new_inset);
3806         text->CursorLeft();
3807         update(1);
3808         new_inset->Edit(0,0);
3809 }
3810
3811
3812 /* This function should be in Buffer because it's a buffer's property (ale) */
3813 string Buffer::getIncludeonlyList(char delim)
3814 {
3815         string list;
3816         LyXParagraph *par = paragraph;
3817         int pos;
3818         Inset* inset;
3819         while (par){
3820                 pos = -1;
3821                 while ((inset = par->ReturnNextInsetPointer(pos))){
3822                         if (inset->LyxCode()==Inset::INCLUDE_CODE) {
3823                                 InsetInclude *insetinc = (InsetInclude*)inset;
3824                                 if (insetinc->isInclude() 
3825                                     && insetinc->isNoLoad()) {
3826                                         if (!list.empty())
3827                                                 list += delim;
3828                                         list += ChangeExtension(insetinc->getContents(), string(), true);
3829                                 }
3830                         }
3831                         pos++;
3832                 } 
3833                 par = par->next;
3834         }
3835         lyxerr.debug() << "Includeonly(" << list << ')' << endl;
3836         return list;
3837 }
3838
3839
3840 /* This is also a buffer property (ale) */ 
3841 string Buffer::getReferenceList(char delim)
3842 {
3843         /// if this is a child document and the parent is already loaded
3844         /// Use the parent's list instead  [ale990407]
3845         if (!params.parentname.empty() && bufferlist.exists(params.parentname)) {
3846                 Buffer *tmp = bufferlist.getBuffer(params.parentname);
3847                 if (tmp)
3848                   return tmp->getReferenceList(delim);
3849         }
3850
3851         LyXParagraph *par = paragraph;
3852         int pos;
3853         Inset* inset;
3854         string list;
3855         while (par){
3856                 pos = -1;
3857                 while ((inset = par->ReturnNextInsetPointer(pos))){     
3858                         for (int i = 0; i < inset->GetNumberOfLabels(); i++) {
3859                                 if (!list.empty())
3860                                         list += delim;
3861                                 list += inset->getLabel(i);
3862                         }
3863                         pos++;
3864                 } 
3865                 par = par->next;
3866         }
3867         lyxerr.debug() << "References(" <<  list << ")" << endl;
3868         return list;
3869 }
3870
3871
3872 /* This is also a buffer property (ale) */ 
3873 string Buffer::getBibkeyList(char delim)
3874 {
3875         /// if this is a child document and the parent is already loaded
3876         /// Use the parent's list instead  [ale990412]
3877         if (!params.parentname.empty() && bufferlist.exists(params.parentname)) {
3878                 Buffer *tmp = bufferlist.getBuffer(params.parentname);
3879                 if (tmp)
3880                         return tmp->getBibkeyList(delim);
3881         }
3882
3883         string bibkeys;
3884         LyXParagraph *par = paragraph;
3885         while (par) {
3886                 if (par->bibkey) {
3887                         if (!bibkeys.empty())
3888                                 bibkeys += delim;
3889                         bibkeys += par->bibkey->getContents();
3890                 }
3891                 par = par->next;
3892         }
3893
3894         // Might be either using bibtex or a child has bibliography
3895         if (bibkeys.empty()) {
3896                 par = paragraph;
3897                 while (par) {
3898                         Inset *inset;
3899                         int pos = -1;
3900
3901                         // Search for Bibtex or Include inset
3902                         while ((inset = par->ReturnNextInsetPointer(pos))) {
3903                                 if (inset-> LyxCode()==Inset::BIBTEX_CODE) {
3904                                         if (!bibkeys.empty())
3905                                                 bibkeys += delim;
3906                                         bibkeys += ((InsetBibtex*)inset)->getKeys();
3907                                 } else if (inset-> LyxCode()==Inset::INCLUDE_CODE) {
3908                                         string bk = ((InsetInclude*)inset)->getKeys();
3909                                         if (!bk.empty()) {
3910                                                 if (!bibkeys.empty())
3911                                                         bibkeys += delim;
3912                                                 bibkeys += bk;
3913                                         }
3914                                 }
3915                                 pos++;
3916                         }
3917                         par = par->next;
3918                 }
3919         }
3920  
3921         lyxerr.debug() << "Bibkeys(" << bibkeys << ")" << endl;
3922         return bibkeys;
3923 }
3924
3925
3926 /* This is also a buffer property (ale) */
3927 // Not so sure about that. a goto Label function can not be buffer local, just
3928 // think how this will work in a multiwindo/buffer environment, all the
3929 // cursors in all the views showing this buffer will move. (Lgb)
3930 // OK, then no cursor action should be allowed in buffer. (ale)
3931 bool Buffer::gotoLabel(const string &label)
3932
3933 {
3934         LyXParagraph *par = paragraph;
3935         int pos;
3936         Inset* inset;
3937         string list;
3938         while (par) {
3939                 pos = -1;
3940                 while ((inset = par->ReturnNextInsetPointer(pos))){     
3941                         for (int i = 0; i < inset->GetNumberOfLabels(); i++) {
3942                                 if (label==inset->getLabel(i)) {
3943                                         BeforeChange();
3944                                         text->SetCursor(par, pos);
3945                                         text->sel_cursor = text->cursor;
3946                                         update(0);
3947                                         return true;
3948                                 }
3949                         }
3950                         pos++;
3951                 } 
3952                 par = par->next;
3953         }
3954         return false;
3955 }
3956
3957
3958 bool Buffer::isDepClean(string const & name) const
3959 {
3960         DEPCLEAN* item = dep_clean;
3961         while (item && item->master != name)
3962                 item = item->next;
3963         if (!item) return true;
3964         return item->clean;
3965 }
3966
3967
3968 void Buffer::markDepClean(string const & name)
3969 {
3970         if (!dep_clean) {
3971                 dep_clean = new DEPCLEAN;
3972                 dep_clean->clean = true;
3973                 dep_clean->master = name;
3974                 dep_clean->next = 0;
3975         } else {
3976                 DEPCLEAN* item = dep_clean;
3977                 while (item && item->master != name)
3978                         item = item->next;
3979                 if (item) {
3980                         item->clean = true;
3981                 } else {
3982                         item = new DEPCLEAN;
3983                         item->clean = true;
3984                         item->master = name;
3985                         item->next = 0;;
3986                 }
3987         }
3988         //return false; // why use that in a void method??
3989 }