1 /*
2  * PPD test program for CUPS.
3  *
4  * Copyright © 2007-2018 by Apple Inc.
5  * Copyright © 1997-2006 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 #undef _CUPS_NO_DEPRECATED
16 #include "cups-private.h"
17 #include "ppd-private.h"
18 #include "raster-private.h"
19 #include <sys/stat.h>
20 #ifdef _WIN32
21 #  include <io.h>
22 #else
23 #  include <unistd.h>
24 #  include <fcntl.h>
25 #endif /* _WIN32 */
26 #include <math.h>
27 
28 
29 /*
30  * Local functions...
31  */
32 
33 static int	do_ppd_tests(const char *filename, int num_options, cups_option_t *options);
34 static int	do_ps_tests(void);
35 static void	print_changes(cups_page_header2_t *header, cups_page_header2_t *expected);
36 
37 
38 /*
39  * Test data...
40  */
41 
42 static const char *dsc_code =
43 "[{\n"
44 "%%BeginFeature: *PageSize Tabloid\n"
45 "<</PageSize[792 1224]>>setpagedevice\n"
46 "%%EndFeature\n"
47 "} stopped cleartomark\n";
48 static const char *setpagedevice_code =
49 "<<"
50 "/MediaClass(Media Class)"
51 "/MediaColor((Media Color))"
52 "/MediaType(Media\\\\Type)"
53 "/OutputType<416263>"
54 "/AdvanceDistance 1000"
55 "/AdvanceMedia 1"
56 "/Collate false"
57 "/CutMedia 2"
58 "/Duplex true"
59 "/HWResolution[100 200]"
60 "/InsertSheet true"
61 "/Jog 3"
62 "/LeadingEdge 1"
63 "/ManualFeed true"
64 "/MediaPosition 8#777"
65 "/MediaWeight 16#fe01"
66 "/MirrorPrint true"
67 "/NegativePrint true"
68 "/NumCopies 1"
69 "/Orientation 1"
70 "/OutputFaceUp true"
71 "/PageSize[612 792.1]"
72 "/Separations true"
73 "/TraySwitch true"
74 "/Tumble true"
75 "/cupsMediaType 2"
76 "/cupsColorOrder 1"
77 "/cupsColorSpace 1"
78 "/cupsCompression 1"
79 "/cupsRowCount 1"
80 "/cupsRowFeed 1"
81 "/cupsRowStep 1"
82 "/cupsBorderlessScalingFactor 1.001"
83 "/cupsInteger0 1"
84 "/cupsInteger1 2"
85 "/cupsInteger2 3"
86 "/cupsInteger3 4"
87 "/cupsInteger4 5"
88 "/cupsInteger5 6"
89 "/cupsInteger6 7"
90 "/cupsInteger7 8"
91 "/cupsInteger8 9"
92 "/cupsInteger9 10"
93 "/cupsInteger10 11"
94 "/cupsInteger11 12"
95 "/cupsInteger12 13"
96 "/cupsInteger13 14"
97 "/cupsInteger14 15"
98 "/cupsInteger15 16"
99 "/cupsReal0 1.1"
100 "/cupsReal1 2.1"
101 "/cupsReal2 3.1"
102 "/cupsReal3 4.1"
103 "/cupsReal4 5.1"
104 "/cupsReal5 6.1"
105 "/cupsReal6 7.1"
106 "/cupsReal7 8.1"
107 "/cupsReal8 9.1"
108 "/cupsReal9 10.1"
109 "/cupsReal10 11.1"
110 "/cupsReal11 12.1"
111 "/cupsReal12 13.1"
112 "/cupsReal13 14.1"
113 "/cupsReal14 15.1"
114 "/cupsReal15 16.1"
115 "/cupsString0(1)"
116 "/cupsString1(2)"
117 "/cupsString2(3)"
118 "/cupsString3(4)"
119 "/cupsString4(5)"
120 "/cupsString5(6)"
121 "/cupsString6(7)"
122 "/cupsString7(8)"
123 "/cupsString8(9)"
124 "/cupsString9(10)"
125 "/cupsString10(11)"
126 "/cupsString11(12)"
127 "/cupsString12(13)"
128 "/cupsString13(14)"
129 "/cupsString14(15)"
130 "/cupsString15(16)"
131 "/cupsMarkerType(Marker Type)"
132 "/cupsRenderingIntent(Rendering Intent)"
133 "/cupsPageSizeName(Letter)"
134 "/cupsPreferredBitsPerColor 17"
135 ">> setpagedevice";
136 
137 static cups_page_header2_t setpagedevice_header =
138 {
139   "Media Class",			/* MediaClass */
140   "(Media Color)",			/* MediaColor */
141   "Media\\Type",			/* MediaType */
142   "Abc",				/* OutputType */
143   1000,					/* AdvanceDistance */
144   CUPS_ADVANCE_FILE,			/* AdvanceMedia */
145   CUPS_FALSE,				/* Collate */
146   CUPS_CUT_JOB,				/* CutMedia */
147   CUPS_TRUE,				/* Duplex */
148   { 100, 200 },				/* HWResolution */
149   { 0, 0, 0, 0 },			/* ImagingBoundingBox */
150   CUPS_TRUE,				/* InsertSheet */
151   CUPS_JOG_SET,				/* Jog */
152   CUPS_EDGE_RIGHT,			/* LeadingEdge */
153   { 0, 0 },				/* Margins */
154   CUPS_TRUE,				/* ManualFeed */
155   0777,					/* MediaPosition */
156   0xfe01,				/* MediaWeight */
157   CUPS_TRUE,				/* MirrorPrint */
158   CUPS_TRUE,				/* NegativePrint */
159   1,					/* NumCopies */
160   CUPS_ORIENT_90,			/* Orientation */
161   CUPS_TRUE,				/* OutputFaceUp */
162   { 612, 792 },				/* PageSize */
163   CUPS_TRUE,				/* Separations */
164   CUPS_TRUE,				/* TraySwitch */
165   CUPS_TRUE,				/* Tumble */
166   0,					/* cupsWidth */
167   0,					/* cupsHeight */
168   2,					/* cupsMediaType */
169   0,					/* cupsBitsPerColor */
170   0,					/* cupsBitsPerPixel */
171   0,					/* cupsBytesPerLine */
172   CUPS_ORDER_BANDED,			/* cupsColorOrder */
173   CUPS_CSPACE_RGB,			/* cupsColorSpace */
174   1,					/* cupsCompression */
175   1,					/* cupsRowCount */
176   1,					/* cupsRowFeed */
177   1,					/* cupsRowStep */
178   0,					/* cupsNumColors */
179   1.001f,				/* cupsBorderlessScalingFactor */
180   { 612.0f, 792.1f },			/* cupsPageSize */
181   { 0.0f, 0.0f, 0.0f, 0.0f },		/* cupsImagingBBox */
182   { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 },
183 					/* cupsInteger[16] */
184   { 1.1f, 2.1f, 3.1f, 4.1f, 5.1f, 6.1f, 7.1f, 8.1f, 9.1f, 10.1f, 11.1f, 12.1f, 13.1f, 14.1f, 15.1f, 16.1f },			/* cupsReal[16] */
185   { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13",
186     "14", "15", "16" },			/* cupsString[16] */
187   "Marker Type",			/* cupsMarkerType */
188   "Rendering Intent",			/* cupsRenderingIntent */
189   "Letter"				/* cupsPageSizeName */
190 };
191 
192 static const char	*default_code =
193 			"[{\n"
194 			"%%BeginFeature: *InstalledDuplexer False\n"
195 			"%%EndFeature\n"
196 			"} stopped cleartomark\n"
197 			"[{\n"
198 			"%%BeginFeature: *PageRegion Letter\n"
199 			"PageRegion=Letter\n"
200 			"%%EndFeature\n"
201 			"} stopped cleartomark\n"
202 			"[{\n"
203 			"%%BeginFeature: *InputSlot Tray\n"
204 			"InputSlot=Tray\n"
205 			"%%EndFeature\n"
206 			"} stopped cleartomark\n"
207 			"[{\n"
208 			"%%BeginFeature: *OutputBin Tray1\n"
209 			"OutputBin=Tray1\n"
210 			"%%EndFeature\n"
211 			"} stopped cleartomark\n"
212 			"[{\n"
213 			"%%BeginFeature: *MediaType Plain\n"
214 			"MediaType=Plain\n"
215 			"%%EndFeature\n"
216 			"} stopped cleartomark\n"
217 			"[{\n"
218 			"%%BeginFeature: *IntOption None\n"
219 			"%%EndFeature\n"
220 			"} stopped cleartomark\n"
221 			"[{\n"
222 			"%%BeginFeature: *StringOption None\n"
223 			"%%EndFeature\n"
224 			"} stopped cleartomark\n";
225 
226 static const char	*custom_code =
227 			"[{\n"
228 			"%%BeginFeature: *InstalledDuplexer False\n"
229 			"%%EndFeature\n"
230 			"} stopped cleartomark\n"
231 			"[{\n"
232 			"%%BeginFeature: *InputSlot Tray\n"
233 			"InputSlot=Tray\n"
234 			"%%EndFeature\n"
235 			"} stopped cleartomark\n"
236 			"[{\n"
237 			"%%BeginFeature: *MediaType Plain\n"
238 			"MediaType=Plain\n"
239 			"%%EndFeature\n"
240 			"} stopped cleartomark\n"
241 			"[{\n"
242 			"%%BeginFeature: *OutputBin Tray1\n"
243 			"OutputBin=Tray1\n"
244 			"%%EndFeature\n"
245 			"} stopped cleartomark\n"
246 			"[{\n"
247 			"%%BeginFeature: *IntOption None\n"
248 			"%%EndFeature\n"
249 			"} stopped cleartomark\n"
250 			"[{\n"
251 			"%%BeginFeature: *CustomStringOption True\n"
252 			"(value\\0502\\051)\n"
253 			"(value 1)\n"
254 			"StringOption=Custom\n"
255 			"%%EndFeature\n"
256 			"} stopped cleartomark\n"
257 			"[{\n"
258 			"%%BeginFeature: *CustomPageSize True\n"
259 			"400\n"
260 			"500\n"
261 			"0\n"
262 			"0\n"
263 			"0\n"
264 			"PageSize=Custom\n"
265 			"%%EndFeature\n"
266 			"} stopped cleartomark\n";
267 
268 static const char	*default2_code =
269 			"[{\n"
270 			"%%BeginFeature: *InstalledDuplexer False\n"
271 			"%%EndFeature\n"
272 			"} stopped cleartomark\n"
273 			"[{\n"
274 			"%%BeginFeature: *InputSlot Tray\n"
275 			"InputSlot=Tray\n"
276 			"%%EndFeature\n"
277 			"} stopped cleartomark\n"
278 			"[{\n"
279 			"%%BeginFeature: *Quality Normal\n"
280 			"Quality=Normal\n"
281 			"%%EndFeature\n"
282 			"} stopped cleartomark\n"
283 			"[{\n"
284 			"%%BeginFeature: *IntOption None\n"
285 			"%%EndFeature\n"
286 			"} stopped cleartomark\n"
287 			"[{\n"
288 			"%%BeginFeature: *StringOption None\n"
289 			"%%EndFeature\n"
290 			"} stopped cleartomark\n";
291 
292 
293 /*
294  * 'main()' - Main entry.
295  */
296 
297 int					/* O - Exit status */
main(int argc,char * argv[])298 main(int  argc,				/* I - Number of command-line arguments */
299      char *argv[])			/* I - Command-line arguments */
300 {
301   int		i;			/* Looping var */
302   ppd_file_t	*ppd = NULL;		/* PPD file loaded from disk */
303   int		status;			/* Status of tests (0 = success, 1 = fail) */
304   int		conflicts;		/* Number of conflicts */
305   char		*s;			/* String */
306   char		buffer[8192];		/* String buffer */
307   const char	*text,			/* Localized text */
308 		*val;			/* Option value */
309   int		num_options;		/* Number of options */
310   cups_option_t	*options;		/* Options */
311   ppd_size_t	minsize,		/* Minimum size */
312 		maxsize,		/* Maximum size */
313 		*size;			/* Current size */
314   ppd_attr_t	*attr;			/* Current attribute */
315   _ppd_cache_t	*pc;			/* PPD cache */
316 
317 
318   status = 0;
319 
320   if (argc == 1)
321   {
322    /*
323     * Setup directories for locale stuff...
324     */
325 
326     if (access("locale", 0))
327     {
328       mkdir("locale", 0777);
329       mkdir("locale/fr", 0777);
330       symlink("../../../locale/cups_fr.po", "locale/fr/cups_fr.po");
331       mkdir("locale/zh_TW", 0777);
332       symlink("../../../locale/cups_zh_TW.po", "locale/zh_TW/cups_zh_TW.po");
333     }
334 
335     putenv("LOCALEDIR=locale");
336     putenv("SOFTWARE=CUPS");
337 
338    /*
339     * Do tests with test.ppd...
340     */
341 
342     fputs("ppdOpenFile(test.ppd): ", stdout);
343 
344     if ((ppd = _ppdOpenFile("test.ppd", _PPD_LOCALIZATION_ALL)) != NULL)
345       puts("PASS");
346     else
347     {
348       ppd_status_t	err;		/* Last error in file */
349       int		line;		/* Line number in file */
350 
351 
352       status ++;
353       err = ppdLastError(&line);
354 
355       printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
356     }
357 
358     fputs("ppdFindAttr(wildcard): ", stdout);
359     if ((attr = ppdFindAttr(ppd, "cupsTest", NULL)) == NULL)
360     {
361       status ++;
362       puts("FAIL (not found)");
363     }
364     else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
365     {
366       status ++;
367       printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
368     }
369     else
370       puts("PASS");
371 
372     fputs("ppdFindNextAttr(wildcard): ", stdout);
373     if ((attr = ppdFindNextAttr(ppd, "cupsTest", NULL)) == NULL)
374     {
375       status ++;
376       puts("FAIL (not found)");
377     }
378     else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Bar"))
379     {
380       status ++;
381       printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
382     }
383     else
384       puts("PASS");
385 
386     fputs("ppdFindAttr(Foo): ", stdout);
387     if ((attr = ppdFindAttr(ppd, "cupsTest", "Foo")) == NULL)
388     {
389       status ++;
390       puts("FAIL (not found)");
391     }
392     else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
393     {
394       status ++;
395       printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
396     }
397     else
398       puts("PASS");
399 
400     fputs("ppdFindNextAttr(Foo): ", stdout);
401     if ((attr = ppdFindNextAttr(ppd, "cupsTest", "Foo")) != NULL)
402     {
403       status ++;
404       printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
405     }
406     else
407       puts("PASS");
408 
409     fputs("ppdMarkDefaults: ", stdout);
410     ppdMarkDefaults(ppd);
411 
412     if ((conflicts = ppdConflicts(ppd)) == 0)
413       puts("PASS");
414     else
415     {
416       status ++;
417       printf("FAIL (%d conflicts)\n", conflicts);
418     }
419 
420     fputs("ppdEmitString (defaults): ", stdout);
421     if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
422 	!strcmp(s, default_code))
423       puts("PASS");
424     else
425     {
426       status ++;
427       printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
428 	     (int)strlen(default_code));
429 
430       if (s)
431 	puts(s);
432     }
433 
434     if (s)
435       free(s);
436 
437     fputs("ppdEmitString (custom size and string): ", stdout);
438     ppdMarkOption(ppd, "PageSize", "Custom.400x500");
439     ppdMarkOption(ppd, "StringOption", "{String1=\"value 1\" String2=value(2)}");
440 
441     if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
442 	!strcmp(s, custom_code))
443       puts("PASS");
444     else
445     {
446       status ++;
447       printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
448 	     (int)strlen(custom_code));
449 
450       if (s)
451 	puts(s);
452     }
453 
454     if (s)
455       free(s);
456 
457    /*
458     * Test constraints...
459     */
460 
461     fputs("cupsGetConflicts(InputSlot=Envelope): ", stdout);
462     ppdMarkOption(ppd, "PageSize", "Letter");
463 
464     num_options = cupsGetConflicts(ppd, "InputSlot", "Envelope", &options);
465     if (num_options != 2 ||
466         (val = cupsGetOption("PageRegion", num_options, options)) == NULL ||
467 	_cups_strcasecmp(val, "Letter") ||
468 	(val = cupsGetOption("PageSize", num_options, options)) == NULL ||
469 	_cups_strcasecmp(val, "Letter"))
470     {
471       printf("FAIL (%d options:", num_options);
472       for (i = 0; i < num_options; i ++)
473         printf(" %s=%s", options[i].name, options[i].value);
474       puts(")");
475       status ++;
476     }
477     else
478       puts("PASS");
479 
480     fputs("ppdConflicts(): ", stdout);
481     ppdMarkOption(ppd, "InputSlot", "Envelope");
482 
483     if ((conflicts = ppdConflicts(ppd)) == 2)
484       puts("PASS (2)");
485     else
486     {
487       printf("FAIL (%d)\n", conflicts);
488       status ++;
489     }
490 
491     fputs("cupsResolveConflicts(InputSlot=Envelope): ", stdout);
492     num_options = 0;
493     options     = NULL;
494     if (!cupsResolveConflicts(ppd, "InputSlot", "Envelope", &num_options,
495                              &options))
496     {
497       puts("FAIL (Unable to resolve)");
498       status ++;
499     }
500     else if (num_options != 2 ||
501              !cupsGetOption("PageSize", num_options, options))
502     {
503       printf("FAIL (%d options:", num_options);
504       for (i = 0; i < num_options; i ++)
505         printf(" %s=%s", options[i].name, options[i].value);
506       puts(")");
507       status ++;
508     }
509     else
510       puts("PASS (Resolved by changing PageSize)");
511 
512     cupsFreeOptions(num_options, options);
513 
514     fputs("cupsResolveConflicts(No option/choice): ", stdout);
515     num_options = 0;
516     options     = NULL;
517     if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
518         num_options == 1 && !_cups_strcasecmp(options[0].name, "InputSlot") &&
519 	!_cups_strcasecmp(options[0].value, "Tray"))
520       puts("PASS (Resolved by changing InputSlot)");
521     else if (num_options > 0)
522     {
523       printf("FAIL (%d options:", num_options);
524       for (i = 0; i < num_options; i ++)
525         printf(" %s=%s", options[i].name, options[i].value);
526       puts(")");
527       status ++;
528     }
529     else
530     {
531       puts("FAIL (Unable to resolve)");
532       status ++;
533     }
534     cupsFreeOptions(num_options, options);
535 
536     fputs("ppdInstallableConflict(): ", stdout);
537     if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
538         !ppdInstallableConflict(ppd, "Duplex", "None"))
539       puts("PASS");
540     else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
541     {
542       puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
543       status ++;
544     }
545     else
546     {
547       puts("FAIL (Duplex=None conflicted)");
548       status ++;
549     }
550 
551    /*
552     * ppdPageSizeLimits
553     */
554 
555     fputs("ppdPageSizeLimits: ", stdout);
556     if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
557     {
558       if (fabs(minsize.width - 36.0) > 0.001 || fabs(minsize.length - 36.0) > 0.001 ||
559           fabs(maxsize.width - 1080.0) > 0.001 || fabs(maxsize.length - 86400.0) > 0.001)
560       {
561         printf("FAIL (got min=%.3fx%.3f, max=%.3fx%.3f, "
562 	       "expected min=36x36, max=1080x86400)\n", minsize.width,
563 	       minsize.length, maxsize.width, maxsize.length);
564         status ++;
565       }
566       else
567         puts("PASS");
568     }
569     else
570     {
571       puts("FAIL (returned 0)");
572       status ++;
573     }
574 
575    /*
576     * cupsMarkOptions with PWG and IPP size names.
577     */
578 
579     fputs("cupsMarkOptions(media=iso-a4): ", stdout);
580     num_options = cupsAddOption("media", "iso-a4", 0, &options);
581     cupsMarkOptions(ppd, num_options, options);
582     cupsFreeOptions(num_options, options);
583 
584     size = ppdPageSize(ppd, NULL);
585     if (!size || strcmp(size->name, "A4"))
586     {
587       printf("FAIL (%s)\n", size ? size->name : "unknown");
588       status ++;
589     }
590     else
591       puts("PASS");
592 
593     fputs("cupsMarkOptions(media=na_letter_8.5x11in): ", stdout);
594     num_options = cupsAddOption("media", "na_letter_8.5x11in", 0, &options);
595     cupsMarkOptions(ppd, num_options, options);
596     cupsFreeOptions(num_options, options);
597 
598     size = ppdPageSize(ppd, NULL);
599     if (!size || strcmp(size->name, "Letter"))
600     {
601       printf("FAIL (%s)\n", size ? size->name : "unknown");
602       status ++;
603     }
604     else
605       puts("PASS");
606 
607     fputs("cupsMarkOptions(media=oe_letter-fullbleed_8.5x11in): ", stdout);
608     num_options = cupsAddOption("media", "oe_letter-fullbleed_8.5x11in", 0,
609                                 &options);
610     cupsMarkOptions(ppd, num_options, options);
611     cupsFreeOptions(num_options, options);
612 
613     size = ppdPageSize(ppd, NULL);
614     if (!size || strcmp(size->name, "Letter.Fullbleed"))
615     {
616       printf("FAIL (%s)\n", size ? size->name : "unknown");
617       status ++;
618     }
619     else
620       puts("PASS");
621 
622     fputs("cupsMarkOptions(media=A4): ", stdout);
623     num_options = cupsAddOption("media", "A4", 0, &options);
624     cupsMarkOptions(ppd, num_options, options);
625     cupsFreeOptions(num_options, options);
626 
627     size = ppdPageSize(ppd, NULL);
628     if (!size || strcmp(size->name, "A4"))
629     {
630       printf("FAIL (%s)\n", size ? size->name : "unknown");
631       status ++;
632     }
633     else
634       puts("PASS");
635 
636    /*
637     * Custom sizes...
638     */
639 
640     fputs("cupsMarkOptions(media=Custom.8x10in): ", stdout);
641     num_options = cupsAddOption("media", "Custom.8x10in", 0, &options);
642     cupsMarkOptions(ppd, num_options, options);
643     cupsFreeOptions(num_options, options);
644 
645     size = ppdPageSize(ppd, NULL);
646     if (!size || strcmp(size->name, "Custom") ||
647         fabs(size->width - 576.0) > 0.001 ||
648         fabs(size->length - 720.0) > 0.001)
649     {
650       printf("FAIL (%s - %gx%g)\n", size ? size->name : "unknown",
651              size ? size->width : 0.0, size ? size->length : 0.0);
652       status ++;
653     }
654     else
655       puts("PASS");
656 
657    /*
658     * Test localization...
659     */
660 
661     fputs("ppdLocalizeIPPReason(text): ", stdout);
662     if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
663         !strcmp(buffer, "Foo Reason"))
664       puts("PASS");
665     else
666     {
667       status ++;
668       printf("FAIL (\"%s\" instead of \"Foo Reason\")\n", buffer);
669     }
670 
671     fputs("ppdLocalizeIPPReason(http): ", stdout);
672     if (ppdLocalizeIPPReason(ppd, "foo", "http", buffer, sizeof(buffer)) &&
673         !strcmp(buffer, "http://foo/bar.html"))
674       puts("PASS");
675     else
676     {
677       status ++;
678       printf("FAIL (\"%s\" instead of \"http://foo/bar.html\")\n", buffer);
679     }
680 
681     fputs("ppdLocalizeIPPReason(help): ", stdout);
682     if (ppdLocalizeIPPReason(ppd, "foo", "help", buffer, sizeof(buffer)) &&
683         !strcmp(buffer, "help:anchor='foo'%20bookID=Vendor%20Help"))
684       puts("PASS");
685     else
686     {
687       status ++;
688       printf("FAIL (\"%s\" instead of \"help:anchor='foo'%%20bookID=Vendor%%20Help\")\n", buffer);
689     }
690 
691     fputs("ppdLocalizeIPPReason(file): ", stdout);
692     if (ppdLocalizeIPPReason(ppd, "foo", "file", buffer, sizeof(buffer)) &&
693         !strcmp(buffer, "/help/foo/bar.html"))
694       puts("PASS");
695     else
696     {
697       status ++;
698       printf("FAIL (\"%s\" instead of \"/help/foo/bar.html\")\n", buffer);
699     }
700 
701     putenv("LANG=fr");
702     putenv("LC_ALL=fr");
703     putenv("LC_CTYPE=fr");
704     putenv("LC_MESSAGES=fr");
705 
706     fputs("ppdLocalizeIPPReason(fr text): ", stdout);
707     if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
708         !strcmp(buffer, "La Long Foo Reason"))
709       puts("PASS");
710     else
711     {
712       status ++;
713       printf("FAIL (\"%s\" instead of \"La Long Foo Reason\")\n", buffer);
714     }
715 
716     putenv("LANG=zh_TW");
717     putenv("LC_ALL=zh_TW");
718     putenv("LC_CTYPE=zh_TW");
719     putenv("LC_MESSAGES=zh_TW");
720 
721     fputs("ppdLocalizeIPPReason(zh_TW text): ", stdout);
722     if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
723         !strcmp(buffer, "Number 1 Foo Reason"))
724       puts("PASS");
725     else
726     {
727       status ++;
728       printf("FAIL (\"%s\" instead of \"Number 1 Foo Reason\")\n", buffer);
729     }
730 
731    /*
732     * cupsMarkerName localization...
733     */
734 
735     putenv("LANG=en");
736     putenv("LC_ALL=en");
737     putenv("LC_CTYPE=en");
738     putenv("LC_MESSAGES=en");
739 
740     fputs("ppdLocalizeMarkerName(bogus): ", stdout);
741 
742     if ((text = ppdLocalizeMarkerName(ppd, "bogus")) != NULL)
743     {
744       status ++;
745       printf("FAIL (\"%s\" instead of NULL)\n", text);
746     }
747     else
748       puts("PASS");
749 
750     fputs("ppdLocalizeMarkerName(cyan): ", stdout);
751 
752     if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
753         !strcmp(text, "Cyan Toner"))
754       puts("PASS");
755     else
756     {
757       status ++;
758       printf("FAIL (\"%s\" instead of \"Cyan Toner\")\n",
759              text ? text : "(null)");
760     }
761 
762     putenv("LANG=fr");
763     putenv("LC_ALL=fr");
764     putenv("LC_CTYPE=fr");
765     putenv("LC_MESSAGES=fr");
766 
767     fputs("ppdLocalizeMarkerName(fr cyan): ", stdout);
768     if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
769         !strcmp(text, "La Toner Cyan"))
770       puts("PASS");
771     else
772     {
773       status ++;
774       printf("FAIL (\"%s\" instead of \"La Toner Cyan\")\n",
775              text ? text : "(null)");
776     }
777 
778     putenv("LANG=zh_TW");
779     putenv("LC_ALL=zh_TW");
780     putenv("LC_CTYPE=zh_TW");
781     putenv("LC_MESSAGES=zh_TW");
782 
783     fputs("ppdLocalizeMarkerName(zh_TW cyan): ", stdout);
784     if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
785         !strcmp(text, "Number 1 Cyan Toner"))
786       puts("PASS");
787     else
788     {
789       status ++;
790       printf("FAIL (\"%s\" instead of \"Number 1 Cyan Toner\")\n",
791              text ? text : "(null)");
792     }
793 
794     ppdClose(ppd);
795 
796    /*
797     * Test new constraints...
798     */
799 
800     fputs("ppdOpenFile(test2.ppd): ", stdout);
801 
802     if ((ppd = ppdOpenFile("test2.ppd")) != NULL)
803       puts("PASS");
804     else
805     {
806       ppd_status_t	err;		/* Last error in file */
807       int		line;		/* Line number in file */
808 
809 
810       status ++;
811       err = ppdLastError(&line);
812 
813       printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
814     }
815 
816     fputs("ppdMarkDefaults: ", stdout);
817     ppdMarkDefaults(ppd);
818 
819     if ((conflicts = ppdConflicts(ppd)) == 0)
820       puts("PASS");
821     else
822     {
823       status ++;
824       printf("FAIL (%d conflicts)\n", conflicts);
825     }
826 
827     fputs("ppdEmitString (defaults): ", stdout);
828     if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
829 	!strcmp(s, default2_code))
830       puts("PASS");
831     else
832     {
833       status ++;
834       printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
835 	     (int)strlen(default2_code));
836 
837       if (s)
838 	puts(s);
839     }
840 
841     if (s)
842       free(s);
843 
844     fputs("ppdConflicts(): ", stdout);
845     ppdMarkOption(ppd, "PageSize", "Env10");
846     ppdMarkOption(ppd, "InputSlot", "Envelope");
847     ppdMarkOption(ppd, "Quality", "Photo");
848 
849     if ((conflicts = ppdConflicts(ppd)) == 1)
850       puts("PASS (1)");
851     else
852     {
853       printf("FAIL (%d)\n", conflicts);
854       status ++;
855     }
856 
857     fputs("cupsResolveConflicts(Quality=Photo): ", stdout);
858     num_options = 0;
859     options     = NULL;
860     if (cupsResolveConflicts(ppd, "Quality", "Photo", &num_options,
861                              &options))
862     {
863       printf("FAIL (%d options:", num_options);
864       for (i = 0; i < num_options; i ++)
865         printf(" %s=%s", options[i].name, options[i].value);
866       puts(")");
867       status ++;
868     }
869     else
870       puts("PASS (Unable to resolve)");
871     cupsFreeOptions(num_options, options);
872 
873     fputs("cupsResolveConflicts(No option/choice): ", stdout);
874     num_options = 0;
875     options     = NULL;
876     if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
877         num_options == 1 && !_cups_strcasecmp(options->name, "Quality") &&
878 	!_cups_strcasecmp(options->value, "Normal"))
879       puts("PASS");
880     else if (num_options > 0)
881     {
882       printf("FAIL (%d options:", num_options);
883       for (i = 0; i < num_options; i ++)
884         printf(" %s=%s", options[i].name, options[i].value);
885       puts(")");
886       status ++;
887     }
888     else
889     {
890       puts("FAIL (Unable to resolve!)");
891       status ++;
892     }
893     cupsFreeOptions(num_options, options);
894 
895     fputs("cupsResolveConflicts(loop test): ", stdout);
896     ppdMarkOption(ppd, "PageSize", "A4");
897     ppdMarkOption(ppd, "InputSlot", "Tray");
898     ppdMarkOption(ppd, "Quality", "Photo");
899     num_options = 0;
900     options     = NULL;
901     if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options))
902       puts("PASS");
903     else if (num_options > 0)
904     {
905       printf("FAIL (%d options:", num_options);
906       for (i = 0; i < num_options; i ++)
907         printf(" %s=%s", options[i].name, options[i].value);
908       puts(")");
909     }
910     else
911       puts("FAIL (No conflicts!)");
912 
913     fputs("ppdInstallableConflict(): ", stdout);
914     if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
915         !ppdInstallableConflict(ppd, "Duplex", "None"))
916       puts("PASS");
917     else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
918     {
919       puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
920       status ++;
921     }
922     else
923     {
924       puts("FAIL (Duplex=None conflicted)");
925       status ++;
926     }
927 
928    /*
929     * ppdPageSizeLimits
930     */
931 
932     ppdMarkDefaults(ppd);
933 
934     fputs("ppdPageSizeLimits(default): ", stdout);
935     if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
936     {
937       if (fabs(minsize.width - 36.0) > 0.001 || fabs(minsize.length - 36.0) > 0.001 ||
938           fabs(maxsize.width - 1080.0) > 0.001 || fabs(maxsize.length - 86400.0) > 0.001)
939       {
940         printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
941 	       "expected min=36x36, max=1080x86400)\n", minsize.width,
942 	       minsize.length, maxsize.width, maxsize.length);
943         status ++;
944       }
945       else
946         puts("PASS");
947     }
948     else
949     {
950       puts("FAIL (returned 0)");
951       status ++;
952     }
953 
954     ppdMarkOption(ppd, "InputSlot", "Manual");
955 
956     fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout);
957     if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
958     {
959       if (fabs(minsize.width - 100.0) > 0.001 || fabs(minsize.length - 100.0) > 0.001 ||
960           fabs(maxsize.width - 1000.0) > 0.001 || fabs(maxsize.length - 1000.0) > 0.001)
961       {
962         printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
963 	       "expected min=100x100, max=1000x1000)\n", minsize.width,
964 	       minsize.length, maxsize.width, maxsize.length);
965         status ++;
966       }
967       else
968         puts("PASS");
969     }
970     else
971     {
972       puts("FAIL (returned 0)");
973       status ++;
974     }
975 
976     ppdMarkOption(ppd, "Quality", "Photo");
977 
978     fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
979     if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
980     {
981       if (fabs(minsize.width - 200.0) > 0.001 || fabs(minsize.length - 200.0) > 0.001 ||
982           fabs(maxsize.width - 1000.0) > 0.001 || fabs(maxsize.length - 1000.0) > 0.001)
983       {
984         printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
985 	       "expected min=200x200, max=1000x1000)\n", minsize.width,
986 	       minsize.length, maxsize.width, maxsize.length);
987         status ++;
988       }
989       else
990         puts("PASS");
991     }
992     else
993     {
994       puts("FAIL (returned 0)");
995       status ++;
996     }
997 
998     ppdMarkOption(ppd, "InputSlot", "Tray");
999 
1000     fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
1001     if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
1002     {
1003       if (fabs(minsize.width - 300.0) > 0.001 || fabs(minsize.length - 300.0) > 0.001 ||
1004           fabs(maxsize.width - 1080.0) > 0.001 || fabs(maxsize.length - 86400.0) > 0.001)
1005       {
1006         printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
1007 	       "expected min=300x300, max=1080x86400)\n", minsize.width,
1008 	       minsize.length, maxsize.width, maxsize.length);
1009         status ++;
1010       }
1011       else
1012         puts("PASS");
1013     }
1014     else
1015     {
1016       puts("FAIL (returned 0)");
1017       status ++;
1018     }
1019 
1020     status += do_ps_tests();
1021   }
1022   else if (!strcmp(argv[1], "--raster"))
1023   {
1024     for (status = 0, num_options = 0, options = NULL, i = 1; i < argc; i ++)
1025     {
1026       if (argv[i][0] == '-')
1027       {
1028         if (argv[i][1] == 'o')
1029         {
1030           if (argv[i][2])
1031             num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
1032           else
1033           {
1034             i ++;
1035             if (i < argc)
1036               num_options = cupsParseOptions(argv[i], num_options, &options);
1037             else
1038             {
1039               puts("Usage: testppd --raster [-o name=value ...] [filename.ppd ...]");
1040               return (1);
1041             }
1042           }
1043         }
1044         else
1045         {
1046 	  puts("Usage: testppd --raster [-o name=value ...] [filename.ppd ...]");
1047 	  return (1);
1048         }
1049       }
1050       else
1051 	status += do_ppd_tests(argv[i], num_options, options);
1052     }
1053 
1054     cupsFreeOptions(num_options, options);
1055   }
1056   else if (!strncmp(argv[1], "ipp://", 6) || !strncmp(argv[1], "ipps://", 7))
1057   {
1058    /*
1059     * ipp://... or ipps://...
1060     */
1061 
1062     http_t	*http;			/* Connection to printer */
1063     ipp_t	*request,		/* Get-Printer-Attributes request */
1064 		*response;		/* Get-Printer-Attributes response */
1065     char	scheme[32],		/* URI scheme */
1066 		userpass[256],		/* Username:password */
1067 		host[256],		/* Hostname */
1068 		resource[256];		/* Resource path */
1069     int		port;			/* Port number */
1070     static const char * const pattrs[] =/* Requested printer attributes */
1071     {
1072       "job-template",
1073       "printer-defaults",
1074       "printer-description",
1075       "media-col-database"
1076     };
1077 
1078     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)
1079     {
1080       printf("Bad URI \"%s\".\n", argv[1]);
1081       return (1);
1082     }
1083 
1084     http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
1085     if (!http)
1086     {
1087       printf("Unable to connect to \"%s:%d\": %s\n", host, port, cupsLastErrorString());
1088       return (1);
1089     }
1090 
1091     request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1092     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, argv[1]);
1093     ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs);
1094     response = cupsDoRequest(http, request, resource);
1095 
1096     if (_ppdCreateFromIPP(buffer, sizeof(buffer), response))
1097       printf("Created PPD: %s\n", buffer);
1098     else
1099       puts("Unable to create PPD.");
1100 
1101     ippDelete(response);
1102     httpClose(http);
1103     return (0);
1104   }
1105   else
1106   {
1107     const char	*filename;		/* PPD filename */
1108     struct stat	fileinfo;		/* File information */
1109 
1110 
1111     if (strchr(argv[1], ':'))
1112     {
1113      /*
1114       * Server PPD...
1115       */
1116 
1117       if ((filename = cupsGetServerPPD(CUPS_HTTP_DEFAULT, argv[1])) == NULL)
1118       {
1119         printf("%s: %s\n", argv[1], cupsLastErrorString());
1120         return (1);
1121       }
1122     }
1123     else if (!strncmp(argv[1], "-d", 2))
1124     {
1125       const char *printer;		/* Printer name */
1126 
1127       if (argv[1][2])
1128 	printer = argv[1] + 2;
1129       else if (argv[2])
1130 	printer = argv[2];
1131       else
1132       {
1133         puts("Usage: ./testppd -d printer");
1134 	return (1);
1135       }
1136 
1137       filename = cupsGetPPD(printer);
1138 
1139       if (!filename)
1140       {
1141         printf("%s: %s\n", printer, cupsLastErrorString());
1142         return (1);
1143       }
1144     }
1145     else
1146       filename = argv[1];
1147 
1148     if (lstat(filename, &fileinfo))
1149     {
1150       printf("%s: %s\n", filename, strerror(errno));
1151       return (1);
1152     }
1153 
1154     if (S_ISLNK(fileinfo.st_mode))
1155     {
1156       char	realfile[1024];		/* Real file path */
1157       ssize_t	realsize;		/* Size of real file path */
1158 
1159 
1160       if ((realsize = readlink(filename, realfile, sizeof(realfile) - 1)) < 0)
1161         strlcpy(realfile, "Unknown", sizeof(realfile));
1162       else
1163         realfile[realsize] = '\0';
1164 
1165       if (stat(realfile, &fileinfo))
1166 	printf("%s: symlink to \"%s\", %s\n", filename, realfile,
1167 	       strerror(errno));
1168       else
1169 	printf("%s: symlink to \"%s\", %ld bytes\n", filename, realfile,
1170 	       (long)fileinfo.st_size);
1171     }
1172     else
1173       printf("%s: regular file, %ld bytes\n", filename, (long)fileinfo.st_size);
1174 
1175     if ((ppd = ppdOpenFile(filename)) == NULL)
1176     {
1177       ppd_status_t	err;		/* Last error in file */
1178       int		line;		/* Line number in file */
1179 
1180 
1181       status ++;
1182       err = ppdLastError(&line);
1183 
1184       printf("%s: %s on line %d\n", argv[1], ppdErrorString(err), line);
1185     }
1186     else
1187     {
1188       int		j, k;		/* Looping vars */
1189       ppd_group_t	*group;		/* Option group */
1190       ppd_option_t	*option;	/* Option */
1191       ppd_coption_t	*coption;	/* Custom option */
1192       ppd_cparam_t	*cparam;	/* Custom parameter */
1193       ppd_const_t	*c;		/* UIConstraints */
1194       char		lang[255],	/* LANG environment variable */
1195 			lc_all[255],	/* LC_ALL environment variable */
1196 			lc_ctype[255],	/* LC_CTYPE environment variable */
1197 			lc_messages[255];/* LC_MESSAGES environment variable */
1198 
1199 
1200       if (argc > 2)
1201       {
1202         snprintf(lang, sizeof(lang), "LANG=%s", argv[2]);
1203 	putenv(lang);
1204         snprintf(lc_all, sizeof(lc_all), "LC_ALL=%s", argv[2]);
1205 	putenv(lc_all);
1206         snprintf(lc_ctype, sizeof(lc_ctype), "LC_CTYPE=%s", argv[2]);
1207 	putenv(lc_ctype);
1208         snprintf(lc_messages, sizeof(lc_messages), "LC_MESSAGES=%s", argv[2]);
1209 	putenv(lc_messages);
1210       }
1211 
1212       ppdLocalize(ppd);
1213       ppdMarkDefaults(ppd);
1214 
1215       if (argc > 3)
1216       {
1217         text = ppdLocalizeIPPReason(ppd, argv[3], NULL, buffer, sizeof(buffer));
1218 	printf("ppdLocalizeIPPReason(%s)=%s\n", argv[3],
1219 	       text ? text : "(null)");
1220 	return (text == NULL);
1221       }
1222 
1223       for (i = ppd->num_groups, group = ppd->groups;
1224 	   i > 0;
1225 	   i --, group ++)
1226       {
1227 	printf("%s (%s):\n", group->name, group->text);
1228 
1229 	for (j = group->num_options, option = group->options;
1230 	     j > 0;
1231 	     j --, option ++)
1232 	{
1233 	  printf("    %s (%s):\n", option->keyword, option->text);
1234 
1235 	  for (k = 0; k < option->num_choices; k ++)
1236 	    printf("        - %s%s (%s)\n",
1237 	           option->choices[k].marked ? "*" : "",
1238 		   option->choices[k].choice, option->choices[k].text);
1239 
1240           if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1241 	  {
1242 	    for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
1243 	         cparam;
1244 		 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
1245             {
1246 	      switch (cparam->type)
1247 	      {
1248 	        case PPD_CUSTOM_UNKNOWN :
1249 		    printf("              %s(%s): PPD_CUSTOM_UNKNOWN (error)\n", cparam->name, cparam->text);
1250 	            break;
1251 
1252 	        case PPD_CUSTOM_CURVE :
1253 		    printf("              %s(%s): PPD_CUSTOM_CURVE (%g to %g)\n",
1254 		           cparam->name, cparam->text,
1255 			   cparam->minimum.custom_curve,
1256 			   cparam->maximum.custom_curve);
1257 		    break;
1258 
1259 	        case PPD_CUSTOM_INT :
1260 		    printf("              %s(%s): PPD_CUSTOM_INT (%d to %d)\n",
1261 		           cparam->name, cparam->text,
1262 			   cparam->minimum.custom_int,
1263 			   cparam->maximum.custom_int);
1264 		    break;
1265 
1266 	        case PPD_CUSTOM_INVCURVE :
1267 		    printf("              %s(%s): PPD_CUSTOM_INVCURVE (%g to %g)\n",
1268 		           cparam->name, cparam->text,
1269 			   cparam->minimum.custom_invcurve,
1270 			   cparam->maximum.custom_invcurve);
1271 		    break;
1272 
1273 	        case PPD_CUSTOM_PASSCODE :
1274 		    printf("              %s(%s): PPD_CUSTOM_PASSCODE (%d to %d)\n",
1275 		           cparam->name, cparam->text,
1276 			   cparam->minimum.custom_passcode,
1277 			   cparam->maximum.custom_passcode);
1278 		    break;
1279 
1280 	        case PPD_CUSTOM_PASSWORD :
1281 		    printf("              %s(%s): PPD_CUSTOM_PASSWORD (%d to %d)\n",
1282 		           cparam->name, cparam->text,
1283 			   cparam->minimum.custom_password,
1284 			   cparam->maximum.custom_password);
1285 		    break;
1286 
1287 	        case PPD_CUSTOM_POINTS :
1288 		    printf("              %s(%s): PPD_CUSTOM_POINTS (%g to %g)\n",
1289 		           cparam->name, cparam->text,
1290 			   cparam->minimum.custom_points,
1291 			   cparam->maximum.custom_points);
1292 		    break;
1293 
1294 	        case PPD_CUSTOM_REAL :
1295 		    printf("              %s(%s): PPD_CUSTOM_REAL (%g to %g)\n",
1296 		           cparam->name, cparam->text,
1297 			   cparam->minimum.custom_real,
1298 			   cparam->maximum.custom_real);
1299 		    break;
1300 
1301 	        case PPD_CUSTOM_STRING :
1302 		    printf("              %s(%s): PPD_CUSTOM_STRING (%d to %d)\n",
1303 		           cparam->name, cparam->text,
1304 			   cparam->minimum.custom_string,
1305 			   cparam->maximum.custom_string);
1306 		    break;
1307 	      }
1308 	    }
1309 	  }
1310 	}
1311       }
1312 
1313       puts("\nSizes:");
1314       for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
1315         printf("    %s = %gx%g, [%g %g %g %g]\n", size->name, size->width,
1316 	       size->length, size->left, size->bottom, size->right, size->top);
1317 
1318       puts("\nConstraints:");
1319 
1320       for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
1321         printf("    *UIConstraints: *%s %s *%s %s\n", c->option1, c->choice1,
1322 	       c->option2, c->choice2);
1323       if (ppd->num_consts == 0)
1324         puts("    NO CONSTRAINTS");
1325 
1326       puts("\nFilters:");
1327 
1328       for (i = 0; i < ppd->num_filters; i ++)
1329         printf("    %s\n", ppd->filters[i]);
1330 
1331       if (ppd->num_filters == 0)
1332         puts("    NO FILTERS");
1333 
1334       puts("\nAttributes:");
1335 
1336       for (attr = (ppd_attr_t *)cupsArrayFirst(ppd->sorted_attrs);
1337            attr;
1338 	   attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs))
1339         printf("    *%s %s/%s: \"%s\"\n", attr->name, attr->spec,
1340 	       attr->text, attr->value ? attr->value : "");
1341 
1342       puts("\nPPD Cache:");
1343       if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL)
1344         printf("    Unable to create: %s\n", cupsLastErrorString());
1345       else
1346       {
1347         _ppdCacheWriteFile(pc, "t.cache", NULL);
1348         puts("    Wrote t.cache.");
1349       }
1350     }
1351 
1352     if (!strncmp(argv[1], "-d", 2))
1353       unlink(filename);
1354   }
1355 
1356 #ifdef __APPLE__
1357   if (getenv("MallocStackLogging") && getenv("MallocStackLoggingNoCompact"))
1358   {
1359     char	command[1024];		/* malloc_history command */
1360 
1361     snprintf(command, sizeof(command), "malloc_history %d -all_by_size",
1362 	     getpid());
1363     fflush(stdout);
1364     system(command);
1365   }
1366 #endif /* __APPLE__ */
1367 
1368   ppdClose(ppd);
1369 
1370   return (status);
1371 }
1372 
1373 
1374 /*
1375  * 'do_ppd_tests()' - Test the default option commands in a PPD file.
1376  */
1377 
1378 static int				/* O - Number of errors */
do_ppd_tests(const char * filename,int num_options,cups_option_t * options)1379 do_ppd_tests(const char    *filename,	/* I - PPD file */
1380              int           num_options,	/* I - Number of options */
1381              cups_option_t *options)	/* I - Options */
1382 {
1383   ppd_file_t		*ppd;		/* PPD file data */
1384   cups_page_header2_t	header;		/* Page header */
1385 
1386 
1387   printf("\"%s\": ", filename);
1388   fflush(stdout);
1389 
1390   if ((ppd = ppdOpenFile(filename)) == NULL)
1391   {
1392     ppd_status_t	status;		/* Status from PPD loader */
1393     int			line;		/* Line number containing error */
1394 
1395 
1396     status = ppdLastError(&line);
1397 
1398     puts("FAIL (bad PPD file)");
1399     printf("    %s on line %d\n", ppdErrorString(status), line);
1400 
1401     return (1);
1402   }
1403 
1404   ppdMarkDefaults(ppd);
1405   cupsMarkOptions(ppd, num_options, options);
1406 
1407   if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, NULL))
1408   {
1409     puts("FAIL (error from function)");
1410     puts(cupsRasterErrorString());
1411 
1412     return (1);
1413   }
1414   else
1415   {
1416     puts("PASS");
1417 
1418     return (0);
1419   }
1420 }
1421 
1422 
1423 /*
1424  * 'do_ps_tests()' - Test standard PostScript commands.
1425  */
1426 
1427 static int
do_ps_tests(void)1428 do_ps_tests(void)
1429 {
1430   cups_page_header2_t	header;		/* Page header */
1431   int			preferred_bits;	/* Preferred bits */
1432   int			errors = 0;	/* Number of errors */
1433 
1434 
1435  /*
1436   * Test PS exec code...
1437   */
1438 
1439   fputs("_cupsRasterExecPS(\"setpagedevice\"): ", stdout);
1440   fflush(stdout);
1441 
1442   memset(&header, 0, sizeof(header));
1443   header.Collate = CUPS_TRUE;
1444   preferred_bits = 0;
1445 
1446   if (_cupsRasterExecPS(&header, &preferred_bits, setpagedevice_code))
1447   {
1448     puts("FAIL (error from function)");
1449     puts(cupsRasterErrorString());
1450     errors ++;
1451   }
1452   else if (preferred_bits != 17 ||
1453            memcmp(&header, &setpagedevice_header, sizeof(header)))
1454   {
1455     puts("FAIL (bad header)");
1456 
1457     if (preferred_bits != 17)
1458       printf("    cupsPreferredBitsPerColor %d, expected 17\n",
1459              preferred_bits);
1460 
1461     print_changes(&setpagedevice_header, &header);
1462     errors ++;
1463   }
1464   else
1465     puts("PASS");
1466 
1467   fputs("_cupsRasterExecPS(\"roll\"): ", stdout);
1468   fflush(stdout);
1469 
1470   if (_cupsRasterExecPS(&header, &preferred_bits,
1471                         "792 612 0 0 0\n"
1472 			"pop pop pop\n"
1473 			"<</PageSize[5 -2 roll]/ImagingBBox null>>"
1474 			"setpagedevice\n"))
1475   {
1476     puts("FAIL (error from function)");
1477     puts(cupsRasterErrorString());
1478     errors ++;
1479   }
1480   else if (header.PageSize[0] != 792 || header.PageSize[1] != 612)
1481   {
1482     printf("FAIL (PageSize [%d %d], expected [792 612])\n", header.PageSize[0],
1483            header.PageSize[1]);
1484     errors ++;
1485   }
1486   else
1487     puts("PASS");
1488 
1489   fputs("_cupsRasterExecPS(\"dup index\"): ", stdout);
1490   fflush(stdout);
1491 
1492   if (_cupsRasterExecPS(&header, &preferred_bits,
1493                         "true false dup\n"
1494 			"<</Collate 4 index"
1495 			"/Duplex 5 index"
1496 			"/Tumble 6 index>>setpagedevice\n"
1497 			"pop pop pop"))
1498   {
1499     puts("FAIL (error from function)");
1500     puts(cupsRasterErrorString());
1501     errors ++;
1502   }
1503   else
1504   {
1505     if (!header.Collate)
1506     {
1507       printf("FAIL (Collate false, expected true)\n");
1508       errors ++;
1509     }
1510 
1511     if (header.Duplex)
1512     {
1513       printf("FAIL (Duplex true, expected false)\n");
1514       errors ++;
1515     }
1516 
1517     if (header.Tumble)
1518     {
1519       printf("FAIL (Tumble true, expected false)\n");
1520       errors ++;
1521     }
1522 
1523     if(header.Collate && !header.Duplex && !header.Tumble)
1524       puts("PASS");
1525   }
1526 
1527   fputs("_cupsRasterExecPS(\"%%Begin/EndFeature code\"): ", stdout);
1528   fflush(stdout);
1529 
1530   if (_cupsRasterExecPS(&header, &preferred_bits, dsc_code))
1531   {
1532     puts("FAIL (error from function)");
1533     puts(cupsRasterErrorString());
1534     errors ++;
1535   }
1536   else if (header.PageSize[0] != 792 || header.PageSize[1] != 1224)
1537   {
1538     printf("FAIL (bad PageSize [%d %d], expected [792 1224])\n",
1539            header.PageSize[0], header.PageSize[1]);
1540     errors ++;
1541   }
1542   else
1543     puts("PASS");
1544 
1545   return (errors);
1546 }
1547 
1548 
1549 
1550 
1551 /*
1552  * 'print_changes()' - Print differences in the page header.
1553  */
1554 
1555 static void
print_changes(cups_page_header2_t * header,cups_page_header2_t * expected)1556 print_changes(
1557     cups_page_header2_t *header,	/* I - Actual page header */
1558     cups_page_header2_t *expected)	/* I - Expected page header */
1559 {
1560   int	i;				/* Looping var */
1561 
1562 
1563   if (strcmp(header->MediaClass, expected->MediaClass))
1564     printf("    MediaClass (%s), expected (%s)\n", header->MediaClass,
1565            expected->MediaClass);
1566 
1567   if (strcmp(header->MediaColor, expected->MediaColor))
1568     printf("    MediaColor (%s), expected (%s)\n", header->MediaColor,
1569            expected->MediaColor);
1570 
1571   if (strcmp(header->MediaType, expected->MediaType))
1572     printf("    MediaType (%s), expected (%s)\n", header->MediaType,
1573            expected->MediaType);
1574 
1575   if (strcmp(header->OutputType, expected->OutputType))
1576     printf("    OutputType (%s), expected (%s)\n", header->OutputType,
1577            expected->OutputType);
1578 
1579   if (header->AdvanceDistance != expected->AdvanceDistance)
1580     printf("    AdvanceDistance %d, expected %d\n", header->AdvanceDistance,
1581            expected->AdvanceDistance);
1582 
1583   if (header->AdvanceMedia != expected->AdvanceMedia)
1584     printf("    AdvanceMedia %d, expected %d\n", header->AdvanceMedia,
1585            expected->AdvanceMedia);
1586 
1587   if (header->Collate != expected->Collate)
1588     printf("    Collate %d, expected %d\n", header->Collate,
1589            expected->Collate);
1590 
1591   if (header->CutMedia != expected->CutMedia)
1592     printf("    CutMedia %d, expected %d\n", header->CutMedia,
1593            expected->CutMedia);
1594 
1595   if (header->Duplex != expected->Duplex)
1596     printf("    Duplex %d, expected %d\n", header->Duplex,
1597            expected->Duplex);
1598 
1599   if (header->HWResolution[0] != expected->HWResolution[0] ||
1600       header->HWResolution[1] != expected->HWResolution[1])
1601     printf("    HWResolution [%d %d], expected [%d %d]\n",
1602            header->HWResolution[0], header->HWResolution[1],
1603            expected->HWResolution[0], expected->HWResolution[1]);
1604 
1605   if (memcmp(header->ImagingBoundingBox, expected->ImagingBoundingBox,
1606              sizeof(header->ImagingBoundingBox)))
1607     printf("    ImagingBoundingBox [%d %d %d %d], expected [%d %d %d %d]\n",
1608            header->ImagingBoundingBox[0],
1609            header->ImagingBoundingBox[1],
1610            header->ImagingBoundingBox[2],
1611            header->ImagingBoundingBox[3],
1612            expected->ImagingBoundingBox[0],
1613            expected->ImagingBoundingBox[1],
1614            expected->ImagingBoundingBox[2],
1615            expected->ImagingBoundingBox[3]);
1616 
1617   if (header->InsertSheet != expected->InsertSheet)
1618     printf("    InsertSheet %d, expected %d\n", header->InsertSheet,
1619            expected->InsertSheet);
1620 
1621   if (header->Jog != expected->Jog)
1622     printf("    Jog %d, expected %d\n", header->Jog,
1623            expected->Jog);
1624 
1625   if (header->LeadingEdge != expected->LeadingEdge)
1626     printf("    LeadingEdge %d, expected %d\n", header->LeadingEdge,
1627            expected->LeadingEdge);
1628 
1629   if (header->Margins[0] != expected->Margins[0] ||
1630       header->Margins[1] != expected->Margins[1])
1631     printf("    Margins [%d %d], expected [%d %d]\n",
1632            header->Margins[0], header->Margins[1],
1633            expected->Margins[0], expected->Margins[1]);
1634 
1635   if (header->ManualFeed != expected->ManualFeed)
1636     printf("    ManualFeed %d, expected %d\n", header->ManualFeed,
1637            expected->ManualFeed);
1638 
1639   if (header->MediaPosition != expected->MediaPosition)
1640     printf("    MediaPosition %d, expected %d\n", header->MediaPosition,
1641            expected->MediaPosition);
1642 
1643   if (header->MediaWeight != expected->MediaWeight)
1644     printf("    MediaWeight %d, expected %d\n", header->MediaWeight,
1645            expected->MediaWeight);
1646 
1647   if (header->MirrorPrint != expected->MirrorPrint)
1648     printf("    MirrorPrint %d, expected %d\n", header->MirrorPrint,
1649            expected->MirrorPrint);
1650 
1651   if (header->NegativePrint != expected->NegativePrint)
1652     printf("    NegativePrint %d, expected %d\n", header->NegativePrint,
1653            expected->NegativePrint);
1654 
1655   if (header->NumCopies != expected->NumCopies)
1656     printf("    NumCopies %d, expected %d\n", header->NumCopies,
1657            expected->NumCopies);
1658 
1659   if (header->Orientation != expected->Orientation)
1660     printf("    Orientation %d, expected %d\n", header->Orientation,
1661            expected->Orientation);
1662 
1663   if (header->OutputFaceUp != expected->OutputFaceUp)
1664     printf("    OutputFaceUp %d, expected %d\n", header->OutputFaceUp,
1665            expected->OutputFaceUp);
1666 
1667   if (header->PageSize[0] != expected->PageSize[0] ||
1668       header->PageSize[1] != expected->PageSize[1])
1669     printf("    PageSize [%d %d], expected [%d %d]\n",
1670            header->PageSize[0], header->PageSize[1],
1671            expected->PageSize[0], expected->PageSize[1]);
1672 
1673   if (header->Separations != expected->Separations)
1674     printf("    Separations %d, expected %d\n", header->Separations,
1675            expected->Separations);
1676 
1677   if (header->TraySwitch != expected->TraySwitch)
1678     printf("    TraySwitch %d, expected %d\n", header->TraySwitch,
1679            expected->TraySwitch);
1680 
1681   if (header->Tumble != expected->Tumble)
1682     printf("    Tumble %d, expected %d\n", header->Tumble,
1683            expected->Tumble);
1684 
1685   if (header->cupsWidth != expected->cupsWidth)
1686     printf("    cupsWidth %d, expected %d\n", header->cupsWidth,
1687            expected->cupsWidth);
1688 
1689   if (header->cupsHeight != expected->cupsHeight)
1690     printf("    cupsHeight %d, expected %d\n", header->cupsHeight,
1691            expected->cupsHeight);
1692 
1693   if (header->cupsMediaType != expected->cupsMediaType)
1694     printf("    cupsMediaType %d, expected %d\n", header->cupsMediaType,
1695            expected->cupsMediaType);
1696 
1697   if (header->cupsBitsPerColor != expected->cupsBitsPerColor)
1698     printf("    cupsBitsPerColor %d, expected %d\n", header->cupsBitsPerColor,
1699            expected->cupsBitsPerColor);
1700 
1701   if (header->cupsBitsPerPixel != expected->cupsBitsPerPixel)
1702     printf("    cupsBitsPerPixel %d, expected %d\n", header->cupsBitsPerPixel,
1703            expected->cupsBitsPerPixel);
1704 
1705   if (header->cupsBytesPerLine != expected->cupsBytesPerLine)
1706     printf("    cupsBytesPerLine %d, expected %d\n", header->cupsBytesPerLine,
1707            expected->cupsBytesPerLine);
1708 
1709   if (header->cupsColorOrder != expected->cupsColorOrder)
1710     printf("    cupsColorOrder %d, expected %d\n", header->cupsColorOrder,
1711            expected->cupsColorOrder);
1712 
1713   if (header->cupsColorSpace != expected->cupsColorSpace)
1714     printf("    cupsColorSpace %s, expected %s\n", _cupsRasterColorSpaceString(header->cupsColorSpace),
1715            _cupsRasterColorSpaceString(expected->cupsColorSpace));
1716 
1717   if (header->cupsCompression != expected->cupsCompression)
1718     printf("    cupsCompression %d, expected %d\n", header->cupsCompression,
1719            expected->cupsCompression);
1720 
1721   if (header->cupsRowCount != expected->cupsRowCount)
1722     printf("    cupsRowCount %d, expected %d\n", header->cupsRowCount,
1723            expected->cupsRowCount);
1724 
1725   if (header->cupsRowFeed != expected->cupsRowFeed)
1726     printf("    cupsRowFeed %d, expected %d\n", header->cupsRowFeed,
1727            expected->cupsRowFeed);
1728 
1729   if (header->cupsRowStep != expected->cupsRowStep)
1730     printf("    cupsRowStep %d, expected %d\n", header->cupsRowStep,
1731            expected->cupsRowStep);
1732 
1733   if (header->cupsNumColors != expected->cupsNumColors)
1734     printf("    cupsNumColors %d, expected %d\n", header->cupsNumColors,
1735            expected->cupsNumColors);
1736 
1737   if (fabs(header->cupsBorderlessScalingFactor - expected->cupsBorderlessScalingFactor) > 0.001)
1738     printf("    cupsBorderlessScalingFactor %g, expected %g\n",
1739            header->cupsBorderlessScalingFactor,
1740            expected->cupsBorderlessScalingFactor);
1741 
1742   if (fabs(header->cupsPageSize[0] - expected->cupsPageSize[0]) > 0.001 ||
1743       fabs(header->cupsPageSize[1] - expected->cupsPageSize[1]) > 0.001)
1744     printf("    cupsPageSize [%g %g], expected [%g %g]\n",
1745            header->cupsPageSize[0], header->cupsPageSize[1],
1746            expected->cupsPageSize[0], expected->cupsPageSize[1]);
1747 
1748   if (fabs(header->cupsImagingBBox[0] - expected->cupsImagingBBox[0]) > 0.001 ||
1749       fabs(header->cupsImagingBBox[1] - expected->cupsImagingBBox[1]) > 0.001 ||
1750       fabs(header->cupsImagingBBox[2] - expected->cupsImagingBBox[2]) > 0.001 ||
1751       fabs(header->cupsImagingBBox[3] - expected->cupsImagingBBox[3]) > 0.001)
1752     printf("    cupsImagingBBox [%g %g %g %g], expected [%g %g %g %g]\n",
1753            header->cupsImagingBBox[0], header->cupsImagingBBox[1],
1754            header->cupsImagingBBox[2], header->cupsImagingBBox[3],
1755            expected->cupsImagingBBox[0], expected->cupsImagingBBox[1],
1756            expected->cupsImagingBBox[2], expected->cupsImagingBBox[3]);
1757 
1758   for (i = 0; i < 16; i ++)
1759     if (header->cupsInteger[i] != expected->cupsInteger[i])
1760       printf("    cupsInteger%d %d, expected %d\n", i, header->cupsInteger[i],
1761              expected->cupsInteger[i]);
1762 
1763   for (i = 0; i < 16; i ++)
1764     if (fabs(header->cupsReal[i] - expected->cupsReal[i]) > 0.001)
1765       printf("    cupsReal%d %g, expected %g\n", i, header->cupsReal[i],
1766              expected->cupsReal[i]);
1767 
1768   for (i = 0; i < 16; i ++)
1769     if (strcmp(header->cupsString[i], expected->cupsString[i]))
1770       printf("    cupsString%d (%s), expected (%s)\n", i,
1771 	     header->cupsString[i], expected->cupsString[i]);
1772 
1773   if (strcmp(header->cupsMarkerType, expected->cupsMarkerType))
1774     printf("    cupsMarkerType (%s), expected (%s)\n", header->cupsMarkerType,
1775            expected->cupsMarkerType);
1776 
1777   if (strcmp(header->cupsRenderingIntent, expected->cupsRenderingIntent))
1778     printf("    cupsRenderingIntent (%s), expected (%s)\n",
1779            header->cupsRenderingIntent,
1780            expected->cupsRenderingIntent);
1781 
1782   if (strcmp(header->cupsPageSizeName, expected->cupsPageSizeName))
1783     printf("    cupsPageSizeName (%s), expected (%s)\n",
1784            header->cupsPageSizeName,
1785            expected->cupsPageSizeName);
1786 }
1787