Blame gettext-tools/src/format-python.c

Packit Bot 06c835
/* Python format strings.
Packit Bot 06c835
   Copyright (C) 2001-2004, 2006-2009, 2015 Free Software Foundation,
Packit Bot 06c835
   Inc.
Packit Bot 06c835
   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
Packit Bot 06c835
Packit Bot 06c835
   This program is free software: you can redistribute it and/or modify
Packit Bot 06c835
   it under the terms of the GNU General Public License as published by
Packit Bot 06c835
   the Free Software Foundation; either version 3 of the License, or
Packit Bot 06c835
   (at your option) any later version.
Packit Bot 06c835
Packit Bot 06c835
   This program is distributed in the hope that it will be useful,
Packit Bot 06c835
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Bot 06c835
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Bot 06c835
   GNU General Public License for more details.
Packit Bot 06c835
Packit Bot 06c835
   You should have received a copy of the GNU General Public License
Packit Bot 06c835
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Bot 06c835
Packit Bot 06c835
#ifdef HAVE_CONFIG_H
Packit Bot 06c835
# include <config.h>
Packit Bot 06c835
#endif
Packit Bot 06c835
Packit Bot 06c835
#include <stdbool.h>
Packit Bot 06c835
#include <stdlib.h>
Packit Bot 06c835
#include <string.h>
Packit Bot 06c835
Packit Bot 06c835
#include "format.h"
Packit Bot 06c835
#include "c-ctype.h"
Packit Bot 06c835
#include "xalloc.h"
Packit Bot 06c835
#include "xvasprintf.h"
Packit Bot 06c835
#include "format-invalid.h"
Packit Bot 06c835
#include "gettext.h"
Packit Bot 06c835
Packit Bot 06c835
#define _(str) gettext (str)
Packit Bot 06c835
Packit Bot 06c835
/* Python format strings are described in
Packit Bot 06c835
     Python Library reference
Packit Bot 06c835
     2. Built-in Types, Exceptions and Functions
Packit Bot 06c835
     2.1. Built-in Types
Packit Bot 06c835
     2.1.5. Sequence Types
Packit Bot 06c835
     2.1.5.2. String Formatting Operations
Packit Bot 06c835
   Any string or Unicode string can act as format string via the '%' operator,
Packit Bot 06c835
   implemented in stringobject.c and unicodeobject.c.
Packit Bot 06c835
   A directive
Packit Bot 06c835
   - starts with '%'
Packit Bot 06c835
   - is optionally followed by '(ident)' where ident is any sequence of
Packit Bot 06c835
     characters with balanced left and right parentheses,
Packit Bot 06c835
   - is optionally followed by any of the characters '-' (left justification),
Packit Bot 06c835
     '+' (sign), ' ' (blank), '#' (alt), '0' (zero), each of which acts as a
Packit Bot 06c835
     flag,
Packit Bot 06c835
   - is optionally followed by a width specification: '*' (reads an argument)
Packit Bot 06c835
     or a nonempty digit sequence,
Packit Bot 06c835
   - is optionally followed by '.' and a precision specification: '*' (reads
Packit Bot 06c835
     an argument) or a nonempty digit sequence,
Packit Bot 06c835
   - is optionally followed by a size specifier, one of 'h' 'l' 'L'.
Packit Bot 06c835
   - is finished by a specifier
Packit Bot 06c835
       - '%', that needs no argument,
Packit Bot 06c835
       - 'c', that needs a character argument,
Packit Bot 06c835
       - 's', 'r', that need a string argument (or, when a precision of 0 is
Packit Bot 06c835
         given, an argument of any type),
Packit Bot 06c835
       - 'i', 'd', 'u', 'o', 'x', 'X', that need an integer argument,
Packit Bot 06c835
       - 'e', 'E', 'f', 'g', 'G', that need a floating-point argument.
Packit Bot 06c835
   Use of '(ident)' and use of unnamed argument specifications are exclusive,
Packit Bot 06c835
   because the first requires a mapping as argument, while the second requires
Packit Bot 06c835
   a tuple as argument. When unnamed arguments are used, the number of
Packit Bot 06c835
   arguments in the format string and the number of elements in the argument
Packit Bot 06c835
   tuple (to the right of the '%' operator) must be the same.
Packit Bot 06c835
 */
