Пример #1
0
ppd_file_t *				/* O - PPD file */
SetCommonOptions(
    int           num_options,		/* I - Number of options */
    cups_option_t *options,		/* I - Options */
    int           change_size)		/* I - Change page size? */
{
  ppd_file_t	*ppd;			/* PPD file */
  ppd_size_t	*pagesize;		/* Current page size */
  const char	*val;			/* Option value */


#ifdef LC_TIME
  setlocale(LC_TIME, "");
#endif /* LC_TIME */

  ppd = ppdOpenFile(getenv("PPD"));

  ppdMarkDefaults(ppd);
  cupsMarkOptions(ppd, num_options, options);

  if ((pagesize = ppdPageSize(ppd, NULL)) != NULL)
  {
    PageWidth  = pagesize->width;
    PageLength = pagesize->length;
    PageTop    = pagesize->top;
    PageBottom = pagesize->bottom;
    PageLeft   = pagesize->left;
    PageRight  = pagesize->right;

    fprintf(stderr, "DEBUG: Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n",
            PageWidth, PageLength, PageLeft, PageBottom, PageRight, PageTop);
  }

  if (ppd != NULL)
  {
    ColorDevice   = ppd->color_device;
    LanguageLevel = ppd->language_level;
  }

  if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
  {
    if (_cups_strcasecmp(val, "no") != 0 && _cups_strcasecmp(val, "off") != 0 &&
        _cups_strcasecmp(val, "false") != 0)
    {
      if (ppd && ppd->landscape > 0)
        Orientation = 1;
      else
        Orientation = 3;
    }
  }
  else if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL)
  {
   /*
    * Map IPP orientation values to 0 to 3:
    *
    *   3 = 0 degrees   = 0
    *   4 = 90 degrees  = 1
    *   5 = -90 degrees = 3
    *   6 = 180 degrees = 2
    */

    Orientation = atoi(val) - 3;
    if (Orientation >= 2)
      Orientation ^= 1;
  }

  if ((val = cupsGetOption("page-left", num_options, options)) != NULL)
  {
    switch (Orientation & 3)
    {
      case 0 :
          PageLeft = (float)atof(val);
	  break;
      case 1 :
          PageBottom = (float)atof(val);
	  break;
      case 2 :
          PageRight = PageWidth - (float)atof(val);
	  break;
      case 3 :
          PageTop = PageLength - (float)atof(val);
	  break;
    }
  }

  if ((val = cupsGetOption("page-right", num_options, options)) != NULL)
  {
    switch (Orientation & 3)
    {
      case 0 :
          PageRight = PageWidth - (float)atof(val);
	  break;
      case 1 :
          PageTop = PageLength - (float)atof(val);
	  break;
      case 2 :
          PageLeft = (float)atof(val);
	  break;
      case 3 :
          PageBottom = (float)atof(val);
	  break;
    }
  }

  if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL)
  {
    switch (Orientation & 3)
    {
      case 0 :
          PageBottom = (float)atof(val);
	  break;
      case 1 :
          PageLeft = (float)atof(val);
	  break;
      case 2 :
          PageTop = PageLength - (float)atof(val);
	  break;
      case 3 :
          PageRight = PageWidth - (float)atof(val);
	  break;
    }
  }

  if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
  {
    switch (Orientation & 3)
    {
      case 0 :
          PageTop = PageLength - (float)atof(val);
	  break;
      case 1 :
          PageRight = PageWidth - (float)atof(val);
	  break;
      case 2 :
          PageBottom = (float)atof(val);
	  break;
      case 3 :
          PageLeft = (float)atof(val);
	  break;
    }
  }

  if (change_size)
    UpdatePageVars();

  if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
      ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
      ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
      ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
      ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
      ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
      ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
      ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))
    Duplex = 1;

  return (ppd);
}
Пример #2
0
int					/* O - 1 if conflicts exist, 0 otherwise */
cupsMarkOptions(
    ppd_file_t    *ppd,			/* I - PPD file */
    int           num_options,		/* I - Number of options */
    cups_option_t *options)		/* I - Options */
{
  int		i, j;			/* Looping vars */
  char		*ptr,			/* Pointer into string */
		s[255];			/* Temporary string */
  const char	*val,			/* Pointer into value */
		*media,			/* media option */
		*output_bin,		/* output-bin option */
		*page_size,		/* PageSize option */
		*ppd_keyword,		/* PPD keyword */
		*print_color_mode,	/* print-color-mode option */
		*print_quality,		/* print-quality option */
		*sides;			/* sides option */
  cups_option_t	*optptr;		/* Current option */
  ppd_attr_t	*attr;			/* PPD attribute */
  _ppd_cache_t	*cache;			/* PPD cache and mapping data */


 /*
  * Check arguments...
  */

  if (!ppd || num_options <= 0 || !options)
    return (0);

  ppd_debug_marked(ppd, "Before...");

 /*
  * Do special handling for finishings, media, output-bin, output-mode,
  * print-color-mode, print-quality, and PageSize...
  */

  media         = cupsGetOption("media", num_options, options);
  output_bin    = cupsGetOption("output-bin", num_options, options);
  page_size     = cupsGetOption("PageSize", num_options, options);
  print_quality = cupsGetOption("print-quality", num_options, options);
  sides         = cupsGetOption("sides", num_options, options);

  if ((print_color_mode = cupsGetOption("print-color-mode", num_options,
                                        options)) == NULL)
    print_color_mode = cupsGetOption("output-mode", num_options, options);

  if ((media || output_bin || print_color_mode || print_quality || sides) &&
      !ppd->cache)
  {
   /*
    * Load PPD cache and mapping data as needed...
    */

    ppd->cache = _ppdCacheCreateWithPPD(ppd);
  }

  cache = ppd->cache;

  if (media)
  {
   /*
    * Loop through the option string, separating it at commas and marking each
    * individual option as long as the corresponding PPD option (PageSize,
    * InputSlot, etc.) is not also set.
    *
    * For PageSize, we also check for an empty option value since some versions
    * of MacOS X use it to specify auto-selection of the media based solely on
    * the size.
    */

    for (val = media; *val;)
    {
     /*
      * Extract the sub-option from the string...
      */

      for (ptr = s; *val && *val != ',' && (size_t)(ptr - s) < (sizeof(s) - 1);)
	*ptr++ = *val++;
      *ptr++ = '\0';

      if (*val == ',')
	val ++;

     /*
      * Mark it...
      */

      if (!page_size || !page_size[0])
      {
        if (!_cups_strncasecmp(s, "Custom.", 7) || ppdPageSize(ppd, s))
          ppd_mark_option(ppd, "PageSize", s);
        else if ((ppd_keyword = _ppdCacheGetPageSize(cache, NULL, s, NULL)) != NULL)
	  ppd_mark_option(ppd, "PageSize", ppd_keyword);
      }

      if (cache && cache->source_option &&
          !cupsGetOption(cache->source_option, num_options, options) &&
	  (ppd_keyword = _ppdCacheGetInputSlot(cache, NULL, s)) != NULL)
	ppd_mark_option(ppd, cache->source_option, ppd_keyword);

      if (!cupsGetOption("MediaType", num_options, options) &&
	  (ppd_keyword = _ppdCacheGetMediaType(cache, NULL, s)) != NULL)
	ppd_mark_option(ppd, "MediaType", ppd_keyword);
    }
  }

  if (cache)
  {
    if (!cupsGetOption("com.apple.print.DocumentTicket.PMSpoolFormat",
                       num_options, options) &&
        !cupsGetOption("APPrinterPreset", num_options, options) &&
        (print_color_mode || print_quality))
    {
     /*
      * Map output-mode and print-quality to a preset...
      */

      _pwg_print_color_mode_t	pwg_pcm;/* print-color-mode index */
      _pwg_print_quality_t	pwg_pq;	/* print-quality index */
      cups_option_t		*preset;/* Current preset option */

      if (print_color_mode && !strcmp(print_color_mode, "monochrome"))
	pwg_pcm = _PWG_PRINT_COLOR_MODE_MONOCHROME;
      else
	pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR;

      if (print_quality)
      {
	pwg_pq = (_pwg_print_quality_t)(atoi(print_quality) - IPP_QUALITY_DRAFT);
	if (pwg_pq < _PWG_PRINT_QUALITY_DRAFT)
	  pwg_pq = _PWG_PRINT_QUALITY_DRAFT;
	else if (pwg_pq > _PWG_PRINT_QUALITY_HIGH)
	  pwg_pq = _PWG_PRINT_QUALITY_HIGH;
      }
      else
	pwg_pq = _PWG_PRINT_QUALITY_NORMAL;

      if (cache->num_presets[pwg_pcm][pwg_pq] == 0)
      {
       /*
	* Try to find a preset that works so that we maximize the chances of us
	* getting a good print using IPP attributes.
	*/

	if (cache->num_presets[pwg_pcm][_PWG_PRINT_QUALITY_NORMAL] > 0)
	  pwg_pq = _PWG_PRINT_QUALITY_NORMAL;
	else if (cache->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_pq] > 0)
	  pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR;
	else
	{
	  pwg_pq  = _PWG_PRINT_QUALITY_NORMAL;
	  pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR;
	}
      }

      if (cache->num_presets[pwg_pcm][pwg_pq] > 0)
      {
       /*
	* Copy the preset options as long as the corresponding names are not
	* already defined in the IPP request...
	*/

	for (i = cache->num_presets[pwg_pcm][pwg_pq],
		 preset = cache->presets[pwg_pcm][pwg_pq];
	     i > 0;
	     i --, preset ++)
	{
	  if (!cupsGetOption(preset->name, num_options, options))
	    ppd_mark_option(ppd, preset->name, preset->value);
	}
      }
    }

    if (output_bin && !cupsGetOption("OutputBin", num_options, options) &&
	(ppd_keyword = _ppdCacheGetOutputBin(cache, output_bin)) != NULL)
    {
     /*
      * Map output-bin to OutputBin...
      */

      ppd_mark_option(ppd, "OutputBin", ppd_keyword);
    }

    if (sides && cache->sides_option &&
        !cupsGetOption(cache->sides_option, num_options, options))
    {
     /*
      * Map sides to duplex option...
      */

      if (!strcmp(sides, "one-sided") && cache->sides_1sided)
        ppd_mark_option(ppd, cache->sides_option, cache->sides_1sided);
      else if (!strcmp(sides, "two-sided-long-edge") &&
               cache->sides_2sided_long)
        ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_long);
      else if (!strcmp(sides, "two-sided-short-edge") &&
               cache->sides_2sided_short)
        ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_short);
    }
  }

 /*
  * Mark other options...
  */

  for (i = num_options, optptr = options; i > 0; i --, optptr ++)
    if (!_cups_strcasecmp(optptr->name, "media") ||
        !_cups_strcasecmp(optptr->name, "output-bin") ||
	!_cups_strcasecmp(optptr->name, "output-mode") ||
	!_cups_strcasecmp(optptr->name, "print-quality") ||
	!_cups_strcasecmp(optptr->name, "sides"))
      continue;
    else if (!_cups_strcasecmp(optptr->name, "resolution") ||
             !_cups_strcasecmp(optptr->name, "printer-resolution"))
    {
      ppd_mark_option(ppd, "Resolution", optptr->value);
      ppd_mark_option(ppd, "SetResolution", optptr->value);
      	/* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
      ppd_mark_option(ppd, "JCLResolution", optptr->value);
      	/* HP */
      ppd_mark_option(ppd, "CNRes_PGP", optptr->value);
      	/* Canon */
    }
    else if (!_cups_strcasecmp(optptr->name, "multiple-document-handling"))
    {
      if (!cupsGetOption("Collate", num_options, options) &&
          ppdFindOption(ppd, "Collate"))
      {
        if (_cups_strcasecmp(optptr->value, "separate-documents-uncollated-copies"))
	  ppd_mark_option(ppd, "Collate", "True");
	else
	  ppd_mark_option(ppd, "Collate", "False");
      }
    }
    else if (!_cups_strcasecmp(optptr->name, "finishings"))
    {
     /*
      * Lookup cupsIPPFinishings attributes for each value...
      */

      for (ptr = optptr->value; *ptr;)
      {
       /*
        * Get the next finishings number...
	*/

        if (!isdigit(*ptr & 255))
	  break;

        if ((j = (int)strtol(ptr, &ptr, 10)) < 3)
	  break;

       /*
        * Skip separator as needed...
	*/

        if (*ptr == ',')
	  ptr ++;

       /*
        * Look it up in the PPD file...
	*/

	sprintf(s, "%d", j);

        if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL)
	  continue;

       /*
        * Apply "*Option Choice" settings from the attribute value...
	*/

        ppd_mark_choices(ppd, attr->value);
      }
    }
    else if (!_cups_strcasecmp(optptr->name, "APPrinterPreset"))
    {
     /*
      * Lookup APPrinterPreset value...
      */

      if ((attr = ppdFindAttr(ppd, "APPrinterPreset", optptr->value)) != NULL)
      {
       /*
        * Apply "*Option Choice" settings from the attribute value...
	*/

        ppd_mark_choices(ppd, attr->value);
      }
    }
    else if (!_cups_strcasecmp(optptr->name, "mirror"))
      ppd_mark_option(ppd, "MirrorPrint", optptr->value);
    else
      ppd_mark_option(ppd, optptr->name, optptr->value);

  ppd_debug_marked(ppd, "After...");

  return (ppdConflicts(ppd) > 0);
}
Пример #3
0
int					/* O  - 1 on success, 0 on failure */
cupsResolveConflicts(
    ppd_file_t    *ppd,			/* I  - PPD file */
    const char    *option,		/* I  - Newly selected option or @code NULL@ for none */
    const char    *choice,		/* I  - Newly selected choice or @code NULL@ for none */
    int           *num_options,		/* IO - Number of additional selected options */
    cups_option_t **options)		/* IO - Additional selected options */
{
  int			i,		/* Looping var */
			tries,		/* Number of tries */
			num_newopts;	/* Number of new options */
  cups_option_t		*newopts;	/* New options */
  cups_array_t		*active = NULL,	/* Active constraints */
			*pass,		/* Resolvers for this pass */
			*resolvers,	/* Resolvers we have used */
			*test;		/* Test array for conflicts */
  _ppd_cups_uiconsts_t	*consts;	/* Current constraints */
  _ppd_cups_uiconst_t	*constptr;	/* Current constraint */
  ppd_attr_t		*resolver;	/* Current resolver */
  const char		*resval;	/* Pointer into resolver value */
  char			resoption[PPD_MAX_NAME],
					/* Current resolver option */
			reschoice[PPD_MAX_NAME],
					/* Current resolver choice */
			*resptr,	/* Pointer into option/choice */
			firstpage[255];	/* AP_FIRSTPAGE_Keyword string */
  const char		*value;		/* Selected option value */
  int			changed;	/* Did we change anything? */
  ppd_choice_t		*marked;	/* Marked choice */


 /*
  * Range check input...
  */

  if (!ppd || !num_options || !options || (option == NULL) != (choice == NULL))
    return (0);

 /*
  * Build a shadow option array...
  */

  num_newopts = 0;
  newopts     = NULL;

  for (i = 0; i < *num_options; i ++)
    num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value,
                                num_newopts, &newopts);
  if (option && _cups_strcasecmp(option, "Collate"))
    num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);

 /*
  * Loop until we have no conflicts...
  */

  cupsArraySave(ppd->sorted_attrs);

  resolvers = NULL;
  pass      = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
  tries     = 0;

  while (tries < 100 &&
         (active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts,
                                        _PPD_ALL_CONSTRAINTS)) != NULL)
  {
    tries ++;

    if (!resolvers)
      resolvers = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);

    for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0;
         consts;
	 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
    {
      if (consts->resolver[0])
      {
       /*
        * Look up the resolver...
	*/

        if (cupsArrayFind(pass, consts->resolver))
	  continue;			/* Already applied this resolver... */

        if (cupsArrayFind(resolvers, consts->resolver))
	{
	 /*
	  * Resolver loop!
	  */

	  DEBUG_printf(("1cupsResolveConflicts: Resolver loop with %s!",
	                consts->resolver));
          goto error;
	}

        if ((resolver = ppdFindAttr(ppd, "cupsUIResolver",
	                            consts->resolver)) == NULL)
        {
	  DEBUG_printf(("1cupsResolveConflicts: Resolver %s not found!",
	                consts->resolver));
	  goto error;
	}

        if (!resolver->value)
	{
	  DEBUG_printf(("1cupsResolveConflicts: Resolver %s has no value!",
	                consts->resolver));
	  goto error;
	}

       /*
        * Add the options from the resolver...
	*/

        cupsArrayAdd(pass, consts->resolver);
	cupsArrayAdd(resolvers, consts->resolver);

        for (resval = resolver->value; *resval && !changed;)
	{
	  while (_cups_isspace(*resval))
	    resval ++;

	  if (*resval != '*')
	    break;

	  for (resval ++, resptr = resoption;
	       *resval && !_cups_isspace(*resval);
	       resval ++)
            if (resptr < (resoption + sizeof(resoption) - 1))
	      *resptr++ = *resval;

          *resptr = '\0';

	  while (_cups_isspace(*resval))
	    resval ++;

	  for (resptr = reschoice;
	       *resval && !_cups_isspace(*resval);
	       resval ++)
            if (resptr < (reschoice + sizeof(reschoice) - 1))
	      *resptr++ = *resval;

          *resptr = '\0';

          if (!resoption[0] || !reschoice[0])
	    break;

         /*
	  * Is this the option we are changing?
	  */

          snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption);

	  if (option &&
	      (!_cups_strcasecmp(resoption, option) ||
	       !_cups_strcasecmp(firstpage, option) ||
	       (!_cups_strcasecmp(option, "PageSize") &&
		!_cups_strcasecmp(resoption, "PageRegion")) ||
	       (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") &&
		!_cups_strcasecmp(resoption, "PageSize")) ||
	       (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") &&
		!_cups_strcasecmp(resoption, "PageRegion")) ||
	       (!_cups_strcasecmp(option, "PageRegion") &&
	        !_cups_strcasecmp(resoption, "PageSize")) ||
	       (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") &&
	        !_cups_strcasecmp(resoption, "PageSize")) ||
	       (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") &&
	        !_cups_strcasecmp(resoption, "PageRegion"))))
	    continue;

	 /*
	  * Try this choice...
	  */

          if ((test = ppd_test_constraints(ppd, resoption, reschoice,
					   num_newopts, newopts,
					   _PPD_ALL_CONSTRAINTS)) == NULL)
	  {
	   /*
	    * That worked...
	    */

            changed = 1;
	  }
	  else
            cupsArrayDelete(test);

	 /*
	  * Add the option/choice from the resolver regardless of whether it
	  * worked; this makes sure that we can cascade several changes to
	  * make things resolve...
	  */

	  num_newopts = cupsAddOption(resoption, reschoice, num_newopts,
				      &newopts);
        }
      }
      else
      {
       /*
        * Try resolving by choosing the default values for non-installable
	* options, then by iterating through the possible choices...
	*/

        int		j;		/* Looping var */
	ppd_choice_t	*cptr;		/* Current choice */
        ppd_size_t	*size;		/* Current page size */


        for (i = consts->num_constraints, constptr = consts->constraints;
	     i > 0 && !changed;
	     i --, constptr ++)
	{
	 /*
	  * Can't resolve by changing an installable option...
	  */

	  if (constptr->installable)
	    continue;

         /*
	  * Is this the option we are changing?
	  */

	  if (option &&
	      (!_cups_strcasecmp(constptr->option->keyword, option) ||
	       (!_cups_strcasecmp(option, "PageSize") &&
		!_cups_strcasecmp(constptr->option->keyword, "PageRegion")) ||
	       (!_cups_strcasecmp(option, "PageRegion") &&
		!_cups_strcasecmp(constptr->option->keyword, "PageSize"))))
	    continue;

         /*
	  * Get the current option choice...
	  */

          if ((value = cupsGetOption(constptr->option->keyword, num_newopts,
	                             newopts)) == NULL)
          {
	    if (!_cups_strcasecmp(constptr->option->keyword, "PageSize") ||
	        !_cups_strcasecmp(constptr->option->keyword, "PageRegion"))
	    {
	      if ((value = cupsGetOption("PageSize", num_newopts,
	                                 newopts)) == NULL)
                value = cupsGetOption("PageRegion", num_newopts, newopts);

              if (!value)
	      {
	        if ((size = ppdPageSize(ppd, NULL)) != NULL)
		  value = size->name;
		else
		  value = "";
	      }
	    }
	    else
	    {
	      marked = ppdFindMarkedChoice(ppd, constptr->option->keyword);
	      value  = marked ? marked->choice : "";
	    }
	  }

	  if (!_cups_strncasecmp(value, "Custom.", 7))
	    value = "Custom";

         /*
	  * Try the default choice...
	  */

          test = NULL;

          if (_cups_strcasecmp(value, constptr->option->defchoice) &&
	      (test = ppd_test_constraints(ppd, constptr->option->keyword,
	                                   constptr->option->defchoice,
					   num_newopts, newopts,
					   _PPD_OPTION_CONSTRAINTS)) == NULL)
	  {
	   /*
	    * That worked...
	    */

	    num_newopts = cupsAddOption(constptr->option->keyword,
	                                constptr->option->defchoice,
					num_newopts, &newopts);
            changed     = 1;
	  }
	  else
	  {
	   /*
	    * Try each choice instead...
	    */

            for (j = constptr->option->num_choices,
	             cptr = constptr->option->choices;
		 j > 0;
		 j --, cptr ++)
            {
	      cupsArrayDelete(test);
	      test = NULL;

	      if (_cups_strcasecmp(value, cptr->choice) &&
	          _cups_strcasecmp(constptr->option->defchoice, cptr->choice) &&
		  _cups_strcasecmp("Custom", cptr->choice) &&
	          (test = ppd_test_constraints(ppd, constptr->option->keyword,
	                                       cptr->choice, num_newopts,
					       newopts,
					       _PPD_OPTION_CONSTRAINTS)) == NULL)
	      {
	       /*
		* This choice works...
		*/

		num_newopts = cupsAddOption(constptr->option->keyword,
					    cptr->choice, num_newopts,
					    &newopts);
		changed     = 1;
		break;
	      }
	    }

	    cupsArrayDelete(test);
          }
        }
      }
    }

    if (!changed)
    {
      DEBUG_puts("1cupsResolveConflicts: Unable to automatically resolve "
		 "constraint!");
      goto error;
    }

    cupsArrayClear(pass);
    cupsArrayDelete(active);
    active = NULL;
  }

  if (tries >= 100)
    goto error;

 /*
  * Free the caller's option array...
  */

  cupsFreeOptions(*num_options, *options);

 /*
  * If Collate is the option we are testing, add it here.  Otherwise, remove
  * any Collate option from the resolve list since the filters automatically
  * handle manual collation...
  */

  if (option && !_cups_strcasecmp(option, "Collate"))
    num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
  else
    num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts);

 /*
  * Return the new list of options to the caller...
  */

  *num_options = num_newopts;
  *options     = newopts;

  cupsArrayDelete(pass);
  cupsArrayDelete(resolvers);

  cupsArrayRestore(ppd->sorted_attrs);

  DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts));
