class AdLint::Cc1::PrintfFormat::ConversionSpecifier

Attributes

conversion_argument[R]
conversion_specifier_character[R]
field_width[R]
field_width_argument[R]
flags[R]
length_modifier[R]
precision[R]
precision_argument[R]

Public Class Methods

new(fmt, trailing_args, env, consume_args, flags, field_width, prec, len_mod, cs_char) click to toggle source
# File lib/adlint/cc1/format.rb, line 406
def initialize(fmt, trailing_args, env, consume_args, flags, field_width,
               prec, len_mod, cs_char)
  super(fmt, consume_args)

  @flags = flags
  @field_width = field_width
  @precision = prec
  @length_modifier = len_mod
  @conversion_specifier_character = cs_char

  if consume_arguments? && @field_width == "*"
    @field_width_argument = trailing_args.shift
  else
    @field_width_argument = nil
  end

  if consume_arguments? && @precision == ".*"
    @precision_argument = trailing_args.shift
  else
    @precision_argument = nil
  end

  if consume_arguments?
    @conversion_argument = trailing_args.shift
  else
    @conversion_argument = nil
  end

  @environment = env
end
scan(fmt_str) click to toggle source
# File lib/adlint/cc1/format.rb, line 339
def self.scan(fmt_str)
  # NOTE: The ISO C99 standard says;
  #
  # 7.19.6.1 The fprintf function
  #
  # 4 Each conversion specification is introduced by the character %.
  #   After the %, the following appear in sequence:
  #
  #   -- Zero or more flags (in any order) that modify the meaning of the
  #      conversion specification.
  #   -- An optional minimum field width.  If the converted value has
  #      fewer characters than the field width, it is padded with spaces
  #      (by default) on the left (or right, if the left adjustment flag,
  #      described later, has been given) to the field width.  The field
  #      width takes the form of an asterisk * (described later) or a
  #      nonnegative decimal integer.
  #   -- An optional precision that gives the minimum number of digits to
  #      appear for the d, i, o, u, x, and X conversions, the number of
  #      digits to appear after the decimal-point character for a, A, e,
  #      E, f, and F conversions, the maximum number of significant
  #      digits for the g and G conversions, or the maximum number of
  #      bytes to be written for s conversions.  The precision takes the
  #      form of a period (.) followed either by an asterisk * (described
  #      later) or by an optional decimal interger; if only the period is
  #      specified, the precision is taken as zero.  If a precision
  #      appears with any other conversion specifier, the behavior is
  #      undefined.
  #   -- An optional length modifier that specifies the size of the
  #      argument.
  #   -- A conversion specifier character that specifies the type of
  #      conversion to be applied.

  if header = fmt_str.slice!(/\A%/)
    scanned = header
  else
    return nil, nil, nil, nil, nil, nil
  end

  if flags = fmt_str.slice!(/\A#{flags_re}/)
    scanned += flags
  end

  if field_width = fmt_str.slice!(/\A#{field_width_re}/)
    scanned += field_width
  end

  if prec = fmt_str.slice!(/\A#{precision_re}/)
    scanned += prec
  end

  if len_mod = fmt_str.slice!(/\A#{length_modifier_re}/)
    scanned += len_mod
  end

  if cs_char = fmt_str.slice!(/\A#{cs_char_re}/)
    scanned += cs_char
  else
    # NOTE: If no valid conversion specifier character, force to scan
    #       the heading 1 character as a conversion specifier character.
    if cs_char = fmt_str.slice!(/\A[a-z]/i)
      scanned += cs_char
    end
  end

  return scanned, flags, field_width, prec, len_mod, cs_char
end

Private Class Methods

cs_char_re() click to toggle source
# File lib/adlint/cc1/format.rb, line 601
def self.cs_char_re
  # NOTE: The ISO C99 standard says;
  #
  # 7.19.6.1 The fprintf function
  #
  # 8 The conversion specifiers and their meanings are:
  #
  #   d,i     The int argument is converted to signed decimal in the
  #           style [-]dddd.  The precision specifies the minimum number
  #           of digits to appear; if the value being converted can be
  #           represented in fewer digits, it is expanded with leading
  #           zeros.  The default precision is 1.  The result of
  #           converting a zero value with a precision of zero is no
  #           characters.
  #   o,u,x,X The unsigned int argument is converted to unsigned octal
  #           (o), unsigned decimal (u), or unsigned hexadecimal notation
  #           (x or X) in the style dddd; the letters abcdef are used for
  #           x conversion and the letters ABCDEF for X conversion.  The
  #           precision specifies the minimum number of digits to appear;
  #           if the value being converted can be represented in fewer
  #           digits, it is expanded with leading zeros.  The default
  #           precision in 1.  The result of converting a zero value with
  #           a precision of zero is no characters.
  #   f,F     A double argument representing a floating-point number is
  #           converted to decimal notation in the style [-]ddd.ddd,
  #           where the number of digits after the decimal-point
  #           character is equal to the precision specification.  If the
  #           precision is missing, it is taken as 6; if the precision is
  #           zero and the # flag is not specified, no decimal-point
  #           character appears.  If a decimal-point character appears,
  #           at least one digit appears before it.  The value is rounded
  #           to the appropriate number of digits.
  #           A double argument representing an infinity is converted in
  #           one of the styles [-]inf or [-]infinity -- which style is
  #           implementation-defined.  A double argument representing a
  #           NaN is converted in one of the styles [-]nan or
  #           [-]nan(n-char-sequence) -- which style, and the meaning of
  #           any n-char-sequence, is implementation-defined.  The F
  #           conversion specifier produces INF, INFINITY, or NAN instead
  #           of inf, infinity, or nan, respectively.
  #   e,E     A double argument representing a floating-point number is
  #           converted in the style [-]d.ddde[+-]dd, where there is one
  #           digit (which is nonzero if the argument is nonzero) before
  #           the decimal-point character and the number of digits after
  #           it is equal to the precision; if the precision is missing,
  #           it is taken as 6; if the precision is zero and the # flag
  #           is not specified, no decimal-point character appears.  The
  #           value is rounded to the appropriate number of digits.  The
  #           E conversion specifier produces a number with E instead of
  #           e introducing the exponent.  The exponent always contains
  #           at least two digits, and only as many more digits as
  #           necessary to represent the exponent.  If the value is zero,
  #           the exponent is zero.
  #   g,G     A double argument representing a floating-point number is
  #           converted in style f or e (or in style F or E in the case
  #           of a G conversion specifier), depending on the value
  #           converted and the precision.  Let P equal the precision if
  #           nonzero, 6 if the precision is omitted, or 1 if the
  #           precision is zero.  Then, if a conversion with style E
  #           would have an exponent of X:
  #             -- if P > X >= -4, the conversion is which style f (or F)
  #                and precision P - (X + 1).
  #             -- otherwise, the conversion is with style e (or E) and
  #                precision P - 1.
  #           Finally, unless the # flag is used, any trailing zeros are
  #           removed from the fractional portion of the result and the
  #           decimal-point character is removed if there is no
  #           fractional portion remaining.
  #           A double argument representing an infinity or NaN is
  #           converted in the style of an f or F conversion specifier.
  #   a,A     A double argument representing a floating-point number is
  #           converted in the style [-]0xh.hhhhp[+-]d, where there is
  #           one hexadecimal digit (which is nonzero if the argument is
  #           a normalized floating-point number and is otherwise
  #           unspecified) before the decimal-point character and the
  #           number of hexadecimal digits after it is equal to the
  #           precision; if the precision is missing and FLT_RADIX is a
  #           power of 2, then the precision is sufficient for an exact
  #           representation of the value; if the precision is missing
  #           and FLT_RADIX is not a power of 2, then the precision is
  #           sufficient to distinguish values of type double, except
  #           that trailing zeros may be omitted; if the precision is
  #           zero and the # flag is not specified, no decimal-point
  #           character appears.  The letters abcdef are used for a
  #           conversion and the letters ABCDEF for A conversion.  The A
  #           conversion specifier produces a number with X and P instead
  #           of x and p.  The exponent always contains at least one
  #           digit, and only as many more digits as necessary to
  #           represent the decimal exponent of 2.  If the value is zero,
  #           the exponent is zero.
  #   c       If no l length modifier is present, the int argument is
  #           converted to an unsigned char, and the resulting character
  #           is written.
  #   s       If no l length modifier is present, the argument shall be a
  #           pointer to the initial element of an array of character
  #           type.  Characters from the array are written up to (but not
  #           including) the terminating null character.  If the
  #           precision is specified, no more than that many bytes are
  #           written.  If the precision is not specified or is greater
  #           than the size of the array, the array shall contain a null
  #           character.
  #           If an l length modifier is present, the argument shall be a
  #           pointer to the initial element of an array of wchar_t type.
  #           Wide characters from the array are converted to multibyte
  #           characters (each as if by a call to the wcrtomb function,
  #           with the conversion state described by an mbstate_t object
  #           initialized to zero before the first wide character is
  #           converted) up to and including a terminating null wide
  #           character.  The resulting multibyte characters are written
  #           up to (but not including) the terminating null character
  #           (byte).  If no precision is specified, the array shall
  #           contain a null wide character.  If a precision is
  #           specified, no more than that many bytes are written
  #           (including shift sequence, if any), and the array shall
  #           contain a null wide character if, to equal the multibyte
  #           character sequence length given by the precision, the
  #           function would need to access a wide character one past the
  #           end of the array.  In no case is a partial multibyte
  #           character written.
  #   p       The argument shall be a pointer to void.  The value of the
  #           pointer is converted to a sequence of printing characters,
  #           in an implementation-defined manner.
  #   n       The argument shall be a pointer to signed integer into
  #           which is written the number of characters written to the
  #           output stream so far by this call to fprintf.  No argument
  #           is converted, but one is consumed.  If the conversion
  #           specification includes any flags, a field width, or a
  #           precision, the behavior is undefined.
  #   %       A % character is written.  No argument is converted.  The
  #           complete conversion specification shall be %%.
  /[diouxXfFeEgGaAcspn%]/
end
field_width_re() click to toggle source
# File lib/adlint/cc1/format.rb, line 539
def self.field_width_re
  /(?:\*|[1-9][0-9]*)?/
end
flags_re() click to toggle source
# File lib/adlint/cc1/format.rb, line 498
def self.flags_re
  # NOTE: The ISO C99 standard says;
  #
  # 7.19.6.1 The fprintf function
  #
  # 6 The flag characters and their meaning are:
  #
  #   -     The result of the conversion is left-justified within the
  #         field. (It is right-justified if this flag is not specified.)
  #   +     The result of a signed conversion always begins with a plus
  #         or minus sign. (It begins with a sign only when a negative
  #         value is converted if this flag is not specified.)
  #   space If the first character of a signed conversion is not a sign,
  #         or if a signed conversion results in no characters, a space
  #         is prefixed to the result.  If the space and + flags both
  #         appear, the space flag is ignored.
  #   #     The result is converted to an "alternative form".  For o
  #         conversion, it increases the precision, if an only if
  #         necessary, to force the first digit of the result to be a
  #         zero (if the value and precision are both 0, a single 0 is
  #         printed).  For x (or X) conversion, a nonzero result has 0x
  #         (or 0X) prefixed to it.  For a, A, e, E, f, F, g, and G
  #         conversions, the result of converting a floating-point number
  #         always contains a decimal-point character, even if no digits
  #         follow it. (Normally, a decimal-point character appears in
  #         the result of these conversions only if a digit follows it.)
  #         For g and G conversions, trailing zeros are not removed from
  #         the result.  For other conversions, the behavior is
  #         undefined.
  #   0     For d, i, o, u, x, X, a, A, e, E, f, F, g, and G conversions,
  #         leading zeros (following any indication of sign or base) are
  #         used to pad to the field width rather than performing space
  #         padding, except when converting an infinity or NaN.  If the 0
  #         and - flags both appear, the 0 flag is ignored.  For d, i, o,
  #         u, x, and X conversions, if a precision is specified, the 0
  #         flag is ignored.  For other conversions, the behavior is
  #         undefined.
  /[-+ #0]*/
end
length_modifier_re() click to toggle source
# File lib/adlint/cc1/format.rb, line 549
def self.length_modifier_re
  # NOTE: The ISO C99 standard says;
  #
  # 7.19.6.1 The fprintf function
  #
  # 7 The length modifiers and their meanings are:
  #
  #   hh   Specifies that a following d, i, o, u, x, or X conversion
  #        specifier applies to a signed char or unsigned char argument
  #        (the argument will have been promoted according to the integer
  #        promotions, but its value shall be converted to signed char or
  #        unsigned char before printing); or that a following n
  #        conversion specifier applies to a pointer to a signed char
  #        argument.
  #   h    Specifies that a following d, i, o, u, x, or X conversion
  #        specifier applies to a short int or unsigned short int
  #        argument (the argument will have been promoted according to
  #        the integer promotions, but its value shall be converted to
  #        short int or unsigned short int before printing); or that a
  #        following n conversion specifier applies to a pointer to a
  #        short int argument.
  #   l    Specifies that a following d, i, o, u, x, or X conversion
  #        specifier applies to a long int or unsigned long int argument;
  #        that a following n conversion specifier applies to a pointer
  #        to a long int argument; that a following c conversion
  #        specifier applies to a wint_t argument; that a following s
  #        conversion specifier applies to a pointer to a wchar_t
  #        argument; or has no effect on a following a, A, e, E, f, F, g,
  #        or G conversion specifier.
  #   ll   Specifies that a following d, i, o, u, x, or X conversion
  #        specifier applies to a long long int or unsigned long long int
  #        argument; or that a following n conversion specifier applies
  #        to a pointer to a long long int argument.
  #   j    Specifies that a following d, i, o, u, x, or X conversion
  #        specifier applies to an intmax_t or uintmax_t argument; or
  #        that a following n conversion specifier applies to a pointer
  #        to an intmax_t argument.
  #   z    Specifies that a following d, i, o, u, x, or X conversion
  #        specifier applies to a size_t or the corresponding signed
  #        integer type argument; or that a following n conversion
  #        specifier applies to a pointer to a signed integer type
  #        corresponding to size_t argument.
  #   t    Specifies that a following d, i, o, u, x, or X conversion
  #        specifier applies to a ptrdiff_t or the corresponding unsigned
  #        integer type argument; or that a following n conversion
  #        specifier applies to a pointer to a ptrdiff_t argument.
  #   L    Specifies that a following a, A, e, E, f, F, g, or G
  #        conversion specifier applies to a long double argument.
  /(?:h+|l+|j|z|t|L)?/
end
precision_re() click to toggle source
# File lib/adlint/cc1/format.rb, line 544
def self.precision_re
  /(?:\.\*|\.[1-9][0-9]*)?/
end

Public Instance Methods

conversion_specifier?() click to toggle source
# File lib/adlint/cc1/format.rb, line 437
def conversion_specifier?
  true
end
field_width_value() click to toggle source
# File lib/adlint/cc1/format.rb, line 454
def field_width_value
  case @field_width
  when "*"
    # TODO: Should support the parameterized field width.
    1
  when /\A[1-9][0-9]*\z/
    @field_width.to_i
  else
    1
  end
end
precision_value() click to toggle source
# File lib/adlint/cc1/format.rb, line 466
def precision_value
  # NOTE: The ISO C99 standard says;
  #
  # 7.19.6.1 The fprintf function
  #
  # 4 Each conversion specification is introduced by the character %.
  #   After the %, the following appear in sequence:
  #
  #   -- An optional precision that gives the minimum number of digits to
  #      appear for the d, i, o, u, x, and X conversions, the number of
  #      digits to appear after the decimal-point character for a, A, e,
  #      E, f, and F conversions, the maximum number of significant
  #      digits for the g and G conversions, or the maximum number of
  #      bytes to be written for s conversions.  The precision takes the
  #      form of a period (.) followed either by an asterisk * (described
  #      later) or by an optional decimal interger; if only the period is
  #      specified, the precision is taken as zero.  If a precision
  #      appears with any other conversion specifier, the behavior is
  #      undefined.
  case @precision
  when "."
    0
  when ".*"
    # TODO: Should support the parameterized precision.
    default_precision_value
  when /\A\.([1-9][0-9]*)\z/
    $1.to_i
  else
    default_precision_value
  end
end
undefined?() click to toggle source
# File lib/adlint/cc1/format.rb, line 441
def undefined?
  false
end

Private Instance Methods

default_precision_value() click to toggle source
# File lib/adlint/cc1/format.rb, line 736
def default_precision_value
  subclass_responsibility
end
ruby_sprintf_format() click to toggle source
# File lib/adlint/cc1/format.rb, line 740
def ruby_sprintf_format
  # TODO: Should support the parameterized field width and the
  #       parameterized precision.
  fw = @field_width == "*" ? "1" : @field_width
  pr = @precision == ".*" ? ".1" : @precision
  "%#{flags}#{fw}#{pr}#{conversion_specifier_character}"
end