1*c1c95addSBrooks Davis /* $Id: demandoc.c,v 1.34 2022/04/14 16:43:43 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 361d06d6bSBaptiste Daroussin * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> 461d06d6bSBaptiste Daroussin * 561d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 661d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 761d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 861d06d6bSBaptiste Daroussin * 961d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1061d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1161d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1261d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1361d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1461d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1561d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1661d06d6bSBaptiste Daroussin */ 1761d06d6bSBaptiste Daroussin #include "config.h" 1861d06d6bSBaptiste Daroussin 1961d06d6bSBaptiste Daroussin #include <sys/types.h> 2061d06d6bSBaptiste Daroussin 2161d06d6bSBaptiste Daroussin #include <assert.h> 2261d06d6bSBaptiste Daroussin #include <ctype.h> 2361d06d6bSBaptiste Daroussin #include <stdio.h> 2461d06d6bSBaptiste Daroussin #include <stdlib.h> 2561d06d6bSBaptiste Daroussin #include <string.h> 2661d06d6bSBaptiste Daroussin #include <unistd.h> 2761d06d6bSBaptiste Daroussin 2861d06d6bSBaptiste Daroussin #include "mandoc.h" 29*c1c95addSBrooks Davis #if DEBUG_MEMORY 30*c1c95addSBrooks Davis #define DEBUG_NODEF 31*c1c95addSBrooks Davis #include "mandoc_dbg.h" 32*c1c95addSBrooks Davis #endif 3361d06d6bSBaptiste Daroussin #include "roff.h" 3461d06d6bSBaptiste Daroussin #include "man.h" 3561d06d6bSBaptiste Daroussin #include "mdoc.h" 367295610fSBaptiste Daroussin #include "mandoc_parse.h" 3761d06d6bSBaptiste Daroussin 3861d06d6bSBaptiste Daroussin static void pline(int, int *, int *, int); 3961d06d6bSBaptiste Daroussin static void pman(const struct roff_node *, int *, int *, int); 4061d06d6bSBaptiste Daroussin static void pmandoc(struct mparse *, int, const char *, int); 4161d06d6bSBaptiste Daroussin static void pmdoc(const struct roff_node *, int *, int *, int); 4261d06d6bSBaptiste Daroussin static void pstring(const char *, int, int *, int); 4361d06d6bSBaptiste Daroussin static void usage(void); 4461d06d6bSBaptiste Daroussin 4561d06d6bSBaptiste Daroussin static const char *progname; 4661d06d6bSBaptiste Daroussin 4761d06d6bSBaptiste Daroussin int 4861d06d6bSBaptiste Daroussin main(int argc, char *argv[]) 4961d06d6bSBaptiste Daroussin { 5061d06d6bSBaptiste Daroussin struct mparse *mp; 5161d06d6bSBaptiste Daroussin int ch, fd, i, list; 5261d06d6bSBaptiste Daroussin extern int optind; 5361d06d6bSBaptiste Daroussin 54*c1c95addSBrooks Davis #if DEBUG_MEMORY 55*c1c95addSBrooks Davis mandoc_dbg_init(argc, argv); 56*c1c95addSBrooks Davis #endif 57*c1c95addSBrooks Davis 5861d06d6bSBaptiste Daroussin if (argc < 1) 5961d06d6bSBaptiste Daroussin progname = "demandoc"; 6061d06d6bSBaptiste Daroussin else if ((progname = strrchr(argv[0], '/')) == NULL) 6161d06d6bSBaptiste Daroussin progname = argv[0]; 6261d06d6bSBaptiste Daroussin else 6361d06d6bSBaptiste Daroussin ++progname; 6461d06d6bSBaptiste Daroussin 6561d06d6bSBaptiste Daroussin mp = NULL; 6661d06d6bSBaptiste Daroussin list = 0; 6761d06d6bSBaptiste Daroussin 6861d06d6bSBaptiste Daroussin while (-1 != (ch = getopt(argc, argv, "ikm:pw"))) 6961d06d6bSBaptiste Daroussin switch (ch) { 7061d06d6bSBaptiste Daroussin case ('i'): 7161d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 7261d06d6bSBaptiste Daroussin case ('k'): 7361d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 7461d06d6bSBaptiste Daroussin case ('m'): 7561d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 7661d06d6bSBaptiste Daroussin case ('p'): 7761d06d6bSBaptiste Daroussin break; 7861d06d6bSBaptiste Daroussin case ('w'): 7961d06d6bSBaptiste Daroussin list = 1; 8061d06d6bSBaptiste Daroussin break; 8161d06d6bSBaptiste Daroussin default: 8261d06d6bSBaptiste Daroussin usage(); 8361d06d6bSBaptiste Daroussin return (int)MANDOCLEVEL_BADARG; 8461d06d6bSBaptiste Daroussin } 8561d06d6bSBaptiste Daroussin 8661d06d6bSBaptiste Daroussin argc -= optind; 8761d06d6bSBaptiste Daroussin argv += optind; 8861d06d6bSBaptiste Daroussin 8961d06d6bSBaptiste Daroussin mchars_alloc(); 907295610fSBaptiste Daroussin mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 | 917295610fSBaptiste Daroussin MPARSE_VALIDATE, MANDOC_OS_OTHER, NULL); 9261d06d6bSBaptiste Daroussin assert(mp); 9361d06d6bSBaptiste Daroussin 9461d06d6bSBaptiste Daroussin if (argc < 1) 9561d06d6bSBaptiste Daroussin pmandoc(mp, STDIN_FILENO, "<stdin>", list); 9661d06d6bSBaptiste Daroussin 9761d06d6bSBaptiste Daroussin for (i = 0; i < argc; i++) { 9861d06d6bSBaptiste Daroussin mparse_reset(mp); 9961d06d6bSBaptiste Daroussin if ((fd = mparse_open(mp, argv[i])) == -1) { 10061d06d6bSBaptiste Daroussin perror(argv[i]); 10161d06d6bSBaptiste Daroussin continue; 10261d06d6bSBaptiste Daroussin } 10361d06d6bSBaptiste Daroussin pmandoc(mp, fd, argv[i], list); 10461d06d6bSBaptiste Daroussin } 10561d06d6bSBaptiste Daroussin 10661d06d6bSBaptiste Daroussin mparse_free(mp); 10761d06d6bSBaptiste Daroussin mchars_free(); 108*c1c95addSBrooks Davis #if DEBUG_MEMORY 109*c1c95addSBrooks Davis mandoc_dbg_finish(); 110*c1c95addSBrooks Davis #endif 11161d06d6bSBaptiste Daroussin return (int)MANDOCLEVEL_OK; 11261d06d6bSBaptiste Daroussin } 11361d06d6bSBaptiste Daroussin 11461d06d6bSBaptiste Daroussin static void 11561d06d6bSBaptiste Daroussin usage(void) 11661d06d6bSBaptiste Daroussin { 11761d06d6bSBaptiste Daroussin 11861d06d6bSBaptiste Daroussin fprintf(stderr, "usage: %s [-w] [files...]\n", progname); 11961d06d6bSBaptiste Daroussin } 12061d06d6bSBaptiste Daroussin 12161d06d6bSBaptiste Daroussin static void 12261d06d6bSBaptiste Daroussin pmandoc(struct mparse *mp, int fd, const char *fn, int list) 12361d06d6bSBaptiste Daroussin { 1247295610fSBaptiste Daroussin struct roff_meta *meta; 12561d06d6bSBaptiste Daroussin int line, col; 12661d06d6bSBaptiste Daroussin 12761d06d6bSBaptiste Daroussin mparse_readfd(mp, fd, fn); 12861d06d6bSBaptiste Daroussin close(fd); 1297295610fSBaptiste Daroussin meta = mparse_result(mp); 13061d06d6bSBaptiste Daroussin line = 1; 13161d06d6bSBaptiste Daroussin col = 0; 13261d06d6bSBaptiste Daroussin 1337295610fSBaptiste Daroussin if (meta->macroset == MACROSET_MDOC) 1347295610fSBaptiste Daroussin pmdoc(meta->first->child, &line, &col, list); 1357295610fSBaptiste Daroussin else 1367295610fSBaptiste Daroussin pman(meta->first->child, &line, &col, list); 13761d06d6bSBaptiste Daroussin 13861d06d6bSBaptiste Daroussin if ( ! list) 13961d06d6bSBaptiste Daroussin putchar('\n'); 14061d06d6bSBaptiste Daroussin } 14161d06d6bSBaptiste Daroussin 14261d06d6bSBaptiste Daroussin /* 14361d06d6bSBaptiste Daroussin * Strip the escapes out of a string, emitting the results. 14461d06d6bSBaptiste Daroussin */ 14561d06d6bSBaptiste Daroussin static void 14661d06d6bSBaptiste Daroussin pstring(const char *p, int col, int *colp, int list) 14761d06d6bSBaptiste Daroussin { 14861d06d6bSBaptiste Daroussin enum mandoc_esc esc; 14961d06d6bSBaptiste Daroussin const char *start, *end; 15061d06d6bSBaptiste Daroussin int emit; 15161d06d6bSBaptiste Daroussin 15261d06d6bSBaptiste Daroussin /* 15361d06d6bSBaptiste Daroussin * Print as many column spaces til we achieve parity with the 15461d06d6bSBaptiste Daroussin * input document. 15561d06d6bSBaptiste Daroussin */ 15661d06d6bSBaptiste Daroussin 15761d06d6bSBaptiste Daroussin again: 15861d06d6bSBaptiste Daroussin if (list && '\0' != *p) { 15961d06d6bSBaptiste Daroussin while (isspace((unsigned char)*p)) 16061d06d6bSBaptiste Daroussin p++; 16161d06d6bSBaptiste Daroussin 16261d06d6bSBaptiste Daroussin while ('\'' == *p || '(' == *p || '"' == *p) 16361d06d6bSBaptiste Daroussin p++; 16461d06d6bSBaptiste Daroussin 16561d06d6bSBaptiste Daroussin emit = isalpha((unsigned char)p[0]) && 16661d06d6bSBaptiste Daroussin isalpha((unsigned char)p[1]); 16761d06d6bSBaptiste Daroussin 16861d06d6bSBaptiste Daroussin for (start = p; '\0' != *p; p++) 16961d06d6bSBaptiste Daroussin if ('\\' == *p) { 17061d06d6bSBaptiste Daroussin p++; 17161d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL); 17261d06d6bSBaptiste Daroussin if (ESCAPE_ERROR == esc) 17361d06d6bSBaptiste Daroussin return; 17461d06d6bSBaptiste Daroussin emit = 0; 17561d06d6bSBaptiste Daroussin } else if (isspace((unsigned char)*p)) 17661d06d6bSBaptiste Daroussin break; 17761d06d6bSBaptiste Daroussin 17861d06d6bSBaptiste Daroussin end = p - 1; 17961d06d6bSBaptiste Daroussin 18061d06d6bSBaptiste Daroussin while (end > start) 18161d06d6bSBaptiste Daroussin if ('.' == *end || ',' == *end || 18261d06d6bSBaptiste Daroussin '\'' == *end || '"' == *end || 18361d06d6bSBaptiste Daroussin ')' == *end || '!' == *end || 18461d06d6bSBaptiste Daroussin '?' == *end || ':' == *end || 18561d06d6bSBaptiste Daroussin ';' == *end) 18661d06d6bSBaptiste Daroussin end--; 18761d06d6bSBaptiste Daroussin else 18861d06d6bSBaptiste Daroussin break; 18961d06d6bSBaptiste Daroussin 19061d06d6bSBaptiste Daroussin if (emit && end - start >= 1) { 19161d06d6bSBaptiste Daroussin for ( ; start <= end; start++) 19261d06d6bSBaptiste Daroussin if (ASCII_HYPH == *start) 19361d06d6bSBaptiste Daroussin putchar('-'); 19461d06d6bSBaptiste Daroussin else 19561d06d6bSBaptiste Daroussin putchar((unsigned char)*start); 19661d06d6bSBaptiste Daroussin putchar('\n'); 19761d06d6bSBaptiste Daroussin } 19861d06d6bSBaptiste Daroussin 19961d06d6bSBaptiste Daroussin if (isspace((unsigned char)*p)) 20061d06d6bSBaptiste Daroussin goto again; 20161d06d6bSBaptiste Daroussin 20261d06d6bSBaptiste Daroussin return; 20361d06d6bSBaptiste Daroussin } 20461d06d6bSBaptiste Daroussin 20561d06d6bSBaptiste Daroussin while (*colp < col) { 20661d06d6bSBaptiste Daroussin putchar(' '); 20761d06d6bSBaptiste Daroussin (*colp)++; 20861d06d6bSBaptiste Daroussin } 20961d06d6bSBaptiste Daroussin 21061d06d6bSBaptiste Daroussin /* 21161d06d6bSBaptiste Daroussin * Print the input word, skipping any special characters. 21261d06d6bSBaptiste Daroussin */ 21361d06d6bSBaptiste Daroussin while ('\0' != *p) 21461d06d6bSBaptiste Daroussin if ('\\' == *p) { 21561d06d6bSBaptiste Daroussin p++; 21661d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL); 21761d06d6bSBaptiste Daroussin if (ESCAPE_ERROR == esc) 21861d06d6bSBaptiste Daroussin break; 21961d06d6bSBaptiste Daroussin } else { 22061d06d6bSBaptiste Daroussin putchar((unsigned char )*p++); 22161d06d6bSBaptiste Daroussin (*colp)++; 22261d06d6bSBaptiste Daroussin } 22361d06d6bSBaptiste Daroussin } 22461d06d6bSBaptiste Daroussin 22561d06d6bSBaptiste Daroussin static void 22661d06d6bSBaptiste Daroussin pline(int line, int *linep, int *col, int list) 22761d06d6bSBaptiste Daroussin { 22861d06d6bSBaptiste Daroussin 22961d06d6bSBaptiste Daroussin if (list) 23061d06d6bSBaptiste Daroussin return; 23161d06d6bSBaptiste Daroussin 23261d06d6bSBaptiste Daroussin /* 23361d06d6bSBaptiste Daroussin * Print out as many lines as needed to reach parity with the 23461d06d6bSBaptiste Daroussin * original input. 23561d06d6bSBaptiste Daroussin */ 23661d06d6bSBaptiste Daroussin 23761d06d6bSBaptiste Daroussin while (*linep < line) { 23861d06d6bSBaptiste Daroussin putchar('\n'); 23961d06d6bSBaptiste Daroussin (*linep)++; 24061d06d6bSBaptiste Daroussin } 24161d06d6bSBaptiste Daroussin 24261d06d6bSBaptiste Daroussin *col = 0; 24361d06d6bSBaptiste Daroussin } 24461d06d6bSBaptiste Daroussin 24561d06d6bSBaptiste Daroussin static void 24661d06d6bSBaptiste Daroussin pmdoc(const struct roff_node *p, int *line, int *col, int list) 24761d06d6bSBaptiste Daroussin { 24861d06d6bSBaptiste Daroussin 24961d06d6bSBaptiste Daroussin for ( ; p; p = p->next) { 25061d06d6bSBaptiste Daroussin if (NODE_LINE & p->flags) 25161d06d6bSBaptiste Daroussin pline(p->line, line, col, list); 25261d06d6bSBaptiste Daroussin if (ROFFT_TEXT == p->type) 25361d06d6bSBaptiste Daroussin pstring(p->string, p->pos, col, list); 25461d06d6bSBaptiste Daroussin if (p->child) 25561d06d6bSBaptiste Daroussin pmdoc(p->child, line, col, list); 25661d06d6bSBaptiste Daroussin } 25761d06d6bSBaptiste Daroussin } 25861d06d6bSBaptiste Daroussin 25961d06d6bSBaptiste Daroussin static void 26061d06d6bSBaptiste Daroussin pman(const struct roff_node *p, int *line, int *col, int list) 26161d06d6bSBaptiste Daroussin { 26261d06d6bSBaptiste Daroussin 26361d06d6bSBaptiste Daroussin for ( ; p; p = p->next) { 26461d06d6bSBaptiste Daroussin if (NODE_LINE & p->flags) 26561d06d6bSBaptiste Daroussin pline(p->line, line, col, list); 26661d06d6bSBaptiste Daroussin if (ROFFT_TEXT == p->type) 26761d06d6bSBaptiste Daroussin pstring(p->string, p->pos, col, list); 26861d06d6bSBaptiste Daroussin if (p->child) 26961d06d6bSBaptiste Daroussin pman(p->child, line, col, list); 27061d06d6bSBaptiste Daroussin } 27161d06d6bSBaptiste Daroussin } 272