glibc: Parsing a Template String 如何解析printf格式化

Posted rtoax

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了glibc: Parsing a Template String 如何解析printf格式化相关的知识,希望对你有一定的参考价值。

https://www.gnu.org/software/libc/manual//html_node/Parsing-a-Template-String.html#:~:text=12.10%20Parsing%20a%20Template%20String%20You%20can%20use,the%20user%E2%80%99s%20program%2C%20which%20could%20cause%20a%20crash.

 

#include <stdio.h>
#include <printf.h>

static void fmt_parse(const char *fmt)
{
    int i;
    int argtypes[1024] = {0};
    
    size_t ret = parse_printf_format(fmt, 1024, argtypes);

    printf("===========================\\n");
    printf("%s\\n", fmt);
    for(i=0;i<ret;i++) {
        switch(argtypes[i]) {

#define _CASE(i, v, intro) \\
        case v:              \\
            printf("\\t%d is %s\\n", i, intro);    \\
            break;  

        _CASE(i, PA_INT, "int");
        _CASE(i, PA_INT|PA_FLAG_LONG, "long int");
        _CASE(i, PA_INT|PA_FLAG_SHORT, "short int");
        _CASE(i, PA_INT|PA_FLAG_LONG_LONG, "long long int");

        _CASE(i, PA_CHAR, "char");
        _CASE(i, PA_WCHAR, "wchar");
        _CASE(i, PA_STRING, "string");
        _CASE(i, PA_WSTRING, "wstring");
        _CASE(i, PA_POINTER, "pointer");
        _CASE(i, PA_FLOAT, "float");
        _CASE(i, PA_DOUBLE, "double");
        _CASE(i, PA_DOUBLE|PA_FLAG_LONG_DOUBLE, "long double");
        _CASE(i, PA_LAST, "LAST");


        default:
            printf("\\t%d unknown(%d).\\n", i, argtypes[i]);
            break;
        }
    }
}


const char *test_fmts[] = {

"1.%d 2.%u 3.%x",
"1.%2d 2.%2u 3.%2x",
"1.%-d 2.%-u 3.%-x",
"1.%-2d 2.%-2u 3.%-2x",

"1.%ld 2.%lu 3.%lx",
"1.%2ld 2.%2lu 3.%2lx",
"1.%-ld 2.%-lu 3.%-lx",
"1.%-2ld 2.%-2lu 3.%-2lx %lld %-lld %2lld %-2lld",

"1.%s 2.%S 3.%c 4.%C",
"1.%-s 2.%-S 3.%-c 4.%-C",
"1.%10s 2.%10S 3.%c 4.%C",
"1.%-10s 2.%-10S 3.%c 4.%C",

"1.%f 2.%lf %llf",
"1.%-f 2.%-lf",
"1.%2f 2.%2lf",
"1.%.2f 2.%.2lf %llf %-llf %2llf %-2llf",


"%10.2f %2.lf %-2.lf %-.10lf",

"%p %x %0x %#02x %#02lx",

NULL,
};

int main()
{
    int i = 0;

    while(test_fmts[i]) {
        fmt_parse(test_fmts[i++]);
    }
}


12.12.10 Parsing a Template String

You can use the function parse_printf_format to obtain information about the number and types of arguments that are expected by a given template string. This function permits interpreters that provide interfaces to printf to avoid passing along invalid arguments from the user’s program, which could cause a crash.

All the symbols described in this section are declared in the header file printf.h.

Function: size_t parse_printf_format (const char *template, size_t n, int *argtypes)

Preliminary: | MT-Safe locale | AS-Safe | AC-Safe | See POSIX Safety Concepts.

This function returns information about the number and types of arguments expected by the printf template string template. The information is stored in the array argtypes; each element of this array describes one argument. This information is encoded using the various ‘PA_’ macros, listed below.

The argument n specifies the number of elements in the array argtypes. This is the maximum number of elements that parse_printf_format will try to write.

parse_printf_format returns the total number of arguments required by template. If this number is greater than n, then the information returned describes only the first n arguments. If you want information about additional arguments, allocate a bigger array and call parse_printf_format again.

The argument types are encoded as a combination of a basic type and modifier flag bits.

Macro: int PA_FLAG_MASK

