- char *sp, *ep;
- int idx;
-
- sp = ep = ds_c_str (&tokstr);
- while (isalpha ((unsigned char) *ep))
- ep++;
-
- if (sp != ep)
- {
- /* Find format. */
- for (idx = 0; idx < FMT_NUMBER_OF_FORMATS; idx++)
- if (strlen (formats[idx].name) == ep - sp
- && !buf_compare_case (formats[idx].name, sp, ep - sp))
- break;
-
- /* Check format. */
- if (idx < FMT_NUMBER_OF_FORMATS)
- {
- if (!(flags & FMTP_ALLOW_XT) && (idx == FMT_T || idx == FMT_X))
- {
- if (!(flags & FMTP_SUPPRESS_ERRORS))
- msg (SE, _("X and T format specifiers not allowed here."));
- idx = -1;
- }
- }
- else
- {
- /* No match. */
- if (!(flags & FMTP_SUPPRESS_ERRORS))
- msg (SE, _("%.*s is not a valid data format."),
- (int) (ep - sp), ds_c_str (&tokstr));
- idx = -1;
- }
- }
- else
- {
- lex_error ("expecting data format");
- idx = -1;
- }
-
- if (cp != NULL)
+ struct substring s;
+ struct substring type_ss, width_ss, decimals_ss;
+ bool has_decimals;
+
+ if (lex_token (lexer) != T_ID)
+ goto error;
+
+ /* Extract pieces. */
+ s = ds_ss (lex_tokstr (lexer));
+ ss_get_chars (&s, ss_span (s, ss_cstr (CC_LETTERS)), &type_ss);
+ ss_get_chars (&s, ss_span (s, ss_cstr (CC_DIGITS)), &width_ss);
+ if (ss_match_char (&s, '.'))