1*7295610fSBaptiste Daroussin /* $Id: demandoc.c,v 1.33 2019/03/03 11:01:15 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" 2961d06d6bSBaptiste Daroussin #include "roff.h" 3061d06d6bSBaptiste Daroussin #include "man.h" 3161d06d6bSBaptiste Daroussin #include "mdoc.h" 32*7295610fSBaptiste Daroussin #include "mandoc_parse.h" 3361d06d6bSBaptiste Daroussin 3461d06d6bSBaptiste Daroussin static void pline(int, int *, int *, int); 3561d06d6bSBaptiste Daroussin static void pman(const struct roff_node *, int *, int *, int); 3661d06d6bSBaptiste Daroussin static void pmandoc(struct mparse *, int, const char *, int); 3761d06d6bSBaptiste Daroussin static void pmdoc(const struct roff_node *, int *, int *, int); 3861d06d6bSBaptiste Daroussin static void pstring(const char *, int, int *, int); 3961d06d6bSBaptiste Daroussin static void usage(void); 4061d06d6bSBaptiste Daroussin 4161d06d6bSBaptiste Daroussin static const char *progname; 4261d06d6bSBaptiste Daroussin 4361d06d6bSBaptiste Daroussin int 4461d06d6bSBaptiste Daroussin main(int argc, char *argv[]) 4561d06d6bSBaptiste Daroussin { 4661d06d6bSBaptiste Daroussin struct mparse *mp; 4761d06d6bSBaptiste Daroussin int ch, fd, i, list; 4861d06d6bSBaptiste Daroussin extern int optind; 4961d06d6bSBaptiste Daroussin 5061d06d6bSBaptiste Daroussin if (argc < 1) 5161d06d6bSBaptiste Daroussin progname = "demandoc"; 5261d06d6bSBaptiste Daroussin else if ((progname = strrchr(argv[0], '/')) == NULL) 5361d06d6bSBaptiste Daroussin progname = argv[0]; 5461d06d6bSBaptiste Daroussin else 5561d06d6bSBaptiste Daroussin ++progname; 5661d06d6bSBaptiste Daroussin 5761d06d6bSBaptiste Daroussin mp = NULL; 5861d06d6bSBaptiste Daroussin list = 0; 5961d06d6bSBaptiste Daroussin 6061d06d6bSBaptiste Daroussin while (-1 != (ch = getopt(argc, argv, "ikm:pw"))) 6161d06d6bSBaptiste Daroussin switch (ch) { 6261d06d6bSBaptiste Daroussin case ('i'): 6361d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 6461d06d6bSBaptiste Daroussin case ('k'): 6561d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 6661d06d6bSBaptiste Daroussin case ('m'): 6761d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 6861d06d6bSBaptiste Daroussin case ('p'): 6961d06d6bSBaptiste Daroussin break; 7061d06d6bSBaptiste Daroussin case ('w'): 7161d06d6bSBaptiste Daroussin list = 1; 7261d06d6bSBaptiste Daroussin break; 7361d06d6bSBaptiste Daroussin default: 7461d06d6bSBaptiste Daroussin usage(); 7561d06d6bSBaptiste Daroussin return (int)MANDOCLEVEL_BADARG; 7661d06d6bSBaptiste Daroussin } 7761d06d6bSBaptiste Daroussin 7861d06d6bSBaptiste Daroussin argc -= optind; 7961d06d6bSBaptiste Daroussin argv += optind; 8061d06d6bSBaptiste Daroussin 8161d06d6bSBaptiste Daroussin mchars_alloc(); 82*7295610fSBaptiste Daroussin mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 | 83*7295610fSBaptiste Daroussin MPARSE_VALIDATE, MANDOC_OS_OTHER, NULL); 8461d06d6bSBaptiste Daroussin assert(mp); 8561d06d6bSBaptiste Daroussin 8661d06d6bSBaptiste Daroussin if (argc < 1) 8761d06d6bSBaptiste Daroussin pmandoc(mp, STDIN_FILENO, "<stdin>", list); 8861d06d6bSBaptiste Daroussin 8961d06d6bSBaptiste Daroussin for (i = 0; i < argc; i++) { 9061d06d6bSBaptiste Daroussin mparse_reset(mp); 9161d06d6bSBaptiste Daroussin if ((fd = mparse_open(mp, argv[i])) == -1) { 9261d06d6bSBaptiste Daroussin perror(argv[i]); 9361d06d6bSBaptiste Daroussin continue; 9461d06d6bSBaptiste Daroussin } 9561d06d6bSBaptiste Daroussin pmandoc(mp, fd, argv[i], list); 9661d06d6bSBaptiste Daroussin } 9761d06d6bSBaptiste Daroussin 9861d06d6bSBaptiste Daroussin mparse_free(mp); 9961d06d6bSBaptiste Daroussin mchars_free(); 10061d06d6bSBaptiste Daroussin return (int)MANDOCLEVEL_OK; 10161d06d6bSBaptiste Daroussin } 10261d06d6bSBaptiste Daroussin 10361d06d6bSBaptiste Daroussin static void 10461d06d6bSBaptiste Daroussin usage(void) 10561d06d6bSBaptiste Daroussin { 10661d06d6bSBaptiste Daroussin 10761d06d6bSBaptiste Daroussin fprintf(stderr, "usage: %s [-w] [files...]\n", progname); 10861d06d6bSBaptiste Daroussin } 10961d06d6bSBaptiste Daroussin 11061d06d6bSBaptiste Daroussin static void 11161d06d6bSBaptiste Daroussin pmandoc(struct mparse *mp, int fd, const char *fn, int list) 11261d06d6bSBaptiste Daroussin { 113*7295610fSBaptiste Daroussin struct roff_meta *meta; 11461d06d6bSBaptiste Daroussin int line, col; 11561d06d6bSBaptiste Daroussin 11661d06d6bSBaptiste Daroussin mparse_readfd(mp, fd, fn); 11761d06d6bSBaptiste Daroussin close(fd); 118*7295610fSBaptiste Daroussin meta = mparse_result(mp); 11961d06d6bSBaptiste Daroussin line = 1; 12061d06d6bSBaptiste Daroussin col = 0; 12161d06d6bSBaptiste Daroussin 122*7295610fSBaptiste Daroussin if (meta->macroset == MACROSET_MDOC) 123*7295610fSBaptiste Daroussin pmdoc(meta->first->child, &line, &col, list); 124*7295610fSBaptiste Daroussin else 125*7295610fSBaptiste Daroussin pman(meta->first->child, &line, &col, list); 12661d06d6bSBaptiste Daroussin 12761d06d6bSBaptiste Daroussin if ( ! list) 12861d06d6bSBaptiste Daroussin putchar('\n'); 12961d06d6bSBaptiste Daroussin } 13061d06d6bSBaptiste Daroussin 13161d06d6bSBaptiste Daroussin /* 13261d06d6bSBaptiste Daroussin * Strip the escapes out of a string, emitting the results. 13361d06d6bSBaptiste Daroussin */ 13461d06d6bSBaptiste Daroussin static void 13561d06d6bSBaptiste Daroussin pstring(const char *p, int col, int *colp, int list) 13661d06d6bSBaptiste Daroussin { 13761d06d6bSBaptiste Daroussin enum mandoc_esc esc; 13861d06d6bSBaptiste Daroussin const char *start, *end; 13961d06d6bSBaptiste Daroussin int emit; 14061d06d6bSBaptiste Daroussin 14161d06d6bSBaptiste Daroussin /* 14261d06d6bSBaptiste Daroussin * Print as many column spaces til we achieve parity with the 14361d06d6bSBaptiste Daroussin * input document. 14461d06d6bSBaptiste Daroussin */ 14561d06d6bSBaptiste Daroussin 14661d06d6bSBaptiste Daroussin again: 14761d06d6bSBaptiste Daroussin if (list && '\0' != *p) { 14861d06d6bSBaptiste Daroussin while (isspace((unsigned char)*p)) 14961d06d6bSBaptiste Daroussin p++; 15061d06d6bSBaptiste Daroussin 15161d06d6bSBaptiste Daroussin while ('\'' == *p || '(' == *p || '"' == *p) 15261d06d6bSBaptiste Daroussin p++; 15361d06d6bSBaptiste Daroussin 15461d06d6bSBaptiste Daroussin emit = isalpha((unsigned char)p[0]) && 15561d06d6bSBaptiste Daroussin isalpha((unsigned char)p[1]); 15661d06d6bSBaptiste Daroussin 15761d06d6bSBaptiste Daroussin for (start = p; '\0' != *p; p++) 15861d06d6bSBaptiste Daroussin if ('\\' == *p) { 15961d06d6bSBaptiste Daroussin p++; 16061d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL); 16161d06d6bSBaptiste Daroussin if (ESCAPE_ERROR == esc) 16261d06d6bSBaptiste Daroussin return; 16361d06d6bSBaptiste Daroussin emit = 0; 16461d06d6bSBaptiste Daroussin } else if (isspace((unsigned char)*p)) 16561d06d6bSBaptiste Daroussin break; 16661d06d6bSBaptiste Daroussin 16761d06d6bSBaptiste Daroussin end = p - 1; 16861d06d6bSBaptiste Daroussin 16961d06d6bSBaptiste Daroussin while (end > start) 17061d06d6bSBaptiste Daroussin if ('.' == *end || ',' == *end || 17161d06d6bSBaptiste Daroussin '\'' == *end || '"' == *end || 17261d06d6bSBaptiste Daroussin ')' == *end || '!' == *end || 17361d06d6bSBaptiste Daroussin '?' == *end || ':' == *end || 17461d06d6bSBaptiste Daroussin ';' == *end) 17561d06d6bSBaptiste Daroussin end--; 17661d06d6bSBaptiste Daroussin else 17761d06d6bSBaptiste Daroussin break; 17861d06d6bSBaptiste Daroussin 17961d06d6bSBaptiste Daroussin if (emit && end - start >= 1) { 18061d06d6bSBaptiste Daroussin for ( ; start <= end; start++) 18161d06d6bSBaptiste Daroussin if (ASCII_HYPH == *start) 18261d06d6bSBaptiste Daroussin putchar('-'); 18361d06d6bSBaptiste Daroussin else 18461d06d6bSBaptiste Daroussin putchar((unsigned char)*start); 18561d06d6bSBaptiste Daroussin putchar('\n'); 18661d06d6bSBaptiste Daroussin } 18761d06d6bSBaptiste Daroussin 18861d06d6bSBaptiste Daroussin if (isspace((unsigned char)*p)) 18961d06d6bSBaptiste Daroussin goto again; 19061d06d6bSBaptiste Daroussin 19161d06d6bSBaptiste Daroussin return; 19261d06d6bSBaptiste Daroussin } 19361d06d6bSBaptiste Daroussin 19461d06d6bSBaptiste Daroussin while (*colp < col) { 19561d06d6bSBaptiste Daroussin putchar(' '); 19661d06d6bSBaptiste Daroussin (*colp)++; 19761d06d6bSBaptiste Daroussin } 19861d06d6bSBaptiste Daroussin 19961d06d6bSBaptiste Daroussin /* 20061d06d6bSBaptiste Daroussin * Print the input word, skipping any special characters. 20161d06d6bSBaptiste Daroussin */ 20261d06d6bSBaptiste Daroussin while ('\0' != *p) 20361d06d6bSBaptiste Daroussin if ('\\' == *p) { 20461d06d6bSBaptiste Daroussin p++; 20561d06d6bSBaptiste Daroussin esc = mandoc_escape(&p, NULL, NULL); 20661d06d6bSBaptiste Daroussin if (ESCAPE_ERROR == esc) 20761d06d6bSBaptiste Daroussin break; 20861d06d6bSBaptiste Daroussin } else { 20961d06d6bSBaptiste Daroussin putchar((unsigned char )*p++); 21061d06d6bSBaptiste Daroussin (*colp)++; 21161d06d6bSBaptiste Daroussin } 21261d06d6bSBaptiste Daroussin } 21361d06d6bSBaptiste Daroussin 21461d06d6bSBaptiste Daroussin static void 21561d06d6bSBaptiste Daroussin pline(int line, int *linep, int *col, int list) 21661d06d6bSBaptiste Daroussin { 21761d06d6bSBaptiste Daroussin 21861d06d6bSBaptiste Daroussin if (list) 21961d06d6bSBaptiste Daroussin return; 22061d06d6bSBaptiste Daroussin 22161d06d6bSBaptiste Daroussin /* 22261d06d6bSBaptiste Daroussin * Print out as many lines as needed to reach parity with the 22361d06d6bSBaptiste Daroussin * original input. 22461d06d6bSBaptiste Daroussin */ 22561d06d6bSBaptiste Daroussin 22661d06d6bSBaptiste Daroussin while (*linep < line) { 22761d06d6bSBaptiste Daroussin putchar('\n'); 22861d06d6bSBaptiste Daroussin (*linep)++; 22961d06d6bSBaptiste Daroussin } 23061d06d6bSBaptiste Daroussin 23161d06d6bSBaptiste Daroussin *col = 0; 23261d06d6bSBaptiste Daroussin } 23361d06d6bSBaptiste Daroussin 23461d06d6bSBaptiste Daroussin static void 23561d06d6bSBaptiste Daroussin pmdoc(const struct roff_node *p, int *line, int *col, int list) 23661d06d6bSBaptiste Daroussin { 23761d06d6bSBaptiste Daroussin 23861d06d6bSBaptiste Daroussin for ( ; p; p = p->next) { 23961d06d6bSBaptiste Daroussin if (NODE_LINE & p->flags) 24061d06d6bSBaptiste Daroussin pline(p->line, line, col, list); 24161d06d6bSBaptiste Daroussin if (ROFFT_TEXT == p->type) 24261d06d6bSBaptiste Daroussin pstring(p->string, p->pos, col, list); 24361d06d6bSBaptiste Daroussin if (p->child) 24461d06d6bSBaptiste Daroussin pmdoc(p->child, line, col, list); 24561d06d6bSBaptiste Daroussin } 24661d06d6bSBaptiste Daroussin } 24761d06d6bSBaptiste Daroussin 24861d06d6bSBaptiste Daroussin static void 24961d06d6bSBaptiste Daroussin pman(const struct roff_node *p, int *line, int *col, int list) 25061d06d6bSBaptiste Daroussin { 25161d06d6bSBaptiste Daroussin 25261d06d6bSBaptiste Daroussin for ( ; p; p = p->next) { 25361d06d6bSBaptiste Daroussin if (NODE_LINE & p->flags) 25461d06d6bSBaptiste Daroussin pline(p->line, line, col, list); 25561d06d6bSBaptiste Daroussin if (ROFFT_TEXT == p->type) 25661d06d6bSBaptiste Daroussin pstring(p->string, p->pos, col, list); 25761d06d6bSBaptiste Daroussin if (p->child) 25861d06d6bSBaptiste Daroussin pman(p->child, line, col, list); 25961d06d6bSBaptiste Daroussin } 26061d06d6bSBaptiste Daroussin } 261