This macro is a bitmask for the type modifier flag bits. You can write the expression (argtypes[i] & PA_FLAG_MASK) to extract just the flag bits for an argument, or (argtypes[i] & ~PA_FLAG_MASK) to extract just the basic type code.

Here are symbolic constants that represent the basic types; they stand for integer values.

PA_INT

This specifies that the base type is int.

PA_CHAR

This specifies that the base type is int, cast to char.

PA_STRING

This specifies that the base type is char *, a null-terminated string.

PA_POINTER

This specifies that the base type is void *, an arbitrary pointer.

PA_FLOAT

This specifies that the base type is float.

PA_DOUBLE

This specifies that the base type is double.

PA_LAST

You can define additional base types for your own programs as offsets from PA_LAST. For example, if you have data types ‘foo’ and ‘bar’ with their own specialized printf conversions, you could define encodings for these types as:

#define PA_FOO  PA_LAST
#define PA_BAR  (PA_LAST + 1)

Here are the flag bits that modify a basic type. They are combined with the code for the basic type using inclusive-or.

PA_FLAG_PTR

If this bit is set, it indicates that the encoded type is a pointer to the base type, rather than an immediate value. For example, ‘PA_INT|PA_FLAG_PTR’ represents the type ‘int *’.

PA_FLAG_SHORT

If this bit is set, it indicates that the base type is modified with short. (This corresponds to the ‘h’ type modifier.)

PA_FLAG_LONG

If this bit is set, it indicates that the base type is modified with long. (This corresponds to the ‘l’ type modifier.)

PA_FLAG_LONG_LONG

If this bit is set, it indicates that the base type is modified with long long. (This corresponds to the ‘L’ type modifier.)

PA_FLAG_LONG_DOUBLE

This is a synonym for PA_FLAG_LONG_LONG, used by convention with a base type of PA_DOUBLE to indicate a type of long double.


Next: Example of Parsing, Previous: Variable Arguments Output, Up: Formatted Output   [Contents][Index]

 

12.12.11 Example of Parsing a Template String

https://www.gnu.org/software/libc/manual//html_node/Example-of-Parsing.html

Here is an example of decoding argument types for a format string. We assume this is part of an interpreter which contains arguments of type NUMBERCHARSTRING and STRUCTURE (and perhaps others which are not valid here).

/* Test whether the nargs specified objects
   in the vector args are valid
   for the format string format:
   if so, return 1.
   If not, return 0 after printing an error message.  */

int
validate_args (char *format, int nargs, OBJECT *args)
{
  int *argtypes;
  int nwanted;

  /* Get the information about the arguments.
     Each conversion specification must be at least two characters
     long, so there cannot be more specifications than half the
     length of the string.  */

  argtypes = (int *) alloca (strlen (format) / 2 * sizeof (int));
  nwanted = parse_printf_format (format, nargs, argtypes);

  /* Check the number of arguments.  */
  if (nwanted > nargs)
    {
      error ("too few arguments (at least %d required)", nwanted);
      return 0;
    }

  /* Check the C type wanted for each argument
     and see if the object given is suitable.  */
  for (i = 0; i < nwanted; i++)
    {
      int wanted;

      if (argtypes[i] & PA_FLAG_PTR)
	wanted = STRUCTURE;
      else
	switch (argtypes[i] & ~PA_FLAG_MASK)
	  {
	  case PA_INT:
	  case PA_FLOAT:
	  case PA_DOUBLE:
	    wanted = NUMBER;
	    break;
	  case PA_CHAR:
	    wanted = CHAR;
	    break;
	  case PA_STRING:
	    wanted = STRING;
	    break;
	  case PA_POINTER:
	    wanted = STRUCTURE;
	    break;
	  }
      if (TYPE (args[i]) != wanted)
	{
	  error ("type mismatch for arg number %d", i);
	  return 0;
	}
    }
  return 1;
}

 

以上是关于glibc: Parsing a Template String 如何解析printf格式化的主要内容,如果未能解决你的问题,请参考以下文章

[vue/no-parsing-error] Parsing error: x-invalid-end-tag 提示报错

[vue/no-parsing-error] Parsing error: x-invalid-end-tag 提示报错

[vue/no-parsing-error] Parsing error: x-invalid-end-tag.eslint-plugin-vue

leetcode1106. Parsing A Boolean Expression

Expected a key while parsing a block mapping.

Error parsing XML: not well-formed (invalid token) 报错+R文件消失解决的方法