+2006-11-26 Bruno Haible <bruno@clisp.org>
+
+ * format.h (FMTDIR_START, FMTDIR_END, FMTDIR_ERROR): New enum values.
+ (FDI_SET): New macro.
+ (struct formatstring_parser): Add fdi argument to 'parse' method.
+ * format.c (check_msgid_msgstr_format): Update.
+ * format-awk.c (format_parse): Add fdi argument. Invoke FDI_SET.
+ * format-boost.c (format_parse): Likewise.
+ * format-c.c (format_parse): Add fdi argument. Invoke FDI_SET.
+ (format_c_parse, format_objc_parse): Add fdi argument.
+ (get_sysdep_c_format_directives): Update.
+ * format-csharp.c (format_parse): Add fdi argument. Invoke FDI_SET.
+ * format-elisp.c (format_parse): Likewise.
+ * format-gcc-internal.c (format_parse): Likewise.
+ * format-java.c (message_format_parse): Add fdi argument. Invoke
+ FDI_SET.
+ (choice_format_parse): Update.
+ (format_parse): Add fdi argument.
+ * format-librep.c (format_parse): Add fdi argument. Invoke FDI_SET.
+ * format-lisp.c (parse_upto): Add fdi argument. Invoke FDI_SET.
+ (format_parse): Add fdi argument.
+ * format-pascal.c (format_parse): Add fdi argument. Invoke FDI_SET.
+ * format-perl.c (format_parse): Likewise.
+ * format-perl-brace.c (format_parse): Likewise.
+ * format-php.c (format_parse): Likewise.
+ * format-python.c (format_parse): Add fdi argument. Invoke FDI_SET.
+ (get_python_format_unnamed_arg_count): Update.
+ * format-qt.c (format_parse): Add fdi argument. Invoke FDI_SET.
+ * format-scheme.c (parse_upto): Add fdi argument. Invoke FDI_SET.
+ (format_parse): Add fdi argument.
+ * format-sh.c (format_parse): Add fdi argument. Invoke FDI_SET.
+ * format-tcl.c (format_parse): Likewise.
+ * format-ycp.c (format_parse): Likewise.
+ * msgmerge.c (msgfmt_check_pair_fails): Update.
+ * read-mo.c (read_mo_file): Update.
+ * xgettext.c (set_format_flags_from_context, remember_a_message,
+ remember_a_message_plural): Update.
+
2006-11-25 Bruno Haible <bruno@clisp.org>
* message.h (message_list_copy, msgdomain_list_copy): New declarations.
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
unsigned int unnumbered_arg_count;
struct spec *result;
unsigned int number = 0;
enum format_arg_type type;
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (isdigit (*format))
if (m == 0)
{
*invalid_reason = INVALID_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
number = m;
{
*invalid_reason =
INVALID_WIDTH_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
width_number = m;
if (unnumbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
if (spec.numbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
{
*invalid_reason =
INVALID_PRECISION_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
precision_number = m;
if (unnumbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
if (spec.numbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
type = FAT_FLOAT;
break;
default:
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (spec.directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
if (unnumbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
if (spec.numbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
}
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
unsigned int unnumbered_arg_count;
struct spec *result;
if (*format++ == '%')
{
/* A directive. */
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (*format == '%')
if (m == 0) /* can happen if m overflows */
{
*invalid_reason = INVALID_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
number = m;
{
*invalid_reason =
INVALID_WIDTH_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
width_number = m;
{
*invalid_reason =
INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
{
*invalid_reason =
INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
{
*invalid_reason =
INVALID_PRECISION_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
precision_number = m;
{
*invalid_reason =
INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
{
*invalid_reason =
INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
if (*format == '\0')
{
*invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
format++;
/*FALLTHROUGH*/
default:
--format;
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (spec.directives,
- *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (spec.directives,
+ *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
if (brackets)
{
if (*format != '|')
{
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : xasprintf (_("The directive number %u starts with | but does not end with |."),
- spec.directives));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ xasprintf (_("The directive number %u starts with | but does not end with |."),
+ spec.directives);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
format++;
if (unnumbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
if (spec.numbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
}
}
}
+
+ FDI_SET (format - 1, FMTDIR_END);
}
/* Convert the unnumbered argument array to numbered arguments. */
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
static void *
format_parse (const char *format, bool translated, bool objc_extensions,
- char **invalid_reason)
+ char *fdi, char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
unsigned int numbered_arg_count;
struct numbered_arg *numbered;
format_arg_type_t type;
format_arg_type_t size;
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (isdigit (*format))
if (m == 0)
{
*invalid_reason = INVALID_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
number = m;
{
*invalid_reason =
INVALID_WIDTH_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
width_number = m;
if (spec.unnumbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
if (numbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
{
*invalid_reason =
INVALID_PRECISION_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
precision_number = m;
if (spec.unnumbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
if (numbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
if (*format != 'P')
{
*invalid_reason = INVALID_C99_MACRO (spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
goto bad_format;
}
format++;
if (*format != 'R')
{
*invalid_reason = INVALID_C99_MACRO (spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
goto bad_format;
}
format++;
if (*format != 'I')
{
*invalid_reason = INVALID_C99_MACRO (spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
goto bad_format;
}
format++;
break;
default:
*invalid_reason = INVALID_C99_MACRO (spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
goto bad_format;
}
format++;
else
{
*invalid_reason = INVALID_C99_MACRO (spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format,
+ FMTDIR_ERROR);
goto bad_format;
}
}
else
{
*invalid_reason = INVALID_C99_MACRO (spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format,
+ FMTDIR_ERROR);
goto bad_format;
}
}
else
{
*invalid_reason = INVALID_C99_MACRO (spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format,
+ FMTDIR_ERROR);
goto bad_format;
}
}
{
*invalid_reason =
xasprintf (_("In the directive number %u, the token after '<' is not followed by '>'."), spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
goto bad_format;
}
break;
other:
default:
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (spec.directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
}
if (spec.unnumbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
if (numbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
}
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
}
static void *
-format_c_parse (const char *format, bool translated, char **invalid_reason)
+format_c_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
- return format_parse (format, translated, false, invalid_reason);
+ return format_parse (format, translated, false, fdi, invalid_reason);
}
static void *
-format_objc_parse (const char *format, bool translated, char **invalid_reason)
+format_objc_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
- return format_parse (format, translated, true, invalid_reason);
+ return format_parse (format, translated, true, fdi, invalid_reason);
}
static void
particular language.) */
char *invalid_reason = NULL;
struct spec *descr =
- (struct spec *) format_parse (string, translated, true, &invalid_reason);
+ (struct spec *)
+ format_parse (string, translated, true, NULL, &invalid_reason);
if (descr != NULL && descr->sysdep_directives_count > 0)
{
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_c_parse (line, false, &invalid_reason);
+ descr = format_c_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
};
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
struct spec *result;
if (c == '{')
{
+ FDI_SET (format - 1, FMTDIR_START);
if (*format == '{')
format++;
else
{
*invalid_reason =
xasprintf (_("In the directive number %u, '{' is not followed by an argument number."), spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
return NULL;
}
number = 0;
{
*invalid_reason =
xasprintf (_("In the directive number %u, ',' is not followed by a number."), spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format,
+ FMTDIR_ERROR);
return NULL;
}
do
{
*invalid_reason =
xstrdup (_("The string ends in the middle of a directive: found '{' without matching '}'."));
+ FDI_SET (format - 1, FMTDIR_ERROR);
return NULL;
}
(c_isprint (*format)
? xasprintf (_("The directive number %u ends with an invalid character '%c' instead of '}'."), spec.directives, *format)
: xasprintf (_("The directive number %u ends with an invalid character instead of '}'."), spec.directives));
+ FDI_SET (format, FMTDIR_ERROR);
return NULL;
}
if (spec.numbered_arg_count <= number)
spec.numbered_arg_count = number + 1;
}
+ FDI_SET (format - 1, FMTDIR_END);
}
else if (c == '}')
{
+ FDI_SET (format - 1, FMTDIR_START);
if (*format == '}')
format++;
else
(spec.directives == 0
? xstrdup (_("The string starts in the middle of a directive: found '}' without matching '{'."))
: xasprintf (_("The string contains a lone '}' after directive number %u."), spec.directives));
+ FDI_SET (*format == '\0' ? format - 1 : format, FMTDIR_ERROR);
return NULL;
}
+ FDI_SET (format - 1, FMTDIR_END);
}
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
struct spec *result;
unsigned int number;
/* A directive. */
enum format_arg_type type;
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (isdigit (*format))
type = FAT_OBJECT;
break;
default:
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (spec.directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
number++;
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
unsigned int unnumbered_arg_count;
struct spec *result;
if (*format++ == '%')
{
/* A directive. */
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (*format == '%' || *format == '<' || *format == '>'
if (m == 0)
{
*invalid_reason = INVALID_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
number = m;
continue;
invalid_flags:
*invalid_reason = xasprintf (_("In the directive number %u, the flags combination is invalid."), spec.directives);
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
default:
break;
if (*format != 's')
{
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : xasprintf (_("In the directive number %u, a precision is not allowed before '%c'."), spec.directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ xasprintf (_("In the directive number %u, a precision is not allowed before '%c'."), spec.directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
if (m == 0)
{
*invalid_reason = INVALID_WIDTH_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
if (unnumbered_arg_count > 0 || number == 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
if (m != number - 1)
{
*invalid_reason = xasprintf (_("In the directive number %u, the argument number for the precision must be equal to %u."), spec.directives, number - 1);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
precision_number = m;
if (unnumbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
if (spec.numbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
type = FAT_STRING;
else
{
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : xasprintf (_("In the directive number %u, a precision is not allowed before '%c'."), spec.directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ xasprintf (_("In the directive number %u, a precision is not allowed before '%c'."), spec.directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
}
else
{
*invalid_reason = xasprintf (_("In the directive number %u, the precision specification is invalid."), spec.directives);
+ FDI_SET (*format == '\0' ? format - 1 : format,
+ FMTDIR_ERROR);
goto bad_format;
}
}
type = FAT_TREE | FAT_TREE_CV;
else
{
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : (*format == 'c'
- || *format == 's'
- || *format == 'i' || *format == 'd'
- || *format == 'o' || *format == 'u' || *format == 'x'
- || *format == 'H'
- ? xasprintf (_("In the directive number %u, flags are not allowed before '%c'."), spec.directives, *format)
- : INVALID_CONVERSION_SPECIFIER (spec.directives,
- *format)));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ (*format == 'c'
+ || *format == 's'
+ || *format == 'i' || *format == 'd'
+ || *format == 'o' || *format == 'u' || *format == 'x'
+ || *format == 'H'
+ ? xasprintf (_("In the directive number %u, flags are not allowed before '%c'."), spec.directives, *format)
+ : INVALID_CONVERSION_SPECIFIER (spec.directives,
+ *format));
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
}
if (unnumbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
if (spec.numbered_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
}
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
/* Return true if a format is a valid messageFormatPattern.
Extracts argument type information into spec. */
static bool
-message_format_parse (const char *format, struct spec *spec,
+message_format_parse (const char *format, char *fdi, struct spec *spec,
char **invalid_reason)
{
+ const char *const format_start = format;
bool quoting = false;
for (;;)
unsigned int number;
enum format_arg_type type;
+ FDI_SET (format, FMTDIR_START);
spec->directives++;
element_start = ++format;
{
*invalid_reason =
xstrdup (_("The string ends in the middle of a directive: found '{' without matching '}'."));
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
element_end = format++;
{
*invalid_reason =
xasprintf (_("In the directive number %u, '{' is not followed by an argument number."), spec->directives);
+ FDI_SET (format - 1, FMTDIR_ERROR);
freesa (element_alloced);
return false;
}
{
*invalid_reason =
xasprintf (_("In the directive number %u, the substring \"%s\" is not a valid date/time style."), spec->directives, element);
+ FDI_SET (format - 1, FMTDIR_ERROR);
freesa (element_alloced);
return false;
}
element -= 4;
*invalid_reason =
xasprintf (_("In the directive number %u, \"%s\" is not followed by a comma."), spec->directives, element);
+ FDI_SET (format - 1, FMTDIR_ERROR);
freesa (element_alloced);
return false;
}
{
*invalid_reason =
xasprintf (_("In the directive number %u, the substring \"%s\" is not a valid number style."), spec->directives, element);
+ FDI_SET (format - 1, FMTDIR_ERROR);
freesa (element_alloced);
return false;
}
element -= 6;
*invalid_reason =
xasprintf (_("In the directive number %u, \"%s\" is not followed by a comma."), spec->directives, element);
+ FDI_SET (format - 1, FMTDIR_ERROR);
freesa (element_alloced);
return false;
}
;
else
{
+ FDI_SET (format - 1, FMTDIR_ERROR);
freesa (element_alloced);
return false;
}
element -= 6;
*invalid_reason =
xasprintf (_("In the directive number %u, \"%s\" is not followed by a comma."), spec->directives, element);
+ FDI_SET (format - 1, FMTDIR_ERROR);
freesa (element_alloced);
return false;
}
{
*invalid_reason =
xasprintf (_("In the directive number %u, the argument number is not followed by a comma and one of \"%s\", \"%s\", \"%s\", \"%s\"."), spec->directives, "time", "date", "number", "choice");
+ FDI_SET (format - 1, FMTDIR_ERROR);
freesa (element_alloced);
return false;
}
spec->numbered[spec->numbered_arg_count].number = number;
spec->numbered[spec->numbered_arg_count].type = type;
spec->numbered_arg_count++;
+
+ FDI_SET (format - 1, FMTDIR_END);
}
/* The doc says "ab}de" is invalid. Even though JDK accepts it. */
else if (!quoting && *format == '}')
{
+ FDI_SET (format, FMTDIR_START);
*invalid_reason =
xstrdup (_("The string starts in the middle of a directive: found '}' without matching '{'."));
+ FDI_SET (format, FMTDIR_ERROR);
return false;
}
else if (*format != '\0')
}
*mp = '\0';
- msgformat_valid = message_format_parse (msgformat, spec, invalid_reason);
+ msgformat_valid =
+ message_format_parse (msgformat, NULL, spec, invalid_reason);
freesa (msgformat);
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
struct spec spec;
struct spec *result;
spec.allocated = 0;
spec.numbered = NULL;
- if (!message_format_parse (format, &spec, invalid_reason))
+ if (!message_format_parse (format, fdi, &spec, invalid_reason))
goto bad_format;
/* Sort the numbered argument array, and eliminate duplicates. */
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
struct spec *result;
unsigned int number;
/* A directive. */
enum format_arg_type type;
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (isdigit (*format))
type = FAT_OBJECT;
break;
default:
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (spec.directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
number++;
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
spec is the global struct spec.
terminator is the directive that terminates this parse.
separator specifies if ~; separators are allowed.
+ fdi is an array to be filled with format directive indicators, or NULL.
If the format string is invalid, false is returned and *invalid_reason is
set to an error message explaining why. */
static bool
int *positionp, struct format_arg_list **listp,
struct format_arg_list **escapep, int *separatorp,
struct spec *spec, char terminator, bool separator,
- char **invalid_reason)
+ char *fdi, char **invalid_reason)
{
const char *format = *formatp;
+ const char *const format_start = format;
int position = *positionp;
struct format_arg_list *list = *listp;
struct format_arg_list *escape = *escapep;
unsigned int paramcount = 0;
struct param *params = NULL;
+ FDI_SET (format - 1, FMTDIR_START);
+
/* Count number of directives. */
spec->directives++;
format++;
if (!c_isdigit (*format))
{
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : xasprintf (_("In the directive number %u, '%c' is not followed by a digit."), spec->directives, format[-1]));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ xasprintf (_("In the directive number %u, '%c' is not followed by a digit."), spec->directives, format[-1]);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
return false;
}
do
if (*format == '\0')
{
*invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
format++;
case 'S': case 's': /* 22.3.4.2 FORMAT-S-EXPRESSION */
if (!check_params (&list, paramcount, params, 4, IIIC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_OBJECT);
break;
case 'W': case 'w': /* 22.3.4.3 FORMAT-WRITE */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_OBJECT);
break;
case 'X': case 'x': /* 22.3.2.5 FORMAT-HEXADECIMAL */
if (!check_params (&list, paramcount, params, 4, ICCI,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_INTEGER);
break;
case 'R': case 'r': /* 22.3.2.1 FORMAT-RADIX */
if (!check_params (&list, paramcount, params, 5, IICCI,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_INTEGER);
break;
case 'P': case 'p': /* 22.3.8.3 FORMAT-PLURAL */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (colon_p)
{
/* Go back by 1 argument. */
case 'C': case 'c': /* 22.3.1.1 FORMAT-CHARACTER */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_CHARACTER);
break;
case 'F': case 'f': /* 22.3.3.1 FORMAT-FIXED-FLOAT */
if (!check_params (&list, paramcount, params, 5, IIICC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_REAL);
break;
case 'G': case 'g': /* 22.3.3.3 FORMAT-GENERAL-FLOAT */
if (!check_params (&list, paramcount, params, 7, IIIICCC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_REAL);
break;
case '$': /* 22.3.3.4 FORMAT-DOLLARS-FLOAT */
if (!check_params (&list, paramcount, params, 4, IIIC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_REAL);
break;
case 'I': case 'i': /* 22.3.5.3 */
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
break;
case '\n': /* 22.3.9.3 #\Newline */
case '_': /* 22.3.5.1 */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
break;
case 'T': case 't': /* 22.3.6.1 FORMAT-TABULATE */
if (!check_params (&list, paramcount, params, 2, II,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
break;
case '*': /* 22.3.7.1 FORMAT-GOTO */
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
{
int n; /* value of first parameter */
if (paramcount == 0
/* invalid argument */
*invalid_reason =
xasprintf (_("In the directive number %u, the argument %d is negative."), spec->directives, n);
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (atsign_p)
case '?': /* 22.3.7.6 FORMAT-INDIRECTION */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_FORMATSTRING);
if (atsign_p)
case '/': /* 22.3.5.4 FORMAT-CALL-USER-FUNCTION */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_OBJECT);
while (*format != '\0' && *format != '/')
{
*invalid_reason =
xstrdup (_("The string ends in the middle of a ~/.../ directive."));
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
format++;
case '(': /* 22.3.8.1 FORMAT-CASE-CONVERSION */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*positionp = position;
*listp = list;
{
if (!parse_upto (formatp, positionp, listp, escapep,
NULL, spec, ')', false,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
}
format = *formatp;
position = *positionp;
{
*invalid_reason =
xasprintf (_("Found '~%c' without matching '~%c'."), ')', '(');
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*positionp = position;
*listp = list;
{
*invalid_reason =
xasprintf (_("In the directive number %u, both the @ and the : modifiers are given."), spec->directives);
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
else if (atsign_p)
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*escapep = escape;
(list != NULL ? copy_list (list) : NULL);
if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
NULL, spec, ']', false,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
if (sub_list != NULL)
{
if (position >= 0)
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_OBJECT);
}
if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
&sub_separator, spec, ']', true,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
if (!sub_separator)
{
*invalid_reason =
xasprintf (_("In the directive number %u, '~:[' is not followed by two clauses, separated by '~;'."), spec->directives);
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
return false;
}
if (sub_list != NULL)
(list != NULL ? copy_list (list) : NULL);
if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
NULL, spec, ']', false,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
if (sub_list != NULL)
{
if (union_position == -2)
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
/* If there was no first parameter, an argument is consumed. */
arg_position = -1;
int sub_separator = 0;
if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
&sub_separator, spec, ']', !last_alternative,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
/* If this alternative is chosen, the argument arg_position
is an integer, namely the index of this alternative. */
if (!last_alternative && arg_position >= 0)
{
*invalid_reason =
xasprintf (_("Found '~%c' without matching '~%c'."), ']', '[');
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*positionp = position;
*listp = list;
case '{': /* 22.3.7.4 FORMAT-ITERATION */
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
{
int sub_position = 0;
sub_spec.list = sub_list;
if (!parse_upto (formatp, &sub_position, &sub_list, &sub_escape,
NULL, &sub_spec, '}', false,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
spec->directives += sub_spec.directives;
/* If the sub-formatstring is empty, except for the terminating
{
*invalid_reason =
xasprintf (_("Found '~%c' without matching '~%c'."), '}', '{');
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*positionp = position;
*listp = list;
case '<': /* 22.3.6.2, 22.3.5.2 FORMAT-JUSTIFICATION */
if (!check_params (&list, paramcount, params, 4, IIIC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
{
struct format_arg_list *sub_escape = NULL;
int sub_separator = 0;
if (!parse_upto (formatp, positionp, listp, &sub_escape,
&sub_separator, spec, '>', true,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
if (!sub_separator)
break;
}
{
*invalid_reason =
xasprintf (_("Found '~%c' without matching '~%c'."), '>', '<');
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*positionp = position;
*listp = list;
case '^': /* 22.3.9.2 FORMAT-UP-AND-OUT */
if (!check_params (&list, paramcount, params, 3, THREE,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0 && list != NULL && is_required (list, position))
/* This ~^ can never be executed. Ignore it. */
break;
{
*invalid_reason =
xasprintf (_("In the directive number %u, '~;' is used in an invalid position."), spec->directives);
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (terminator == '>')
{
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
}
else
{
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
}
*formatp = format;
*positionp = position;
case '!': /* FORMAT-CALL, a CLISP extension */
if (!nocheck_params (&list, paramcount, params,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
{
add_req_type_constraint (&list, position++, FAT_FUNCTION);
default:
--format;
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (spec->directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (spec->directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
return false;
}
+ FDI_SET (format - 1, FMTDIR_END);
+
free (params);
}
/* ============== Top level format string handling functions ============== */
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
struct spec spec;
struct spec *result;
if (!parse_upto (&format, &position, &spec.list, &escape,
NULL, &spec, '\0', false,
- invalid_reason))
+ fdi, invalid_reason))
/* Invalid format string. */
return NULL;
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
unsigned int directives;
unsigned int numbered_arg_count;
unsigned int allocated;
if (*format++ == '%')
{
/* A directive. */
+ FDI_SET (format - 1, FMTDIR_START);
directives++;
if (*format != '%')
type = FAT_INTEGER;
break;
default:
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
numbered_arg_count++;
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
struct spec *result;
const char *name_end = f;
size_t n = name_end - name_start;
+ FDI_SET (format - 1, FMTDIR_START);
+
name = XNMALLOC (n + 1, char);
memcpy (name, name_start, n);
name[n] = '\0';
spec.named[spec.named_arg_count].name = name;
spec.named_arg_count++;
+ FDI_SET (f, FMTDIR_END);
+
format = ++f;
}
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
unsigned int directives;
unsigned int numbered_arg_count;
unsigned int allocated;
format_arg_type_t type;
format_arg_type_t size;
+ FDI_SET (format - 1, FMTDIR_START);
directives++;
if (isnonzerodigit (*format))
{
*invalid_reason =
xasprintf (_("In the directive number %u, the size specifier is incompatible with the conversion specifier '%c'."), directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
type = FAT_DOUBLE | size;
type = FAT_COUNT_POINTER | size;
break;
default:
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
numbered_arg_count++;
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
unsigned int directives;
unsigned int numbered_arg_count;
unsigned int allocated;
if (*format++ == '%')
{
/* A directive. */
+ FDI_SET (format - 1, FMTDIR_START);
directives++;
if (*format != '%')
if (m == 0)
{
*invalid_reason = INVALID_ARGNO_0 (directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
number = m;
if (*format == '\0')
{
*invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
format++;
type = FAT_STRING;
break;
default:
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
numbered_arg_count++;
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
xstrdup (_("The string refers to arguments both through argument names and through unnamed argument specifications."))
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
struct spec *result;
char *name = NULL;
enum format_arg_type type;
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (*format == '(')
if (*format == '\0')
{
*invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
name_end = format++;
if (spec.named_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
if (spec.named_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
type = FAT_FLOAT;
break;
default:
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (spec.directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
if (spec.unnamed_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
if (spec.named_arg_count > 0)
{
*invalid_reason = INVALID_MIXES_NAMED_UNNAMED ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
spec.unnamed_arg_count++;
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
/* Parse the format string. */
char *invalid_reason = NULL;
struct spec *descr =
- (struct spec *) format_parse (string, false, &invalid_reason);
+ (struct spec *) format_parse (string, false, NULL, &invalid_reason);
if (descr != NULL)
{
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
struct spec *result;
/* A directive. */
unsigned int number;
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
number = *format - '0';
{
*invalid_reason =
xasprintf (_("Multiple references to %%%c."), *format);
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
spec.args_used[number] = true;
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
spec is the global struct spec.
terminator is the directive that terminates this parse.
separator specifies if ~; separators are allowed.
+ fdi is an array to be filled with format directive indicators, or NULL.
If the format string is invalid, false is returned and *invalid_reason is
set to an error message explaining why. */
static bool
int *positionp, struct format_arg_list **listp,
struct format_arg_list **escapep, int *separatorp,
struct spec *spec, char terminator, bool separator,
- char **invalid_reason)
+ char *fdi, char **invalid_reason)
{
const char *format = *formatp;
+ const char *const format_start = format;
int position = *positionp;
struct format_arg_list *list = *listp;
struct format_arg_list *escape = *escapep;
unsigned int paramcount = 0;
struct param *params = NULL;
+ FDI_SET (format - 1, FMTDIR_START);
+
/* Count number of directives. */
spec->directives++;
format++;
if (!c_isdigit (*format))
{
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : xasprintf (_("In the directive number %u, '%c' is not followed by a digit."), spec->directives, format[-1]));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ xasprintf (_("In the directive number %u, '%c' is not followed by a digit."), spec->directives, format[-1]);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
return false;
}
do
if (*format == '\0')
{
*invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
format++;
case 'S': case 's': /* 22.3.4.2 FORMAT-S-EXPRESSION */
if (!check_params (&list, paramcount, params, 4, IIIC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_OBJECT);
break;
case 'C': case 'c': /* FORMAT-CHARACTER */
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (paramcount == 0
|| (paramcount == 1 && params[0].type == PT_NIL))
if (position >= 0)
case 'X': case 'x': /* 22.3.2.5 FORMAT-HEXADECIMAL */
if (!check_params (&list, paramcount, params, 4, ICCI,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_INTEGER);
break;
case 'R': case 'r': /* 22.3.2.1 FORMAT-RADIX */
if (!check_params (&list, paramcount, params, 5, IICCI,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_INTEGER);
break;
case 'P': case 'p': /* 22.3.8.3 FORMAT-PLURAL */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (colon_p)
{
/* Go back by 1 argument. */
case 'F': case 'f': /* 22.3.3.1 FORMAT-FIXED-FLOAT */
if (!check_params (&list, paramcount, params, 5, IIICC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_REAL);
break;
case 'G': case 'g': /* 22.3.3.3 FORMAT-GENERAL-FLOAT */
if (!check_params (&list, paramcount, params, 7, IIIICCC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_REAL);
break;
case '$': /* 22.3.3.4 FORMAT-DOLLARS-FLOAT */
if (!check_params (&list, paramcount, params, 4, IIIC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_REAL);
break;
case 'I': case 'i': /* FORMAT-FIXED-FLOAT-COMPLEX */
if (!check_params (&list, paramcount, params, 5, IIICC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_COMPLEX);
break;
case 'Y': case 'y': /* FORMAT-PRETTY */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_OBJECT);
break;
case '~': /* 22.3.1.5 FORMAT-TILDE */
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
break;
case '!': /* FORMAT-FORCE-OUTPUT */
case 'Q': case 'q': /* FORMAT-IMPLEMENTATION */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
break;
case 'T': case 't': /* FORMAT-TABULATE */
if (!check_params (&list, paramcount, params, 3, IIC,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
break;
case '*': /* 22.3.7.1 FORMAT-GOTO */
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
{
int n; /* value of first parameter */
if (paramcount == 0
/* invalid argument */
*invalid_reason =
xasprintf (_("In the directive number %u, the argument %d is negative."), spec->directives, n);
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (atsign_p)
case '?': case 'K': case 'k': /* 22.3.7.6 FORMAT-INDIRECTION */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_FORMATSTRING);
if (atsign_p)
case '(': /* 22.3.8.1 FORMAT-CASE-CONVERSION */
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*positionp = position;
*listp = list;
{
if (!parse_upto (formatp, positionp, listp, escapep,
NULL, spec, ')', false,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
}
format = *formatp;
position = *positionp;
{
*invalid_reason =
xasprintf (_("Found '~%c' without matching '~%c'."), ')', '(');
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*positionp = position;
*listp = list;
{
*invalid_reason =
xasprintf (_("In the directive number %u, both the @ and the : modifiers are given."), spec->directives);
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
else if (atsign_p)
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*escapep = escape;
(list != NULL ? copy_list (list) : NULL);
if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
NULL, spec, ']', false,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
if (sub_list != NULL)
{
if (position >= 0)
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0)
add_req_type_constraint (&list, position++, FAT_OBJECT);
}
if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
&sub_separator, spec, ']', true,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
if (!sub_separator)
{
*invalid_reason =
xasprintf (_("In the directive number %u, '~:[' is not followed by two clauses, separated by '~;'."), spec->directives);
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
return false;
}
if (sub_list != NULL)
(list != NULL ? copy_list (list) : NULL);
if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
NULL, spec, ']', false,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
if (sub_list != NULL)
{
if (union_position == -2)
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
/* If there was no first parameter, an argument is consumed. */
arg_position = -1;
int sub_separator = 0;
if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
&sub_separator, spec, ']', !last_alternative,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
/* If this alternative is chosen, the argument arg_position
is an integer, namely the index of this alternative. */
if (!last_alternative && arg_position >= 0)
{
*invalid_reason =
xasprintf (_("Found '~%c' without matching '~%c'."), ']', '[');
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*positionp = position;
*listp = list;
case '{': /* 22.3.7.4 FORMAT-ITERATION */
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
{
int sub_position = 0;
sub_spec.list = sub_list;
if (!parse_upto (formatp, &sub_position, &sub_list, &sub_escape,
NULL, &sub_spec, '}', false,
- invalid_reason))
- return false;
+ NULL, invalid_reason))
+ {
+ FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
+ FMTDIR_ERROR);
+ return false;
+ }
spec->directives += sub_spec.directives;
/* If the sub-formatstring is empty, except for the terminating
{
*invalid_reason =
xasprintf (_("Found '~%c' without matching '~%c'."), '}', '{');
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
*formatp = format;
*positionp = position;
*listp = list;
case '^': /* 22.3.9.2 FORMAT-UP-AND-OUT */
if (!check_params (&list, paramcount, params, 3, THREE,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
if (position >= 0 && list != NULL && is_required (list, position))
/* This ~^ can never be executed. Ignore it. */
break;
{
*invalid_reason =
xasprintf (_("In the directive number %u, '~;' is used in an invalid position."), spec->directives);
+ FDI_SET (format - 1, FMTDIR_ERROR);
return false;
}
if (terminator == '>')
{
if (!check_params (&list, paramcount, params, 1, I,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
}
else
{
if (!check_params (&list, paramcount, params, 0, NULL,
spec->directives, invalid_reason))
- return false;
+ {
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ return false;
+ }
}
*formatp = format;
*positionp = position;
default:
--format;
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (spec->directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (spec->directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
return false;
}
+ FDI_SET (format - 1, FMTDIR_END);
+
free (params);
}
/* ============== Top level format string handling functions ============== */
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
struct spec spec;
struct spec *result;
if (!parse_upto (&format, &position, &spec.list, &escape,
NULL, &spec, '\0', false,
- invalid_reason))
+ fdi, invalid_reason))
/* Invalid format string. */
return NULL;
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
xstrdup (_("The string refers to a shell variable with an empty name."))
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
struct spec *result;
/* A variable substitution. */
char *name;
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (*format == '{')
if (!c_isascii (*format))
{
*invalid_reason = INVALID_NON_ASCII_VARIABLE ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
if (format > name_start
|| *format == '?' || *format == ':'))
{
*invalid_reason = INVALID_SHELL_SYNTAX ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
if (!(c_isalnum (*format) || *format == '_')
|| (format == name_start && c_isdigit (*format)))
{
*invalid_reason = INVALID_CONTEXT_DEPENDENT_VARIABLE ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
}
if (*format == '\0')
{
*invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
name_end = format++;
if (n == 0)
{
*invalid_reason = INVALID_EMPTY_VARIABLE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
name = XNMALLOC (n + 1, char);
if (!c_isascii (*format))
{
*invalid_reason = INVALID_NON_ASCII_VARIABLE ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
else
{
*invalid_reason = INVALID_CONTEXT_DEPENDENT_VARIABLE ();
+ FDI_SET (format, FMTDIR_ERROR);
goto bad_format;
}
}
else
{
*invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
}
spec.named[spec.named_arg_count].name = name;
spec.named_arg_count++;
+
+ FDI_SET (format - 1, FMTDIR_END);
}
/* Sort the named argument array, and eliminate duplicates. */
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
}
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
struct spec *result;
bool seen_numbered_arg;
if (*format++ == '%')
{
/* A directive. */
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (*format != '%')
if (m == 0)
{
*invalid_reason = INVALID_ARGNO_0 (spec.directives);
+ FDI_SET (f, FMTDIR_ERROR);
goto bad_format;
}
number = m;
if (seen_unnumbered_arg)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
is_numbered_arg = true;
if (seen_numbered_arg)
{
*invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
goto bad_format;
}
seen_unnumbered_arg = true;
type = FAT_FLOAT;
break;
default:
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : INVALID_CONVERSION_SPECIFIER (spec.directives, *format));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
number++;
}
+ FDI_SET (format, FMTDIR_END);
+
format++;
}
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
static void *
-format_parse (const char *format, bool translated, char **invalid_reason)
+format_parse (const char *format, bool translated, char *fdi,
+ char **invalid_reason)
{
+ const char *const format_start = format;
struct spec spec;
struct spec *result;
if (*format++ == '%')
{
/* A directive. */
+ FDI_SET (format - 1, FMTDIR_START);
spec.directives++;
if (*format == '%')
}
else
{
- *invalid_reason =
- (*format == '\0'
- ? INVALID_UNTERMINATED_DIRECTIVE ()
- : (c_isprint (*format)
- ? xasprintf (_("In the directive number %u, the character '%c' is not a digit between 1 and 9."), spec.directives, *format)
- : xasprintf (_("The character that terminates the directive number %u is not a digit between 1 and 9."), spec.directives)));
+ if (*format == '\0')
+ {
+ *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
+ FDI_SET (format - 1, FMTDIR_ERROR);
+ }
+ else
+ {
+ *invalid_reason =
+ (c_isprint (*format)
+ ? xasprintf (_("In the directive number %u, the character '%c' is not a digit between 1 and 9."), spec.directives, *format)
+ : xasprintf (_("The character that terminates the directive number %u is not a digit between 1 and 9."), spec.directives));
+ FDI_SET (format, FMTDIR_ERROR);
+ }
goto bad_format;
}
+
+ FDI_SET (format - 1, FMTDIR_END);
}
result = XMALLOC (struct spec);
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, false, &invalid_reason);
+ descr = format_parse (line, false, NULL, &invalid_reason);
format_print (descr);
printf ("\n");
char *invalid_reason = NULL;
void *msgid_descr =
parser->parse (msgid_plural != NULL ? msgid_plural : msgid,
- false, &invalid_reason);
+ false, NULL, &invalid_reason);
if (msgid_descr != NULL)
{
pretty_msgstr = buf;
}
- msgstr_descr = parser->parse (p, true, &invalid_reason);
+ msgstr_descr = parser->parse (p, true, NULL, &invalid_reason);
if (msgstr_descr != NULL)
{
#endif
+/* These indicators are set by the parse function at the appropriate
+ positions. */
+enum
+{
+ /* Set on the first byte of a format directive. */
+ FMTDIR_START = 1 << 0,
+ /* Set on the last byte of a format directive. */
+ FMTDIR_END = 1 << 1,
+ /* Set on the last byte of an invalid format directive, where a parse error
+ was recognized. */
+ FMTDIR_ERROR = 1 << 2
+};
+
+/* Macro for use inside a parser:
+ Sets an indicator at the position corresponding to PTR.
+ Assumes local variables 'fdi' and 'format_start' are defined. */
+#define FDI_SET(ptr, flag) \
+ if (fdi != NULL) \
+ fdi[(ptr) - format_start] |= (flag)/*;*/
+
/* This type of callback is responsible for showing an error. */
typedef void (*formatstring_error_logger_t) (const char *format, ...)
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
/* Parse the given string as a format string.
If translated is true, some extensions available only to msgstr but not
to msgid strings are recognized.
+ If fdi is non-NULL, it must be a an array of strlen (string) zero bytes.
Return a freshly allocated structure describing
1. the argument types/names needed for the format string,
2. the total number of format directives.
Return NULL if the string is not a valid format string. In this case,
- also set *invalid_reason to an error message explaining why. */
- void * (*parse) (const char *string, bool translated, char **invalid_reason);
+ also set *invalid_reason to an error message explaining why.
+ In both cases, set FMTDIR_* bits at the appropriate positions in fdi. */
+ void * (*parse) (const char *string, bool translated, char *fdi, char **invalid_reason);
/* Free a format string descriptor, returned by parse(). */
void (*free) (void *descr);
struct formatstring_parser *parser = formatstring_parsers[fmt];
char *invalid_reason = NULL;
void *msgid_descr =
- parser->parse (msgid_plural != NULL ? msgid_plural : msgid, false,
+ parser->parse (msgid_plural != NULL ? msgid_plural : msgid, false, NULL,
&invalid_reason);
failure = false;
for (p = msgstr; p < p_end; p += strlen (p) + 1)
{
- void *msgstr_descr = parser->parse (msgstr, true, &invalid_reason);
+ void *msgstr_descr =
+ parser->parse (msgstr, true, NULL, &invalid_reason);
if (msgstr_descr != NULL)
{
for (str = msgid; str < str_end; str += strlen (str) + 1)
{
char *invalid_reason = NULL;
- void *descr = parser->parse (str, false, &invalid_reason);
+ void *descr =
+ parser->parse (str, false, NULL, &invalid_reason);
if (descr != NULL)
parser->free (descr);
{
char *invalid_reason = NULL;
void *descr =
- parser->parse (str, true, &invalid_reason);
+ parser->parse (str, true, NULL, &invalid_reason);
if (descr != NULL)
parser->free (descr);
{
struct formatstring_parser *parser = formatstring_parsers[i];
char *invalid_reason = NULL;
- void *descr = parser->parse (string, false, &invalid_reason);
+ void *descr = parser->parse (string, false, NULL, &invalid_reason);
if (descr != NULL)
parser->free (descr);
{
struct formatstring_parser *parser = formatstring_parsers[i];
char *invalid_reason = NULL;
- void *descr = parser->parse (mp->msgid, false, &invalid_reason);
+ void *descr = parser->parse (mp->msgid, false, NULL, &invalid_reason);
if (descr != NULL)
{
struct formatstring_parser *parser = formatstring_parsers[i];
char *invalid_reason = NULL;
void *descr =
- parser->parse (mp->msgid_plural, false, &invalid_reason);
+ parser->parse (mp->msgid_plural, false, NULL, &invalid_reason);
if (descr != NULL)
{