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