]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/mdocml/eqn_html.c
Import mandoc cvs snapshot 20170121 (pre 1.14)
[FreeBSD/FreeBSD.git] / contrib / mdocml / eqn_html.c
1 /*      $Id: eqn_html.c,v 1.11 2017/01/17 01:47:51 schwarze Exp $ */
2 /*
3  * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #include "config.h"
19
20 #include <sys/types.h>
21
22 #include <assert.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "mandoc.h"
28 #include "out.h"
29 #include "html.h"
30
31 static void
32 eqn_box(struct html *p, const struct eqn_box *bp)
33 {
34         struct tag      *post, *row, *cell, *t;
35         const struct eqn_box *child, *parent;
36         size_t           i, j, rows;
37
38         if (NULL == bp)
39                 return;
40
41         post = NULL;
42
43         /*
44          * Special handling for a matrix, which is presented to us in
45          * column order, but must be printed in row-order.
46          */
47         if (EQN_MATRIX == bp->type) {
48                 if (NULL == bp->first)
49                         goto out;
50                 if (EQN_LIST != bp->first->type) {
51                         eqn_box(p, bp->first);
52                         goto out;
53                 }
54                 if (NULL == (parent = bp->first->first))
55                         goto out;
56                 /* Estimate the number of rows, first. */
57                 if (NULL == (child = parent->first))
58                         goto out;
59                 for (rows = 0; NULL != child; rows++)
60                         child = child->next;
61                 /* Print row-by-row. */
62                 post = print_otag(p, TAG_MTABLE, "");
63                 for (i = 0; i < rows; i++) {
64                         parent = bp->first->first;
65                         row = print_otag(p, TAG_MTR, "");
66                         while (NULL != parent) {
67                                 child = parent->first;
68                                 for (j = 0; j < i; j++) {
69                                         if (NULL == child)
70                                                 break;
71                                         child = child->next;
72                                 }
73                                 cell = print_otag(p, TAG_MTD, "");
74                                 /*
75                                  * If we have no data for this
76                                  * particular cell, then print a
77                                  * placeholder and continue--don't puke.
78                                  */
79                                 if (NULL != child)
80                                         eqn_box(p, child->first);
81                                 print_tagq(p, cell);
82                                 parent = parent->next;
83                         }
84                         print_tagq(p, row);
85                 }
86                 goto out;
87         }
88
89         switch (bp->pos) {
90         case (EQNPOS_TO):
91                 post = print_otag(p, TAG_MOVER, "");
92                 break;
93         case (EQNPOS_SUP):
94                 post = print_otag(p, TAG_MSUP, "");
95                 break;
96         case (EQNPOS_FROM):
97                 post = print_otag(p, TAG_MUNDER, "");
98                 break;
99         case (EQNPOS_SUB):
100                 post = print_otag(p, TAG_MSUB, "");
101                 break;
102         case (EQNPOS_OVER):
103                 post = print_otag(p, TAG_MFRAC, "");
104                 break;
105         case (EQNPOS_FROMTO):
106                 post = print_otag(p, TAG_MUNDEROVER, "");
107                 break;
108         case (EQNPOS_SUBSUP):
109                 post = print_otag(p, TAG_MSUBSUP, "");
110                 break;
111         case (EQNPOS_SQRT):
112                 post = print_otag(p, TAG_MSQRT, "");
113                 break;
114         default:
115                 break;
116         }
117
118         if (bp->top || bp->bottom) {
119                 assert(NULL == post);
120                 if (bp->top && NULL == bp->bottom)
121                         post = print_otag(p, TAG_MOVER, "");
122                 else if (bp->top && bp->bottom)
123                         post = print_otag(p, TAG_MUNDEROVER, "");
124                 else if (bp->bottom)
125                         post = print_otag(p, TAG_MUNDER, "");
126         }
127
128         if (EQN_PILE == bp->type) {
129                 assert(NULL == post);
130                 if (bp->first != NULL && bp->first->type == EQN_LIST)
131                         post = print_otag(p, TAG_MTABLE, "");
132         } else if (bp->type == EQN_LIST &&
133             bp->parent && bp->parent->type == EQN_PILE) {
134                 assert(NULL == post);
135                 post = print_otag(p, TAG_MTR, "");
136                 print_otag(p, TAG_MTD, "");
137         }
138
139         if (NULL != bp->text) {
140                 assert(NULL == post);
141                 post = print_otag(p, TAG_MI, "");
142                 print_text(p, bp->text);
143         } else if (NULL == post) {
144                 if (NULL != bp->left || NULL != bp->right)
145                         post = print_otag(p, TAG_MFENCED, "??",
146                             "open", bp->left == NULL ? "" : bp->left,
147                             "close", bp->right == NULL ? "" : bp->right);
148                 if (NULL == post)
149                         post = print_otag(p, TAG_MROW, "");
150                 else
151                         print_otag(p, TAG_MROW, "");
152         }
153
154         eqn_box(p, bp->first);
155
156 out:
157         if (NULL != bp->bottom) {
158                 t = print_otag(p, TAG_MO, "");
159                 print_text(p, bp->bottom);
160                 print_tagq(p, t);
161         }
162         if (NULL != bp->top) {
163                 t = print_otag(p, TAG_MO, "");
164                 print_text(p, bp->top);
165                 print_tagq(p, t);
166         }
167
168         if (NULL != post)
169                 print_tagq(p, post);
170
171         eqn_box(p, bp->next);
172 }
173
174 void
175 print_eqn(struct html *p, const struct eqn *ep)
176 {
177         struct tag      *t;
178
179         t = print_otag(p, TAG_MATH, "c", "eqn");
180
181         p->flags |= HTML_NONOSPACE;
182         eqn_box(p, ep->root);
183         p->flags &= ~HTML_NONOSPACE;
184
185         print_tagq(p, t);
186 }