Blame locale/checkpo.c

Packit 2fc92b
/*
Packit 2fc92b
 * Verify that translations in the .po file have the same number and type of
Packit 2fc92b
 * printf-style format strings.
Packit 2fc92b
 *
Packit 2fc92b
 * Copyright 2007-2017 by Apple Inc.
Packit 2fc92b
 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
Packit 2fc92b
 *
Packit 2fc92b
 * These coded instructions, statements, and computer programs are the
Packit 2fc92b
 * property of Apple Inc. and are protected by Federal copyright
Packit 2fc92b
 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
Packit 2fc92b
 * which should have been included with this file.  If this file is
Packit 2fc92b
 * missing or damaged, see the license at "http://www.cups.org/".
Packit 2fc92b
 *
Packit 2fc92b
 * Usage:
Packit 2fc92b
 *
Packit 2fc92b
 *   checkpo filename.{po,strings} [... filenameN.{po,strings}]
Packit 2fc92b
 *
Packit 2fc92b
 * Compile with:
Packit 2fc92b
 *
Packit 2fc92b
 *   gcc -o checkpo checkpo.c `cups-config --libs`
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
#include <cups/cups-private.h>
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Local functions...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static char		*abbreviate(const char *s, char *buf, int bufsize);
Packit 2fc92b
static cups_array_t	*collect_formats(const char *id);
Packit 2fc92b
static cups_array_t     *cups_load_strings(const char *filename);
Packit 2fc92b
static int	        cups_read_strings(cups_file_t *fp, char *buffer, size_t bufsize, char **id, char **str);
Packit 2fc92b
static char	        *cups_scan_strings(char *buffer);
Packit 2fc92b
static void		free_formats(cups_array_t *fmts);
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'main()' - Validate .po and .strings files.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
int					/* O - Exit code */
Packit 2fc92b
main(int  argc,				/* I - Number of command-line args */
Packit 2fc92b
     char *argv[])			/* I - Command-line arguments */
