diff options
author | Didier Raboud <odyx@debian.org> | 2012-10-25 21:07:57 +0200 |
---|---|---|
committer | Didier Raboud <odyx@debian.org> | 2012-10-25 21:07:57 +0200 |
commit | 81ab83f382660bc7980ae954725c4ebf28764b03 (patch) | |
tree | 523268f698a63a8fd44f3491d94d140266b2403b /test/xmltotest.c | |
parent | a75966e33dbc3e3e096338fd332f515cb313b58a (diff) | |
download | cups-upstream/1.6.0.tar.gz |
Imported Upstream version 1.6.0upstream/1.6.0
Diffstat (limited to 'test/xmltotest.c')
-rw-r--r-- | test/xmltotest.c | 529 |
1 files changed, 529 insertions, 0 deletions
diff --git a/test/xmltotest.c b/test/xmltotest.c new file mode 100644 index 00000000..efe04553 --- /dev/null +++ b/test/xmltotest.c @@ -0,0 +1,529 @@ +/* + * "$Id: xmltotest.c 10192 2012-01-20 21:49:02Z mike $" + * + * IANA XML registration to test file generator for CUPS. + * + * Copyright 2011-2012 by Apple Inc. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Usage: + * + * ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] >file.test + * + * If not specified, loads the XML registrations from: + * + * http://www.iana.org/assignments/ipp-registrations/ipp-registrations.xml + * + * "Standard" is of the form "rfcNNNN" or "pwgNNNN.N". + * + * Contents: + * + * main() - Process command-line arguments. + * compare_reg() - Compare two registrations. + * load_xml() - Load the XML registration file or URL. + * match_xref() - Compare the xref against the named standard. + * new_reg() - Create a new registration record. + * usage() - Show usage message. + * write_expect() - Write an EXPECT test for an attribute. + */ + + +#include <config.h> +#include <cups/cups.h> +#include <unistd.h> +#include <fcntl.h> + +#ifdef HAVE_MXML_H +# include <mxml.h> +/* + * Local types... + */ + +typedef struct _cups_reg_s /**** Registration data ****/ +{ + char *name, /* Attribute name */ + *member, /* Member attribute name */ + *sub_member, /* Sub-member attribute name */ + *syntax; /* Attribute syntax */ +} _cups_reg_t; + + +/* + * Local functions... + */ + +static int compare_reg(_cups_reg_t *a, _cups_reg_t *b); +static mxml_node_t *load_xml(const char *reg_file); +static int match_xref(mxml_node_t *xref, const char *standard); +static _cups_reg_t *new_reg(mxml_node_t *name, mxml_node_t *member, + mxml_node_t *sub_member, mxml_node_t *syntax); +static int usage(void); +static void write_expect(_cups_reg_t *reg, ipp_tag_t group); + + +/* + * 'main()' - Process command-line arguments. + */ + +int +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + const char *reg_file = NULL, /* Registration file/URL to use */ + *reg_standard = NULL; /* Which standard to extract */ + mxml_node_t *reg_xml, /* Registration XML data */ + *reg_2, /* ipp-registrations-2 */ + *reg_record, /* <record> */ + *reg_collection, /* <collection> */ + *reg_name, /* <name> */ + *reg_member, /* <member_attribute> */ + *reg_sub_member, /* <sub-member_attribute> */ + *reg_syntax, /* <syntax> */ + *reg_xref; /* <xref> */ + cups_array_t *attrs; /* Attribute registrations */ + _cups_reg_t *current; /* Current attribute registration */ + ipp_tag_t group = IPP_TAG_ZERO, /* Which attributes to test */ + reg_group; /* Group for registration */ + + + /* + * Parse command-line... + */ + + for (i = 1; i < argc; i ++) + { + if (!strcmp(argv[i], "--job") && group == IPP_TAG_ZERO) + group = IPP_TAG_JOB; + else if (!strcmp(argv[i], "--ref")) + { + i ++; + if (i >= argc) + return (usage()); + + reg_standard = argv[i]; + } + else if (!strcmp(argv[i], "--printer") && group == IPP_TAG_ZERO) + group = IPP_TAG_PRINTER; + else if (argv[i][0] == '-' || reg_file) + return (usage()); + else + reg_file = argv[i]; + } + + if (group == IPP_TAG_ZERO) + return (usage()); + + /* + * Read registrations... + */ + + if (!reg_file) + reg_file = "http://www.iana.org/assignments/ipp-registrations/" + "ipp-registrations.xml"; + + if ((reg_xml = load_xml(reg_file)) == NULL) + return (1); + + /* + * Scan registrations for attributes... + */ + + if ((reg_2 = mxmlFindElement(reg_xml, reg_xml, "registry", "id", + "ipp-registrations-2", + MXML_DESCEND)) == NULL) + { + fprintf(stderr, "xmltotest: No IPP attribute registrations in \"%s\".\n", + reg_file); + return (1); + } + + attrs = cupsArrayNew((cups_array_func_t)compare_reg, NULL); + + for (reg_record = mxmlFindElement(reg_2, reg_2, "record", NULL, NULL, + MXML_DESCEND); + reg_record; + reg_record = mxmlFindElement(reg_record, reg_2, "record", NULL, NULL, + MXML_NO_DESCEND)) + { + /* + * Get the values from the current record... + */ + + reg_collection = mxmlFindElement(reg_record, reg_record, "collection", + NULL, NULL, MXML_DESCEND); + reg_name = mxmlFindElement(reg_record, reg_record, "name", NULL, NULL, + MXML_DESCEND); + reg_member = mxmlFindElement(reg_record, reg_record, "member_attribute", + NULL, NULL, MXML_DESCEND); + reg_sub_member = mxmlFindElement(reg_record, reg_record, + "sub-member_attribute", NULL, NULL, + MXML_DESCEND); + reg_syntax = mxmlFindElement(reg_record, reg_record, "syntax", NULL, + NULL, MXML_DESCEND); + reg_xref = mxmlFindElement(reg_record, reg_record, "xref", NULL, NULL, + MXML_DESCEND); + + if (!reg_collection || !reg_name || !reg_syntax || !reg_xref) + continue; + + /* + * Filter based on group and standard... + */ + + if (!strcmp(reg_collection->child->value.opaque, "Printer Description")) + reg_group = IPP_TAG_PRINTER; + else if (!strcmp(reg_collection->child->value.opaque, "Job Description")) + reg_group = IPP_TAG_JOB; + else if (!strcmp(reg_collection->child->value.opaque, "Job Template")) + { + if (strstr(reg_name->child->value.opaque, "-default") || + strstr(reg_name->child->value.opaque, "-supported")) + reg_group = IPP_TAG_PRINTER; + else + reg_group = IPP_TAG_JOB; + } + else + reg_group = IPP_TAG_ZERO; + + if (reg_group != group) + continue; + + if (reg_standard && !match_xref(reg_xref, reg_standard)) + continue; + + /* + * Add the record to the array... + */ + + if ((current = new_reg(reg_name, reg_member, reg_sub_member, + reg_syntax)) != NULL) + cupsArrayAdd(attrs, current); + } + + /* + * Write out a test for all of the selected attributes... + */ + + puts("{"); + + if (group == IPP_TAG_PRINTER) + { + puts("\tOPERATION Get-Printer-Attributes"); + puts("\tGROUP operation-attributes-tag"); + puts("\tATTR charset attributes-charset utf-8"); + puts("\tATTR naturalLanguage attributes-natural-language en"); + puts("\tATTR uri printer-uri $uri"); + puts("\tATTR name requesting-user-name $user"); + puts("\tATTR keyword requested-attributes all,media-col-database"); + puts(""); + puts("\tSTATUS successful-ok"); + puts("\tSTATUS successful-ok-ignored-or-substituted-attributes"); + puts(""); + } + else + { + puts("\tOPERATION Get-Job-Attributes"); + puts("\tGROUP operation-attributes-tag"); + puts("\tATTR charset attributes-charset utf-8"); + puts("\tATTR naturalLanguage attributes-natural-language en"); + puts("\tATTR uri printer-uri $uri"); + puts("\tATTR integer job-id $job-id"); + puts("\tATTR name requesting-user-name $user"); + puts(""); + puts("\tSTATUS successful-ok"); + puts(""); + } + + for (current = cupsArrayFirst(attrs); + current; + current = cupsArrayNext(attrs)) + write_expect(current, group); + + puts("}"); + + return (0); +} + + +/* + * 'compare_reg()' - Compare two registrations. + */ + +static int /* O - Result of comparison */ +compare_reg(_cups_reg_t *a, /* I - First registration */ + _cups_reg_t *b) /* I - Second registration */ +{ + int retval; /* Return value */ + + + if ((retval = strcmp(a->name, b->name)) != 0) + return (retval); + + if (a->member && b->member) + retval = strcmp(a->member, b->member); + else if (a->member) + retval = 1; + else if (b->member) + retval = -1; + + if (retval) + return (retval); + + if (a->sub_member && b->sub_member) + retval = strcmp(a->sub_member, b->sub_member); + else if (a->sub_member) + retval = 1; + else if (b->sub_member) + retval = -1; + + return (retval); +} + + +/* + * 'load_xml()' - Load the XML registration file or URL. + */ + +static mxml_node_t * /* O - XML file or NULL */ +load_xml(const char *reg_file) /* I - Filename or URL */ +{ + mxml_node_t *xml; /* XML file */ + char scheme[256], /* Scheme */ + userpass[256], /* Username and password */ + hostname[256], /* Hostname */ + resource[1024], /* Resource path */ + filename[1024]; /* Temporary file */ + int port, /* Port number */ + fd; /* File descriptor */ + + + if (httpSeparateURI(HTTP_URI_CODING_ALL, reg_file, scheme, sizeof(scheme), + userpass, sizeof(userpass), hostname, sizeof(hostname), + &port, resource, sizeof(resource)) < HTTP_URI_OK) + { + fprintf(stderr, "xmltotest: Bad URI or filename \"%s\".\n", reg_file); + return (NULL); + } + + if (!strcmp(scheme, "file")) + { + /* + * Local file... + */ + + if ((fd = open(resource, O_RDONLY)) < 0) + { + fprintf(stderr, "xmltotest: Unable to open \"%s\": %s\n", resource, + strerror(errno)); + return (NULL); + } + + filename[0] = '\0'; + } + else if (strcmp(scheme, "http") && strcmp(scheme, "https")) + { + fprintf(stderr, "xmltotest: Unsupported URI scheme \"%s\".\n", scheme); + return (NULL); + } + else + { + http_t *http; /* HTTP connection */ + http_encryption_t encryption; /* Encryption to use */ + http_status_t status; /* Status of HTTP GET */ + + if (!strcmp(scheme, "https") || port == 443) + encryption = HTTP_ENCRYPT_ALWAYS; + else + encryption = HTTP_ENCRYPT_IF_REQUESTED; + + if ((http = httpConnectEncrypt(hostname, port, encryption)) == NULL) + { + fprintf(stderr, "xmltotest: Unable to connect to \"%s\": %s\n", hostname, + cupsLastErrorString()); + return (NULL); + } + + if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) + { + fprintf(stderr, "xmltotest: Unable to create temporary file: %s\n", + strerror(errno)); + httpClose(http); + return (NULL); + } + + status = cupsGetFd(http, resource, fd); + httpClose(http); + + if (status != HTTP_OK) + { + fprintf(stderr, "mxmltotest: Unable to get \"%s\": %d\n", reg_file, + status); + close(fd); + unlink(filename); + return (NULL); + } + + lseek(fd, 0, SEEK_SET); + } + + /* + * Load the XML file... + */ + + xml = mxmlLoadFd(NULL, fd, MXML_OPAQUE_CALLBACK); + + close(fd); + + if (filename[0]) + unlink(filename); + + return (xml); +} + + +/* + * 'match_xref()' - Compare the xref against the named standard. + */ + +static int /* O - 1 if match, 0 if not */ +match_xref(mxml_node_t *xref, /* I - <xref> node */ + const char *standard) /* I - Name of standard */ +{ + const char *data; /* "data" attribute */ + char s[256]; /* String to look for */ + + + if ((data = mxmlElementGetAttr(xref, "data")) == NULL) + return (1); + + if (!strcmp(data, standard)) + return (1); + + if (!strncmp(standard, "pwg", 3)) + { + snprintf(s, sizeof(s), "-%s.pdf", standard + 3); + return (strstr(data, s) != NULL); + } + else + return (0); +} + + +/* + * 'new_reg()' - Create a new registration record. + */ + +static _cups_reg_t * /* O - New record */ +new_reg(mxml_node_t *name, /* I - Attribute name */ + mxml_node_t *member, /* I - Member attribute, if any */ + mxml_node_t *sub_member, /* I - Sub-member attribute, if any */ + mxml_node_t *syntax) /* I - Syntax */ +{ + _cups_reg_t *reg; /* New record */ + + + if ((reg = calloc(1, sizeof(_cups_reg_t))) != NULL) + { + reg->name = name->child->value.opaque; + reg->syntax = syntax->child->value.opaque; + + if (member) + reg->member = member->child->value.opaque; + + if (sub_member) + reg->sub_member = sub_member->child->value.opaque; + } + + return (reg); +} + + +/* + * 'usage()' - Show usage message. + */ + +static int /* O - Exit status */ +usage(void) +{ + puts("Usage ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] " + ">file.test"); + return (1); +} + + +/* + * 'write_expect()' - Write an EXPECT test for an attribute. + */ + +static void +write_expect(_cups_reg_t *reg, /* I - Registration information */ + ipp_tag_t group) /* I - Attribute group tag */ +{ + const char *syntax; /* Pointer into syntax string */ + int single = 1, /* Single valued? */ + skip = 0; /* Skip characters? */ + + + printf("\tEXPECT ?%s OF-TYPE ", reg->name); + + syntax = reg->syntax; + + while (*syntax) + { + if (!strncmp(syntax, "1setOf", 6)) + { + single = 0; + syntax += 6; + + while (isspace(*syntax & 255)) + syntax ++; + + if (*syntax == '(') + syntax ++; + } + else if (!strncmp(syntax, "type1", 5) || !strncmp(syntax, "type2", 5) || + !strncmp(syntax, "type3", 5)) + syntax += 5; + else if (*syntax == '(') + { + skip = 1; + syntax ++; + } + else if (*syntax == ')') + { + skip = 0; + syntax ++; + } + else if (!skip && (*syntax == '|' || isalpha(*syntax & 255))) + putchar(*syntax++); + else + syntax ++; + } + + if (single) + printf(" IN-GROUP %s COUNT 1\n", ippTagString(group)); + else + printf(" IN-GROUP %s\n", ippTagString(group)); +} + + +#else /* !HAVE_MXML */ +int +main(void) +{ + return (1); +} +#endif /* HAVE_MXML */ + + +/* + * End of "$Id: xmltotest.c 10192 2012-01-20 21:49:02Z mike $". + */ |