]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
1a18c85c | 2 | * "$Id: mantohtml.c 11818 2014-04-15 20:56:19Z msweet $" |
ef416fc2 | 3 | * |
1a18c85c | 4 | * Man page to HTML conversion program. |
ef416fc2 | 5 | * |
1a18c85c MS |
6 | * Copyright 2007-2010, 2014 by Apple Inc. |
7 | * Copyright 2004-2006 by Easy Software Products. | |
ef416fc2 | 8 | * |
1a18c85c MS |
9 | * These coded instructions, statements, and computer programs are the |
10 | * property of Apple Inc. and are protected by Federal copyright | |
11 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
12 | * which should have been included with this file. If this file is | |
13 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
ef416fc2 | 14 | */ |
15 | ||
16 | /* | |
17 | * Include necessary headers. | |
18 | */ | |
19 | ||
71e16022 | 20 | #include <cups/string-private.h> |
1a18c85c | 21 | #include <cups/array-private.h> |
ecdc0628 | 22 | #include <unistd.h> |
ef416fc2 | 23 | |
24 | ||
1a18c85c MS |
25 | /* |
26 | * Local globals... | |
27 | */ | |
28 | ||
29 | static const char /* Start/end tags for fonts */ | |
30 | * const start_fonts[] = { "", "<b>", "<i>" }, | |
31 | * const end_fonts[] = { "", "</b>", "</i>" }; | |
32 | ||
33 | ||
ef416fc2 | 34 | /* |
35 | * Local functions... | |
36 | */ | |
37 | ||
1a18c85c MS |
38 | static void html_alternate(const char *s, const char *first, const char *second, FILE *fp); |
39 | static void html_fputs(const char *s, int *font, FILE *fp); | |
40 | static void html_putc(int ch, FILE *fp); | |
ef416fc2 | 41 | static void strmove(char *d, const char *s); |
42 | ||
43 | ||
44 | /* | |
45 | * 'main()' - Convert a man page to HTML. | |
46 | */ | |
47 | ||
48 | int /* O - Exit status */ | |
49 | main(int argc, /* I - Number of command-line args */ | |
50 | char *argv[]) /* I - Command-line arguments */ | |
51 | { | |
52 | FILE *infile, /* Input file */ | |
53 | *outfile; /* Output file */ | |
54 | char line[1024], /* Line from file */ | |
55 | *lineptr, /* Pointer into line */ | |
1a18c85c MS |
56 | name[1024], /* Man page name */ |
57 | ddpost[256]; /* Tagged list post markup */ | |
58 | int section = -1, /* Man page section */ | |
59 | pre = 0, /* Preformatted */ | |
60 | font = 0, /* Current font */ | |
61 | linenum = 0; /* Current line number */ | |
62 | float list_indent = 0.0f, /* Current list indentation */ | |
63 | nested_indent = 0.0f; /* Nested list indentation, if any */ | |
64 | const char *list = NULL, /* Current list, if any */ | |
65 | *nested = NULL; /* Nested list, if any */ | |
66 | const char *post = NULL; /* Text to add after the current line */ | |
67 | ||
ef416fc2 | 68 | |
69 | /* | |
70 | * Check arguments... | |
71 | */ | |
72 | ||
73 | if (argc > 3) | |
74 | { | |
75 | fputs("Usage: mantohtml [filename.man [filename.html]]\n", stderr); | |
76 | return (1); | |
77 | } | |
78 | ||
79 | /* | |
80 | * Open files as needed... | |
81 | */ | |
82 | ||
83 | if (argc > 1) | |
84 | { | |
85 | if ((infile = fopen(argv[1], "r")) == NULL) | |
86 | { | |
87 | perror(argv[1]); | |
88 | return (1); | |
89 | } | |
90 | } | |
91 | else | |
92 | infile = stdin; | |
93 | ||
94 | if (argc > 2) | |
95 | { | |
96 | if ((outfile = fopen(argv[2], "w")) == NULL) | |
97 | { | |
98 | perror(argv[2]); | |
99 | fclose(infile); | |
100 | return (1); | |
101 | } | |
102 | } | |
103 | else | |
104 | outfile = stdout; | |
105 | ||
106 | /* | |
107 | * Read from input and write the output... | |
108 | */ | |
109 | ||
1a18c85c | 110 | fputs("<!DOCTYPE HTML>\n" |
ef416fc2 | 111 | "<html>\n" |
112 | "<!-- SECTION: Man Pages -->\n" | |
113 | "<head>\n" | |
178cb736 MS |
114 | "\t<link rel=\"stylesheet\" type=\"text/css\" " |
115 | "href=\"../cups-printable.css\">\n", outfile); | |
ef416fc2 | 116 | |
ef416fc2 | 117 | while (fgets(line, sizeof(line), infile)) |
118 | { | |
1a18c85c MS |
119 | size_t linelen = strlen(line); /* Length of line */ |
120 | ||
121 | if (linelen > 0 && line[linelen - 1] == '\n') | |
122 | line[linelen - 1] = '\0'; | |
123 | ||
ef416fc2 | 124 | linenum ++; |
125 | ||
126 | if (line[0] == '.') | |
127 | { | |
128 | /* | |
129 | * Strip leading whitespace... | |
130 | */ | |
131 | ||
132 | while (line[1] == ' ' || line[1] == '\t') | |
133 | strmove(line + 1, line + 2); | |
134 | ||
135 | /* | |
136 | * Process man page commands... | |
137 | */ | |
138 | ||
139 | if (!strncmp(line, ".TH ", 4) && section < 0) | |
140 | { | |
141 | /* | |
142 | * Grab man page title... | |
143 | */ | |
144 | ||
145 | sscanf(line + 4, "%s%d", name, §ion); | |
146 | ||
147 | fprintf(outfile, | |
bd7854cb | 148 | "\t<title>%s(%d)</title>\n" |
ef416fc2 | 149 | "</head>\n" |
150 | "<body>\n" | |
178cb736 | 151 | "<h1 class=\"title\">%s(%d)</h1>\n" |
ef416fc2 | 152 | "%s", |
178cb736 | 153 | name, section, name, section, start_fonts[font]); |
ef416fc2 | 154 | } |
155 | else if (section < 0) | |
156 | continue; | |
dd1abb6b | 157 | else if (!strncmp(line, ".SH ", 4) || !strncmp(line, ".SS ", 4)) |
ef416fc2 | 158 | { |
159 | /* | |
160 | * Grab heading... | |
161 | */ | |
162 | ||
163 | int first = 1; | |
164 | ||
165 | fputs(end_fonts[font], outfile); | |
1a18c85c | 166 | font = 0; |
ef416fc2 | 167 | |
168 | if (list) | |
169 | { | |
1a18c85c MS |
170 | fprintf(outfile, "</%s>\n", list); |
171 | list = NULL; | |
ef416fc2 | 172 | } |
173 | ||
174 | if (line[2] == 'H') | |
178cb736 | 175 | fputs("<h2 class=\"title\"><a name=\"", outfile); |
ef416fc2 | 176 | else |
178cb736 | 177 | fputs("<h3><a name=\"", outfile); |
bd7854cb | 178 | |
179 | for (lineptr = line + 4; *lineptr; lineptr ++) | |
1a18c85c | 180 | if (*lineptr == '\"') |
bd7854cb | 181 | continue; |
1a18c85c MS |
182 | else if (isalnum(*lineptr & 255)) |
183 | html_putc(*lineptr, outfile); | |
bd7854cb | 184 | else |
1a18c85c | 185 | html_putc('_', outfile); |
bd7854cb | 186 | |
178cb736 | 187 | fputs("\">", outfile); |
ef416fc2 | 188 | |
189 | for (lineptr = line + 4; *lineptr; lineptr ++) | |
1a18c85c | 190 | { |
ef416fc2 | 191 | if (*lineptr == '\"') |
192 | continue; | |
193 | else if (*lineptr == ' ') | |
194 | { | |
1a18c85c | 195 | html_putc(' ', outfile); |
ef416fc2 | 196 | |
197 | first = 1; | |
198 | } | |
bd7854cb | 199 | else |
ef416fc2 | 200 | { |
201 | if (first) | |
1a18c85c | 202 | html_putc(*lineptr, outfile); |
ef416fc2 | 203 | else |
1a18c85c | 204 | html_putc(tolower(*lineptr & 255), outfile); |
ef416fc2 | 205 | |
206 | first = 0; | |
207 | } | |
1a18c85c | 208 | } |
ef416fc2 | 209 | |
210 | if (line[2] == 'H') | |
1a18c85c | 211 | fputs("</a></h2>\n", outfile); |
ef416fc2 | 212 | else |
1a18c85c | 213 | fputs("</a></h3>\n", outfile); |
ef416fc2 | 214 | } |
1a18c85c | 215 | else if (!strncmp(line, ".B ", 3)) |
ef416fc2 | 216 | { |
217 | /* | |
1a18c85c | 218 | * Grab bold text... |
ef416fc2 | 219 | */ |
220 | ||
221 | fputs(end_fonts[font], outfile); | |
1a18c85c MS |
222 | font = 0; |
223 | ||
224 | html_alternate(line + 3, "b", "b", outfile); | |
ef416fc2 | 225 | |
1a18c85c | 226 | if (post) |
ef416fc2 | 227 | { |
1a18c85c MS |
228 | fputs(post, outfile); |
229 | post = NULL; | |
ef416fc2 | 230 | } |
1a18c85c MS |
231 | } |
232 | else if (!strncmp(line, ".I ", 3)) | |
233 | { | |
234 | /* | |
235 | * Grab italic text... | |
236 | */ | |
ef416fc2 | 237 | |
1a18c85c MS |
238 | fputs(end_fonts[font], outfile); |
239 | font = 0; | |
240 | ||
241 | html_alternate(line + 3, "i", "i", outfile); | |
242 | ||
243 | if (post) | |
ef416fc2 | 244 | { |
1a18c85c MS |
245 | fputs(post, outfile); |
246 | post = NULL; | |
247 | } | |
248 | } | |
249 | else if (!strncmp(line, ".BI ", 4)) | |
250 | { | |
251 | /* | |
252 | * Alternating bold and italic text... | |
253 | */ | |
254 | ||
255 | fputs(end_fonts[font], outfile); | |
256 | font = 0; | |
257 | ||
258 | html_alternate(line + 4, "b", "i", outfile); | |
ef416fc2 | 259 | |
1a18c85c MS |
260 | if (post) |
261 | { | |
262 | fputs(post, outfile); | |
263 | post = NULL; | |
ef416fc2 | 264 | } |
1a18c85c MS |
265 | } |
266 | else if (!strncmp(line, ".BR ", 4)) | |
267 | { | |
268 | /* | |
269 | * Alternating bold and roman (plain) text... | |
270 | */ | |
ef416fc2 | 271 | |
1a18c85c | 272 | fputs(end_fonts[font], outfile); |
ef416fc2 | 273 | font = 0; |
1a18c85c MS |
274 | |
275 | html_alternate(line + 4, "b", NULL, outfile); | |
276 | ||
277 | if (post) | |
278 | { | |
279 | fputs(post, outfile); | |
280 | post = NULL; | |
281 | } | |
ef416fc2 | 282 | } |
1a18c85c | 283 | else if (!strncmp(line, ".IB ", 4)) |
ef416fc2 | 284 | { |
285 | /* | |
1a18c85c MS |
286 | * Alternating italic and bold text... |
287 | */ | |
ef416fc2 | 288 | |
289 | fputs(end_fonts[font], outfile); | |
1a18c85c MS |
290 | font = 0; |
291 | ||
292 | html_alternate(line + 4, "i", "b", outfile); | |
ef416fc2 | 293 | |
1a18c85c | 294 | if (post) |
ef416fc2 | 295 | { |
1a18c85c MS |
296 | fputs(post, outfile); |
297 | post = NULL; | |
ef416fc2 | 298 | } |
1a18c85c MS |
299 | } |
300 | else if (!strncmp(line, ".IR ", 4)) | |
301 | { | |
302 | /* | |
303 | * Alternating italic and roman (plain) text... | |
304 | */ | |
ef416fc2 | 305 | |
1a18c85c | 306 | fputs(end_fonts[font], outfile); |
ef416fc2 | 307 | font = 0; |
1a18c85c MS |
308 | |
309 | html_alternate(line + 4, "i", NULL, outfile); | |
310 | ||
311 | if (post) | |
312 | { | |
313 | fputs(post, outfile); | |
314 | post = NULL; | |
315 | } | |
ef416fc2 | 316 | } |
1a18c85c | 317 | else if (!strncmp(line, ".RB ", 4)) |
ef416fc2 | 318 | { |
319 | /* | |
1a18c85c MS |
320 | * Alternating roman (plain) and bold text... |
321 | */ | |
ef416fc2 | 322 | |
1a18c85c MS |
323 | fputs(end_fonts[font], outfile); |
324 | font = 0; | |
325 | ||
326 | html_alternate(line + 4, NULL, "b", outfile); | |
327 | ||
328 | if (post) | |
ef416fc2 | 329 | { |
1a18c85c MS |
330 | fputs(post, outfile); |
331 | post = NULL; | |
ef416fc2 | 332 | } |
ef416fc2 | 333 | } |
1a18c85c | 334 | else if (!strncmp(line, ".RI ", 4)) |
ef416fc2 | 335 | { |
336 | /* | |
1a18c85c MS |
337 | * Alternating roman (plain) and italic text... |
338 | */ | |
ef416fc2 | 339 | |
1a18c85c MS |
340 | fputs(end_fonts[font], outfile); |
341 | font = 0; | |
342 | ||
343 | html_alternate(line + 4, NULL, "i", outfile); | |
344 | ||
345 | if (post) | |
ef416fc2 | 346 | { |
1a18c85c MS |
347 | fputs(post, outfile); |
348 | post = NULL; | |
349 | } | |
350 | } | |
351 | else if (!strncmp(line, ".SB ", 4)) | |
352 | { | |
353 | /* | |
354 | * Alternating small and bold text... | |
355 | */ | |
ef416fc2 | 356 | |
1a18c85c MS |
357 | fputs(end_fonts[font], outfile); |
358 | font = 0; | |
359 | ||
360 | html_alternate(line + 4, "small", "b", outfile); | |
361 | ||
362 | if (post) | |
363 | { | |
364 | fputs(post, outfile); | |
365 | post = NULL; | |
ef416fc2 | 366 | } |
367 | } | |
1a18c85c | 368 | else if (!strncmp(line, ".SM ", 4)) |
ef416fc2 | 369 | { |
370 | /* | |
1a18c85c MS |
371 | * Small text... |
372 | */ | |
ef416fc2 | 373 | |
1a18c85c MS |
374 | fputs(end_fonts[font], outfile); |
375 | font = 0; | |
376 | ||
377 | html_alternate(line + 4, "small", "small", outfile); | |
378 | ||
379 | if (post) | |
380 | { | |
381 | fputs(post, outfile); | |
382 | post = NULL; | |
383 | } | |
ef416fc2 | 384 | } |
1a18c85c | 385 | else if (!strcmp(line, ".LP") || !strcmp(line, ".PP") || !strcmp(line, ".P")) |
ef416fc2 | 386 | { |
387 | /* | |
1a18c85c | 388 | * New paragraph... |
ef416fc2 | 389 | */ |
390 | ||
1a18c85c MS |
391 | fputs(end_fonts[font], outfile); |
392 | font = 0; | |
393 | ||
394 | if (list) | |
395 | { | |
396 | fprintf(outfile, "</%s>\n", list); | |
397 | list = NULL; | |
398 | } | |
399 | ||
400 | fputs("<p>", outfile); | |
ef416fc2 | 401 | } |
1a18c85c | 402 | else if (!strcmp(line, ".RS") || !strncmp(line, ".RS ", 4)) |
ef416fc2 | 403 | { |
404 | /* | |
1a18c85c | 405 | * Indent... |
ef416fc2 | 406 | */ |
1a18c85c MS |
407 | |
408 | float amount = 3.0; /* Indentation */ | |
409 | ||
410 | if (line[3]) | |
411 | amount = atof(line + 4); | |
412 | ||
413 | fputs(end_fonts[font], outfile); | |
414 | font = 0; | |
415 | ||
416 | if (list) | |
417 | { | |
418 | nested = list; | |
419 | list = NULL; | |
420 | nested_indent = list_indent; | |
421 | list_indent = 0.0f; | |
422 | } | |
423 | ||
424 | fprintf(outfile, "<div style=\"margin-left: %.1fem;\">\n", amount - nested_indent); | |
ef416fc2 | 425 | } |
1a18c85c | 426 | else if (!strcmp(line, ".RE")) |
ef416fc2 | 427 | { |
428 | /* | |
1a18c85c | 429 | * Unindent... |
ef416fc2 | 430 | */ |
431 | ||
1a18c85c MS |
432 | fputs(end_fonts[font], outfile); |
433 | font = 0; | |
434 | ||
435 | fputs("</div>\n", outfile); | |
436 | ||
437 | if (nested) | |
438 | { | |
439 | list = nested; | |
440 | nested = NULL; | |
441 | ||
442 | list_indent = nested_indent; | |
443 | nested_indent = 0.0f; | |
444 | } | |
ef416fc2 | 445 | } |
1a18c85c | 446 | else if (!strcmp(line, ".HP") || !strncmp(line, ".HP ", 4)) |
ef416fc2 | 447 | { |
448 | /* | |
1a18c85c MS |
449 | * Hanging paragraph... |
450 | * | |
451 | * .HP i | |
ef416fc2 | 452 | */ |
453 | ||
1a18c85c MS |
454 | float amount = 3.0; /* Indentation */ |
455 | ||
456 | if (line[3]) | |
457 | amount = atof(line + 4); | |
458 | ||
459 | fputs(end_fonts[font], outfile); | |
460 | font = 0; | |
461 | ||
462 | if (list) | |
463 | { | |
464 | fprintf(outfile, "</%s>\n", list); | |
465 | list = NULL; | |
466 | } | |
467 | ||
468 | fprintf(outfile, "<p style=\"margin-left: %.1fem; text-indent: %.1fem\">", amount, -amount); | |
469 | ||
470 | if (line[1] == 'T') | |
471 | post = "<br>\n"; | |
ef416fc2 | 472 | } |
1a18c85c | 473 | else if (!strcmp(line, ".TP") || !strncmp(line, ".TP ", 4)) |
ef416fc2 | 474 | { |
475 | /* | |
1a18c85c MS |
476 | * Tagged list... |
477 | * | |
478 | * .TP i | |
ef416fc2 | 479 | */ |
480 | ||
1a18c85c MS |
481 | float amount = 3.0; /* Indentation */ |
482 | ||
483 | if (line[3]) | |
484 | amount = atof(line + 4); | |
485 | ||
486 | fputs(end_fonts[font], outfile); | |
487 | font = 0; | |
488 | ||
489 | if (list && strcmp(list, "dl")) | |
490 | { | |
491 | fprintf(outfile, "</%s>\n", list); | |
492 | list = NULL; | |
493 | } | |
ef416fc2 | 494 | |
1a18c85c MS |
495 | if (!list) |
496 | { | |
497 | fputs("<dl class=\"man\">\n", outfile); | |
498 | list = "dl"; | |
499 | list_indent = amount; | |
500 | } | |
501 | ||
502 | fputs("<dt>", outfile); | |
503 | snprintf(ddpost, sizeof(ddpost), "<dd style=\"margin-left: %.1fem\">", amount); | |
504 | post = ddpost; | |
ef416fc2 | 505 | } |
506 | else if (!strncmp(line, ".IP ", 4)) | |
507 | { | |
508 | /* | |
509 | * Indented paragraph... | |
1a18c85c MS |
510 | * |
511 | * .IP x i | |
ef416fc2 | 512 | */ |
513 | ||
1a18c85c MS |
514 | float amount = 3.0; /* Indentation */ |
515 | const char *newlist = NULL; /* New list style */ | |
516 | const char *newtype = NULL; /* New list numbering type */ | |
517 | ||
518 | fputs(end_fonts[font], outfile); | |
519 | font = 0; | |
520 | ||
521 | lineptr = line + 4; | |
522 | while (isspace(*lineptr & 255)) | |
523 | lineptr ++; | |
524 | ||
525 | if (!strncmp(lineptr, "\\(bu", 4) || !strncmp(lineptr, "\\(em", 4)) | |
ef416fc2 | 526 | { |
1a18c85c MS |
527 | /* |
528 | * Bullet list... | |
529 | */ | |
ef416fc2 | 530 | |
1a18c85c MS |
531 | newlist = "ul"; |
532 | } | |
533 | else if (isdigit(*lineptr & 255)) | |
534 | { | |
535 | /* | |
536 | * Numbered list... | |
537 | */ | |
ef416fc2 | 538 | |
1a18c85c MS |
539 | newlist = "ol"; |
540 | } | |
541 | else if (islower(*lineptr & 255)) | |
542 | { | |
543 | /* | |
544 | * Lowercase alpha list... | |
545 | */ | |
ef416fc2 | 546 | |
1a18c85c MS |
547 | newlist = "ol"; |
548 | newtype = "a"; | |
549 | } | |
550 | else if (isupper(*lineptr & 255)) | |
ef416fc2 | 551 | { |
1a18c85c MS |
552 | /* |
553 | * Lowercase alpha list... | |
554 | */ | |
555 | ||
556 | newlist = "ol"; | |
557 | newtype = "A"; | |
558 | } | |
559 | ||
560 | while (!isspace(*lineptr & 255)) | |
561 | lineptr ++; | |
562 | while (isspace(*lineptr & 255)) | |
563 | lineptr ++; | |
ef416fc2 | 564 | |
1a18c85c MS |
565 | if (isdigit(*lineptr & 255)) |
566 | amount = atof(lineptr); | |
567 | ||
568 | if (newlist && list && strcmp(newlist, list)) | |
569 | { | |
570 | fprintf(outfile, "</%s>\n", list); | |
571 | list = NULL; | |
ef416fc2 | 572 | } |
ef416fc2 | 573 | |
1a18c85c MS |
574 | if (newlist && !list) |
575 | { | |
576 | if (newtype) | |
577 | fprintf(outfile, "<%s type=\"%s\">\n", newlist, newtype); | |
578 | else | |
579 | fprintf(outfile, "<%s>\n", newlist); | |
580 | ||
581 | list = newlist; | |
ef416fc2 | 582 | } |
583 | ||
1a18c85c MS |
584 | if (list) |
585 | fprintf(outfile, "<li style=\"margin-left: %.1fem;\">", amount); | |
586 | else | |
587 | fprintf(outfile, "<p style=\"margin-left: %.1fem;\">", amount); | |
588 | } | |
589 | else if (!strncmp(line, ".br", 3)) | |
590 | { | |
ef416fc2 | 591 | /* |
1a18c85c | 592 | * Grab line break... |
ef416fc2 | 593 | */ |
594 | ||
1a18c85c MS |
595 | fputs("<br>\n", outfile); |
596 | } | |
597 | else if (!strncmp(line, ".de ", 4)) | |
598 | { | |
599 | /* | |
600 | * Define macro - ignore... | |
601 | */ | |
602 | ||
603 | while (fgets(line, sizeof(line), infile)) | |
604 | { | |
605 | linenum ++; | |
606 | ||
607 | if (!strncmp(line, "..", 2)) | |
608 | break; | |
609 | } | |
610 | } | |
611 | else if (!strncmp(line, ".ds ", 4) || !strncmp(line, ".rm ", 4) || | |
612 | !strncmp(line, ".tr ", 4) || !strncmp(line, ".hy ", 4) || | |
613 | !strncmp(line, ".IX ", 4) || !strncmp(line, ".PD", 3) || | |
614 | !strncmp(line, ".Sp", 3)) | |
615 | { | |
616 | /* | |
617 | * Ignore unused commands... | |
618 | */ | |
619 | } | |
620 | else if (!strncmp(line, ".Vb", 3) || !strncmp(line, ".nf", 3) || !strncmp(line, ".EX", 3)) | |
621 | { | |
622 | /* | |
623 | * Start preformatted... | |
624 | */ | |
625 | ||
626 | fputs(end_fonts[font], outfile); | |
627 | font = 0; | |
628 | ||
629 | // if (list) | |
630 | // { | |
631 | // fprintf(outfile, "</%s>\n", list); | |
632 | // list = NULL; | |
633 | // } | |
634 | ||
635 | pre = 1; | |
636 | fputs("<pre class=\"man\">\n", outfile); | |
637 | } | |
638 | else if (!strncmp(line, ".Ve", 3) || !strncmp(line, ".fi", 3) || !strncmp(line, ".EE", 3)) | |
639 | { | |
640 | /* | |
641 | * End preformatted... | |
642 | */ | |
643 | ||
644 | fputs(end_fonts[font], outfile); | |
645 | font = 0; | |
646 | ||
647 | if (pre) | |
648 | { | |
649 | pre = 0; | |
650 | fputs("</pre>\n", outfile); | |
651 | } | |
ef416fc2 | 652 | } |
653 | else if (!strncmp(line, ".\\}", 3)) | |
654 | { | |
655 | /* | |
656 | * Ignore close block... | |
657 | */ | |
658 | } | |
659 | else if (!strncmp(line, ".ie", 3) || !strncmp(line, ".if", 3) || | |
660 | !strncmp(line, ".el", 3)) | |
661 | { | |
662 | /* | |
663 | * If/else - ignore... | |
664 | */ | |
665 | ||
666 | if (strchr(line, '{') != NULL) | |
667 | { | |
668 | /* | |
669 | * Skip whole block... | |
670 | */ | |
671 | ||
672 | while (fgets(line, sizeof(line), infile)) | |
673 | { | |
674 | linenum ++; | |
675 | ||
676 | if (strchr(line, '}') != NULL) | |
677 | break; | |
678 | } | |
679 | } | |
680 | } | |
681 | #if 0 | |
682 | else if (!strncmp(line, ". ", 4)) | |
683 | { | |
684 | /* | |
685 | * Grab ... | |
686 | */ | |
687 | } | |
688 | #endif /* 0 */ | |
ef416fc2 | 689 | else if (strncmp(line, ".\\\"", 3)) |
690 | { | |
691 | /* | |
692 | * Unknown... | |
693 | */ | |
694 | ||
695 | if ((lineptr = strchr(line, ' ')) != NULL) | |
696 | *lineptr = '\0'; | |
697 | else if ((lineptr = strchr(line, '\n')) != NULL) | |
698 | *lineptr = '\0'; | |
699 | ||
1a18c85c | 700 | fprintf(stderr, "mantohtml: Unknown man page command \'%s\' on line %d.\n", line, linenum); |
ef416fc2 | 701 | } |
702 | ||
703 | /* | |
704 | * Skip continuation lines... | |
705 | */ | |
706 | ||
1a18c85c | 707 | lineptr = line + strlen(line) - 1; |
ef416fc2 | 708 | if (lineptr >= line && *lineptr == '\\') |
709 | { | |
710 | while (fgets(line, sizeof(line), infile)) | |
711 | { | |
712 | linenum ++; | |
713 | lineptr = line + strlen(line) - 2; | |
714 | ||
715 | if (lineptr < line || *lineptr != '\\') | |
716 | break; | |
717 | } | |
718 | } | |
719 | } | |
720 | else | |
721 | { | |
722 | /* | |
723 | * Process man page text... | |
724 | */ | |
725 | ||
1a18c85c MS |
726 | html_fputs(line, &font, outfile); |
727 | putc('\n', outfile); | |
ef416fc2 | 728 | |
729 | if (post) | |
730 | { | |
731 | fputs(post, outfile); | |
732 | post = NULL; | |
733 | } | |
734 | } | |
735 | } | |
736 | ||
737 | fprintf(outfile, "%s\n", end_fonts[font]); | |
1a18c85c | 738 | font = 0; |
ef416fc2 | 739 | |
740 | if (list) | |
741 | { | |
1a18c85c MS |
742 | fprintf(outfile, "</%s>\n", list); |
743 | list = NULL; | |
ef416fc2 | 744 | } |
745 | ||
746 | fputs("</body>\n" | |
747 | "</html>\n", outfile); | |
748 | ||
749 | /* | |
750 | * Close files... | |
751 | */ | |
752 | ||
753 | if (infile != stdin) | |
754 | fclose(infile); | |
755 | ||
756 | if (outfile != stdout) | |
757 | fclose(outfile); | |
758 | ||
759 | /* | |
760 | * Return with no errors... | |
761 | */ | |
762 | ||
763 | return (0); | |
764 | } | |
765 | ||
766 | ||
767 | /* | |
1a18c85c MS |
768 | * 'html_alternate()' - Alternate words between two styles of text. |
769 | */ | |
770 | ||
771 | static void | |
772 | html_alternate(const char *s, /* I - String */ | |
773 | const char *first, /* I - First style or NULL */ | |
774 | const char *second, /* I - Second style of NULL */ | |
775 | FILE *fp) /* I - File */ | |
776 | { | |
777 | int i = 0; /* Which style */ | |
778 | int quote = 0; /* Saw quote? */ | |
779 | int dolinks, /* Do hyperlinks to other man pages? */ | |
780 | link = 0; /* Doing a link now? */ | |
781 | ||
782 | ||
783 | /* | |
784 | * Skip leading whitespace... | |
785 | */ | |
786 | ||
787 | while (isspace(*s & 255)) | |
788 | s ++; | |
789 | ||
790 | dolinks = first && !strcmp(first, "b") && !second; | |
791 | ||
792 | while (*s) | |
793 | { | |
794 | if (!i && dolinks) | |
795 | { | |
796 | /* | |
797 | * See if we need to make a link to a man page... | |
798 | */ | |
799 | ||
800 | const char *end; /* End of current word */ | |
801 | const char *next; /* Start of next word */ | |
802 | ||
803 | for (end = s; *end && !isspace(*end & 255); end ++); | |
804 | for (next = end; isspace(*next & 255); next ++); | |
805 | ||
806 | if (isalnum(*s & 255) && *next == '(') | |
807 | { | |
808 | /* | |
809 | * See if the man file is available locally... | |
810 | */ | |
811 | ||
812 | char name[1024], /* Name */ | |
813 | manfile[1024], /* Man page filename */ | |
814 | manurl[1024]; /* Man page URL */ | |
815 | ||
816 | strlcpy(name, s, sizeof(name)); | |
817 | if ((size_t)(end - s) < sizeof(name)) | |
818 | name[end - s] = '\0'; | |
819 | ||
820 | snprintf(manfile, sizeof(manfile), "%s.man", name); | |
821 | snprintf(manurl, sizeof(manurl), "man-%s.html?TOPIC=Man+Pages", name); | |
822 | ||
823 | if (!access(manfile, 0)) | |
824 | { | |
825 | /* | |
826 | * Local man page, do a link... | |
827 | */ | |
828 | ||
829 | fprintf(fp, "<a href=\"%s\">", manurl); | |
830 | link = 1; | |
831 | } | |
832 | } | |
833 | } | |
834 | ||
835 | if (!i && first) | |
836 | fprintf(fp, "<%s>", first); | |
837 | else if (i && second) | |
838 | fprintf(fp, "<%s>", second); | |
839 | ||
840 | while ((!isspace(*s & 255) || quote) && *s) | |
841 | { | |
842 | if (*s == '\"') | |
843 | quote = !quote; | |
844 | else if (*s == '\\' && s[1]) | |
845 | { | |
846 | s ++; | |
847 | html_putc(*s++, fp); | |
848 | } | |
849 | else | |
850 | html_putc(*s++, fp); | |
851 | } | |
852 | ||
853 | if (!i && first) | |
854 | fprintf(fp, "</%s>", first); | |
855 | else if (i && second) | |
856 | fprintf(fp, "</%s>", second); | |
857 | ||
858 | if (i && link) | |
859 | { | |
860 | fputs("</a>", fp); | |
861 | link = 0; | |
862 | } | |
863 | ||
864 | i = 1 - i; | |
865 | ||
866 | /* | |
867 | * Skip trailing whitespace... | |
868 | */ | |
869 | ||
870 | while (isspace(*s & 255)) | |
871 | s ++; | |
872 | } | |
873 | ||
874 | putc('\n', fp); | |
875 | } | |
876 | ||
877 | /* | |
878 | * 'html_fputs()' - Output a string, quoting as needed HTML entities. | |
879 | */ | |
880 | ||
881 | static void | |
882 | html_fputs(const char *s, /* I - String */ | |
883 | int *font, /* IO - Font */ | |
884 | FILE *fp) /* I - File */ | |
885 | { | |
886 | while (*s) | |
887 | { | |
888 | if (*s == '\\') | |
889 | { | |
890 | s ++; | |
891 | if (!*s) | |
892 | break; | |
893 | ||
894 | if (*s == 'f') | |
895 | { | |
896 | int newfont; /* New font */ | |
897 | ||
898 | s ++; | |
899 | if (!*s) | |
900 | break; | |
901 | ||
902 | if (!font) | |
903 | { | |
904 | s ++; | |
905 | continue; | |
906 | } | |
907 | ||
908 | switch (*s++) | |
909 | { | |
910 | case 'R' : | |
911 | case 'P' : | |
912 | newfont = 0; | |
913 | break; | |
914 | ||
915 | case 'b' : | |
916 | case 'B' : | |
917 | newfont = 1; | |
918 | break; | |
919 | ||
920 | case 'i' : | |
921 | case 'I' : | |
922 | newfont = 2; | |
923 | break; | |
924 | ||
925 | default : | |
926 | fprintf(stderr, "mantohtml: Unknown font \"\\f%c\" ignored.\n", s[-1]); | |
927 | newfont = *font; | |
928 | break; | |
929 | } | |
930 | ||
931 | if (newfont != *font) | |
932 | { | |
933 | fputs(end_fonts[*font], fp); | |
934 | *font = newfont; | |
935 | fputs(start_fonts[*font], fp); | |
936 | } | |
937 | } | |
938 | else if (*s == '*') | |
939 | { | |
940 | /* | |
941 | * Substitute macro... | |
942 | */ | |
943 | ||
944 | s ++; | |
945 | if (!*s) | |
946 | break; | |
947 | ||
948 | switch (*s++) | |
949 | { | |
950 | case 'R' : | |
951 | fputs("®", fp); | |
952 | break; | |
953 | ||
954 | case '(' : | |
955 | if (!strncmp(s, "lq", 2)) | |
956 | fputs("“", fp); | |
957 | else if (!strncmp(s, "rq", 2)) | |
958 | fputs("”", fp); | |
959 | else if (!strncmp(s, "Tm", 2)) | |
960 | fputs("<sup>TM</sup>", fp); | |
961 | else | |
962 | fprintf(stderr, "mantohtml: Unknown macro \"\\*(%2s\" ignored.\n", s); | |
963 | ||
964 | if (*s) | |
965 | s ++; | |
966 | if (*s) | |
967 | s ++; | |
968 | break; | |
969 | ||
970 | default : | |
971 | fprintf(stderr, "mantohtml: Unknown macro \"\\*%c\" ignored.\n", s[-1]); | |
972 | break; | |
973 | } | |
974 | } | |
975 | else if (*s == '(') | |
976 | { | |
977 | if (!strncmp(s, "(em", 3)) | |
978 | { | |
979 | fputs("—", fp); | |
980 | s += 3; | |
981 | } | |
982 | else if (!strncmp(s, "(en", 3)) | |
983 | { | |
984 | fputs("–", fp); | |
985 | s += 3; | |
986 | } | |
987 | else | |
988 | { | |
989 | putc(*s, fp); | |
990 | s ++; | |
991 | } | |
992 | } | |
993 | else if (*s == '[') | |
994 | { | |
995 | /* | |
996 | * Substitute escaped character... | |
997 | */ | |
998 | ||
999 | s ++; | |
1000 | if (!strncmp(s, "co]", 3)) | |
1001 | fputs("©", fp); | |
1002 | else if (!strncmp(s, "de]", 3)) | |
1003 | fputs("°", fp); | |
1004 | else if (!strncmp(s, "rg]", 3)) | |
1005 | fputs("®", fp); | |
1006 | else if (!strncmp(s, "tm]", 3)) | |
1007 | fputs("<sup>TM</sup>", fp); | |
1008 | ||
1009 | if (*s) | |
1010 | s ++; | |
1011 | if (*s) | |
1012 | s ++; | |
1013 | if (*s) | |
1014 | s ++; | |
1015 | } | |
1016 | else if (isdigit(s[0]) && isdigit(s[1]) && | |
1017 | isdigit(s[2])) | |
1018 | { | |
1019 | fprintf(fp, "&#%d;", ((s[0] - '0') * 8 + s[1] - '0') * 8 + s[2] - '0'); | |
1020 | s += 3; | |
1021 | } | |
1022 | else | |
1023 | { | |
1024 | if (*s != '\\' && *s == '\"' && *s == '\'' && *s == '-') | |
1025 | fprintf(stderr, "mantohtml: Unrecognized escape \"\\%c\" ignored.\n", *s); | |
1026 | ||
1027 | html_putc(*s++, fp); | |
1028 | } | |
1029 | } | |
1030 | else if (!strncmp(s, "http://", 7) || !strncmp(s, "https://", 8) || !strncmp(s, "ftp://", 6)) | |
1031 | { | |
1032 | /* | |
1033 | * Embed URL... | |
1034 | */ | |
1035 | ||
1036 | char temp[1024]; /* Temporary string */ | |
1037 | const char *end = s + 6; /* End of URL */ | |
1038 | ||
1039 | while (*end && !isspace(*end & 255)) | |
1040 | end ++; | |
1041 | ||
1042 | if (end[-1] == ',' || end[-1] == '.' || end[-1] == ')') | |
1043 | end --; | |
1044 | ||
1045 | strlcpy(temp, s, sizeof(temp)); | |
1046 | if ((size_t)(end -s) < sizeof(temp)) | |
1047 | temp[end - s] = '\0'; | |
1048 | ||
1049 | fprintf(fp, "<a href=\"%s\">%s</a>", temp, temp); | |
1050 | s = end; | |
1051 | } | |
1052 | else | |
1053 | html_putc(*s++ & 255, fp); | |
1054 | } | |
1055 | } | |
1056 | ||
1057 | ||
1058 | /* | |
1059 | * 'html_putc()' - Put a single character, using entities as needed. | |
ef416fc2 | 1060 | */ |
1061 | ||
1062 | static void | |
1a18c85c MS |
1063 | html_putc(int ch, /* I - Character */ |
1064 | FILE *fp) /* I - File */ | |
ef416fc2 | 1065 | { |
1066 | if (ch == '&') | |
1067 | fputs("&", fp); | |
1068 | else if (ch == '<') | |
1069 | fputs("<", fp); | |
1070 | else | |
1071 | putc(ch, fp); | |
1072 | } | |
1073 | ||
1074 | ||
1075 | /* | |
1076 | * 'strmove()' - Move characters within a string. | |
1077 | */ | |
1078 | ||
1079 | static void | |
1080 | strmove(char *d, /* I - Destination */ | |
1081 | const char *s) /* I - Source */ | |
1082 | { | |
1083 | while (*s) | |
1084 | *d++ = *s++; | |
1085 | ||
1086 | *d = '\0'; | |
1087 | } | |
1088 | ||
1089 | ||
1090 | /* | |
1a18c85c | 1091 | * End of "$Id: mantohtml.c 11818 2014-04-15 20:56:19Z msweet $". |
ef416fc2 | 1092 | */ |