+ case 'm':
+ {
+ const char *errstr = xstrerror (text->err_no);
+ obstack_grow (&buffer->chunk_obstack, errstr, strlen (errstr));
+ }
+ p++;
+ continue;
+
+ default:
+ /* Handled in phase 2. Terminate the plain chunk here. */
+ obstack_1grow (&buffer->chunk_obstack, '\0');
+ gcc_assert (chunk < PP_NL_ARGMAX * 2);
+ args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
+ break;
+ }
+
+ if (ISDIGIT (*p))
+ {
+ char *end;
+ argno = strtoul (p, &end, 10) - 1;
+ p = end;
+ gcc_assert (*p == '$');
+ p++;
+
+ any_numbered = true;
+ gcc_assert (!any_unnumbered);
+ }
+ else
+ {
+ argno = curarg++;
+ any_unnumbered = true;
+ gcc_assert (!any_numbered);
+ }
+ gcc_assert (argno < PP_NL_ARGMAX);
+ gcc_assert (!formatters[argno]);
+ formatters[argno] = &args[chunk];
+ do
+ {
+ obstack_1grow (&buffer->chunk_obstack, *p);
+ p++;
+ }
+ while (strchr ("qwl+#", p[-1]));
+
+ if (p[-1] == '.')
+ {
+ /* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
+ (where M == N + 1). */
+ if (ISDIGIT (*p))
+ {
+ do
+ {
+ obstack_1grow (&buffer->chunk_obstack, *p);
+ p++;
+ }
+ while (ISDIGIT (p[-1]));
+ gcc_assert (p[-1] == 's');
+ }
+ else
+ {
+ gcc_assert (*p == '*');
+ obstack_1grow (&buffer->chunk_obstack, '*');
+ p++;
+
+ if (ISDIGIT (*p))
+ {
+ char *end;
+ unsigned int argno2 = strtoul (p, &end, 10) - 1;
+ p = end;
+ gcc_assert (argno2 == argno - 1);
+ gcc_assert (!any_unnumbered);
+ gcc_assert (*p == '$');
+
+ p++;
+ formatters[argno2] = formatters[argno];
+ }
+ else
+ {
+ gcc_assert (!any_numbered);
+ formatters[argno+1] = formatters[argno];
+ curarg++;
+ }
+ gcc_assert (*p == 's');
+ obstack_1grow (&buffer->chunk_obstack, 's');
+ p++;
+ }
+ }
+ if (*p == '\0')