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