]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ipp-file.c
Support <hex> strings in IPP files.
[thirdparty/cups.git] / cups / ipp-file.c
CommitLineData
fd96ad89
MS
1/*
2 * IPP data file parsing functions.
3 *
bd516571 4 * Copyright © 2007-2019 by Apple Inc.
fd96ad89
MS
5 * Copyright © 1997-2007 by Easy Software Products.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11/*
12 * Include necessary headers...
13 */
14
15#include "ipp-private.h"
16#include "string-private.h"
fb863569 17#include "debug-internal.h"
fd96ad89
MS
18
19
20/*
21 * Local functions...
22 */
23
a166e933
MS
24static ipp_t *parse_collection(_ipp_file_t *f, _ipp_vars_t *v, void *user_data);
25static int parse_value(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, ipp_t *ipp, ipp_attribute_t **attr, int element);
86206ccf 26static void report_error(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *message, ...) _CUPS_FORMAT(4, 5);
fd96ad89
MS
27
28
29/*
30 * '_ippFileParse()' - Parse an IPP data file.
31 */
32
33ipp_t * /* O - IPP attributes or @code NULL@ on failure */
34_ippFileParse(
35 _ipp_vars_t *v, /* I - Variables */
36 const char *filename, /* I - Name of file to parse */
fd96ad89
MS
37 void *user_data) /* I - User data pointer */
38{
39 _ipp_file_t f; /* IPP data file information */
a166e933 40 ipp_t *attrs = NULL; /* Active IPP message */
fd96ad89
MS
41 ipp_attribute_t *attr = NULL; /* Current attribute */
42 char token[1024]; /* Token string */
a166e933 43 ipp_t *ignored = NULL; /* Ignored attributes */
fd96ad89
MS
44
45
a166e933 46 DEBUG_printf(("_ippFileParse(v=%p, filename=\"%s\", user_data=%p)", (void *)v, filename, user_data));
fd96ad89
MS
47
48 /*
49 * Initialize file info...
50 */
51
52 memset(&f, 0, sizeof(f));
53 f.filename = filename;
54 f.linenum = 1;
55
56 if ((f.fp = cupsFileOpen(filename, "r")) == NULL)
57 {
58 DEBUG_printf(("1_ippFileParse: Unable to open \"%s\": %s", filename, strerror(errno)));
59 return (0);
60 }
61
62 /*
63 * Do the callback with a NULL token to setup any initial state...
64 */
65
a166e933 66 (*v->tokencb)(&f, v, user_data, NULL);
fd96ad89
MS
67
68 /*
69 * Read data file, using the callback function as needed...
70 */
71
72 while (_ippFileReadToken(&f, token, sizeof(token)))
73 {
74 if (!_cups_strcasecmp(token, "DEFINE") || !_cups_strcasecmp(token, "DEFINE-DEFAULT"))
75 {
76 char name[128], /* Variable name */
77 value[1024], /* Variable value */
78 temp[1024]; /* Temporary string */
79
80 attr = NULL;
81
82 if (_ippFileReadToken(&f, name, sizeof(name)) && _ippFileReadToken(&f, temp, sizeof(temp)))
83 {
367068f3
MS
84 if (_cups_strcasecmp(token, "DEFINE-DEFAULT") || !_ippVarsGet(v, name))
85 {
86 _ippVarsExpand(v, value, temp, sizeof(value));
87 _ippVarsSet(v, name, value);
88 }
fd96ad89
MS
89 }
90 else
91 {
a166e933 92 report_error(&f, v, user_data, "Missing %s name and/or value on line %d of \"%s\".", token, f.linenum, f.filename);
fd96ad89
MS
93 break;
94 }
95 }
96 else if (f.attrs && !_cups_strcasecmp(token, "ATTR"))
97 {
98 /*
99 * Attribute definition...
100 */
101
102 char syntax[128], /* Attribute syntax (value tag) */
103 name[128]; /* Attribute name */
104 ipp_tag_t value_tag; /* Value tag */
105
106 attr = NULL;
107
108 if (!_ippFileReadToken(&f, syntax, sizeof(syntax)))
109 {
a166e933 110 report_error(&f, v, user_data, "Missing ATTR syntax on line %d of \"%s\".", f.linenum, f.filename);
fd96ad89
MS
111 break;
112 }
113 else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE)
114 {
a166e933 115 report_error(&f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f.linenum, f.filename);
fd96ad89
MS
116 break;
117 }
118
119 if (!_ippFileReadToken(&f, name, sizeof(name)) || !name[0])
120 {
a166e933 121 report_error(&f, v, user_data, "Missing ATTR name on line %d of \"%s\".", f.linenum, f.filename);
fd96ad89
MS
122 break;
123 }
124
a166e933
MS
125 if (!v->attrcb || (*v->attrcb)(&f, user_data, name))
126 {
127 /*
128 * Add this attribute...
129 */
130
131 attrs = f.attrs;
132 }
133 else
134 {
135 /*
136 * Ignore this attribute...
137 */
138
139 if (!ignored)
140 ignored = ippNew();
141
142 attrs = ignored;
143 }
144
fd96ad89
MS
145 if (value_tag < IPP_TAG_INTEGER)
146 {
147 /*
148 * Add out-of-band attribute - no value string needed...
149 */
150
a166e933 151 ippAddOutOfBand(attrs, f.group_tag, value_tag, name);
fd96ad89
MS
152 }
153 else
154 {
155 /*
156 * Add attribute with one or more values...
157 */
158
a166e933 159 attr = ippAddString(attrs, f.group_tag, value_tag, name, NULL, NULL);
fd96ad89 160
a166e933 161 if (!parse_value(&f, v, user_data, attrs, &attr, 0))
fd96ad89 162 break;
fd96ad89
MS
163 }
164
165 }
166 else if (attr && !_cups_strcasecmp(token, ","))
167 {
168 /*
169 * Additional value...
170 */
171
a166e933 172 if (!parse_value(&f, v, user_data, attrs, &attr, ippGetCount(attr)))
fd96ad89 173 break;
fd96ad89
MS
174 }
175 else
176 {
177 /*
178 * Something else...
179 */
180
a166e933
MS
181 attr = NULL;
182 attrs = NULL;
fd96ad89 183
a166e933 184 if (!(*v->tokencb)(&f, v, user_data, token))
fd96ad89
MS
185 break;
186 }
187 }
188
189 /*
a166e933
MS
190 * Close the file and free ignored attributes, then return any attributes we
191 * kept...
fd96ad89
MS
192 */
193
194 cupsFileClose(f.fp);
a166e933 195 ippDelete(ignored);
fd96ad89
MS
196
197 return (f.attrs);
198}
199
200
201/*
202 * '_ippFileReadToken()' - Read a token from an IPP data file.
203 */
204
205int /* O - 1 on success, 0 on failure */
206_ippFileReadToken(_ipp_file_t *f, /* I - File to read from */
207 char *token, /* I - Token string buffer */
208 size_t tokensize)/* I - Size of token string buffer */
209{
210 int ch, /* Character from file */
211 quote = 0; /* Quoting character */
212 char *tokptr = token, /* Pointer into token buffer */
213 *tokend = token + tokensize - 1;/* End of token buffer */
214
215
216 /*
217 * Skip whitespace and comments...
218 */
219
0b353e63
MS
220 DEBUG_printf(("1_ippFileReadToken: linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
221
fd96ad89
MS
222 while ((ch = cupsFileGetChar(f->fp)) != EOF)
223 {
224 if (_cups_isspace(ch))
225 {
226 /*
227 * Whitespace...
228 */
229
230 if (ch == '\n')
0b353e63 231 {
fd96ad89 232 f->linenum ++;
0b353e63
MS
233 DEBUG_printf(("1_ippFileReadToken: LF in leading whitespace, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
234 }
fd96ad89
MS
235 }
236 else if (ch == '#')
237 {
238 /*
239 * Comment...
240 */
241
0b353e63
MS
242 DEBUG_puts("1_ippFileReadToken: Skipping comment in leading whitespace...");
243
fd96ad89
MS
244 while ((ch = cupsFileGetChar(f->fp)) != EOF)
245 {
246 if (ch == '\n')
247 break;
248 }
249
250 if (ch == '\n')
0b353e63 251 {
fd96ad89 252 f->linenum ++;
0b353e63
MS
253 DEBUG_printf(("1_ippFileReadToken: LF at end of comment, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
254 }
fd96ad89
MS
255 else
256 break;
257 }
258 else
259 break;
260 }
261
262 if (ch == EOF)
263 {
264 DEBUG_puts("1_ippFileReadToken: EOF");
265 return (0);
266 }
267
268 /*
269 * Read a token...
270 */
271
272 while (ch != EOF)
273 {
8e2e09c1 274 if (ch == '\n')
0b353e63 275 {
8e2e09c1 276 f->linenum ++;
0b353e63
MS
277 DEBUG_printf(("1_ippFileReadToken: LF in token, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
278 }
8e2e09c1 279
fd96ad89
MS
280 if (ch == quote)
281 {
282 /*
283 * End of quoted text...
284 */
285
286 *tokptr = '\0';
0b353e63 287 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at closing quote.", token));
fd96ad89
MS
288 return (1);
289 }
290 else if (!quote && _cups_isspace(ch))
291 {
292 /*
293 * End of unquoted text...
294 */
295
296 *tokptr = '\0';
0b353e63 297 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before whitespace.", token));
fd96ad89
MS
298 return (1);
299 }
bd516571 300 else if (!quote && (ch == '\'' || ch == '\"' || ch == '<'))
fd96ad89
MS
301 {
302 /*
303 * Start of quoted text or regular expression...
304 */
305
bd516571
MS
306 if (ch == '<')
307 quote = '>';
308 else
309 quote = ch;
0b353e63
MS
310
311 DEBUG_printf(("1_ippFileReadToken: Start of quoted string, quote=%c, pos=%ld", quote, (long)cupsFileTell(f->fp)));
fd96ad89
MS
312 }
313 else if (!quote && ch == '#')
314 {
315 /*
316 * Start of comment...
317 */
318
319 cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
320 *tokptr = '\0';
0b353e63 321 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before comment.", token));
fd96ad89
MS
322 return (1);
323 }
324 else if (!quote && (ch == '{' || ch == '}' || ch == ','))
325 {
326 /*
327 * Delimiter...
328 */
329
330 if (tokptr > token)
331 {
332 /*
333 * Return the preceding token first...
334 */
335
336 cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
337 }
338 else
339 {
340 /*
341 * Return this delimiter by itself...
342 */
343
344 *tokptr++ = (char)ch;
345 }
346
347 *tokptr = '\0';
348 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
349 return (1);
350 }
351 else
352 {
353 if (ch == '\\')
354 {
355 /*
356 * Quoted character...
357 */
358
0b353e63
MS
359 DEBUG_printf(("1_ippFileReadToken: Quoted character at pos=%ld", (long)cupsFileTell(f->fp)));
360
fd96ad89
MS
361 if ((ch = cupsFileGetChar(f->fp)) == EOF)
362 {
363 *token = '\0';
364 DEBUG_puts("1_ippFileReadToken: EOF");
365 return (0);
366 }
8e2e09c1 367 else if (ch == '\n')
0b353e63 368 {
8e2e09c1 369 f->linenum ++;
0b353e63
MS
370 DEBUG_printf(("1_ippFileReadToken: quoted LF, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
371 }
0c178dec
MS
372 else if (ch == 'a')
373 ch = '\a';
374 else if (ch == 'b')
375 ch = '\b';
376 else if (ch == 'f')
377 ch = '\f';
378 else if (ch == 'n')
379 ch = '\n';
380 else if (ch == 'r')
381 ch = '\r';
382 else if (ch == 't')
383 ch = '\t';
384 else if (ch == 'v')
385 ch = '\v';
fd96ad89
MS
386 }
387
bd516571 388 if (quote != '>' || !isspace(ch & 255))
fd96ad89 389 {
bd516571
MS
390 if (tokptr < tokend)
391 {
392 /*
393 * Add to current token...
394 */
fd96ad89 395
bd516571
MS
396 *tokptr++ = (char)ch;
397 }
398 else
399 {
400 /*
401 * Token too long...
402 */
fd96ad89 403
bd516571
MS
404 *tokptr = '\0';
405 DEBUG_printf(("1_ippFileReadToken: Too long: \"%s\".", token));
406 return (0);
407 }
fd96ad89
MS
408 }
409 }
410
411 /*
412 * Get the next character...
413 */
414
415 ch = cupsFileGetChar(f->fp);
416 }
417
418 *tokptr = '\0';
0b353e63 419 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at EOF.", token));
fd96ad89
MS
420
421 return (tokptr > token);
422}
423
424
425/*
426 * 'parse_collection()' - Parse an IPP collection value.
427 */
428
429static ipp_t * /* O - Collection value or @code NULL@ on error */
430parse_collection(
431 _ipp_file_t *f, /* I - IPP data file */
432 _ipp_vars_t *v, /* I - IPP variables */
fd96ad89
MS
433 void *user_data) /* I - User data pointer */
434{
435 ipp_t *col = ippNew(); /* Collection value */
436 ipp_attribute_t *attr = NULL; /* Current member attribute */
437 char token[1024]; /* Token string */
438
439
440 /*
441 * Parse the collection value...
442 */
443
444 while (_ippFileReadToken(f, token, sizeof(token)))
445 {
446 if (!_cups_strcasecmp(token, "}"))
447 {
448 /*
449 * End of collection value...
450 */
451
452 break;
453 }
454 else if (!_cups_strcasecmp(token, "MEMBER"))
455 {
456 /*
457 * Member attribute definition...
458 */
459
460 char syntax[128], /* Attribute syntax (value tag) */
461 name[128]; /* Attribute name */
462 ipp_tag_t value_tag; /* Value tag */
463
464 attr = NULL;
465
466 if (!_ippFileReadToken(f, syntax, sizeof(syntax)))
467 {
a166e933 468 report_error(f, v, user_data, "Missing ATTR syntax on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
469 ippDelete(col);
470 col = NULL;
471 break;
472 }
473 else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE)
474 {
a166e933 475 report_error(f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename);
fd96ad89
MS
476 ippDelete(col);
477 col = NULL;
478 break;
479 }
480
481 if (!_ippFileReadToken(f, name, sizeof(name)) || !name[0])
482 {
a166e933 483 report_error(f, v, user_data, "Missing ATTR name on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
484 ippDelete(col);
485 col = NULL;
486 break;
487 }
488
489 if (value_tag < IPP_TAG_INTEGER)
490 {
491 /*
492 * Add out-of-band attribute - no value string needed...
493 */
494
495 ippAddOutOfBand(col, IPP_TAG_ZERO, value_tag, name);
496 }
497 else
498 {
499 /*
500 * Add attribute with one or more values...
501 */
502
503 attr = ippAddString(col, IPP_TAG_ZERO, value_tag, name, NULL, NULL);
504
a166e933 505 if (!parse_value(f, v, user_data, col, &attr, 0))
fd96ad89
MS
506 {
507 ippDelete(col);
508 col = NULL;
509 break;
510 }
511 }
512
513 }
514 else if (attr && !_cups_strcasecmp(token, ","))
515 {
516 /*
517 * Additional value...
518 */
519
a166e933 520 if (!parse_value(f, v, user_data, col, &attr, ippGetCount(attr)))
fd96ad89
MS
521 {
522 ippDelete(col);
523 col = NULL;
524 break;
525 }
526 }
527 else
528 {
529 /*
530 * Something else...
531 */
532
a166e933 533 report_error(f, v, user_data, "Unknown directive \"%s\" on line %d of \"%s\".", token, f->linenum, f->filename);
fd96ad89
MS
534 ippDelete(col);
535 col = NULL;
536 attr = NULL;
537 break;
538
539 }
540 }
541
542 return (col);
543}
544
545
546/*
547 * 'parse_value()' - Parse an IPP value.
548 */
549
550static int /* O - 1 on success or 0 on error */
551parse_value(_ipp_file_t *f, /* I - IPP data file */
552 _ipp_vars_t *v, /* I - IPP variables */
fd96ad89
MS
553 void *user_data,/* I - User data pointer */
554 ipp_t *ipp, /* I - IPP message */
555 ipp_attribute_t **attr, /* IO - IPP attribute */
556 int element) /* I - Element number */
557{
bd516571
MS
558 char value[2049], /* Value string */
559 *valueptr, /* Pointer into value string */
560 temp[2049], /* Temporary string */
561 *tempptr; /* Pointer into temporary string */
562 size_t valuelen; /* Length of value */
fd96ad89
MS
563
564
565 if (!_ippFileReadToken(f, temp, sizeof(temp)))
566 {
a166e933 567 report_error(f, v, user_data, "Missing value on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
568 return (0);
569 }
570
571 _ippVarsExpand(v, value, temp, sizeof(value));
572
573 switch (ippGetValueTag(*attr))
574 {
575 case IPP_TAG_BOOLEAN :
576 return (ippSetBoolean(ipp, attr, element, !_cups_strcasecmp(value, "true")));
577 break;
578
579 case IPP_TAG_ENUM :
580 case IPP_TAG_INTEGER :
564cd57d 581 return (ippSetInteger(ipp, attr, element, (int)strtol(value, NULL, 0)));
fd96ad89
MS
582 break;
583
06e1afc3
MS
584 case IPP_TAG_DATE :
585 {
586 int year, /* Year */
587 month, /* Month */
588 day, /* Day of month */
589 hour, /* Hour */
590 minute, /* Minute */
591 second, /* Second */
592 utc_offset = 0; /* Timezone offset from UTC */
593 ipp_uchar_t date[11]; /* dateTime value */
594
f17549fb 595 if (sscanf(value, "%d-%d-%dT%d:%d:%d%d", &year, &month, &day, &hour, &minute, &second, &utc_offset) < 6)
06e1afc3
MS
596 {
597 report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
598 return (0);
599 }
600
601 date[0] = (ipp_uchar_t)(year >> 8);
602 date[1] = (ipp_uchar_t)(year & 255);
603 date[2] = (ipp_uchar_t)month;
604 date[3] = (ipp_uchar_t)day;
605 date[4] = (ipp_uchar_t)hour;
606 date[5] = (ipp_uchar_t)minute;
607 date[6] = (ipp_uchar_t)second;
608 date[7] = 0;
609 if (utc_offset < 0)
610 {
611 utc_offset = -utc_offset;
612 date[8] = (ipp_uchar_t)'-';
613 }
614 else
615 {
616 date[8] = (ipp_uchar_t)'+';
617 }
618
619 date[9] = (ipp_uchar_t)(utc_offset / 100);
620 date[10] = (ipp_uchar_t)(utc_offset % 100);
621
622 return (ippSetDate(ipp, attr, element, date));
623 }
624 break;
625
fd96ad89
MS
626 case IPP_TAG_RESOLUTION :
627 {
628 int xres, /* X resolution */
629 yres; /* Y resolution */
630 char *ptr; /* Pointer into value */
631
632 xres = yres = (int)strtol(value, (char **)&ptr, 10);
633 if (ptr > value && xres > 0)
634 {
635 if (*ptr == 'x')
636 yres = (int)strtol(ptr + 1, (char **)&ptr, 10);
637 }
638
639 if (ptr <= value || xres <= 0 || yres <= 0 || !ptr || (_cups_strcasecmp(ptr, "dpi") && _cups_strcasecmp(ptr, "dpc") && _cups_strcasecmp(ptr, "dpcm") && _cups_strcasecmp(ptr, "other")))
640 {
a166e933 641 report_error(f, v, user_data, "Bad resolution value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
fd96ad89
MS
642 return (0);
643 }
644
645 if (!_cups_strcasecmp(ptr, "dpi"))
646 return (ippSetResolution(ipp, attr, element, IPP_RES_PER_INCH, xres, yres));
647 else if (!_cups_strcasecmp(ptr, "dpc") || !_cups_strcasecmp(ptr, "dpcm"))
648 return (ippSetResolution(ipp, attr, element, IPP_RES_PER_CM, xres, yres));
649 else
650 return (ippSetResolution(ipp, attr, element, (ipp_res_t)0, xres, yres));
651 }
652 break;
653
654 case IPP_TAG_RANGE :
655 {
656 int lower, /* Lower value */
657 upper; /* Upper value */
658
659 if (sscanf(value, "%d-%d", &lower, &upper) != 2)
660 {
a166e933 661 report_error(f, v, user_data, "Bad rangeOfInteger value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
fd96ad89
MS
662 return (0);
663 }
664
665 return (ippSetRange(ipp, attr, element, lower, upper));
666 }
667 break;
668
669 case IPP_TAG_STRING :
bd516571
MS
670 valuelen = strlen(value);
671
672 if (value[0] == '<' && value[strlen(value) - 1] == '>')
673 {
674 if (valuelen & 1)
675 {
676 report_error(f, v, user_data, "Bad ATTR octetString value on line %d of \"%s\".", f->linenum, f->filename);
677 return (0);
678 }
679
680 valueptr = value + 1;
681 tempptr = temp;
682
683 while (*valueptr && *valueptr != '>')
684 {
685 if (!isxdigit(valueptr[0] & 255) || !isxdigit(valueptr[1] & 255))
686 {
687 report_error(f, v, user_data, "Bad ATTR octetString value on line %d of \"%s\".", f->linenum, f->filename);
688 return (0);
689 }
690
691 if (valueptr[0] >= '0' && valueptr[0] <= '9')
692 *tempptr = (char)((valueptr[0] - '0') << 4);
693 else
694 *tempptr = (char)((tolower(valueptr[0]) - 'a' + 10) << 4);
695
696 if (valueptr[1] >= '0' && valueptr[1] <= '9')
697 *tempptr |= (valueptr[1] - '0');
698 else
699 *tempptr |= (tolower(valueptr[1]) - 'a' + 10);
700
701 tempptr ++;
702 }
703
704 return (ippSetOctetString(ipp, attr, element, temp, (int)(tempptr - temp)));
705 }
706 else
707 return (ippSetOctetString(ipp, attr, element, value, (int)valuelen));
fd96ad89
MS
708 break;
709
710 case IPP_TAG_TEXTLANG :
711 case IPP_TAG_NAMELANG :
712 case IPP_TAG_TEXT :
713 case IPP_TAG_NAME :
714 case IPP_TAG_KEYWORD :
715 case IPP_TAG_URI :
716 case IPP_TAG_URISCHEME :
717 case IPP_TAG_CHARSET :
718 case IPP_TAG_LANGUAGE :
719 case IPP_TAG_MIMETYPE :
720 return (ippSetString(ipp, attr, element, value));
721 break;
722
723 case IPP_TAG_BEGIN_COLLECTION :
724 {
725 int status; /* Add status */
726 ipp_t *col; /* Collection value */
727
728 if (strcmp(value, "{"))
729 {
a166e933 730 report_error(f, v, user_data, "Bad ATTR collection value on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
731 return (0);
732 }
733
a166e933 734 if ((col = parse_collection(f, v, user_data)) == NULL)
fd96ad89
MS
735 return (0);
736
737 status = ippSetCollection(ipp, attr, element, col);
738 ippDelete(col);
739
740 return (status);
741 }
742 break;
743
744 default :
a166e933 745 report_error(f, v, user_data, "Unsupported ATTR value on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
746 return (0);
747 }
748
749 return (1);
750}
751
752
753/*
754 * 'report_error()' - Report an error.
755 */
756
757static void
758report_error(
a166e933
MS
759 _ipp_file_t *f, /* I - IPP data file */
760 _ipp_vars_t *v, /* I - Error callback function, if any */
761 void *user_data, /* I - User data pointer */
762 const char *message, /* I - Printf-style message */
fd96ad89
MS
763 ...) /* I - Additional arguments as needed */
764{
765 char buffer[8192]; /* Formatted string */
766 va_list ap; /* Argument pointer */
767
768
769 va_start(ap, message);
770 vsnprintf(buffer, sizeof(buffer), message, ap);
771 va_end(ap);
772
a166e933
MS
773 if (v->errorcb)
774 (*v->errorcb)(f, user_data, buffer);
fd96ad89
MS
775 else
776 fprintf(stderr, "%s\n", buffer);
777}