]>
Commit | Line | Data |
---|---|---|
fa73b229 | 1 | /* |
bc44d920 | 2 | * "$Id: rfctohtml.c 6649 2007-07-11 21:46:42Z mike $" |
fa73b229 | 3 | * |
4 | * RFC file to HTML conversion program. | |
5 | * | |
bc44d920 | 6 | * Copyright 2007 by Apple Inc. |
fa73b229 | 7 | * Copyright 2006 by Easy Software Products. |
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/". | |
fa73b229 | 14 | * |
15 | * Contents: | |
16 | * | |
ecdc0628 | 17 | * main() - Convert a man page to HTML. |
18 | * put_entity() - Put a single character, using entities as needed. | |
19 | * put_line() - Put a whole string for a line. | |
fa73b229 | 20 | */ |
21 | ||
22 | /* | |
23 | * Include necessary headers. | |
24 | */ | |
25 | ||
26 | #include <cups/string.h> | |
27 | #include <stdlib.h> | |
28 | #include <cups/file.h> | |
29 | ||
30 | ||
31 | /* | |
32 | * Local functions... | |
33 | */ | |
34 | ||
35 | void put_entity(cups_file_t *fp, int ch); | |
36 | void put_line(cups_file_t *fp, const char *line); | |
37 | ||
38 | ||
39 | /* | |
40 | * 'main()' - Convert a man page to HTML. | |
41 | */ | |
42 | ||
43 | int /* O - Exit status */ | |
44 | main(int argc, /* I - Number of command-line args */ | |
45 | char *argv[]) /* I - Command-line arguments */ | |
46 | { | |
47 | cups_file_t *infile, /* Input file */ | |
48 | *outfile; /* Output file */ | |
49 | char line[1024], /* Line from file */ | |
50 | *lineptr, /* Pointer into line */ | |
51 | name[1024], /* Heading anchor name */ | |
52 | *nameptr; /* Pointer into anchor name */ | |
ecdc0628 | 53 | int rfc, /* RFC # */ |
54 | inheading, /* Inside a heading? */ | |
fa73b229 | 55 | inpre, /* Inside preformatted text? */ |
56 | intoc, /* Inside table-of-contents? */ | |
57 | toclevel, /* Current table-of-contents level */ | |
58 | linenum; /* Current line on page */ | |
59 | ||
60 | ||
61 | /* | |
62 | * Check arguments... | |
63 | */ | |
64 | ||
65 | if (argc > 3) | |
66 | { | |
67 | fputs("Usage: rfctohtml [rfcNNNN.txt [rfcNNNN.html]]\n", stderr); | |
68 | return (1); | |
69 | } | |
70 | ||
71 | /* | |
72 | * Open files as needed... | |
73 | */ | |
74 | ||
75 | if (argc > 1) | |
76 | { | |
77 | if ((infile = cupsFileOpen(argv[1], "r")) == NULL) | |
78 | { | |
79 | perror(argv[1]); | |
80 | return (1); | |
81 | } | |
82 | } | |
83 | else | |
84 | infile = cupsFileOpenFd(0, "r"); | |
85 | ||
86 | if (argc > 2) | |
87 | { | |
88 | if ((outfile = cupsFileOpen(argv[2], "w")) == NULL) | |
89 | { | |
90 | perror(argv[2]); | |
91 | cupsFileClose(infile); | |
92 | return (1); | |
93 | } | |
94 | } | |
95 | else | |
96 | outfile = cupsFileOpenFd(1, "w"); | |
97 | ||
98 | /* | |
99 | * Read from input and write the output... | |
100 | */ | |
101 | ||
102 | cupsFilePuts(outfile, | |
103 | "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" " | |
104 | "\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n" | |
105 | "<html>\n" | |
106 | "<!-- SECTION: Specifications -->\n" | |
107 | "<head>\n" | |
108 | "\t<style type='text/css'><!--\n" | |
109 | "\th1, h2, h3 { font-family: sans-serif; }\n" | |
110 | "\tp, pre { font-family: monospace; }\n" | |
ecdc0628 | 111 | "\th2.title, h3.title, h3.title { border-bottom: solid " |
fa73b229 | 112 | "2px #000000; }\n" |
113 | "\t--></style>\n"); | |
114 | ||
115 | /* | |
116 | * Skip the initial header stuff (working group ID, RFC #, authors, and | |
117 | * copyright... | |
118 | */ | |
119 | ||
120 | linenum = 0; | |
ecdc0628 | 121 | rfc = 0; |
fa73b229 | 122 | |
123 | while (cupsFileGets(infile, line, sizeof(line))) | |
124 | { | |
125 | linenum ++; | |
126 | ||
127 | if (line[0]) | |
128 | break; | |
129 | } | |
130 | ||
131 | while (cupsFileGets(infile, line, sizeof(line))) | |
132 | { | |
133 | linenum ++; | |
134 | ||
135 | if (!line[0]) | |
136 | break; | |
ecdc0628 | 137 | else if (!strncasecmp(line, "Request for Comments:", 21)) |
138 | rfc = atoi(line + 21); | |
fa73b229 | 139 | } |
140 | ||
141 | /* | |
142 | * Read the document title... | |
143 | */ | |
144 | ||
145 | while (cupsFileGets(infile, line, sizeof(line))) | |
146 | { | |
147 | linenum ++; | |
148 | ||
149 | if (line[0]) | |
150 | break; | |
151 | } | |
152 | ||
153 | for (lineptr = line; isspace(*lineptr & 255); lineptr ++); | |
154 | ||
ecdc0628 | 155 | cupsFilePrintf(outfile, "<title>RFC %d: %s", rfc, lineptr); |
fa73b229 | 156 | |
157 | while (cupsFileGets(infile, line, sizeof(line))) | |
158 | { | |
159 | linenum ++; | |
160 | ||
161 | if (!line[0]) | |
162 | break; | |
163 | else | |
164 | { | |
165 | for (lineptr = line; isspace(*lineptr & 255); lineptr ++); | |
166 | cupsFilePrintf(outfile, " %s", lineptr); | |
167 | } | |
168 | } | |
169 | ||
170 | cupsFilePuts(outfile, "</title>\n" | |
171 | "</head>\n" | |
172 | "<body>\n"); | |
173 | ||
174 | /* | |
175 | * Read the rest of the file... | |
176 | */ | |
177 | ||
178 | inheading = 0; | |
179 | inpre = 0; | |
180 | intoc = 0; | |
181 | toclevel = 0; | |
182 | ||
183 | while (cupsFileGets(infile, line, sizeof(line))) | |
184 | { | |
185 | linenum ++; | |
186 | ||
187 | if (!line[0]) | |
188 | { | |
189 | if (linenum > 50) | |
190 | continue; | |
191 | ||
192 | if (inpre) | |
193 | { | |
194 | cupsFilePuts(outfile, "</pre>\n"); | |
195 | inpre = 0; | |
196 | } | |
197 | ||
198 | if (inheading) | |
199 | { | |
200 | if (inheading < 0) | |
201 | cupsFilePuts(outfile, "</h1>\n"); | |
202 | else | |
203 | cupsFilePrintf(outfile, "</a></h%d>\n", inheading); | |
204 | ||
205 | inheading = 0; | |
206 | } | |
207 | } | |
208 | else if ((line[0] == ' ' || | |
209 | (!isupper(line[0] & 255) && !isdigit(line[0] & 255) && | |
210 | !strstr(line, "[Page "))) && !inheading) | |
211 | { | |
212 | if (inheading) | |
213 | { | |
214 | if (inheading < 0) | |
215 | cupsFilePuts(outfile, "</h1>\n"); | |
216 | else | |
217 | cupsFilePrintf(outfile, "</a></h%d>\n", inheading); | |
218 | ||
219 | inheading = 0; | |
220 | } | |
221 | ||
222 | for (lineptr = line; *lineptr == ' '; lineptr ++); | |
223 | ||
224 | if (intoc) | |
225 | { | |
226 | char *temp; /* Temporary pointer into line */ | |
227 | int level; /* Heading level */ | |
228 | ||
229 | ||
230 | if (isdigit(*lineptr & 255)) | |
231 | { | |
232 | strlcpy(name, lineptr, sizeof(name)); | |
233 | ||
234 | for (nameptr = name, level = -1; *nameptr;) | |
235 | if (isdigit(*nameptr & 255)) | |
236 | { | |
237 | while (isdigit(*nameptr & 255)) | |
238 | nameptr ++; | |
239 | ||
240 | level ++; | |
241 | } | |
242 | else if (*nameptr == ' ') | |
243 | { | |
244 | *nameptr = '\0'; | |
245 | break; | |
246 | } | |
247 | else | |
248 | nameptr ++; | |
249 | ||
250 | while (toclevel > level) | |
251 | { | |
252 | cupsFilePuts(outfile, "\n</ul>"); | |
253 | toclevel --; | |
254 | } | |
255 | ||
256 | while (toclevel < level) | |
257 | { | |
258 | cupsFilePuts(outfile, "\n<ul style=\"list-style-type: none;\">\n"); | |
259 | toclevel ++; | |
260 | } | |
261 | ||
262 | cupsFilePrintf(outfile, "\n<%s><a href=\"#s%s\">", toclevel ? "li" : "p", | |
263 | name); | |
264 | } | |
265 | ||
266 | temp = lineptr + strlen(lineptr) - 1; | |
267 | ||
268 | while (temp > lineptr) | |
269 | if (*temp == ' ' || !isdigit(*temp & 255)) | |
270 | break; | |
271 | else | |
272 | temp --; | |
273 | ||
274 | if (*temp == ' ') | |
275 | { | |
276 | while (temp > lineptr) | |
277 | if (*temp != ' ' && *temp != '.') | |
278 | break; | |
279 | else | |
280 | *temp-- = '\0'; | |
281 | } | |
282 | else | |
283 | temp = NULL; | |
284 | ||
285 | if (isdigit(*lineptr & 255)) | |
286 | put_line(outfile, lineptr); | |
287 | else | |
288 | put_line(outfile, lineptr - 1); | |
289 | ||
290 | if (temp) | |
291 | cupsFilePuts(outfile, "</a>"); | |
292 | } | |
293 | else if (!inpre) | |
294 | { | |
295 | cupsFilePuts(outfile, "\n<pre>"); | |
296 | put_line(outfile, line); | |
297 | inpre = 1; | |
298 | } | |
299 | else | |
300 | { | |
301 | cupsFilePutChar(outfile, '\n'); | |
302 | put_line(outfile, line); | |
303 | } | |
304 | } | |
305 | else if (strstr(line, "[Page ")) | |
306 | { | |
307 | /* | |
308 | * Skip page footer and header... | |
309 | */ | |
310 | ||
311 | cupsFileGets(infile, line, sizeof(line)); | |
312 | cupsFileGets(infile, line, sizeof(line)); | |
313 | cupsFileGets(infile, line, sizeof(line)); | |
314 | cupsFileGets(infile, line, sizeof(line)); | |
315 | linenum = 3; | |
316 | } | |
317 | else if (isdigit(line[0] & 255) && !inheading) | |
318 | { | |
319 | int level; /* Heading level */ | |
320 | ||
321 | ||
322 | if (intoc) | |
323 | { | |
324 | while (toclevel > 0) | |
325 | { | |
326 | cupsFilePuts(outfile, "\n</ul>"); | |
327 | toclevel --; | |
328 | } | |
329 | ||
330 | cupsFilePutChar(outfile, '\n'); | |
331 | intoc = 0; | |
332 | } | |
333 | ||
334 | if (inpre) | |
335 | { | |
336 | cupsFilePuts(outfile, "</pre>\n"); | |
337 | inpre = 0; | |
338 | } | |
339 | ||
340 | strlcpy(name, line, sizeof(name)); | |
ecdc0628 | 341 | for (nameptr = name, level = 1; *nameptr;) |
fa73b229 | 342 | if (isdigit(*nameptr & 255)) |
343 | { | |
344 | while (isdigit(*nameptr & 255)) | |
345 | nameptr ++; | |
346 | ||
347 | level ++; | |
348 | } | |
349 | else if (*nameptr == ' ') | |
350 | { | |
351 | *nameptr = '\0'; | |
352 | break; | |
353 | } | |
354 | else | |
355 | nameptr ++; | |
356 | ||
ecdc0628 | 357 | cupsFilePrintf(outfile, "\n<h%d class='title'><a name='s%s'>", level, |
358 | name); | |
fa73b229 | 359 | put_line(outfile, line); |
360 | ||
361 | intoc = 0; | |
362 | inheading = level; | |
363 | } | |
364 | else | |
365 | { | |
366 | if (intoc) | |
367 | { | |
368 | while (toclevel > 0) | |
369 | { | |
370 | cupsFilePuts(outfile, "\n</ul>"); | |
371 | toclevel --; | |
372 | } | |
373 | ||
374 | cupsFilePutChar(outfile, '\n'); | |
375 | intoc = 0; | |
376 | } | |
377 | ||
378 | if (!inheading) | |
379 | { | |
ecdc0628 | 380 | cupsFilePuts(outfile, "\n<h2 class='title'>"); |
fa73b229 | 381 | inheading = -1; |
382 | } | |
383 | ||
384 | put_line(outfile, line); | |
385 | ||
386 | intoc = !strcasecmp(line, "Table of Contents"); | |
387 | toclevel = 0; | |
388 | } | |
389 | } | |
390 | ||
391 | if (inpre) | |
392 | cupsFilePuts(outfile, "</pre>\n"); | |
393 | ||
394 | if (inheading) | |
395 | { | |
396 | if (inheading < 0) | |
ecdc0628 | 397 | cupsFilePuts(outfile, "</h2>\n"); |
fa73b229 | 398 | else |
399 | cupsFilePrintf(outfile, "</a></h%d>\n", inheading); | |
400 | } | |
401 | ||
402 | cupsFilePuts(outfile, "</body>\n" | |
403 | "</html>\n"); | |
404 | ||
405 | /* | |
406 | * Close files... | |
407 | */ | |
408 | ||
409 | cupsFileClose(infile); | |
410 | cupsFileClose(outfile); | |
411 | ||
412 | /* | |
413 | * Return with no errors... | |
414 | */ | |
415 | ||
416 | return (0); | |
417 | } | |
418 | ||
419 | ||
420 | /* | |
421 | * 'put_entity()' - Put a single character, using entities as needed. | |
422 | */ | |
423 | ||
424 | void | |
425 | put_entity(cups_file_t *fp, /* I - File */ | |
426 | int ch) /* I - Character */ | |
427 | { | |
428 | if (ch == '&') | |
429 | cupsFilePuts(fp, "&"); | |
430 | else if (ch == '<') | |
431 | cupsFilePuts(fp, "<"); | |
432 | else | |
433 | cupsFilePutChar(fp, ch); | |
434 | } | |
435 | ||
436 | ||
437 | /* | |
438 | * 'put_line()' - Put a whole string for a line. | |
439 | */ | |
440 | ||
441 | void | |
442 | put_line(cups_file_t *fp, /* I - File */ | |
443 | const char *s) /* I - String */ | |
444 | { | |
445 | int whitespace, /* Saw whitespace */ | |
446 | i, /* Looping var */ | |
447 | len; /* Length of keyword */ | |
448 | static const char * const keywords[] =/* Special keywords to boldface */ | |
449 | { | |
450 | "MAY", | |
451 | "MUST", | |
452 | "NOT", | |
453 | "SHALL", | |
454 | "SHOULD" | |
455 | }; | |
456 | ||
457 | ||
458 | whitespace = 1; | |
459 | ||
460 | while (*s) | |
461 | { | |
462 | if (*s == ' ') | |
463 | whitespace = 1; | |
464 | ||
465 | if (whitespace && isupper(*s & 255)) | |
466 | { | |
467 | whitespace = 0; | |
468 | ||
469 | for (i = 0; i < (int)(sizeof(keywords) / sizeof(sizeof(keywords[0]))); i ++) | |
470 | { | |
471 | len = strlen(keywords[i]); | |
472 | if (!strncmp(s, keywords[i], len) && (isspace(s[len] & 255) || !*s)) | |
473 | { | |
474 | cupsFilePrintf(fp, "<b>%s</b>", keywords[i]); | |
475 | s += len; | |
476 | break; | |
477 | } | |
478 | } | |
479 | ||
480 | if (i >= (int)(sizeof(keywords) / sizeof(sizeof(keywords[0])))) | |
481 | put_entity(fp, *s++); | |
482 | } | |
483 | else | |
484 | { | |
485 | if (*s != ' ') | |
486 | whitespace = 0; | |
487 | ||
488 | put_entity(fp, *s++); | |
489 | } | |
490 | } | |
491 | } | |
492 | ||
493 | ||
494 | /* | |
bc44d920 | 495 | * End of "$Id: rfctohtml.c 6649 2007-07-11 21:46:42Z mike $". |
fa73b229 | 496 | */ |