Packit 2fc92b
{
Packit 2fc92b
  int			i;		/* Looping var */
Packit 2fc92b
  cups_array_t		*po;		/* .po file */
Packit 2fc92b
  _cups_message_t	*msg;		/* Current message */
Packit 2fc92b
  cups_array_t		*idfmts,	/* Format strings in msgid */
Packit 2fc92b
			*strfmts;	/* Format strings in msgstr */
Packit 2fc92b
  char			*idfmt,		/* Current msgid format string */
Packit 2fc92b
			*strfmt;	/* Current msgstr format string */
Packit 2fc92b
  int			fmtidx;		/* Format index */
Packit 2fc92b
  int			status,		/* Exit status */
Packit 2fc92b
			pass,		/* Pass/fail status */
Packit 2fc92b
			untranslated;	/* Untranslated messages */
Packit 2fc92b
  char			idbuf[80],	/* Abbreviated msgid */
Packit 2fc92b
			strbuf[80];	/* Abbreviated msgstr */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  if (argc < 2)
Packit 2fc92b
  {
Packit 2fc92b
    puts("Usage: checkpo filename.{po,strings} [... filenameN.{po,strings}]");
Packit 2fc92b
    return (1);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Check every .po or .strings file on the command-line...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  for (i = 1, status = 0; i < argc; i ++)
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Use the CUPS .po loader to get the message strings...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    if (strstr(argv[i], ".strings"))
Packit 2fc92b
      po = cups_load_strings(argv[i]);
Packit 2fc92b
    else
Packit 2fc92b
      po = _cupsMessageLoad(argv[i], 1);
Packit 2fc92b
Packit 2fc92b
    if (!po)
Packit 2fc92b
    {
Packit 2fc92b
      perror(argv[i]);
Packit 2fc92b
      return (1);
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    if (i > 1)
Packit 2fc92b
      putchar('\n');
Packit 2fc92b
    printf("%s: ", argv[i]);
Packit 2fc92b
    fflush(stdout);
Packit 2fc92b
Packit 2fc92b
   /*
Packit 2fc92b
    * Scan every message for a % string and then match them up with
Packit 2fc92b
    * the corresponding string in the translation...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    pass         = 1;
Packit 2fc92b
    untranslated = 0;
Packit 2fc92b
Packit 2fc92b
    for (msg = (_cups_message_t *)cupsArrayFirst(po);
Packit 2fc92b
         msg;
Packit 2fc92b
	 msg = (_cups_message_t *)cupsArrayNext(po))
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Make sure filter message prefixes are not translated...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      if (!strncmp(msg->id, "ALERT:", 6) || !strncmp(msg->id, "CRIT:", 5) ||
Packit 2fc92b
          !strncmp(msg->id, "DEBUG:", 6) || !strncmp(msg->id, "DEBUG2:", 7) ||
Packit 2fc92b
          !strncmp(msg->id, "EMERG:", 6) || !strncmp(msg->id, "ERROR:", 6) ||
Packit 2fc92b
          !strncmp(msg->id, "INFO:", 5) || !strncmp(msg->id, "NOTICE:", 7) ||
Packit 2fc92b
          !strncmp(msg->id, "WARNING:", 8))
Packit 2fc92b
      {
Packit 2fc92b
        if (pass)
Packit 2fc92b
	{
Packit 2fc92b
	  pass = 0;
Packit 2fc92b
	  puts("FAIL");
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
	printf("    Bad prefix on filter message \"%s\"\n",
Packit 2fc92b
	       abbreviate(msg->id, idbuf, sizeof(idbuf)));
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
      idfmt = msg->id + strlen(msg->id) - 1;
Packit 2fc92b
      if (idfmt >= msg->id && *idfmt == '\n')
Packit 2fc92b
      {
Packit 2fc92b
        if (pass)
Packit 2fc92b
	{
Packit 2fc92b
	  pass = 0;
Packit 2fc92b
	  puts("FAIL");
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
	printf("    Trailing newline in message \"%s\"\n",
Packit 2fc92b
	       abbreviate(msg->id, idbuf, sizeof(idbuf)));
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
      for (; idfmt >= msg->id; idfmt --)
Packit 2fc92b
        if (!isspace(*idfmt & 255))
Packit 2fc92b
	  break;
Packit 2fc92b
Packit 2fc92b
      if (idfmt >= msg->id && *idfmt == '!')
Packit 2fc92b
      {
Packit 2fc92b
        if (pass)
Packit 2fc92b
	{
Packit 2fc92b
	  pass = 0;
Packit 2fc92b
	  puts("FAIL");
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
	printf("    Exclamation in message \"%s\"\n",
Packit 2fc92b
	       abbreviate(msg->id, idbuf, sizeof(idbuf)));
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
      if ((idfmt - 2) >= msg->id && !strncmp(idfmt - 2, "...", 3))
Packit 2fc92b
      {
Packit 2fc92b
        if (pass)
Packit 2fc92b
	{
Packit 2fc92b
	  pass = 0;
Packit 2fc92b
	  puts("FAIL");
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
	printf("    Ellipsis in message \"%s\"\n",
Packit 2fc92b
	       abbreviate(msg->id, idbuf, sizeof(idbuf)));
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
      if (!msg->str || !msg->str[0])
Packit 2fc92b
      {
Packit 2fc92b
        untranslated ++;
Packit 2fc92b
	continue;
Packit 2fc92b
      }
Packit 2fc92b
      else if (strchr(msg->id, '%'))
Packit 2fc92b
      {
Packit 2fc92b
        idfmts  = collect_formats(msg->id);
Packit 2fc92b
	strfmts = collect_formats(msg->str);
Packit 2fc92b
	fmtidx  = 0;
Packit 2fc92b
Packit 2fc92b
        for (strfmt = (char *)cupsArrayFirst(strfmts);
Packit 2fc92b
	     strfmt;
Packit 2fc92b
	     strfmt = (char *)cupsArrayNext(strfmts))
Packit 2fc92b
	{
Packit 2fc92b
	  if (isdigit(strfmt[1] & 255) && strfmt[2] == '$')
Packit 2fc92b
	  {
Packit 2fc92b
	   /*
Packit 2fc92b
	    * Handle positioned format stuff...
Packit 2fc92b
	    */
Packit 2fc92b
Packit 2fc92b
            fmtidx = strfmt[1] - '1';
Packit 2fc92b
            strfmt += 3;
Packit 2fc92b
	    if ((idfmt = (char *)cupsArrayIndex(idfmts, fmtidx)) != NULL)
Packit 2fc92b
	      idfmt ++;
Packit 2fc92b
	  }
Packit 2fc92b
	  else
Packit 2fc92b
	  {
Packit 2fc92b
	   /*
Packit 2fc92b
	    * Compare against the current format...
Packit 2fc92b
	    */
Packit 2fc92b
Packit 2fc92b
	    idfmt = (char *)cupsArrayIndex(idfmts, fmtidx);
Packit 2fc92b
          }
Packit 2fc92b
Packit 2fc92b
	  fmtidx ++;
Packit 2fc92b
Packit 2fc92b
	  if (!idfmt || strcmp(strfmt, idfmt))
Packit 2fc92b
	    break;
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
        if (cupsArrayCount(strfmts) != cupsArrayCount(idfmts) || strfmt)
Packit 2fc92b
	{
Packit 2fc92b
	  if (pass)
Packit 2fc92b
	  {
Packit 2fc92b
	    pass = 0;
Packit 2fc92b
	    puts("FAIL");
Packit 2fc92b
	  }
Packit 2fc92b
Packit 2fc92b
	  printf("    Bad translation string \"%s\"\n        for \"%s\"\n",
Packit 2fc92b
	         abbreviate(msg->str, strbuf, sizeof(strbuf)),
Packit 2fc92b
		 abbreviate(msg->id, idbuf, sizeof(idbuf)));
Packit 2fc92b
          fputs("    Translation formats:", stdout);
Packit 2fc92b
	  for (strfmt = (char *)cupsArrayFirst(strfmts);
Packit 2fc92b
	       strfmt;
Packit 2fc92b
	       strfmt = (char *)cupsArrayNext(strfmts))
Packit 2fc92b
	    printf(" %s", strfmt);
Packit 2fc92b
          fputs("\n    Original formats:", stdout);
Packit 2fc92b
	  for (idfmt = (char *)cupsArrayFirst(idfmts);
Packit 2fc92b
	       idfmt;
Packit 2fc92b
	       idfmt = (char *)cupsArrayNext(idfmts))
Packit 2fc92b
	    printf(" %s", idfmt);
Packit 2fc92b
          putchar('\n');
Packit 2fc92b
          putchar('\n');
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
	free_formats(idfmts);
Packit 2fc92b
	free_formats(strfmts);
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * Only allow \\, \n, \r, \t, \", and \### character escapes...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      for (strfmt = msg->str; *strfmt; strfmt ++)
Packit 2fc92b
        if (*strfmt == '\\' &&
Packit 2fc92b
	    strfmt[1] != '\\' && strfmt[1] != 'n' && strfmt[1] != 'r' &&
Packit 2fc92b
	    strfmt[1] != 't' && strfmt[1] != '\"' && !isdigit(strfmt[1] & 255))
Packit 2fc92b
	{
Packit 2fc92b
	  if (pass)
Packit 2fc92b
	  {
Packit 2fc92b
	    pass = 0;
Packit 2fc92b
	    puts("FAIL");
Packit 2fc92b
	  }
Packit 2fc92b
Packit 2fc92b
	  printf("    Bad escape \\%c in filter message \"%s\"\n"
Packit 2fc92b
	         "      for \"%s\"\n", strfmt[1],
Packit 2fc92b
		 abbreviate(msg->str, strbuf, sizeof(strbuf)),
Packit 2fc92b
		 abbreviate(msg->id, idbuf, sizeof(idbuf)));
Packit 2fc92b
          break;
Packit 2fc92b
        }
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    if (pass)
Packit 2fc92b
    {
Packit 2fc92b
      if ((untranslated * 10) >= cupsArrayCount(po) &&
Packit 2fc92b
          strcmp(argv[i], "cups.pot"))
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
        * Only allow 10% of messages to be untranslated before we fail...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
        pass = 0;
Packit 2fc92b
        puts("FAIL");
Packit 2fc92b
	printf("    Too many untranslated messages (%d of %d)\n",
Packit 2fc92b
	       untranslated, cupsArrayCount(po));
Packit 2fc92b
      }
Packit 2fc92b
      else if (untranslated > 0)
Packit 2fc92b
        printf("PASS (%d of %d untranslated)\n", untranslated,
Packit 2fc92b
	       cupsArrayCount(po));
Packit 2fc92b
      else
Packit 2fc92b
        puts("PASS");
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    if (!pass)
Packit 2fc92b
      status = 1;
Packit 2fc92b
Packit 2fc92b
    _cupsMessageFree(po);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  return (status);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'abbreviate()' - Abbreviate a message string as needed.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static char *				/* O - Abbreviated string */
Packit 2fc92b
abbreviate(const char *s,		/* I - String to abbreviate */
Packit 2fc92b
           char       *buf,		/* I - Buffer */
Packit 2fc92b
	   int        bufsize)		/* I - Size of buffer */
Packit 2fc92b
{
Packit 2fc92b
  char	*bufptr;			/* Pointer into buffer */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  for (bufptr = buf, bufsize -= 4; *s && bufsize > 0; s ++)
Packit 2fc92b
  {
Packit 2fc92b
    if (*s == '\n')
Packit 2fc92b
    {
Packit 2fc92b
      if (bufsize < 2)
Packit 2fc92b
        break;
Packit 2fc92b
Packit 2fc92b
      *bufptr++ = '\\';
Packit 2fc92b
      *bufptr++ = 'n';
Packit 2fc92b
      bufsize -= 2;
Packit 2fc92b
    }
Packit 2fc92b
    else if (*s == '\t')
Packit 2fc92b
    {
Packit 2fc92b
      if (bufsize < 2)
Packit 2fc92b
        break;
Packit 2fc92b
Packit 2fc92b
      *bufptr++ = '\\';
Packit 2fc92b
      *bufptr++ = 't';
Packit 2fc92b
      bufsize -= 2;
Packit 2fc92b
    }
Packit 2fc92b
    else if (*s >= 0 && *s < ' ')
Packit 2fc92b
    {
Packit 2fc92b
      if (bufsize < 4)
Packit 2fc92b
        break;
Packit 2fc92b
Packit 2fc92b
      sprintf(bufptr, "\\%03o", *s);
Packit 2fc92b
      bufptr += 4;
Packit 2fc92b
      bufsize -= 4;
Packit 2fc92b
    }
Packit 2fc92b
    else
Packit 2fc92b
    {
Packit 2fc92b
      *bufptr++ = *s;
Packit 2fc92b
      bufsize --;
Packit 2fc92b
    }
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (*s)
Packit 2fc92b
    memcpy(bufptr, "...", 4);
Packit 2fc92b
  else
Packit 2fc92b
    *bufptr = '\0';
Packit 2fc92b
Packit 2fc92b
  return (buf);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'collect_formats()' - Collect all of the format strings in the msgid.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static cups_array_t *			/* O - Array of format strings */
Packit 2fc92b
collect_formats(const char *id)		/* I - msgid string */
Packit 2fc92b
{
Packit 2fc92b
  cups_array_t	*fmts;			/* Array of format strings */
Packit 2fc92b
  char		buf[255],		/* Format string buffer */
Packit 2fc92b
		*bufptr;		/* Pointer into format string */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  fmts = cupsArrayNew(NULL, NULL);
Packit 2fc92b
Packit 2fc92b
  while ((id = strchr(id, '%')) != NULL)
Packit 2fc92b
  {
Packit 2fc92b
    if (id[1] == '%')
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Skip %%...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      id += 2;
Packit 2fc92b
      continue;
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    for (bufptr = buf; *id && bufptr < (buf + sizeof(buf) - 1); id ++)
Packit 2fc92b
    {
Packit 2fc92b
      *bufptr++ = *id;
Packit 2fc92b
Packit 2fc92b
      if (strchr("CDEFGIOSUXcdeifgopsux", *id))
Packit 2fc92b
      {
Packit 2fc92b
        id ++;
Packit 2fc92b
        break;
Packit 2fc92b
      }
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    *bufptr = '\0';
Packit 2fc92b
    cupsArrayAdd(fmts, strdup(buf));
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  return (fmts);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cups_load_strings()' - Load a .strings file into a _cups_msg_t array.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static cups_array_t *                   /* O - CUPS array of _cups_msg_t values */
Packit 2fc92b
cups_load_strings(const char *filename) /* I - File to load */
Packit 2fc92b
{
Packit 2fc92b
  cups_file_t     *fp;                  /* .strings file */
Packit 2fc92b
  cups_array_t    *po;                  /* Localization array */
Packit 2fc92b
  _cups_message_t *m;                   /* Localization message */
Packit 2fc92b
  char		  buffer[8192],	        /* Message buffer */
Packit 2fc92b
                  *id,		        /* ID string */
Packit 2fc92b
                  *str;		        /* Translated message */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  if ((fp = cupsFileOpen(filename, "r")) == NULL)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  po = _cupsMessageNew(NULL);
Packit 2fc92b
Packit 2fc92b
  while (cups_read_strings(fp, buffer, sizeof(buffer), &id, &str))
Packit 2fc92b
  {
Packit 2fc92b
    if ((m = malloc(sizeof(_cups_message_t))) == NULL)
Packit 2fc92b
      break;
Packit 2fc92b
Packit 2fc92b
    m->id  = strdup(id);
Packit 2fc92b
    m->str = strdup(str);
Packit 2fc92b
Packit 2fc92b
    if (m->id && m->str)
Packit 2fc92b
      cupsArrayAdd(po, m);
Packit 2fc92b
    else
Packit 2fc92b
    {
Packit 2fc92b
      if (m->id)
Packit 2fc92b
        free(m->id);
Packit 2fc92b
Packit 2fc92b
      if (m->str)
Packit 2fc92b
        free(m->str);
Packit 2fc92b
Packit 2fc92b
      free(m);
Packit 2fc92b
Packit 2fc92b
      cupsArrayDelete(po);
Packit 2fc92b
      po = NULL;
Packit 2fc92b
      break;
Packit 2fc92b
    }
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  cupsFileClose(fp);
Packit 2fc92b
Packit 2fc92b
  return (po);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cups_read_strings()' - Read a pair of strings from a .strings file.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static int				/* O - 1 on success, 0 on failure */
Packit 2fc92b
cups_read_strings(cups_file_t *strings,	/* I - .strings file */
Packit 2fc92b
                  char        *buffer,	/* I - Line buffer */
Packit 2fc92b
                  size_t      bufsize,	/* I - Size of line buffer */
Packit 2fc92b
		  char        **id,	/* O - Pointer to ID string */
Packit 2fc92b
		  char        **str)	/* O - Pointer to translation string */
Packit 2fc92b
{
Packit 2fc92b
  char	*bufptr;			/* Pointer into buffer */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  while (cupsFileGets(strings, buffer, bufsize))
Packit 2fc92b
  {
Packit 2fc92b
    if (buffer[0] != '\"')
Packit 2fc92b
      continue;
Packit 2fc92b
Packit 2fc92b
    *id    = buffer + 1;
Packit 2fc92b
    bufptr = cups_scan_strings(buffer);
Packit 2fc92b
Packit 2fc92b
    if (*bufptr != '\"')
Packit 2fc92b
      continue;
Packit 2fc92b
Packit 2fc92b
    *bufptr++ = '\0';
Packit 2fc92b
Packit 2fc92b
    while (*bufptr && *bufptr != '\"')
Packit 2fc92b
      bufptr ++;
Packit 2fc92b
Packit 2fc92b
    if (!*bufptr)
Packit 2fc92b
      continue;
Packit 2fc92b
Packit 2fc92b
    *str   = bufptr + 1;
Packit 2fc92b
    bufptr = cups_scan_strings(bufptr);
Packit 2fc92b
Packit 2fc92b
    if (*bufptr != '\"')
Packit 2fc92b
      continue;
Packit 2fc92b
Packit 2fc92b
    *bufptr = '\0';
Packit 2fc92b
Packit 2fc92b
    return (1);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  return (0);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cups_scan_strings()' - Scan a quoted string.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static char *				/* O - End of string */
Packit 2fc92b
cups_scan_strings(char *buffer)		/* I - Start of string */
Packit 2fc92b
{
Packit 2fc92b
  char	*bufptr;			/* Pointer into string */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  for (bufptr = buffer + 1; *bufptr && *bufptr != '\"'; bufptr ++)
Packit 2fc92b
  {
Packit 2fc92b
    if (*bufptr == '\\')
Packit 2fc92b
    {
Packit 2fc92b
      if (bufptr[1] >= '0' && bufptr[1] <= '3' &&
Packit 2fc92b
	  bufptr[2] >= '0' && bufptr[2] <= '7' &&
Packit 2fc92b
	  bufptr[3] >= '0' && bufptr[3] <= '7')
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
	* Decode \nnn octal escape...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
	*bufptr = (char)(((((bufptr[1] - '0') << 3) | (bufptr[2] - '0')) << 3) | (bufptr[3] - '0'));
Packit 2fc92b
	_cups_strcpy(bufptr + 1, bufptr + 4);
Packit 2fc92b
      }
Packit 2fc92b
      else
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
	* Decode \C escape...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
	_cups_strcpy(bufptr, bufptr + 1);
Packit 2fc92b
	if (*bufptr == 'n')
Packit 2fc92b
	  *bufptr = '\n';
Packit 2fc92b
	else if (*bufptr == 'r')
Packit 2fc92b
	  *bufptr = '\r';
Packit 2fc92b
	else if (*bufptr == 't')
Packit 2fc92b
	  *bufptr = '\t';
Packit 2fc92b
      }
Packit 2fc92b
    }
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  return (bufptr);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'free_formats()' - Free all of the format strings.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void
Packit 2fc92b
free_formats(cups_array_t *fmts)	/* I - Array of format strings */
Packit 2fc92b
{
Packit 2fc92b
  char	*s;				/* Current string */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  for (s = (char *)cupsArrayFirst(fmts); s; s = (char *)cupsArrayNext(fmts))
Packit 2fc92b
    free(s);
Packit 2fc92b
Packit 2fc92b
  cupsArrayDelete(fmts);
Packit 2fc92b
}