1*6d38604fSBaptiste Daroussin /* $Id: tbl_html.c,v 1.38 2021/09/09 16:52:52 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 361d06d6bSBaptiste Daroussin * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*6d38604fSBaptiste Daroussin * Copyright (c) 2014,2015,2017,2018,2021 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" 2845a5aec3SBaptiste Daroussin #include "roff.h" 297295610fSBaptiste Daroussin #include "tbl.h" 3061d06d6bSBaptiste Daroussin #include "out.h" 3161d06d6bSBaptiste Daroussin #include "html.h" 3261d06d6bSBaptiste Daroussin 3361d06d6bSBaptiste Daroussin static void html_tblopen(struct html *, const struct tbl_span *); 3461d06d6bSBaptiste Daroussin static size_t html_tbl_len(size_t, void *); 3561d06d6bSBaptiste Daroussin static size_t html_tbl_strlen(const char *, void *); 3661d06d6bSBaptiste Daroussin static size_t html_tbl_sulen(const struct roffsu *, void *); 3761d06d6bSBaptiste Daroussin 3861d06d6bSBaptiste Daroussin 3961d06d6bSBaptiste Daroussin static size_t 4061d06d6bSBaptiste Daroussin html_tbl_len(size_t sz, void *arg) 4161d06d6bSBaptiste Daroussin { 4261d06d6bSBaptiste Daroussin return sz; 4361d06d6bSBaptiste Daroussin } 4461d06d6bSBaptiste Daroussin 4561d06d6bSBaptiste Daroussin static size_t 4661d06d6bSBaptiste Daroussin html_tbl_strlen(const char *p, void *arg) 4761d06d6bSBaptiste Daroussin { 4861d06d6bSBaptiste Daroussin return strlen(p); 4961d06d6bSBaptiste Daroussin } 5061d06d6bSBaptiste Daroussin 5161d06d6bSBaptiste Daroussin static size_t 5261d06d6bSBaptiste Daroussin html_tbl_sulen(const struct roffsu *su, void *arg) 5361d06d6bSBaptiste Daroussin { 5461d06d6bSBaptiste Daroussin if (su->scale < 0.0) 5561d06d6bSBaptiste Daroussin return 0; 5661d06d6bSBaptiste Daroussin 5761d06d6bSBaptiste Daroussin switch (su->unit) { 5861d06d6bSBaptiste Daroussin case SCALE_FS: /* 2^16 basic units */ 5961d06d6bSBaptiste Daroussin return su->scale * 65536.0 / 24.0; 6061d06d6bSBaptiste Daroussin case SCALE_IN: /* 10 characters per inch */ 6161d06d6bSBaptiste Daroussin return su->scale * 10.0; 6261d06d6bSBaptiste Daroussin case SCALE_CM: /* 2.54 cm per inch */ 6361d06d6bSBaptiste Daroussin return su->scale * 10.0 / 2.54; 6461d06d6bSBaptiste Daroussin case SCALE_PC: /* 6 pica per inch */ 6561d06d6bSBaptiste Daroussin case SCALE_VS: 6661d06d6bSBaptiste Daroussin return su->scale * 10.0 / 6.0; 6761d06d6bSBaptiste Daroussin case SCALE_EN: 6861d06d6bSBaptiste Daroussin case SCALE_EM: 6961d06d6bSBaptiste Daroussin return su->scale; 7061d06d6bSBaptiste Daroussin case SCALE_PT: /* 12 points per pica */ 7161d06d6bSBaptiste Daroussin return su->scale * 10.0 / 6.0 / 12.0; 7261d06d6bSBaptiste Daroussin case SCALE_BU: /* 24 basic units per character */ 7361d06d6bSBaptiste Daroussin return su->scale / 24.0; 7461d06d6bSBaptiste Daroussin case SCALE_MM: /* 1/1000 inch */ 7561d06d6bSBaptiste Daroussin return su->scale / 100.0; 7661d06d6bSBaptiste Daroussin default: 7761d06d6bSBaptiste Daroussin abort(); 7861d06d6bSBaptiste Daroussin } 7961d06d6bSBaptiste Daroussin } 8061d06d6bSBaptiste Daroussin 8161d06d6bSBaptiste Daroussin static void 8261d06d6bSBaptiste Daroussin html_tblopen(struct html *h, const struct tbl_span *sp) 8361d06d6bSBaptiste Daroussin { 847295610fSBaptiste Daroussin html_close_paragraph(h); 8561d06d6bSBaptiste Daroussin if (h->tbl.cols == NULL) { 8661d06d6bSBaptiste Daroussin h->tbl.len = html_tbl_len; 8761d06d6bSBaptiste Daroussin h->tbl.slen = html_tbl_strlen; 8861d06d6bSBaptiste Daroussin h->tbl.sulen = html_tbl_sulen; 8961d06d6bSBaptiste Daroussin tblcalc(&h->tbl, sp, 0, 0); 9061d06d6bSBaptiste Daroussin } 9161d06d6bSBaptiste Daroussin assert(NULL == h->tblt); 927295610fSBaptiste Daroussin h->tblt = print_otag(h, TAG_TABLE, "c?ss", "tbl", 937295610fSBaptiste Daroussin "border", 947295610fSBaptiste Daroussin sp->opts->opts & TBL_OPT_ALLBOX ? "1" : NULL, 957295610fSBaptiste Daroussin "border-style", 967295610fSBaptiste Daroussin sp->opts->opts & TBL_OPT_DBOX ? "double" : 977295610fSBaptiste Daroussin sp->opts->opts & TBL_OPT_BOX ? "solid" : NULL, 987295610fSBaptiste Daroussin "border-top-style", 997295610fSBaptiste Daroussin sp->pos == TBL_SPAN_DHORIZ ? "double" : 1007295610fSBaptiste Daroussin sp->pos == TBL_SPAN_HORIZ ? "solid" : NULL); 10161d06d6bSBaptiste Daroussin } 10261d06d6bSBaptiste Daroussin 10361d06d6bSBaptiste Daroussin void 10461d06d6bSBaptiste Daroussin print_tblclose(struct html *h) 10561d06d6bSBaptiste Daroussin { 10661d06d6bSBaptiste Daroussin 10761d06d6bSBaptiste Daroussin assert(h->tblt); 10861d06d6bSBaptiste Daroussin print_tagq(h, h->tblt); 10961d06d6bSBaptiste Daroussin h->tblt = NULL; 11061d06d6bSBaptiste Daroussin } 11161d06d6bSBaptiste Daroussin 11261d06d6bSBaptiste Daroussin void 11361d06d6bSBaptiste Daroussin print_tbl(struct html *h, const struct tbl_span *sp) 11461d06d6bSBaptiste Daroussin { 11561d06d6bSBaptiste Daroussin const struct tbl_dat *dp; 1167295610fSBaptiste Daroussin const struct tbl_cell *cp; 1177295610fSBaptiste Daroussin const struct tbl_span *psp; 118*6d38604fSBaptiste Daroussin const struct roffcol *col; 11961d06d6bSBaptiste Daroussin struct tag *tt; 1207295610fSBaptiste Daroussin const char *hspans, *vspans, *halign, *valign; 1217295610fSBaptiste Daroussin const char *bborder, *lborder, *rborder; 122*6d38604fSBaptiste Daroussin const char *ccp; 1237295610fSBaptiste Daroussin char hbuf[4], vbuf[4]; 124*6d38604fSBaptiste Daroussin size_t sz; 125*6d38604fSBaptiste Daroussin enum mandoc_esc save_font; 1267295610fSBaptiste Daroussin int i; 12761d06d6bSBaptiste Daroussin 12861d06d6bSBaptiste Daroussin if (h->tblt == NULL) 12961d06d6bSBaptiste Daroussin html_tblopen(h, sp); 13061d06d6bSBaptiste Daroussin 1317295610fSBaptiste Daroussin /* 1327295610fSBaptiste Daroussin * Horizontal lines spanning the whole table 1337295610fSBaptiste Daroussin * are handled by previous or following table rows. 1347295610fSBaptiste Daroussin */ 1357295610fSBaptiste Daroussin 1367295610fSBaptiste Daroussin if (sp->pos != TBL_SPAN_DATA) 1377295610fSBaptiste Daroussin return; 1387295610fSBaptiste Daroussin 1397295610fSBaptiste Daroussin /* Inhibit printing of spaces: we do padding ourselves. */ 14061d06d6bSBaptiste Daroussin 14161d06d6bSBaptiste Daroussin h->flags |= HTML_NONOSPACE; 14261d06d6bSBaptiste Daroussin h->flags |= HTML_NOSPACE; 14361d06d6bSBaptiste Daroussin 1447295610fSBaptiste Daroussin /* Draw a vertical line left of this row? */ 14561d06d6bSBaptiste Daroussin 1467295610fSBaptiste Daroussin switch (sp->layout->vert) { 1477295610fSBaptiste Daroussin case 2: 1487295610fSBaptiste Daroussin lborder = "double"; 1497295610fSBaptiste Daroussin break; 1507295610fSBaptiste Daroussin case 1: 1517295610fSBaptiste Daroussin lborder = "solid"; 15261d06d6bSBaptiste Daroussin break; 15361d06d6bSBaptiste Daroussin default: 1547295610fSBaptiste Daroussin lborder = NULL; 1557295610fSBaptiste Daroussin break; 1567295610fSBaptiste Daroussin } 15761d06d6bSBaptiste Daroussin 1587295610fSBaptiste Daroussin /* Draw a horizontal line below this row? */ 1597295610fSBaptiste Daroussin 1607295610fSBaptiste Daroussin bborder = NULL; 1617295610fSBaptiste Daroussin if ((psp = sp->next) != NULL) { 1627295610fSBaptiste Daroussin switch (psp->pos) { 1637295610fSBaptiste Daroussin case TBL_SPAN_DHORIZ: 1647295610fSBaptiste Daroussin bborder = "double"; 1657295610fSBaptiste Daroussin break; 1667295610fSBaptiste Daroussin case TBL_SPAN_HORIZ: 1677295610fSBaptiste Daroussin bborder = "solid"; 1687295610fSBaptiste Daroussin break; 1697295610fSBaptiste Daroussin default: 1707295610fSBaptiste Daroussin break; 1717295610fSBaptiste Daroussin } 1727295610fSBaptiste Daroussin } 1737295610fSBaptiste Daroussin 1747295610fSBaptiste Daroussin tt = print_otag(h, TAG_TR, "ss", 1757295610fSBaptiste Daroussin "border-left-style", lborder, 1767295610fSBaptiste Daroussin "border-bottom-style", bborder); 1777295610fSBaptiste Daroussin 1787295610fSBaptiste Daroussin for (dp = sp->first; dp != NULL; dp = dp->next) { 1797295610fSBaptiste Daroussin print_stagq(h, tt); 1807295610fSBaptiste Daroussin 1817295610fSBaptiste Daroussin /* 1827295610fSBaptiste Daroussin * Do not generate <td> elements for continuations 1837295610fSBaptiste Daroussin * of spanned cells. Larger <td> elements covering 1847295610fSBaptiste Daroussin * this space were already generated earlier. 1857295610fSBaptiste Daroussin */ 1867295610fSBaptiste Daroussin 1877295610fSBaptiste Daroussin cp = dp->layout; 1887295610fSBaptiste Daroussin if (cp->pos == TBL_CELL_SPAN || cp->pos == TBL_CELL_DOWN || 1897295610fSBaptiste Daroussin (dp->string != NULL && strcmp(dp->string, "\\^") == 0)) 19061d06d6bSBaptiste Daroussin continue; 1917295610fSBaptiste Daroussin 1927295610fSBaptiste Daroussin /* Determine the attribute values. */ 1937295610fSBaptiste Daroussin 1947295610fSBaptiste Daroussin if (dp->hspans > 0) { 1957295610fSBaptiste Daroussin (void)snprintf(hbuf, sizeof(hbuf), 1967295610fSBaptiste Daroussin "%d", dp->hspans + 1); 1977295610fSBaptiste Daroussin hspans = hbuf; 1987295610fSBaptiste Daroussin } else 1997295610fSBaptiste Daroussin hspans = NULL; 2007295610fSBaptiste Daroussin if (dp->vspans > 0) { 2017295610fSBaptiste Daroussin (void)snprintf(vbuf, sizeof(vbuf), 2027295610fSBaptiste Daroussin "%d", dp->vspans + 1); 2037295610fSBaptiste Daroussin vspans = vbuf; 2047295610fSBaptiste Daroussin } else 2057295610fSBaptiste Daroussin vspans = NULL; 2067295610fSBaptiste Daroussin 2077295610fSBaptiste Daroussin switch (cp->pos) { 2087295610fSBaptiste Daroussin case TBL_CELL_CENTRE: 2097295610fSBaptiste Daroussin halign = "center"; 2107295610fSBaptiste Daroussin break; 2117295610fSBaptiste Daroussin case TBL_CELL_RIGHT: 2127295610fSBaptiste Daroussin case TBL_CELL_NUMBER: 2137295610fSBaptiste Daroussin halign = "right"; 2147295610fSBaptiste Daroussin break; 2157295610fSBaptiste Daroussin default: 2167295610fSBaptiste Daroussin halign = NULL; 2177295610fSBaptiste Daroussin break; 2187295610fSBaptiste Daroussin } 2197295610fSBaptiste Daroussin if (cp->flags & TBL_CELL_TALIGN) 2207295610fSBaptiste Daroussin valign = "top"; 2217295610fSBaptiste Daroussin else if (cp->flags & TBL_CELL_BALIGN) 2227295610fSBaptiste Daroussin valign = "bottom"; 2237295610fSBaptiste Daroussin else 2247295610fSBaptiste Daroussin valign = NULL; 2257295610fSBaptiste Daroussin 2267295610fSBaptiste Daroussin for (i = dp->hspans; i > 0; i--) 2277295610fSBaptiste Daroussin cp = cp->next; 2287295610fSBaptiste Daroussin switch (cp->vert) { 2297295610fSBaptiste Daroussin case 2: 2307295610fSBaptiste Daroussin rborder = "double"; 2317295610fSBaptiste Daroussin break; 2327295610fSBaptiste Daroussin case 1: 2337295610fSBaptiste Daroussin rborder = "solid"; 2347295610fSBaptiste Daroussin break; 2357295610fSBaptiste Daroussin default: 2367295610fSBaptiste Daroussin rborder = NULL; 2377295610fSBaptiste Daroussin break; 2387295610fSBaptiste Daroussin } 2397295610fSBaptiste Daroussin 2407295610fSBaptiste Daroussin /* Print the element and the attributes. */ 2417295610fSBaptiste Daroussin 2427295610fSBaptiste Daroussin print_otag(h, TAG_TD, "??sss", 2437295610fSBaptiste Daroussin "colspan", hspans, "rowspan", vspans, 2447295610fSBaptiste Daroussin "vertical-align", valign, 2457295610fSBaptiste Daroussin "text-align", halign, 2467295610fSBaptiste Daroussin "border-right-style", rborder); 247*6d38604fSBaptiste Daroussin if (dp->layout->pos == TBL_CELL_HORIZ || 248*6d38604fSBaptiste Daroussin dp->layout->pos == TBL_CELL_DHORIZ || 249*6d38604fSBaptiste Daroussin dp->pos == TBL_DATA_HORIZ || 250*6d38604fSBaptiste Daroussin dp->pos == TBL_DATA_DHORIZ) 251*6d38604fSBaptiste Daroussin print_otag(h, TAG_HR, ""); 252*6d38604fSBaptiste Daroussin else if (dp->string != NULL) { 253*6d38604fSBaptiste Daroussin save_font = h->metac; 254*6d38604fSBaptiste Daroussin html_setfont(h, dp->layout->font); 255*6d38604fSBaptiste Daroussin if (dp->layout->pos == TBL_CELL_LONG) 256*6d38604fSBaptiste Daroussin print_text(h, "\\[u2003]"); /* em space */ 25761d06d6bSBaptiste Daroussin print_text(h, dp->string); 258*6d38604fSBaptiste Daroussin if (dp->layout->pos == TBL_CELL_NUMBER) { 259*6d38604fSBaptiste Daroussin col = h->tbl.cols + dp->layout->col; 260*6d38604fSBaptiste Daroussin if (col->decimal < col->nwidth) { 261*6d38604fSBaptiste Daroussin if ((ccp = strrchr(dp->string, 262*6d38604fSBaptiste Daroussin sp->opts->decimal)) == NULL) { 263*6d38604fSBaptiste Daroussin /* Punctuation space. */ 264*6d38604fSBaptiste Daroussin print_text(h, "\\[u2008]"); 265*6d38604fSBaptiste Daroussin ccp = strchr(dp->string, '\0'); 266*6d38604fSBaptiste Daroussin } else 267*6d38604fSBaptiste Daroussin ccp++; 268*6d38604fSBaptiste Daroussin sz = col->nwidth - col->decimal; 269*6d38604fSBaptiste Daroussin while (--sz > 0) { 270*6d38604fSBaptiste Daroussin if (*ccp == '\0') 271*6d38604fSBaptiste Daroussin /* Figure space. */ 272*6d38604fSBaptiste Daroussin print_text(h, 273*6d38604fSBaptiste Daroussin "\\[u2007]"); 274*6d38604fSBaptiste Daroussin else 275*6d38604fSBaptiste Daroussin ccp++; 276*6d38604fSBaptiste Daroussin } 277*6d38604fSBaptiste Daroussin } 278*6d38604fSBaptiste Daroussin } 279*6d38604fSBaptiste Daroussin html_setfont(h, save_font); 280*6d38604fSBaptiste Daroussin } 28161d06d6bSBaptiste Daroussin } 28261d06d6bSBaptiste Daroussin 28361d06d6bSBaptiste Daroussin print_tagq(h, tt); 28461d06d6bSBaptiste Daroussin 28561d06d6bSBaptiste Daroussin h->flags &= ~HTML_NONOSPACE; 28661d06d6bSBaptiste Daroussin 28761d06d6bSBaptiste Daroussin if (sp->next == NULL) { 28861d06d6bSBaptiste Daroussin assert(h->tbl.cols); 28961d06d6bSBaptiste Daroussin free(h->tbl.cols); 29061d06d6bSBaptiste Daroussin h->tbl.cols = NULL; 29161d06d6bSBaptiste Daroussin print_tblclose(h); 29261d06d6bSBaptiste Daroussin } 29361d06d6bSBaptiste Daroussin } 294