text: /*
   * PPD model-specific attribute routines for libppd.
   *
   * Copyright 2007-2015 by Apple Inc.
   * Copyright 1997-2006 by Easy Software Products.
   *
   * Licensed under Apache License v2.0.  See the file "LICENSE" for more
   * information.
   */
  
  /*
   * Include necessary headers...
   */
  
  #include "string-private.h"
  #include "ppd.h"
  #include "debug-internal.h"
  
  
  /*
   * 'ppdFindAttr()' - Find the first matching attribute.
   *
   * @since CUPS 1.1.19/macOS 10.3@
   */
  
  ppd_attr_t *				/* O - Attribute or @code NULL@ if not found */
  ppdFindAttr(ppd_file_t *ppd,		/* I - PPD file data */
              const char *name,		/* I - Attribute name */
              const char *spec)		/* I - Specifier string or @code NULL@ */
  {
    ppd_attr_t	key,			/* Search key */
  		*attr;			/* Current attribute */
  
  
    DEBUG_printf(("2ppdFindAttr(ppd=%p, name=\"%s\", spec=\"%s\")", ppd, name,
                  spec));
  
   /*
    * Range check input...
    */
  
    if (!ppd || !name || ppd->num_attrs == 0)
      return (NULL);
  
   /*
    * Search for a matching attribute...
    */
  
    memset(&key, 0, sizeof(key));
    strlcpy(key.name, name, sizeof(key.name));
  
   /*
    * Return the first matching attribute, if any...
    */
  
    if ((attr = (ppd_attr_t *)cupsArrayFind(ppd->sorted_attrs, &key)) != NULL)
    {
      if (spec)
      {
       /*
        * Loop until we find the first matching attribute for "spec"...
        */
  
        while (attr && _ppd_strcasecmp(spec, attr->spec))
        {
          if ((attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) != NULL &&
  	    _ppd_strcasecmp(attr->name, name))
  	  attr = NULL;
        }
      }
    }
  
    return (attr);
  }
  
  
  /*
   * 'ppdFindNextAttr()' - Find the next matching attribute.
   *
   * @since CUPS 1.1.19/macOS 10.3@
   */
  
  ppd_attr_t *				/* O - Attribute or @code NULL@ if not found */
  ppdFindNextAttr(ppd_file_t *ppd,	/* I - PPD file data */
                  const char *name,	/* I - Attribute name */
  		const char *spec)	/* I - Specifier string or @code NULL@ */
  {
    ppd_attr_t	*attr;			/* Current attribute */
  
  
   /*
    * Range check input...
    */
  
    if (!ppd || !name || ppd->num_attrs == 0)
      return (NULL);
  
   /*
    * See if there are more attributes to return...
    */
  
    while ((attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) != NULL)
    {
     /*
      * Check the next attribute to see if it is a match...
      */
  
      if (_ppd_strcasecmp(attr->name, name))
      {
       /*
        * Nope, reset the current pointer to the end of the array...
        */
  
        cupsArrayIndex(ppd->sorted_attrs, cupsArrayCount(ppd->sorted_attrs));
  
        return (NULL);
      }
  
      if (!spec || !_ppd_strcasecmp(attr->spec, spec))
        break;
    }
  
   /*
    * Return the next attribute's value...
    */
  
    return (attr);
  }
  
  
  /*
   * 'ppdNormalizeMakeAndModel()' - Normalize a product/make-and-model string.
   *
   * This function tries to undo the mistakes made by many printer manufacturers
   * to produce a clean make-and-model string we can use.
   */
  
  char *					/* O - Normalized make-and-model string or NULL on error */
  ppdNormalizeMakeAndModel(
      const char *make_and_model,		/* I - Original make-and-model string */
      char       *buffer,			/* I - String buffer */
      size_t     bufsize)			/* I - Size of string buffer */
  {
    char	*bufptr;			/* Pointer into buffer */
  
  
    if (!make_and_model || !buffer || bufsize < 1)
    {
      if (buffer)
        *buffer = '\0';
  
      return (NULL);
    }
  
   /*
    * Skip leading whitespace...
    */
  
    while (_ppd_isspace(*make_and_model))
      make_and_model ++;
  
   /*
    * Remove parenthesis and add manufacturers as needed...
    */
  
    if (make_and_model[0] == '(')
    {
      strlcpy(buffer, make_and_model + 1, bufsize);
  
      if ((bufptr = strrchr(buffer, ')')) != NULL)
        *bufptr = '\0';
    }
    else if (!_ppd_strncasecmp(make_and_model, "XPrint", 6))
    {
     /*
      * Xerox XPrint...
      */
  
      snprintf(buffer, bufsize, "Xerox %s", make_and_model);
    }
    else if (!_ppd_strncasecmp(make_and_model, "Eastman", 7))
    {
     /*
      * Kodak...
      */
  
      snprintf(buffer, bufsize, "Kodak %s", make_and_model + 7);
    }
    else if (!_ppd_strncasecmp(make_and_model, "laserwriter", 11))
    {
     /*
      * Apple LaserWriter...
      */
  
      snprintf(buffer, bufsize, "Apple LaserWriter%s", make_and_model + 11);
    }
    else if (!_ppd_strncasecmp(make_and_model, "colorpoint", 10))
    {
     /*
      * Seiko...
      */
  
      snprintf(buffer, bufsize, "Seiko %s", make_and_model);
    }
    else if (!_ppd_strncasecmp(make_and_model, "fiery", 5))
    {
     /*
      * EFI...
      */
  
      snprintf(buffer, bufsize, "EFI %s", make_and_model);
    }
    else if (!_ppd_strncasecmp(make_and_model, "ps ", 3) ||
  	   !_ppd_strncasecmp(make_and_model, "colorpass", 9))
    {
     /*
      * Canon...
      */
  
      snprintf(buffer, bufsize, "Canon %s", make_and_model);
    }
    else if (!_ppd_strncasecmp(make_and_model, "designjet", 9) ||
             !_ppd_strncasecmp(make_and_model, "deskjet", 7))
    {
     /*
      * HP...
      */
  
      snprintf(buffer, bufsize, "HP %s", make_and_model);
    }
    else
      strlcpy(buffer, make_and_model, bufsize);
  
   /*
    * Clean up the make...
    */
  
    if (!_ppd_strncasecmp(buffer, "agfa", 4))
    {
     /*
      * Replace with AGFA (all uppercase)...
      */
  
      buffer[0] = 'A';
      buffer[1] = 'G';
      buffer[2] = 'F';
      buffer[3] = 'A';
    }
    else if (!_ppd_strncasecmp(buffer, "Hewlett-Packard hp ", 19))
    {
     /*
      * Just put "HP" on the front...
      */
  
      buffer[0] = 'H';
      buffer[1] = 'P';
      _ppd_strcpy(buffer + 2, buffer + 18);
    }
    else if (!_ppd_strncasecmp(buffer, "Hewlett-Packard ", 16))
    {
     /*
      * Just put "HP" on the front...
      */
  
      buffer[0] = 'H';
      buffer[1] = 'P';
      _ppd_strcpy(buffer + 2, buffer + 15);
    }
    else if (!_ppd_strncasecmp(buffer, "Lexmark International", 21))
    {
     /*
      * Strip "International"...
      */
  
      _ppd_strcpy(buffer + 8, buffer + 21);
    }
    else if (!_ppd_strncasecmp(buffer, "herk", 4))
    {
     /*
      * Replace with LHAG...
      */
  
      buffer[0] = 'L';
      buffer[1] = 'H';
      buffer[2] = 'A';
      buffer[3] = 'G';
    }
    else if (!_ppd_strncasecmp(buffer, "linotype", 8))
    {
     /*
      * Replace with LHAG...
      */
  
      buffer[0] = 'L';
      buffer[1] = 'H';
      buffer[2] = 'A';
      buffer[3] = 'G';
      _ppd_strcpy(buffer + 4, buffer + 8);
    }
  
   /*
    * Remove trailing whitespace and return...
    */
  
    for (bufptr = buffer + strlen(buffer) - 1;
         bufptr >= buffer && _ppd_isspace(*bufptr);
         bufptr --);
  
    bufptr[1] = '\0';
  
    return (buffer[0] ? buffer : NULL);
  }
  