]> git.ipfire.org Git - thirdparty/cups.git/blob - man/mantohtml.c
Remove more unnecessary documentation.
[thirdparty/cups.git] / man / mantohtml.c
1 /*
2 * "$Id$"
3 *
4 * Man page to HTML conversion program.
5 *
6 * Copyright 2007-2010, 2014 by Apple Inc.
7 * Copyright 2004-2006 by Easy Software Products.
8 *
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/".
14 */
15
16 /*
17 * Include necessary headers.
18 */
19
20 #include <cups/string-private.h>
21 #include <cups/array-private.h>
22 #include <unistd.h>
23
24
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
34 /*
35 * Local functions...
36 */
37
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);
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 */
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
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
110 fputs("<!DOCTYPE HTML>\n"
111 "<html>\n"
112 "<!-- SECTION: Man Pages -->\n"
113 "<head>\n"
114 "\t<link rel=\"stylesheet\" type=\"text/css\" "
115 "href=\"../cups-printable.css\">\n", outfile);
116
117 while (fgets(line, sizeof(line), infile))
118 {
119 size_t linelen = strlen(line); /* Length of line */
120
121 if (linelen > 0 && line[linelen - 1] == '\n')
122 line[linelen - 1] = '\0';
123
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, &section);
146
147 fprintf(outfile,
148 "\t<title>%s(%d)</title>\n"
149 "</head>\n"
150 "<body>\n"
151 "<h1 class=\"title\">%s(%d)</h1>\n"
152 "%s",
153 name, section, name, section, start_fonts[font]);
154 }
155 else if (section < 0)
156 continue;
157 else if (!strncmp(line, ".SH ", 4) || !strncmp(line, ".SS ", 4))
158 {
159 /*
160 * Grab heading...
161 */
162
163 int first = 1;
164
165 fputs(end_fonts[font], outfile);
166 font = 0;
167
168 if (list)
169 {
170 fprintf(outfile, "</%s>\n", list);
171 list = NULL;
172 }
173
174 if (line[2] == 'H')
175 fputs("<h2 class=\"title\"><a name=\"", outfile);
176 else
177 fputs("<h3><a name=\"", outfile);
178
179 for (lineptr = line + 4; *lineptr; lineptr ++)
180 if (*lineptr == '\"')
181 continue;
182 else if (isalnum(*lineptr & 255))
183 html_putc(*lineptr, outfile);
184 else
185 html_putc('_', outfile);
186
187 fputs("\">", outfile);
188
189 for (lineptr = line + 4; *lineptr; lineptr ++)
190 {
191 if (*lineptr == '\"')
192 continue;
193 else if (*lineptr == ' ')
194 {
195 html_putc(' ', outfile);
196
197 first = 1;
198 }
199 else
200 {
201 if (first)
202 html_putc(*lineptr, outfile);
203 else
204 html_putc(tolower(*lineptr & 255), outfile);
205
206 first = 0;
207 }
208 }
209
210 if (line[2] == 'H')
211 fputs("</a></h2>\n", outfile);
212 else
213 fputs("</a></h3>\n", outfile);
214 }
215 else if (!strncmp(line, ".B ", 3))
216 {
217 /*
218 * Grab bold text...
219 */
220
221 fputs(end_fonts[font], outfile);
222 font = 0;
223
224 html_alternate(line + 3, "b", "b", outfile);
225
226 if (post)
227 {
228 fputs(post, outfile);
229 post = NULL;
230 }
231 }
232 else if (!strncmp(line, ".I ", 3))
233 {
234 /*
235 * Grab italic text...
236 */
237
238 fputs(end_fonts[font], outfile);
239 font = 0;
240
241 html_alternate(line + 3, "i", "i", outfile);
242
243 if (post)
244 {
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);
259
260 if (post)
261 {
262 fputs(post, outfile);
263 post = NULL;
264 }
265 }
266 else if (!strncmp(line, ".BR ", 4))
267 {
268 /*
269 * Alternating bold and roman (plain) text...
270 */
271
272 fputs(end_fonts[font], outfile);
273 font = 0;
274
275 html_alternate(line + 4, "b", NULL, outfile);
276
277 if (post)
278 {
279 fputs(post, outfile);
280 post = NULL;
281 }
282 }
283 else if (!strncmp(line, ".IB ", 4))
284 {
285 /*
286 * Alternating italic and bold text...
287 */
288
289 fputs(end_fonts[font], outfile);
290 font = 0;
291
292 html_alternate(line + 4, "i", "b", outfile);
293
294 if (post)
295 {
296 fputs(post, outfile);
297 post = NULL;
298 }
299 }
300 else if (!strncmp(line, ".IR ", 4))
301 {
302 /*
303 * Alternating italic and roman (plain) text...
304 */
305
306 fputs(end_fonts[font], outfile);
307 font = 0;
308
309 html_alternate(line + 4, "i", NULL, outfile);
310
311 if (post)
312 {
313 fputs(post, outfile);
314 post = NULL;
315 }
316 }
317 else if (!strncmp(line, ".RB ", 4))
318 {
319 /*
320 * Alternating roman (plain) and bold text...
321 */
322
323 fputs(end_fonts[font], outfile);
324 font = 0;
325
326 html_alternate(line + 4, NULL, "b", outfile);
327
328 if (post)
329 {
330 fputs(post, outfile);
331 post = NULL;
332 }
333 }
334 else if (!strncmp(line, ".RI ", 4))
335 {
336 /*
337 * Alternating roman (plain) and italic text...
338 */
339
340 fputs(end_fonts[font], outfile);
341 font = 0;
342
343 html_alternate(line + 4, NULL, "i", outfile);
344
345 if (post)
346 {
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 */
356
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;
366 }
367 }
368 else if (!strncmp(line, ".SM ", 4))
369 {
370 /*
371 * Small text...
372 */
373
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 }
384 }
385 else if (!strcmp(line, ".LP") || !strcmp(line, ".PP") || !strcmp(line, ".P"))
386 {
387 /*
388 * New paragraph...
389 */
390
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);
401 }
402 else if (!strcmp(line, ".RS") || !strncmp(line, ".RS ", 4))
403 {
404 /*
405 * Indent...
406 */
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);
425 }
426 else if (!strcmp(line, ".RE"))
427 {
428 /*
429 * Unindent...
430 */
431
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 }
445 }
446 else if (!strcmp(line, ".HP") || !strncmp(line, ".HP ", 4))
447 {
448 /*
449 * Hanging paragraph...
450 *
451 * .HP i
452 */
453
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";
472 }
473 else if (!strcmp(line, ".TP") || !strncmp(line, ".TP ", 4))
474 {
475 /*
476 * Tagged list...
477 *
478 * .TP i
479 */
480
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 }
494
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;
505 }
506 else if (!strncmp(line, ".IP ", 4))
507 {
508 /*
509 * Indented paragraph...
510 *
511 * .IP x i
512 */
513
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))
526 {
527 /*
528 * Bullet list...
529 */
530
531 newlist = "ul";
532 }
533 else if (isdigit(*lineptr & 255))
534 {
535 /*
536 * Numbered list...
537 */
538
539 newlist = "ol";
540 }
541 else if (islower(*lineptr & 255))
542 {
543 /*
544 * Lowercase alpha list...
545 */
546
547 newlist = "ol";
548 newtype = "a";
549 }
550 else if (isupper(*lineptr & 255))
551 {
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 ++;
564
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;
572 }
573
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;
582 }
583
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 {
591 /*
592 * Grab line break...
593 */
594
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 }
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 */
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
700 fprintf(stderr, "mantohtml: Unknown man page command \'%s\' on line %d.\n", line, linenum);
701 }
702
703 /*
704 * Skip continuation lines...
705 */
706
707 lineptr = line + strlen(line) - 1;
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
726 html_fputs(line, &font, outfile);
727 putc('\n', outfile);
728
729 if (post)
730 {
731 fputs(post, outfile);
732 post = NULL;
733 }
734 }
735 }
736
737 fprintf(outfile, "%s\n", end_fonts[font]);
738 font = 0;
739
740 if (list)
741 {
742 fprintf(outfile, "</%s>\n", list);
743 list = NULL;
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 /*
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("&reg;", fp);
952 break;
953
954 case '(' :
955 if (!strncmp(s, "lq", 2))
956 fputs("&ldquo;", fp);
957 else if (!strncmp(s, "rq", 2))
958 fputs("&rdquo;", 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("&mdash;", fp);
980 s += 3;
981 }
982 else if (!strncmp(s, "(en", 3))
983 {
984 fputs("&ndash;", 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("&copy;", fp);
1002 else if (!strncmp(s, "de]", 3))
1003 fputs("&deg;", fp);
1004 else if (!strncmp(s, "rg]", 3))
1005 fputs("&reg;", 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.
1060 */
1061
1062 static void
1063 html_putc(int ch, /* I - Character */
1064 FILE *fp) /* I - File */
1065 {
1066 if (ch == '&')
1067 fputs("&amp;", fp);
1068 else if (ch == '<')
1069 fputs("&lt;", 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 /*
1091 * End of "$Id$".
1092 */