1*7295610fSBaptiste Daroussin /* $Id: tbl_html.c,v 1.32 2019/01/06 04:55:09 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 361d06d6bSBaptiste Daroussin * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*7295610fSBaptiste Daroussin * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org> 561d06d6bSBaptiste Daroussin * 661d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 761d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 861d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 961d06d6bSBaptiste Daroussin * 1061d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1161d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1261d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1361d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1461d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1561d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1661d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1761d06d6bSBaptiste Daroussin */ 1861d06d6bSBaptiste Daroussin #include "config.h" 1961d06d6bSBaptiste Daroussin 2061d06d6bSBaptiste Daroussin #include <sys/types.h> 2161d06d6bSBaptiste Daroussin 2261d06d6bSBaptiste Daroussin #include <assert.h> 2361d06d6bSBaptiste Daroussin #include <stdio.h> 2461d06d6bSBaptiste Daroussin #include <stdlib.h> 2561d06d6bSBaptiste Daroussin #include <string.h> 2661d06d6bSBaptiste Daroussin 2761d06d6bSBaptiste Daroussin #include "mandoc.h" 28*7295610fSBaptiste Daroussin #include "tbl.h" 2961d06d6bSBaptiste Daroussin #include "out.h" 3061d06d6bSBaptiste Daroussin #include "html.h" 3161d06d6bSBaptiste Daroussin 3261d06d6bSBaptiste Daroussin static void html_tblopen(struct html *, const struct tbl_span *); 3361d06d6bSBaptiste Daroussin static size_t html_tbl_len(size_t, void *); 3461d06d6bSBaptiste Daroussin static size_t html_tbl_strlen(const char *, void *); 3561d06d6bSBaptiste Daroussin static size_t html_tbl_sulen(const struct roffsu *, void *); 3661d06d6bSBaptiste Daroussin 3761d06d6bSBaptiste Daroussin 3861d06d6bSBaptiste Daroussin static size_t 3961d06d6bSBaptiste Daroussin html_tbl_len(size_t sz, void *arg) 4061d06d6bSBaptiste Daroussin { 4161d06d6bSBaptiste Daroussin return sz; 4261d06d6bSBaptiste Daroussin } 4361d06d6bSBaptiste Daroussin 4461d06d6bSBaptiste Daroussin static size_t 4561d06d6bSBaptiste Daroussin html_tbl_strlen(const char *p, void *arg) 4661d06d6bSBaptiste Daroussin { 4761d06d6bSBaptiste Daroussin return strlen(p); 4861d06d6bSBaptiste Daroussin } 4961d06d6bSBaptiste Daroussin 5061d06d6bSBaptiste Daroussin static size_t 5161d06d6bSBaptiste Daroussin html_tbl_sulen(const struct roffsu *su, void *arg) 5261d06d6bSBaptiste Daroussin { 5361d06d6bSBaptiste Daroussin if (su->scale < 0.0) 5461d06d6bSBaptiste Daroussin return 0; 5561d06d6bSBaptiste Daroussin 5661d06d6bSBaptiste Daroussin switch (su->unit) { 5761d06d6bSBaptiste Daroussin case SCALE_FS: /* 2^16 basic units */ 5861d06d6bSBaptiste Daroussin return su->scale * 65536.0 / 24.0; 5961d06d6bSBaptiste Daroussin case SCALE_IN: /* 10 characters per inch */ 6061d06d6bSBaptiste Daroussin return su->scale * 10.0; 6161d06d6bSBaptiste Daroussin case SCALE_CM: /* 2.54 cm per inch */ 6261d06d6bSBaptiste Daroussin return su->scale * 10.0 / 2.54; 6361d06d6bSBaptiste Daroussin case SCALE_PC: /* 6 pica per inch */ 6461d06d6bSBaptiste Daroussin case SCALE_VS: 6561d06d6bSBaptiste Daroussin return su->scale * 10.0 / 6.0; 6661d06d6bSBaptiste Daroussin case SCALE_EN: 6761d06d6bSBaptiste Daroussin case SCALE_EM: 6861d06d6bSBaptiste Daroussin return su->scale; 6961d06d6bSBaptiste Daroussin case SCALE_PT: /* 12 points per pica */ 7061d06d6bSBaptiste Daroussin return su->scale * 10.0 / 6.0 / 12.0; 7161d06d6bSBaptiste Daroussin case SCALE_BU: /* 24 basic units per character */ 7261d06d6bSBaptiste Daroussin return su->scale / 24.0; 7361d06d6bSBaptiste Daroussin case SCALE_MM: /* 1/1000 inch */ 7461d06d6bSBaptiste Daroussin return su->scale / 100.0; 7561d06d6bSBaptiste Daroussin default: 7661d06d6bSBaptiste Daroussin abort(); 7761d06d6bSBaptiste Daroussin } 7861d06d6bSBaptiste Daroussin } 7961d06d6bSBaptiste Daroussin 8061d06d6bSBaptiste Daroussin static void 8161d06d6bSBaptiste Daroussin html_tblopen(struct html *h, const struct tbl_span *sp) 8261d06d6bSBaptiste Daroussin { 83*7295610fSBaptiste Daroussin html_close_paragraph(h); 8461d06d6bSBaptiste Daroussin if (h->tbl.cols == NULL) { 8561d06d6bSBaptiste Daroussin h->tbl.len = html_tbl_len; 8661d06d6bSBaptiste Daroussin h->tbl.slen = html_tbl_strlen; 8761d06d6bSBaptiste Daroussin h->tbl.sulen = html_tbl_sulen; 8861d06d6bSBaptiste Daroussin tblcalc(&h->tbl, sp, 0, 0); 8961d06d6bSBaptiste Daroussin } 9061d06d6bSBaptiste Daroussin assert(NULL == h->tblt); 91*7295610fSBaptiste Daroussin h->tblt = print_otag(h, TAG_TABLE, "c?ss", "tbl", 92*7295610fSBaptiste Daroussin "border", 93*7295610fSBaptiste Daroussin sp->opts->opts & TBL_OPT_ALLBOX ? "1" : NULL, 94*7295610fSBaptiste Daroussin "border-style", 95*7295610fSBaptiste Daroussin sp->opts->opts & TBL_OPT_DBOX ? "double" : 96*7295610fSBaptiste Daroussin sp->opts->opts & TBL_OPT_BOX ? "solid" : NULL, 97*7295610fSBaptiste Daroussin "border-top-style", 98*7295610fSBaptiste Daroussin sp->pos == TBL_SPAN_DHORIZ ? "double" : 99*7295610fSBaptiste Daroussin sp->pos == TBL_SPAN_HORIZ ? "solid" : NULL); 10061d06d6bSBaptiste Daroussin } 10161d06d6bSBaptiste Daroussin 10261d06d6bSBaptiste Daroussin void 10361d06d6bSBaptiste Daroussin print_tblclose(struct html *h) 10461d06d6bSBaptiste Daroussin { 10561d06d6bSBaptiste Daroussin 10661d06d6bSBaptiste Daroussin assert(h->tblt); 10761d06d6bSBaptiste Daroussin print_tagq(h, h->tblt); 10861d06d6bSBaptiste Daroussin h->tblt = NULL; 10961d06d6bSBaptiste Daroussin } 11061d06d6bSBaptiste Daroussin 11161d06d6bSBaptiste Daroussin void 11261d06d6bSBaptiste Daroussin print_tbl(struct html *h, const struct tbl_span *sp) 11361d06d6bSBaptiste Daroussin { 11461d06d6bSBaptiste Daroussin const struct tbl_dat *dp; 115*7295610fSBaptiste Daroussin const struct tbl_cell *cp; 116*7295610fSBaptiste Daroussin const struct tbl_span *psp; 11761d06d6bSBaptiste Daroussin struct tag *tt; 118*7295610fSBaptiste Daroussin const char *hspans, *vspans, *halign, *valign; 119*7295610fSBaptiste Daroussin const char *bborder, *lborder, *rborder; 120*7295610fSBaptiste Daroussin char hbuf[4], vbuf[4]; 121*7295610fSBaptiste Daroussin int i; 12261d06d6bSBaptiste Daroussin 12361d06d6bSBaptiste Daroussin if (h->tblt == NULL) 12461d06d6bSBaptiste Daroussin html_tblopen(h, sp); 12561d06d6bSBaptiste Daroussin 126*7295610fSBaptiste Daroussin /* 127*7295610fSBaptiste Daroussin * Horizontal lines spanning the whole table 128*7295610fSBaptiste Daroussin * are handled by previous or following table rows. 129*7295610fSBaptiste Daroussin */ 130*7295610fSBaptiste Daroussin 131*7295610fSBaptiste Daroussin if (sp->pos != TBL_SPAN_DATA) 132*7295610fSBaptiste Daroussin return; 133*7295610fSBaptiste Daroussin 134*7295610fSBaptiste Daroussin /* Inhibit printing of spaces: we do padding ourselves. */ 13561d06d6bSBaptiste Daroussin 13661d06d6bSBaptiste Daroussin h->flags |= HTML_NONOSPACE; 13761d06d6bSBaptiste Daroussin h->flags |= HTML_NOSPACE; 13861d06d6bSBaptiste Daroussin 139*7295610fSBaptiste Daroussin /* Draw a vertical line left of this row? */ 14061d06d6bSBaptiste Daroussin 141*7295610fSBaptiste Daroussin switch (sp->layout->vert) { 142*7295610fSBaptiste Daroussin case 2: 143*7295610fSBaptiste Daroussin lborder = "double"; 144*7295610fSBaptiste Daroussin break; 145*7295610fSBaptiste Daroussin case 1: 146*7295610fSBaptiste Daroussin lborder = "solid"; 14761d06d6bSBaptiste Daroussin break; 14861d06d6bSBaptiste Daroussin default: 149*7295610fSBaptiste Daroussin lborder = NULL; 150*7295610fSBaptiste Daroussin break; 151*7295610fSBaptiste Daroussin } 15261d06d6bSBaptiste Daroussin 153*7295610fSBaptiste Daroussin /* Draw a horizontal line below this row? */ 154*7295610fSBaptiste Daroussin 155*7295610fSBaptiste Daroussin bborder = NULL; 156*7295610fSBaptiste Daroussin if ((psp = sp->next) != NULL) { 157*7295610fSBaptiste Daroussin switch (psp->pos) { 158*7295610fSBaptiste Daroussin case TBL_SPAN_DHORIZ: 159*7295610fSBaptiste Daroussin bborder = "double"; 160*7295610fSBaptiste Daroussin break; 161*7295610fSBaptiste Daroussin case TBL_SPAN_HORIZ: 162*7295610fSBaptiste Daroussin bborder = "solid"; 163*7295610fSBaptiste Daroussin break; 164*7295610fSBaptiste Daroussin default: 165*7295610fSBaptiste Daroussin break; 166*7295610fSBaptiste Daroussin } 167*7295610fSBaptiste Daroussin } 168*7295610fSBaptiste Daroussin 169*7295610fSBaptiste Daroussin tt = print_otag(h, TAG_TR, "ss", 170*7295610fSBaptiste Daroussin "border-left-style", lborder, 171*7295610fSBaptiste Daroussin "border-bottom-style", bborder); 172*7295610fSBaptiste Daroussin 173*7295610fSBaptiste Daroussin for (dp = sp->first; dp != NULL; dp = dp->next) { 174*7295610fSBaptiste Daroussin print_stagq(h, tt); 175*7295610fSBaptiste Daroussin 176*7295610fSBaptiste Daroussin /* 177*7295610fSBaptiste Daroussin * Do not generate <td> elements for continuations 178*7295610fSBaptiste Daroussin * of spanned cells. Larger <td> elements covering 179*7295610fSBaptiste Daroussin * this space were already generated earlier. 180*7295610fSBaptiste Daroussin */ 181*7295610fSBaptiste Daroussin 182*7295610fSBaptiste Daroussin cp = dp->layout; 183*7295610fSBaptiste Daroussin if (cp->pos == TBL_CELL_SPAN || cp->pos == TBL_CELL_DOWN || 184*7295610fSBaptiste Daroussin (dp->string != NULL && strcmp(dp->string, "\\^") == 0)) 18561d06d6bSBaptiste Daroussin continue; 186*7295610fSBaptiste Daroussin 187*7295610fSBaptiste Daroussin /* Determine the attribute values. */ 188*7295610fSBaptiste Daroussin 189*7295610fSBaptiste Daroussin if (dp->hspans > 0) { 190*7295610fSBaptiste Daroussin (void)snprintf(hbuf, sizeof(hbuf), 191*7295610fSBaptiste Daroussin "%d", dp->hspans + 1); 192*7295610fSBaptiste Daroussin hspans = hbuf; 193*7295610fSBaptiste Daroussin } else 194*7295610fSBaptiste Daroussin hspans = NULL; 195*7295610fSBaptiste Daroussin if (dp->vspans > 0) { 196*7295610fSBaptiste Daroussin (void)snprintf(vbuf, sizeof(vbuf), 197*7295610fSBaptiste Daroussin "%d", dp->vspans + 1); 198*7295610fSBaptiste Daroussin vspans = vbuf; 199*7295610fSBaptiste Daroussin } else 200*7295610fSBaptiste Daroussin vspans = NULL; 201*7295610fSBaptiste Daroussin 202*7295610fSBaptiste Daroussin switch (cp->pos) { 203*7295610fSBaptiste Daroussin case TBL_CELL_CENTRE: 204*7295610fSBaptiste Daroussin halign = "center"; 205*7295610fSBaptiste Daroussin break; 206*7295610fSBaptiste Daroussin case TBL_CELL_RIGHT: 207*7295610fSBaptiste Daroussin case TBL_CELL_NUMBER: 208*7295610fSBaptiste Daroussin halign = "right"; 209*7295610fSBaptiste Daroussin break; 210*7295610fSBaptiste Daroussin default: 211*7295610fSBaptiste Daroussin halign = NULL; 212*7295610fSBaptiste Daroussin break; 213*7295610fSBaptiste Daroussin } 214*7295610fSBaptiste Daroussin if (cp->flags & TBL_CELL_TALIGN) 215*7295610fSBaptiste Daroussin valign = "top"; 216*7295610fSBaptiste Daroussin else if (cp->flags & TBL_CELL_BALIGN) 217*7295610fSBaptiste Daroussin valign = "bottom"; 218*7295610fSBaptiste Daroussin else 219*7295610fSBaptiste Daroussin valign = NULL; 220*7295610fSBaptiste Daroussin 221*7295610fSBaptiste Daroussin for (i = dp->hspans; i > 0; i--) 222*7295610fSBaptiste Daroussin cp = cp->next; 223*7295610fSBaptiste Daroussin switch (cp->vert) { 224*7295610fSBaptiste Daroussin case 2: 225*7295610fSBaptiste Daroussin rborder = "double"; 226*7295610fSBaptiste Daroussin break; 227*7295610fSBaptiste Daroussin case 1: 228*7295610fSBaptiste Daroussin rborder = "solid"; 229*7295610fSBaptiste Daroussin break; 230*7295610fSBaptiste Daroussin default: 231*7295610fSBaptiste Daroussin rborder = NULL; 232*7295610fSBaptiste Daroussin break; 233*7295610fSBaptiste Daroussin } 234*7295610fSBaptiste Daroussin 235*7295610fSBaptiste Daroussin /* Print the element and the attributes. */ 236*7295610fSBaptiste Daroussin 237*7295610fSBaptiste Daroussin print_otag(h, TAG_TD, "??sss", 238*7295610fSBaptiste Daroussin "colspan", hspans, "rowspan", vspans, 239*7295610fSBaptiste Daroussin "vertical-align", valign, 240*7295610fSBaptiste Daroussin "text-align", halign, 241*7295610fSBaptiste Daroussin "border-right-style", rborder); 24261d06d6bSBaptiste Daroussin if (dp->string != NULL) 24361d06d6bSBaptiste Daroussin print_text(h, dp->string); 24461d06d6bSBaptiste Daroussin } 24561d06d6bSBaptiste Daroussin 24661d06d6bSBaptiste Daroussin print_tagq(h, tt); 24761d06d6bSBaptiste Daroussin 24861d06d6bSBaptiste Daroussin h->flags &= ~HTML_NONOSPACE; 24961d06d6bSBaptiste Daroussin 25061d06d6bSBaptiste Daroussin if (sp->next == NULL) { 25161d06d6bSBaptiste Daroussin assert(h->tbl.cols); 25261d06d6bSBaptiste Daroussin free(h->tbl.cols); 25361d06d6bSBaptiste Daroussin h->tbl.cols = NULL; 25461d06d6bSBaptiste Daroussin print_tblclose(h); 25561d06d6bSBaptiste Daroussin } 25661d06d6bSBaptiste Daroussin } 257