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