]> git.lyx.org Git - features.git/blob - src/mathed/math_write.C
apply the ostream changes to mathed, some other small related things
[features.git] / src / mathed / math_write.C
1 /*
2  *  File:        math_write.h
3  *  Purpose:     Write math paragraphs in LaTeX
4  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
5  *  Created:     January 1996
6  *  Description: 
7  *
8  *  Dependencies: Xlib, XForms
9  *
10  *  Copyright: (c) 1996, 1997 Alejandro Aguilar Sierra
11  *
12  *   Version: 0.8beta, Mathed & Lyx project.
13  *
14  *   You are free to use and modify this code under the terms of
15  *   the GNU General Public Licence version 2 or later.
16  */
17
18 #include <config.h>
19
20 #include "LString.h"
21 #include "math_inset.h"
22 #include "math_iter.h"
23 #include "math_parser.h"
24 #include "support/lstrings.h"
25 #include "debug.h"
26
27 extern char const * latex_mathenv[];
28 extern char * latex_mathspace[];
29
30 // quite a hack i know. Should be done with return values...
31 static int number_of_newlines;
32
33 char const * math_font_name[] = {
34    "mathrm",
35    "mathcal",
36    "mathbf",
37    "mathsf",
38    "mathtt",
39    "mathit",
40    "textrm"
41 };
42
43
44 void
45 MathSpaceInset::Write(ostream & os)
46 {
47 #ifdef USE_OSTREAM_ONLY
48    if (space >= 0 && space < 6) {
49            os << '\\' << latex_mathspace[space] << ' ';
50    }
51 #else
52    if (space >= 0 && space < 6) {
53        string output;
54        MathSpaceInset::Write(output);
55        os << output;
56    }
57 #endif
58 }
59
60
61 #ifndef USE_OSTREAM_ONLY
62 void
63 MathSpaceInset::Write(string & outf)
64
65    if (space >= 0 && space < 6) {
66        outf += '\\';
67        outf += latex_mathspace[space];
68        outf += ' ';
69    }
70 }
71 #endif
72
73
74 void
75 MathDotsInset::Write(ostream & os)
76 {
77 #ifdef USE_OSTREAM_ONLY
78         os << '\\' << name << ' ';
79 #else
80    string output;
81    MathDotsInset::Write(output);
82    os << output;
83 #endif
84 }
85
86
87 #ifndef USE_OSTREAM_ONLY
88 void
89 MathDotsInset::Write(string & outf)
90 {
91    outf += '\\';
92    outf += name;
93    outf += ' ';
94 }
95 #endif
96
97
98 void MathSqrtInset::Write(ostream & os)
99 {
100 #ifdef USE_OSTREAM_ONLY
101         os << '\\' << name << '{';
102         MathParInset::Write(os); 
103         os << '}';
104 #else
105    string output;
106    MathSqrtInset::Write(output);
107    os << output;
108 #endif
109 }
110
111
112 #ifndef USE_OSTREAM_ONLY
113 void MathSqrtInset::Write(string & outf)
114
115    outf += '\\';
116    outf += name;
117    outf += '{';
118    MathParInset::Write(outf);  
119    outf += '}';
120 }
121 #endif
122
123
124 void MathDelimInset::Write(ostream & os)
125 {
126 #ifdef USE_OSTREAM_ONLY
127     latexkeys * l = (left != '|') ? lm_get_key_by_id(left, LM_TK_SYM): 0;
128     latexkeys * r = (right != '|') ? lm_get_key_by_id(right, LM_TK_SYM): 0;
129     os << "\\left";
130     if (l) {
131             os << '\\' << l->name << ' ';
132     } else {
133         if (left == '{' || left == '}') {
134                 os << '\\' << char(left) << ' ';
135         } else {
136                 os << char(left) << ' ';
137         }
138     }
139    MathParInset::Write(os);
140    os << "\\right";
141    if (r) {
142            os << '\\' << r->name << ' ';
143    } else {
144        if (right == '{' || right == '}') {
145                os << '\\' << char(right) << ' ';
146       } else {
147               os << char(right) << ' ';
148       }
149    }
150 #else
151     string output;
152     MathDelimInset::Write(output);
153     os << output;
154 #endif
155 }
156
157
158 #ifndef USE_OSTREAM_ONLY
159 void MathDelimInset::Write(string & outf)
160 {
161     latexkeys * l = (left != '|') ? lm_get_key_by_id(left, LM_TK_SYM): 0;
162     latexkeys * r = (right != '|') ? lm_get_key_by_id(right, LM_TK_SYM): 0;
163     outf += "\\left";
164     if (l) {
165         outf += '\\';
166         outf += l->name;
167         outf += ' ';
168     } else {
169         if (left == '{' || left == '}') {
170             outf += '\\';
171             outf += char(left);
172             outf += ' ';
173         } else {
174             outf += char(left);
175             outf += ' ';
176         }
177     }
178    MathParInset::Write(outf);  
179    outf += "\\right";
180    if (r) {
181        outf += '\\';
182        outf += r->name;
183        outf += ' ';
184    } else {
185        if (right == '{' || right == '}') {
186            outf += '\\';
187            outf += char(right);
188            outf += ' ';
189       } else {
190            outf += char(right);
191            outf += ' ';
192       }
193    }        
194 }
195 #endif
196
197
198 void MathDecorationInset::Write(ostream & os)
199 {
200 #ifdef USE_OSTREAM_ONLY
201         latexkeys * l = lm_get_key_by_id(deco, LM_TK_WIDE);
202         os << '\\' << l->name << '{';
203         MathParInset::Write(os);  
204         os << '}';
205 #else
206    string output;
207    MathDecorationInset::Write(output);
208    os << output;
209 #endif
210 }
211
212
213 #ifndef USE_OSTREAM_ONLY
214 void MathDecorationInset::Write(string & outf)
215
216    latexkeys * l = lm_get_key_by_id(deco, LM_TK_WIDE);
217    outf += '\\';
218    outf += l->name;
219    outf += '{';
220    MathParInset::Write(outf);  
221    outf += '}';
222 }
223 #endif
224
225
226 void MathAccentInset::Write(ostream & os)
227 {
228 #ifdef USE_OSTREAM_ONLY
229         latexkeys * l = lm_get_key_by_id(code, LM_TK_ACCENT);
230         os << '\\' << l->name;
231         if (code!= LM_not)
232                 os << '{';
233         else
234                 os << ' ';
235         
236         if (inset) {
237                 inset->Write(os);
238         } else {
239                 if (fn>= LM_TC_RM && fn<= LM_TC_TEXTRM) {
240                         os << '\\'
241                            << math_font_name[fn-LM_TC_RM]
242                            << '{';
243                 }
244                 if (MathIsSymbol(fn)) {
245                         latexkeys * l = lm_get_key_by_id(c, LM_TK_SYM);
246                         if (l) {
247                                 os << '\\' << l->name << ' ';
248                         }
249                 } else
250                         os << char(c);
251                 
252                 if (fn>= LM_TC_RM && fn<= LM_TC_TEXTRM)
253                         os << '}';
254         }
255         
256         if (code!= LM_not)
257                 os << '}';
258 #else
259     string output;
260     MathAccentInset::Write(output);
261     os << output;
262 #endif
263 }
264
265
266 #ifndef USE_OSTREAM_ONLY
267 void MathAccentInset::Write(string & outf)
268
269     latexkeys * l = lm_get_key_by_id(code, LM_TK_ACCENT);
270     outf += '\\';
271     outf += l->name;
272     if (code!= LM_not)
273       outf += '{';
274     else
275       outf += ' ';
276
277     if (inset) {
278       inset->Write(outf);
279     } else {
280       if (fn>= LM_TC_RM && fn<= LM_TC_TEXTRM) {
281         outf += '\\';
282         outf += math_font_name[fn-LM_TC_RM];
283         outf += '{';
284       }
285       if (MathIsSymbol(fn)) {
286           latexkeys *l = lm_get_key_by_id(c, LM_TK_SYM);
287           if (l) {
288             outf += '\\';
289             outf += l->name;
290             outf += ' ';
291           }
292       } else
293         outf += char(c);
294
295       if (fn>= LM_TC_RM && fn<= LM_TC_TEXTRM)
296         outf += '}';
297     }
298
299     if (code!= LM_not)
300       outf += '}';
301 }
302 #endif
303
304
305 void MathBigopInset::Write(ostream & os)
306 {
307 #ifdef USE_OSTREAM_ONLY
308     bool limp = GetLimits();
309     
310     os << '\\' << name;
311     
312     if (limp && !(sym != LM_int && sym != LM_oint
313                   && (GetStyle() == LM_ST_DISPLAY)))
314             os << "\\limits ";
315     else 
316     if (!limp && (sym != LM_int && sym != LM_oint
317                   && (GetStyle() == LM_ST_DISPLAY)))
318             os << "\\nolimits ";
319     else 
320             os << ' ';
321 #else
322    string output;
323    MathBigopInset::Write(output);
324    os << output;
325 #endif
326 }
327
328
329 #ifndef USE_OSTREAM_ONLY
330 void MathBigopInset::Write(string & outf)
331
332     bool limp = GetLimits();
333     
334     outf += '\\';
335     outf += name;
336     
337     if (limp && !(sym!= LM_int && sym!= LM_oint && (GetStyle() == LM_ST_DISPLAY)))
338       outf += "\\limits ";
339     else 
340     if (!limp && (sym!= LM_int && sym!= LM_oint && (GetStyle() == LM_ST_DISPLAY)))
341         outf += "\\nolimits ";
342     else 
343       outf += ' ';
344 }
345 #endif
346
347
348 void MathFracInset::Write(ostream & os)
349 {
350 #ifdef USE_OSTREAM_ONLY
351         os << '\\' << name << '{';
352         MathParInset::Write(os);
353         os << "}{";
354         den->Write(os);
355         os << '}';
356 #else
357    string output;
358    MathFracInset::Write(output);
359    os << output;
360 #endif
361 }
362
363
364 #ifndef USE_OSTREAM_ONLY
365 void MathFracInset::Write(string & outf)
366
367    outf += '\\';
368    outf += name;
369    outf += '{';
370    MathParInset::Write(outf);  
371    outf += "}{";
372    den->Write(outf);  
373    outf += '}';
374 }
375 #endif
376
377
378 void MathParInset::Write(ostream & os)
379 {
380 #ifdef USE_OSTREAM_ONLY
381         if (!array) return;
382         int brace = 0;
383         latexkeys * l;
384         MathedIter data(array);
385         // hack
386         MathedRowSt const * crow = getRowSt();   
387         data.Reset();
388         
389         if (!Permit(LMPF_FIXED_SIZE)) { 
390                 l = lm_get_key_by_id(size, LM_TK_STY);
391                 if (l) {
392                         os << '\\' << l->name << ' ';
393                 }
394         }
395         while (data.OK()) {
396                 byte cx = data.GetChar();
397                 if (cx >= ' ') {
398                         int ls;
399                         byte * s = data.GetString(ls);
400                         
401                         if (data.FCode() >= LM_TC_RM && data.FCode() <= LM_TC_TEXTRM) {
402                                 os << '\\' << math_font_name[data.FCode()-LM_TC_RM] << '{';
403                         }
404                         while (ls > 0) {
405                                 if (MathIsSymbol(data.FCode())) {
406                                         l = lm_get_key_by_id(*s, (data.FCode() == LM_TC_BSYM) ?
407                                                              LM_TK_BIGSYM : LM_TK_SYM);
408                                         if (l) {
409                                                 os << '\\' << l->name << ' ';
410                                         } else { 
411                                                 lyxerr << "Illegal symbol code[" << *s
412                                                        << " " << ls << " " << data.FCode() << "]";
413                                         }
414                                 } else {
415                                         // Is there a standard logical XOR?
416                                         if ((data.FCode() == LM_TC_TEX && *s != '{' && *s != '}') ||
417                                             (data.FCode() == LM_TC_SPECIAL))
418                                                 os << '\\';
419                                         else {
420                                                 if (*s == '{') ++brace;
421                                                 if (*s == '}') --brace;
422                                         }
423                                         if (*s == '}' && data.FCode() == LM_TC_TEX && brace < 0) 
424                                                 lyxerr <<"Math warning: Unexpected closing brace."
425                                                        << endl;
426                                         else           
427                                                 os << char(*s);
428                                 }
429                                 ++s; --ls;
430                         }
431                         if (data.FCode()>= LM_TC_RM && data.FCode()<= LM_TC_TEXTRM)
432                                 os << '}';
433                 } else     
434                         if (MathIsInset(cx)) {
435                                 MathedInset * p = data.GetInset();
436                                 if (cx == LM_TC_UP)
437                                         os << "^{";
438                                 if (cx == LM_TC_DOWN)
439                                         os << "_{";
440                                 p->Write(os);
441                                 if (cx == LM_TC_UP || cx == LM_TC_DOWN)
442                                         os << '}';
443                                 data.Next();
444                         } else
445                                 switch(cx) {
446                                 case LM_TC_TAB:
447                                 {
448                                         os << " & ";
449                                         data.Next();
450                                         break;
451                                 }
452                                 case LM_TC_CR:
453                                 {
454                                         if (crow) {
455                                                 if (!crow->isNumbered()) {  
456                                                         os << "\\nonumber ";
457                                                 }
458                                                 if (crow->getLabel()) {
459                                                         os << "\\label{"
460                                                            << crow->getLabel()
461                                                            << "} ";
462                                                 }
463                                                 crow = crow->getNext();
464                                         }
465                                         os << "\\\\\n";
466                                         ++number_of_newlines;
467                                         data.Next();
468                                         break;
469                                 }
470                                 default:
471                                         lyxerr << "WMath Error: unrecognized code[" << cx << "]";
472                                         return;
473                                 }     
474         }
475         
476         if (crow) {
477                 if (!crow->isNumbered()) {
478                         os << "\\nonumber ";
479                 }
480                 if (crow->getLabel()) {
481                         os << "\\label{"
482                            << crow->getLabel()
483                            << "} ";
484                 }
485         }
486 #if 1
487         while (brace > 0) {
488                 os << '}';
489                 --brace;
490         }
491 #else
492         // Something like this should work too:
493         os << string(brace, '}'); // not one-off error I hope.
494 #endif
495 #else
496    if (!array) return;
497    string output;
498    MathParInset::Write(output);
499    os << output;
500 #endif
501 }
502
503
504 #ifndef USE_OSTREAM_ONLY
505 void MathParInset::Write(string & outf)
506 {
507    if (!array) return;
508    int brace = 0;
509    latexkeys * l;
510    MathedIter data(array);
511    // hack
512    MathedRowSt const * crow = getRowSt();   
513    data.Reset();
514     
515    if (!Permit(LMPF_FIXED_SIZE)) { 
516        l = lm_get_key_by_id(size, LM_TK_STY);
517        if (l) {
518            outf += '\\';
519            outf += l->name;
520            outf += ' ';
521        }
522    }
523    while (data.OK()) {
524       byte cx = data.GetChar();
525       if (cx>= ' ') {
526          int ls;
527          byte * s = data.GetString(ls);
528        
529          if (data.FCode()>= LM_TC_RM && data.FCode()<= LM_TC_TEXTRM) {
530              outf += '\\';
531              outf += math_font_name[data.FCode()-LM_TC_RM];
532              outf += '{';
533          }
534          while (ls>0) {
535             if (MathIsSymbol(data.FCode())) {
536                 l = lm_get_key_by_id(*s,(data.FCode() == LM_TC_BSYM)?LM_TK_BIGSYM:LM_TK_SYM);
537                if (l) {
538                  outf += '\\';
539                  outf += l->name;
540                  outf += ' ';
541                } else { 
542                        lyxerr << "Illegal symbol code[" << *s
543                               << " " << ls << " " << data.FCode() << "]";
544                }
545             } else {
546                // Is there a standard logical XOR?
547                if ((data.FCode() == LM_TC_TEX && *s!= '{' && *s!= '}') ||
548                    (data.FCode() == LM_TC_SPECIAL))
549                  outf += '\\';
550                else {
551                   if (*s == '{') ++brace;
552                   if (*s == '}') --brace;
553                }
554                if (*s == '}' && data.FCode() == LM_TC_TEX && brace<0) 
555                        lyxerr <<"Math warning: Unexpected closing brace."
556                               << endl;
557                else            
558                  outf += char(*s);
559             }
560             ++s; --ls;
561          }
562          if (data.FCode()>= LM_TC_RM && data.FCode()<= LM_TC_TEXTRM)
563            outf += '}';
564       } else     
565       if (MathIsInset(cx)) {
566          MathedInset *p = data.GetInset();
567          if (cx == LM_TC_UP)
568            outf += "^{";
569          if (cx == LM_TC_DOWN)
570            outf += "_{";
571          p->Write(outf);
572          if (cx == LM_TC_UP || cx == LM_TC_DOWN)
573            outf += '}';
574          data.Next();
575       } else
576         switch(cx) {
577          case LM_TC_TAB:
578             {
579                outf += " & ";
580                data.Next();
581                break;
582             }
583          case LM_TC_CR:
584             {
585                 if (crow) {
586                     if (!crow->isNumbered()) {  
587                         outf += "\\nonumber ";
588                     }
589                     if (crow->getLabel()) {
590                         outf += "\\label{";
591                         outf += crow->getLabel();
592                         outf += "} ";
593                     }
594                     crow = crow->getNext();
595                 }
596                outf += "\\\\\n";
597                ++number_of_newlines;
598                data.Next();
599                break;
600             }
601          default:
602                  lyxerr << "WMath Error: unrecognized code[" << cx << "]";
603            return;
604         }     
605    }
606     
607     if (crow) {
608         if (!crow->isNumbered()) {
609             outf += "\\nonumber ";
610         }
611         if (crow->getLabel()) {
612             outf += "\\label{";
613             outf += crow->getLabel();
614             outf += "} ";
615         }
616     }
617    while (brace>0) {
618       outf += '}';
619       --brace;
620    }
621 }
622 #endif
623
624
625 void MathMatrixInset::Write(ostream & os)
626 {
627 #ifdef USE_OSTREAM_ONLY
628     if (GetType() == LM_OT_MATRIX){
629             os << "\\begin{"
630                << name
631                << '}';
632         if (v_align == 't' || v_align == 'b') {
633                 os << '['
634                    << char(v_align)
635                    << ']';
636         }
637         os << '{'
638            << h_align
639            << "}\n";
640         ++number_of_newlines;
641     }
642     MathParInset::Write(os);
643     if (GetType() == LM_OT_MATRIX){
644             os << "\n\\end{"
645                << name
646                << '}';
647         ++number_of_newlines;
648     }
649 #else
650     string output;
651     MathMatrixInset::Write(output);
652     os << output;
653 #endif
654 }
655
656
657 #ifndef USE_OSTREAM_ONLY
658 void MathMatrixInset::Write(string & outf)
659 {
660     if (GetType() == LM_OT_MATRIX){
661         outf += "\\begin{";
662         outf += name;
663         outf += '}';
664         if (v_align == 't' || v_align == 'b') {
665             outf += '[';
666             outf += char(v_align);
667             outf += ']';
668         }
669         outf += '{';
670         outf += h_align;
671         outf += "}\n";
672         ++number_of_newlines;
673     }
674     MathParInset::Write(outf);
675     if (GetType() == LM_OT_MATRIX){
676         outf += "\n\\end{";
677         outf += name;
678         outf += '}';
679         ++number_of_newlines;
680     }
681 }
682 #endif
683
684
685 void mathed_write(MathParInset * p, ostream & os, int * newlines,
686                   char fragile, char const * label)
687 {
688 #ifdef USE_OSTREAM_ONLY
689    number_of_newlines = 0;
690    short mathed_env = p->GetType();
691
692    if (mathed_env == LM_EN_INTEXT) {
693            if (fragile) os << "\\protect";
694            os << "\\( "; // changed from " \\( " (Albrecht Dress)
695    } 
696    else {
697            // Thinko!
698            // Is this '\n' really needed, what can go wrong
699            //if it is not there?
700 #warning Thinko!
701 #if 0
702      if (!suffixIs(outf, '\n')) {
703        // in batchmode we need to make sure
704        // a space before an equation doesn't
705        // make the LaTeX output different 
706        // compared to "Exported LaTeX"  ARRae
707        // Modified to work in a cleaner and hopefully more general way
708        // (JMarc)
709        outf += "\n";
710        ++number_of_newlines;
711      }
712 #endif
713      if (mathed_env == LM_EN_DISPLAY){
714              os << "\\[\n";
715      } else {
716              os << "\\begin{"
717                 << latex_mathenv[mathed_env]
718                 << "}\n";
719      }
720      ++number_of_newlines;
721    }
722    
723    if (label && label[0] > ' ' && mathed_env == LM_EN_EQUATION){
724            os << "\\label{"
725               << label
726               << "}\n";
727      ++number_of_newlines;
728    }
729
730    p->Write(os);
731    
732    if (mathed_env == LM_EN_INTEXT){
733            if (fragile) os << "\\protect";
734            os << " \\)";
735    }
736    else if (mathed_env == LM_EN_DISPLAY) {
737            os << "\\]\n";
738      ++number_of_newlines;
739    }
740    else {
741            os << "\n\\end{"
742               << latex_mathenv[mathed_env]
743               << "}\n";
744      number_of_newlines += 2;
745    }
746    *newlines = number_of_newlines;
747 #else
748    string output;
749    mathed_write(p, output, newlines, fragile, label);
750    os << output;
751 #endif
752 }
753
754
755 #ifndef USE_OSTREAM_ONLY
756 void mathed_write(MathParInset * p, string & outf, int * newlines,
757                   char fragile, char const * label)
758 {
759    number_of_newlines = 0;
760    short mathed_env = p->GetType();
761
762    if (mathed_env == LM_EN_INTEXT) {
763      if (fragile) outf += "\\protect";
764      outf += "\\( "; // changed from " \\( " (Albrecht Dress)
765    } 
766    else {
767      if (!suffixIs(outf, '\n')) {
768        // in batchmode we need to make sure
769        // a space before an equation doesn't
770        // make the LaTeX output different 
771        // compared to "Exported LaTeX"  ARRae
772        // Modified to work in a cleaner and hopefully more general way
773        // (JMarc)
774        outf += "\n";
775        ++number_of_newlines;
776      }
777      if (mathed_env == LM_EN_DISPLAY){
778        outf += "\\[\n";
779      }
780      else {
781        outf += "\\begin{";
782        outf += latex_mathenv[mathed_env];
783        outf += "}\n";
784      }
785      ++number_of_newlines;
786    }
787    
788    if (label && label[0]>' ' && mathed_env == LM_EN_EQUATION){
789      outf += "\\label{";
790      outf += label;
791      outf += "}\n";
792      ++number_of_newlines;
793    }
794
795    p->Write(outf);
796    
797    if (mathed_env == LM_EN_INTEXT){
798      if (fragile) outf += "\\protect";
799      outf += " \\)";
800    }
801    else if (mathed_env == LM_EN_DISPLAY){
802      outf += "\\]\n";
803      ++number_of_newlines;
804    }
805    else {
806      outf += "\n\\end{";
807      outf += latex_mathenv[mathed_env];
808      outf += "}\n";
809      number_of_newlines += 2;
810    }
811    *newlines = number_of_newlines;
812 }
813 #endif