Packit Bot 06c835
Packit Bot 06c835
enum format_arg_type
Packit Bot 06c835
{
Packit Bot 06c835
  FAT_NONE,
Packit Bot 06c835
  FAT_ANY,
Packit Bot 06c835
  FAT_CHARACTER,
Packit Bot 06c835
  FAT_STRING,
Packit Bot 06c835
  FAT_INTEGER,
Packit Bot 06c835
  FAT_FLOAT
Packit Bot 06c835
};
Packit Bot 06c835
Packit Bot 06c835
struct named_arg
Packit Bot 06c835
{
Packit Bot 06c835
  char *name;
Packit Bot 06c835
  enum format_arg_type type;
Packit Bot 06c835
};
Packit Bot 06c835
Packit Bot 06c835
struct unnamed_arg
Packit Bot 06c835
{
Packit Bot 06c835
  enum format_arg_type type;
Packit Bot 06c835
};
Packit Bot 06c835
Packit Bot 06c835
struct spec
Packit Bot 06c835
{
Packit Bot 06c835
  unsigned int directives;
Packit Bot 06c835
  unsigned int named_arg_count;
Packit Bot 06c835
  unsigned int unnamed_arg_count;
Packit Bot 06c835
  unsigned int allocated;
Packit Bot 06c835
  struct named_arg *named;
Packit Bot 06c835
  struct unnamed_arg *unnamed;
Packit Bot 06c835
};
Packit Bot 06c835
Packit Bot 06c835
/* Locale independent test for a decimal digit.
Packit Bot 06c835
   Argument can be  'char' or 'unsigned char'.  (Whereas the argument of
Packit Bot 06c835
   <ctype.h> isdigit must be an 'unsigned char'.)  */
