demandoc.c revision 1.1.1.4
1/* Id: demandoc.c,v 1.27 2016/07/09 15:24:19 schwarze Exp */ 2/* 3 * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17#include "config.h" 18 19#include <sys/types.h> 20 21#include <assert.h> 22#include <ctype.h> 23#include <stdio.h> 24#include <stdlib.h> 25#include <string.h> 26#include <unistd.h> 27 28#include "roff.h" 29#include "man.h" 30#include "mdoc.h" 31#include "mandoc.h" 32 33static void pline(int, int *, int *, int); 34static void pman(const struct roff_node *, int *, int *, int); 35static void pmandoc(struct mparse *, int, const char *, int); 36static void pmdoc(const struct roff_node *, int *, int *, int); 37static void pstring(const char *, int, int *, int); 38static void usage(void); 39 40static const char *progname; 41 42int 43main(int argc, char *argv[]) 44{ 45 struct mparse *mp; 46 int ch, fd, i, list; 47 extern int optind; 48 49 if (argc < 1) 50 progname = "demandoc"; 51 else if ((progname = strrchr(argv[0], '/')) == NULL) 52 progname = argv[0]; 53 else 54 ++progname; 55 56 mp = NULL; 57 list = 0; 58 59 while (-1 != (ch = getopt(argc, argv, "ikm:pw"))) 60 switch (ch) { 61 case ('i'): 62 /* FALLTHROUGH */ 63 case ('k'): 64 /* FALLTHROUGH */ 65 case ('m'): 66 /* FALLTHROUGH */ 67 case ('p'): 68 break; 69 case ('w'): 70 list = 1; 71 break; 72 default: 73 usage(); 74 return (int)MANDOCLEVEL_BADARG; 75 } 76 77 argc -= optind; 78 argv += optind; 79 80 mchars_alloc(); 81 mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL, NULL); 82 assert(mp); 83 84 if (argc < 1) 85 pmandoc(mp, STDIN_FILENO, "<stdin>", list); 86 87 for (i = 0; i < argc; i++) { 88 mparse_reset(mp); 89 if ((fd = mparse_open(mp, argv[i])) == -1) { 90 perror(argv[i]); 91 continue; 92 } 93 pmandoc(mp, fd, argv[i], list); 94 } 95 96 mparse_free(mp); 97 mchars_free(); 98 return (int)MANDOCLEVEL_OK; 99} 100 101static void 102usage(void) 103{ 104 105 fprintf(stderr, "usage: %s [-w] [files...]\n", progname); 106} 107 108static void 109pmandoc(struct mparse *mp, int fd, const char *fn, int list) 110{ 111 struct roff_man *man; 112 int line, col; 113 114 mparse_readfd(mp, fd, fn); 115 close(fd); 116 mparse_result(mp, &man, NULL); 117 line = 1; 118 col = 0; 119 120 if (man == NULL) 121 return; 122 if (man->macroset == MACROSET_MDOC) { 123 mdoc_validate(man); 124 pmdoc(man->first->child, &line, &col, list); 125 } else { 126 man_validate(man); 127 pman(man->first->child, &line, &col, list); 128 } 129 130 if ( ! list) 131 putchar('\n'); 132} 133 134/* 135 * Strip the escapes out of a string, emitting the results. 136 */ 137static void 138pstring(const char *p, int col, int *colp, int list) 139{ 140 enum mandoc_esc esc; 141 const char *start, *end; 142 int emit; 143 144 /* 145 * Print as many column spaces til we achieve parity with the 146 * input document. 147 */ 148 149again: 150 if (list && '\0' != *p) { 151 while (isspace((unsigned char)*p)) 152 p++; 153 154 while ('\'' == *p || '(' == *p || '"' == *p) 155 p++; 156 157 emit = isalpha((unsigned char)p[0]) && 158 isalpha((unsigned char)p[1]); 159 160 for (start = p; '\0' != *p; p++) 161 if ('\\' == *p) { 162 p++; 163 esc = mandoc_escape(&p, NULL, NULL); 164 if (ESCAPE_ERROR == esc) 165 return; 166 emit = 0; 167 } else if (isspace((unsigned char)*p)) 168 break; 169 170 end = p - 1; 171 172 while (end > start) 173 if ('.' == *end || ',' == *end || 174 '\'' == *end || '"' == *end || 175 ')' == *end || '!' == *end || 176 '?' == *end || ':' == *end || 177 ';' == *end) 178 end--; 179 else 180 break; 181 182 if (emit && end - start >= 1) { 183 for ( ; start <= end; start++) 184 if (ASCII_HYPH == *start) 185 putchar('-'); 186 else 187 putchar((unsigned char)*start); 188 putchar('\n'); 189 } 190 191 if (isspace((unsigned char)*p)) 192 goto again; 193 194 return; 195 } 196 197 while (*colp < col) { 198 putchar(' '); 199 (*colp)++; 200 } 201 202 /* 203 * Print the input word, skipping any special characters. 204 */ 205 while ('\0' != *p) 206 if ('\\' == *p) { 207 p++; 208 esc = mandoc_escape(&p, NULL, NULL); 209 if (ESCAPE_ERROR == esc) 210 break; 211 } else { 212 putchar((unsigned char )*p++); 213 (*colp)++; 214 } 215} 216 217static void 218pline(int line, int *linep, int *col, int list) 219{ 220 221 if (list) 222 return; 223 224 /* 225 * Print out as many lines as needed to reach parity with the 226 * original input. 227 */ 228 229 while (*linep < line) { 230 putchar('\n'); 231 (*linep)++; 232 } 233 234 *col = 0; 235} 236 237static void 238pmdoc(const struct roff_node *p, int *line, int *col, int list) 239{ 240 241 for ( ; p; p = p->next) { 242 if (MDOC_LINE & p->flags) 243 pline(p->line, line, col, list); 244 if (ROFFT_TEXT == p->type) 245 pstring(p->string, p->pos, col, list); 246 if (p->child) 247 pmdoc(p->child, line, col, list); 248 } 249} 250 251static void 252pman(const struct roff_node *p, int *line, int *col, int list) 253{ 254 255 for ( ; p; p = p->next) { 256 if (MAN_LINE & p->flags) 257 pline(p->line, line, col, list); 258 if (ROFFT_TEXT == p->type) 259 pstring(p->string, p->pos, col, list); 260 if (p->child) 261 pman(p->child, line, col, list); 262 } 263} 264