コード例 #1
0
ファイル: mark.c プロジェクト: AnotherView/cups
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);
}
コード例 #2
0
ファイル: ppd-conflicts.c プロジェクト: Cacauu/cups
static void
ppd_load_constraints(ppd_file_t *ppd)	/* I - PPD file */
{
  int		i;			/* Looping var */
  ppd_const_t	*oldconst;		/* Current UIConstraints data */
  ppd_attr_t	*constattr;		/* Current cupsUIConstraints attribute */
  _ppd_cups_uiconsts_t	*consts;	/* Current cupsUIConstraints data */
  _ppd_cups_uiconst_t	*constptr;	/* Current constraint */
  ppd_group_t	*installable;		/* Installable options group */
  const char	*vptr;			/* Pointer into constraint value */
  char		option[PPD_MAX_NAME],	/* Option name/MainKeyword */
		choice[PPD_MAX_NAME],	/* Choice/OptionKeyword */
		*ptr;			/* Pointer into option or choice */


  DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd));

 /*
  * Create an array to hold the constraint data...
  */

  ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL);

 /*
  * Find the installable options group if it exists...
  */

  for (i = ppd->num_groups, installable = ppd->groups;
       i > 0;
       i --, installable ++)
    if (!_cups_strcasecmp(installable->name, "InstallableOptions"))
      break;

  if (i <= 0)
    installable = NULL;

 /*
  * Load old-style [Non]UIConstraints data...
  */

  for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++)
  {
   /*
    * Weed out nearby duplicates, since the PPD spec requires that you
    * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
    */

    if (i > 1 &&
	!_cups_strcasecmp(oldconst[0].option1, oldconst[1].option2) &&
	!_cups_strcasecmp(oldconst[0].choice1, oldconst[1].choice2) &&
	!_cups_strcasecmp(oldconst[0].option2, oldconst[1].option1) &&
	!_cups_strcasecmp(oldconst[0].choice2, oldconst[1].choice1))
      continue;

   /*
    * Allocate memory...
    */

    if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
    {
      DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
		 "UIConstraints!");
      return;
    }

    if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL)
    {
      free(consts);
      DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
		 "UIConstraints!");
      return;
    }

   /*
    * Fill in the information...
    */

    consts->num_constraints = 2;
    consts->constraints     = constptr;

    if (!_cups_strncasecmp(oldconst->option1, "Custom", 6) &&
	!_cups_strcasecmp(oldconst->choice1, "True"))
    {
      constptr[0].option      = ppdFindOption(ppd, oldconst->option1 + 6);
      constptr[0].choice      = ppdFindChoice(constptr[0].option, "Custom");
      constptr[0].installable = 0;
    }
    else
    {
      constptr[0].option      = ppdFindOption(ppd, oldconst->option1);
      constptr[0].choice      = ppdFindChoice(constptr[0].option,
					      oldconst->choice1);
      constptr[0].installable = ppd_is_installable(installable,
						   oldconst->option1);
    }

    if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0]))
    {
      DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
		    oldconst->option1, oldconst->choice1));
      free(consts->constraints);
      free(consts);
      continue;
    }

    if (!_cups_strncasecmp(oldconst->option2, "Custom", 6) &&
	!_cups_strcasecmp(oldconst->choice2, "True"))
    {
      constptr[1].option      = ppdFindOption(ppd, oldconst->option2 + 6);
      constptr[1].choice      = ppdFindChoice(constptr[1].option, "Custom");
      constptr[1].installable = 0;
    }
    else
    {
      constptr[1].option      = ppdFindOption(ppd, oldconst->option2);
      constptr[1].choice      = ppdFindChoice(constptr[1].option,
					      oldconst->choice2);
      constptr[1].installable = ppd_is_installable(installable,
						   oldconst->option2);
    }

    if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0]))
    {
      DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
		    oldconst->option2, oldconst->choice2));
      free(consts->constraints);
      free(consts);
      continue;
    }

    consts->installable = constptr[0].installable || constptr[1].installable;

   /*
    * Add it to the constraints array...
    */

    cupsArrayAdd(ppd->cups_uiconstraints, consts);
  }

 /*
  * Then load new-style constraints...
  */

  for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL);
       constattr;
       constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
  {
    if (!constattr->value)
    {
      DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
      continue;
    }

    for (i = 0, vptr = strchr(constattr->value, '*');
	 vptr;
	 i ++, vptr = strchr(vptr + 1, '*'));

    if (i == 0)
    {
      DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
      continue;
    }

    if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
    {
      DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
		 "cupsUIConstraints!");
      return;
    }

    if ((constptr = calloc((size_t)i, sizeof(_ppd_cups_uiconst_t))) == NULL)
    {
      free(consts);
      DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
		 "cupsUIConstraints!");
      return;
    }

    consts->num_constraints = i;
    consts->constraints     = constptr;

    strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver));

    for (i = 0, vptr = strchr(constattr->value, '*');
	 vptr;
	 i ++, vptr = strchr(vptr, '*'), constptr ++)
    {
     /*
      * Extract "*Option Choice" or just "*Option"...
      */

      for (vptr ++, ptr = option; *vptr && !_cups_isspace(*vptr); vptr ++)
	if (ptr < (option + sizeof(option) - 1))
	  *ptr++ = *vptr;

      *ptr = '\0';

      while (_cups_isspace(*vptr))
	vptr ++;

      if (*vptr == '*')
	choice[0] = '\0';
      else
      {
	for (ptr = choice; *vptr && !_cups_isspace(*vptr); vptr ++)
	  if (ptr < (choice + sizeof(choice) - 1))
	    *ptr++ = *vptr;

	*ptr = '\0';
      }

      if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True"))
      {
	_cups_strcpy(option, option + 6);
	strlcpy(choice, "Custom", sizeof(choice));
      }

      constptr->option      = ppdFindOption(ppd, option);
      constptr->choice      = ppdFindChoice(constptr->option, choice);
      constptr->installable = ppd_is_installable(installable, option);
      consts->installable   |= constptr->installable;

      if (!constptr->option || (!constptr->choice && choice[0]))
      {
	DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
		      option, choice));
	break;
      }
    }

    if (!vptr)
      cupsArrayAdd(ppd->cups_uiconstraints, consts);
    else
    {
      free(consts->constraints);
      free(consts);
    }
  }
}
コード例 #3
0
ファイル: commandtops.c プロジェクト: jianglei12138/cups
static int				/* O - Exit status */
auto_configure(ppd_file_t *ppd,		/* I - PPD file */
               const char *user)	/* I - Printing user */
{
  int		status = 0;		/* Exit status */
  ppd_option_t	*option;		/* Current option in PPD */
  ppd_attr_t	*attr;			/* Query command attribute */
  const char	*valptr;		/* Pointer into attribute value */
  char		buffer[1024],		/* String buffer */
		*bufptr;		/* Pointer into buffer */
  ssize_t	bytes;			/* Number of bytes read */
  int		datalen;		/* Side-channel data length */


 /*
  * See if the backend supports bidirectional I/O...
  */

  datalen = 1;
  if (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer, &datalen,
                               30.0) != CUPS_SC_STATUS_OK ||
      buffer[0] != CUPS_SC_BIDI_SUPPORTED)
  {
    fputs("DEBUG: Unable to auto-configure PostScript Printer - no "
          "bidirectional I/O available!\n", stderr);
    return (1);
  }

 /*
  * Put the printer in PostScript mode...
  */

  begin_ps(ppd, user);

 /*
  * (STR #4028)
  *
  * As a lot of PPDs contain bad PostScript query code, we need to prevent one
  * bad query sequence from affecting all auto-configuration.  The following
  * error handler allows us to log PostScript errors to cupsd.
  */

  puts("/cups_handleerror {\n"
       "  $error /newerror false put\n"
       "  (:PostScript error in \") print cups_query_keyword print (\": ) "
       "print\n"
       "  $error /errorname get 128 string cvs print\n"
       "  (; offending command:) print $error /command get 128 string cvs "
       "print (\n) print flush\n"
       "} bind def\n"
       "errordict /timeout {} put\n"
       "/cups_query_keyword (?Unknown) def\n");
  fflush(stdout);

 /*
  * Wait for the printer to become connected...
  */

  do
  {
    sleep(1);
    datalen = 1;
  }
  while (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_CONNECTED, buffer, &datalen,
                                  5.0) == CUPS_SC_STATUS_OK && !buffer[0]);

 /*
  * Then loop through every option in the PPD file and ask for the current
  * value...
  */

  fputs("DEBUG: Auto-configuring PostScript printer...\n", stderr);

  for (option = ppdFirstOption(ppd); option; option = ppdNextOption(ppd))
  {
   /*
    * See if we have a query command for this option...
    */

    snprintf(buffer, sizeof(buffer), "?%s", option->keyword);

    if ((attr = ppdFindAttr(ppd, buffer, NULL)) == NULL || !attr->value)
    {
      fprintf(stderr, "DEBUG: Skipping %s option...\n", option->keyword);
      continue;
    }

   /*
    * Send the query code to the printer...
    */

    fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword);

    for (bufptr = buffer, valptr = attr->value; *valptr; valptr ++)
    {
     /*
      * Log the query code, breaking at newlines...
      */

      if (*valptr == '\n')
      {
        *bufptr = '\0';
        fprintf(stderr, "DEBUG: %s\\n\n", buffer);
        bufptr = buffer;
      }
      else if (*valptr < ' ')
      {
        if (bufptr >= (buffer + sizeof(buffer) - 4))
        {
	  *bufptr = '\0';
	  fprintf(stderr, "DEBUG: %s\n", buffer);
	  bufptr = buffer;
        }

        if (*valptr == '\r')
        {
          *bufptr++ = '\\';
          *bufptr++ = 'r';
        }
        else if (*valptr == '\t')
        {
          *bufptr++ = '\\';
          *bufptr++ = 't';
        }
        else
        {
          *bufptr++ = '\\';
          *bufptr++ = '0' + ((*valptr / 64) & 7);
          *bufptr++ = '0' + ((*valptr / 8) & 7);
          *bufptr++ = '0' + (*valptr & 7);
        }
      }
      else
      {
        if (bufptr >= (buffer + sizeof(buffer) - 1))
        {
	  *bufptr = '\0';
	  fprintf(stderr, "DEBUG: %s\n", buffer);
	  bufptr = buffer;
        }

	*bufptr++ = *valptr;
      }
    }

    if (bufptr > buffer)
    {
      *bufptr = '\0';
      fprintf(stderr, "DEBUG: %s\n", buffer);
    }

    printf("/cups_query_keyword (?%s) def\n", option->keyword);
					/* Set keyword for error reporting */
    fputs("{ (", stdout);
    for (valptr = attr->value; *valptr; valptr ++)
    {
      if (*valptr == '(' || *valptr == ')' || *valptr == '\\')
        putchar('\\');
      putchar(*valptr);
    }
    fputs(") cvx exec } stopped { cups_handleerror } if clear\n", stdout);
    					/* Send query code */
    fflush(stdout);

    datalen = 0;
    cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer, &datalen, 5.0);

   /*
    * Read the response data...
    */

    bufptr    = buffer;
    buffer[0] = '\0';
    while ((bytes = cupsBackChannelRead(bufptr, sizeof(buffer) - (size_t)(bufptr - buffer) - 1, 10.0)) > 0)
    {
     /*
      * No newline at the end? Go on reading ...
      */

      bufptr += bytes;
      *bufptr = '\0';

      if (bytes == 0 ||
          (bufptr > buffer && bufptr[-1] != '\r' && bufptr[-1] != '\n'))
	continue;

     /*
      * Trim whitespace and control characters from both ends...
      */

      bytes = bufptr - buffer;

      for (bufptr --; bufptr >= buffer; bufptr --)
        if (isspace(*bufptr & 255) || iscntrl(*bufptr & 255))
	  *bufptr = '\0';
	else
	  break;

      for (bufptr = buffer; isspace(*bufptr & 255) || iscntrl(*bufptr & 255);
	   bufptr ++);

      if (bufptr > buffer)
      {
        _cups_strcpy(buffer, bufptr);
	bufptr = buffer;
      }

      fprintf(stderr, "DEBUG: Got %d bytes.\n", (int)bytes);

     /*
      * Skip blank lines...
      */

      if (!buffer[0])
        continue;

     /*
      * Check the response...
      */

      if ((bufptr = strchr(buffer, ':')) != NULL)
      {
       /*
        * PostScript code for this option in the PPD is broken; show the
        * interpreter's error message that came back...
        */

	fprintf(stderr, "DEBUG%s\n", bufptr);
	break;
      }

     /*
      * Verify the result is a valid option choice...
      */

      if (!ppdFindChoice(option, buffer))
      {
	if (!strcasecmp(buffer, "Unknown"))
	  break;

	bufptr    = buffer;
	buffer[0] = '\0';
        continue;
      }

     /*
      * Write out the result and move on to the next option...
      */

      fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, buffer);
      break;
    }

   /*
    * Printer did not answer this option's query
    */

    if (bytes <= 0)
    {
      fprintf(stderr,
	      "DEBUG: No answer to query for option %s within 10 seconds.\n",
	      option->keyword);
      status = 1;
    }
  }

 /*
  * Finish the job...
  */

  fflush(stdout);
  end_ps(ppd);

 /*
  * Return...
  */

  if (status)
    _cupsLangPrintFilter(stderr, "WARNING",
                         _("Unable to configure printer options."));

  return (0);
}
コード例 #4
0
ファイル: testlang.c プロジェクト: jianglei12138/cups
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line arguments */
     char *argv[])			/* I - Command-line arguments */
{
  int			i;		/* Looping var */
  int			errors = 0;	/* Number of errors */
  cups_lang_t		*language;	/* Message catalog */
  cups_lang_t		*language2;	/* Message catalog */
  struct lconv		*loc;		/* Locale data */
  char			buffer[1024];	/* String buffer */
  double		number;		/* Number */
  static const char * const tests[] =	/* Test strings */
  {
    "1",
    "-1",
    "3",
    "5.125"
  };


  if (argc == 1)
  {
    language  = cupsLangDefault();
    language2 = cupsLangDefault();
  }
  else
  {
    language  = cupsLangGet(argv[1]);
    language2 = cupsLangGet(argv[1]);

    setenv("LANG", argv[1], 1);
    setenv("SOFTWARE", "CUPS/" CUPS_SVERSION, 1);
  }

  _cupsSetLocale(argv);

  if (language != language2)
  {
    errors ++;

    puts("**** ERROR: Language cache did not work! ****");
    puts("First result from cupsLangGet:");
  }

  printf("Language = \"%s\"\n", language->language);
  printf("Encoding = \"%s\"\n", _cupsEncodingName(language->encoding));
  printf("No       = \"%s\"\n", _cupsLangString(language, "No"));
  printf("Yes      = \"%s\"\n", _cupsLangString(language, "Yes"));

  if (language != language2)
  {
    puts("Second result from cupsLangGet:");

    printf("Language = \"%s\"\n", language2->language);
    printf("Encoding = \"%s\"\n", _cupsEncodingName(language2->encoding));
    printf("No       = \"%s\"\n", _cupsLangString(language2, "No"));
    printf("Yes      = \"%s\"\n", _cupsLangString(language2, "Yes"));
  }

  loc = localeconv();

  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i ++)
  {
    number = _cupsStrScand(tests[i], NULL, loc);

    printf("_cupsStrScand(\"%s\") number=%f\n", tests[i], number);

    _cupsStrFormatd(buffer, buffer + sizeof(buffer), number, loc);

    printf("_cupsStrFormatd(%f) buffer=\"%s\"\n", number, buffer);

    if (strcmp(buffer, tests[i]))
    {
      errors ++;
      puts("**** ERROR: Bad formatted number! ****");
    }
  }

  if (argc == 3)
  {
    ppd_file_t		*ppd;		/* PPD file */
    ppd_option_t	*option;	/* PageSize option */
    ppd_choice_t	*choice;	/* PageSize/Letter choice */

    if ((ppd = ppdOpenFile(argv[2])) == NULL)
    {
      printf("Unable to open PPD file \"%s\".\n", argv[2]);
      errors ++;
    }
    else
    {
      ppdLocalize(ppd);

      if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
      {
        puts("No PageSize option.");
        errors ++;
      }
      else
      {
        printf("PageSize: %s\n", option->text);

        if ((choice = ppdFindChoice(option, "Letter")) == NULL)
        {
	  puts("No Letter PageSize choice.");
	  errors ++;
        }
        else
        {
	  printf("Letter: %s\n", choice->text);
        }
      }

      ppdClose(ppd);
    }
  }

  return (errors > 0);
}