]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/makedocset.c
Import CUPS v1.7.1
[thirdparty/cups.git] / cgi-bin / makedocset.c
CommitLineData
f11a948a 1/*
61515785 2 * "$Id: makedocset.c 3833 2012-05-23 22:51:18Z msweet $"
f11a948a
MS
3 *
4 * Xcode documentation set generator.
5 *
a29fd7dd 6 * Copyright 2007-2012 by Apple Inc.
f11a948a
MS
7 * Copyright 1997-2007 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 * Usage:
16 *
17 * makedocset directory *.tokens
18 *
19 * Contents:
20 *
21 * main() - Test the help index code.
22 * compare_html() - Compare the titles of two HTML files.
23 * compare_sections() - Compare the names of two help sections.
24 * compare_sections_files() - Compare the number of files and section names.
25 * write_index() - Write an index file for the CUPS help.
26 * write_info() - Write the Info.plist file.
27 * write_nodes() - Write the Nodes.xml file.
28 */
29
30/*
31 * Include necessary headers...
32 */
33
a29fd7dd 34#include "cgi-private.h"
f11a948a
MS
35#include <errno.h>
36
37
38/*
39 * Local structures...
40 */
41
42typedef struct _cups_html_s /**** Help file ****/
43{
44 char *path; /* Path to help file */
45 char *title; /* Title of help file */
46} _cups_html_t;
47
48typedef struct _cups_section_s /**** Help section ****/
49{
50 char *name; /* Section name */
51 cups_array_t *files; /* Files in this section */
52} _cups_section_t;
53
54
55/*
56 * Local functions...
57 */
58
59static int compare_html(_cups_html_t *a, _cups_html_t *b);
60static int compare_sections(_cups_section_t *a, _cups_section_t *b);
61static int compare_sections_files(_cups_section_t *a, _cups_section_t *b);
62static void write_index(const char *path, help_index_t *hi);
63static void write_info(const char *path, const char *revision);
64static void write_nodes(const char *path, help_index_t *hi);
65
66
67/*
68 * 'main()' - Test the help index code.
69 */
70
71int /* O - Exit status */
72main(int argc, /* I - Number of command-line args */
73 char *argv[]) /* I - Command-line arguments */
74{
75 int i; /* Looping var */
76 char path[1024], /* Path to documentation */
77 line[1024]; /* Line from file */
78 help_index_t *hi; /* Help index */
79 cups_file_t *tokens, /* Tokens.xml file */
80 *fp; /* Current file */
81
82
83 if (argc < 4)
84 {
85 puts("Usage: makedocset directory revision *.tokens");
86 return (1);
87 }
88
89 /*
90 * Index the help documents...
91 */
92
93 snprintf(path, sizeof(path), "%s/Contents/Resources/Documentation", argv[1]);
94 if ((hi = helpLoadIndex(NULL, path)) == NULL)
95 {
96 fputs("makedocset: Unable to index help files!\n", stderr);
97 return (1);
98 }
99
100 snprintf(path, sizeof(path), "%s/Contents/Resources/Documentation/index.html",
101 argv[1]);
102 write_index(path, hi);
103
104 snprintf(path, sizeof(path), "%s/Contents/Resources/Nodes.xml", argv[1]);
105 write_nodes(path, hi);
106
107 /*
108 * Write the Info.plist file...
109 */
110
111 snprintf(path, sizeof(path), "%s/Contents/Info.plist", argv[1]);
112 write_info(path, argv[2]);
113
114 /*
115 * Merge the Tokens.xml files...
116 */
117
118 snprintf(path, sizeof(path), "%s/Contents/Resources/Tokens.xml", argv[1]);
119 if ((tokens = cupsFileOpen(path, "w")) == NULL)
120 {
121 fprintf(stderr, "makedocset: Unable to create \"%s\": %s\n", path,
122 strerror(errno));
123 return (1);
124 }
125
126 cupsFilePuts(tokens, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
127 cupsFilePuts(tokens, "<Tokens version=\"1.0\">\n");
128
129 for (i = 3; i < argc; i ++)
130 {
131 if ((fp = cupsFileOpen(argv[i], "r")) == NULL)
132 {
133 fprintf(stderr, "makedocset: Unable to open \"%s\": %s\n", argv[i],
134 strerror(errno));
135 return (1);
136 }
137
138 if (!cupsFileGets(fp, line, sizeof(line)) || strncmp(line, "<?xml ", 6) ||
139 !cupsFileGets(fp, line, sizeof(line)) || strncmp(line, "<Tokens ", 8))
140 {
141 fprintf(stderr, "makedocset: Bad Tokens.xml file \"%s\"!\n", argv[i]);
142 return (1);
143 }
144
145 while (cupsFileGets(fp, line, sizeof(line)))
146 {
147 if (strcmp(line, "</Tokens>"))
148 cupsFilePrintf(tokens, "%s\n", line);
149 }
150
151 cupsFileClose(fp);
152 }
153
154 cupsFilePuts(tokens, "</Tokens>\n");
155
156 cupsFileClose(tokens);
157
158 /*
159 * Return with no errors...
160 */
161
162 return (0);
163}
164
165
166/*
167 * 'compare_html()' - Compare the titles of two HTML files.
168 */
169
170static int /* O - Result of comparison */
171compare_html(_cups_html_t *a, /* I - First file */
172 _cups_html_t *b) /* I - Second file */
173{
88f9aafc 174 return (_cups_strcasecmp(a->title, b->title));
f11a948a
MS
175}
176
177
178/*
179 * 'compare_sections()' - Compare the names of two help sections.
180 */
181
182static int /* O - Result of comparison */
183compare_sections(_cups_section_t *a, /* I - First section */
184 _cups_section_t *b) /* I - Second section */
185{
88f9aafc 186 return (_cups_strcasecmp(a->name, b->name));
f11a948a
MS
187}
188
189
190/*
191 * 'compare_sections_files()' - Compare the number of files and section names.
192 */
193
194static int /* O - Result of comparison */
195compare_sections_files(
196 _cups_section_t *a, /* I - First section */
197 _cups_section_t *b) /* I - Second section */
198{
199 int ret = cupsArrayCount(b->files) - cupsArrayCount(a->files);
200
201 if (ret)
202 return (ret);
203 else
88f9aafc 204 return (_cups_strcasecmp(a->name, b->name));
f11a948a
MS
205}
206
207
208/*
209 * 'write_index()' - Write an index file for the CUPS help.
210 */
211
212static void
213write_index(const char *path, /* I - File to write */
214 help_index_t *hi) /* I - Index of files */
215{
216 cups_file_t *fp; /* Output file */
217 help_node_t *node; /* Current help node */
218 _cups_section_t *section, /* Current section */
219 key; /* Section search key */
220 _cups_html_t *html; /* Current HTML file */
221 cups_array_t *sections, /* Sections in index */
222 *sections_files,/* Sections sorted by size */
223 *columns[3]; /* Columns in final HTML file */
224 int column, /* Current column */
225 lines[3], /* Number of lines in each column */
226 min_column, /* Smallest column */
227 min_lines; /* Smallest number of lines */
228
229
230 /*
231 * Build an array of sections and their files.
232 */
233
234 sections = cupsArrayNew((cups_array_func_t)compare_sections, NULL);
235
236 for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
237 node;
238 node = (help_node_t *)cupsArrayNext(hi->nodes))
239 {
240 if (node->anchor)
241 continue;
242
243 key.name = node->section ? node->section : "Miscellaneous";
244 if ((section = (_cups_section_t *)cupsArrayFind(sections, &key)) == NULL)
245 {
246 section = (_cups_section_t *)calloc(1, sizeof(_cups_section_t));
247 section->name = key.name;
248 section->files = cupsArrayNew((cups_array_func_t)compare_html, NULL);
249
250 cupsArrayAdd(sections, section);
251 }
252
253 html = (_cups_html_t *)calloc(1, sizeof(_cups_html_t));
254 html->path = node->filename;
255 html->title = node->text;
256
257 cupsArrayAdd(section->files, html);
258 }
259
260 /*
261 * Build a sorted list of sections based on the number of files in each section
262 * and the section name...
263 */
264
265 sections_files = cupsArrayNew((cups_array_func_t)compare_sections_files,
266 NULL);
267 for (section = (_cups_section_t *)cupsArrayFirst(sections);
268 section;
269 section = (_cups_section_t *)cupsArrayNext(sections))
270 cupsArrayAdd(sections_files, section);
271
272 /*
273 * Then build three columns to hold everything, trying to balance the number of
274 * lines in each column...
275 */
276
277 for (column = 0; column < 3; column ++)
278 {
279 columns[column] = cupsArrayNew((cups_array_func_t)compare_sections, NULL);
280 lines[column] = 0;
281 }
282
283 for (section = (_cups_section_t *)cupsArrayFirst(sections_files);
284 section;
285 section = (_cups_section_t *)cupsArrayNext(sections_files))
286 {
287 for (min_column = 0, min_lines = lines[0], column = 1;
288 column < 3;
289 column ++)
290 {
291 if (lines[column] < min_lines)
292 {
293 min_column = column;
294 min_lines = lines[column];
295 }
296 }
297
298 cupsArrayAdd(columns[min_column], section);
299 lines[min_column] += cupsArrayCount(section->files) + 2;
300 }
301
302 /*
303 * Write the HTML file...
304 */
305
306 if ((fp = cupsFileOpen(path, "w")) == NULL)
307 {
308 fprintf(stderr, "makedocset: Unable to create %s: %s\n", path,
309 strerror(errno));
310 exit(1);
311 }
312
313 cupsFilePuts(fp, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 "
314 "Transitional//EN\" "
315 "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
316 "<html>\n"
317 "<head>\n"
318 "<title>CUPS Documentation</title>\n"
319 "<link rel='stylesheet' type='text/css' "
178cb736 320 "href='cups-printable.css'>\n"
f11a948a
MS
321 "</head>\n"
322 "<body>\n"
178cb736 323 "<h1 class='title'>CUPS Documentation</h1>\n"
f11a948a
MS
324 "<table width='100%' summary=''>\n"
325 "<tr>\n");
326
327 for (column = 0; column < 3; column ++)
328 {
329 if (column)
330 cupsFilePuts(fp, "<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>\n");
331
332 cupsFilePuts(fp, "<td valign='top' width='33%'>");
333 for (section = (_cups_section_t *)cupsArrayFirst(columns[column]);
334 section;
335 section = (_cups_section_t *)cupsArrayNext(columns[column]))
336 {
337 cupsFilePrintf(fp, "<h2 class='title'>%s</h2>\n", section->name);
338 for (html = (_cups_html_t *)cupsArrayFirst(section->files);
339 html;
340 html = (_cups_html_t *)cupsArrayNext(section->files))
341 cupsFilePrintf(fp, "<p class='compact'><a href='%s'>%s</a></p>\n",
342 html->path, html->title);
343 }
344 cupsFilePuts(fp, "</td>\n");
345 }
346 cupsFilePuts(fp, "</tr>\n"
347 "</table>\n"
348 "</body>\n"
349 "</html>\n");
350 cupsFileClose(fp);
351}
352
353
354/*
355 * 'write_info()' - Write the Info.plist file.
356 */
357
358static void
359write_info(const char *path, /* I - File to write */
85b5d1df 360 const char *revision) /* I - Subversion revision number */
f11a948a
MS
361{
362 cups_file_t *fp; /* File */
363
364
365 if ((fp = cupsFileOpen(path, "w")) == NULL)
366 {
367 fprintf(stderr, "makedocset: Unable to create %s: %s\n", path,
368 strerror(errno));
369 exit(1);
370 }
371
372 cupsFilePrintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
373 "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
374 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
375 "<plist version=\"1.0\">\n"
376 "<dict>\n"
377 "\t<key>CFBundleIdentifier</key>\n"
378 "\t<string>org.cups.docset</string>\n"
379 "\t<key>CFBundleName</key>\n"
380 "\t<string>CUPS Documentation</string>\n"
381 "\t<key>CFBundleVersion</key>\n"
85b5d1df
MS
382 "\t<string>%d.%d.%s</string>\n"
383 "\t<key>CFBundleShortVersionString</key>\n"
384 "\t<string>%d.%d.%d</string>\n"
f11a948a
MS
385 "\t<key>DocSetFeedName</key>\n"
386 "\t<string>cups.org</string>\n"
387 "\t<key>DocSetFeedURL</key>\n"
85b5d1df 388 "\t<string>http://www.cups.org/org.cups.docset.atom"
f11a948a 389 "</string>\n"
85b5d1df
MS
390 "\t<key>DocSetPublisherIdentifier</key>\n"
391 "\t<string>org.cups</string>\n"
392 "\t<key>DocSetPublisherName</key>\n"
393 "\t<string>CUPS</string>\n"
f11a948a 394 "</dict>\n"
85b5d1df
MS
395 "</plist>\n",
396 CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR, revision,
397 CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR, CUPS_VERSION_PATCH);
f11a948a
MS
398
399 cupsFileClose(fp);
400}
401
402
403/*
404 * 'write_nodes()' - Write the Nodes.xml file.
405 */
406
407static void
408write_nodes(const char *path, /* I - File to write */
409 help_index_t *hi) /* I - Index of files */
410{
411 cups_file_t *fp; /* Output file */
412 int id; /* Current node ID */
413 help_node_t *node; /* Current help node */
414 int subnodes; /* Currently in Subnodes for file? */
415 int needclose; /* Need to close the current node? */
416
417
418 if ((fp = cupsFileOpen(path, "w")) == NULL)
419 {
420 fprintf(stderr, "makedocset: Unable to create %s: %s\n", path,
421 strerror(errno));
422 exit(1);
423 }
424
425 cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
426 "<DocSetNodes version=\"1.0\">\n"
427 "<TOC>\n"
428 "<Node id=\"0\">\n"
429 "<Name>CUPS Documentation</Name>\n"
430 "<Path>Documentation/index.html</Path>\n"
431 "</Node>\n");
432
433 for (node = (help_node_t *)cupsArrayFirst(hi->nodes), id = 1, subnodes = 0,
434 needclose = 0;
435 node;
436 node = (help_node_t *)cupsArrayNext(hi->nodes), id ++)
437 {
438 if (node->anchor)
439 {
440 if (!subnodes)
441 {
442 cupsFilePuts(fp, "<Subnodes>\n");
443 subnodes = 1;
444 }
88f9aafc 445
f11a948a
MS
446 cupsFilePrintf(fp, "<Node id=\"%d\">\n"
447 "<Path>Documentation/%s</Path>\n"
448 "<Anchor>%s</Anchor>\n"
449 "<Name>%s</Name>\n"
450 "</Node>\n", id, node->filename, node->anchor,
451 node->text);
452 }
453 else
454 {
455 if (subnodes)
456 {
457 cupsFilePuts(fp, "</Subnodes>\n");
458 subnodes = 0;
459 }
460
461 if (needclose)
462 cupsFilePuts(fp, "</Node>\n");
463
464 cupsFilePrintf(fp, "<Node id=\"%d\">\n"
465 "<Path>Documentation/%s</Path>\n"
466 "<Name>%s</Name>\n", id, node->filename, node->text);
467 needclose = 1;
468 }
469 }
470
471 if (subnodes)
472 cupsFilePuts(fp, "</Subnodes>\n");
473
474 if (needclose)
475 cupsFilePuts(fp, "</Node>\n");
476
477 cupsFilePuts(fp, "</TOC>\n"
478 "</DocSetNodes>\n");
479
480 cupsFileClose(fp);
481}
482
483
484/*
61515785 485 * End of "$Id: makedocset.c 3833 2012-05-23 22:51:18Z msweet $".
f11a948a 486 */