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