4 * ipptool command for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * main() - Parse options and do tests.
20 * compare_vars() - Compare two variables.
21 * do_tests() - Do tests as specified in the test file.
22 * expand_variables() - Expand variables in a string.
23 * expect_matches() - Return true if the tag matches the specification.
24 * get_collection() - Get a collection value from the current test file.
25 * get_filename() - Get a filename based on the current test file.
26 * get_token() - Get a token from a file.
27 * get_variable() - Get the value of a variable.
28 * iso_date() - Return an ISO 8601 date/time string for the given IPP
30 * password_cb() - Password callback for authenticated tests.
31 * print_attr() - Print an attribute on the screen.
32 * print_col() - Print a collection attribute on the screen.
33 * print_csv() - Print a line of CSV text.
34 * print_fatal_error() - Print a fatal error message.
35 * print_line() - Print a line of formatted or CSV text.
36 * print_test_error() - Print a test error message.
37 * print_xml_header() - Print a standard XML plist header.
38 * print_xml_string() - Print an XML string with escaping.
39 * print_xml_trailer() - Print the XML trailer with success/fail value.
40 * set_variable() - Set a variable value.
41 * sigterm_handler() - Handle SIGINT and SIGTERM.
42 * timeout_cb() - Handle HTTP timeouts.
43 * usage() - Show program usage.
44 * validate_attr() - Determine whether an attribute is valid.
45 * with_value() - Test a WITH-VALUE predicate.
49 * Include necessary headers...
52 #include <cups/cups-private.h>
53 #include <cups/file-private.h>
59 #endif /* !O_BINARY */
66 typedef enum _cups_transfer_e
/**** How to send request data ****/
68 _CUPS_TRANSFER_AUTO
, /* Chunk for files, length for static */
69 _CUPS_TRANSFER_CHUNKED
, /* Chunk always */
70 _CUPS_TRANSFER_LENGTH
/* Length always */
73 typedef enum _cups_output_e
/**** Output mode ****/
75 _CUPS_OUTPUT_QUIET
, /* No output */
76 _CUPS_OUTPUT_TEST
, /* Traditional CUPS test output */
77 _CUPS_OUTPUT_PLIST
, /* XML plist test output */
78 _CUPS_OUTPUT_LIST
, /* Tabular list output */
79 _CUPS_OUTPUT_CSV
/* Comma-separated values output */
82 typedef struct _cups_expect_s
/**** Expected attribute info ****/
84 int optional
, /* Optional attribute? */
85 not_expect
; /* Don't expect attribute? */
86 char *name
, /* Attribute name */
87 *of_type
, /* Type name */
88 *same_count_as
, /* Parallel attribute name */
89 *if_defined
, /* Only required if variable defined */
90 *if_not_defined
, /* Only required if variable is not defined */
91 *with_value
, /* Attribute must include this value */
92 *define_match
, /* Variable to define on match */
93 *define_no_match
, /* Variable to define on no-match */
94 *define_value
; /* Variable to define with value */
95 int with_regex
, /* WITH-VALUE is a regular expression */
96 count
; /* Expected count if > 0 */
97 ipp_tag_t in_group
; /* IN-GROUP value */
100 typedef struct _cups_status_s
/**** Status info ****/
102 ipp_status_t status
; /* Expected status code */
103 char *if_defined
, /* Only if variable is defined */
104 *if_not_defined
; /* Only if variable is not defined */
107 typedef struct _cups_var_s
/**** Variable ****/
109 char *name
, /* Name of variable */
110 *value
; /* Value of variable */
113 typedef struct _cups_vars_s
/**** Set of variables ****/
115 const char *uri
, /* URI for printer */
116 *filename
; /* Filename */
117 char scheme
[64], /* Scheme from URI */
118 userpass
[256], /* Username/password from URI */
119 hostname
[256], /* Hostname from URI */
120 resource
[1024]; /* Resource path from URI */
121 int port
; /* Port number from URI */
122 http_encryption_t encryption
; /* Encryption for connection? */
123 double timeout
; /* Timeout for connection */
124 int family
; /* Address family */
125 cups_array_t
*vars
; /* Array of variables */
133 _cups_transfer_t Transfer
= _CUPS_TRANSFER_AUTO
;
134 /* How to transfer requests */
135 _cups_output_t Output
= _CUPS_OUTPUT_LIST
;
137 int Cancel
= 0, /* Cancel test? */
138 IgnoreErrors
= 0, /* Ignore errors? */
139 Verbosity
= 0, /* Show all attributes? */
140 Version
= 11, /* Default IPP version */
141 XMLHeader
= 0; /* 1 if header is written */
142 char *Password
= NULL
; /* Password from URI */
143 const char * const URIStatusStrings
[] = /* URI status strings */
146 "Bad arguments to function",
147 "Bad resource in URI",
148 "Bad port number in URI",
149 "Bad hostname/address in URI",
150 "Bad username in URI",
154 "Missing scheme in URI",
155 "Unknown scheme in URI",
156 "Missing resource in URI"
164 static int compare_vars(_cups_var_t
*a
, _cups_var_t
*b
);
165 static int do_tests(_cups_vars_t
*vars
, const char *testfile
);
166 static void expand_variables(_cups_vars_t
*vars
, char *dst
, const char *src
,
167 size_t dstsize
) __attribute((nonnull(1,2,3)));
168 static int expect_matches(_cups_expect_t
*expect
, ipp_tag_t value_tag
);
169 static ipp_t
*get_collection(_cups_vars_t
*vars
, FILE *fp
, int *linenum
);
170 static char *get_filename(const char *testfile
, char *dst
, const char *src
,
172 static char *get_token(FILE *fp
, char *buf
, int buflen
,
174 static char *get_variable(_cups_vars_t
*vars
, const char *name
);
175 static char *iso_date(ipp_uchar_t
*date
);
176 static const char *password_cb(const char *prompt
);
177 static void print_attr(ipp_attribute_t
*attr
, ipp_tag_t
*group
);
178 static void print_col(ipp_t
*col
);
179 static void print_csv(ipp_attribute_t
*attr
, int num_displayed
,
180 char **displayed
, size_t *widths
);
181 static void print_fatal_error(const char *s
, ...)
182 __attribute__ ((__format__ (__printf__
, 1, 2)));
183 static void print_line(ipp_attribute_t
*attr
, int num_displayed
,
184 char **displayed
, size_t *widths
);
185 static void print_test_error(const char *s
, ...)
186 __attribute__ ((__format__ (__printf__
, 1, 2)));
187 static void print_xml_header(void);
188 static void print_xml_string(const char *element
, const char *s
);
189 static void print_xml_trailer(int success
, const char *message
);
190 static void set_variable(_cups_vars_t
*vars
, const char *name
,
192 static void sigterm_handler(int sig
);
193 static int timeout_cb(http_t
*http
, void *user_data
);
194 static void usage(void) __attribute__((noreturn
));
195 static int validate_attr(ipp_attribute_t
*attr
, int print
);
196 static int with_value(char *value
, int regex
, ipp_attribute_t
*attr
,
201 * 'main()' - Parse options and do tests.
204 int /* O - Exit status */
205 main(int argc
, /* I - Number of command-line args */
206 char *argv
[]) /* I - Command-line arguments */
208 int i
; /* Looping var */
209 int status
; /* Status of tests... */
210 char *opt
, /* Current option */
211 name
[1024], /* Name/value buffer */
212 *value
, /* Pointer to value */
213 filename
[1024], /* Real filename */
214 testname
[1024]; /* Real test filename */
215 const char *testfile
; /* Test file to use */
216 int interval
, /* Test interval in microseconds */
217 repeat
; /* Repeat count */
218 _cups_vars_t vars
; /* Variables */
219 http_uri_status_t uri_status
; /* URI separation status */
220 _cups_globals_t
*cg
= _cupsGlobals();
225 * Catch SIGINT and SIGTERM...
228 signal(SIGINT
, sigterm_handler
);
229 signal(SIGTERM
, sigterm_handler
);
232 * Initialize the locale and variables...
235 _cupsSetLocale(argv
);
237 memset(&vars
, 0, sizeof(vars
));
238 vars
.family
= AF_UNSPEC
;
239 vars
.vars
= cupsArrayNew((cups_array_func_t
)compare_vars
, NULL
);
244 * ipptool URI testfile
252 for (i
= 1; i
< argc
; i
++)
254 if (argv
[i
][0] == '-')
256 for (opt
= argv
[i
] + 1; *opt
; opt
++)
260 case '4' : /* Connect using IPv4 only */
261 vars
.family
= AF_INET
;
265 case '6' : /* Connect using IPv6 only */
266 vars
.family
= AF_INET6
;
268 #endif /* AF_INET6 */
270 case 'C' : /* Enable HTTP chunking */
271 Transfer
= _CUPS_TRANSFER_CHUNKED
;
274 case 'E' : /* Encrypt with TLS */
276 vars
.encryption
= HTTP_ENCRYPT_REQUIRED
;
278 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
280 #endif /* HAVE_SSL */
283 case 'I' : /* Ignore errors */
287 case 'L' : /* Disable HTTP chunking */
288 Transfer
= _CUPS_TRANSFER_LENGTH
;
291 case 'S' : /* Encrypt with SSL */
293 vars
.encryption
= HTTP_ENCRYPT_ALWAYS
;
295 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
297 #endif /* HAVE_SSL */
300 case 'T' : /* Set timeout */
305 _cupsLangPuts(stderr
,
306 _("ipptool: Missing timeout for \"-T\"."));
310 vars
.timeout
= _cupsStrScand(argv
[i
], NULL
, localeconv());
313 case 'V' : /* Set IPP version */
318 _cupsLangPuts(stderr
,
319 _("ipptool: Missing version for \"-V\"."));
323 if (!strcmp(argv
[i
], "1.0"))
325 else if (!strcmp(argv
[i
], "1.1"))
327 else if (!strcmp(argv
[i
], "2.0"))
329 else if (!strcmp(argv
[i
], "2.1"))
331 else if (!strcmp(argv
[i
], "2.2"))
335 _cupsLangPrintf(stderr
,
336 _("ipptool: Bad version %s for \"-V\"."),
342 case 'X' : /* Produce XML output */
343 Output
= _CUPS_OUTPUT_PLIST
;
345 if (interval
|| repeat
)
347 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are "
348 "incompatible with -X\"."));
353 case 'c' : /* CSV output */
354 Output
= _CUPS_OUTPUT_CSV
;
357 case 'd' : /* Define a variable */
362 _cupsLangPuts(stderr
,
363 _("ipptool: Missing name=value for \"-d\"."));
367 strlcpy(name
, argv
[i
], sizeof(name
));
368 if ((value
= strchr(name
, '=')) != NULL
)
371 value
= name
+ strlen(name
);
373 set_variable(&vars
, name
, value
);
376 case 'f' : /* Set the default test filename */
381 _cupsLangPuts(stderr
,
382 _("ipptool: Missing filename for \"-f\"."));
386 if (access(argv
[i
], 0) && argv
[i
][0] != '/')
388 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s",
389 cg
->cups_datadir
, argv
[i
]);
390 if (access(argv
[i
], 0))
391 vars
.filename
= argv
[i
];
393 vars
.filename
= filename
;
396 vars
.filename
= argv
[i
];
399 case 'i' : /* Test every N seconds */
404 _cupsLangPuts(stderr
,
405 _("ipptool: Missing seconds for \"-i\"."));
410 interval
= (int)(_cupsStrScand(argv
[i
], NULL
, localeconv()) *
414 _cupsLangPuts(stderr
,
415 _("ipptool: Invalid seconds for \"-i\"."));
420 if (Output
== _CUPS_OUTPUT_PLIST
&& interval
)
422 _cupsLangPuts(stderr
, _("ipptool: \"-i\" is incompatible with "
428 case 'l' : /* List as a table */
429 Output
= _CUPS_OUTPUT_LIST
;
432 case 'n' : /* Repeat count */
437 _cupsLangPuts(stderr
,
438 _("ipptool: Missing count for \"-n\"."));
442 repeat
= atoi(argv
[i
]);
444 if (Output
== _CUPS_OUTPUT_PLIST
&& repeat
)
446 _cupsLangPuts(stderr
, _("ipptool: \"-n\" is incompatible with "
452 case 'q' : /* Be quiet */
453 Output
= _CUPS_OUTPUT_QUIET
;
456 case 't' : /* CUPS test output */
457 Output
= _CUPS_OUTPUT_TEST
;
460 case 'v' : /* Be verbose */
465 _cupsLangPrintf(stderr
, _("ipptool: Unknown option \"-%c\"."),
472 else if (!strncmp(argv
[i
], "ipp://", 6) || !strncmp(argv
[i
], "http://", 7)
474 || !strncmp(argv
[i
], "ipps://", 7)
475 || !strncmp(argv
[i
], "https://", 8)
476 #endif /* HAVE_SSL */
485 _cupsLangPuts(stderr
, _("ipptool: May only specify a single URI."));
490 if (!strncmp(argv
[i
], "ipps://", 7) || !strncmp(argv
[i
], "https://", 8))
491 vars
.encryption
= HTTP_ENCRYPT_ALWAYS
;
492 #endif /* HAVE_SSL */
495 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
, vars
.uri
,
496 vars
.scheme
, sizeof(vars
.scheme
),
497 vars
.userpass
, sizeof(vars
.userpass
),
498 vars
.hostname
, sizeof(vars
.hostname
),
500 vars
.resource
, sizeof(vars
.resource
));
502 if (uri_status
!= HTTP_URI_OK
)
504 _cupsLangPrintf(stderr
, _("ipptool: Bad URI - %s."),
505 URIStatusStrings
[uri_status
- HTTP_URI_OVERFLOW
]);
509 if (vars
.userpass
[0])
511 if ((Password
= strchr(vars
.userpass
, ':')) != NULL
)
514 cupsSetUser(vars
.userpass
);
515 cupsSetPasswordCB(password_cb
);
516 set_variable(&vars
, "uriuser", vars
.userpass
);
527 _cupsLangPuts(stderr
, _("ipptool: URI required before test file."));
531 if (access(argv
[i
], 0) && argv
[i
][0] != '/')
533 snprintf(testname
, sizeof(testname
), "%s/ipptool/%s", cg
->cups_datadir
,
535 if (access(testname
, 0))
543 if (!do_tests(&vars
, testfile
))
548 if (!vars
.uri
|| !testfile
)
552 * Loop if the interval is set...
555 if (Output
== _CUPS_OUTPUT_PLIST
)
556 print_xml_trailer(!status
, NULL
);
557 else if (interval
> 0 && repeat
> 0)
562 do_tests(&vars
, testfile
);
566 else if (interval
> 0)
571 do_tests(&vars
, testfile
);
584 * 'compare_vars()' - Compare two variables.
587 static int /* O - Result of comparison */
588 compare_vars(_cups_var_t
*a
, /* I - First variable */
589 _cups_var_t
*b
) /* I - Second variable */
591 return (_cups_strcasecmp(a
->name
, b
->name
));
596 * 'do_tests()' - Do tests as specified in the test file.
599 static int /* 1 = success, 0 = failure */
600 do_tests(_cups_vars_t
*vars
, /* I - Variables */
601 const char *testfile
) /* I - Test file to use */
603 int i
, /* Looping var */
604 linenum
, /* Current line number */
605 pass
, /* Did we pass the test? */
606 prev_pass
= 1, /* Did we pass the previous test? */
607 request_id
, /* Current request ID */
608 show_header
= 1, /* Show the test header? */
609 ignore_errors
, /* Ignore test failures? */
610 skip_previous
= 0; /* Skip on previous test failure? */
611 http_t
*http
= NULL
; /* HTTP connection to server */
612 FILE *fp
= NULL
; /* Test file */
613 char resource
[512], /* Resource for request */
614 token
[1024], /* Token from file */
615 *tokenptr
, /* Pointer into token */
616 temp
[1024], /* Temporary string */
617 buffer
[8192]; /* Copy buffer */
618 ipp_t
*request
= NULL
, /* IPP request */
619 *response
= NULL
; /* IPP response */
620 size_t length
; /* Length of IPP request */
621 http_status_t status
; /* HTTP status */
622 int fd
; /* File to send */
623 ssize_t bytes
; /* Bytes read/written */
624 char attr
[128]; /* Attribute name */
625 ipp_op_t op
; /* Operation */
626 ipp_tag_t group
; /* Current group */
627 ipp_tag_t value
; /* Current value type */
628 ipp_attribute_t
*attrptr
, /* Attribute pointer */
629 *found
, /* Found attribute */
630 *lastcol
= NULL
; /* Last collection attribute */
631 char name
[1024]; /* Name of test */
632 char filename
[1024]; /* Filename */
633 _cups_transfer_t transfer
; /* To chunk or not to chunk */
634 int version
, /* IPP version number to use */
635 skip_test
; /* Skip this test? */
636 int num_statuses
= 0; /* Number of valid status codes */
637 _cups_status_t statuses
[100], /* Valid status codes */
638 *last_status
; /* Last STATUS (for predicates) */
639 int num_expects
= 0; /* Number of expected attributes */
640 _cups_expect_t expects
[200], /* Expected attributes */
641 *expect
, /* Current expected attribute */
642 *last_expect
; /* Last EXPECT (for predicates) */
643 int num_displayed
= 0; /* Number of displayed attributes */
644 char *displayed
[200]; /* Displayed attributes */
645 size_t widths
[200]; /* Width of columns */
649 * Open the test file...
652 if ((fp
= fopen(testfile
, "r")) == NULL
)
654 print_fatal_error("Unable to open test file %s - %s", testfile
,
661 * Connect to the server...
664 if ((http
= _httpCreate(vars
->hostname
, vars
->port
, NULL
, vars
->encryption
,
665 vars
->family
)) == NULL
)
667 print_fatal_error("Unable to connect to %s on port %d - %s", vars
->hostname
,
668 vars
->port
, cupsLastErrorString());
673 if (httpReconnect(http
))
675 print_fatal_error("Unable to connect to %s on port %d - %s", vars
->hostname
,
676 vars
->port
, cupsLastErrorString());
681 if (vars
->timeout
> 0.0)
682 httpSetTimeout(http
, vars
->timeout
, timeout_cb
, NULL
);
688 CUPS_SRAND(time(NULL
));
692 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
694 while (!Cancel
&& get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
697 * Expect an open brace...
700 if (!strcmp(token
, "DEFINE"))
706 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
707 get_token(fp
, temp
, sizeof(temp
), &linenum
))
709 expand_variables(vars
, token
, temp
, sizeof(token
));
710 set_variable(vars
, attr
, token
);
714 print_fatal_error("Missing DEFINE name and/or value on line %d.",
722 else if (!strcmp(token
, "DEFINE-DEFAULT"))
725 * DEFINE-DEFAULT name value
728 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
729 get_token(fp
, temp
, sizeof(temp
), &linenum
))
731 expand_variables(vars
, token
, temp
, sizeof(token
));
732 if (!get_variable(vars
, attr
))
733 set_variable(vars
, attr
, token
);
737 print_fatal_error("Missing DEFINE-DEFAULT name and/or value on line "
745 else if (!strcmp(token
, "IGNORE-ERRORS"))
752 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
753 (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
755 IgnoreErrors
= !_cups_strcasecmp(temp
, "yes");
759 print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum
);
766 else if (!strcmp(token
, "INCLUDE"))
773 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
776 * Map the filename to and then run the tests...
779 if (!do_tests(vars
, get_filename(testfile
, filename
, temp
,
790 print_fatal_error("Missing INCLUDE filename on line %d.", linenum
);
798 else if (!strcmp(token
, "INCLUDE-IF-DEFINED"))
801 * INCLUDE-IF-DEFINED name "filename"
802 * INCLUDE-IF-DEFINED name <filename>
805 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
806 get_token(fp
, temp
, sizeof(temp
), &linenum
))
809 * Map the filename to and then run the tests...
812 if (get_variable(vars
, attr
) &&
813 !do_tests(vars
, get_filename(testfile
, filename
, temp
,
824 print_fatal_error("Missing INCLUDE-IF-DEFINED name or filename on line "
833 else if (!strcmp(token
, "INCLUDE-IF-NOT-DEFINED"))
836 * INCLUDE-IF-NOT-DEFINED name "filename"
837 * INCLUDE-IF-NOT-DEFINED name <filename>
840 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
841 get_token(fp
, temp
, sizeof(temp
), &linenum
))
844 * Map the filename to and then run the tests...
847 if (!get_variable(vars
, attr
) &&
848 !do_tests(vars
, get_filename(testfile
, filename
, temp
,
859 print_fatal_error("Missing INCLUDE-IF-NOT-DEFINED name or filename on "
860 "line %d.", linenum
);
868 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
871 * SKIP-IF-DEFINED variable
874 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
876 if (get_variable(vars
, temp
))
881 print_fatal_error("Missing SKIP-IF-DEFINED variable on line %d.",
887 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
890 * SKIP-IF-NOT-DEFINED variable
893 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
895 if (!get_variable(vars
, temp
))
900 print_fatal_error("Missing SKIP-IF-NOT-DEFINED variable on line %d.",
906 else if (!strcmp(token
, "TRANSFER"))
914 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
916 if (!strcmp(temp
, "auto"))
917 Transfer
= _CUPS_TRANSFER_AUTO
;
918 else if (!strcmp(temp
, "chunked"))
919 Transfer
= _CUPS_TRANSFER_CHUNKED
;
920 else if (!strcmp(temp
, "length"))
921 Transfer
= _CUPS_TRANSFER_LENGTH
;
924 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
932 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
939 else if (!strcmp(token
, "VERSION"))
941 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
943 if (!strcmp(temp
, "1.0"))
945 else if (!strcmp(temp
, "1.1"))
947 else if (!strcmp(temp
, "2.0"))
949 else if (!strcmp(temp
, "2.1"))
951 else if (!strcmp(temp
, "2.2"))
955 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
962 print_fatal_error("Missing VERSION number on line %d.", linenum
);
969 else if (strcmp(token
, "{"))
971 print_fatal_error("Unexpected token %s seen on line %d.", token
, linenum
);
977 * Initialize things...
982 if (Output
== _CUPS_OUTPUT_PLIST
)
984 else if (Output
== _CUPS_OUTPUT_TEST
)
985 printf("\"%s\":\n", testfile
);
990 strlcpy(resource
, vars
->resource
, sizeof(resource
));
995 group
= IPP_TAG_ZERO
;
996 ignore_errors
= IgnoreErrors
;
1002 transfer
= Transfer
;
1004 strlcpy(name
, testfile
, sizeof(name
));
1005 if (strrchr(name
, '.') != NULL
)
1006 *strrchr(name
, '.') = '\0';
1009 * Parse until we see a close brace...
1012 while (get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
1014 if (_cups_strcasecmp(token
, "COUNT") &&
1015 _cups_strcasecmp(token
, "DEFINE-MATCH") &&
1016 _cups_strcasecmp(token
, "DEFINE-NO-MATCH") &&
1017 _cups_strcasecmp(token
, "DEFINE-VALUE") &&
1018 _cups_strcasecmp(token
, "IF-DEFINED") &&
1019 _cups_strcasecmp(token
, "IF-NOT-DEFINED") &&
1020 _cups_strcasecmp(token
, "IN-GROUP") &&
1021 _cups_strcasecmp(token
, "OF-TYPE") &&
1022 _cups_strcasecmp(token
, "SAME-COUNT-AS") &&
1023 _cups_strcasecmp(token
, "WITH-VALUE"))
1026 if (_cups_strcasecmp(token
, "IF-DEFINED") &&
1027 _cups_strcasecmp(token
, "IF-NOT-DEFINED"))
1030 if (!strcmp(token
, "}"))
1032 else if (!strcmp(token
, "{") && lastcol
)
1035 * Another collection value
1038 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
1039 /* Collection value */
1043 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
1047 * Reallocate memory...
1050 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
1051 (lastcol
->num_values
+ 1) *
1052 sizeof(ipp_value_t
))) == NULL
)
1054 print_fatal_error("Unable to allocate memory on line %d.", linenum
);
1059 if (tempcol
!= lastcol
)
1062 * Reset pointers in the list...
1066 request
->prev
->next
= tempcol
;
1068 request
->attrs
= tempcol
;
1070 lastcol
= request
->current
= request
->last
= tempcol
;
1073 lastcol
->values
[lastcol
->num_values
].collection
= col
;
1074 lastcol
->num_values
++;
1082 else if (!strcmp(token
, "DEFINE"))
1088 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
1089 get_token(fp
, temp
, sizeof(temp
), &linenum
))
1091 expand_variables(vars
, token
, temp
, sizeof(token
));
1092 set_variable(vars
, attr
, token
);
1096 print_fatal_error("Missing DEFINE name and/or value on line %d.",
1102 else if (!strcmp(token
, "IGNORE-ERRORS"))
1109 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
1110 (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
1112 ignore_errors
= !_cups_strcasecmp(temp
, "yes");
1116 print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum
);
1123 else if (!_cups_strcasecmp(token
, "NAME"))
1129 get_token(fp
, name
, sizeof(name
), &linenum
);
1131 else if (!strcmp(token
, "REQUEST-ID"))
1138 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1140 if (isdigit(temp
[0] & 255))
1141 request_id
= atoi(temp
);
1142 else if (!_cups_strcasecmp(temp
, "random"))
1143 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
1146 print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp
,
1154 print_fatal_error("Missing REQUEST-ID value on line %d.", linenum
);
1159 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
1162 * SKIP-IF-DEFINED variable
1165 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1167 if (get_variable(vars
, temp
))
1172 print_fatal_error("Missing SKIP-IF-DEFINED value on line %d.",
1178 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
1181 * SKIP-IF-NOT-DEFINED variable
1184 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1186 if (!get_variable(vars
, temp
))
1191 print_fatal_error("Missing SKIP-IF-NOT-DEFINED value on line %d.",
1197 else if (!strcmp(token
, "SKIP-PREVIOUS-ERROR"))
1200 * SKIP-PREVIOUS-ERROR yes
1201 * SKIP-PREVIOUS-ERROR no
1204 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
1205 (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
1207 skip_previous
= !_cups_strcasecmp(temp
, "yes");
1211 print_fatal_error("Missing SKIP-PREVIOUS-ERROR value on line %d.", linenum
);
1218 else if (!strcmp(token
, "TRANSFER"))
1226 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1228 if (!strcmp(temp
, "auto"))
1229 transfer
= _CUPS_TRANSFER_AUTO
;
1230 else if (!strcmp(temp
, "chunked"))
1231 transfer
= _CUPS_TRANSFER_CHUNKED
;
1232 else if (!strcmp(temp
, "length"))
1233 transfer
= _CUPS_TRANSFER_LENGTH
;
1236 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
1244 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
1249 else if (!_cups_strcasecmp(token
, "VERSION"))
1251 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1253 if (!strcmp(temp
, "0.0"))
1255 else if (!strcmp(temp
, "1.0"))
1257 else if (!strcmp(temp
, "1.1"))
1259 else if (!strcmp(temp
, "2.0"))
1261 else if (!strcmp(temp
, "2.1"))
1263 else if (!strcmp(temp
, "2.2"))
1267 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
1274 print_fatal_error("Missing VERSION number on line %d.", linenum
);
1279 else if (!_cups_strcasecmp(token
, "RESOURCE"))
1285 if (!get_token(fp
, resource
, sizeof(resource
), &linenum
))
1287 print_fatal_error("Missing RESOURCE path on line %d.", linenum
);
1292 else if (!_cups_strcasecmp(token
, "OPERATION"))
1298 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1300 print_fatal_error("Missing OPERATION code on line %d.", linenum
);
1305 if ((op
= ippOpValue(token
)) == (ipp_op_t
)-1 &&
1306 (op
= strtol(token
, NULL
, 0)) == 0)
1308 print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token
,
1314 else if (!_cups_strcasecmp(token
, "GROUP"))
1317 * Attribute group...
1320 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1322 print_fatal_error("Missing GROUP tag on line %d.", linenum
);
1327 if ((value
= ippTagValue(token
)) < 0)
1329 print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token
, linenum
);
1335 ippAddSeparator(request
);
1339 else if (!_cups_strcasecmp(token
, "DELAY"))
1342 * Delay before operation...
1347 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1349 print_fatal_error("Missing DELAY value on line %d.", linenum
);
1354 if ((delay
= _cupsStrScand(token
, NULL
, localeconv())) <= 0.0)
1356 print_fatal_error("Bad DELAY value \"%s\" on line %d.", token
,
1363 if (Output
== _CUPS_OUTPUT_TEST
)
1364 printf(" [%g second delay]\n", delay
);
1366 usleep((int)(1000000.0 * delay
));
1369 else if (!_cups_strcasecmp(token
, "ATTR"))
1375 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1377 print_fatal_error("Missing ATTR value tag on line %d.", linenum
);
1382 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
1384 print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token
,
1390 if (!get_token(fp
, attr
, sizeof(attr
), &linenum
))
1392 print_fatal_error("Missing ATTR name on line %d.", linenum
);
1397 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1399 print_fatal_error("Missing ATTR value on line %d.", linenum
);
1404 expand_variables(vars
, token
, temp
, sizeof(token
));
1408 case IPP_TAG_BOOLEAN
:
1409 if (!_cups_strcasecmp(token
, "true"))
1410 ippAddBoolean(request
, group
, attr
, 1);
1412 ippAddBoolean(request
, group
, attr
, atoi(token
));
1415 case IPP_TAG_INTEGER
:
1417 if (!strchr(token
, ','))
1418 ippAddInteger(request
, group
, value
, attr
,
1419 strtol(token
, &tokenptr
, 0));
1422 int values
[100], /* Values */
1423 num_values
= 1; /* Number of values */
1425 values
[0] = strtol(token
, &tokenptr
, 10);
1426 while (tokenptr
&& *tokenptr
&&
1427 num_values
< (int)(sizeof(values
) / sizeof(values
[0])))
1429 if (*tokenptr
== ',')
1431 else if (!isdigit(*tokenptr
& 255) && *tokenptr
!= '-')
1434 values
[num_values
] = strtol(tokenptr
, &tokenptr
, 0);
1438 ippAddIntegers(request
, group
, value
, attr
, num_values
, values
);
1441 if (!tokenptr
|| *tokenptr
)
1443 print_fatal_error("Bad %s value \"%s\" on line %d.",
1444 ippTagString(value
), token
, linenum
);
1450 case IPP_TAG_RESOLUTION
:
1452 int xres
, /* X resolution */
1453 yres
; /* Y resolution */
1454 char *ptr
; /* Pointer into value */
1456 xres
= yres
= strtol(token
, (char **)&ptr
, 10);
1457 if (ptr
> token
&& xres
> 0)
1460 yres
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1463 if (ptr
<= token
|| xres
<= 0 || yres
<= 0 || !ptr
||
1464 (_cups_strcasecmp(ptr
, "dpi") && _cups_strcasecmp(ptr
, "dpc") &&
1465 _cups_strcasecmp(ptr
, "other")))
1467 print_fatal_error("Bad resolution value \"%s\" on line %d.",
1473 if (!_cups_strcasecmp(ptr
, "dpi"))
1474 ippAddResolution(request
, group
, attr
, IPP_RES_PER_INCH
,
1476 else if (!_cups_strcasecmp(ptr
, "dpc"))
1477 ippAddResolution(request
, group
, attr
, IPP_RES_PER_CM
,
1480 ippAddResolution(request
, group
, attr
, (ipp_res_t
)0,
1485 case IPP_TAG_RANGE
:
1487 int lowers
[4], /* Lower value */
1488 uppers
[4], /* Upper values */
1489 num_vals
; /* Number of values */
1492 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
1493 lowers
+ 0, uppers
+ 0,
1494 lowers
+ 1, uppers
+ 1,
1495 lowers
+ 2, uppers
+ 2,
1496 lowers
+ 3, uppers
+ 3);
1498 if ((num_vals
& 1) || num_vals
== 0)
1500 print_fatal_error("Bad rangeOfInteger value \"%s\" on line "
1501 "%d.", token
, linenum
);
1506 ippAddRanges(request
, group
, attr
, num_vals
/ 2, lowers
,
1511 case IPP_TAG_BEGIN_COLLECTION
:
1512 if (!strcmp(token
, "{"))
1514 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
1515 /* Collection value */
1519 lastcol
= ippAddCollection(request
, group
, attr
, col
);
1530 print_fatal_error("Bad ATTR collection value on line %d.",
1538 print_fatal_error("Unsupported ATTR value tag %s on line %d.",
1539 ippTagString(value
), linenum
);
1543 case IPP_TAG_TEXTLANG
:
1544 case IPP_TAG_NAMELANG
:
1547 case IPP_TAG_KEYWORD
:
1549 case IPP_TAG_URISCHEME
:
1550 case IPP_TAG_CHARSET
:
1551 case IPP_TAG_LANGUAGE
:
1552 case IPP_TAG_MIMETYPE
:
1553 if (!strchr(token
, ','))
1554 ippAddString(request
, group
, value
, attr
, NULL
, token
);
1558 * Multiple string values...
1561 int num_values
; /* Number of values */
1562 char *values
[100], /* Values */
1563 *ptr
; /* Pointer to next value */
1569 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
1572 values
[num_values
] = ptr
;
1576 ippAddStrings(request
, group
, value
, attr
, num_values
,
1577 NULL
, (const char **)values
);
1582 else if (!_cups_strcasecmp(token
, "FILE"))
1588 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1590 print_fatal_error("Missing FILE filename on line %d.", linenum
);
1595 expand_variables(vars
, token
, temp
, sizeof(token
));
1596 get_filename(testfile
, filename
, token
, sizeof(filename
));
1598 else if (!_cups_strcasecmp(token
, "STATUS"))
1604 if (num_statuses
>= (int)(sizeof(statuses
) / sizeof(statuses
[0])))
1606 print_fatal_error("Too many STATUS's on line %d.", linenum
);
1611 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1613 print_fatal_error("Missing STATUS code on line %d.", linenum
);
1618 if ((statuses
[num_statuses
].status
= ippErrorValue(token
))
1619 == (ipp_status_t
)-1 &&
1620 (statuses
[num_statuses
].status
= strtol(token
, NULL
, 0)) == 0)
1622 print_fatal_error("Bad STATUS code \"%s\" on line %d.", token
,
1628 last_status
= statuses
+ num_statuses
;
1631 last_status
->if_defined
= NULL
;
1632 last_status
->if_not_defined
= NULL
;
1634 else if (!_cups_strcasecmp(token
, "EXPECT"))
1637 * Expected attributes...
1640 if (num_expects
>= (int)(sizeof(expects
) / sizeof(expects
[0])))
1642 print_fatal_error("Too many EXPECT's on line %d.", linenum
);
1647 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1649 print_fatal_error("Missing EXPECT name on line %d.", linenum
);
1654 last_expect
= expects
+ num_expects
;
1657 memset(last_expect
, 0, sizeof(_cups_expect_t
));
1659 if (token
[0] == '!')
1661 last_expect
->not_expect
= 1;
1662 last_expect
->name
= strdup(token
+ 1);
1664 else if (token
[0] == '?')
1666 last_expect
->optional
= 1;
1667 last_expect
->name
= strdup(token
+ 1);
1670 last_expect
->name
= strdup(token
);
1672 else if (!_cups_strcasecmp(token
, "COUNT"))
1674 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1676 print_fatal_error("Missing COUNT number on line %d.", linenum
);
1681 if ((i
= atoi(token
)) <= 0)
1683 print_fatal_error("Bad COUNT \"%s\" on line %d.", token
, linenum
);
1689 last_expect
->count
= i
;
1692 print_fatal_error("COUNT without a preceding EXPECT on line %d.",
1698 else if (!_cups_strcasecmp(token
, "DEFINE-MATCH"))
1700 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1702 print_fatal_error("Missing DEFINE-MATCH variable on line %d.",
1709 last_expect
->define_match
= strdup(token
);
1712 print_fatal_error("DEFINE-MATCH without a preceding EXPECT on line "
1718 else if (!_cups_strcasecmp(token
, "DEFINE-NO-MATCH"))
1720 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1722 print_fatal_error("Missing DEFINE-NO-MATCH variable on line %d.",
1729 last_expect
->define_no_match
= strdup(token
);
1732 print_fatal_error("DEFINE-NO-MATCH without a preceding EXPECT on "
1733 "line %d.", linenum
);
1738 else if (!_cups_strcasecmp(token
, "DEFINE-VALUE"))
1740 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1742 print_fatal_error("Missing DEFINE-VALUE variable on line %d.",
1749 last_expect
->define_value
= strdup(token
);
1752 print_fatal_error("DEFINE-VALUE without a preceding EXPECT on line "
1758 else if (!_cups_strcasecmp(token
, "OF-TYPE"))
1760 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1762 print_fatal_error("Missing OF-TYPE value tag(s) on line %d.",
1769 last_expect
->of_type
= strdup(token
);
1772 print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.",
1778 else if (!_cups_strcasecmp(token
, "IN-GROUP"))
1780 ipp_tag_t in_group
; /* IN-GROUP value */
1783 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1785 print_fatal_error("Missing IN-GROUP group tag on line %d.", linenum
);
1790 if ((in_group
= ippTagValue(token
)) == (ipp_tag_t
)-1)
1793 else if (last_expect
)
1794 last_expect
->in_group
= in_group
;
1797 print_fatal_error("IN-GROUP without a preceding EXPECT on line %d.",
1803 else if (!_cups_strcasecmp(token
, "SAME-COUNT-AS"))
1805 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1807 print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum
);
1813 last_expect
->same_count_as
= strdup(token
);
1816 print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line "
1822 else if (!_cups_strcasecmp(token
, "IF-DEFINED"))
1824 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1826 print_fatal_error("Missing IF-DEFINED name on line %d.", linenum
);
1832 last_expect
->if_defined
= strdup(token
);
1833 else if (last_status
)
1834 last_status
->if_defined
= strdup(token
);
1837 print_fatal_error("IF-DEFINED without a preceding EXPECT or STATUS "
1838 "on line %d.", linenum
);
1843 else if (!_cups_strcasecmp(token
, "IF-NOT-DEFINED"))
1845 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1847 print_fatal_error("Missing IF-NOT-DEFINED name on line %d.", linenum
);
1853 last_expect
->if_not_defined
= strdup(token
);
1854 else if (last_status
)
1855 last_status
->if_not_defined
= strdup(token
);
1858 print_fatal_error("IF-NOT-DEFINED without a preceding EXPECT or STATUS "
1859 "on line %d.", linenum
);
1864 else if (!_cups_strcasecmp(token
, "WITH-VALUE"))
1866 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1868 print_fatal_error("Missing WITH-VALUE value on line %d.", linenum
);
1876 * Expand any variables in the value and then save it.
1879 expand_variables(vars
, token
, temp
, sizeof(token
));
1881 tokenptr
= token
+ strlen(token
) - 1;
1883 if (token
[0] == '/' && tokenptr
> token
&& *tokenptr
== '/')
1886 * WITH-VALUE is a POSIX extended regular expression.
1889 last_expect
->with_value
= calloc(1, tokenptr
- token
);
1890 last_expect
->with_regex
= 1;
1892 if (last_expect
->with_value
)
1893 memcpy(last_expect
->with_value
, token
+ 1, tokenptr
- token
- 1);
1898 * WITH-VALUE is a literal value...
1901 last_expect
->with_value
= strdup(token
);
1906 print_fatal_error("WITH-VALUE without a preceding EXPECT on line %d.",
1912 else if (!_cups_strcasecmp(token
, "DISPLAY"))
1915 * Display attributes...
1918 if (num_displayed
>= (int)(sizeof(displayed
) / sizeof(displayed
[0])))
1920 print_fatal_error("Too many DISPLAY's on line %d", linenum
);
1925 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1927 print_fatal_error("Missing DISPLAY name on line %d.", linenum
);
1932 displayed
[num_displayed
] = strdup(token
);
1937 print_fatal_error("Unexpected token %s seen on line %d.", token
,
1945 * Submit the IPP request...
1948 request
->request
.op
.version
[0] = version
/ 10;
1949 request
->request
.op
.version
[1] = version
% 10;
1950 request
->request
.op
.operation_id
= op
;
1951 request
->request
.op
.request_id
= request_id
;
1953 if (Output
== _CUPS_OUTPUT_PLIST
)
1956 puts("<key>Name</key>");
1957 print_xml_string("string", name
);
1958 puts("<key>Operation</key>");
1959 print_xml_string("string", ippOpString(op
));
1960 puts("<key>RequestAttributes</key>");
1965 for (attrptr
= request
->attrs
, group
= attrptr
->group_tag
;
1967 attrptr
= attrptr
->next
)
1968 print_attr(attrptr
, &group
);
1973 else if (Output
== _CUPS_OUTPUT_TEST
)
1977 printf(" %s:\n", ippOpString(op
));
1979 for (attrptr
= request
->attrs
; attrptr
; attrptr
= attrptr
->next
)
1980 print_attr(attrptr
, NULL
);
1983 printf(" %-69.69s [", name
);
1987 if ((skip_previous
&& !prev_pass
) || skip_test
)
1992 if (Output
== _CUPS_OUTPUT_PLIST
)
1994 puts("<key>Successful</key>");
1996 puts("<key>StatusCode</key>");
1997 print_xml_string("string", "skip");
1998 puts("<key>ResponseAttributes</key>");
2002 else if (Output
== _CUPS_OUTPUT_TEST
)
2010 if (transfer
== _CUPS_TRANSFER_CHUNKED
||
2011 (transfer
== _CUPS_TRANSFER_AUTO
&& filename
[0]))
2014 * Send request using chunking - a 0 length means "chunk".
2022 * Send request using content length...
2025 length
= ippLength(request
);
2029 struct stat fileinfo
; /* File information */
2031 if (stat(filename
, &fileinfo
))
2033 snprintf(buffer
, sizeof(buffer
), "%s: %s", filename
, strerror(errno
));
2034 _cupsSetError(IPP_INTERNAL_ERROR
, buffer
, 0);
2036 status
= HTTP_ERROR
;
2039 length
+= fileinfo
.st_size
;
2044 * Send the request...
2049 if (status
!= HTTP_ERROR
)
2051 while (!response
&& !Cancel
)
2053 status
= cupsSendRequest(http
, request
, resource
, length
);
2055 if (!Cancel
&& status
== HTTP_CONTINUE
&& request
->state
== IPP_DATA
&&
2058 if ((fd
= open(filename
, O_RDONLY
| O_BINARY
)) >= 0)
2060 while (!Cancel
&& (bytes
= read(fd
, buffer
, sizeof(buffer
))) > 0)
2061 if ((status
= cupsWriteRequestData(http
, buffer
,
2062 bytes
)) != HTTP_CONTINUE
)
2067 snprintf(buffer
, sizeof(buffer
), "%s: %s", filename
,
2069 _cupsSetError(IPP_INTERNAL_ERROR
, buffer
, 0);
2071 status
= HTTP_ERROR
;
2076 * Get the server's response...
2079 if (!Cancel
&& (status
== HTTP_CONTINUE
|| status
== HTTP_OK
))
2081 response
= cupsGetResponse(http
, resource
);
2082 status
= http
->status
;
2087 if ((status
== HTTP_ERROR
&& cupsLastError() != IPP_INTERNAL_ERROR
) ||
2088 (status
>= HTTP_BAD_REQUEST
&& status
!= HTTP_UNAUTHORIZED
&&
2089 status
!= HTTP_UPGRADE_REQUIRED
))
2091 _cupsSetHTTPError(status
);
2095 if (http
->state
!= HTTP_WAITING
)
2098 * Flush any remaining data...
2112 prev_pass
= pass
= 0;
2115 if (http
->version
!= HTTP_1_1
)
2116 prev_pass
= pass
= 0;
2118 if (response
->request
.status
.request_id
!= request_id
)
2119 prev_pass
= pass
= 0;
2122 (response
->request
.status
.version
[0] != (version
/ 10) ||
2123 response
->request
.status
.version
[1] != (version
% 10)))
2124 prev_pass
= pass
= 0;
2126 if ((attrptr
= ippFindAttribute(response
, "job-id",
2127 IPP_TAG_INTEGER
)) != NULL
)
2129 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
2130 set_variable(vars
, "job-id", temp
);
2133 if ((attrptr
= ippFindAttribute(response
, "job-uri",
2134 IPP_TAG_URI
)) != NULL
)
2135 set_variable(vars
, "job-uri", attrptr
->values
[0].string
.text
);
2137 if ((attrptr
= ippFindAttribute(response
, "notify-subscription-id",
2138 IPP_TAG_INTEGER
)) != NULL
)
2140 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
2141 set_variable(vars
, "notify-subscription-id", temp
);
2144 attrptr
= response
->attrs
;
2145 if (!attrptr
|| !attrptr
->name
||
2146 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
2147 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2148 attrptr
->num_values
!= 1 ||
2149 strcmp(attrptr
->name
, "attributes-charset"))
2150 prev_pass
= pass
= 0;
2154 attrptr
= attrptr
->next
;
2155 if (!attrptr
|| !attrptr
->name
||
2156 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
2157 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2158 attrptr
->num_values
!= 1 ||
2159 strcmp(attrptr
->name
, "attributes-natural-language"))
2160 prev_pass
= pass
= 0;
2163 if ((attrptr
= ippFindAttribute(response
, "status-message",
2164 IPP_TAG_ZERO
)) != NULL
&&
2165 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
2166 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2167 attrptr
->num_values
!= 1 ||
2168 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2169 strlen(attrptr
->values
[0].string
.text
) > 255)))
2170 prev_pass
= pass
= 0;
2172 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
2173 IPP_TAG_ZERO
)) != NULL
&&
2174 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
2175 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2176 attrptr
->num_values
!= 1 ||
2177 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2178 strlen(attrptr
->values
[0].string
.text
) > 1023)))
2179 prev_pass
= pass
= 0;
2181 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
2183 attrptr
= attrptr
->next
)
2185 if (attrptr
->group_tag
< group
&& attrptr
->group_tag
!= IPP_TAG_ZERO
)
2187 prev_pass
= pass
= 0;
2191 if (!validate_attr(attrptr
, 0))
2193 prev_pass
= pass
= 0;
2198 for (i
= 0; i
< num_statuses
; i
++)
2200 if (statuses
[i
].if_defined
&&
2201 !get_variable(vars
, statuses
[i
].if_defined
))
2204 if (statuses
[i
].if_not_defined
&&
2205 get_variable(vars
, statuses
[i
].if_not_defined
))
2208 if (response
->request
.status
.status_code
== statuses
[i
].status
)
2212 if (i
== num_statuses
&& num_statuses
> 0)
2213 prev_pass
= pass
= 0;
2216 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2218 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
2221 if (expect
->if_not_defined
&&
2222 get_variable(vars
, expect
->if_not_defined
))
2225 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
2227 if ((found
&& expect
->not_expect
) ||
2228 (!found
&& !(expect
->not_expect
|| expect
->optional
)) ||
2229 (found
&& !expect_matches(expect
, found
->value_tag
)) ||
2230 (found
&& expect
->in_group
&&
2231 found
->group_tag
!= expect
->in_group
))
2233 if (expect
->define_no_match
)
2234 set_variable(vars
, expect
->define_no_match
, "1");
2235 else if (!expect
->define_match
)
2236 prev_pass
= pass
= 0;
2242 !with_value(expect
->with_value
, expect
->with_regex
, found
, 0))
2244 if (expect
->define_no_match
)
2245 set_variable(vars
, expect
->define_no_match
, "1");
2246 else if (!expect
->define_match
)
2247 prev_pass
= pass
= 0;
2252 if (found
&& expect
->count
> 0 && found
->num_values
!= expect
->count
)
2254 if (expect
->define_no_match
)
2255 set_variable(vars
, expect
->define_no_match
, "1");
2256 else if (!expect
->define_match
)
2257 prev_pass
= pass
= 0;
2262 if (found
&& expect
->same_count_as
)
2264 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
2267 if (!attrptr
|| attrptr
->num_values
!= found
->num_values
)
2269 if (expect
->define_no_match
)
2270 set_variable(vars
, expect
->define_no_match
, "1");
2271 else if (!expect
->define_match
)
2272 prev_pass
= pass
= 0;
2278 if (found
&& expect
->define_match
)
2279 set_variable(vars
, expect
->define_match
, "1");
2281 if (found
&& expect
->define_value
)
2283 _ippAttrString(found
, token
, sizeof(token
));
2284 set_variable(vars
, expect
->define_value
, token
);
2290 if (Output
== _CUPS_OUTPUT_PLIST
)
2292 puts("<key>Successful</key>");
2293 puts(prev_pass
? "<true />" : "<false />");
2294 puts("<key>StatusCode</key>");
2295 print_xml_string("string", ippErrorString(cupsLastError()));
2296 puts("<key>ResponseAttributes</key>");
2299 for (attrptr
= response
? response
->attrs
: NULL
,
2300 group
= attrptr
? attrptr
->group_tag
: IPP_TAG_ZERO
;
2302 attrptr
= attrptr
->next
)
2303 print_attr(attrptr
, &group
);
2307 else if (Output
== _CUPS_OUTPUT_TEST
)
2309 puts(prev_pass
? "PASS]" : "FAIL]");
2311 if (Verbosity
&& response
)
2313 printf(" RECEIVED: %lu bytes in response\n",
2314 (unsigned long)ippLength(response
));
2315 printf(" status-code = %x (%s)\n", cupsLastError(),
2316 ippErrorString(cupsLastError()));
2318 for (attrptr
= response
->attrs
;
2320 attrptr
= attrptr
->next
)
2322 print_attr(attrptr
, NULL
);
2326 else if (!prev_pass
)
2327 fprintf(stderr
, "%s\n", cupsLastErrorString());
2329 if (prev_pass
&& Output
!= _CUPS_OUTPUT_PLIST
&&
2330 Output
!= _CUPS_OUTPUT_QUIET
&& !Verbosity
&& num_displayed
> 0)
2332 if (Output
>= _CUPS_OUTPUT_LIST
)
2334 size_t width
; /* Length of value */
2337 for (i
= 0; i
< num_displayed
; i
++)
2339 widths
[i
] = strlen(displayed
[i
]);
2341 for (attrptr
= ippFindAttribute(response
, displayed
[i
], IPP_TAG_ZERO
);
2343 attrptr
= ippFindNextAttribute(response
, displayed
[i
],
2346 width
= _ippAttrString(attrptr
, NULL
, 0);
2347 if (width
> widths
[i
])
2352 if (Output
== _CUPS_OUTPUT_CSV
)
2353 print_csv(NULL
, num_displayed
, displayed
, widths
);
2355 print_line(NULL
, num_displayed
, displayed
, widths
);
2357 attrptr
= response
->attrs
;
2361 while (attrptr
&& attrptr
->group_tag
<= IPP_TAG_OPERATION
)
2362 attrptr
= attrptr
->next
;
2366 if (Output
== _CUPS_OUTPUT_CSV
)
2367 print_csv(attrptr
, num_displayed
, displayed
, widths
);
2369 print_line(attrptr
, num_displayed
, displayed
, widths
);
2371 while (attrptr
&& attrptr
->group_tag
> IPP_TAG_OPERATION
)
2372 attrptr
= attrptr
->next
;
2378 for (attrptr
= response
->attrs
;
2380 attrptr
= attrptr
->next
)
2384 for (i
= 0; i
< num_displayed
; i
++)
2386 if (!strcmp(displayed
[i
], attrptr
->name
))
2388 print_attr(attrptr
, NULL
);
2396 else if (!prev_pass
)
2398 if (Output
== _CUPS_OUTPUT_PLIST
)
2400 puts("<key>Errors</key>");
2404 if (http
->version
!= HTTP_1_1
)
2405 print_test_error("Bad HTTP version (%d.%d)", http
->version
/ 100,
2406 http
->version
% 100);
2409 print_test_error("IPP request failed with status %s (%s)",
2410 ippErrorString(cupsLastError()),
2411 cupsLastErrorString());
2415 (response
->request
.status
.version
[0] != (version
/ 10) ||
2416 response
->request
.status
.version
[1] != (version
% 10)))
2417 print_test_error("Bad version %d.%d in response - expected %d.%d "
2418 "(RFC 2911 section 3.1.8).",
2419 response
->request
.status
.version
[0],
2420 response
->request
.status
.version
[1],
2421 version
/ 10, version
% 10);
2423 if (response
->request
.status
.request_id
!= request_id
)
2424 print_test_error("Bad request ID %d in response - expected %d "
2425 "(RFC 2911 section 3.1.1)",
2426 response
->request
.status
.request_id
, request_id
);
2428 attrptr
= response
->attrs
;
2430 print_test_error("Missing first attribute \"attributes-charset "
2431 "(charset)\" in group operation-attributes-tag "
2432 "(RFC 2911 section 3.1.4).");
2435 if (!attrptr
->name
||
2436 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
2437 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2438 attrptr
->num_values
!= 1 ||
2439 strcmp(attrptr
->name
, "attributes-charset"))
2440 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
2441 "expected \"attributes-charset (charset)\" in "
2442 "group operation-attributes-tag (RFC 2911 section "
2444 attrptr
->name
? attrptr
->name
: "(null)",
2445 attrptr
->num_values
> 1 ? "1setOf " : "",
2446 ippTagString(attrptr
->value_tag
),
2447 ippTagString(attrptr
->group_tag
));
2449 attrptr
= attrptr
->next
;
2451 print_test_error("Missing second attribute \"attributes-natural-"
2452 "language (naturalLanguage)\" in group "
2453 "operation-attributes-tag (RFC 2911 section "
2455 else if (!attrptr
->name
||
2456 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
2457 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2458 attrptr
->num_values
!= 1 ||
2459 strcmp(attrptr
->name
, "attributes-natural-language"))
2460 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
2461 "expected \"attributes-natural-language "
2462 "(naturalLanguage)\" in group "
2463 "operation-attributes-tag (RFC 2911 section "
2465 attrptr
->name
? attrptr
->name
: "(null)",
2466 attrptr
->num_values
> 1 ? "1setOf " : "",
2467 ippTagString(attrptr
->value_tag
),
2468 ippTagString(attrptr
->group_tag
));
2471 if ((attrptr
= ippFindAttribute(response
, "status-message",
2472 IPP_TAG_ZERO
)) != NULL
)
2474 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
2475 print_test_error("status-message (text(255)) has wrong value tag "
2476 "%s (RFC 2911 section 3.1.6.2).",
2477 ippTagString(attrptr
->value_tag
));
2478 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
2479 print_test_error("status-message (text(255)) has wrong group tag "
2480 "%s (RFC 2911 section 3.1.6.2).",
2481 ippTagString(attrptr
->group_tag
));
2482 if (attrptr
->num_values
!= 1)
2483 print_test_error("status-message (text(255)) has %d values "
2484 "(RFC 2911 section 3.1.6.2).",
2485 attrptr
->num_values
);
2486 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2487 strlen(attrptr
->values
[0].string
.text
) > 255)
2488 print_test_error("status-message (text(255)) has bad length %d"
2489 " (RFC 2911 section 3.1.6.2).",
2490 (int)strlen(attrptr
->values
[0].string
.text
));
2493 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
2494 IPP_TAG_ZERO
)) != NULL
)
2496 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
2497 print_test_error("detailed-status-message (text(MAX)) has wrong "
2498 "value tag %s (RFC 2911 section 3.1.6.3).",
2499 ippTagString(attrptr
->value_tag
));
2500 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
2501 print_test_error("detailed-status-message (text(MAX)) has wrong "
2502 "group tag %s (RFC 2911 section 3.1.6.3).",
2503 ippTagString(attrptr
->group_tag
));
2504 if (attrptr
->num_values
!= 1)
2505 print_test_error("detailed-status-message (text(MAX)) has %d values"
2506 " (RFC 2911 section 3.1.6.3).",
2507 attrptr
->num_values
);
2508 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2509 strlen(attrptr
->values
[0].string
.text
) > 1023)
2510 print_test_error("detailed-status-message (text(MAX)) has bad "
2511 "length %d (RFC 2911 section 3.1.6.3).",
2512 (int)strlen(attrptr
->values
[0].string
.text
));
2515 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
2517 attrptr
= attrptr
->next
)
2519 if (attrptr
->group_tag
< group
&& attrptr
->group_tag
!= IPP_TAG_ZERO
)
2520 print_test_error("Attribute groups out of order (%s < %s)",
2521 ippTagString(attrptr
->group_tag
),
2522 ippTagString(group
));
2524 validate_attr(attrptr
, 1);
2527 for (i
= 0; i
< num_statuses
; i
++)
2529 if (statuses
[i
].if_defined
&&
2530 !get_variable(vars
, statuses
[i
].if_defined
))
2533 if (statuses
[i
].if_not_defined
&&
2534 get_variable(vars
, statuses
[i
].if_not_defined
))
2537 if (response
->request
.status
.status_code
== statuses
[i
].status
)
2541 if (i
== num_statuses
&& num_statuses
> 0)
2543 for (i
= 0; i
< num_statuses
; i
++)
2545 if (statuses
[i
].if_defined
&&
2546 !get_variable(vars
, statuses
[i
].if_defined
))
2549 if (statuses
[i
].if_not_defined
&&
2550 get_variable(vars
, statuses
[i
].if_not_defined
))
2553 print_test_error("EXPECTED: STATUS %s (got %s)",
2554 ippErrorString(statuses
[i
].status
),
2555 ippErrorString(cupsLastError()));
2558 if ((attrptr
= ippFindAttribute(response
, "status-message",
2559 IPP_TAG_TEXT
)) != NULL
)
2560 print_test_error("status-message=\"%s\"",
2561 attrptr
->values
[0].string
.text
);
2564 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2566 if (expect
->define_match
|| expect
->define_no_match
)
2569 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
2572 if (expect
->if_not_defined
&&
2573 get_variable(vars
, expect
->if_not_defined
))
2576 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
2578 if (found
&& expect
->not_expect
)
2579 print_test_error("NOT EXPECTED: %s", expect
->name
);
2580 else if (!found
&& !(expect
->not_expect
|| expect
->optional
))
2581 print_test_error("EXPECTED: %s", expect
->name
);
2584 if (!expect_matches(expect
, found
->value_tag
))
2585 print_test_error("EXPECTED: %s OF-TYPE %s (got %s)",
2586 expect
->name
, expect
->of_type
,
2587 ippTagString(found
->value_tag
));
2589 if (expect
->in_group
&& found
->group_tag
!= expect
->in_group
)
2590 print_test_error("EXPECTED: %s IN-GROUP %s (got %s).",
2591 expect
->name
, ippTagString(expect
->in_group
),
2592 ippTagString(found
->group_tag
));
2594 if (!with_value(expect
->with_value
, expect
->with_regex
, found
, 0))
2596 if (expect
->with_regex
)
2597 print_test_error("EXPECTED: %s WITH-VALUE /%s/",
2598 expect
->name
, expect
->with_value
);
2600 print_test_error("EXPECTED: %s WITH-VALUE \"%s\"",
2601 expect
->name
, expect
->with_value
);
2603 with_value(expect
->with_value
, expect
->with_regex
, found
, 1);
2606 if (expect
->count
> 0 && found
->num_values
!= expect
->count
)
2608 print_test_error("EXPECTED: %s COUNT %d (got %d)", expect
->name
,
2609 expect
->count
, found
->num_values
);
2612 if (expect
->same_count_as
)
2614 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
2618 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
2619 "(not returned)", expect
->name
,
2620 found
->num_values
, expect
->same_count_as
);
2621 else if (attrptr
->num_values
!= found
->num_values
)
2622 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
2623 "(%d values)", expect
->name
, found
->num_values
,
2624 expect
->same_count_as
, attrptr
->num_values
);
2630 if (Output
== _CUPS_OUTPUT_PLIST
)
2636 if (Output
== _CUPS_OUTPUT_PLIST
)
2639 ippDelete(response
);
2642 for (i
= 0; i
< num_statuses
; i
++)
2644 if (statuses
[i
].if_defined
)
2645 free(statuses
[i
].if_defined
);
2646 if (statuses
[i
].if_not_defined
)
2647 free(statuses
[i
].if_not_defined
);
2651 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2654 if (expect
->of_type
)
2655 free(expect
->of_type
);
2656 if (expect
->same_count_as
)
2657 free(expect
->same_count_as
);
2658 if (expect
->if_defined
)
2659 free(expect
->if_defined
);
2660 if (expect
->if_not_defined
)
2661 free(expect
->if_not_defined
);
2662 if (expect
->with_value
)
2663 free(expect
->with_value
);
2664 if (expect
->define_match
)
2665 free(expect
->define_match
);
2666 if (expect
->define_no_match
)
2667 free(expect
->define_no_match
);
2668 if (expect
->define_value
)
2669 free(expect
->define_value
);
2673 for (i
= 0; i
< num_displayed
; i
++)
2677 if (!ignore_errors
&& !prev_pass
)
2688 ippDelete(response
);
2690 for (i
= 0; i
< num_statuses
; i
++)
2692 if (statuses
[i
].if_defined
)
2693 free(statuses
[i
].if_defined
);
2694 if (statuses
[i
].if_not_defined
)
2695 free(statuses
[i
].if_not_defined
);
2698 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2701 if (expect
->of_type
)
2702 free(expect
->of_type
);
2703 if (expect
->same_count_as
)
2704 free(expect
->same_count_as
);
2705 if (expect
->if_defined
)
2706 free(expect
->if_defined
);
2707 if (expect
->if_not_defined
)
2708 free(expect
->if_not_defined
);
2709 if (expect
->with_value
)
2710 free(expect
->with_value
);
2711 if (expect
->define_match
)
2712 free(expect
->define_match
);
2713 if (expect
->define_no_match
)
2714 free(expect
->define_no_match
);
2715 if (expect
->define_value
)
2716 free(expect
->define_value
);
2719 for (i
= 0; i
< num_displayed
; i
++)
2727 * 'expand_variables()' - Expand variables in a string.
2731 expand_variables(_cups_vars_t
*vars
, /* I - Variables */
2732 char *dst
, /* I - Destination string buffer */
2733 const char *src
, /* I - Source string */
2734 size_t dstsize
) /* I - Size of destination buffer */
2736 char *dstptr
, /* Pointer into destination */
2737 *dstend
, /* End of destination */
2738 temp
[256], /* Temporary string */
2739 *tempptr
; /* Pointer into temporary string */
2740 const char *value
; /* Value to substitute */
2744 dstend
= dst
+ dstsize
- 1;
2746 while (*src
&& dstptr
< dstend
)
2751 * Substitute a string/number...
2754 if (!strncmp(src
, "$$", 2))
2759 else if (!strncmp(src
, "$ENV[", 5))
2761 strlcpy(temp
, src
+ 5, sizeof(temp
));
2763 for (tempptr
= temp
; *tempptr
; tempptr
++)
2764 if (*tempptr
== ']')
2770 value
= getenv(temp
);
2771 src
+= tempptr
- temp
+ 5;
2775 strlcpy(temp
, src
+ 1, sizeof(temp
));
2777 for (tempptr
= temp
; *tempptr
; tempptr
++)
2778 if (!isalnum(*tempptr
& 255) && *tempptr
!= '-' && *tempptr
!= '_')
2784 if (!strcmp(temp
, "uri"))
2786 else if (!strcmp(temp
, "filename"))
2787 value
= vars
->filename
;
2788 else if (!strcmp(temp
, "scheme") || !strcmp(temp
, "method"))
2789 value
= vars
->scheme
;
2790 else if (!strcmp(temp
, "username"))
2791 value
= vars
->userpass
;
2792 else if (!strcmp(temp
, "hostname"))
2793 value
= vars
->hostname
;
2794 else if (!strcmp(temp
, "port"))
2796 snprintf(temp
, sizeof(temp
), "%d", vars
->port
);
2799 else if (!strcmp(temp
, "resource"))
2800 value
= vars
->resource
;
2801 else if (!strcmp(temp
, "user"))
2804 value
= get_variable(vars
, temp
);
2806 src
+= tempptr
- temp
+ 1;
2816 strlcpy(dstptr
, value
, dstend
- dstptr
+ 1);
2817 dstptr
+= strlen(dstptr
);
2829 * 'expect_matches()' - Return true if the tag matches the specification.
2832 static int /* O - 1 if matches, 0 otherwise */
2834 _cups_expect_t
*expect
, /* I - Expected attribute */
2835 ipp_tag_t value_tag
) /* I - Value tag for attribute */
2837 int match
; /* Match? */
2838 char *of_type
, /* Type name to match */
2839 *next
, /* Next name to match */
2840 sep
; /* Separator character */
2844 * If we don't expect a particular type, return immediately...
2847 if (!expect
->of_type
)
2851 * Parse the "of_type" value since the string can contain multiple attribute
2852 * types separated by "," or "|"...
2855 for (of_type
= expect
->of_type
, match
= 0; !match
&& *of_type
; of_type
= next
)
2858 * Find the next separator, and set it (temporarily) to nul if present.
2861 for (next
= of_type
; *next
&& *next
!= '|' && *next
!= ','; next
++);
2863 if ((sep
= *next
) != '\0')
2867 * Support some meta-types to make it easier to write the test file.
2870 if (!strcmp(of_type
, "text"))
2871 match
= value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_TEXT
;
2872 else if (!strcmp(of_type
, "name"))
2873 match
= value_tag
== IPP_TAG_NAMELANG
|| value_tag
== IPP_TAG_NAME
;
2874 else if (!strcmp(of_type
, "collection"))
2875 match
= value_tag
== IPP_TAG_BEGIN_COLLECTION
;
2877 match
= value_tag
== ippTagValue(of_type
);
2880 * Restore the separator if we have one...
2892 * 'get_collection()' - Get a collection value from the current test file.
2895 static ipp_t
* /* O - Collection value */
2896 get_collection(_cups_vars_t
*vars
, /* I - Variables */
2897 FILE *fp
, /* I - File to read from */
2898 int *linenum
) /* IO - Line number */
2900 char token
[1024], /* Token from file */
2901 temp
[1024], /* Temporary string */
2902 attr
[128]; /* Attribute name */
2903 ipp_tag_t value
; /* Current value type */
2904 ipp_t
*col
= ippNew(); /* Collection value */
2905 ipp_attribute_t
*lastcol
= NULL
; /* Last collection attribute */
2908 while (get_token(fp
, token
, sizeof(token
), linenum
) != NULL
)
2910 if (!strcmp(token
, "}"))
2912 else if (!strcmp(token
, "{") && lastcol
)
2915 * Another collection value
2918 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
2919 /* Collection value */
2923 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
2927 * Reallocate memory...
2930 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
2931 (lastcol
->num_values
+ 1) *
2932 sizeof(ipp_value_t
))) == NULL
)
2934 print_fatal_error("Unable to allocate memory on line %d.", *linenum
);
2938 if (tempcol
!= lastcol
)
2941 * Reset pointers in the list...
2945 col
->prev
->next
= tempcol
;
2947 col
->attrs
= tempcol
;
2949 lastcol
= col
->current
= col
->last
= tempcol
;
2952 lastcol
->values
[lastcol
->num_values
].collection
= subcol
;
2953 lastcol
->num_values
++;
2958 else if (!_cups_strcasecmp(token
, "MEMBER"))
2966 if (!get_token(fp
, token
, sizeof(token
), linenum
))
2968 print_fatal_error("Missing MEMBER value tag on line %d.", *linenum
);
2972 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
2974 print_fatal_error("Bad MEMBER value tag \"%s\" on line %d.", token
,
2979 if (!get_token(fp
, attr
, sizeof(attr
), linenum
))
2981 print_fatal_error("Missing MEMBER name on line %d.", *linenum
);
2985 if (!get_token(fp
, temp
, sizeof(temp
), linenum
))
2987 print_fatal_error("Missing MEMBER value on line %d.", *linenum
);
2991 expand_variables(vars
, token
, temp
, sizeof(token
));
2995 case IPP_TAG_BOOLEAN
:
2996 if (!_cups_strcasecmp(token
, "true"))
2997 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, 1);
2999 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, atoi(token
));
3002 case IPP_TAG_INTEGER
:
3004 ippAddInteger(col
, IPP_TAG_ZERO
, value
, attr
, atoi(token
));
3007 case IPP_TAG_RESOLUTION
:
3009 int xres
, /* X resolution */
3010 yres
; /* Y resolution */
3011 char units
[6]; /* Units */
3013 if (sscanf(token
, "%dx%d%5s", &xres
, &yres
, units
) != 3 ||
3014 (_cups_strcasecmp(units
, "dpi") && _cups_strcasecmp(units
, "dpc") &&
3015 _cups_strcasecmp(units
, "other")))
3017 print_fatal_error("Bad resolution value \"%s\" on line %d.",
3022 if (!_cups_strcasecmp(units
, "dpi"))
3023 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
3025 else if (!_cups_strcasecmp(units
, "dpc"))
3026 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
3029 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
3034 case IPP_TAG_RANGE
:
3036 int lowers
[4], /* Lower value */
3037 uppers
[4], /* Upper values */
3038 num_vals
; /* Number of values */
3041 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
3042 lowers
+ 0, uppers
+ 0,
3043 lowers
+ 1, uppers
+ 1,
3044 lowers
+ 2, uppers
+ 2,
3045 lowers
+ 3, uppers
+ 3);
3047 if ((num_vals
& 1) || num_vals
== 0)
3049 print_fatal_error("Bad rangeOfInteger value \"%s\" on line %d.",
3054 ippAddRanges(col
, IPP_TAG_ZERO
, attr
, num_vals
/ 2, lowers
,
3059 case IPP_TAG_BEGIN_COLLECTION
:
3060 if (!strcmp(token
, "{"))
3062 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
3063 /* Collection value */
3067 lastcol
= ippAddCollection(col
, IPP_TAG_ZERO
, attr
, subcol
);
3075 print_fatal_error("Bad collection value on line %d.", *linenum
);
3081 if (!strchr(token
, ','))
3082 ippAddString(col
, IPP_TAG_ZERO
, value
, attr
, NULL
, token
);
3086 * Multiple string values...
3089 int num_values
; /* Number of values */
3090 char *values
[100], /* Values */
3091 *ptr
; /* Pointer to next value */
3097 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
3100 values
[num_values
] = ptr
;
3104 ippAddStrings(col
, IPP_TAG_ZERO
, value
, attr
, num_values
,
3105 NULL
, (const char **)values
);
3115 * If we get here there was a parse error; free memory and return.
3127 * 'get_filename()' - Get a filename based on the current test file.
3130 static char * /* O - Filename */
3131 get_filename(const char *testfile
, /* I - Current test file */
3132 char *dst
, /* I - Destination filename */
3133 const char *src
, /* I - Source filename */
3134 size_t dstsize
) /* I - Size of destination buffer */
3136 char *dstptr
; /* Pointer into destination */
3137 _cups_globals_t
*cg
= _cupsGlobals();
3141 if (*src
== '<' && src
[strlen(src
) - 1] == '>')
3144 * Map <filename> to CUPS_DATADIR/ipptool/filename...
3147 snprintf(dst
, dstsize
, "%s/ipptool/%s", cg
->cups_datadir
, src
+ 1);
3148 dstptr
= dst
+ strlen(dst
) - 1;
3152 else if (*src
== '/' || !strchr(testfile
, '/'))
3155 * Use the path as-is...
3158 strlcpy(dst
, src
, dstsize
);
3163 * Make path relative to testfile...
3166 strlcpy(dst
, testfile
, dstsize
);
3167 if ((dstptr
= strrchr(dst
, '/')) != NULL
)
3170 dstptr
= dst
; /* Should never happen */
3172 strlcpy(dstptr
, src
, dstsize
- (dstptr
- dst
));
3180 * 'get_token()' - Get a token from a file.
3183 static char * /* O - Token from file or NULL on EOF */
3184 get_token(FILE *fp
, /* I - File to read from */
3185 char *buf
, /* I - Buffer to read into */
3186 int buflen
, /* I - Length of buffer */
3187 int *linenum
) /* IO - Current line number */
3189 int ch
, /* Character from file */
3190 quote
; /* Quoting character */
3191 char *bufptr
, /* Pointer into buffer */
3192 *bufend
; /* End of buffer */
3198 * Skip whitespace...
3201 while (isspace(ch
= getc(fp
)))
3213 else if (ch
== '\'' || ch
== '\"')
3216 * Quoted text or regular expression...
3221 bufend
= buf
+ buflen
- 1;
3223 while ((ch
= getc(fp
)) != EOF
)
3228 * Escape next character...
3231 if (bufptr
< bufend
)
3234 if ((ch
= getc(fp
)) != EOF
&& bufptr
< bufend
)
3237 else if (ch
== quote
)
3239 else if (bufptr
< bufend
)
3253 while ((ch
= getc(fp
)) != EOF
)
3262 * Whitespace delimited text...
3268 bufend
= buf
+ buflen
- 1;
3270 while ((ch
= getc(fp
)) != EOF
)
3271 if (isspace(ch
) || ch
== '#')
3273 else if (bufptr
< bufend
)
3278 else if (ch
== '\n')
3290 * 'get_variable()' - Get the value of a variable.
3293 static char * /* O - Value or NULL */
3294 get_variable(_cups_vars_t
*vars
, /* I - Variables */
3295 const char *name
) /* I - Variable name */
3297 _cups_var_t key
, /* Search key */
3298 *match
; /* Matching variable, if any */
3301 key
.name
= (char *)name
;
3302 match
= cupsArrayFind(vars
->vars
, &key
);
3304 return (match
? match
->value
: NULL
);
3309 * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
3313 static char * /* O - ISO 8601 date/time string */
3314 iso_date(ipp_uchar_t
*date
) /* I - IPP (RFC 1903) date/time value */
3316 time_t utctime
; /* UTC time since 1970 */
3317 struct tm
*utcdate
; /* UTC date/time */
3318 static char buffer
[255]; /* String buffer */
3321 utctime
= ippDateToTime(date
);
3322 utcdate
= gmtime(&utctime
);
3324 snprintf(buffer
, sizeof(buffer
), "%04d-%02d-%02dT%02d:%02d:%02dZ",
3325 utcdate
->tm_year
+ 1900, utcdate
->tm_mon
+ 1, utcdate
->tm_mday
,
3326 utcdate
->tm_hour
, utcdate
->tm_min
, utcdate
->tm_sec
);
3333 * 'password_cb()' - Password callback for authenticated tests.
3336 static const char * /* O - Password */
3337 password_cb(const char *prompt
) /* I - Prompt (unused) */
3346 * 'print_attr()' - Print an attribute on the screen.
3350 print_attr(ipp_attribute_t
*attr
, /* I - Attribute to print */
3351 ipp_tag_t
*group
) /* IO - Current group */
3353 int i
; /* Looping var */
3354 ipp_attribute_t
*colattr
; /* Collection attribute */
3357 if (Output
== _CUPS_OUTPUT_PLIST
)
3359 if (!attr
->name
|| (group
&& *group
!= attr
->group_tag
))
3365 *group
= attr
->group_tag
;
3371 print_xml_string("key", attr
->name
);
3372 if (attr
->num_values
> 1)
3375 else if (Output
== _CUPS_OUTPUT_TEST
)
3379 puts(" -- separator --");
3383 printf(" %s (%s%s) = ", attr
->name
,
3384 attr
->num_values
> 1 ? "1setOf " : "",
3385 ippTagString(attr
->value_tag
));
3388 switch (attr
->value_tag
)
3390 case IPP_TAG_INTEGER
:
3392 for (i
= 0; i
< attr
->num_values
; i
++)
3393 if (Output
== _CUPS_OUTPUT_PLIST
)
3394 printf("<integer>%d</integer>\n", attr
->values
[i
].integer
);
3396 printf("%d ", attr
->values
[i
].integer
);
3399 case IPP_TAG_BOOLEAN
:
3400 for (i
= 0; i
< attr
->num_values
; i
++)
3401 if (Output
== _CUPS_OUTPUT_PLIST
)
3402 puts(attr
->values
[i
].boolean
? "<true />" : "<false />");
3403 else if (attr
->values
[i
].boolean
)
3404 fputs("true ", stdout
);
3406 fputs("false ", stdout
);
3409 case IPP_TAG_RANGE
:
3410 for (i
= 0; i
< attr
->num_values
; i
++)
3411 if (Output
== _CUPS_OUTPUT_PLIST
)
3412 printf("<dict><key>lower</key><integer>%d</integer>"
3413 "<key>upper</key><integer>%d</integer></dict>\n",
3414 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
3416 printf("%d-%d ", attr
->values
[i
].range
.lower
,
3417 attr
->values
[i
].range
.upper
);
3420 case IPP_TAG_RESOLUTION
:
3421 for (i
= 0; i
< attr
->num_values
; i
++)
3422 if (Output
== _CUPS_OUTPUT_PLIST
)
3423 printf("<dict><key>xres</key><integer>%d</integer>"
3424 "<key>yres</key><integer>%d</integer>"
3425 "<key>units</key><string>%s</string></dict>\n",
3426 attr
->values
[i
].resolution
.xres
,
3427 attr
->values
[i
].resolution
.yres
,
3428 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3431 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
3432 attr
->values
[i
].resolution
.yres
,
3433 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3438 for (i
= 0; i
< attr
->num_values
; i
++)
3439 if (Output
== _CUPS_OUTPUT_PLIST
)
3440 printf("<date>%s</date>\n", iso_date(attr
->values
[i
].date
));
3442 printf("%s ", iso_date(attr
->values
[i
].date
));
3445 case IPP_TAG_STRING
:
3448 case IPP_TAG_KEYWORD
:
3449 case IPP_TAG_CHARSET
:
3451 case IPP_TAG_MIMETYPE
:
3452 case IPP_TAG_LANGUAGE
:
3453 for (i
= 0; i
< attr
->num_values
; i
++)
3454 if (Output
== _CUPS_OUTPUT_PLIST
)
3455 print_xml_string("string", attr
->values
[i
].string
.text
);
3457 printf("\"%s\" ", attr
->values
[i
].string
.text
);
3460 case IPP_TAG_TEXTLANG
:
3461 case IPP_TAG_NAMELANG
:
3462 for (i
= 0; i
< attr
->num_values
; i
++)
3463 if (Output
== _CUPS_OUTPUT_PLIST
)
3465 fputs("<dict><key>language</key><string>", stdout
);
3466 print_xml_string(NULL
, attr
->values
[i
].string
.charset
);
3467 fputs("</string><key>string</key><string>", stdout
);
3468 print_xml_string(NULL
, attr
->values
[i
].string
.text
);
3469 puts("</string></dict>");
3472 printf("\"%s\"(%s) ", attr
->values
[i
].string
.text
,
3473 attr
->values
[i
].string
.charset
);
3476 case IPP_TAG_BEGIN_COLLECTION
:
3477 for (i
= 0; i
< attr
->num_values
; i
++)
3479 if (Output
== _CUPS_OUTPUT_PLIST
)
3482 for (colattr
= attr
->values
[i
].collection
->attrs
;
3484 colattr
= colattr
->next
)
3485 print_attr(colattr
, NULL
);
3493 print_col(attr
->values
[i
].collection
);
3499 if (Output
== _CUPS_OUTPUT_PLIST
)
3500 printf("<string><<%s>></string>\n",
3501 ippTagString(attr
->value_tag
));
3503 fputs(ippTagString(attr
->value_tag
), stdout
);
3507 if (Output
== _CUPS_OUTPUT_PLIST
)
3509 if (attr
->num_values
> 1)
3518 * 'print_col()' - Print a collection attribute on the screen.
3522 print_col(ipp_t
*col
) /* I - Collection attribute to print */
3524 int i
; /* Looping var */
3525 ipp_attribute_t
*attr
; /* Current attribute in collection */
3528 fputs("{ ", stdout
);
3529 for (attr
= col
->attrs
; attr
; attr
= attr
->next
)
3531 printf("%s (%s%s) = ", attr
->name
, attr
->num_values
> 1 ? "1setOf " : "",
3532 ippTagString(attr
->value_tag
));
3534 switch (attr
->value_tag
)
3536 case IPP_TAG_INTEGER
:
3538 for (i
= 0; i
< attr
->num_values
; i
++)
3539 printf("%d ", attr
->values
[i
].integer
);
3542 case IPP_TAG_BOOLEAN
:
3543 for (i
= 0; i
< attr
->num_values
; i
++)
3544 if (attr
->values
[i
].boolean
)
3550 case IPP_TAG_NOVALUE
:
3554 case IPP_TAG_RANGE
:
3555 for (i
= 0; i
< attr
->num_values
; i
++)
3556 printf("%d-%d ", attr
->values
[i
].range
.lower
,
3557 attr
->values
[i
].range
.upper
);
3560 case IPP_TAG_RESOLUTION
:
3561 for (i
= 0; i
< attr
->num_values
; i
++)
3562 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
3563 attr
->values
[i
].resolution
.yres
,
3564 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3568 case IPP_TAG_STRING
:
3571 case IPP_TAG_KEYWORD
:
3572 case IPP_TAG_CHARSET
:
3574 case IPP_TAG_MIMETYPE
:
3575 case IPP_TAG_LANGUAGE
:
3576 for (i
= 0; i
< attr
->num_values
; i
++)
3577 printf("\"%s\" ", attr
->values
[i
].string
.text
);
3580 case IPP_TAG_TEXTLANG
:
3581 case IPP_TAG_NAMELANG
:
3582 for (i
= 0; i
< attr
->num_values
; i
++)
3583 printf("\"%s\",%s ", attr
->values
[i
].string
.text
,
3584 attr
->values
[i
].string
.charset
);
3587 case IPP_TAG_BEGIN_COLLECTION
:
3588 for (i
= 0; i
< attr
->num_values
; i
++)
3590 print_col(attr
->values
[i
].collection
);
3596 break; /* anti-compiler-warning-code */
3605 * 'print_csv()' - Print a line of CSV text.
3610 ipp_attribute_t
*attr
, /* I - First attribute for line */
3611 int num_displayed
, /* I - Number of attributes to display */
3612 char **displayed
, /* I - Attributes to display */
3613 size_t *widths
) /* I - Column widths */
3615 int i
; /* Looping var */
3616 size_t maxlength
; /* Max length of all columns */
3617 char *buffer
, /* String buffer */
3618 *bufptr
; /* Pointer into buffer */
3619 ipp_attribute_t
*current
; /* Current attribute */
3623 * Get the maximum string length we have to show and allocate...
3626 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
3627 if (widths
[i
] > maxlength
)
3628 maxlength
= widths
[i
];
3632 if ((buffer
= malloc(maxlength
)) == NULL
)
3636 * Loop through the attributes to display...
3641 for (i
= 0; i
< num_displayed
; i
++)
3648 for (current
= attr
; current
; current
= current
->next
)
3652 else if (!strcmp(current
->name
, displayed
[i
]))
3654 _ippAttrString(current
, buffer
, maxlength
);
3659 if (strchr(buffer
, ',') != NULL
|| strchr(buffer
, '\"') != NULL
||
3660 strchr(buffer
, '\\') != NULL
)
3663 for (bufptr
= buffer
; *bufptr
; bufptr
++)
3665 if (*bufptr
== '\\' || *bufptr
== '\"')
3672 fputs(buffer
, stdout
);
3678 for (i
= 0; i
< num_displayed
; i
++)
3683 fputs(displayed
[i
], stdout
);
3693 * 'print_fatal_error()' - Print a fatal error message.
3697 print_fatal_error(const char *s
, /* I - Printf-style format string */
3698 ...) /* I - Additional arguments as needed */
3700 char buffer
[10240]; /* Format buffer */
3701 va_list ap
; /* Pointer to arguments */
3705 * Format the error message...
3709 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
3716 if (Output
== _CUPS_OUTPUT_PLIST
)
3719 print_xml_trailer(0, buffer
);
3722 _cupsLangPrintf(stderr
, "ipptool: %s", buffer
);
3727 * 'print_line()' - Print a line of formatted or CSV text.
3732 ipp_attribute_t
*attr
, /* I - First attribute for line */
3733 int num_displayed
, /* I - Number of attributes to display */
3734 char **displayed
, /* I - Attributes to display */
3735 size_t *widths
) /* I - Column widths */
3737 int i
; /* Looping var */
3738 size_t maxlength
; /* Max length of all columns */
3739 char *buffer
; /* String buffer */
3740 ipp_attribute_t
*current
; /* Current attribute */
3744 * Get the maximum string length we have to show and allocate...
3747 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
3748 if (widths
[i
] > maxlength
)
3749 maxlength
= widths
[i
];
3753 if ((buffer
= malloc(maxlength
)) == NULL
)
3757 * Loop through the attributes to display...
3762 for (i
= 0; i
< num_displayed
; i
++)
3769 for (current
= attr
; current
; current
= current
->next
)
3773 else if (!strcmp(current
->name
, displayed
[i
]))
3775 _ippAttrString(current
, buffer
, maxlength
);
3780 printf("%*s", (int)-widths
[i
], buffer
);
3786 for (i
= 0; i
< num_displayed
; i
++)
3791 printf("%*s", (int)-widths
[i
], displayed
[i
]);
3795 for (i
= 0; i
< num_displayed
; i
++)
3800 memset(buffer
, '-', widths
[i
]);
3801 buffer
[widths
[i
]] = '\0';
3802 fputs(buffer
, stdout
);
3812 * 'print_test_error()' - Print a test error message.
3816 print_test_error(const char *s
, /* I - Printf-style format string */
3817 ...) /* I - Additional arguments as needed */
3819 char buffer
[10240]; /* Format buffer */
3820 va_list ap
; /* Pointer to arguments */
3824 * Format the error message...
3828 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
3835 if (Output
== _CUPS_OUTPUT_PLIST
)
3836 print_xml_string("string", buffer
);
3838 printf(" %s\n", buffer
);
3843 * 'print_xml_header()' - Print a standard XML plist header.
3847 print_xml_header(void)
3851 puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
3852 puts("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
3853 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
3854 puts("<plist version=\"1.0\">");
3856 puts("<key>Transfer</key>");
3857 printf("<string>%s</string>\n",
3858 Transfer
== _CUPS_TRANSFER_AUTO
? "auto" :
3859 Transfer
== _CUPS_TRANSFER_CHUNKED
? "chunked" : "length");
3860 puts("<key>Tests</key>");
3869 * 'print_xml_string()' - Print an XML string with escaping.
3873 print_xml_string(const char *element
, /* I - Element name or NULL */
3874 const char *s
) /* I - String to print */
3877 printf("<%s>", element
);
3882 fputs("&", stdout
);
3884 fputs("<", stdout
);
3886 fputs(">", stdout
);
3887 else if ((*s
& 0xe0) == 0xc0)
3890 * Validate UTF-8 two-byte sequence...
3893 if ((s
[1] & 0xc0) != 0x80)
3904 else if ((*s
& 0xf0) == 0xe0)
3907 * Validate UTF-8 three-byte sequence...
3910 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80)
3922 else if ((*s
& 0xf8) == 0xf0)
3925 * Validate UTF-8 four-byte sequence...
3928 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80 ||
3929 (s
[3] & 0xc0) != 0x80)
3942 else if ((*s
& 0x80) || (*s
< ' ' && !isspace(*s
& 255)))
3945 * Invalid control character...
3957 printf("</%s>\n", element
);
3962 * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
3966 print_xml_trailer(int success
, /* I - 1 on success, 0 on failure */
3967 const char *message
) /* I - Error message or NULL */
3972 puts("<key>Successful</key>");
3973 puts(success
? "<true />" : "<false />");
3976 puts("<key>ErrorMessage</key>");
3977 print_xml_string("string", message
);
3988 * 'set_variable()' - Set a variable value.
3992 set_variable(_cups_vars_t
*vars
, /* I - Variables */
3993 const char *name
, /* I - Variable name */
3994 const char *value
) /* I - Value string */
3996 _cups_var_t key
, /* Search key */
3997 *var
; /* New variable */
4000 key
.name
= (char *)name
;
4001 if ((var
= cupsArrayFind(vars
->vars
, &key
)) != NULL
)
4004 var
->value
= strdup(value
);
4006 else if ((var
= malloc(sizeof(_cups_var_t
))) == NULL
)
4008 print_fatal_error("Unable to allocate memory for variable \"%s\".", name
);
4013 var
->name
= strdup(name
);
4014 var
->value
= strdup(value
);
4016 cupsArrayAdd(vars
->vars
, var
);
4022 * 'sigterm_handler()' - Handle SIGINT and SIGTERM.
4026 sigterm_handler(int sig
) /* I - Signal number (unused) */
4035 * 'timeout_cb()' - Handle HTTP timeouts.
4038 static int /* O - 1 to continue, 0 to cancel */
4039 timeout_cb(http_t
*http
, /* I - Connection to server (unused) */
4040 void *user_data
) /* I - User data (unused) */
4045 /* Always cancel on timeout */
4051 * 'usage()' - Show program usage.
4057 _cupsLangPuts(stderr
, _("Usage: ipptool [options] URI filename [ ... "
4059 _cupsLangPuts(stderr
, _("Options:"));
4060 _cupsLangPuts(stderr
, _(" -4 Connect using IPv4."));
4061 _cupsLangPuts(stderr
, _(" -6 Connect using IPv6."));
4062 _cupsLangPuts(stderr
, _(" -C Send requests using "
4063 "chunking (default)."));
4064 _cupsLangPuts(stderr
, _(" -E Test with TLS "
4066 _cupsLangPuts(stderr
, _(" -I Ignore errors."));
4067 _cupsLangPuts(stderr
, _(" -L Send requests using "
4068 "content-length."));
4069 _cupsLangPuts(stderr
, _(" -S Test with SSL "
4071 _cupsLangPuts(stderr
, _(" -T Set the receive/send "
4072 "timeout in seconds."));
4073 _cupsLangPuts(stderr
, _(" -V version Set default IPP "
4075 _cupsLangPuts(stderr
, _(" -X Produce XML plist instead "
4077 _cupsLangPuts(stderr
, _(" -d name=value Set named variable to "
4079 _cupsLangPuts(stderr
, _(" -f filename Set default request "
4081 _cupsLangPuts(stderr
, _(" -i seconds Repeat the last file with "
4082 "the given time interval."));
4083 _cupsLangPuts(stderr
, _(" -n count Repeat the last file the "
4084 "given number of times."));
4085 _cupsLangPuts(stderr
, _(" -q Be quiet - no output "
4087 _cupsLangPuts(stderr
, _(" -t Produce a test report."));
4088 _cupsLangPuts(stderr
, _(" -v Show all attributes sent "
4096 * 'validate_attr()' - Determine whether an attribute is valid.
4099 static int /* O - 1 if valid, 0 otherwise */
4100 validate_attr(ipp_attribute_t
*attr
, /* I - Attribute to validate */
4101 int print
) /* I - 1 = report issues to stdout */
4103 int i
; /* Looping var */
4104 char scheme
[64], /* Scheme from URI */
4105 userpass
[256], /* Username/password from URI */
4106 hostname
[256], /* Hostname from URI */
4107 resource
[1024]; /* Resource from URI */
4108 int port
, /* Port number from URI */
4109 uri_status
, /* URI separation status */
4110 valid
= 1; /* Is the attribute valid? */
4111 const char *ptr
; /* Pointer into string */
4112 ipp_attribute_t
*colattr
; /* Collection attribute */
4113 regex_t re
; /* Regular expression */
4114 ipp_uchar_t
*date
; /* Current date value */
4125 * Validate the attribute name.
4128 for (ptr
= attr
->name
; *ptr
; ptr
++)
4129 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
4132 if (*ptr
|| ptr
== attr
->name
)
4137 print_test_error("\"%s\": Bad attribute name - invalid character (RFC "
4138 "2911 section 4.1.3).", attr
->name
);
4141 if ((ptr
- attr
->name
) > 255)
4146 print_test_error("\"%s\": Bad attribute name - bad length (RFC 2911 "
4147 "section 4.1.3).", attr
->name
);
4150 switch (attr
->value_tag
)
4152 case IPP_TAG_INTEGER
:
4155 case IPP_TAG_BOOLEAN
:
4156 for (i
= 0; i
< attr
->num_values
; i
++)
4158 if (attr
->values
[i
].boolean
!= 0 &&
4159 attr
->values
[i
].boolean
!= 1)
4164 print_test_error("\"%s\": Bad boolen value %d (RFC 2911 section "
4165 "4.1.10).", attr
->name
, attr
->values
[i
].boolean
);
4173 for (i
= 0; i
< attr
->num_values
; i
++)
4175 if (attr
->values
[i
].integer
< 1)
4180 print_test_error("\"%s\": Bad enum value %d - out of range "
4181 "(RFC 2911 section 4.1.4).", attr
->name
,
4182 attr
->values
[i
].integer
);
4189 case IPP_TAG_STRING
:
4190 for (i
= 0; i
< attr
->num_values
; i
++)
4192 if (attr
->values
[i
].unknown
.length
> 1023)
4197 print_test_error("\"%s\": Bad octetString value - bad length %d "
4198 "(RFC 2911 section 4.1.10).", attr
->name
,
4199 attr
->values
[i
].unknown
.length
);
4207 for (i
= 0; i
< attr
->num_values
; i
++)
4209 date
= attr
->values
[i
].date
;
4211 if (date
[2] < 1 || date
[2] > 12)
4216 print_test_error("\"%s\": Bad dateTime month %u (RFC 2911 "
4217 "section 4.1.13).", attr
->name
, date
[2]);
4222 if (date
[3] < 1 || date
[3] > 31)
4227 print_test_error("\"%s\": Bad dateTime day %u (RFC 2911 "
4228 "section 4.1.13).", attr
->name
, date
[3]);
4238 print_test_error("\"%s\": Bad dateTime hours %u (RFC 2911 "
4239 "section 4.1.13).", attr
->name
, date
[4]);
4249 print_test_error("\"%s\": Bad dateTime minutes %u (RFC 2911 "
4250 "section 4.1.13).", attr
->name
, date
[5]);
4260 print_test_error("\"%s\": Bad dateTime seconds %u (RFC 2911 "
4261 "section 4.1.13).", attr
->name
, date
[6]);
4271 print_test_error("\"%s\": Bad dateTime deciseconds %u (RFC 2911 "
4272 "section 4.1.13).", attr
->name
, date
[7]);
4277 if (date
[8] != '-' && date
[8] != '+')
4282 print_test_error("\"%s\": Bad dateTime UTC sign '%c' (RFC 2911 "
4283 "section 4.1.13).", attr
->name
, date
[8]);
4293 print_test_error("\"%s\": Bad dateTime UTC hours %u (RFC 2911 "
4294 "section 4.1.13).", attr
->name
, date
[9]);
4304 print_test_error("\"%s\": Bad dateTime UTC minutes %u (RFC 2911 "
4305 "section 4.1.13).", attr
->name
, date
[10]);
4312 case IPP_TAG_RESOLUTION
:
4313 for (i
= 0; i
< attr
->num_values
; i
++)
4315 if (attr
->values
[i
].resolution
.xres
<= 0)
4320 print_test_error("\"%s\": Bad resolution value %dx%d%s - cross "
4321 "feed resolution must be positive (RFC 2911 "
4322 "section 4.1.13).", attr
->name
,
4323 attr
->values
[i
].resolution
.xres
,
4324 attr
->values
[i
].resolution
.yres
,
4325 attr
->values
[i
].resolution
.units
==
4326 IPP_RES_PER_INCH
? "dpi" :
4327 attr
->values
[i
].resolution
.units
==
4328 IPP_RES_PER_CM
? "dpc" : "unknown");
4333 if (attr
->values
[i
].resolution
.yres
<= 0)
4338 print_test_error("\"%s\": Bad resolution value %dx%d%s - feed "
4339 "resolution must be positive (RFC 2911 section "
4340 "4.1.13).", attr
->name
,
4341 attr
->values
[i
].resolution
.xres
,
4342 attr
->values
[i
].resolution
.yres
,
4343 attr
->values
[i
].resolution
.units
==
4344 IPP_RES_PER_INCH
? "dpi" :
4345 attr
->values
[i
].resolution
.units
==
4346 IPP_RES_PER_CM
? "dpc" : "unknown");
4351 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
4352 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
4357 print_test_error("\"%s\": Bad resolution value %dx%d%s - bad "
4358 "units value (RFC 2911 section 4.1.13).",
4359 attr
->name
, attr
->values
[i
].resolution
.xres
,
4360 attr
->values
[i
].resolution
.yres
,
4361 attr
->values
[i
].resolution
.units
==
4362 IPP_RES_PER_INCH
? "dpi" :
4363 attr
->values
[i
].resolution
.units
==
4364 IPP_RES_PER_CM
? "dpc" : "unknown");
4371 case IPP_TAG_RANGE
:
4372 for (i
= 0; i
< attr
->num_values
; i
++)
4374 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
4379 print_test_error("\"%s\": Bad rangeOfInteger value %d-%d - lower "
4380 "greater than upper (RFC 2911 section 4.1.13).",
4381 attr
->name
, attr
->values
[i
].range
.lower
,
4382 attr
->values
[i
].range
.upper
);
4389 case IPP_TAG_BEGIN_COLLECTION
:
4390 for (i
= 0; i
< attr
->num_values
; i
++)
4392 for (colattr
= attr
->values
[i
].collection
->attrs
;
4394 colattr
= colattr
->next
)
4396 if (!validate_attr(colattr
, 0))
4403 if (colattr
&& print
)
4405 print_test_error("\"%s\": Bad collection value.", attr
->name
);
4409 validate_attr(colattr
, print
);
4410 colattr
= colattr
->next
;
4417 case IPP_TAG_TEXTLANG
:
4418 for (i
= 0; i
< attr
->num_values
; i
++)
4420 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4422 if ((*ptr
& 0xe0) == 0xc0)
4425 if ((*ptr
& 0xc0) != 0x80)
4428 else if ((*ptr
& 0xf0) == 0xe0)
4431 if ((*ptr
& 0xc0) != 0x80)
4434 if ((*ptr
& 0xc0) != 0x80)
4437 else if ((*ptr
& 0xf8) == 0xf0)
4440 if ((*ptr
& 0xc0) != 0x80)
4443 if ((*ptr
& 0xc0) != 0x80)
4446 if ((*ptr
& 0xc0) != 0x80)
4449 else if (*ptr
& 0x80)
4458 print_test_error("\"%s\": Bad text value \"%s\" - bad UTF-8 "
4459 "sequence (RFC 2911 section 4.1.1).", attr
->name
,
4460 attr
->values
[i
].string
.text
);
4465 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
4470 print_test_error("\"%s\": Bad text value \"%s\" - bad length %d "
4471 "(RFC 2911 section 4.1.1).", attr
->name
,
4472 attr
->values
[i
].string
.text
,
4473 (int)strlen(attr
->values
[i
].string
.text
));
4481 case IPP_TAG_NAMELANG
:
4482 for (i
= 0; i
< attr
->num_values
; i
++)
4484 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4486 if ((*ptr
& 0xe0) == 0xc0)
4489 if ((*ptr
& 0xc0) != 0x80)
4492 else if ((*ptr
& 0xf0) == 0xe0)
4495 if ((*ptr
& 0xc0) != 0x80)
4498 if ((*ptr
& 0xc0) != 0x80)
4501 else if ((*ptr
& 0xf8) == 0xf0)
4504 if ((*ptr
& 0xc0) != 0x80)
4507 if ((*ptr
& 0xc0) != 0x80)
4510 if ((*ptr
& 0xc0) != 0x80)
4513 else if (*ptr
& 0x80)
4522 print_test_error("\"%s\": Bad name value \"%s\" - bad UTF-8 "
4523 "sequence (RFC 2911 section 4.1.2).", attr
->name
,
4524 attr
->values
[i
].string
.text
);
4529 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
4534 print_test_error("\"%s\": Bad name value \"%s\" - bad length %d "
4535 "(RFC 2911 section 4.1.2).", attr
->name
,
4536 attr
->values
[i
].string
.text
,
4537 (int)strlen(attr
->values
[i
].string
.text
));
4544 case IPP_TAG_KEYWORD
:
4545 for (i
= 0; i
< attr
->num_values
; i
++)
4547 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4548 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
4552 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4557 print_test_error("\"%s\": Bad keyword value \"%s\" - invalid "
4558 "character (RFC 2911 section 4.1.3).",
4559 attr
->name
, attr
->values
[i
].string
.text
);
4564 if ((ptr
- attr
->values
[i
].string
.text
) > 255)
4569 print_test_error("\"%s\": Bad keyword value \"%s\" - bad "
4570 "length %d (RFC 2911 section 4.1.3).",
4571 attr
->name
, attr
->values
[i
].string
.text
,
4572 (int)strlen(attr
->values
[i
].string
.text
));
4580 for (i
= 0; i
< attr
->num_values
; i
++)
4582 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
4583 attr
->values
[i
].string
.text
,
4584 scheme
, sizeof(scheme
),
4585 userpass
, sizeof(userpass
),
4586 hostname
, sizeof(hostname
),
4587 &port
, resource
, sizeof(resource
));
4589 if (uri_status
< HTTP_URI_OK
)
4594 print_test_error("\"%s\": Bad URI value \"%s\" - %s "
4595 "(RFC 2911 section 4.1.5).", attr
->name
,
4596 attr
->values
[i
].string
.text
,
4597 URIStatusStrings
[uri_status
-
4598 HTTP_URI_OVERFLOW
]);
4603 if (strlen(attr
->values
[i
].string
.text
) > 1023)
4608 print_test_error("\"%s\": Bad URI value \"%s\" - bad length %d "
4609 "(RFC 2911 section 4.1.5).", attr
->name
,
4610 attr
->values
[i
].string
.text
,
4611 (int)strlen(attr
->values
[i
].string
.text
));
4618 case IPP_TAG_URISCHEME
:
4619 for (i
= 0; i
< attr
->num_values
; i
++)
4621 ptr
= attr
->values
[i
].string
.text
;
4622 if (islower(*ptr
& 255))
4624 for (ptr
++; *ptr
; ptr
++)
4625 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
4626 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
4630 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4635 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
4636 "characters (RFC 2911 section 4.1.6).",
4637 attr
->name
, attr
->values
[i
].string
.text
);
4642 if ((ptr
- attr
->values
[i
].string
.text
) > 63)
4647 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
4648 "length %d (RFC 2911 section 4.1.6).",
4649 attr
->name
, attr
->values
[i
].string
.text
,
4650 (int)strlen(attr
->values
[i
].string
.text
));
4657 case IPP_TAG_CHARSET
:
4658 for (i
= 0; i
< attr
->num_values
; i
++)
4660 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4661 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
4662 isspace(*ptr
& 255))
4665 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4670 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
4671 "characters (RFC 2911 section 4.1.7).",
4672 attr
->name
, attr
->values
[i
].string
.text
);
4677 if ((ptr
- attr
->values
[i
].string
.text
) > 40)
4682 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
4683 "length %d (RFC 2911 section 4.1.7).",
4684 attr
->name
, attr
->values
[i
].string
.text
,
4685 (int)strlen(attr
->values
[i
].string
.text
));
4692 case IPP_TAG_LANGUAGE
:
4694 * The following regular expression is derived from the ABNF for
4695 * language tags in RFC 4646. All I can say is that this is the
4696 * easiest way to check the values...
4699 if ((i
= regcomp(&re
,
4701 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
4703 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
4704 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
4705 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
4706 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
4707 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
4709 "x(-[a-z0-9]{1,8})+" /* privateuse */
4711 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
4713 REG_NOSUB
| REG_EXTENDED
)) != 0)
4715 char temp
[256]; /* Temporary error string */
4717 regerror(i
, &re
, temp
, sizeof(temp
));
4718 print_fatal_error("Unable to compile naturalLanguage regular "
4719 "expression: %s.", temp
);
4722 for (i
= 0; i
< attr
->num_values
; i
++)
4724 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
4729 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
4730 "characters (RFC 2911 section 4.1.8).",
4731 attr
->name
, attr
->values
[i
].string
.text
);
4736 if (strlen(attr
->values
[i
].string
.text
) > 63)
4741 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
4742 "length %d (RFC 2911 section 4.1.8).",
4743 attr
->name
, attr
->values
[i
].string
.text
,
4744 (int)strlen(attr
->values
[i
].string
.text
));
4753 case IPP_TAG_MIMETYPE
:
4755 * The following regular expression is derived from the ABNF for
4756 * language tags in RFC 2045 and 4288. All I can say is that this is
4757 * the easiest way to check the values...
4760 if ((i
= regcomp(&re
,
4762 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
4764 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
4765 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
4766 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
4769 REG_NOSUB
| REG_EXTENDED
)) != 0)
4771 char temp
[256]; /* Temporary error string */
4773 regerror(i
, &re
, temp
, sizeof(temp
));
4774 print_fatal_error("Unable to compile mimeMediaType regular "
4775 "expression: %s.", temp
);
4778 for (i
= 0; i
< attr
->num_values
; i
++)
4780 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
4785 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
4786 "characters (RFC 2911 section 4.1.9).",
4787 attr
->name
, attr
->values
[i
].string
.text
);
4792 if (strlen(attr
->values
[i
].string
.text
) > 255)
4797 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
4798 "length %d (RFC 2911 section 4.1.9).",
4799 attr
->name
, attr
->values
[i
].string
.text
,
4800 (int)strlen(attr
->values
[i
].string
.text
));
4816 * 'with_value()' - Test a WITH-VALUE predicate.
4819 static int /* O - 1 on match, 0 on non-match */
4820 with_value(char *value
, /* I - Value string */
4821 int regex
, /* I - Value is a regular expression */
4822 ipp_attribute_t
*attr
, /* I - Attribute to compare */
4823 int report
) /* I - 1 = report failures */
4825 int i
; /* Looping var */
4826 char *valptr
; /* Pointer into value */
4830 * NULL matches everything.
4833 if (!value
|| !*value
)
4837 * Compare the value string to the attribute value.
4840 switch (attr
->value_tag
)
4842 case IPP_TAG_INTEGER
:
4844 for (i
= 0; i
< attr
->num_values
; i
++)
4846 char op
, /* Comparison operator */
4847 *nextptr
; /* Next pointer */
4848 int intvalue
; /* Integer value */
4852 if (!strncmp(valptr
, "no-value,", 9))
4855 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
4856 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
4857 *valptr
== '=' || *valptr
== '>')
4860 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
4862 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
4870 intvalue
= strtol(valptr
, &nextptr
, 0);
4871 if (nextptr
== valptr
)
4878 if (attr
->values
[i
].integer
== intvalue
)
4882 if (attr
->values
[i
].integer
< intvalue
)
4886 if (attr
->values
[i
].integer
> intvalue
)
4895 for (i
= 0; i
< attr
->num_values
; i
++)
4896 print_test_error("GOT: %s=%d", attr
->name
, attr
->values
[i
].integer
);
4900 case IPP_TAG_RANGE
:
4901 for (i
= 0; i
< attr
->num_values
; i
++)
4903 char op
, /* Comparison operator */
4904 *nextptr
; /* Next pointer */
4905 int intvalue
; /* Integer value */
4909 if (!strncmp(valptr
, "no-value,", 9))
4912 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
4913 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
4914 *valptr
== '=' || *valptr
== '>')
4917 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
4919 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
4927 intvalue
= strtol(valptr
, &nextptr
, 0);
4928 if (nextptr
== valptr
)
4935 if (attr
->values
[i
].range
.lower
== intvalue
||
4936 attr
->values
[i
].range
.upper
== intvalue
)
4940 if (attr
->values
[i
].range
.upper
< intvalue
)
4944 if (attr
->values
[i
].range
.upper
> intvalue
)
4953 for (i
= 0; i
< attr
->num_values
; i
++)
4954 print_test_error("GOT: %s=%d-%d", attr
->name
,
4955 attr
->values
[i
].range
.lower
,
4956 attr
->values
[i
].range
.upper
);
4960 case IPP_TAG_BOOLEAN
:
4961 for (i
= 0; i
< attr
->num_values
; i
++)
4963 if (!strcmp(value
, "true") == attr
->values
[i
].boolean
)
4969 for (i
= 0; i
< attr
->num_values
; i
++)
4970 print_test_error("GOT: %s=%s", attr
->name
,
4971 attr
->values
[i
].boolean
? "true" : "false");
4975 case IPP_TAG_NOVALUE
:
4976 return (!strcmp(value
, "no-value") || !strncmp(value
, "no-value,", 9));
4978 case IPP_TAG_CHARSET
:
4979 case IPP_TAG_KEYWORD
:
4980 case IPP_TAG_LANGUAGE
:
4981 case IPP_TAG_MIMETYPE
:
4983 case IPP_TAG_NAMELANG
:
4985 case IPP_TAG_TEXTLANG
:
4987 case IPP_TAG_URISCHEME
:
4991 * Value is an extended, case-sensitive POSIX regular expression...
4994 regex_t re
; /* Regular expression */
4996 if ((i
= regcomp(&re
, value
, REG_EXTENDED
| REG_NOSUB
)) != 0)
4998 char temp
[256]; /* Temporary string */
5000 regerror(i
, &re
, temp
, sizeof(temp
));
5002 print_fatal_error("Unable to compile WITH-VALUE regular expression "
5003 "\"%s\" - %s", value
, temp
);
5008 * See if ALL of the values match the given regular expression.
5011 for (i
= 0; i
< attr
->num_values
; i
++)
5013 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5016 print_test_error("GOT: %s=\"%s\"", attr
->name
,
5017 attr
->values
[i
].string
.text
);
5025 return (i
== attr
->num_values
);
5030 * Value is a literal string, see if at least one value matches the
5034 for (i
= 0; i
< attr
->num_values
; i
++)
5036 if (!strcmp(value
, attr
->values
[i
].string
.text
))
5042 for (i
= 0; i
< attr
->num_values
; i
++)
5043 print_test_error("GOT: %s=\"%s\"", attr
->name
,
5044 attr
->values
[i
].string
.text
);