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