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