1 /* $Id: demandoc.c,v 1.10 2014/03/19 22:20:43 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 #ifdef HAVE_CONFIG_H 18 #include "config.h" 19 #endif 20 21 #include <assert.h> 22 #include <ctype.h> 23 #include <getopt.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include "man.h" 30 #include "mdoc.h" 31 #include "mandoc.h" 32 33 static void pline(int, int *, int *, int); 34 static void pman(const struct man_node *, int *, int *, int); 35 static void pmandoc(struct mparse *, int, const char *, int); 36 static void pmdoc(const struct mdoc_node *, int *, int *, int); 37 static void pstring(const char *, int, int *, int); 38 static void usage(void); 39 40 static const char *progname; 41 42 int 43 main(int argc, char *argv[]) 44 { 45 struct mparse *mp; 46 int ch, i, list; 47 extern int optind; 48 49 progname = strrchr(argv[0], '/'); 50 if (progname == NULL) 51 progname = argv[0]; 52 else 53 ++progname; 54 55 mp = NULL; 56 list = 0; 57 58 while (-1 != (ch = getopt(argc, argv, "ikm:pw"))) 59 switch (ch) { 60 case ('i'): 61 /* FALLTHROUGH */ 62 case ('k'): 63 /* FALLTHROUGH */ 64 case ('m'): 65 /* FALLTHROUGH */ 66 case ('p'): 67 break; 68 case ('w'): 69 list = 1; 70 break; 71 default: 72 usage(); 73 return((int)MANDOCLEVEL_BADARG); 74 } 75 76 argc -= optind; 77 argv += optind; 78 79 mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, NULL); 80 assert(mp); 81 82 if (0 == argc) 83 pmandoc(mp, STDIN_FILENO, "<stdin>", list); 84 85 for (i = 0; i < argc; i++) { 86 mparse_reset(mp); 87 pmandoc(mp, -1, argv[i], list); 88 } 89 90 mparse_free(mp); 91 return((int)MANDOCLEVEL_OK); 92 } 93 94 static void 95 usage(void) 96 { 97 98 fprintf(stderr, "usage: %s [-w] [files...]\n", progname); 99 } 100 101 static void 102 pmandoc(struct mparse *mp, int fd, const char *fn, int list) 103 { 104 struct mdoc *mdoc; 105 struct man *man; 106 int line, col; 107 108 if (mparse_readfd(mp, fd, fn) >= MANDOCLEVEL_FATAL) { 109 fprintf(stderr, "%s: Parse failure\n", fn); 110 return; 111 } 112 113 mparse_result(mp, &mdoc, &man, NULL); 114 line = 1; 115 col = 0; 116 117 if (mdoc) 118 pmdoc(mdoc_node(mdoc), &line, &col, list); 119 else if (man) 120 pman(man_node(man), &line, &col, list); 121 else 122 return; 123 124 if ( ! list) 125 putchar('\n'); 126 } 127 128 /* 129 * Strip the escapes out of a string, emitting the results. 130 */ 131 static void 132 pstring(const char *p, int col, int *colp, int list) 133 { 134 enum mandoc_esc esc; 135 const char *start, *end; 136 int emit; 137 138 /* 139 * Print as many column spaces til we achieve parity with the 140 * input document. 141 */ 142 143 again: 144 if (list && '\0' != *p) { 145 while (isspace((unsigned char)*p)) 146 p++; 147 148 while ('\'' == *p || '(' == *p || '"' == *p) 149 p++; 150 151 emit = isalpha((unsigned char)p[0]) && 152 isalpha((unsigned char)p[1]); 153 154 for (start = p; '\0' != *p; p++) 155 if ('\\' == *p) { 156 p++; 157 esc = mandoc_escape(&p, NULL, NULL); 158 if (ESCAPE_ERROR == esc) 159 return; 160 emit = 0; 161 } else if (isspace((unsigned char)*p)) 162 break; 163 164 end = p - 1; 165 166 while (end > start) 167 if ('.' == *end || ',' == *end || 168 '\'' == *end || '"' == *end || 169 ')' == *end || '!' == *end || 170 '?' == *end || ':' == *end || 171 ';' == *end) 172 end--; 173 else 174 break; 175 176 if (emit && end - start >= 1) { 177 for ( ; start <= end; start++) 178 if (ASCII_HYPH == *start) 179 putchar('-'); 180 else 181 putchar((unsigned char)*start); 182 putchar('\n'); 183 } 184 185 if (isspace((unsigned char)*p)) 186 goto again; 187 188 return; 189 } 190 191 while (*colp < col) { 192 putchar(' '); 193 (*colp)++; 194 } 195 196 /* 197 * Print the input word, skipping any special characters. 198 */ 199 while ('\0' != *p) 200 if ('\\' == *p) { 201 p++; 202 esc = mandoc_escape(&p, NULL, NULL); 203 if (ESCAPE_ERROR == esc) 204 break; 205 } else { 206 putchar((unsigned char )*p++); 207 (*colp)++; 208 } 209 } 210 211 static void 212 pline(int line, int *linep, int *col, int list) 213 { 214 215 if (list) 216 return; 217 218 /* 219 * Print out as many lines as needed to reach parity with the 220 * original input. 221 */ 222 223 while (*linep < line) { 224 putchar('\n'); 225 (*linep)++; 226 } 227 228 *col = 0; 229 } 230 231 static void 232 pmdoc(const struct mdoc_node *p, int *line, int *col, int list) 233 { 234 235 for ( ; p; p = p->next) { 236 if (MDOC_LINE & p->flags) 237 pline(p->line, line, col, list); 238 if (MDOC_TEXT == p->type) 239 pstring(p->string, p->pos, col, list); 240 if (p->child) 241 pmdoc(p->child, line, col, list); 242 } 243 } 244 245 static void 246 pman(const struct man_node *p, int *line, int *col, int list) 247 { 248 249 for ( ; p; p = p->next) { 250 if (MAN_LINE & p->flags) 251 pline(p->line, line, col, list); 252 if (MAN_TEXT == p->type) 253 pstring(p->string, p->pos, col, list); 254 if (p->child) 255 pman(p->child, line, col, list); 256 } 257 } 258