Packit Bot 06c835
#undef isdigit
Packit Bot 06c835
#define isdigit(c) ((unsigned int) ((c) - '0') < 10)
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
named_arg_compare (const void *p1, const void *p2)
Packit Bot 06c835
{
Packit Bot 06c835
  return strcmp (((const struct named_arg *) p1)->name,
Packit Bot 06c835
                 ((const struct named_arg *) p2)->name);
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
#define INVALID_MIXES_NAMED_UNNAMED() \
Packit Bot 06c835
  xstrdup (_("The string refers to arguments both through argument names and through unnamed argument specifications."))
Packit Bot 06c835
Packit Bot 06c835
static void *
Packit Bot 06c835
format_parse (const char *format, bool translated, char *fdi,
Packit Bot 06c835
              char **invalid_reason)
Packit Bot 06c835
{
Packit Bot 06c835
  const char *const format_start = format;
Packit Bot 06c835
  struct spec spec;
Packit Bot 06c835
  struct spec *result;
Packit Bot 06c835
Packit Bot 06c835
  spec.directives = 0;
Packit Bot 06c835
  spec.named_arg_count = 0;
Packit Bot 06c835
  spec.unnamed_arg_count = 0;
Packit Bot 06c835
  spec.allocated = 0;
Packit Bot 06c835
  spec.named = NULL;
Packit Bot 06c835
  spec.unnamed = NULL;
Packit Bot 06c835
Packit Bot 06c835
  for (; *format != '\0';)
Packit Bot 06c835
    if (*format++ == '%')
Packit Bot 06c835
      {
Packit Bot 06c835
        /* A directive.  */
Packit Bot 06c835
        char *name = NULL;
Packit Bot 06c835
        bool zero_precision = false;
Packit Bot 06c835
        enum format_arg_type type;
Packit Bot 06c835
Packit Bot 06c835
        FDI_SET (format - 1, FMTDIR_START);
Packit Bot 06c835
        spec.directives++;
Packit Bot 06c835
Packit Bot 06c835
        if (*format == '(')
Packit Bot 06c835
          {
Packit Bot 06c835
            unsigned int depth;
Packit Bot 06c835
            const char *name_start;
Packit Bot 06c835
            const char *name_end;
Packit Bot 06c835
            size_t n;
Packit Bot 06c835
Packit Bot 06c835
            name_start = ++format;
Packit Bot 06c835
            depth = 0;
Packit Bot 06c835
            for (; *format != '\0'; format++)
Packit Bot 06c835
              {
Packit Bot 06c835
                if (*format == '(')
Packit Bot 06c835
                  depth++;
Packit Bot 06c835
                else if (*format == ')')
Packit Bot 06c835
                  {
Packit Bot 06c835
                    if (depth == 0)
Packit Bot 06c835
                      break;
Packit Bot 06c835
                    else
Packit Bot 06c835
                      depth--;
Packit Bot 06c835
                  }
Packit Bot 06c835
              }
Packit Bot 06c835
            if (*format == '\0')
Packit Bot 06c835
              {
Packit Bot 06c835
                *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
Packit Bot 06c835
                FDI_SET (format - 1, FMTDIR_ERROR);
Packit Bot 06c835
                goto bad_format;
Packit Bot 06c835
              }
Packit Bot 06c835
            name_end = format++;
Packit Bot 06c835
Packit Bot 06c835
            n = name_end - name_start;
Packit Bot 06c835
            name = XNMALLOC (n + 1, char);
Packit Bot 06c835
            memcpy (name, name_start, n);
Packit Bot 06c835
            name[n] = '\0';
Packit Bot 06c835
          }
Packit Bot 06c835
Packit Bot 06c835
        while (*format == '-' || *format == '+' || *format == ' '
Packit Bot 06c835
               || *format == '#' || *format == '0')
Packit Bot 06c835
          format++;
Packit Bot 06c835
Packit Bot 06c835
        if (*format == '*')
Packit Bot 06c835
          {
Packit Bot 06c835
            format++;
Packit Bot 06c835
Packit Bot 06c835
            /* Named and unnamed specifications are exclusive.  */
Packit Bot 06c835
            if (spec.named_arg_count > 0)
Packit Bot 06c835
              {
Packit Bot 06c835
                *invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
Packit Bot 06c835
                FDI_SET (format - 1, FMTDIR_ERROR);
Packit Bot 06c835
                goto bad_format;
Packit Bot 06c835
              }
Packit Bot 06c835
Packit Bot 06c835
            if (spec.allocated == spec.unnamed_arg_count)
Packit Bot 06c835
              {
Packit Bot 06c835
                spec.allocated = 2 * spec.allocated + 1;
Packit Bot 06c835
                spec.unnamed = (struct unnamed_arg *) xrealloc (spec.unnamed, spec.allocated * sizeof (struct unnamed_arg));
Packit Bot 06c835
              }
Packit Bot 06c835
            spec.unnamed[spec.unnamed_arg_count].type = FAT_INTEGER;
Packit Bot 06c835
            spec.unnamed_arg_count++;
Packit Bot 06c835
          }
Packit Bot 06c835
        else if (isdigit (*format))
Packit Bot 06c835
          {
Packit Bot 06c835
            do format++; while (isdigit (*format));
Packit Bot 06c835
          }
Packit Bot 06c835
Packit Bot 06c835
        if (*format == '.')
Packit Bot 06c835
          {
Packit Bot 06c835
            format++;
Packit Bot 06c835
Packit Bot 06c835
            if (*format == '*')
Packit Bot 06c835
              {
Packit Bot 06c835
                format++;
Packit Bot 06c835
Packit Bot 06c835
                /* Named and unnamed specifications are exclusive.  */
Packit Bot 06c835
                if (spec.named_arg_count > 0)
Packit Bot 06c835
                  {
Packit Bot 06c835
                    *invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
Packit Bot 06c835
                    FDI_SET (format - 1, FMTDIR_ERROR);
Packit Bot 06c835
                    goto bad_format;
Packit Bot 06c835
                  }
Packit Bot 06c835
Packit Bot 06c835
                if (spec.allocated == spec.unnamed_arg_count)
Packit Bot 06c835
                  {
Packit Bot 06c835
                    spec.allocated = 2 * spec.allocated + 1;
Packit Bot 06c835
                    spec.unnamed = (struct unnamed_arg *) xrealloc (spec.unnamed, spec.allocated * sizeof (struct unnamed_arg));
Packit Bot 06c835
                  }
Packit Bot 06c835
                spec.unnamed[spec.unnamed_arg_count].type = FAT_INTEGER;
Packit Bot 06c835
                spec.unnamed_arg_count++;
Packit Bot 06c835
              }
Packit Bot 06c835
            else if (isdigit (*format))
Packit Bot 06c835
              {
Packit Bot 06c835
                zero_precision = true;
Packit Bot 06c835
                do
Packit Bot 06c835
                  {
Packit Bot 06c835
                    if (*format != '0')
Packit Bot 06c835
                      zero_precision = false;
Packit Bot 06c835
                    format++;
Packit Bot 06c835
                  }
Packit Bot 06c835
                while (isdigit (*format));
Packit Bot 06c835
              }
Packit Bot 06c835
          }
Packit Bot 06c835
Packit Bot 06c835
        if (*format == 'h' || *format == 'l' || *format == 'L')
Packit Bot 06c835
          format++;
Packit Bot 06c835
Packit Bot 06c835
        switch (*format)
Packit Bot 06c835
          {
Packit Bot 06c835
          case '%':
Packit Bot 06c835
            type = FAT_NONE;
Packit Bot 06c835
            break;
Packit Bot 06c835
          case 'c':
Packit Bot 06c835
            type = FAT_CHARACTER;
Packit Bot 06c835
            break;
Packit Bot 06c835
          case 's': case 'r':
Packit Bot 06c835
            type = (zero_precision ? FAT_ANY : FAT_STRING);
Packit Bot 06c835
            break;
Packit Bot 06c835
          case 'i': case 'd': case 'u': case 'o': case 'x': case 'X':
Packit Bot 06c835
            type = FAT_INTEGER;
Packit Bot 06c835
            break;
Packit Bot 06c835
          case 'e': case 'E': case 'f': case 'g': case 'G':
Packit Bot 06c835
            type = FAT_FLOAT;
Packit Bot 06c835
            break;
Packit Bot 06c835
          default:
Packit Bot 06c835
            if (*format == '\0')
Packit Bot 06c835
              {
Packit Bot 06c835
                *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
Packit Bot 06c835
                FDI_SET (format - 1, FMTDIR_ERROR);
Packit Bot 06c835
              }
Packit Bot 06c835
            else
Packit Bot 06c835
              {
Packit Bot 06c835
                *invalid_reason =
Packit Bot 06c835
                  INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
Packit Bot 06c835
                FDI_SET (format, FMTDIR_ERROR);
Packit Bot 06c835
              }
Packit Bot 06c835
            goto bad_format;
Packit Bot 06c835
          }
Packit Bot 06c835
Packit Bot 06c835
        if (name != NULL)
Packit Bot 06c835
          {
Packit Bot 06c835
            /* Named argument.  */
Packit Bot 06c835
Packit Bot 06c835
            /* Named and unnamed specifications are exclusive.  */
Packit Bot 06c835
            if (spec.unnamed_arg_count > 0)
Packit Bot 06c835
              {
Packit Bot 06c835
                *invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
Packit Bot 06c835
                FDI_SET (format, FMTDIR_ERROR);
Packit Bot 06c835
                goto bad_format;
Packit Bot 06c835
              }
Packit Bot 06c835
Packit Bot 06c835
            if (spec.allocated == spec.named_arg_count)
Packit Bot 06c835
              {
Packit Bot 06c835
                spec.allocated = 2 * spec.allocated + 1;
Packit Bot 06c835
                spec.named = (struct named_arg *) xrealloc (spec.named, spec.allocated * sizeof (struct named_arg));
Packit Bot 06c835
              }
Packit Bot 06c835
            spec.named[spec.named_arg_count].name = name;
Packit Bot 06c835
            spec.named[spec.named_arg_count].type = type;
Packit Bot 06c835
            spec.named_arg_count++;
Packit Bot 06c835
          }
Packit Bot 06c835
        else if (*format != '%')
Packit Bot 06c835
          {
Packit Bot 06c835
            /* Unnamed argument.  */
Packit Bot 06c835
Packit Bot 06c835
            /* Named and unnamed specifications are exclusive.  */
Packit Bot 06c835
            if (spec.named_arg_count > 0)
Packit Bot 06c835
              {
Packit Bot 06c835
                *invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
Packit Bot 06c835
                FDI_SET (format, FMTDIR_ERROR);
Packit Bot 06c835
                goto bad_format;
Packit Bot 06c835
              }
Packit Bot 06c835
Packit Bot 06c835
            if (spec.allocated == spec.unnamed_arg_count)
Packit Bot 06c835
              {
Packit Bot 06c835
                spec.allocated = 2 * spec.allocated + 1;
Packit Bot 06c835
                spec.unnamed = (struct unnamed_arg *) xrealloc (spec.unnamed, spec.allocated * sizeof (struct unnamed_arg));
Packit Bot 06c835
              }
Packit Bot 06c835
            spec.unnamed[spec.unnamed_arg_count].type = type;
Packit Bot 06c835
            spec.unnamed_arg_count++;
Packit Bot 06c835
          }
Packit Bot 06c835
Packit Bot 06c835
        FDI_SET (format, FMTDIR_END);
Packit Bot 06c835
Packit Bot 06c835
        format++;
Packit Bot 06c835
      }
Packit Bot 06c835
Packit Bot 06c835
  /* Sort the named argument array, and eliminate duplicates.  */
Packit Bot 06c835
  if (spec.named_arg_count > 1)
Packit Bot 06c835
    {
Packit Bot 06c835
      unsigned int i, j;
Packit Bot 06c835
      bool err;
Packit Bot 06c835
Packit Bot 06c835
      qsort (spec.named, spec.named_arg_count, sizeof (struct named_arg),
Packit Bot 06c835
             named_arg_compare);
Packit Bot 06c835
Packit Bot 06c835
      /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i.  */
Packit Bot 06c835
      err = false;
Packit Bot 06c835
      for (i = j = 0; i < spec.named_arg_count; i++)
Packit Bot 06c835
        if (j > 0 && strcmp (spec.named[i].name, spec.named[j-1].name) == 0)
Packit Bot 06c835
          {
Packit Bot 06c835
            enum format_arg_type type1 = spec.named[i].type;
Packit Bot 06c835
            enum format_arg_type type2 = spec.named[j-1].type;
Packit Bot 06c835
            enum format_arg_type type_both;
Packit Bot 06c835
Packit Bot 06c835
            if (type1 == type2 || type2 == FAT_ANY)
Packit Bot 06c835
              type_both = type1;
Packit Bot 06c835
            else if (type1 == FAT_ANY)
Packit Bot 06c835
              type_both = type2;
Packit Bot 06c835
            else
Packit Bot 06c835
              {
Packit Bot 06c835
                /* Incompatible types.  */
Packit Bot 06c835
                type_both = FAT_NONE;
Packit Bot 06c835
                if (!err)
Packit Bot 06c835
                  *invalid_reason =
Packit Bot 06c835
                    xasprintf (_("The string refers to the argument named '%s' in incompatible ways."), spec.named[i].name);
Packit Bot 06c835
                err = true;
Packit Bot 06c835
              }
Packit Bot 06c835
Packit Bot 06c835
            spec.named[j-1].type = type_both;
Packit Bot 06c835
            free (spec.named[i].name);
Packit Bot 06c835
          }
Packit Bot 06c835
        else
Packit Bot 06c835
          {
Packit Bot 06c835
            if (j < i)
Packit Bot 06c835
              {
Packit Bot 06c835
                spec.named[j].name = spec.named[i].name;
Packit Bot 06c835
                spec.named[j].type = spec.named[i].type;
Packit Bot 06c835
              }
Packit Bot 06c835
            j++;
Packit Bot 06c835
          }
Packit Bot 06c835
      spec.named_arg_count = j;
Packit Bot 06c835
      if (err)
Packit Bot 06c835
        /* *invalid_reason has already been set above.  */
Packit Bot 06c835
        goto bad_format;
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  result = XMALLOC (struct spec);
Packit Bot 06c835
  *result = spec;
Packit Bot 06c835
  return result;
Packit Bot 06c835
Packit Bot 06c835
 bad_format:
Packit Bot 06c835
  if (spec.named != NULL)
Packit Bot 06c835
    {
Packit Bot 06c835
      unsigned int i;
Packit Bot 06c835
      for (i = 0; i < spec.named_arg_count; i++)
Packit Bot 06c835
        free (spec.named[i].name);
Packit Bot 06c835
      free (spec.named);
Packit Bot 06c835
    }
Packit Bot 06c835
  if (spec.unnamed != NULL)
Packit Bot 06c835
    free (spec.unnamed);
Packit Bot 06c835
  return NULL;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
static void
Packit Bot 06c835
format_free (void *descr)
Packit Bot 06c835
{
Packit Bot 06c835
  struct spec *spec = (struct spec *) descr;
Packit Bot 06c835
Packit Bot 06c835
  if (spec->named != NULL)
Packit Bot 06c835
    {
Packit Bot 06c835
      unsigned int i;
Packit Bot 06c835
      for (i = 0; i < spec->named_arg_count; i++)
Packit Bot 06c835
        free (spec->named[i].name);
Packit Bot 06c835
      free (spec->named);
Packit Bot 06c835
    }
Packit Bot 06c835
  if (spec->unnamed != NULL)
Packit Bot 06c835
    free (spec->unnamed);
Packit Bot 06c835
  free (spec);
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
format_get_number_of_directives (void *descr)
Packit Bot 06c835
{
Packit Bot 06c835
  struct spec *spec = (struct spec *) descr;
Packit Bot 06c835
Packit Bot 06c835
  return spec->directives;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
static bool
Packit Bot 06c835
format_check (void *msgid_descr, void *msgstr_descr, bool equality,
Packit Bot 06c835
              formatstring_error_logger_t error_logger,
Packit Bot 06c835
              const char *pretty_msgid, const char *pretty_msgstr)
Packit Bot 06c835
{
Packit Bot 06c835
  struct spec *spec1 = (struct spec *) msgid_descr;
Packit Bot 06c835
  struct spec *spec2 = (struct spec *) msgstr_descr;
Packit Bot 06c835
  bool err = false;
Packit Bot 06c835
Packit Bot 06c835
  if (spec1->named_arg_count > 0 && spec2->unnamed_arg_count > 0)
Packit Bot 06c835
    {
Packit Bot 06c835
      if (error_logger)
Packit Bot 06c835
        error_logger (_("format specifications in '%s' expect a mapping, those in '%s' expect a tuple"),
Packit Bot 06c835
                      pretty_msgid, pretty_msgstr);
Packit Bot 06c835
      err = true;
Packit Bot 06c835
    }
Packit Bot 06c835
  else if (spec1->unnamed_arg_count > 0 && spec2->named_arg_count > 0)
Packit Bot 06c835
    {
Packit Bot 06c835
      if (error_logger)
Packit Bot 06c835
        error_logger (_("format specifications in '%s' expect a tuple, those in '%s' expect a mapping"),
Packit Bot 06c835
                      pretty_msgid, pretty_msgstr);
Packit Bot 06c835
      err = true;
Packit Bot 06c835
    }
Packit Bot 06c835
  else
Packit Bot 06c835
    {
Packit Bot 06c835
      if (spec1->named_arg_count + spec2->named_arg_count > 0)
Packit Bot 06c835
        {
Packit Bot 06c835
          unsigned int i, j;
Packit Bot 06c835
          unsigned int n1 = spec1->named_arg_count;
Packit Bot 06c835
          unsigned int n2 = spec2->named_arg_count;
Packit Bot 06c835
Packit Bot 06c835
          /* Check the argument names are the same.
Packit Bot 06c835
             Both arrays are sorted.  We search for the first difference.  */
Packit Bot 06c835
          for (i = 0, j = 0; i < n1 || j < n2; )
Packit Bot 06c835
            {
Packit Bot 06c835
              int cmp = (i >= n1 ? 1 :
Packit Bot 06c835
                         j >= n2 ? -1 :
Packit Bot 06c835
                         strcmp (spec1->named[i].name, spec2->named[j].name));
Packit Bot 06c835
Packit Bot 06c835
              if (cmp > 0)
Packit Bot 06c835
                {
Packit Bot 06c835
                  if (error_logger)
Packit Bot 06c835
                    error_logger (_("a format specification for argument '%s', as in '%s', doesn't exist in '%s'"),
Packit Bot 06c835
                                  spec2->named[j].name, pretty_msgstr,
Packit Bot 06c835
                                  pretty_msgid);
Packit Bot 06c835
                  err = true;
Packit Bot 06c835
                  break;
Packit Bot 06c835
                }
Packit Bot 06c835
              else if (cmp < 0)
Packit Bot 06c835
                {
Packit Bot 06c835
                  if (equality)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      if (error_logger)
Packit Bot 06c835
                        error_logger (_("a format specification for argument '%s' doesn't exist in '%s'"),
Packit Bot 06c835
                                      spec1->named[i].name, pretty_msgstr);
Packit Bot 06c835
                      err = true;
Packit Bot 06c835
                      break;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  else
Packit Bot 06c835
                    i++;
Packit Bot 06c835
                }
Packit Bot 06c835
              else
Packit Bot 06c835
                j++, i++;
Packit Bot 06c835
            }
Packit Bot 06c835
          /* Check the argument types are the same.  */
Packit Bot 06c835
          if (!err)
Packit Bot 06c835
            for (i = 0, j = 0; j < n2; )
Packit Bot 06c835
              {
Packit Bot 06c835
                if (strcmp (spec1->named[i].name, spec2->named[j].name) == 0)
Packit Bot 06c835
                  {
Packit Bot 06c835
                    if (!(spec1->named[i].type == spec2->named[j].type
Packit Bot 06c835
                          || (!equality
Packit Bot 06c835
                              && (spec1->named[i].type == FAT_ANY
Packit Bot 06c835
                                  || spec2->named[j].type == FAT_ANY))))
Packit Bot 06c835
                      {
Packit Bot 06c835
                        if (error_logger)
Packit Bot 06c835
                          error_logger (_("format specifications in '%s' and '%s' for argument '%s' are not the same"),
Packit Bot 06c835
                                        pretty_msgid, pretty_msgstr,
Packit Bot 06c835
                                        spec2->named[j].name);
Packit Bot 06c835
                        err = true;
Packit Bot 06c835
                        break;
Packit Bot 06c835
                      }
Packit Bot 06c835
                    j++, i++;
Packit Bot 06c835
                  }
Packit Bot 06c835
                else
Packit Bot 06c835
                  i++;
Packit Bot 06c835
              }
Packit Bot 06c835
        }
Packit Bot 06c835
Packit Bot 06c835
      if (spec1->unnamed_arg_count + spec2->unnamed_arg_count > 0)
Packit Bot 06c835
        {
Packit Bot 06c835
          unsigned int i;
Packit Bot 06c835
Packit Bot 06c835
          /* Check the argument types are the same.  */
Packit Bot 06c835
          if (spec1->unnamed_arg_count != spec2->unnamed_arg_count)
Packit Bot 06c835
            {
Packit Bot 06c835
              if (error_logger)
Packit Bot 06c835
                error_logger (_("number of format specifications in '%s' and '%s' does not match"),
Packit Bot 06c835
                              pretty_msgid, pretty_msgstr);
Packit Bot 06c835
              err = true;
Packit Bot 06c835
            }
Packit Bot 06c835
          else
Packit Bot 06c835
            for (i = 0; i < spec2->unnamed_arg_count; i++)
Packit Bot 06c835
              if (!(spec1->unnamed[i].type == spec2->unnamed[i].type
Packit Bot 06c835
                    || (!equality
Packit Bot 06c835
                        && (spec1->unnamed[i].type == FAT_ANY
Packit Bot 06c835
                            || spec2->unnamed[i].type == FAT_ANY))))
Packit Bot 06c835
                {
Packit Bot 06c835
                  if (error_logger)
Packit Bot 06c835
                    error_logger (_("format specifications in '%s' and '%s' for argument %u are not the same"),
Packit Bot 06c835
                                  pretty_msgid, pretty_msgstr, i + 1);
Packit Bot 06c835
                  err = true;
Packit Bot 06c835
                }
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  return err;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
struct formatstring_parser formatstring_python =
Packit Bot 06c835
{
Packit Bot 06c835
  format_parse,
Packit Bot 06c835
  format_free,
Packit Bot 06c835
  format_get_number_of_directives,
Packit Bot 06c835
  NULL,
Packit Bot 06c835
  format_check
Packit Bot 06c835
};
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
unsigned int
Packit Bot 06c835
get_python_format_unnamed_arg_count (const char *string)
Packit Bot 06c835
{
Packit Bot 06c835
  /* Parse the format string.  */
Packit Bot 06c835
  char *invalid_reason = NULL;
Packit Bot 06c835
  struct spec *descr =
Packit Bot 06c835
    (struct spec *) format_parse (string, false, NULL, &invalid_reason);
Packit Bot 06c835
Packit Bot 06c835
  if (descr != NULL)
Packit Bot 06c835
    {
Packit Bot 06c835
      unsigned int result = descr->unnamed_arg_count;
Packit Bot 06c835
Packit Bot 06c835
      format_free (descr);
Packit Bot 06c835
      return result;
Packit Bot 06c835
    }
Packit Bot 06c835
  else
Packit Bot 06c835
    {
Packit Bot 06c835
      free (invalid_reason);
Packit Bot 06c835
      return 0;
Packit Bot 06c835
    }
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
#ifdef TEST
Packit Bot 06c835
Packit Bot 06c835
/* Test program: Print the argument list specification returned by
Packit Bot 06c835
   format_parse for strings read from standard input.  */
Packit Bot 06c835
Packit Bot 06c835
#include <stdio.h>
Packit Bot 06c835
Packit Bot 06c835
static void
Packit Bot 06c835
format_print (void *descr)
Packit Bot 06c835
{
Packit Bot 06c835
  struct spec *spec = (struct spec *) descr;
Packit Bot 06c835
  unsigned int i;
Packit Bot 06c835
Packit Bot 06c835
  if (spec == NULL)
Packit Bot 06c835
    {
Packit Bot 06c835
      printf ("INVALID");
Packit Bot 06c835
      return;
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  if (spec->named_arg_count > 0)
Packit Bot 06c835
    {
Packit Bot 06c835
      if (spec->unnamed_arg_count > 0)
Packit Bot 06c835
        abort ();
Packit Bot 06c835
Packit Bot 06c835
      printf ("{");
Packit Bot 06c835
      for (i = 0; i < spec->named_arg_count; i++)
Packit Bot 06c835
        {
Packit Bot 06c835
          if (i > 0)
Packit Bot 06c835
            printf (", ");
Packit Bot 06c835
          printf ("'%s':", spec->named[i].name);
Packit Bot 06c835
          switch (spec->named[i].type)
Packit Bot 06c835
            {
Packit Bot 06c835
            case FAT_ANY:
Packit Bot 06c835
              printf ("*");
Packit Bot 06c835
              break;
Packit Bot 06c835
            case FAT_CHARACTER:
Packit Bot 06c835
              printf ("c");
Packit Bot 06c835
              break;
Packit Bot 06c835
            case FAT_STRING:
Packit Bot 06c835
              printf ("s");
Packit Bot 06c835
              break;
Packit Bot 06c835
            case FAT_INTEGER:
Packit Bot 06c835
              printf ("i");
Packit Bot 06c835
              break;
Packit Bot 06c835
            case FAT_FLOAT:
Packit Bot 06c835
              printf ("f");
Packit Bot 06c835
              break;
Packit Bot 06c835
            default:
Packit Bot 06c835
              abort ();
Packit Bot 06c835
            }
Packit Bot 06c835
        }
Packit Bot 06c835
      printf ("}");
Packit Bot 06c835
    }
Packit Bot 06c835
  else
Packit Bot 06c835
    {
Packit Bot 06c835
      printf ("(");
Packit Bot 06c835
      for (i = 0; i < spec->unnamed_arg_count; i++)
Packit Bot 06c835
        {
Packit Bot 06c835
          if (i > 0)
Packit Bot 06c835
            printf (" ");
Packit Bot 06c835
          switch (spec->unnamed[i].type)
Packit Bot 06c835
            {
Packit Bot 06c835
            case FAT_ANY:
Packit Bot 06c835
              printf ("*");
Packit Bot 06c835
              break;
Packit Bot 06c835
            case FAT_CHARACTER:
Packit Bot 06c835
              printf ("c");
Packit Bot 06c835
              break;
Packit Bot 06c835
            case FAT_STRING:
Packit Bot 06c835
              printf ("s");
Packit Bot 06c835
              break;
Packit Bot 06c835
            case FAT_INTEGER:
Packit Bot 06c835
              printf ("i");
Packit Bot 06c835
              break;
Packit Bot 06c835
            case FAT_FLOAT:
Packit Bot 06c835
              printf ("f");
Packit Bot 06c835
              break;
Packit Bot 06c835
            default:
Packit Bot 06c835
              abort ();
Packit Bot 06c835
            }
Packit Bot 06c835
        }
Packit Bot 06c835
      printf (")");
Packit Bot 06c835
    }
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
int
Packit Bot 06c835
main ()
Packit Bot 06c835
{
Packit Bot 06c835
  for (;;)
Packit Bot 06c835
    {
Packit Bot 06c835
      char *line = NULL;
Packit Bot 06c835
      size_t line_size = 0;
Packit Bot 06c835
      int line_len;
Packit Bot 06c835
      char *invalid_reason;
Packit Bot 06c835
      void *descr;
Packit Bot 06c835
Packit Bot 06c835
      line_len = getline (&line, &line_size, stdin);
Packit Bot 06c835
      if (line_len < 0)
Packit Bot 06c835
        break;
Packit Bot 06c835
      if (line_len > 0 && line[line_len - 1] == '\n')
Packit Bot 06c835
        line[--line_len] = '\0';
Packit Bot 06c835
Packit Bot 06c835
      invalid_reason = NULL;
Packit Bot 06c835
      descr = format_parse (line, false, NULL, &invalid_reason);
Packit Bot 06c835
Packit Bot 06c835
      format_print (descr);
Packit Bot 06c835
      printf ("\n");
Packit Bot 06c835
      if (descr == NULL)
Packit Bot 06c835
        printf ("%s\n", invalid_reason);
Packit Bot 06c835
Packit Bot 06c835
      free (invalid_reason);
Packit Bot 06c835
      free (line);
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  return 0;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/*
Packit Bot 06c835
 * For Emacs M-x compile
Packit Bot 06c835
 * Local Variables:
Packit Bot 06c835
 * compile-command: "/bin/sh ../libtool --tag=CC --mode=link gcc -o a.out -static -O -g -Wall -I.. -I../gnulib-lib -I../intl -DHAVE_CONFIG_H -DTEST format-python.c ../gnulib-lib/libgettextlib.la"
Packit Bot 06c835
 * End:
Packit Bot 06c835
 */
Packit Bot 06c835
Packit Bot 06c835
#endif /* TEST */