#ifdef DEBUG
  for (i = 0; i < num_newopts; i ++)
    DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i,
                  newopts[i].name, newopts[i].value));
#endif /* DEBUG */

  return (1);

 /*
  * If we get here, we failed to resolve...
  */

  error:

  cupsFreeOptions(num_newopts, newopts);

  cupsArrayDelete(active);
  cupsArrayDelete(pass);
  cupsArrayDelete(resolvers);

  cupsArrayRestore(ppd->sorted_attrs);

  DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!");

  return (0);
}
Пример #4
0
static cups_array_t *			/* O - Array of active constraints */
ppd_test_constraints(
    ppd_file_t    *ppd,			/* I - PPD file */
    const char    *option,		/* I - Current option */
    const char    *choice,		/* I - Current choice */
    int           num_options,		/* I - Number of additional options */
    cups_option_t *options,		/* I - Additional options */
    int           which)		/* I - Which constraints to test */
{
  int			i;		/* Looping var */
  _ppd_cups_uiconsts_t	*consts;	/* Current constraints */
  _ppd_cups_uiconst_t	*constptr;	/* Current constraint */
  ppd_choice_t		key,		/* Search key */
			*marked;	/* Marked choice */
  cups_array_t		*active = NULL;	/* Active constraints */
  const char		*value,		/* Current value */
			*firstvalue;	/* AP_FIRSTPAGE_Keyword value */
  char			firstpage[255];	/* AP_FIRSTPAGE_Keyword string */


  DEBUG_printf(("7ppd_test_constraints(ppd=%p, option=\"%s\", choice=\"%s\", "
                "num_options=%d, options=%p, which=%d)", ppd, option, choice,
		num_options, options, which));

  if (!ppd->cups_uiconstraints)
    ppd_load_constraints(ppd);

  DEBUG_printf(("9ppd_test_constraints: %d constraints!",
	        cupsArrayCount(ppd->cups_uiconstraints)));

  cupsArraySave(ppd->marked);

  for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
       consts;
       consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
  {
    DEBUG_printf(("9ppd_test_constraints: installable=%d, resolver=\"%s\", "
                  "num_constraints=%d option1=\"%s\", choice1=\"%s\", "
		  "option2=\"%s\", choice2=\"%s\", ...",
		  consts->installable, consts->resolver, consts->num_constraints,
		  consts->constraints[0].option->keyword,
		  consts->constraints[0].choice ?
		      consts->constraints[0].choice->choice : "",
		  consts->constraints[1].option->keyword,
		  consts->constraints[1].choice ?
		      consts->constraints[1].choice->choice : ""));

    if (consts->installable && which < _PPD_INSTALLABLE_CONSTRAINTS)
      continue;				/* Skip installable option constraint */

    if (!consts->installable && which == _PPD_INSTALLABLE_CONSTRAINTS)
      continue;				/* Skip non-installable option constraint */

    if (which == _PPD_OPTION_CONSTRAINTS && option)
    {
     /*
      * Skip constraints that do not involve the current option...
      */

      for (i = consts->num_constraints, constptr = consts->constraints;
	   i > 0;
	   i --, constptr ++)
      {
        if (!_cups_strcasecmp(constptr->option->keyword, option))
	  break;

        if (!_cups_strncasecmp(option, "AP_FIRSTPAGE_", 13) &&
	    !_cups_strcasecmp(constptr->option->keyword, option + 13))
	  break;
      }

      if (!i)
        continue;
    }

    DEBUG_puts("9ppd_test_constraints: Testing...");

    for (i = consts->num_constraints, constptr = consts->constraints;
         i > 0;
	 i --, constptr ++)
    {
      DEBUG_printf(("9ppd_test_constraints: %s=%s?", constptr->option->keyword,
		    constptr->choice ? constptr->choice->choice : ""));

      if (constptr->choice &&
          (!_cups_strcasecmp(constptr->option->keyword, "PageSize") ||
           !_cups_strcasecmp(constptr->option->keyword, "PageRegion")))
      {
       /*
        * PageSize and PageRegion are used depending on the selected input slot
	* and manual feed mode.  Validate against the selected page size instead
	* of an individual option...
	*/

        if (option && choice &&
	    (!_cups_strcasecmp(option, "PageSize") ||
	     !_cups_strcasecmp(option, "PageRegion")))
	{
	  value = choice;
        }
	else if ((value = cupsGetOption("PageSize", num_options,
	                                options)) == NULL)
	  if ((value = cupsGetOption("PageRegion", num_options,
	                             options)) == NULL)
	    if ((value = cupsGetOption("media", num_options, options)) == NULL)
	    {
	      ppd_size_t *size = ppdPageSize(ppd, NULL);

              if (size)
	        value = size->name;
	    }

        if (value && !_cups_strncasecmp(value, "Custom.", 7))
	  value = "Custom";

        if (option && choice &&
	    (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") ||
	     !_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion")))
	{
	  firstvalue = choice;
        }
	else if ((firstvalue = cupsGetOption("AP_FIRSTPAGE_PageSize",
	                                     num_options, options)) == NULL)
	  firstvalue = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options,
	                             options);

        if (firstvalue && !_cups_strncasecmp(firstvalue, "Custom.", 7))
	  firstvalue = "Custom";

        if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) &&
	    (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice)))
	{
	  DEBUG_puts("9ppd_test_constraints: NO");
	  break;
	}
      }
      else if (constptr->choice)
      {
       /*
        * Compare against the constrained choice...
	*/

        if (option && choice && !_cups_strcasecmp(option, constptr->option->keyword))
	{
	  if (!_cups_strncasecmp(choice, "Custom.", 7))
	    value = "Custom";
	  else
	    value = choice;
	}
        else if ((value = cupsGetOption(constptr->option->keyword, num_options,
	                                options)) != NULL)
        {
	  if (!_cups_strncasecmp(value, "Custom.", 7))
	    value = "Custom";
	}
        else if (constptr->choice->marked)
	  value = constptr->choice->choice;
	else
	  value = NULL;

       /*
        * Now check AP_FIRSTPAGE_option...
	*/

        snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s",
	         constptr->option->keyword);

        if (option && choice && !_cups_strcasecmp(option, firstpage))
	{
	  if (!_cups_strncasecmp(choice, "Custom.", 7))
	    firstvalue = "Custom";
	  else
	    firstvalue = choice;
	}
        else if ((firstvalue = cupsGetOption(firstpage, num_options,
	                                     options)) != NULL)
        {
	  if (!_cups_strncasecmp(firstvalue, "Custom.", 7))
	    firstvalue = "Custom";
	}
	else
	  firstvalue = NULL;

        DEBUG_printf(("9ppd_test_constraints: value=%s, firstvalue=%s", value,
	              firstvalue));

        if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) &&
	    (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice)))
	{
	  DEBUG_puts("9ppd_test_constraints: NO");
	  break;
	}
      }
      else if (option && choice &&
               !_cups_strcasecmp(option, constptr->option->keyword))
      {
	if (!_cups_strcasecmp(choice, "None") || !_cups_strcasecmp(choice, "Off") ||
	    !_cups_strcasecmp(choice, "False"))
	{
	  DEBUG_puts("9ppd_test_constraints: NO");
	  break;
	}
      }
      else if ((value = cupsGetOption(constptr->option->keyword, num_options,
				      options)) != NULL)
      {
	if (!_cups_strcasecmp(value, "None") || !_cups_strcasecmp(value, "Off") ||
	    !_cups_strcasecmp(value, "False"))
	{
	  DEBUG_puts("9ppd_test_constraints: NO");
	  break;
	}
      }
      else
      {
	key.option = constptr->option;

	if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key))
		== NULL ||
	    (!_cups_strcasecmp(marked->choice, "None") ||
	     !_cups_strcasecmp(marked->choice, "Off") ||
	     !_cups_strcasecmp(marked->choice, "False")))
	{
	  DEBUG_puts("9ppd_test_constraints: NO");
	  break;
	}
      }
    }

    if (i <= 0)
    {
      if (!active)
        active = cupsArrayNew(NULL, NULL);

      cupsArrayAdd(active, consts);
      DEBUG_puts("9ppd_test_constraints: Added...");
    }
  }

  cupsArrayRestore(ppd->marked);

  DEBUG_printf(("8ppd_test_constraints: Found %d active constraints!",
                cupsArrayCount(active)));

  return (active);
}
Пример #5
0
char *					/* O - String containing option code or @code NULL@ if there is no option code */
ppdEmitString(ppd_file_t    *ppd,	/* I - PPD file record */
              ppd_section_t section,	/* I - Section to write */
	      float         min_order)	/* I - Lowest OrderDependency */
{
  int		i, j,			/* Looping vars */
		count;			/* Number of choices */
  ppd_choice_t	**choices;		/* Choices */
  ppd_size_t	*size;			/* Custom page size */
  ppd_coption_t	*coption;		/* Custom option */
  ppd_cparam_t	*cparam;		/* Custom parameter */
  size_t	bufsize;		/* Size of string buffer needed */
  char		*buffer,		/* String buffer */
		*bufptr,		/* Pointer into buffer */
		*bufend;		/* End of buffer */
  struct lconv	*loc;			/* Locale data */


  DEBUG_printf(("ppdEmitString(ppd=%p, section=%d, min_order=%f)",
                ppd, section, min_order));

 /*
  * Range check input...
  */

  if (!ppd)
    return (NULL);

 /*
  * Use PageSize or PageRegion as required...
  */

  ppd_handle_media(ppd);

 /*
  * Collect the options we need to emit...
  */

  if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0)
    return (NULL);

 /*
  * Count the number of bytes that are required to hold all of the
  * option code...
  */

  for (i = 0, bufsize = 1; i < count; i ++)
  {
    if (section == PPD_ORDER_JCL)
    {
      if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
	  (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
	      != NULL)
      {
       /*
        * Add space to account for custom parameter substitution...
	*/

        for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
	     cparam;
	     cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
	{
          switch (cparam->type)
	  {
	    case PPD_CUSTOM_CURVE :
	    case PPD_CUSTOM_INVCURVE :
	    case PPD_CUSTOM_POINTS :
	    case PPD_CUSTOM_REAL :
	    case PPD_CUSTOM_INT :
	        bufsize += 10;
	        break;

	    case PPD_CUSTOM_PASSCODE :
	    case PPD_CUSTOM_PASSWORD :
	    case PPD_CUSTOM_STRING :
	        if (cparam->current.custom_string)
		  bufsize += strlen(cparam->current.custom_string);
	        break;
          }
	}
      }
    }
    else if (section != PPD_ORDER_EXIT)
    {
      bufsize += 3;			/* [{\n */

      if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") ||
           !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
          !_cups_strcasecmp(choices[i]->choice, "Custom"))
      {
        DEBUG_puts("2ppdEmitString: Custom size set!");

        bufsize += 37;			/* %%BeginFeature: *CustomPageSize True\n */
        bufsize += 50;			/* Five 9-digit numbers + newline */
      }
      else if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
               (coption = ppdFindCustomOption(ppd,
	                                      choices[i]->option->keyword))
	           != NULL)
      {
        bufsize += 23 + strlen(choices[i]->option->keyword) + 6;
					/* %%BeginFeature: *Customkeyword True\n */


        for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
	     cparam;
	     cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
	{
          switch (cparam->type)
	  {
	    case PPD_CUSTOM_CURVE :
	    case PPD_CUSTOM_INVCURVE :
	    case PPD_CUSTOM_POINTS :
	    case PPD_CUSTOM_REAL :
	    case PPD_CUSTOM_INT :
	        bufsize += 10;
	        break;

	    case PPD_CUSTOM_PASSCODE :
	    case PPD_CUSTOM_PASSWORD :
	    case PPD_CUSTOM_STRING :
		bufsize += 3;
	        if (cparam->current.custom_string)
		  bufsize += 4 * strlen(cparam->current.custom_string);
	        break;
          }
	}
      }
      else
        bufsize += 17 + strlen(choices[i]->option->keyword) + 1 +
	           strlen(choices[i]->choice) + 1;
					/* %%BeginFeature: *keyword choice\n */

      bufsize += 13;			/* %%EndFeature\n */
      bufsize += 22;			/* } stopped cleartomark\n */
    }

    if (choices[i]->code)
      bufsize += strlen(choices[i]->code) + 1;
    else
      bufsize += strlen(ppd_custom_code);
  }

 /*
  * Allocate memory...
  */

  DEBUG_printf(("2ppdEmitString: Allocating %d bytes for string...",
                (int)bufsize));

  if ((buffer = calloc(1, bufsize)) == NULL)
  {
    free(choices);
    return (NULL);
  }

  bufend = buffer + bufsize - 1;
  loc    = localeconv();

 /*
  * Copy the option code to the buffer...
  */

  for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr))
    if (section == PPD_ORDER_JCL)
    {
      if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
	  choices[i]->code &&
          (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
	      != NULL)
      {
       /*
        * Handle substitutions in custom JCL options...
	*/

	char	*cptr;			/* Pointer into code */
	int	pnum;			/* Parameter number */


        for (cptr = choices[i]->code; *cptr && bufptr < bufend;)
	{
	  if (*cptr == '\\')
	  {
	    cptr ++;

	    if (isdigit(*cptr & 255))
	    {
	     /*
	      * Substitute parameter...
	      */

              pnum = *cptr++ - '0';
	      while (isdigit(*cptr & 255))
	        pnum = pnum * 10 + *cptr++ - '0';

              for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
	           cparam;
		   cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
		if (cparam->order == pnum)
		  break;

              if (cparam)
	      {
	        switch (cparam->type)
		{
		  case PPD_CUSTOM_CURVE :
		  case PPD_CUSTOM_INVCURVE :
		  case PPD_CUSTOM_POINTS :
		  case PPD_CUSTOM_REAL :
		      bufptr = _cupsStrFormatd(bufptr, bufend,
					       cparam->current.custom_real,
					       loc);
		      break;

		  case PPD_CUSTOM_INT :
		      snprintf(bufptr, bufend - bufptr, "%d",
		               cparam->current.custom_int);
		      bufptr += strlen(bufptr);
		      break;

		  case PPD_CUSTOM_PASSCODE :
		  case PPD_CUSTOM_PASSWORD :
		  case PPD_CUSTOM_STRING :
		      if (cparam->current.custom_string)
		      {
			strlcpy(bufptr, cparam->current.custom_string,
				bufend - bufptr);
			bufptr += strlen(bufptr);
		      }
		      break;
		}
	      }
	    }
	    else if (*cptr)
	      *bufptr++ = *cptr++;
	  }
	  else
	    *bufptr++ = *cptr++;
	}
      }
      else
      {
       /*
        * Otherwise just copy the option code directly...
	*/

        strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
        bufptr += strlen(bufptr);
      }
    }
    else if (section != PPD_ORDER_EXIT)
    {
     /*
      * Add wrapper commands to prevent printer errors for unsupported
      * options...
      */

      strlcpy(bufptr, "[{\n", bufend - bufptr + 1);
      bufptr += 3;

     /*
      * Send DSC comments with option...
      */

      DEBUG_printf(("2ppdEmitString: Adding code for %s=%s...",
		    choices[i]->option->keyword, choices[i]->choice));

      if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") ||
           !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
          !_cups_strcasecmp(choices[i]->choice, "Custom"))
      {
       /*
        * Variable size; write out standard size options, using the
	* parameter positions defined in the PPD file...
	*/

        ppd_attr_t	*attr;		/* PPD attribute */
	int		pos,		/* Position of custom value */
			orientation;	/* Orientation to use */
	float		values[5];	/* Values for custom command */


        strlcpy(bufptr, "%%BeginFeature: *CustomPageSize True\n",
	        bufend - bufptr + 1);
        bufptr += 37;

        size = ppdPageSize(ppd, "Custom");

        memset(values, 0, sizeof(values));

	if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL)
	{
	  pos = atoi(attr->value) - 1;

          if (pos < 0 || pos > 4)
	    pos = 0;
	}
	else
	  pos = 0;

	values[pos] = size->width;

	if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL)
	{
	  pos = atoi(attr->value) - 1;

          if (pos < 0 || pos > 4)
	    pos = 1;
	}
	else
	  pos = 1;

	values[pos] = size->length;

       /*
        * According to the Adobe PPD specification, an orientation of 1
	* will produce a print that comes out upside-down with the X
	* axis perpendicular to the direction of feed, which is exactly
	* what we want to be consistent with non-PS printers.
	*
	* We could also use an orientation of 3 to produce output that
	* comes out rightside-up (this is the default for many large format
	* printer PPDs), however for consistency we will stick with the
	* value 1.
	*
	* If we wanted to get fancy, we could use orientations of 0 or
	* 2 and swap the width and length, however we don't want to get
	* fancy, we just want it to work consistently.
	*
	* The orientation value is range limited by the Orientation
	* parameter definition, so certain non-PS printer drivers that
	* only support an Orientation of 0 will get the value 0 as
	* expected.
	*/

        orientation = 1;

	if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize",
	                        "Orientation")) != NULL)
	{
	  int min_orient, max_orient;	/* Minimum and maximum orientations */


          if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient,
	             &max_orient) != 3)
	    pos = 4;
	  else
	  {
	    pos --;

            if (pos < 0 || pos > 4)
	      pos = 4;

            if (orientation > max_orient)
	      orientation = max_orient;
	    else if (orientation < min_orient)
	      orientation = min_orient;
	  }
	}
	else
	  pos = 4;

	values[pos] = (float)orientation;

        for (pos = 0; pos < 5; pos ++)
	{
	  bufptr    = _cupsStrFormatd(bufptr, bufend, values[pos], loc);
	  *bufptr++ = '\n';
        }

	if (!choices[i]->code)
	{
	 /*
	  * This can happen with certain buggy PPD files that don't include
	  * a CustomPageSize command sequence...  We just use a generic
	  * Level 2 command sequence...
	  */

	  strlcpy(bufptr, ppd_custom_code, bufend - bufptr + 1);
          bufptr += strlen(bufptr);
	}
      }
      else if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
               (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
	           != NULL)
      {
       /*
        * Custom option...
	*/

        const char	*s;		/* Pointer into string value */
        cups_array_t	*params;	/* Parameters in the correct output order */


        params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);

        for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
	     cparam;
	     cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
          cupsArrayAdd(params, cparam);

        snprintf(bufptr, bufend - bufptr + 1,
	         "%%%%BeginFeature: *Custom%s True\n", coption->keyword);
        bufptr += strlen(bufptr);

        for (cparam = (ppd_cparam_t *)cupsArrayFirst(params);
	     cparam;
	     cparam = (ppd_cparam_t *)cupsArrayNext(params))
	{
          switch (cparam->type)
	  {
	    case PPD_CUSTOM_CURVE :
	    case PPD_CUSTOM_INVCURVE :
	    case PPD_CUSTOM_POINTS :
	    case PPD_CUSTOM_REAL :
	        bufptr    = _cupsStrFormatd(bufptr, bufend,
		                            cparam->current.custom_real, loc);
                *bufptr++ = '\n';
	        break;

	    case PPD_CUSTOM_INT :
	        snprintf(bufptr, bufend - bufptr + 1, "%d\n",
		         cparam->current.custom_int);
		bufptr += strlen(bufptr);
	        break;

	    case PPD_CUSTOM_PASSCODE :
	    case PPD_CUSTOM_PASSWORD :
	    case PPD_CUSTOM_STRING :
	        *bufptr++ = '(';

		if (cparam->current.custom_string)
		{
		  for (s = cparam->current.custom_string; *s; s ++)
		  {
		    if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127)
		    {
		      snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *s & 255);
		      bufptr += strlen(bufptr);
		    }
		    else
		      *bufptr++ = *s;
		  }
		}

	        *bufptr++ = ')';
		*bufptr++ = '\n';
	        break;
          }
	}

	cupsArrayDelete(params);
      }
      else
      {
        snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *%s %s\n",
                 choices[i]->option->keyword, choices[i]->choice);
	bufptr += strlen(bufptr);
      }

      if (choices[i]->code && choices[i]->code[0])
      {
        j = (int)strlen(choices[i]->code);
	memcpy(bufptr, choices[i]->code, j);
	bufptr += j;

	if (choices[i]->code[j - 1] != '\n')
	  *bufptr++ = '\n';
      }

      strlcpy(bufptr, "%%EndFeature\n"
		      "} stopped cleartomark\n", bufend - bufptr + 1);
      bufptr += strlen(bufptr);

      DEBUG_printf(("2ppdEmitString: Offset in string is %d...",
                    (int)(bufptr - buffer)));
    }
    else
    {
      strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
      bufptr += strlen(bufptr);
    }

 /*
  * Nul-terminate, free, and return...
  */

  *bufptr = '\0';

  free(choices);

  return (buffer);
}
Пример #6
0
bool PrinterUtil::getPrinterMarginValues(const QString& printerName, const QString& pageSize, double& ptsTopMargin, double& ptsBottomMargin, double& ptsLeftMargin, double& ptsRightMargin)
{
	bool retVal=false;
#if defined(HAVE_CUPS)
	const char *filename; // tmp PPD filename
	filename=cupsGetPPD(printerName.toLocal8Bit().constData());
	if (filename!=NULL)
	{
		ppd_file_t *ppd; // PPD data
		ppd = ppdOpenFile(filename);
		if (ppd!=NULL)
		{
			ppd_size_t *size; // page size data, null if printer doesnt support selected size
			size = ppdPageSize(ppd, pageSize.toLocal8Bit().constData());
			if (size!=NULL)
			{
				//Store in pts for returning via getNewPrinterMargins in pts
				retVal=true;
				ptsTopMargin=size->length-size->top;
				ptsBottomMargin=size->bottom;
				ptsLeftMargin=size->left;
				ptsRightMargin=size->width-size->right;
			}
			ppdClose(ppd);
		}
	}
#elif defined(_WIN32)
	DWORD nPaper;
	DWORD nPaperNames;
	typedef WCHAR wchar64[64];
	nPaper = DeviceCapabilitiesW( (LPCWSTR) printerName.utf16(), NULL, DC_PAPERS, NULL, NULL );
	nPaperNames = DeviceCapabilitiesW( (LPCWSTR) printerName.utf16(), NULL, DC_PAPERNAMES, NULL, NULL );
	if ( (nPaper > 0) && (nPaperNames > 0) && (nPaper == nPaperNames) )
	{
		int paperIndex = -1;
		DWORD   *papers = new DWORD[nPaper];
		wchar64 *paperNames = new wchar64[nPaperNames];
		DWORD s1 = DeviceCapabilitiesW( (LPCWSTR) printerName.utf16(), NULL, DC_PAPERS, (LPWSTR) papers, NULL );
		DWORD s2 = DeviceCapabilitiesW( (LPCWSTR) printerName.utf16(), NULL, DC_PAPERNAMES, (LPWSTR) paperNames, NULL );
		for ( uint i = 0; i < nPaperNames; i++ )
		{
			if ( pageSize == QString::fromUtf16((const ushort*) paperNames[i]) )
			{
				paperIndex = i;
				break;
			}
		}
		if ( paperIndex >= 0 )
		{
			Qt::HANDLE handle = NULL;
			if( OpenPrinterW( (LPWSTR) printerName.utf16(), &handle, NULL ) )
			{
				// Retrieve DEVMODE structure for selected device
				uint size = DocumentPropertiesW( ScCore->primaryMainWindow()->winId(), handle, (LPWSTR) printerName.utf16(), NULL, NULL, 0);
				QByteArray devModeW(size, 0);
				DEVMODEW* devMode = (DEVMODEW*) devModeW.data();
				DocumentPropertiesW( ScCore->primaryMainWindow()->winId(), handle, (LPWSTR) printerName.utf16(), devMode, NULL, DM_OUT_BUFFER);
				ClosePrinter( handle );
				// Set paper size
				devMode->dmPaperSize = papers[paperIndex];
				// Create device context
				HDC printerDC = CreateDCW( NULL, (LPWSTR) printerName.utf16(), NULL, devMode );
				if( printerDC )
				{
					retVal = true;
					int logPixelsX = GetDeviceCaps( printerDC, LOGPIXELSX );
					int logPixelsY = GetDeviceCaps( printerDC, LOGPIXELSY );
					int physicalOffsetX = GetDeviceCaps( printerDC, PHYSICALOFFSETX );
					int physicalOffsetY = GetDeviceCaps( printerDC, PHYSICALOFFSETY );
					ptsLeftMargin = ptsRightMargin = ( physicalOffsetX / (double) logPixelsX * 72 );
					ptsTopMargin = ptsBottomMargin = ( physicalOffsetY / (double) logPixelsY * 72 );
					DeleteDC(printerDC);
				}
			}
		}
		delete[] papers;
		delete[] paperNames;
	}
#endif
	return retVal;
}
Пример #7
0
static void
ppd_handle_media(ppd_file_t *ppd)	/* I - PPD file */
{
  ppd_choice_t	*manual_feed,		/* ManualFeed choice, if any */
		*input_slot;		/* InputSlot choice, if any */
  ppd_size_t	*size;			/* Current media size */
  ppd_attr_t	*rpr;			/* RequiresPageRegion value */


 /*
  * This function determines what page size code to use, if any, for the
  * current media size, InputSlot, and ManualFeed selections.
  *
  * We use the PageSize code if:
  *
  * 1. A custom media size is selected.
  * 2. ManualFeed and InputSlot are not selected (or do not exist).
  * 3. ManualFeed is selected but is False and InputSlot is not selected or
  *    the selection has no code - the latter check done to support "auto" or
  *    "printer default" InputSlot options.
  *
  * We use the PageRegion code if:
  *
  * 4. RequiresPageRegion does not exist and the PPD contains cupsFilter
  *    keywords, indicating this is a CUPS-based driver.
  * 5. RequiresPageRegion exists for the selected InputSlot (or "All" for any
  *    InputSlot or ManualFeed selection) and is True.
  *
  * If none of the 5 conditions are true, no page size code is used and we
  * unmark any existing PageSize or PageRegion choices.
  */

  if ((size = ppdPageSize(ppd, NULL)) == NULL)
    return;

  manual_feed = ppdFindMarkedChoice(ppd, "ManualFeed");
  input_slot  = ppdFindMarkedChoice(ppd, "InputSlot");

  if (input_slot != NULL)
    rpr = ppdFindAttr(ppd, "RequiresPageRegion", input_slot->choice);
  else
    rpr = NULL;

  if (!rpr)
    rpr = ppdFindAttr(ppd, "RequiresPageRegion", "All");

  if (!_cups_strcasecmp(size->name, "Custom") ||
      (!manual_feed && !input_slot) ||
      (manual_feed && !_cups_strcasecmp(manual_feed->choice, "False") &&
       (!input_slot || (input_slot->code && !input_slot->code[0]))) ||
      (!rpr && ppd->num_filters > 0))
  {
   /*
    * Use PageSize code...
    */

    ppdMarkOption(ppd, "PageSize", size->name);
  }
  else if (rpr && rpr->value && !_cups_strcasecmp(rpr->value, "True"))
  {
   /*
    * Use PageRegion code...
    */

    ppdMarkOption(ppd, "PageRegion", size->name);
  }
  else
  {
   /*
    * Do not use PageSize or PageRegion code...
    */

    ppd_choice_t	*page;		/* PageSize/Region choice, if any */

    if ((page = ppdFindMarkedChoice(ppd, "PageSize")) != NULL)
    {
     /*
      * Unmark PageSize...
      */

      page->marked = 0;
      cupsArrayRemove(ppd->marked, page);
    }

    if ((page = ppdFindMarkedChoice(ppd, "PageRegion")) != NULL)
    {
     /*
      * Unmark PageRegion...
      */

      page->marked = 0;
      cupsArrayRemove(ppd->marked, page);
    }
  }
}
Пример #8
0
static
char* make_cmd_param(cups_option_t *p_cups_opt, int num_opt,
	ParamList *p_param, char *p_product, int len)
{
#ifdef DEBUG_PPD
	char *p_ppd_name = "debug.ppd";
#else
	char *p_ppd_name = getenv("PPD");
#endif
	ppd_file_t *p_ppd;
	char *cmd_buf = NULL;
	ppd_choice_t *p_choice;
	ppd_size_t *p_size;
	ppd_size_t *p_default_size;
	int reso;
	char gs_exec_buf[256];
	char gs_cmd_buf[1024];
	char *flt_cmd_buf = NULL;

//For InkJet
	long minw_mm, maxw_mm;
	long minl_mm, maxl_mm;
	PpdToOptKey *p_opt_key_table = alloc_opt_key_table(p_ppd_name);
	PpdToOptKey *p_table = p_opt_key_table;
	ParamList *p_list = NULL;

	if( (p_ppd = ppdOpenFile(p_ppd_name)) == NULL )
		return NULL;

	if( p_opt_key_table == NULL)
		return NULL;

	ppdMarkDefaults(p_ppd);

	// Obtain default page size setting.
	p_choice = ppdFindMarkedChoice(p_ppd, "PageSize");
	p_default_size = ppdPageSize(p_ppd, p_choice->choice);

	mark_ps_param_options(p_ppd, p_param);
	cupsMarkOptions(p_ppd, num_opt, p_cups_opt);

	// Obtain page size setting.
	p_choice = ppdFindMarkedChoice(p_ppd, "PageSize");
	p_size = ppdPageSize(p_ppd, p_choice->choice);

	if (!p_size || ((int)(p_size->width == 0)) || ((int)(p_size->length == 0))) {
	    p_size = p_default_size;
	}

	// Obtain resolution setting.
	p_choice = ppdFindMarkedChoice(p_ppd, "Resolution");
	reso = atoi(p_choice->choice);

	//Obtain product name.
	parse_product_name(p_ppd->product, p_product, len);

	get_min_max_width_length(p_opt_key_table, p_cups_opt, num_opt,
		&minw_mm, &maxw_mm, &minl_mm, &maxl_mm);

// gs command
	strncpy(gs_exec_buf, GS_PATH, 256);
	strncat(gs_exec_buf, "/", 1);
	strncat(gs_exec_buf, GS_BIN, strlen(GS_BIN));
	snprintf(gs_cmd_buf, 1023,
	"%s -r%d -g%dx%d -q -dNOPROMPT -dSAFER -sDEVICE=ppmraw -sOutputFile=- -| ",
			gs_exec_buf, reso, (int)(p_size->width * (float)reso / 72.0),
			(int)(p_size->length * (float)reso / 72.0));

// For InkJet bjfilter Command 
	while( p_table->ppd_key != NULL )
	{
		p_choice = ppdFindMarkedChoice(p_ppd, p_table->ppd_key);
		if( p_choice != NULL )
		{
			char choice[256];

			strncpy(choice, p_choice->choice, 256);

			if( !strcmp(p_table->ppd_key, "PageSize")
			 && !strcmp(choice, "Custom") )
			{
				char pw[256];
				char pl[256];
				long pw_mm, pl_mm;
				pw_mm = (long)((double)p_size->width * 2540.0 / 72.0);
				pl_mm = (long)((double)p_size->length * 2540.0 / 72.0);
				if( minw_mm != -1 && pw_mm < minw_mm )
					pw_mm = minw_mm;
				if( maxw_mm != -1 && pw_mm > maxw_mm )
					pw_mm = maxw_mm;
				if( minl_mm != -1 && pl_mm < minl_mm )
					pl_mm = minl_mm;
				if( maxl_mm != -1 && pl_mm > maxl_mm )
					pl_mm = maxw_mm;
				snprintf(pw, 255, "%ld", pw_mm);
				snprintf(pl, 255, "%ld", pl_mm);
				param_list_add(&p_list, p_table->opt_key, "user", 5);
				param_list_add(&p_list,
					"--paperwidth", pw, strlen(pw) + 1);
				param_list_add(&p_list,
					"--paperheight", pl, strlen(pl) + 1);
			}
			else
			{
				if( !strcmp(p_table->ppd_key, "PageSize")
				 && is_borderless(choice) )
				{
					param_list_add(&p_list, "--borderless", "", 1);
				}
				param_list_add(&p_list, p_table->opt_key,
					choice, strlen(choice) + 1);
			}
		}
		p_table++;
	}

	while( num_opt-- > 0 )
	{
		char *opt_key = ppd_to_opt_key(p_opt_key_table, p_cups_opt->name);
		if( opt_key != NULL )
		{
			char *value = p_cups_opt->value;
			param_list_add(&p_list, opt_key, value, strlen(value) + 1);
		}
		p_cups_opt++;
	}

	{
		char bbox_buf[256];
		float dd = 1.0 - 36.0 / (float)reso;
		int left   = (int)p_size->left;
		int top    = (int)(p_size->top + dd);
		int right  = left + (int)(p_size->right - p_size->left + dd);
		int bottom = top - (int)(p_size->top - p_size->bottom + dd);

		snprintf(bbox_buf, 255, "%-d,%-d,%-d,%-d", left, bottom, right, top);
		param_list_add(&p_list, "--bbox",
				bbox_buf, strlen(bbox_buf) + 1);
	}

	flt_cmd_buf = make_filter_param_line(p_product, reso, p_list);

	if( p_list != NULL ){
		param_list_free(p_list);
		free_opt_key_table(p_opt_key_table);
	}

	ppdClose(p_ppd);

	if( flt_cmd_buf )
	{
		int buf_len;			
		
		buf_len = strlen(gs_cmd_buf) + strlen(flt_cmd_buf) + 1;

		if( (cmd_buf = (char*)malloc(buf_len)) != NULL )
		{
			strcpy(cmd_buf, gs_cmd_buf);
			strcat(cmd_buf, flt_cmd_buf);
		}
		free(flt_cmd_buf);
fprintf(stderr, "pstocanonbj: %s\n", cmd_buf);
		return cmd_buf;
	}
	else
		return NULL;
}
Пример #9
0
static void
ppd_mark_option(ppd_file_t *ppd,	/* I - PPD file */
                const char *option,	/* I - Option name */
                const char *choice)	/* I - Choice name */
{
  int		i, j;			/* Looping vars */
  ppd_option_t	*o;			/* Option pointer */
  ppd_choice_t	*c,			/* Choice pointer */
		*oldc,			/* Old choice pointer */
		key;			/* Search key for choice */
  struct lconv	*loc;			/* Locale data */


  DEBUG_printf(("7ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")",
        	ppd, option, choice));

 /*
  * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
  * it clears the regular InputSlot choices...
  */

  if (!_cups_strcasecmp(option, "AP_D_InputSlot"))
  {
    cupsArraySave(ppd->options);

    if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
    {
      key.option = o;
      if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
      {
        oldc->marked = 0;
        cupsArrayRemove(ppd->marked, oldc);
      }
    }

    cupsArrayRestore(ppd->options);
  }

 /*
  * Check for custom options...
  */

  cupsArraySave(ppd->options);

  o = ppdFindOption(ppd, option);

  cupsArrayRestore(ppd->options);

  if (!o)
    return;

  loc = localeconv();

  if (!_cups_strncasecmp(choice, "Custom.", 7))
  {
   /*
    * Handle a custom option...
    */

    if ((c = ppdFindChoice(o, "Custom")) == NULL)
      return;

    if (!_cups_strcasecmp(option, "PageSize"))
    {
     /*
      * Handle custom page sizes...
      */

      ppdPageSize(ppd, choice);
    }
    else
    {
     /*
      * Handle other custom options...
      */

      ppd_coption_t	*coption;	/* Custom option */
      ppd_cparam_t	*cparam;	/* Custom parameter */
      char		*units;		/* Custom points units */


      if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
      {
        if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
	  return;

        switch (cparam->type)
	{
	  case PPD_CUSTOM_CURVE :
	  case PPD_CUSTOM_INVCURVE :
	  case PPD_CUSTOM_REAL :
	      cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
	                                                         NULL, loc);
	      break;

	  case PPD_CUSTOM_POINTS :
	      cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
	                                                           &units,
	                                                           loc);

              if (units)
	      {
        	if (!_cups_strcasecmp(units, "cm"))
	          cparam->current.custom_points *= 72.0f / 2.54f;
        	else if (!_cups_strcasecmp(units, "mm"))
	          cparam->current.custom_points *= 72.0f / 25.4f;
        	else if (!_cups_strcasecmp(units, "m"))
	          cparam->current.custom_points *= 72.0f / 0.0254f;
        	else if (!_cups_strcasecmp(units, "in"))
	          cparam->current.custom_points *= 72.0f;
        	else if (!_cups_strcasecmp(units, "ft"))
	          cparam->current.custom_points *= 12.0f * 72.0f;
              }
	      break;

	  case PPD_CUSTOM_INT :
	      cparam->current.custom_int = atoi(choice + 7);
	      break;

	  case PPD_CUSTOM_PASSCODE :
	  case PPD_CUSTOM_PASSWORD :
	  case PPD_CUSTOM_STRING :
	      if (cparam->current.custom_string)
	        _cupsStrFree(cparam->current.custom_string);

	      cparam->current.custom_string = _cupsStrAlloc(choice + 7);
	      break;
	}
      }
    }

   /*
    * Make sure that we keep the option marked below...
    */

    choice = "Custom";
  }
  else if (choice[0] == '{')
  {
   /*
    * Handle multi-value custom options...
    */

    ppd_coption_t	*coption;	/* Custom option */
    ppd_cparam_t	*cparam;	/* Custom parameter */
    char		*units;		/* Custom points units */
    int			num_vals;	/* Number of values */
    cups_option_t	*vals,		/* Values */
			*val;		/* Value */


    if ((c = ppdFindChoice(o, "Custom")) == NULL)
      return;

    if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
    {
      num_vals = cupsParseOptions(choice, 0, &vals);

      for (i = 0, val = vals; i < num_vals; i ++, val ++)
      {
        if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
	  continue;

	switch (cparam->type)
	{
	  case PPD_CUSTOM_CURVE :
	  case PPD_CUSTOM_INVCURVE :
	  case PPD_CUSTOM_REAL :
	      cparam->current.custom_real = (float)_cupsStrScand(val->value,
	                                                         NULL, loc);
	      break;

	  case PPD_CUSTOM_POINTS :
	      cparam->current.custom_points = (float)_cupsStrScand(val->value,
	                                                           &units,
	                                                           loc);

	      if (units)
	      {
        	if (!_cups_strcasecmp(units, "cm"))
		  cparam->current.custom_points *= 72.0f / 2.54f;
        	else if (!_cups_strcasecmp(units, "mm"))
		  cparam->current.custom_points *= 72.0f / 25.4f;
        	else if (!_cups_strcasecmp(units, "m"))
		  cparam->current.custom_points *= 72.0f / 0.0254f;
        	else if (!_cups_strcasecmp(units, "in"))
		  cparam->current.custom_points *= 72.0f;
        	else if (!_cups_strcasecmp(units, "ft"))
		  cparam->current.custom_points *= 12.0f * 72.0f;
	      }
	      break;

	  case PPD_CUSTOM_INT :
	      cparam->current.custom_int = atoi(val->value);
	      break;

	  case PPD_CUSTOM_PASSCODE :
	  case PPD_CUSTOM_PASSWORD :
	  case PPD_CUSTOM_STRING :
	      if (cparam->current.custom_string)
		_cupsStrFree(cparam->current.custom_string);

	      cparam->current.custom_string = _cupsStrRetain(val->value);
	      break;
	}
      }

      cupsFreeOptions(num_vals, vals);
    }
  }
  else
  {
    for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
      if (!_cups_strcasecmp(c->choice, choice))
        break;

    if (!i)
      return;
  }

 /*
  * Option found; mark it and then handle unmarking any other options.
  */

  if (o->ui != PPD_UI_PICKMANY)
  {
   /*
    * Unmark all other choices...
    */

    if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
    {
      oldc->marked = 0;
      cupsArrayRemove(ppd->marked, oldc);
    }

    if (!_cups_strcasecmp(option, "PageSize") || !_cups_strcasecmp(option, "PageRegion"))
    {
     /*
      * Mark current page size...
      */

      for (j = 0; j < ppd->num_sizes; j ++)
	ppd->sizes[j].marked = !_cups_strcasecmp(ppd->sizes[j].name,
		                           choice);

     /*
      * Unmark the current PageSize or PageRegion setting, as
      * appropriate...
      */

      cupsArraySave(ppd->options);

      if (!_cups_strcasecmp(option, "PageSize"))
      {
	if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
        {
          key.option = o;
          if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
          {
            oldc->marked = 0;
            cupsArrayRemove(ppd->marked, oldc);
          }
        }
      }
      else
      {
	if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
        {
          key.option = o;
          if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
          {
            oldc->marked = 0;
            cupsArrayRemove(ppd->marked, oldc);
          }
        }
      }

      cupsArrayRestore(ppd->options);
    }
    else if (!_cups_strcasecmp(option, "InputSlot"))
    {
     /*
      * Unmark ManualFeed option...
      */

      cupsArraySave(ppd->options);

      if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
      {
        key.option = o;
        if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
        {
          oldc->marked = 0;
          cupsArrayRemove(ppd->marked, oldc);
        }
      }

      cupsArrayRestore(ppd->options);
    }
    else if (!_cups_strcasecmp(option, "ManualFeed") &&
	     !_cups_strcasecmp(choice, "True"))
    {
     /*
      * Unmark InputSlot option...
      */

      cupsArraySave(ppd->options);

      if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
      {
        key.option = o;
        if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
        {
          oldc->marked = 0;
          cupsArrayRemove(ppd->marked, oldc);
        }
      }

      cupsArrayRestore(ppd->options);
    }
  }

  c->marked = 1;

  cupsArrayAdd(ppd->marked, c);
}
Пример #10
0
int				/* O - Exit status */
main(int  argc,			/* I - Number of command-line arguments */
     char *argv[])		/* I - Command-line arguments */
{
  int		i, j, k, m;	/* Looping vars */
  const char	*filename;	/* File to load */
  FILE          *ppdfile;

  // Temporary file name (for reading from stdin)
  char          tmpfile[19] = "/tmp/lphelp.XXXXXX";
  const int     blocksize = 1024;
  char          buffer[blocksize];
  int           bytesread;

  // variables for parsing PPD file for usual options (boolean, enumerated)
  ppd_file_t	*ppd;		/* PPD file record */
  ppd_size_t	*size;		/* Size record */
  ppd_group_t	*group;		/* UI group */
  ppd_option_t	*option;	/* Standard UI option */
  ppd_choice_t	*choice;	/* Standard UI option choice */
  static char	*uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
  static char	*sections[] = { "ANY", "DOCUMENT", "EXIT",
                                "JCL", "PAGE", "PROLOG" };

  // variables for parsing CUPS-O-MATIC info for numerical options (float, int)
  char line[1024], /* buffer for reading PPD file line by
                      line to search numerical options */
       item[1024], /* item to be defined (left of "=>") */
       value[1024], /* value for item (right of "=>") */
       argname[1024], /* name of the current argument */
       comment[1024]; /* human-readable argument name */
  const char *line_contents; /* contents of line */
  const char *scan; /* pointer scanning the line */
  char *writepointer;
  double min, max, defvalue; /* Range of numerical 
                                CUPS-O-MATIC option */
  int opttype; /* 0 = other, 1 = int, 2 = float */
  int openbrackets; /* How many curled brackets are open? */
  int inquotes; /* are we in quotes now? */
  int inargspart; /* are we in the arguments part now? */
       
 /*
  * Display PPD files for each file listed on the command-line...
  */

  if (argc == 1) {
    fputs("Usage: lphelp <filename1>.ppd [<filename2>.ppd ...]\n       lphelp <printername1> [<printername2> ...]\n       lphelp -\n", stderr);
      return (1);
  }

  for (i = 1; i < argc; i ++) {
    if ((strstr(argv[i], ".ppd")) || (strstr(argv[i], "-")))
      filename = argv[i];
    else
      filename = cupsGetPPD(argv[i]);
    if (strcmp(filename,"-") == 0) {
      if ((ppdfile = fdopen(mkstemp(tmpfile), "w")) == NULL) {
	fprintf(stderr, "Unable to generate temporary file!\n");
      }
      while ((bytesread = fread(buffer, 1, blocksize, stdin)) > 0) {
	fwrite(buffer, 1, bytesread, ppdfile);
      }
      fclose(ppdfile);
      filename = tmpfile;
    }
    if ((ppd = ppdOpenFile(filename)) == NULL) {
      fprintf(stderr, "Unable to open \'%s\' as a PPD file!\n", filename);
      continue;
    }

    printf("==============================================================================\n\n");
    printf("%s\n\n", ppd->modelname);
    printf("==============================================================================\n\n");
    printf("   %s printer\n\n", ppd->color_device ? "Colour" : "Black & white");
    printf("   Printer-specific options\n");
    printf("   ------------------------\n\n");
    printf("   Besides the options described in the CUPS software users manual\n"); 
    printf("   (http://localhost:631/sum.html) you can use also the following options\n");
    printf("   when you print on this printer with the \"lp\" or \"lpr\" command (a choice\n");
    printf("   with the \"default\" mark represents the behaviour of the printer when the\n");
    printf("   appropriate option is not given on the command line):\n\n");

    for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) {
      for (k = 0, option = group->options; k < group->num_options;
           k ++, option ++) {
        if (strcmp(option->keyword, "PageRegion") != 0) {
          if ((strcmp(uis[option->ui],"BOOLEAN") == 0) || 
              (strcmp(uis[option->ui],"PICKONE") == 0)) {  
	    printf("   %s:  -o %s=<choice>\n\n",
	           option->text, option->keyword);
            printf("      <choice> can be one of the following:\n\n");
          } else {
	    printf("   %s:  -o %s=<choice1>,<choice2>,...\n\n",
	           option->text, option->keyword);
            printf("      <choice1>, <choice2>, and so on can be out of the following:\n\n");
          }
          if (strcmp(option->keyword, "PageSize") == 0) {
            for (m = option->num_choices, choice = option->choices;
	         m > 0;
	         m --, choice ++) {
	      size = ppdPageSize(ppd, choice->choice);

	      if (size == NULL)
	        printf("      %s  (%s, size unknown", choice->choice, choice->text);
              else
	        printf("      %s  (%s, size: %.2fx%.2fin", choice->choice,
	               choice->text, size->width / 72.0, size->length / 72.0);
              if (strcmp(option->defchoice, choice->choice) == 0)
	        puts(", default)");
	      else
	        puts(")");
            }
	  } else {
	    for (m = option->num_choices, choice = option->choices;
	         m > 0;
	         m --, choice ++) {
	      printf("      %s  (%s", choice->choice, choice->text);
              if (strcmp(option->defchoice, choice->choice) == 0)
	        puts(", default)");
	      else
	        puts(")");
	    }
          }
          printf("\n");
        }
      }
    }
    ppdClose(ppd);

    // Search for numerical options of CUPS-O-MATIC
    if ((ppdfile = fopen(filename,"r")) == NULL) {
      fprintf(stderr, "Unable to open \'%s\' as a PPD file!\n", filename);
      continue;
    }
    // Reset all variables
    opttype = 0;
    min = 0.0; max = 0.0; defvalue = 0.0;
    openbrackets = 0;
    inquotes = 0;
    writepointer = item;
    inargspart = 0;
    // Read the PPD file again, line by line.
    while (fgets(line,sizeof(line),ppdfile)) {
      // evaluate only lines with CUPS-O-MATIC info
      if (line_contents = strstr(line,"*% COMDATA #")) {
        line_contents += 12; // Go to the text after 
	                     // "*% COMDATA #"
        for (scan = line_contents; 
             (*scan != '\n') && (*scan != '\0');
	     scan ++) {
          switch(*scan) {
	    case '[': // open square bracket
	    case '{': // open curled bracket
              if (!inquotes) {
                openbrackets ++;
                // we are on the left hand side now
                *writepointer = '\0';
                writepointer = item;
                // in which type of block are we now?
                if ((openbrackets == 2) && 
                    (strncasecmp(item,"args",4) == 0)) {
                  // we are entering the arguments section now
                  inargspart = 1;
		}
                if ((openbrackets == 3) && 
                    (inargspart == 1)) {
                  // new argument, get its name
                  strcpy(argname,item);
		}
                // item already evaluated now
                item[0] = '\0';
              } else {*writepointer = *scan; writepointer ++;}
              break;
	    case ',': // end of logical line
	    case ']': // close square bracket
	    case '}': // close curled bracket
              if (!inquotes) {
                // right hand side completed, go to left hand side
                *writepointer = '\0';
                writepointer = item;
                // evaluate logical line
                if (item[0]) {
                  // Machine-readable argument name
                  if ((openbrackets == 3) &&
                      (inargspart == 1) &&
                      (strcasecmp(item,"name") == 0)) {
                    strcpy(argname,value);
		  }
                  // Human-readable argument name
                  if ((openbrackets == 3) &&
                      (inargspart == 1) &&
                      (strcasecmp(item,"comment") == 0)) {
                    strcpy(comment,value);
		  }
                  // argument type
                  if ((openbrackets == 3) &&
                      (inargspart == 1) &&
                      (strcasecmp(item,"type") == 0)) {
                    if (strcasecmp(value,"int") == 0) opttype = 1;
                    if (strcasecmp(value,"float") == 0) opttype = 2;
		  }
                  // minimum value
                  if ((openbrackets == 3) &&
                      (inargspart == 1) &&
                      (strcasecmp(item,"min") == 0)) {
                    min = atof(value);
		  }
                  // maximum value
                  if ((openbrackets == 3) &&
                      (inargspart == 1) &&
                      (strcasecmp(item,"max") == 0)) {
                    max = atof(value);
		  }
                  // default value
                  if ((openbrackets == 3) &&
                      (inargspart == 1) &&
                      (strcasecmp(item,"default") == 0)) {
                    defvalue = atof(value);
		  }
                  // item already evaluated now
                  item[0] = '\0';
                }
                // close bracket
                if ((*scan == '}') || (*scan == ']')) {
                  // which block did we complete now?
                  if ((openbrackets == 2) && 
                      (inargspart == 1)) {
                    // We are leaving the arguments part now
                    inargspart = 0;
                  }
                  if ((openbrackets == 3) && 
                      (inargspart == 1)) {
                    // The current option is completely parsed
                    // Is the option a valid numerical option?
                    if ((opttype > 0) &&
                        (min != max) &&
                        (argname[0])) {
                      // Correct the default value, if necessary
                      if (min < max) {
                        if (defvalue < min) defvalue = min;
                        if (defvalue > max) defvalue = max;
		      } else {
                        if (defvalue < max) defvalue = max;
                        if (defvalue > min) defvalue = min;
                      }
                      // Show the found argument
	              printf("   %s:  -o %s=<value>\n\n",
	                comment, argname);
                      if (opttype == 1) {
                        printf(
                          "      <value> must be an integer number in the range %d..%d\n",
                          (int)(min),(int)(max));
                        printf(
			  "      The default value is %d\n\n",
                          (int)(defvalue));
		      } else {
                        printf(
                          "      <value> must be a decimal number in the range %.2f..%.2f\n",
                          min,max);
                        printf(
			  "      The default value is %.2f\n\n",
                          defvalue);
                      }
                    }
                    // reset the values
                    argname[0] = '\0';
                    opttype = 0;
                    min = 0.0; max = 0.0; defvalue = 0.0;
                  }
                  openbrackets --;
                }
              } else {*writepointer = *scan; writepointer ++;}
              break;
	    case '\'': // quote
              if (!inquotes) { // open quote pair
                inquotes = 1;
	      } else { // close quote pair
                inquotes = 0;
              }
              break;
	    case '=': // "=>"
              if ((!inquotes) && (*(scan + 1) == '>')) {
                scan ++;
                // left hand side completed, go to right hand side
                *writepointer = '\0';
                writepointer = value;
              } else {*writepointer = *scan; writepointer ++;}
              break;
	    case ' ':  // white space
	    case '\t':
              if (!inquotes) {
                // ignore white space outside quotes
              } else {*writepointer = *scan; writepointer ++;}
              break;
	    default:
              // write all other characters
              *writepointer = *scan; writepointer ++;
              break;
          } 
        }
        inquotes = 0; // quote pairs cannot enclose more
	              // than one line
      }
    }
    fclose(ppdfile);
    printf("\n\n\n");
  }

  if (!(strstr(tmpfile, "XXXXXX"))) {
    unlink(tmpfile);
  }

  return (0);
}
Пример #11
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line arguments */
     char *argv[])			/* I - Command-line arguments */
{
  int		i;			/* Looping var */
  ppd_file_t	*ppd;			/* PPD file loaded from disk */
  int		status;			/* Status of tests (0 = success, 1 = fail) */
  int		conflicts;		/* Number of conflicts */
  char		*s;			/* String */
  char		buffer[8192];		/* String buffer */
  const char	*text,			/* Localized text */
		*val;			/* Option value */
  int		num_options;		/* Number of options */
  cups_option_t	*options;		/* Options */
  ppd_size_t	minsize,		/* Minimum size */
		maxsize,		/* Maximum size */
		*size;			/* Current size */
  ppd_attr_t	*attr;			/* Current attribute */
  _ppd_cache_t	*pc;			/* PPD cache */


  status = 0;

  if (argc == 1)
  {
   /*
    * Setup directories for locale stuff...
    */

    if (access("locale", 0))
    {
      mkdir("locale", 0777);
      mkdir("locale/fr", 0777);
      symlink("../../../locale/cups_fr.po", "locale/fr/cups_fr.po");
      mkdir("locale/zh_TW", 0777);
      symlink("../../../locale/cups_zh_TW.po", "locale/zh_TW/cups_zh_TW.po");
    }

    putenv("LOCALEDIR=locale");
    putenv("SOFTWARE=CUPS");

   /*
    * Do tests with test.ppd...
    */

    fputs("ppdOpenFile(test.ppd): ", stdout);

    if ((ppd = _ppdOpenFile("test.ppd", _PPD_LOCALIZATION_ALL)) != NULL)
      puts("PASS");
    else
    {
      ppd_status_t	err;		/* Last error in file */
      int		line;		/* Line number in file */


      status ++;
      err = ppdLastError(&line);

      printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
    }

    fputs("ppdFindAttr(wildcard): ", stdout);
    if ((attr = ppdFindAttr(ppd, "cupsTest", NULL)) == NULL)
    {
      status ++;
      puts("FAIL (not found)");
    }
    else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
    {
      status ++;
      printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
    }
    else
      puts("PASS");

    fputs("ppdFindNextAttr(wildcard): ", stdout);
    if ((attr = ppdFindNextAttr(ppd, "cupsTest", NULL)) == NULL)
    {
      status ++;
      puts("FAIL (not found)");
    }
    else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Bar"))
    {
      status ++;
      printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
    }
    else
      puts("PASS");

    fputs("ppdFindAttr(Foo): ", stdout);
    if ((attr = ppdFindAttr(ppd, "cupsTest", "Foo")) == NULL)
    {
      status ++;
      puts("FAIL (not found)");
    }
    else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
    {
      status ++;
      printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
    }
    else
      puts("PASS");

    fputs("ppdFindNextAttr(Foo): ", stdout);
    if ((attr = ppdFindNextAttr(ppd, "cupsTest", "Foo")) != NULL)
    {
      status ++;
      printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
    }
    else
      puts("PASS");

    fputs("ppdMarkDefaults: ", stdout);
    ppdMarkDefaults(ppd);

    if ((conflicts = ppdConflicts(ppd)) == 0)
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d conflicts)\n", conflicts);
    }

    fputs("ppdEmitString (defaults): ", stdout);
    if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
	!strcmp(s, default_code))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
	     (int)strlen(default_code));

      if (s)
	puts(s);
    }

    if (s)
      free(s);

    fputs("ppdEmitString (custom size and string): ", stdout);
    ppdMarkOption(ppd, "PageSize", "Custom.400x500");
    ppdMarkOption(ppd, "StringOption", "{String1=\"value 1\" String2=value(2)}");

    if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
	!strcmp(s, custom_code))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
	     (int)strlen(custom_code));

      if (s)
	puts(s);
    }

    if (s)
      free(s);

   /*
    * Test constraints...
    */

    fputs("cupsGetConflicts(InputSlot=Envelope): ", stdout);
    ppdMarkOption(ppd, "PageSize", "Letter");

    num_options = cupsGetConflicts(ppd, "InputSlot", "Envelope", &options);
    if (num_options != 2 ||
        (val = cupsGetOption("PageRegion", num_options, options)) == NULL ||
	_cups_strcasecmp(val, "Letter") ||
	(val = cupsGetOption("PageSize", num_options, options)) == NULL ||
	_cups_strcasecmp(val, "Letter"))
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
      puts("PASS");

    fputs("ppdConflicts(): ", stdout);
    ppdMarkOption(ppd, "InputSlot", "Envelope");

    if ((conflicts = ppdConflicts(ppd)) == 2)
      puts("PASS (2)");
    else
    {
      printf("FAIL (%d)\n", conflicts);
      status ++;
    }

    fputs("cupsResolveConflicts(InputSlot=Envelope): ", stdout);
    num_options = 0;
    options     = NULL;
    if (!cupsResolveConflicts(ppd, "InputSlot", "Envelope", &num_options,
                             &options))
    {
      puts("FAIL (Unable to resolve)");
      status ++;
    }
    else if (num_options != 2 ||
             !cupsGetOption("PageSize", num_options, options))
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
      puts("PASS (Resolved by changing PageSize)");

    cupsFreeOptions(num_options, options);

    fputs("cupsResolveConflicts(No option/choice): ", stdout);
    num_options = 0;
    options     = NULL;
    if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
        num_options == 1 && !_cups_strcasecmp(options[0].name, "InputSlot") &&
	!_cups_strcasecmp(options[0].value, "Tray"))
      puts("PASS (Resolved by changing InputSlot)");
    else if (num_options > 0)
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
    {
      puts("FAIL (Unable to resolve)");
      status ++;
    }
    cupsFreeOptions(num_options, options);

    fputs("ppdInstallableConflict(): ", stdout);
    if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
        !ppdInstallableConflict(ppd, "Duplex", "None"))
      puts("PASS");
    else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
    {
      puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
      status ++;
    }
    else
    {
      puts("FAIL (Duplex=None conflicted)");
      status ++;
    }

   /*
    * ppdPageSizeLimits
    */

    fputs("ppdPageSizeLimits: ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 36 || minsize.length != 36 ||
          maxsize.width != 1080 || maxsize.length != 86400)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=36x36, max=1080x86400)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }

   /*
    * cupsMarkOptions with PWG and IPP size names.
    */

    fputs("cupsMarkOptions(media=iso-a4): ", stdout);
    num_options = cupsAddOption("media", "iso-a4", 0, &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "A4"))
    {
      printf("FAIL (%s)\n", size ? size->name : "unknown");
      status ++;
    }
    else
      puts("PASS");

    fputs("cupsMarkOptions(media=na_letter_8.5x11in): ", stdout);
    num_options = cupsAddOption("media", "na_letter_8.5x11in", 0, &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "Letter"))
    {
      printf("FAIL (%s)\n", size ? size->name : "unknown");
      status ++;
    }
    else
      puts("PASS");

    fputs("cupsMarkOptions(media=oe_letter-fullbleed_8.5x11in): ", stdout);
    num_options = cupsAddOption("media", "oe_letter-fullbleed_8.5x11in", 0,
                                &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "Letter.Fullbleed"))
    {
      printf("FAIL (%s)\n", size ? size->name : "unknown");
      status ++;
    }
    else
      puts("PASS");

    fputs("cupsMarkOptions(media=A4): ", stdout);
    num_options = cupsAddOption("media", "A4", 0, &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "A4"))
    {
      printf("FAIL (%s)\n", size ? size->name : "unknown");
      status ++;
    }
    else
      puts("PASS");

   /*
    * Custom sizes...
    */

    fputs("cupsMarkOptions(media=Custom.8x10in): ", stdout);
    num_options = cupsAddOption("media", "Custom.8x10in", 0, &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "Custom") ||
        size->width != 576 || size->length != 720)
    {
      printf("FAIL (%s - %gx%g)\n", size ? size->name : "unknown",
             size ? size->width : 0.0, size ? size->length : 0.0);
      status ++;
    }
    else
      puts("PASS");

   /*
    * Test localization...
    */

    fputs("ppdLocalizeIPPReason(text): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
        !strcmp(buffer, "Foo Reason"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"Foo Reason\")\n", buffer);
    }

    fputs("ppdLocalizeIPPReason(http): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", "http", buffer, sizeof(buffer)) &&
        !strcmp(buffer, "http://foo/bar.html"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"http://foo/bar.html\")\n", buffer);
    }

    fputs("ppdLocalizeIPPReason(help): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", "help", buffer, sizeof(buffer)) &&
        !strcmp(buffer, "help:anchor='foo'%20bookID=Vendor%20Help"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"help:anchor='foo'%%20bookID=Vendor%%20Help\")\n", buffer);
    }

    fputs("ppdLocalizeIPPReason(file): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", "file", buffer, sizeof(buffer)) &&
        !strcmp(buffer, "/help/foo/bar.html"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"/help/foo/bar.html\")\n", buffer);
    }

    putenv("LANG=fr");
    putenv("LC_ALL=fr");
    putenv("LC_CTYPE=fr");
    putenv("LC_MESSAGES=fr");

    fputs("ppdLocalizeIPPReason(fr text): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
        !strcmp(buffer, "La Long Foo Reason"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"La Long Foo Reason\")\n", buffer);
    }

    putenv("LANG=zh_TW");
    putenv("LC_ALL=zh_TW");
    putenv("LC_CTYPE=zh_TW");
    putenv("LC_MESSAGES=zh_TW");

    fputs("ppdLocalizeIPPReason(zh_TW text): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
        !strcmp(buffer, "Number 1 Foo Reason"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"Number 1 Foo Reason\")\n", buffer);
    }

   /*
    * cupsMarkerName localization...
    */

    putenv("LANG=en");
    putenv("LC_ALL=en");
    putenv("LC_CTYPE=en");
    putenv("LC_MESSAGES=en");

    fputs("ppdLocalizeMarkerName(bogus): ", stdout);

    if ((text = ppdLocalizeMarkerName(ppd, "bogus")) != NULL)
    {
      status ++;
      printf("FAIL (\"%s\" instead of NULL)\n", text);
    }
    else
      puts("PASS");

    fputs("ppdLocalizeMarkerName(cyan): ", stdout);

    if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
        !strcmp(text, "Cyan Toner"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"Cyan Toner\")\n",
             text ? text : "(null)");
    }

    putenv("LANG=fr");
    putenv("LC_ALL=fr");
    putenv("LC_CTYPE=fr");
    putenv("LC_MESSAGES=fr");

    fputs("ppdLocalizeMarkerName(fr cyan): ", stdout);
    if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
        !strcmp(text, "La Toner Cyan"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"La Toner Cyan\")\n",
             text ? text : "(null)");
    }

    putenv("LANG=zh_TW");
    putenv("LC_ALL=zh_TW");
    putenv("LC_CTYPE=zh_TW");
    putenv("LC_MESSAGES=zh_TW");

    fputs("ppdLocalizeMarkerName(zh_TW cyan): ", stdout);
    if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
        !strcmp(text, "Number 1 Cyan Toner"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"Number 1 Cyan Toner\")\n",
             text ? text : "(null)");
    }

    ppdClose(ppd);

   /*
    * Test new constraints...
    */

    fputs("ppdOpenFile(test2.ppd): ", stdout);

    if ((ppd = ppdOpenFile("test2.ppd")) != NULL)
      puts("PASS");
    else
    {
      ppd_status_t	err;		/* Last error in file */
      int		line;		/* Line number in file */


      status ++;
      err = ppdLastError(&line);

      printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
    }

    fputs("ppdMarkDefaults: ", stdout);
    ppdMarkDefaults(ppd);

    if ((conflicts = ppdConflicts(ppd)) == 0)
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d conflicts)\n", conflicts);
    }

    fputs("ppdEmitString (defaults): ", stdout);
    if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
	!strcmp(s, default2_code))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
	     (int)strlen(default2_code));

      if (s)
	puts(s);
    }

    if (s)
      free(s);

    fputs("ppdConflicts(): ", stdout);
    ppdMarkOption(ppd, "PageSize", "Env10");
    ppdMarkOption(ppd, "InputSlot", "Envelope");
    ppdMarkOption(ppd, "Quality", "Photo");

    if ((conflicts = ppdConflicts(ppd)) == 1)
      puts("PASS (1)");
    else
    {
      printf("FAIL (%d)\n", conflicts);
      status ++;
    }

    fputs("cupsResolveConflicts(Quality=Photo): ", stdout);
    num_options = 0;
    options     = NULL;
    if (cupsResolveConflicts(ppd, "Quality", "Photo", &num_options,
                             &options))
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
      puts("PASS (Unable to resolve)");
    cupsFreeOptions(num_options, options);

    fputs("cupsResolveConflicts(No option/choice): ", stdout);
    num_options = 0;
    options     = NULL;
    if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
        num_options == 1 && !_cups_strcasecmp(options->name, "Quality") &&
	!_cups_strcasecmp(options->value, "Normal"))
      puts("PASS");
    else if (num_options > 0)
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
    {
      puts("FAIL (Unable to resolve!)");
      status ++;
    }
    cupsFreeOptions(num_options, options);

    fputs("cupsResolveConflicts(loop test): ", stdout);
    ppdMarkOption(ppd, "PageSize", "A4");
    ppdMarkOption(ppd, "InputSlot", "Tray");
    ppdMarkOption(ppd, "Quality", "Photo");
    num_options = 0;
    options     = NULL;
    if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options))
      puts("PASS");
    else if (num_options > 0)
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
    }
    else
      puts("FAIL (No conflicts!)");

    fputs("ppdInstallableConflict(): ", stdout);
    if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
        !ppdInstallableConflict(ppd, "Duplex", "None"))
      puts("PASS");
    else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
    {
      puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
      status ++;
    }
    else
    {
      puts("FAIL (Duplex=None conflicted)");
      status ++;
    }

   /*
    * ppdPageSizeLimits
    */

    ppdMarkDefaults(ppd);

    fputs("ppdPageSizeLimits(default): ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 36 || minsize.length != 36 ||
          maxsize.width != 1080 || maxsize.length != 86400)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=36x36, max=1080x86400)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }

    ppdMarkOption(ppd, "InputSlot", "Manual");

    fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 100 || minsize.length != 100 ||
          maxsize.width != 1000 || maxsize.length != 1000)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=100x100, max=1000x1000)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }

    ppdMarkOption(ppd, "Quality", "Photo");

    fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 200 || minsize.length != 200 ||
          maxsize.width != 1000 || maxsize.length != 1000)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=200x200, max=1000x1000)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }

    ppdMarkOption(ppd, "InputSlot", "Tray");

    fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 300 || minsize.length != 300 ||
          maxsize.width != 1080 || maxsize.length != 86400)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=300x300, max=1080x86400)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }
  }
  else
  {
    const char	*filename;		/* PPD filename */
    struct stat	fileinfo;		/* File information */


    if (!strncmp(argv[1], "-d", 2))
    {
      const char *printer;		/* Printer name */

      if (argv[1][2])
	printer = argv[1] + 2;
      else if (argv[2])
	printer = argv[2];
      else
      {
        puts("Usage: ./testppd -d printer");
	return (1);
      }

      filename = cupsGetPPD(printer);

      if (!filename)
      {
        printf("%s: %s\n", printer, cupsLastErrorString());
        return (1);
      }
    }
    else
      filename = argv[1];

    if (lstat(filename, &fileinfo))
    {
      printf("%s: %s\n", filename, strerror(errno));
      return (1);
    }

    if (S_ISLNK(fileinfo.st_mode))
    {
      char	realfile[1024];		/* Real file path */
      ssize_t	realsize;		/* Size of real file path */


      if ((realsize = readlink(filename, realfile, sizeof(realfile) - 1)) < 0)
        strlcpy(realfile, "Unknown", sizeof(realfile));
      else
        realfile[realsize] = '\0';

      if (stat(realfile, &fileinfo))
	printf("%s: symlink to \"%s\", %s\n", filename, realfile,
	       strerror(errno));
      else
	printf("%s: symlink to \"%s\", %ld bytes\n", filename, realfile,
	       (long)fileinfo.st_size);
    }
    else
      printf("%s: regular file, %ld bytes\n", filename, (long)fileinfo.st_size);

    if ((ppd = ppdOpenFile(filename)) == NULL)
    {
      ppd_status_t	err;		/* Last error in file */
      int		line;		/* Line number in file */


      status ++;
      err = ppdLastError(&line);

      printf("%s: %s on line %d\n", argv[1], ppdErrorString(err), line);
    }
    else
    {
      int		j, k;		/* Looping vars */
      ppd_group_t	*group;		/* Option group */
      ppd_option_t	*option;	/* Option */
      ppd_coption_t	*coption;	/* Custom option */
      ppd_cparam_t	*cparam;	/* Custom parameter */
      ppd_const_t	*c;		/* UIConstraints */
      char		lang[255],	/* LANG environment variable */
			lc_all[255],	/* LC_ALL environment variable */
			lc_ctype[255],	/* LC_CTYPE environment variable */
			lc_messages[255];/* LC_MESSAGES environment variable */


      if (argc > 2)
      {
        snprintf(lang, sizeof(lang), "LANG=%s", argv[2]);
	putenv(lang);
        snprintf(lc_all, sizeof(lc_all), "LC_ALL=%s", argv[2]);
	putenv(lc_all);
        snprintf(lc_ctype, sizeof(lc_ctype), "LC_CTYPE=%s", argv[2]);
	putenv(lc_ctype);
        snprintf(lc_messages, sizeof(lc_messages), "LC_MESSAGES=%s", argv[2]);
	putenv(lc_messages);
      }

      ppdLocalize(ppd);
      ppdMarkDefaults(ppd);

      if (argc > 3)
      {
        text = ppdLocalizeIPPReason(ppd, argv[3], NULL, buffer, sizeof(buffer));
	printf("ppdLocalizeIPPReason(%s)=%s\n", argv[3],
	       text ? text : "(null)");
	return (text == NULL);
      }

      for (i = ppd->num_groups, group = ppd->groups;
	   i > 0;
	   i --, group ++)
      {
	printf("%s (%s):\n", group->name, group->text);

	for (j = group->num_options, option = group->options;
	     j > 0;
	     j --, option ++)
	{
	  printf("    %s (%s):\n", option->keyword, option->text);

	  for (k = 0; k < option->num_choices; k ++)
	    printf("        - %s%s (%s)\n",
	           option->choices[k].marked ? "*" : "",
		   option->choices[k].choice, option->choices[k].text);

          if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
	  {
	    for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
	         cparam;
		 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
            {
	      switch (cparam->type)
	      {
	        case PPD_CUSTOM_CURVE :
		    printf("              %s(%s): PPD_CUSTOM_CURVE (%g to %g)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_curve,
			   cparam->maximum.custom_curve);
		    break;

	        case PPD_CUSTOM_INT :
		    printf("              %s(%s): PPD_CUSTOM_INT (%d to %d)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_int,
			   cparam->maximum.custom_int);
		    break;

	        case PPD_CUSTOM_INVCURVE :
		    printf("              %s(%s): PPD_CUSTOM_INVCURVE (%g to %g)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_invcurve,
			   cparam->maximum.custom_invcurve);
		    break;

	        case PPD_CUSTOM_PASSCODE :
		    printf("              %s(%s): PPD_CUSTOM_PASSCODE (%d to %d)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_passcode,
			   cparam->maximum.custom_passcode);
		    break;

	        case PPD_CUSTOM_PASSWORD :
		    printf("              %s(%s): PPD_CUSTOM_PASSWORD (%d to %d)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_password,
			   cparam->maximum.custom_password);
		    break;

	        case PPD_CUSTOM_POINTS :
		    printf("              %s(%s): PPD_CUSTOM_POINTS (%g to %g)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_points,
			   cparam->maximum.custom_points);
		    break;

	        case PPD_CUSTOM_REAL :
		    printf("              %s(%s): PPD_CUSTOM_REAL (%g to %g)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_real,
			   cparam->maximum.custom_real);
		    break;

	        case PPD_CUSTOM_STRING :
		    printf("              %s(%s): PPD_CUSTOM_STRING (%d to %d)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_string,
			   cparam->maximum.custom_string);
		    break;
	      }
	    }
	  }
	}
      }

      puts("\nSizes:");
      for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
        printf("    %s = %gx%g, [%g %g %g %g]\n", size->name, size->width,
	       size->length, size->left, size->bottom, size->right, size->top);

      puts("\nConstraints:");

      for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
        printf("    *UIConstraints: *%s %s *%s %s\n", c->option1, c->choice1,
	       c->option2, c->choice2);
      if (ppd->num_consts == 0)
        puts("    NO CONSTRAINTS");

      puts("\nFilters:");

      for (i = 0; i < ppd->num_filters; i ++)
        printf("    %s\n", ppd->filters[i]);

      if (ppd->num_filters == 0)
        puts("    NO FILTERS");

      puts("\nAttributes:");

      for (attr = (ppd_attr_t *)cupsArrayFirst(ppd->sorted_attrs);
           attr;
	   attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs))
        printf("    *%s %s/%s: \"%s\"\n", attr->name, attr->spec,
	       attr->text, attr->value ? attr->value : "");

      puts("\nPPD Cache:");
      if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL)
        printf("    Unable to create: %s\n", cupsLastErrorString());
      else
      {
        _ppdCacheWriteFile(pc, "t.cache", NULL);
        puts("    Wrote t.cache.");
      }
    }

    if (!strncmp(argv[1], "-d", 2))
      unlink(filename);
  }

#ifdef __APPLE__
  if (getenv("MallocStackLogging") && getenv("MallocStackLoggingNoCompact"))
  {
    char	command[1024];		/* malloc_history command */

    snprintf(command, sizeof(command), "malloc_history %d -all_by_size",
	     getpid());
    fflush(stdout);
    system(command);
  }
#endif /* __APPLE__ */

  ppdClose(ppd);

  return (status);
}