]>
git.ipfire.org Git - thirdparty/cups.git/blob - man/mantohtml.c
4 * Man page to HTML conversion program.
6 * Copyright 2007-2010, 2014 by Apple Inc.
7 * Copyright 2004-2006 by Easy Software Products.
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/".
17 * Include necessary headers.
20 #include <cups/string-private.h>
21 #include <cups/array-private.h>
29 static const char /* Start/end tags for fonts */
30 * const start_fonts
[] = { "", "<b>", "<i>" },
31 * const end_fonts
[] = { "", "</b>", "</i>" };
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
);
41 static void strmove(char *d
, const char *s
);
45 * 'main()' - Convert a man page to HTML.
48 int /* O - Exit status */
49 main(int argc
, /* I - Number of command-line args */
50 char *argv
[]) /* I - Command-line arguments */
52 FILE *infile
, /* Input file */
53 *outfile
; /* Output file */
54 char line
[1024], /* Line from file */
55 *lineptr
, /* Pointer into line */
56 name
[1024]; /* Man page name */
57 int section
= -1, /* Man page section */
58 pre
= 0, /* Preformatted */
59 font
= 0, /* Current font */
60 linenum
= 0; /* Current line number */
61 const char *list
= NULL
; /* Current list, if any */
62 const char *post
= NULL
; /* Text to add after the current line */
71 fputs("Usage: mantohtml [filename.man [filename.html]]\n", stderr
);
76 * Open files as needed...
81 if ((infile
= fopen(argv
[1], "r")) == NULL
)
92 if ((outfile
= fopen(argv
[2], "w")) == NULL
)
103 * Read from input and write the output...
106 fputs("<!DOCTYPE HTML>\n"
108 "<!-- SECTION: Man Pages -->\n"
110 "\t<link rel=\"stylesheet\" type=\"text/css\" "
111 "href=\"../cups-printable.css\">\n", outfile
);
113 while (fgets(line
, sizeof(line
), infile
))
115 size_t linelen
= strlen(line
); /* Length of line */
117 if (linelen
> 0 && line
[linelen
- 1] == '\n')
118 line
[linelen
- 1] = '\0';
125 * Strip leading whitespace...
128 while (line
[1] == ' ' || line
[1] == '\t')
129 strmove(line
+ 1, line
+ 2);
132 * Process man page commands...
135 if (!strncmp(line
, ".TH ", 4) && section
< 0)
138 * Grab man page title...
141 sscanf(line
+ 4, "%s%d", name
, §ion
);
144 "\t<title>%s(%d)</title>\n"
147 "<h1 class=\"title\">%s(%d)</h1>\n"
149 name
, section
, name
, section
, start_fonts
[font
]);
151 else if (section
< 0)
153 else if (!strncmp(line
, ".SH ", 4) || !strncmp(line
, ".SS ", 4))
161 fputs(end_fonts
[font
], outfile
);
166 fprintf(outfile
, "</%s>\n", list
);
171 fputs("<h2 class=\"title\"><a name=\"", outfile
);
173 fputs("<h3><a name=\"", outfile
);
175 for (lineptr
= line
+ 4; *lineptr
; lineptr
++)
176 if (*lineptr
== '\"')
178 else if (isalnum(*lineptr
& 255))
179 html_putc(*lineptr
, outfile
);
181 html_putc('_', outfile
);
183 fputs("\">", outfile
);
185 for (lineptr
= line
+ 4; *lineptr
; lineptr
++)
187 if (*lineptr
== '\"')
189 else if (*lineptr
== ' ')
191 html_putc(' ', outfile
);
198 html_putc(*lineptr
, outfile
);
200 html_putc(tolower(*lineptr
& 255), outfile
);
207 fputs("</a></h2>\n", outfile
);
209 fputs("</a></h3>\n", outfile
);
211 else if (!strncmp(line
, ".B ", 3))
217 fputs(end_fonts
[font
], outfile
);
220 html_alternate(line
+ 3, "b", "b", outfile
);
222 else if (!strncmp(line
, ".I ", 3))
225 * Grab italic text...
228 fputs(end_fonts
[font
], outfile
);
231 html_alternate(line
+ 3, "i", "i", outfile
);
233 else if (!strncmp(line
, ".BI ", 4))
236 * Alternating bold and italic text...
239 fputs(end_fonts
[font
], outfile
);
242 html_alternate(line
+ 4, "b", "i", outfile
);
244 else if (!strncmp(line
, ".BR ", 4))
247 * Alternating bold and roman (plain) text...
250 fputs(end_fonts
[font
], outfile
);
253 html_alternate(line
+ 4, "b", NULL
, outfile
);
255 else if (!strncmp(line
, ".IB ", 4))
258 * Alternating italic and bold text...
261 fputs(end_fonts
[font
], outfile
);
264 html_alternate(line
+ 4, "i", "b", outfile
);
266 else if (!strncmp(line
, ".IR ", 4))
269 * Alternating italic and roman (plain) text...
272 fputs(end_fonts
[font
], outfile
);
275 html_alternate(line
+ 4, "i", NULL
, outfile
);
277 else if (!strncmp(line
, ".RB ", 4))
280 * Alternating roman (plain) and bold text...
283 fputs(end_fonts
[font
], outfile
);
286 html_alternate(line
+ 4, NULL
, "b", outfile
);
288 else if (!strncmp(line
, ".RI ", 4))
291 * Alternating roman (plain) and italic text...
294 fputs(end_fonts
[font
], outfile
);
297 html_alternate(line
+ 4, NULL
, "i", outfile
);
299 else if (!strncmp(line
, ".SB ", 4))
302 * Alternating small and bold text...
305 fputs(end_fonts
[font
], outfile
);
308 html_alternate(line
+ 4, "small", "b", outfile
);
310 else if (!strncmp(line
, ".SM ", 4))
316 fputs(end_fonts
[font
], outfile
);
319 html_alternate(line
+ 4, "small", "small", outfile
);
321 else if (!strcmp(line
, ".LP") || !strcmp(line
, ".PP") || !strcmp(line
, ".P"))
327 fputs(end_fonts
[font
], outfile
);
332 fprintf(outfile
, "</%s>\n", list
);
336 fputs("<p>", outfile
);
338 else if (!strcmp(line
, ".RS") || !strncmp(line
, ".RS ", 4))
344 float amount
= 3.0; /* Indentation */
347 amount
= atof(line
+ 4);
349 fputs(end_fonts
[font
], outfile
);
354 fprintf(outfile
, "</%s>\n", list
);
358 fprintf(outfile
, "<div style=\"margin-left: %.1fem;\">\n", amount
);
360 else if (!strcmp(line
, ".RE"))
366 fputs(end_fonts
[font
], outfile
);
369 fputs("</div>\n", outfile
);
371 else if (!strcmp(line
, ".HP") || !strncmp(line
, ".HP ", 4) ||
372 !strcmp(line
, ".TP") || !strncmp(line
, ".TP ", 4))
375 * Hanging paragraph/tagged list...
381 float amount
= 3.0; /* Indentation */
384 amount
= atof(line
+ 4);
386 fputs(end_fonts
[font
], outfile
);
391 fprintf(outfile
, "</%s>\n", list
);
395 fprintf(outfile
, "<p style=\"margin-left: %.1fem; text-indent: %.1fem\">", amount
, -amount
);
400 else if (!strncmp(line
, ".IP ", 4))
403 * Indented paragraph...
408 float amount
= 3.0; /* Indentation */
409 const char *newlist
= NULL
; /* New list style */
410 const char *newtype
= NULL
; /* New list numbering type */
412 fputs(end_fonts
[font
], outfile
);
416 while (isspace(*lineptr
& 255))
419 if (!strncmp(lineptr
, "\\(bu", 4) || !strncmp(lineptr
, "\\(em", 4))
427 else if (isdigit(*lineptr
& 255))
435 else if (islower(*lineptr
& 255))
438 * Lowercase alpha list...
444 else if (isupper(*lineptr
& 255))
447 * Lowercase alpha list...
454 while (!isspace(*lineptr
& 255))
456 while (isspace(*lineptr
& 255))
459 if (isdigit(*lineptr
& 255))
460 amount
= atof(lineptr
);
462 if (newlist
&& list
&& strcmp(newlist
, list
))
464 fprintf(outfile
, "</%s>\n", list
);
468 if (newlist
&& !list
)
471 fprintf(outfile
, "<%s type=\"%s\">\n", newlist
, newtype
);
473 fprintf(outfile
, "<%s>\n", newlist
);
479 fprintf(outfile
, "<li style=\"margin-left: %.1fem;\">", amount
);
481 fprintf(outfile
, "<p style=\"margin-left: %.1fem;\">", amount
);
483 else if (!strncmp(line
, ".br", 3))
489 fputs("<br>\n", outfile
);
491 else if (!strncmp(line
, ".de ", 4))
494 * Define macro - ignore...
497 while (fgets(line
, sizeof(line
), infile
))
501 if (!strncmp(line
, "..", 2))
505 else if (!strncmp(line
, ".ds ", 4) || !strncmp(line
, ".rm ", 4) ||
506 !strncmp(line
, ".tr ", 4) || !strncmp(line
, ".hy ", 4) ||
507 !strncmp(line
, ".IX ", 4) || !strncmp(line
, ".PD", 3) ||
508 !strncmp(line
, ".Sp", 3))
511 * Ignore unused commands...
514 else if (!strncmp(line
, ".Vb", 3) || !strncmp(line
, ".nf", 3))
517 * Start preformatted...
520 fputs(end_fonts
[font
], outfile
);
525 fprintf(outfile
, "</%s>\n", list
);
530 fputs("<pre>\n", outfile
);
532 else if (!strncmp(line
, ".Ve", 3) || !strncmp(line
, ".fi", 3))
535 * End preformatted...
538 fputs(end_fonts
[font
], outfile
);
544 fputs("</pre>\n", outfile
);
547 else if (!strncmp(line
, ".\\}", 3))
550 * Ignore close block...
553 else if (!strncmp(line
, ".ie", 3) || !strncmp(line
, ".if", 3) ||
554 !strncmp(line
, ".el", 3))
557 * If/else - ignore...
560 if (strchr(line
, '{') != NULL
)
563 * Skip whole block...
566 while (fgets(line
, sizeof(line
), infile
))
570 if (strchr(line
, '}') != NULL
)
576 else if (!strncmp(line
, ". ", 4))
583 else if (strncmp(line
, ".\\\"", 3))
589 if ((lineptr
= strchr(line
, ' ')) != NULL
)
591 else if ((lineptr
= strchr(line
, '\n')) != NULL
)
594 fprintf(stderr
, "mantohtml: Unknown man page command \'%s\' on line %d.\n", line
, linenum
);
598 * Skip continuation lines...
601 lineptr
= line
+ strlen(line
) - 1;
602 if (lineptr
>= line
&& *lineptr
== '\\')
604 while (fgets(line
, sizeof(line
), infile
))
607 lineptr
= line
+ strlen(line
) - 2;
609 if (lineptr
< line
|| *lineptr
!= '\\')
617 * Process man page text...
620 html_fputs(line
, &font
, outfile
);
625 fputs(post
, outfile
);
631 fprintf(outfile
, "%s\n", end_fonts
[font
]);
636 fprintf(outfile
, "</%s>\n", list
);
641 "</html>\n", outfile
);
650 if (outfile
!= stdout
)
654 * Return with no errors...
662 * 'html_alternate()' - Alternate words between two styles of text.
666 html_alternate(const char *s
, /* I - String */
667 const char *first
, /* I - First style or NULL */
668 const char *second
, /* I - Second style of NULL */
669 FILE *fp
) /* I - File */
671 int i
= 0; /* Which style */
672 int quote
= 0; /* Saw quote? */
673 int dolinks
, /* Do hyperlinks to other man pages? */
674 link
= 0; /* Doing a link now? */
678 * Skip leading whitespace...
681 while (isspace(*s
& 255))
684 dolinks
= first
&& !strcmp(first
, "b") && !second
;
691 * See if we need to make a link to a man page...
694 const char *end
; /* End of current word */
695 const char *next
; /* Start of next word */
697 for (end
= s
; *end
&& !isspace(*end
& 255); end
++);
698 for (next
= end
; isspace(*next
& 255); next
++);
700 if (isalnum(*s
& 255) && *next
== '(')
703 * See if the man file is available locally...
706 char name
[1024], /* Name */
707 manfile
[1024], /* Man page filename */
708 manurl
[1024]; /* Man page URL */
710 strlcpy(name
, s
, sizeof(name
));
711 if ((size_t)(end
- s
) < sizeof(name
))
712 name
[end
- s
] = '\0';
714 snprintf(manfile
, sizeof(manfile
), "%s.man", name
);
715 snprintf(manurl
, sizeof(manurl
), "man-%s.html?TOPIC=Man+Pages", name
);
717 if (!access(manfile
, 0))
720 * Local man page, do a link...
723 fprintf(fp
, "<a href=\"%s\">", manurl
);
730 fprintf(fp
, "<%s>", first
);
731 else if (i
&& second
)
732 fprintf(fp
, "<%s>", second
);
734 while ((!isspace(*s
& 255) || quote
) && *s
)
738 else if (*s
== '\\' && s
[1])
748 fprintf(fp
, "</%s>", first
);
749 else if (i
&& second
)
750 fprintf(fp
, "</%s>", second
);
761 * Skip trailing whitespace...
764 while (isspace(*s
& 255))
767 if (*s
&& *s
!= '(' && *s
!= '.' && *s
!= ',')
775 * 'html_fputs()' - Output a string, quoting as needed HTML entities.
779 html_fputs(const char *s
, /* I - String */
780 int *font
, /* IO - Font */
781 FILE *fp
) /* I - File */
793 int newfont
; /* New font */
823 fprintf(stderr
, "mantohtml: Unknown font \"\\f%c\" ignored.\n", s
[-1]);
828 if (newfont
!= *font
)
830 fputs(end_fonts
[*font
], fp
);
832 fputs(start_fonts
[*font
], fp
);
838 * Substitute macro...
852 if (!strncmp(s
, "lq", 2))
853 fputs("“", fp
);
854 else if (!strncmp(s
, "rq", 2))
855 fputs("”", fp
);
856 else if (!strncmp(s
, "Tm", 2))
857 fputs("<sup>TM</sup>", fp
);
859 fprintf(stderr
, "mantohtml: Unknown macro \"\\*(%2s\" ignored.\n", s
);
868 fprintf(stderr
, "mantohtml: Unknown macro \"\\*%c\" ignored.\n", s
[-1]);
875 * Substitute escaped character...
879 if (!strncmp(s
, "co]", 3))
881 else if (!strncmp(s
, "de]", 3))
883 else if (!strncmp(s
, "rg]", 3))
885 else if (!strncmp(s
, "tm]", 3))
886 fputs("<sup>TM</sup>", fp
);
895 else if (isdigit(s
[0]) && isdigit(s
[1]) &&
898 fprintf(fp
, "&#%d;", ((s
[0] - '0') * 8 + s
[1] - '0') * 8 + s
[2] - '0');
903 if (*s
!= '\\' && *s
== '\"' && *s
== '\'' && *s
== '-')
904 fprintf(stderr
, "mantohtml: Unrecognized escape \"\\%c\" ignored.\n", *s
);
909 else if (!strncmp(s
, "http://", 7) || !strncmp(s
, "https://", 8) || !strncmp(s
, "ftp://", 6))
915 char temp
[1024]; /* Temporary string */
916 const char *end
= s
+ 6; /* End of URL */
918 while (*end
&& !isspace(*end
& 255))
921 if (end
[-1] == ',' || end
[-1] == '.')
924 strlcpy(temp
, s
, sizeof(temp
));
925 if ((size_t)(end
-s
) < sizeof(temp
))
926 temp
[end
- s
] = '\0';
928 fprintf(fp
, "<a href=\"%s\">%s</a>", temp
, temp
);
932 html_putc(*s
++ & 255, fp
);
938 * 'html_putc()' - Put a single character, using entities as needed.
942 html_putc(int ch
, /* I - Character */
943 FILE *fp
) /* I - File */
955 * 'strmove()' - Move characters within a string.
959 strmove(char *d
, /* I - Destination */
960 const char *s
) /* I - Source */