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