]> git.ipfire.org Git - thirdparty/cups.git/blame - man/mantohtml.c
Merge changes from CUPS 1.4svn-r7961.
[thirdparty/cups.git] / man / mantohtml.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: mantohtml.c 7720 2008-07-11 22:46:21Z mike $"
ef416fc2 3 *
4 * Man page to HTML conversion program.
5 *
1f0275e3 6 * Copyright 2007-2008 by Apple Inc.
bd7854cb 7 * Copyright 2004-2006 by Easy Software Products.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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 * Contents:
16 *
17 * main() - Convert a man page to HTML.
18 * putc_entity() - Put a single character, using entities as needed.
19 * strmove() - Move characters within a string.
20 */
21
22/*
23 * Include necessary headers.
24 */
25
26#include <cups/string.h>
27#include <stdlib.h>
ecdc0628 28#include <unistd.h>
ef416fc2 29
30
31/*
32 * Local functions...
33 */
34
35static void putc_entity(int ch, FILE *fp);
36static void strmove(char *d, const char *s);
37
38
39/*
40 * 'main()' - Convert a man page to HTML.
41 */
42
43int /* O - Exit status */
44main(int argc, /* I - Number of command-line args */
45 char *argv[]) /* I - Command-line arguments */
46{
47 FILE *infile, /* Input file */
48 *outfile; /* Output file */
49 char line[1024], /* Line from file */
50 *lineptr, /* Pointer into line */
bd7854cb 51 *endptr, /* Pointer to end of current */
52 endchar, /* End character */
53 *paren, /* Pointer to parenthesis */
ef416fc2 54 name[1024]; /* Man page name */
55 int section, /* Man page section */
56 pre, /* Preformatted */
57 font, /* Current font */
58 blist, /* In a bullet list? */
59 list, /* In a list? */
60 linenum; /* Current line number */
61 const char *post; /* Text to add after the current line */
62 static const char /* Start/end tags for fonts */
63 * const start_fonts[] = { "", "<b>", "<i>" },
64 * const end_fonts[] = { "", "</b>", "</i>" };
65
66 /*
67 * Check arguments...
68 */
69
70 if (argc > 3)
71 {
72 fputs("Usage: mantohtml [filename.man [filename.html]]\n", stderr);
73 return (1);
74 }
75
76 /*
77 * Open files as needed...
78 */
79
80 if (argc > 1)
81 {
82 if ((infile = fopen(argv[1], "r")) == NULL)
83 {
84 perror(argv[1]);
85 return (1);
86 }
87 }
88 else
89 infile = stdin;
90
91 if (argc > 2)
92 {
93 if ((outfile = fopen(argv[2], "w")) == NULL)
94 {
95 perror(argv[2]);
96 fclose(infile);
97 return (1);
98 }
99 }
100 else
101 outfile = stdout;
102
103 /*
104 * Read from input and write the output...
105 */
106
107 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" "
108 "\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n"
109 "<html>\n"
110 "<!-- SECTION: Man Pages -->\n"
111 "<head>\n"
112 "\t<style type='text/css'><!--\n"
113 "\th1, h2, h3, p { font-family: sans-serif; text-align: justify; }\n"
114 "\ttt, pre a:link, pre a:visited, tt a:link, tt a:visited { font-weight: bold; color: #7f0000; }\n"
115 "\tpre { font-weight: bold; color: #7f0000; margin-left: 2em; }\n"
116 "\th1.title, h2.title, h3.title { border-bottom: solid 2px #000000; }\n"
117 "\t--></style>\n", outfile);
118
119 blist = 0;
120 font = 0;
121 list = 0;
122 linenum = 0;
123 pre = 0;
124 post = NULL;
125 section = -1;
126
127 while (fgets(line, sizeof(line), infile))
128 {
129 linenum ++;
130
131 if (line[0] == '.')
132 {
133 /*
134 * Strip leading whitespace...
135 */
136
137 while (line[1] == ' ' || line[1] == '\t')
138 strmove(line + 1, line + 2);
139
140 /*
141 * Process man page commands...
142 */
143
144 if (!strncmp(line, ".TH ", 4) && section < 0)
145 {
146 /*
147 * Grab man page title...
148 */
149
150 sscanf(line + 4, "%s%d", name, &section);
151
152 fprintf(outfile,
bd7854cb 153 "\t<title>%s(%d)</title>\n"
ef416fc2 154 "</head>\n"
155 "<body>\n"
ef416fc2 156 "%s",
bd7854cb 157 name, section, start_fonts[font]);
ef416fc2 158 }
159 else if (section < 0)
160 continue;
dd1abb6b 161 else if (!strncmp(line, ".SH ", 4) || !strncmp(line, ".SS ", 4))
ef416fc2 162 {
163 /*
164 * Grab heading...
165 */
166
167 int first = 1;
168
169 fputs(end_fonts[font], outfile);
170
171 if (blist)
172 {
173 fputs("</li>\n</ul>\n", outfile);
174 blist = 0;
175 }
176
177 if (list)
178 {
179 if (list == 1)
180 fputs("</dt>\n", outfile);
181 else if (list)
182 fputs("</dd>\n", outfile);
183
184 fputs("</dl>\n", outfile);
185 list = 0;
186 }
187
bd7854cb 188 line[strlen(line) - 1] = '\0'; /* Strip LF */
189
ef416fc2 190 if (line[2] == 'H')
bd7854cb 191 fputs("<h2><a name='", outfile);
ef416fc2 192 else
bd7854cb 193 fputs("<h3><a name='", outfile);
194
195 for (lineptr = line + 4; *lineptr; lineptr ++)
196 if (*lineptr == '\"')
197 continue;
198 else if (*lineptr == ' ')
199 putc_entity('_', outfile);
200 else
201 putc_entity(*lineptr, outfile);
202
203 fputs("'>", outfile);
ef416fc2 204
205 for (lineptr = line + 4; *lineptr; lineptr ++)
206 if (*lineptr == '\"')
207 continue;
208 else if (*lineptr == ' ')
209 {
210 putc_entity(' ', outfile);
211
212 first = 1;
213 }
bd7854cb 214 else
ef416fc2 215 {
216 if (first)
bd7854cb 217 putc_entity(*lineptr, outfile);
ef416fc2 218 else
219 putc_entity(tolower(*lineptr), outfile);
220
221 first = 0;
222 }
223
224 if (line[2] == 'H')
bd7854cb 225 fprintf(outfile, "</a></h2>\n%s", start_fonts[font]);
ef416fc2 226 else
bd7854cb 227 fprintf(outfile, "</a></h3>\n%s", start_fonts[font]);
ef416fc2 228 }
229 else if (!strncmp(line, ".LP", 3) || !strncmp(line, ".PP", 3))
230 {
231 /*
232 * New paragraph...
233 */
234
235 fputs(end_fonts[font], outfile);
236
237 if (blist)
238 {
239 fputs("</li>\n</ul>\n", outfile);
240 blist = 0;
241 }
242
243 if (list)
244 {
245 if (list == 1)
246 fputs("</dt>\n", outfile);
247 else if (list)
248 fputs("</dd>\n", outfile);
249
250 fputs("</dl>\n", outfile);
251 list = 0;
252 }
253
254 fputs("<p>", outfile);
255 font = 0;
256 }
257 else if (!strncmp(line, ".TP ", 4))
258 {
259 /*
260 * Grab list...
261 */
262
263 fputs(end_fonts[font], outfile);
264
265 if (blist)
266 {
267 fputs("</li>\n</ul>\n", outfile);
268 blist = 0;
269 }
270
271 if (!list)
272 fputs("<dl>\n", outfile);
273 else if (list == 1)
274 fputs("</dt>\n", outfile);
275 else if (list)
276 fputs("</dd>\n", outfile);
277
278 fputs("<dt>", outfile);
279 list = 1;
280 font = 0;
281 }
282 else if (!strncmp(line, ".br", 3))
283 {
284 /*
285 * Grab line break...
286 */
287
288 if (list == 1)
289 {
290 fputs("</dt>\n<dd>", outfile);
291 list = 2;
292 }
293 else if (list)
294 fputs("</dd>\n<dd>", outfile);
295 else
296 fputs("<br>\n", outfile);
297 }
298 else if (!strncmp(line, ".de ", 4))
299 {
300 /*
301 * Define macro - ignore...
302 */
303
304 while (fgets(line, sizeof(line), infile))
305 {
306 linenum ++;
307
308 if (!strncmp(line, "..", 2))
309 break;
310 }
311 }
312 else if (!strncmp(line, ".RS", 3))
313 {
314 /*
315 * Indent...
316 */
317
318 fputs("<div style='margin-left: 3em;'>\n", outfile);
319 }
320 else if (!strncmp(line, ".RE", 3))
321 {
322 /*
323 * Unindent...
324 */
325
326 fputs("</div>\n", outfile);
327 }
328 else if (!strncmp(line, ".ds ", 4) || !strncmp(line, ".rm ", 4) ||
329 !strncmp(line, ".tr ", 4) || !strncmp(line, ".hy ", 4) ||
330 !strncmp(line, ".IX ", 4) || !strncmp(line, ".PD", 3) ||
331 !strncmp(line, ".Sp", 3))
332 {
333 /*
334 * Ignore unused commands...
335 */
336 }
337 else if (!strncmp(line, ".Vb", 3) || !strncmp(line, ".nf", 3))
338 {
339 /*
340 * Start preformatted...
341 */
342
343 pre = 1;
344 fputs("<pre>\n", outfile);
345 }
346 else if (!strncmp(line, ".Ve", 3) || !strncmp(line, ".fi", 3))
347 {
348 /*
349 * End preformatted...
350 */
351
352 if (pre)
353 {
354 pre = 0;
355 fputs("</pre>\n", outfile);
356 }
357 }
358 else if (!strncmp(line, ".IP \\(bu", 8))
359 {
360 /*
361 * Bullet list...
362 */
363
364 if (blist)
365 fputs("</li>\n", outfile);
366 else
367 {
368 fputs("<ul>\n", outfile);
369 blist = 1;
370 }
371
372 fputs("<li>", outfile);
373 }
374 else if (!strncmp(line, ".IP ", 4))
375 {
376 /*
377 * Indented paragraph...
378 */
379
380 if (blist)
381 {
382 fputs("</li>\n</ul>\n", outfile);
383 blist = 0;
384 }
385
386 fputs("<p style='margin-left: 3em;'>", outfile);
387
388 for (lineptr = line + 4; isspace(*lineptr); lineptr ++);
389
390 if (*lineptr == '\"')
391 {
392 strmove(line, lineptr + 1);
393
394 if ((lineptr = strchr(line, '\"')) != NULL)
395 *lineptr = '\0';
396 }
397 else
398 {
399 strmove(line, lineptr);
400
401 if ((lineptr = strchr(line, ' ')) != NULL)
402 *lineptr = '\0';
403 }
404
405 /*
406 * Process the text as if it was in-line...
407 */
408
409 post = "\n<br />\n<br />";
410 goto process_text;
411 }
412 else if (!strncmp(line, ".\\}", 3))
413 {
414 /*
415 * Ignore close block...
416 */
417 }
418 else if (!strncmp(line, ".ie", 3) || !strncmp(line, ".if", 3) ||
419 !strncmp(line, ".el", 3))
420 {
421 /*
422 * If/else - ignore...
423 */
424
425 if (strchr(line, '{') != NULL)
426 {
427 /*
428 * Skip whole block...
429 */
430
431 while (fgets(line, sizeof(line), infile))
432 {
433 linenum ++;
434
435 if (strchr(line, '}') != NULL)
436 break;
437 }
438 }
439 }
440#if 0
441 else if (!strncmp(line, ". ", 4))
442 {
443 /*
444 * Grab ...
445 */
446 }
447#endif /* 0 */
448 else if (!strncmp(line, ".B ", 3))
449 {
450 /*
451 * Grab bold text...
452 */
453
454 fprintf(outfile, "%s<b>%s</b>%s", end_fonts[font], line + 3,
455 start_fonts[font]);
456 }
457 else if (!strncmp(line, ".I ", 3))
458 {
459 /*
460 * Grab italic text...
461 */
462
463 fprintf(outfile, "%s<i>%s</i>%s", end_fonts[font], line + 3,
464 start_fonts[font]);
465 }
466 else if (strncmp(line, ".\\\"", 3))
467 {
468 /*
469 * Unknown...
470 */
471
472 if ((lineptr = strchr(line, ' ')) != NULL)
473 *lineptr = '\0';
474 else if ((lineptr = strchr(line, '\n')) != NULL)
475 *lineptr = '\0';
476
477 fprintf(stderr, "mantohtml: Unknown man page command \'%s\' on line %d!\n",
478 line, linenum);
479 }
480
481 /*
482 * Skip continuation lines...
483 */
484
485 lineptr = line + strlen(line) - 2;
486 if (lineptr >= line && *lineptr == '\\')
487 {
488 while (fgets(line, sizeof(line), infile))
489 {
490 linenum ++;
491 lineptr = line + strlen(line) - 2;
492
493 if (lineptr < line || *lineptr != '\\')
494 break;
495 }
496 }
497 }
498 else
499 {
500 /*
501 * Process man page text...
502 */
503
504process_text:
505
506 for (lineptr = line; *lineptr; lineptr ++)
507 {
bd7854cb 508 if (!strncmp(lineptr, "http://", 7))
509 {
510 /*
511 * Embed URL...
512 */
513
514 for (endptr = lineptr + 7;
515 *endptr && !isspace(*endptr & 255);
516 endptr ++);
517
518 endchar = *endptr;
519 *endptr = '\0';
520
521 fprintf(outfile, "<a href='%s'>%s</a>", lineptr, lineptr);
522 *endptr = endchar;
523 lineptr = endptr - 1;
524 }
525 else if (!strncmp(lineptr, "\\fI", 3) &&
526 (endptr = strstr(lineptr, "\\fR")) != NULL &&
527 (paren = strchr(lineptr, '(')) != NULL &&
528 paren < endptr)
529 {
530 /*
531 * Link to man page?
532 */
533
534 char manfile[1024], /* Man page filename */
535 manurl[1024]; /* Man page URL */
536
537
538 /*
539 * See if the man file is available locally...
540 */
541
542 lineptr += 3;
543 endchar = *paren;
544 *paren = '\0';
545
546 snprintf(manfile, sizeof(manfile), "%s.man", lineptr);
547 snprintf(manurl, sizeof(manurl), "man-%s.html?TOPIC=Man+Pages",
548 lineptr);
549
550 *paren = endchar;
551 endchar = *endptr;
552 *endptr = '\0';
553
554 if (access(manfile, 0))
555 {
556 /*
557 * Not a local man page, just do it italic...
558 */
559
560 fputs("<i>", outfile);
561 while (*lineptr)
562 putc_entity(*lineptr++, outfile);
563 fputs("</i>", outfile);
564 }
565 else
566 {
567 /*
568 * Local man page, do a link...
569 */
570
571 fprintf(outfile, "<a href='%s'>", manurl);
572 while (*lineptr)
573 putc_entity(*lineptr++, outfile);
574 fputs("</a>", outfile);
575 }
576
577 *endptr = endchar;
578 lineptr = endptr + 2;
579 }
580 else if (*lineptr == '\\')
ef416fc2 581 {
582 lineptr ++;
583 if (!*lineptr)
584 break;
585 else if (isdigit(lineptr[0]) && isdigit(lineptr[1]) &&
586 isdigit(lineptr[2]))
587 {
588 fprintf(outfile, "&#%d;", ((lineptr[0] - '0') * 8 +
589 lineptr[1] - '0') * 8 +
590 lineptr[2] - '0');
591 lineptr += 2;
592 }
593 else if (*lineptr == '&')
594 continue;
595 else if (*lineptr == 's')
596 {
597 while (lineptr[1] == '-' || isdigit(lineptr[1]))
598 lineptr ++;
599 }
600 else if (*lineptr == '*')
601 {
602 lineptr += 2;
603 }
604 else if (*lineptr != 'f')
605 putc_entity(*lineptr, outfile);
606 else
607 {
608 lineptr ++;
609 if (!*lineptr)
610 break;
611 else
612 {
613 fputs(end_fonts[font], outfile);
614
615 switch (*lineptr)
616 {
617 default : /* Regular */
618 font = 0;
619 break;
620 case 'B' : /* Bold */
621 case 'b' :
622 font = 1;
623 break;
624 case 'I' : /* Italic */
625 case 'i' :
626 font = 2;
627 break;
628 }
629
630 fputs(start_fonts[font], outfile);
631 }
632 }
633 }
634 else
635 putc_entity(*lineptr, outfile);
636 }
637
638 if (post)
639 {
640 fputs(post, outfile);
641 post = NULL;
642 }
643 }
644 }
645
646 fprintf(outfile, "%s\n", end_fonts[font]);
647
648 if (blist)
649 {
650 fputs("</li>\n</ul>\n", outfile);
ef416fc2 651 }
652
653 if (list)
654 {
655 if (list == 1)
656 fputs("</dt>\n", outfile);
657 else if (list)
658 fputs("</dd>\n", outfile);
659
660 fputs("</dl>\n", outfile);
ef416fc2 661 }
662
663 fputs("</body>\n"
664 "</html>\n", outfile);
665
666 /*
667 * Close files...
668 */
669
670 if (infile != stdin)
671 fclose(infile);
672
673 if (outfile != stdout)
674 fclose(outfile);
675
676 /*
677 * Return with no errors...
678 */
679
680 return (0);
681}
682
683
684/*
685 * 'putc_entity()' - Put a single character, using entities as needed.
686 */
687
688static void
689putc_entity(int ch, /* I - Character */
690 FILE *fp) /* I - File */
691{
692 if (ch == '&')
693 fputs("&amp;", fp);
694 else if (ch == '<')
695 fputs("&lt;", fp);
696 else
697 putc(ch, fp);
698}
699
700
701/*
702 * 'strmove()' - Move characters within a string.
703 */
704
705static void
706strmove(char *d, /* I - Destination */
707 const char *s) /* I - Source */
708{
709 while (*s)
710 *d++ = *s++;
711
712 *d = '\0';
713}
714
715
716/*
b19ccc9e 717 * End of "$Id: mantohtml.c 7720 2008-07-11 22:46:21Z mike $".
ef416fc2 718 */