]> git.ipfire.org Git - thirdparty/cups.git/blame - test/xmltotest.c
Remove all of the Subversion keywords from various source files.
[thirdparty/cups.git] / test / xmltotest.c
CommitLineData
9b66acc5 1/*
503b54c9 2 * IANA XML registration to test file generator for CUPS.
9b66acc5 3 *
503b54c9 4 * Copyright 2011-2012 by Apple Inc.
9b66acc5 5 *
503b54c9
MS
6 * These coded instructions, statements, and computer programs are the
7 * property of Apple Inc. and are protected by Federal copyright
8 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
9 * which should have been included with this file. If this file is
10 * file is missing or damaged, see the license at "http://www.cups.org/".
9b66acc5 11 *
503b54c9 12 * This file is subject to the Apple OS-Developed Software exception.
9b66acc5
MS
13 *
14 * Usage:
15 *
16 * ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] >file.test
17 *
503b54c9 18 * If not specified, loads the XML registrations from:
9b66acc5 19 *
503b54c9 20 * http://www.iana.org/assignments/ipp-registrations/ipp-registrations.xml
9b66acc5 21 *
503b54c9 22 * "Standard" is of the form "rfcNNNN" or "pwgNNNN.N".
9b66acc5
MS
23 */
24
12f89d24
MS
25
26#include <config.h>
9b66acc5
MS
27#include <cups/cups.h>
28#include <unistd.h>
29#include <fcntl.h>
30
12f89d24
MS
31#ifdef HAVE_MXML_H
32# include <mxml.h>
9b66acc5
MS
33/*
34 * Local types...
35 */
36
37typedef struct _cups_reg_s /**** Registration data ****/
38{
39 char *name, /* Attribute name */
40 *member, /* Member attribute name */
41 *sub_member, /* Sub-member attribute name */
42 *syntax; /* Attribute syntax */
43} _cups_reg_t;
44
45
46/*
47 * Local functions...
48 */
49
50static int compare_reg(_cups_reg_t *a, _cups_reg_t *b);
51static mxml_node_t *load_xml(const char *reg_file);
52static int match_xref(mxml_node_t *xref, const char *standard);
53static _cups_reg_t *new_reg(mxml_node_t *name, mxml_node_t *member,
54 mxml_node_t *sub_member, mxml_node_t *syntax);
55static int usage(void);
56static void write_expect(_cups_reg_t *reg, ipp_tag_t group);
57
58
59/*
60 * 'main()' - Process command-line arguments.
61 */
62
63int
64main(int argc, /* I - Number of command-line args */
65 char *argv[]) /* I - Command-line arguments */
66{
67 int i; /* Looping var */
68 const char *reg_file = NULL, /* Registration file/URL to use */
69 *reg_standard = NULL; /* Which standard to extract */
70 mxml_node_t *reg_xml, /* Registration XML data */
71 *reg_2, /* ipp-registrations-2 */
72 *reg_record, /* <record> */
73 *reg_collection, /* <collection> */
74 *reg_name, /* <name> */
75 *reg_member, /* <member_attribute> */
76 *reg_sub_member, /* <sub-member_attribute> */
77 *reg_syntax, /* <syntax> */
78 *reg_xref; /* <xref> */
79 cups_array_t *attrs; /* Attribute registrations */
80 _cups_reg_t *current; /* Current attribute registration */
81 ipp_tag_t group = IPP_TAG_ZERO, /* Which attributes to test */
82 reg_group; /* Group for registration */
83
84
85 /*
86 * Parse command-line...
87 */
88
89 for (i = 1; i < argc; i ++)
90 {
91 if (!strcmp(argv[i], "--job") && group == IPP_TAG_ZERO)
92 group = IPP_TAG_JOB;
93 else if (!strcmp(argv[i], "--ref"))
94 {
95 i ++;
96 if (i >= argc)
97 return (usage());
98
99 reg_standard = argv[i];
100 }
101 else if (!strcmp(argv[i], "--printer") && group == IPP_TAG_ZERO)
102 group = IPP_TAG_PRINTER;
103 else if (argv[i][0] == '-' || reg_file)
104 return (usage());
105 else
106 reg_file = argv[i];
107 }
108
109 if (group == IPP_TAG_ZERO)
110 return (usage());
111
112 /*
113 * Read registrations...
114 */
115
116 if (!reg_file)
117 reg_file = "http://www.iana.org/assignments/ipp-registrations/"
118 "ipp-registrations.xml";
119
120 if ((reg_xml = load_xml(reg_file)) == NULL)
121 return (1);
122
123 /*
124 * Scan registrations for attributes...
125 */
126
127 if ((reg_2 = mxmlFindElement(reg_xml, reg_xml, "registry", "id",
128 "ipp-registrations-2",
129 MXML_DESCEND)) == NULL)
130 {
131 fprintf(stderr, "xmltotest: No IPP attribute registrations in \"%s\".\n",
132 reg_file);
133 return (1);
134 }
135
136 attrs = cupsArrayNew((cups_array_func_t)compare_reg, NULL);
137
138 for (reg_record = mxmlFindElement(reg_2, reg_2, "record", NULL, NULL,
139 MXML_DESCEND);
140 reg_record;
141 reg_record = mxmlFindElement(reg_record, reg_2, "record", NULL, NULL,
142 MXML_NO_DESCEND))
143 {
144 /*
145 * Get the values from the current record...
146 */
147
148 reg_collection = mxmlFindElement(reg_record, reg_record, "collection",
149 NULL, NULL, MXML_DESCEND);
150 reg_name = mxmlFindElement(reg_record, reg_record, "name", NULL, NULL,
151 MXML_DESCEND);
152 reg_member = mxmlFindElement(reg_record, reg_record, "member_attribute",
153 NULL, NULL, MXML_DESCEND);
154 reg_sub_member = mxmlFindElement(reg_record, reg_record,
155 "sub-member_attribute", NULL, NULL,
156 MXML_DESCEND);
157 reg_syntax = mxmlFindElement(reg_record, reg_record, "syntax", NULL,
158 NULL, MXML_DESCEND);
159 reg_xref = mxmlFindElement(reg_record, reg_record, "xref", NULL, NULL,
160 MXML_DESCEND);
161
162 if (!reg_collection || !reg_name || !reg_syntax || !reg_xref)
163 continue;
164
165 /*
166 * Filter based on group and standard...
167 */
168
169 if (!strcmp(reg_collection->child->value.opaque, "Printer Description"))
170 reg_group = IPP_TAG_PRINTER;
171 else if (!strcmp(reg_collection->child->value.opaque, "Job Description"))
172 reg_group = IPP_TAG_JOB;
173 else if (!strcmp(reg_collection->child->value.opaque, "Job Template"))
174 {
175 if (strstr(reg_name->child->value.opaque, "-default") ||
176 strstr(reg_name->child->value.opaque, "-supported"))
177 reg_group = IPP_TAG_PRINTER;
178 else
179 reg_group = IPP_TAG_JOB;
180 }
181 else
182 reg_group = IPP_TAG_ZERO;
183
184 if (reg_group != group)
185 continue;
186
187 if (reg_standard && !match_xref(reg_xref, reg_standard))
188 continue;
189
190 /*
191 * Add the record to the array...
192 */
193
194 if ((current = new_reg(reg_name, reg_member, reg_sub_member,
195 reg_syntax)) != NULL)
196 cupsArrayAdd(attrs, current);
197 }
198
199 /*
200 * Write out a test for all of the selected attributes...
201 */
202
203 puts("{");
204
205 if (group == IPP_TAG_PRINTER)
206 {
207 puts("\tOPERATION Get-Printer-Attributes");
208 puts("\tGROUP operation-attributes-tag");
209 puts("\tATTR charset attributes-charset utf-8");
210 puts("\tATTR naturalLanguage attributes-natural-language en");
211 puts("\tATTR uri printer-uri $uri");
212 puts("\tATTR name requesting-user-name $user");
213 puts("\tATTR keyword requested-attributes all,media-col-database");
214 puts("");
215 puts("\tSTATUS successful-ok");
216 puts("\tSTATUS successful-ok-ignored-or-substituted-attributes");
217 puts("");
218 }
219 else
220 {
221 puts("\tOPERATION Get-Job-Attributes");
222 puts("\tGROUP operation-attributes-tag");
223 puts("\tATTR charset attributes-charset utf-8");
224 puts("\tATTR naturalLanguage attributes-natural-language en");
225 puts("\tATTR uri printer-uri $uri");
226 puts("\tATTR integer job-id $job-id");
227 puts("\tATTR name requesting-user-name $user");
228 puts("");
229 puts("\tSTATUS successful-ok");
230 puts("");
231 }
232
233 for (current = cupsArrayFirst(attrs);
234 current;
235 current = cupsArrayNext(attrs))
236 write_expect(current, group);
237
238 puts("}");
239
240 return (0);
241}
242
243
244/*
245 * 'compare_reg()' - Compare two registrations.
246 */
247
248static int /* O - Result of comparison */
249compare_reg(_cups_reg_t *a, /* I - First registration */
250 _cups_reg_t *b) /* I - Second registration */
251{
252 int retval; /* Return value */
253
254
255 if ((retval = strcmp(a->name, b->name)) != 0)
256 return (retval);
257
258 if (a->member && b->member)
259 retval = strcmp(a->member, b->member);
260 else if (a->member)
261 retval = 1;
262 else if (b->member)
263 retval = -1;
264
265 if (retval)
266 return (retval);
267
268 if (a->sub_member && b->sub_member)
269 retval = strcmp(a->sub_member, b->sub_member);
270 else if (a->sub_member)
271 retval = 1;
272 else if (b->sub_member)
273 retval = -1;
274
275 return (retval);
276}
277
278
279/*
280 * 'load_xml()' - Load the XML registration file or URL.
281 */
282
283static mxml_node_t * /* O - XML file or NULL */
284load_xml(const char *reg_file) /* I - Filename or URL */
285{
286 mxml_node_t *xml; /* XML file */
287 char scheme[256], /* Scheme */
288 userpass[256], /* Username and password */
289 hostname[256], /* Hostname */
290 resource[1024], /* Resource path */
291 filename[1024]; /* Temporary file */
292 int port, /* Port number */
293 fd; /* File descriptor */
294
295
296 if (httpSeparateURI(HTTP_URI_CODING_ALL, reg_file, scheme, sizeof(scheme),
297 userpass, sizeof(userpass), hostname, sizeof(hostname),
298 &port, resource, sizeof(resource)) < HTTP_URI_OK)
299 {
300 fprintf(stderr, "xmltotest: Bad URI or filename \"%s\".\n", reg_file);
301 return (NULL);
302 }
303
304 if (!strcmp(scheme, "file"))
305 {
306 /*
307 * Local file...
308 */
309
310 if ((fd = open(resource, O_RDONLY)) < 0)
311 {
312 fprintf(stderr, "xmltotest: Unable to open \"%s\": %s\n", resource,
313 strerror(errno));
314 return (NULL);
315 }
316
317 filename[0] = '\0';
318 }
319 else if (strcmp(scheme, "http") && strcmp(scheme, "https"))
320 {
321 fprintf(stderr, "xmltotest: Unsupported URI scheme \"%s\".\n", scheme);
322 return (NULL);
323 }
324 else
325 {
326 http_t *http; /* HTTP connection */
327 http_encryption_t encryption; /* Encryption to use */
328 http_status_t status; /* Status of HTTP GET */
329
330 if (!strcmp(scheme, "https") || port == 443)
331 encryption = HTTP_ENCRYPT_ALWAYS;
332 else
333 encryption = HTTP_ENCRYPT_IF_REQUESTED;
334
335 if ((http = httpConnectEncrypt(hostname, port, encryption)) == NULL)
336 {
337 fprintf(stderr, "xmltotest: Unable to connect to \"%s\": %s\n", hostname,
338 cupsLastErrorString());
339 return (NULL);
340 }
341
342 if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
343 {
344 fprintf(stderr, "xmltotest: Unable to create temporary file: %s\n",
345 strerror(errno));
346 httpClose(http);
347 return (NULL);
348 }
349
350 status = cupsGetFd(http, resource, fd);
351 httpClose(http);
352
353 if (status != HTTP_OK)
354 {
355 fprintf(stderr, "mxmltotest: Unable to get \"%s\": %d\n", reg_file,
356 status);
357 close(fd);
358 unlink(filename);
359 return (NULL);
360 }
361
362 lseek(fd, 0, SEEK_SET);
363 }
364
365 /*
366 * Load the XML file...
367 */
368
369 xml = mxmlLoadFd(NULL, fd, MXML_OPAQUE_CALLBACK);
370
371 close(fd);
372
373 if (filename[0])
374 unlink(filename);
375
376 return (xml);
377}
378
379
380/*
381 * 'match_xref()' - Compare the xref against the named standard.
382 */
383
384static int /* O - 1 if match, 0 if not */
385match_xref(mxml_node_t *xref, /* I - <xref> node */
386 const char *standard) /* I - Name of standard */
387{
388 const char *data; /* "data" attribute */
389 char s[256]; /* String to look for */
390
391
392 if ((data = mxmlElementGetAttr(xref, "data")) == NULL)
393 return (1);
394
395 if (!strcmp(data, standard))
396 return (1);
397
398 if (!strncmp(standard, "pwg", 3))
399 {
400 snprintf(s, sizeof(s), "-%s.pdf", standard + 3);
401 return (strstr(data, s) != NULL);
402 }
403 else
404 return (0);
405}
406
407
408/*
409 * 'new_reg()' - Create a new registration record.
410 */
411
412static _cups_reg_t * /* O - New record */
413new_reg(mxml_node_t *name, /* I - Attribute name */
414 mxml_node_t *member, /* I - Member attribute, if any */
415 mxml_node_t *sub_member, /* I - Sub-member attribute, if any */
416 mxml_node_t *syntax) /* I - Syntax */
417{
418 _cups_reg_t *reg; /* New record */
419
420
421 if ((reg = calloc(1, sizeof(_cups_reg_t))) != NULL)
422 {
423 reg->name = name->child->value.opaque;
424 reg->syntax = syntax->child->value.opaque;
425
426 if (member)
427 reg->member = member->child->value.opaque;
428
429 if (sub_member)
430 reg->sub_member = sub_member->child->value.opaque;
431 }
432
433 return (reg);
434}
435
436
437/*
438 * 'usage()' - Show usage message.
439 */
440
441static int /* O - Exit status */
442usage(void)
443{
444 puts("Usage ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] "
445 ">file.test");
446 return (1);
447}
448
449
450/*
451 * 'write_expect()' - Write an EXPECT test for an attribute.
452 */
453
454static void
455write_expect(_cups_reg_t *reg, /* I - Registration information */
456 ipp_tag_t group) /* I - Attribute group tag */
457{
458 const char *syntax; /* Pointer into syntax string */
459 int single = 1, /* Single valued? */
460 skip = 0; /* Skip characters? */
461
462
463 printf("\tEXPECT ?%s OF-TYPE ", reg->name);
464
465 syntax = reg->syntax;
466
467 while (*syntax)
468 {
469 if (!strncmp(syntax, "1setOf", 6))
470 {
471 single = 0;
472 syntax += 6;
473
474 while (isspace(*syntax & 255))
475 syntax ++;
476
477 if (*syntax == '(')
478 syntax ++;
479 }
480 else if (!strncmp(syntax, "type1", 5) || !strncmp(syntax, "type2", 5) ||
481 !strncmp(syntax, "type3", 5))
482 syntax += 5;
483 else if (*syntax == '(')
484 {
485 skip = 1;
486 syntax ++;
487 }
488 else if (*syntax == ')')
489 {
490 skip = 0;
491 syntax ++;
492 }
493 else if (!skip && (*syntax == '|' || isalpha(*syntax & 255)))
494 putchar(*syntax++);
495 else
496 syntax ++;
497 }
498
499 if (single)
500 printf(" IN-GROUP %s COUNT 1\n", ippTagString(group));
501 else
502 printf(" IN-GROUP %s\n", ippTagString(group));
503}
504
505
12f89d24
MS
506#else /* !HAVE_MXML */
507int
508main(void)
509{
510 return (1);
511}
512#endif /* HAVE_MXML */