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