1 /*
2 * PPD test program for CUPS.
3 *
4 * Copyright 2007-2017 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
6 *
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * missing or damaged, see the license at "http://www.cups.org/".
12 *
13 * This file is subject to the Apple OS-Developed Software exception.
14 */
15
16 /*
17 * Include necessary headers...
18 */
19
20 #undef _CUPS_NO_DEPRECATED
21 #include "cups-private.h"
22 #include "ppd-private.h"
23 #include <sys/stat.h>
24 #ifdef _WIN32
25 # include <io.h>
26 #else
27 # include <unistd.h>
28 # include <fcntl.h>
29 #endif /* _WIN32 */
30 #include <math.h>
31
32
33 /*
34 * Test data...
35 */
36
37 static const char *default_code =
38 "[{\n"
39 "%%BeginFeature: *InstalledDuplexer False\n"
40 "%%EndFeature\n"
41 "} stopped cleartomark\n"
42 "[{\n"
43 "%%BeginFeature: *PageRegion Letter\n"
44 "PageRegion=Letter\n"
45 "%%EndFeature\n"
46 "} stopped cleartomark\n"
47 "[{\n"
48 "%%BeginFeature: *InputSlot Tray\n"
49 "InputSlot=Tray\n"
50 "%%EndFeature\n"
51 "} stopped cleartomark\n"
52 "[{\n"
53 "%%BeginFeature: *OutputBin Tray1\n"
54 "OutputBin=Tray1\n"
55 "%%EndFeature\n"
56 "} stopped cleartomark\n"
57 "[{\n"
58 "%%BeginFeature: *MediaType Plain\n"
59 "MediaType=Plain\n"
60 "%%EndFeature\n"
61 "} stopped cleartomark\n"
62 "[{\n"
63 "%%BeginFeature: *IntOption None\n"
64 "%%EndFeature\n"
65 "} stopped cleartomark\n"
66 "[{\n"
67 "%%BeginFeature: *StringOption None\n"
68 "%%EndFeature\n"
69 "} stopped cleartomark\n";
70
71 static const char *custom_code =
72 "[{\n"
73 "%%BeginFeature: *InstalledDuplexer False\n"
74 "%%EndFeature\n"
75 "} stopped cleartomark\n"
76 "[{\n"
77 "%%BeginFeature: *InputSlot Tray\n"
78 "InputSlot=Tray\n"
79 "%%EndFeature\n"
80 "} stopped cleartomark\n"
81 "[{\n"
82 "%%BeginFeature: *MediaType Plain\n"
83 "MediaType=Plain\n"
84 "%%EndFeature\n"
85 "} stopped cleartomark\n"
86 "[{\n"
87 "%%BeginFeature: *OutputBin Tray1\n"
88 "OutputBin=Tray1\n"
89 "%%EndFeature\n"
90 "} stopped cleartomark\n"
91 "[{\n"
92 "%%BeginFeature: *IntOption None\n"
93 "%%EndFeature\n"
94 "} stopped cleartomark\n"
95 "[{\n"
96 "%%BeginFeature: *CustomStringOption True\n"
97 "(value\\0502\\051)\n"
98 "(value 1)\n"
99 "StringOption=Custom\n"
100 "%%EndFeature\n"
101 "} stopped cleartomark\n"
102 "[{\n"
103 "%%BeginFeature: *CustomPageSize True\n"
104 "400\n"
105 "500\n"
106 "0\n"
107 "0\n"
108 "0\n"
109 "PageSize=Custom\n"
110 "%%EndFeature\n"
111 "} stopped cleartomark\n";
112
113 static const char *default2_code =
114 "[{\n"
115 "%%BeginFeature: *InstalledDuplexer False\n"
116 "%%EndFeature\n"
117 "} stopped cleartomark\n"
118 "[{\n"
119 "%%BeginFeature: *InputSlot Tray\n"
120 "InputSlot=Tray\n"
121 "%%EndFeature\n"
122 "} stopped cleartomark\n"
123 "[{\n"
124 "%%BeginFeature: *Quality Normal\n"
125 "Quality=Normal\n"
126 "%%EndFeature\n"
127 "} stopped cleartomark\n"
128 "[{\n"
129 "%%BeginFeature: *IntOption None\n"
130 "%%EndFeature\n"
131 "} stopped cleartomark\n"
132 "[{\n"
133 "%%BeginFeature: *StringOption None\n"
134 "%%EndFeature\n"
135 "} stopped cleartomark\n";
136
137
138 /*
139 * 'main()' - Main entry.
140 */
141
142 int /* O - Exit status */
main(int argc,char * argv[])143 main(int argc, /* I - Number of command-line arguments */
144 char *argv[]) /* I - Command-line arguments */
145 {
146 int i; /* Looping var */
147 ppd_file_t *ppd; /* PPD file loaded from disk */
148 int status; /* Status of tests (0 = success, 1 = fail) */
149 int conflicts; /* Number of conflicts */
150 char *s; /* String */
151 char buffer[8192]; /* String buffer */
152 const char *text, /* Localized text */
153 *val; /* Option value */
154 int num_options; /* Number of options */
155 cups_option_t *options; /* Options */
156 ppd_size_t minsize, /* Minimum size */
157 maxsize, /* Maximum size */
158 *size; /* Current size */
159 ppd_attr_t *attr; /* Current attribute */
160 _ppd_cache_t *pc; /* PPD cache */
161
162
163 status = 0;
164
165 if (argc == 1)
166 {
167 /*
168 * Setup directories for locale stuff...
169 */
170
171 if (access("locale", 0))
172 {
173 mkdir("locale", 0777);
174 mkdir("locale/fr", 0777);
175 symlink("../../../locale/cups_fr.po", "locale/fr/cups_fr.po");
176 mkdir("locale/zh_TW", 0777);
177 symlink("../../../locale/cups_zh_TW.po", "locale/zh_TW/cups_zh_TW.po");
178 }
179
180 putenv("LOCALEDIR=locale");
181 putenv("SOFTWARE=CUPS");
182
183 /*
184 * Do tests with test.ppd...
185 */
186
187 fputs("ppdOpenFile(test.ppd): ", stdout);
188
189 if ((ppd = _ppdOpenFile("test.ppd", _PPD_LOCALIZATION_ALL)) != NULL)
190 puts("PASS");
191 else
192 {
193 ppd_status_t err; /* Last error in file */
194 int line; /* Line number in file */
195
196
197 status ++;
198 err = ppdLastError(&line);
199
200 printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
201 }
202
203 fputs("ppdFindAttr(wildcard): ", stdout);
204 if ((attr = ppdFindAttr(ppd, "cupsTest", NULL)) == NULL)
205 {
206 status ++;
207 puts("FAIL (not found)");
208 }
209 else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
210 {
211 status ++;
212 printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
213 }
214 else
215 puts("PASS");
216
217 fputs("ppdFindNextAttr(wildcard): ", stdout);
218 if ((attr = ppdFindNextAttr(ppd, "cupsTest", NULL)) == NULL)
219 {
220 status ++;
221 puts("FAIL (not found)");
222 }
223 else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Bar"))
224 {
225 status ++;
226 printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
227 }
228 else
229 puts("PASS");
230
231 fputs("ppdFindAttr(Foo): ", stdout);
232 if ((attr = ppdFindAttr(ppd, "cupsTest", "Foo")) == NULL)
233 {
234 status ++;
235 puts("FAIL (not found)");
236 }
237 else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
238 {
239 status ++;
240 printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
241 }
242 else
243 puts("PASS");
244
245 fputs("ppdFindNextAttr(Foo): ", stdout);
246 if ((attr = ppdFindNextAttr(ppd, "cupsTest", "Foo")) != NULL)
247 {
248 status ++;
249 printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
250 }
251 else
252 puts("PASS");
253
254 fputs("ppdMarkDefaults: ", stdout);
255 ppdMarkDefaults(ppd);
256
257 if ((conflicts = ppdConflicts(ppd)) == 0)
258 puts("PASS");
259 else
260 {
261 status ++;
262 printf("FAIL (%d conflicts)\n", conflicts);
263 }
264
265 fputs("ppdEmitString (defaults): ", stdout);
266 if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
267 !strcmp(s, default_code))
268 puts("PASS");
269 else
270 {
271 status ++;
272 printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
273 (int)strlen(default_code));
274
275 if (s)
276 puts(s);
277 }
278
279 if (s)
280 free(s);
281
282 fputs("ppdEmitString (custom size and string): ", stdout);
283 ppdMarkOption(ppd, "PageSize", "Custom.400x500");
284 ppdMarkOption(ppd, "StringOption", "{String1=\"value 1\" String2=value(2)}");
285
286 if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
287 !strcmp(s, custom_code))
288 puts("PASS");
289 else
290 {
291 status ++;
292 printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
293 (int)strlen(custom_code));
294
295 if (s)
296 puts(s);
297 }
298
299 if (s)
300 free(s);
301
302 /*
303 * Test constraints...
304 */
305
306 fputs("cupsGetConflicts(InputSlot=Envelope): ", stdout);
307 ppdMarkOption(ppd, "PageSize", "Letter");
308
309 num_options = cupsGetConflicts(ppd, "InputSlot", "Envelope", &options);
310 if (num_options != 2 ||
311 (val = cupsGetOption("PageRegion", num_options, options)) == NULL ||
312 _cups_strcasecmp(val, "Letter") ||
313 (val = cupsGetOption("PageSize", num_options, options)) == NULL ||
314 _cups_strcasecmp(val, "Letter"))
315 {
316 printf("FAIL (%d options:", num_options);
317 for (i = 0; i < num_options; i ++)
318 printf(" %s=%s", options[i].name, options[i].value);
319 puts(")");
320 status ++;
321 }
322 else
323 puts("PASS");
324
325 fputs("ppdConflicts(): ", stdout);
326 ppdMarkOption(ppd, "InputSlot", "Envelope");
327
328 if ((conflicts = ppdConflicts(ppd)) == 2)
329 puts("PASS (2)");
330 else
331 {
332 printf("FAIL (%d)\n", conflicts);
333 status ++;
334 }
335
336 fputs("cupsResolveConflicts(InputSlot=Envelope): ", stdout);
337 num_options = 0;
338 options = NULL;
339 if (!cupsResolveConflicts(ppd, "InputSlot", "Envelope", &num_options,
340 &options))
341 {
342 puts("FAIL (Unable to resolve)");
343 status ++;
344 }
345 else if (num_options != 2 ||
346 !cupsGetOption("PageSize", num_options, options))
347 {
348 printf("FAIL (%d options:", num_options);
349 for (i = 0; i < num_options; i ++)
350 printf(" %s=%s", options[i].name, options[i].value);
351 puts(")");
352 status ++;
353 }
354 else
355 puts("PASS (Resolved by changing PageSize)");
356
357 cupsFreeOptions(num_options, options);
358
359 fputs("cupsResolveConflicts(No option/choice): ", stdout);
360 num_options = 0;
361 options = NULL;
362 if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
363 num_options == 1 && !_cups_strcasecmp(options[0].name, "InputSlot") &&
364 !_cups_strcasecmp(options[0].value, "Tray"))
365 puts("PASS (Resolved by changing InputSlot)");
366 else if (num_options > 0)
367 {
368 printf("FAIL (%d options:", num_options);
369 for (i = 0; i < num_options; i ++)
370 printf(" %s=%s", options[i].name, options[i].value);
371 puts(")");
372 status ++;
373 }
374 else
375 {
376 puts("FAIL (Unable to resolve)");
377 status ++;
378 }
379 cupsFreeOptions(num_options, options);
380
381 fputs("ppdInstallableConflict(): ", stdout);
382 if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
383 !ppdInstallableConflict(ppd, "Duplex", "None"))
384 puts("PASS");
385 else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
386 {
387 puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
388 status ++;
389 }
390 else
391 {
392 puts("FAIL (Duplex=None conflicted)");
393 status ++;
394 }
395
396 /*
397 * ppdPageSizeLimits
398 */
399
400 fputs("ppdPageSizeLimits: ", stdout);
401 if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
402 {
403 if (fabs(minsize.width - 36.0) > 0.001 || fabs(minsize.length - 36.0) > 0.001 ||
404 fabs(maxsize.width - 1080.0) > 0.001 || fabs(maxsize.length - 86400.0) > 0.001)
405 {
406 printf("FAIL (got min=%.3fx%.3f, max=%.3fx%.3f, "
407 "expected min=36x36, max=1080x86400)\n", minsize.width,
408 minsize.length, maxsize.width, maxsize.length);
409 status ++;
410 }
411 else
412 puts("PASS");
413 }
414 else
415 {
416 puts("FAIL (returned 0)");
417 status ++;
418 }
419
420 /*
421 * cupsMarkOptions with PWG and IPP size names.
422 */
423
424 fputs("cupsMarkOptions(media=iso-a4): ", stdout);
425 num_options = cupsAddOption("media", "iso-a4", 0, &options);
426 cupsMarkOptions(ppd, num_options, options);
427 cupsFreeOptions(num_options, options);
428
429 size = ppdPageSize(ppd, NULL);
430 if (!size || strcmp(size->name, "A4"))
431 {
432 printf("FAIL (%s)\n", size ? size->name : "unknown");
433 status ++;
434 }
435 else
436 puts("PASS");
437
438 fputs("cupsMarkOptions(media=na_letter_8.5x11in): ", stdout);
439 num_options = cupsAddOption("media", "na_letter_8.5x11in", 0, &options);
440 cupsMarkOptions(ppd, num_options, options);
441 cupsFreeOptions(num_options, options);
442
443 size = ppdPageSize(ppd, NULL);
444 if (!size || strcmp(size->name, "Letter"))
445 {
446 printf("FAIL (%s)\n", size ? size->name : "unknown");
447 status ++;
448 }
449 else
450 puts("PASS");
451
452 fputs("cupsMarkOptions(media=oe_letter-fullbleed_8.5x11in): ", stdout);
453 num_options = cupsAddOption("media", "oe_letter-fullbleed_8.5x11in", 0,
454 &options);
455 cupsMarkOptions(ppd, num_options, options);
456 cupsFreeOptions(num_options, options);
457
458 size = ppdPageSize(ppd, NULL);
459 if (!size || strcmp(size->name, "Letter.Fullbleed"))
460 {
461 printf("FAIL (%s)\n", size ? size->name : "unknown");
462 status ++;
463 }
464 else
465 puts("PASS");
466
467 fputs("cupsMarkOptions(media=A4): ", stdout);
468 num_options = cupsAddOption("media", "A4", 0, &options);
469 cupsMarkOptions(ppd, num_options, options);
470 cupsFreeOptions(num_options, options);
471
472 size = ppdPageSize(ppd, NULL);
473 if (!size || strcmp(size->name, "A4"))
474 {
475 printf("FAIL (%s)\n", size ? size->name : "unknown");
476 status ++;
477 }
478 else
479 puts("PASS");
480
481 /*
482 * Custom sizes...
483 */
484
485 fputs("cupsMarkOptions(media=Custom.8x10in): ", stdout);
486 num_options = cupsAddOption("media", "Custom.8x10in", 0, &options);
487 cupsMarkOptions(ppd, num_options, options);
488 cupsFreeOptions(num_options, options);
489
490 size = ppdPageSize(ppd, NULL);
491 if (!size || strcmp(size->name, "Custom") ||
492 fabs(size->width - 576.0) > 0.001 ||
493 fabs(size->length - 720.0) > 0.001)
494 {
495 printf("FAIL (%s - %gx%g)\n", size ? size->name : "unknown",
496 size ? size->width : 0.0, size ? size->length : 0.0);
497 status ++;
498 }
499 else
500 puts("PASS");
501
502 /*
503 * Test localization...
504 */
505
506 fputs("ppdLocalizeIPPReason(text): ", stdout);
507 if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
508 !strcmp(buffer, "Foo Reason"))
509 puts("PASS");
510 else
511 {
512 status ++;
513 printf("FAIL (\"%s\" instead of \"Foo Reason\")\n", buffer);
514 }
515
516 fputs("ppdLocalizeIPPReason(http): ", stdout);
517 if (ppdLocalizeIPPReason(ppd, "foo", "http", buffer, sizeof(buffer)) &&
518 !strcmp(buffer, "http://foo/bar.html"))
519 puts("PASS");
520 else
521 {
522 status ++;
523 printf("FAIL (\"%s\" instead of \"http://foo/bar.html\")\n", buffer);
524 }
525
526 fputs("ppdLocalizeIPPReason(help): ", stdout);
527 if (ppdLocalizeIPPReason(ppd, "foo", "help", buffer, sizeof(buffer)) &&
528 !strcmp(buffer, "help:anchor='foo'%20bookID=Vendor%20Help"))
529 puts("PASS");
530 else
531 {
532 status ++;
533 printf("FAIL (\"%s\" instead of \"help:anchor='foo'%%20bookID=Vendor%%20Help\")\n", buffer);
534 }
535
536 fputs("ppdLocalizeIPPReason(file): ", stdout);
537 if (ppdLocalizeIPPReason(ppd, "foo", "file", buffer, sizeof(buffer)) &&
538 !strcmp(buffer, "/help/foo/bar.html"))
539 puts("PASS");
540 else
541 {
542 status ++;
543 printf("FAIL (\"%s\" instead of \"/help/foo/bar.html\")\n", buffer);
544 }
545
546 putenv("LANG=fr");
547 putenv("LC_ALL=fr");
548 putenv("LC_CTYPE=fr");
549 putenv("LC_MESSAGES=fr");
550
551 fputs("ppdLocalizeIPPReason(fr text): ", stdout);
552 if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
553 !strcmp(buffer, "La Long Foo Reason"))
554 puts("PASS");
555 else
556 {
557 status ++;
558 printf("FAIL (\"%s\" instead of \"La Long Foo Reason\")\n", buffer);
559 }
560
561 putenv("LANG=zh_TW");
562 putenv("LC_ALL=zh_TW");
563 putenv("LC_CTYPE=zh_TW");
564 putenv("LC_MESSAGES=zh_TW");
565
566 fputs("ppdLocalizeIPPReason(zh_TW text): ", stdout);
567 if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
568 !strcmp(buffer, "Number 1 Foo Reason"))
569 puts("PASS");
570 else
571 {
572 status ++;
573 printf("FAIL (\"%s\" instead of \"Number 1 Foo Reason\")\n", buffer);
574 }
575
576 /*
577 * cupsMarkerName localization...
578 */
579
580 putenv("LANG=en");
581 putenv("LC_ALL=en");
582 putenv("LC_CTYPE=en");
583 putenv("LC_MESSAGES=en");
584
585 fputs("ppdLocalizeMarkerName(bogus): ", stdout);
586
587 if ((text = ppdLocalizeMarkerName(ppd, "bogus")) != NULL)
588 {
589 status ++;
590 printf("FAIL (\"%s\" instead of NULL)\n", text);
591 }
592 else
593 puts("PASS");
594
595 fputs("ppdLocalizeMarkerName(cyan): ", stdout);
596
597 if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
598 !strcmp(text, "Cyan Toner"))
599 puts("PASS");
600 else
601 {
602 status ++;
603 printf("FAIL (\"%s\" instead of \"Cyan Toner\")\n",
604 text ? text : "(null)");
605 }
606
607 putenv("LANG=fr");
608 putenv("LC_ALL=fr");
609 putenv("LC_CTYPE=fr");
610 putenv("LC_MESSAGES=fr");
611
612 fputs("ppdLocalizeMarkerName(fr cyan): ", stdout);
613 if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
614 !strcmp(text, "La Toner Cyan"))
615 puts("PASS");
616 else
617 {
618 status ++;
619 printf("FAIL (\"%s\" instead of \"La Toner Cyan\")\n",
620 text ? text : "(null)");
621 }
622
623 putenv("LANG=zh_TW");
624 putenv("LC_ALL=zh_TW");
625 putenv("LC_CTYPE=zh_TW");
626 putenv("LC_MESSAGES=zh_TW");
627
628 fputs("ppdLocalizeMarkerName(zh_TW cyan): ", stdout);
629 if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
630 !strcmp(text, "Number 1 Cyan Toner"))
631 puts("PASS");
632 else
633 {
634 status ++;
635 printf("FAIL (\"%s\" instead of \"Number 1 Cyan Toner\")\n",
636 text ? text : "(null)");
637 }
638
639 ppdClose(ppd);
640
641 /*
642 * Test new constraints...
643 */
644
645 fputs("ppdOpenFile(test2.ppd): ", stdout);
646
647 if ((ppd = ppdOpenFile("test2.ppd")) != NULL)
648 puts("PASS");
649 else
650 {
651 ppd_status_t err; /* Last error in file */
652 int line; /* Line number in file */
653
654
655 status ++;
656 err = ppdLastError(&line);
657
658 printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
659 }
660
661 fputs("ppdMarkDefaults: ", stdout);
662 ppdMarkDefaults(ppd);
663
664 if ((conflicts = ppdConflicts(ppd)) == 0)
665 puts("PASS");
666 else
667 {
668 status ++;
669 printf("FAIL (%d conflicts)\n", conflicts);
670 }
671
672 fputs("ppdEmitString (defaults): ", stdout);
673 if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
674 !strcmp(s, default2_code))
675 puts("PASS");
676 else
677 {
678 status ++;
679 printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
680 (int)strlen(default2_code));
681
682 if (s)
683 puts(s);
684 }
685
686 if (s)
687 free(s);
688
689 fputs("ppdConflicts(): ", stdout);
690 ppdMarkOption(ppd, "PageSize", "Env10");
691 ppdMarkOption(ppd, "InputSlot", "Envelope");
692 ppdMarkOption(ppd, "Quality", "Photo");
693
694 if ((conflicts = ppdConflicts(ppd)) == 1)
695 puts("PASS (1)");
696 else
697 {
698 printf("FAIL (%d)\n", conflicts);
699 status ++;
700 }
701
702 fputs("cupsResolveConflicts(Quality=Photo): ", stdout);
703 num_options = 0;
704 options = NULL;
705 if (cupsResolveConflicts(ppd, "Quality", "Photo", &num_options,
706 &options))
707 {
708 printf("FAIL (%d options:", num_options);
709 for (i = 0; i < num_options; i ++)
710 printf(" %s=%s", options[i].name, options[i].value);
711 puts(")");
712 status ++;
713 }
714 else
715 puts("PASS (Unable to resolve)");
716 cupsFreeOptions(num_options, options);
717
718 fputs("cupsResolveConflicts(No option/choice): ", stdout);
719 num_options = 0;
720 options = NULL;
721 if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
722 num_options == 1 && !_cups_strcasecmp(options->name, "Quality") &&
723 !_cups_strcasecmp(options->value, "Normal"))
724 puts("PASS");
725 else if (num_options > 0)
726 {
727 printf("FAIL (%d options:", num_options);
728 for (i = 0; i < num_options; i ++)
729 printf(" %s=%s", options[i].name, options[i].value);
730 puts(")");
731 status ++;
732 }
733 else
734 {
735 puts("FAIL (Unable to resolve!)");
736 status ++;
737 }
738 cupsFreeOptions(num_options, options);
739
740 fputs("cupsResolveConflicts(loop test): ", stdout);
741 ppdMarkOption(ppd, "PageSize", "A4");
742 ppdMarkOption(ppd, "InputSlot", "Tray");
743 ppdMarkOption(ppd, "Quality", "Photo");
744 num_options = 0;
745 options = NULL;
746 if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options))
747 puts("PASS");
748 else if (num_options > 0)
749 {
750 printf("FAIL (%d options:", num_options);
751 for (i = 0; i < num_options; i ++)
752 printf(" %s=%s", options[i].name, options[i].value);
753 puts(")");
754 }
755 else
756 puts("FAIL (No conflicts!)");
757
758 fputs("ppdInstallableConflict(): ", stdout);
759 if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
760 !ppdInstallableConflict(ppd, "Duplex", "None"))
761 puts("PASS");
762 else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
763 {
764 puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
765 status ++;
766 }
767 else
768 {
769 puts("FAIL (Duplex=None conflicted)");
770 status ++;
771 }
772
773 /*
774 * ppdPageSizeLimits
775 */
776
777 ppdMarkDefaults(ppd);
778
779 fputs("ppdPageSizeLimits(default): ", stdout);
780 if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
781 {
782 if (fabs(minsize.width - 36.0) > 0.001 || fabs(minsize.length - 36.0) > 0.001 ||
783 fabs(maxsize.width - 1080.0) > 0.001 || fabs(maxsize.length - 86400.0) > 0.001)
784 {
785 printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
786 "expected min=36x36, max=1080x86400)\n", minsize.width,
787 minsize.length, maxsize.width, maxsize.length);
788 status ++;
789 }
790 else
791 puts("PASS");
792 }
793 else
794 {
795 puts("FAIL (returned 0)");
796 status ++;
797 }
798
799 ppdMarkOption(ppd, "InputSlot", "Manual");
800
801 fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout);
802 if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
803 {
804 if (fabs(minsize.width - 100.0) > 0.001 || fabs(minsize.length - 100.0) > 0.001 ||
805 fabs(maxsize.width - 1000.0) > 0.001 || fabs(maxsize.length - 1000.0) > 0.001)
806 {
807 printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
808 "expected min=100x100, max=1000x1000)\n", minsize.width,
809 minsize.length, maxsize.width, maxsize.length);
810 status ++;
811 }
812 else
813 puts("PASS");
814 }
815 else
816 {
817 puts("FAIL (returned 0)");
818 status ++;
819 }
820
821 ppdMarkOption(ppd, "Quality", "Photo");
822
823 fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
824 if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
825 {
826 if (fabs(minsize.width - 200.0) > 0.001 || fabs(minsize.length - 200.0) > 0.001 ||
827 fabs(maxsize.width - 1000.0) > 0.001 || fabs(maxsize.length - 1000.0) > 0.001)
828 {
829 printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
830 "expected min=200x200, max=1000x1000)\n", minsize.width,
831 minsize.length, maxsize.width, maxsize.length);
832 status ++;
833 }
834 else
835 puts("PASS");
836 }
837 else
838 {
839 puts("FAIL (returned 0)");
840 status ++;
841 }
842
843 ppdMarkOption(ppd, "InputSlot", "Tray");
844
845 fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
846 if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
847 {
848 if (fabs(minsize.width - 300.0) > 0.001 || fabs(minsize.length - 300.0) > 0.001 ||
849 fabs(maxsize.width - 1080.0) > 0.001 || fabs(maxsize.length - 86400.0) > 0.001)
850 {
851 printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
852 "expected min=300x300, max=1080x86400)\n", minsize.width,
853 minsize.length, maxsize.width, maxsize.length);
854 status ++;
855 }
856 else
857 puts("PASS");
858 }
859 else
860 {
861 puts("FAIL (returned 0)");
862 status ++;
863 }
864 }
865 else if (!strncmp(argv[1], "ipp://", 6) || !strncmp(argv[1], "ipps://", 7))
866 {
867 /*
868 * ipp://... or ipps://...
869 */
870
871 http_t *http; /* Connection to printer */
872 ipp_t *request, /* Get-Printer-Attributes request */
873 *response; /* Get-Printer-Attributes response */
874 char scheme[32], /* URI scheme */
875 userpass[256], /* Username:password */
876 host[256], /* Hostname */
877 resource[256]; /* Resource path */
878 int port; /* Port number */
879 static const char * const pattrs[] =/* Requested printer attributes */
880 {
881 "job-template",
882 "printer-defaults",
883 "printer-description",
884 "media-col-database"
885 };
886
887 if (httpSeparateURI(HTTP_URI_CODING_ALL, argv[1], scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
888 {
889 printf("Bad URI \"%s\".\n", argv[1]);
890 return (1);
891 }
892
893 http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
894 if (!http)
895 {
896 printf("Unable to connect to \"%s:%d\": %s\n", host, port, cupsLastErrorString());
897 return (1);
898 }
899
900 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
901 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, argv[1]);
902 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs);
903 response = cupsDoRequest(http, request, resource);
904
905 if (_ppdCreateFromIPP(buffer, sizeof(buffer), response))
906 printf("Created PPD: %s\n", buffer);
907 else
908 puts("Unable to create PPD.");
909
910 ippDelete(response);
911 httpClose(http);
912 return (0);
913 }
914 else
915 {
916 const char *filename; /* PPD filename */
917 struct stat fileinfo; /* File information */
918
919
920 if (strchr(argv[1], ':'))
921 {
922 /*
923 * Server PPD...
924 */
925
926 if ((filename = cupsGetServerPPD(CUPS_HTTP_DEFAULT, argv[1])) == NULL)
927 {
928 printf("%s: %s\n", argv[1], cupsLastErrorString());
929 return (1);
930 }
931 }
932 else if (!strncmp(argv[1], "-d", 2))
933 {
934 const char *printer; /* Printer name */
935
936 if (argv[1][2])
937 printer = argv[1] + 2;
938 else if (argv[2])
939 printer = argv[2];
940 else
941 {
942 puts("Usage: ./testppd -d printer");
943 return (1);
944 }
945
946 filename = cupsGetPPD(printer);
947
948 if (!filename)
949 {
950 printf("%s: %s\n", printer, cupsLastErrorString());
951 return (1);
952 }
953 }
954 else
955 filename = argv[1];
956
957 if (lstat(filename, &fileinfo))
958 {
959 printf("%s: %s\n", filename, strerror(errno));
960 return (1);
961 }
962
963 if (S_ISLNK(fileinfo.st_mode))
964 {
965 char realfile[1024]; /* Real file path */
966 ssize_t realsize; /* Size of real file path */
967
968
969 if ((realsize = readlink(filename, realfile, sizeof(realfile) - 1)) < 0)
970 strlcpy(realfile, "Unknown", sizeof(realfile));
971 else
972 realfile[realsize] = '\0';
973
974 if (stat(realfile, &fileinfo))
975 printf("%s: symlink to \"%s\", %s\n", filename, realfile,
976 strerror(errno));
977 else
978 printf("%s: symlink to \"%s\", %ld bytes\n", filename, realfile,
979 (long)fileinfo.st_size);
980 }
981 else
982 printf("%s: regular file, %ld bytes\n", filename, (long)fileinfo.st_size);
983
984 if ((ppd = ppdOpenFile(filename)) == NULL)
985 {
986 ppd_status_t err; /* Last error in file */
987 int line; /* Line number in file */
988
989
990 status ++;
991 err = ppdLastError(&line);
992
993 printf("%s: %s on line %d\n", argv[1], ppdErrorString(err), line);
994 }
995 else
996 {
997 int j, k; /* Looping vars */
998 ppd_group_t *group; /* Option group */
999 ppd_option_t *option; /* Option */
1000 ppd_coption_t *coption; /* Custom option */
1001 ppd_cparam_t *cparam; /* Custom parameter */
1002 ppd_const_t *c; /* UIConstraints */
1003 char lang[255], /* LANG environment variable */
1004 lc_all[255], /* LC_ALL environment variable */
1005 lc_ctype[255], /* LC_CTYPE environment variable */
1006 lc_messages[255];/* LC_MESSAGES environment variable */
1007
1008
1009 if (argc > 2)
1010 {
1011 snprintf(lang, sizeof(lang), "LANG=%s", argv[2]);
1012 putenv(lang);
1013 snprintf(lc_all, sizeof(lc_all), "LC_ALL=%s", argv[2]);
1014 putenv(lc_all);
1015 snprintf(lc_ctype, sizeof(lc_ctype), "LC_CTYPE=%s", argv[2]);
1016 putenv(lc_ctype);
1017 snprintf(lc_messages, sizeof(lc_messages), "LC_MESSAGES=%s", argv[2]);
1018 putenv(lc_messages);
1019 }
1020
1021 ppdLocalize(ppd);
1022 ppdMarkDefaults(ppd);
1023
1024 if (argc > 3)
1025 {
1026 text = ppdLocalizeIPPReason(ppd, argv[3], NULL, buffer, sizeof(buffer));
1027 printf("ppdLocalizeIPPReason(%s)=%s\n", argv[3],
1028 text ? text : "(null)");
1029 return (text == NULL);
1030 }
1031
1032 for (i = ppd->num_groups, group = ppd->groups;
1033 i > 0;
1034 i --, group ++)
1035 {
1036 printf("%s (%s):\n", group->name, group->text);
1037
1038 for (j = group->num_options, option = group->options;
1039 j > 0;
1040 j --, option ++)
1041 {
1042 printf(" %s (%s):\n", option->keyword, option->text);
1043
1044 for (k = 0; k < option->num_choices; k ++)
1045 printf(" - %s%s (%s)\n",
1046 option->choices[k].marked ? "*" : "",
1047 option->choices[k].choice, option->choices[k].text);
1048
1049 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1050 {
1051 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
1052 cparam;
1053 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
1054 {
1055 switch (cparam->type)
1056 {
1057 case PPD_CUSTOM_CURVE :
1058 printf(" %s(%s): PPD_CUSTOM_CURVE (%g to %g)\n",
1059 cparam->name, cparam->text,
1060 cparam->minimum.custom_curve,
1061 cparam->maximum.custom_curve);
1062 break;
1063
1064 case PPD_CUSTOM_INT :
1065 printf(" %s(%s): PPD_CUSTOM_INT (%d to %d)\n",
1066 cparam->name, cparam->text,
1067 cparam->minimum.custom_int,
1068 cparam->maximum.custom_int);
1069 break;
1070
1071 case PPD_CUSTOM_INVCURVE :
1072 printf(" %s(%s): PPD_CUSTOM_INVCURVE (%g to %g)\n",
1073 cparam->name, cparam->text,
1074 cparam->minimum.custom_invcurve,
1075 cparam->maximum.custom_invcurve);
1076 break;
1077
1078 case PPD_CUSTOM_PASSCODE :
1079 printf(" %s(%s): PPD_CUSTOM_PASSCODE (%d to %d)\n",
1080 cparam->name, cparam->text,
1081 cparam->minimum.custom_passcode,
1082 cparam->maximum.custom_passcode);
1083 break;
1084
1085 case PPD_CUSTOM_PASSWORD :
1086 printf(" %s(%s): PPD_CUSTOM_PASSWORD (%d to %d)\n",
1087 cparam->name, cparam->text,
1088 cparam->minimum.custom_password,
1089 cparam->maximum.custom_password);
1090 break;
1091
1092 case PPD_CUSTOM_POINTS :
1093 printf(" %s(%s): PPD_CUSTOM_POINTS (%g to %g)\n",
1094 cparam->name, cparam->text,
1095 cparam->minimum.custom_points,
1096 cparam->maximum.custom_points);
1097 break;
1098
1099 case PPD_CUSTOM_REAL :
1100 printf(" %s(%s): PPD_CUSTOM_REAL (%g to %g)\n",
1101 cparam->name, cparam->text,
1102 cparam->minimum.custom_real,
1103 cparam->maximum.custom_real);
1104 break;
1105
1106 case PPD_CUSTOM_STRING :
1107 printf(" %s(%s): PPD_CUSTOM_STRING (%d to %d)\n",
1108 cparam->name, cparam->text,
1109 cparam->minimum.custom_string,
1110 cparam->maximum.custom_string);
1111 break;
1112 }
1113 }
1114 }
1115 }
1116 }
1117
1118 puts("\nSizes:");
1119 for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
1120 printf(" %s = %gx%g, [%g %g %g %g]\n", size->name, size->width,
1121 size->length, size->left, size->bottom, size->right, size->top);
1122
1123 puts("\nConstraints:");
1124
1125 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
1126 printf(" *UIConstraints: *%s %s *%s %s\n", c->option1, c->choice1,
1127 c->option2, c->choice2);
1128 if (ppd->num_consts == 0)
1129 puts(" NO CONSTRAINTS");
1130
1131 puts("\nFilters:");
1132
1133 for (i = 0; i < ppd->num_filters; i ++)
1134 printf(" %s\n", ppd->filters[i]);
1135
1136 if (ppd->num_filters == 0)
1137 puts(" NO FILTERS");
1138
1139 puts("\nAttributes:");
1140
1141 for (attr = (ppd_attr_t *)cupsArrayFirst(ppd->sorted_attrs);
1142 attr;
1143 attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs))
1144 printf(" *%s %s/%s: \"%s\"\n", attr->name, attr->spec,
1145 attr->text, attr->value ? attr->value : "");
1146
1147 puts("\nPPD Cache:");
1148 if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL)
1149 printf(" Unable to create: %s\n", cupsLastErrorString());
1150 else
1151 {
1152 _ppdCacheWriteFile(pc, "t.cache", NULL);
1153 puts(" Wrote t.cache.");
1154 }
1155 }
1156
1157 if (!strncmp(argv[1], "-d", 2))
1158 unlink(filename);
1159 }
1160
1161 #ifdef __APPLE__
1162 if (getenv("MallocStackLogging") && getenv("MallocStackLoggingNoCompact"))
1163 {
1164 char command[1024]; /* malloc_history command */
1165
1166 snprintf(command, sizeof(command), "malloc_history %d -all_by_size",
1167 getpid());
1168 fflush(stdout);
1169 system(command);
1170 }
1171 #endif /* __APPLE__ */
1172
1173 ppdClose(ppd);
1174
1175 return (status);
1176 }
1177