4 * IANA XML registration to test file generator for CUPS.
6 * Copyright 2011-2012 by Apple Inc.
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
14 * This file is subject to the Apple OS-Developed Software exception.
18 * ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] >file.test
20 * If not specified, loads the XML registrations from:
22 * http://www.iana.org/assignments/ipp-registrations/ipp-registrations.xml
24 * "Standard" is of the form "rfcNNNN" or "pwgNNNN.N".
28 * main() - Process command-line arguments.
29 * compare_reg() - Compare two registrations.
30 * load_xml() - Load the XML registration file or URL.
31 * match_xref() - Compare the xref against the named standard.
32 * new_reg() - Create a new registration record.
33 * usage() - Show usage message.
34 * write_expect() - Write an EXPECT test for an attribute.
39 #include <cups/cups.h>
49 typedef struct _cups_reg_s
/**** Registration data ****/
51 char *name
, /* Attribute name */
52 *member
, /* Member attribute name */
53 *sub_member
, /* Sub-member attribute name */
54 *syntax
; /* Attribute syntax */
62 static int compare_reg(_cups_reg_t
*a
, _cups_reg_t
*b
);
63 static mxml_node_t
*load_xml(const char *reg_file
);
64 static int match_xref(mxml_node_t
*xref
, const char *standard
);
65 static _cups_reg_t
*new_reg(mxml_node_t
*name
, mxml_node_t
*member
,
66 mxml_node_t
*sub_member
, mxml_node_t
*syntax
);
67 static int usage(void);
68 static void write_expect(_cups_reg_t
*reg
, ipp_tag_t group
);
72 * 'main()' - Process command-line arguments.
76 main(int argc
, /* I - Number of command-line args */
77 char *argv
[]) /* I - Command-line arguments */
79 int i
; /* Looping var */
80 const char *reg_file
= NULL
, /* Registration file/URL to use */
81 *reg_standard
= NULL
; /* Which standard to extract */
82 mxml_node_t
*reg_xml
, /* Registration XML data */
83 *reg_2
, /* ipp-registrations-2 */
84 *reg_record
, /* <record> */
85 *reg_collection
, /* <collection> */
86 *reg_name
, /* <name> */
87 *reg_member
, /* <member_attribute> */
88 *reg_sub_member
, /* <sub-member_attribute> */
89 *reg_syntax
, /* <syntax> */
90 *reg_xref
; /* <xref> */
91 cups_array_t
*attrs
; /* Attribute registrations */
92 _cups_reg_t
*current
; /* Current attribute registration */
93 ipp_tag_t group
= IPP_TAG_ZERO
, /* Which attributes to test */
94 reg_group
; /* Group for registration */
98 * Parse command-line...
101 for (i
= 1; i
< argc
; i
++)
103 if (!strcmp(argv
[i
], "--job") && group
== IPP_TAG_ZERO
)
105 else if (!strcmp(argv
[i
], "--ref"))
111 reg_standard
= argv
[i
];
113 else if (!strcmp(argv
[i
], "--printer") && group
== IPP_TAG_ZERO
)
114 group
= IPP_TAG_PRINTER
;
115 else if (argv
[i
][0] == '-' || reg_file
)
121 if (group
== IPP_TAG_ZERO
)
125 * Read registrations...
129 reg_file
= "http://www.iana.org/assignments/ipp-registrations/"
130 "ipp-registrations.xml";
132 if ((reg_xml
= load_xml(reg_file
)) == NULL
)
136 * Scan registrations for attributes...
139 if ((reg_2
= mxmlFindElement(reg_xml
, reg_xml
, "registry", "id",
140 "ipp-registrations-2",
141 MXML_DESCEND
)) == NULL
)
143 fprintf(stderr
, "xmltotest: No IPP attribute registrations in \"%s\".\n",
148 attrs
= cupsArrayNew((cups_array_func_t
)compare_reg
, NULL
);
150 for (reg_record
= mxmlFindElement(reg_2
, reg_2
, "record", NULL
, NULL
,
153 reg_record
= mxmlFindElement(reg_record
, reg_2
, "record", NULL
, NULL
,
157 * Get the values from the current record...
160 reg_collection
= mxmlFindElement(reg_record
, reg_record
, "collection",
161 NULL
, NULL
, MXML_DESCEND
);
162 reg_name
= mxmlFindElement(reg_record
, reg_record
, "name", NULL
, NULL
,
164 reg_member
= mxmlFindElement(reg_record
, reg_record
, "member_attribute",
165 NULL
, NULL
, MXML_DESCEND
);
166 reg_sub_member
= mxmlFindElement(reg_record
, reg_record
,
167 "sub-member_attribute", NULL
, NULL
,
169 reg_syntax
= mxmlFindElement(reg_record
, reg_record
, "syntax", NULL
,
171 reg_xref
= mxmlFindElement(reg_record
, reg_record
, "xref", NULL
, NULL
,
174 if (!reg_collection
|| !reg_name
|| !reg_syntax
|| !reg_xref
)
178 * Filter based on group and standard...
181 if (!strcmp(reg_collection
->child
->value
.opaque
, "Printer Description"))
182 reg_group
= IPP_TAG_PRINTER
;
183 else if (!strcmp(reg_collection
->child
->value
.opaque
, "Job Description"))
184 reg_group
= IPP_TAG_JOB
;
185 else if (!strcmp(reg_collection
->child
->value
.opaque
, "Job Template"))
187 if (strstr(reg_name
->child
->value
.opaque
, "-default") ||
188 strstr(reg_name
->child
->value
.opaque
, "-supported"))
189 reg_group
= IPP_TAG_PRINTER
;
191 reg_group
= IPP_TAG_JOB
;
194 reg_group
= IPP_TAG_ZERO
;
196 if (reg_group
!= group
)
199 if (reg_standard
&& !match_xref(reg_xref
, reg_standard
))
203 * Add the record to the array...
206 if ((current
= new_reg(reg_name
, reg_member
, reg_sub_member
,
207 reg_syntax
)) != NULL
)
208 cupsArrayAdd(attrs
, current
);
212 * Write out a test for all of the selected attributes...
217 if (group
== IPP_TAG_PRINTER
)
219 puts("\tOPERATION Get-Printer-Attributes");
220 puts("\tGROUP operation-attributes-tag");
221 puts("\tATTR charset attributes-charset utf-8");
222 puts("\tATTR naturalLanguage attributes-natural-language en");
223 puts("\tATTR uri printer-uri $uri");
224 puts("\tATTR name requesting-user-name $user");
225 puts("\tATTR keyword requested-attributes all,media-col-database");
227 puts("\tSTATUS successful-ok");
228 puts("\tSTATUS successful-ok-ignored-or-substituted-attributes");
233 puts("\tOPERATION Get-Job-Attributes");
234 puts("\tGROUP operation-attributes-tag");
235 puts("\tATTR charset attributes-charset utf-8");
236 puts("\tATTR naturalLanguage attributes-natural-language en");
237 puts("\tATTR uri printer-uri $uri");
238 puts("\tATTR integer job-id $job-id");
239 puts("\tATTR name requesting-user-name $user");
241 puts("\tSTATUS successful-ok");
245 for (current
= cupsArrayFirst(attrs
);
247 current
= cupsArrayNext(attrs
))
248 write_expect(current
, group
);
257 * 'compare_reg()' - Compare two registrations.
260 static int /* O - Result of comparison */
261 compare_reg(_cups_reg_t
*a
, /* I - First registration */
262 _cups_reg_t
*b
) /* I - Second registration */
264 int retval
; /* Return value */
267 if ((retval
= strcmp(a
->name
, b
->name
)) != 0)
270 if (a
->member
&& b
->member
)
271 retval
= strcmp(a
->member
, b
->member
);
280 if (a
->sub_member
&& b
->sub_member
)
281 retval
= strcmp(a
->sub_member
, b
->sub_member
);
282 else if (a
->sub_member
)
284 else if (b
->sub_member
)
292 * 'load_xml()' - Load the XML registration file or URL.
295 static mxml_node_t
* /* O - XML file or NULL */
296 load_xml(const char *reg_file
) /* I - Filename or URL */
298 mxml_node_t
*xml
; /* XML file */
299 char scheme
[256], /* Scheme */
300 userpass
[256], /* Username and password */
301 hostname
[256], /* Hostname */
302 resource
[1024], /* Resource path */
303 filename
[1024]; /* Temporary file */
304 int port
, /* Port number */
305 fd
; /* File descriptor */
308 if (httpSeparateURI(HTTP_URI_CODING_ALL
, reg_file
, scheme
, sizeof(scheme
),
309 userpass
, sizeof(userpass
), hostname
, sizeof(hostname
),
310 &port
, resource
, sizeof(resource
)) < HTTP_URI_OK
)
312 fprintf(stderr
, "xmltotest: Bad URI or filename \"%s\".\n", reg_file
);
316 if (!strcmp(scheme
, "file"))
322 if ((fd
= open(resource
, O_RDONLY
)) < 0)
324 fprintf(stderr
, "xmltotest: Unable to open \"%s\": %s\n", resource
,
331 else if (strcmp(scheme
, "http") && strcmp(scheme
, "https"))
333 fprintf(stderr
, "xmltotest: Unsupported URI scheme \"%s\".\n", scheme
);
338 http_t
*http
; /* HTTP connection */
339 http_encryption_t encryption
; /* Encryption to use */
340 http_status_t status
; /* Status of HTTP GET */
342 if (!strcmp(scheme
, "https") || port
== 443)
343 encryption
= HTTP_ENCRYPT_ALWAYS
;
345 encryption
= HTTP_ENCRYPT_IF_REQUESTED
;
347 if ((http
= httpConnectEncrypt(hostname
, port
, encryption
)) == NULL
)
349 fprintf(stderr
, "xmltotest: Unable to connect to \"%s\": %s\n", hostname
,
350 cupsLastErrorString());
354 if ((fd
= cupsTempFd(filename
, sizeof(filename
))) < 0)
356 fprintf(stderr
, "xmltotest: Unable to create temporary file: %s\n",
362 status
= cupsGetFd(http
, resource
, fd
);
365 if (status
!= HTTP_OK
)
367 fprintf(stderr
, "mxmltotest: Unable to get \"%s\": %d\n", reg_file
,
374 lseek(fd
, 0, SEEK_SET
);
378 * Load the XML file...
381 xml
= mxmlLoadFd(NULL
, fd
, MXML_OPAQUE_CALLBACK
);
393 * 'match_xref()' - Compare the xref against the named standard.
396 static int /* O - 1 if match, 0 if not */
397 match_xref(mxml_node_t
*xref
, /* I - <xref> node */
398 const char *standard
) /* I - Name of standard */
400 const char *data
; /* "data" attribute */
401 char s
[256]; /* String to look for */
404 if ((data
= mxmlElementGetAttr(xref
, "data")) == NULL
)
407 if (!strcmp(data
, standard
))
410 if (!strncmp(standard
, "pwg", 3))
412 snprintf(s
, sizeof(s
), "-%s.pdf", standard
+ 3);
413 return (strstr(data
, s
) != NULL
);
421 * 'new_reg()' - Create a new registration record.
424 static _cups_reg_t
* /* O - New record */
425 new_reg(mxml_node_t
*name
, /* I - Attribute name */
426 mxml_node_t
*member
, /* I - Member attribute, if any */
427 mxml_node_t
*sub_member
, /* I - Sub-member attribute, if any */
428 mxml_node_t
*syntax
) /* I - Syntax */
430 _cups_reg_t
*reg
; /* New record */
433 if ((reg
= calloc(1, sizeof(_cups_reg_t
))) != NULL
)
435 reg
->name
= name
->child
->value
.opaque
;
436 reg
->syntax
= syntax
->child
->value
.opaque
;
439 reg
->member
= member
->child
->value
.opaque
;
442 reg
->sub_member
= sub_member
->child
->value
.opaque
;
450 * 'usage()' - Show usage message.
453 static int /* O - Exit status */
456 puts("Usage ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] "
463 * 'write_expect()' - Write an EXPECT test for an attribute.
467 write_expect(_cups_reg_t
*reg
, /* I - Registration information */
468 ipp_tag_t group
) /* I - Attribute group tag */
470 const char *syntax
; /* Pointer into syntax string */
471 int single
= 1, /* Single valued? */
472 skip
= 0; /* Skip characters? */
475 printf("\tEXPECT ?%s OF-TYPE ", reg
->name
);
477 syntax
= reg
->syntax
;
481 if (!strncmp(syntax
, "1setOf", 6))
486 while (isspace(*syntax
& 255))
492 else if (!strncmp(syntax
, "type1", 5) || !strncmp(syntax
, "type2", 5) ||
493 !strncmp(syntax
, "type3", 5))
495 else if (*syntax
== '(')
500 else if (*syntax
== ')')
505 else if (!skip
&& (*syntax
== '|' || isalpha(*syntax
& 255)))
512 printf(" IN-GROUP %s COUNT 1\n", ippTagString(group
));
514 printf(" IN-GROUP %s\n", ippTagString(group
));
518 #else /* !HAVE_MXML */
524 #endif /* HAVE_MXML */