Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
546e5354
Commit
546e5354
authored
Mar 06, 2009
by
Ingo Molnar
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'core/printk' into tracing/ftrace
parents
af438c0f
fef20d9c
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
806 additions
and
227 deletions
+806
-227
include/linux/kernel.h
include/linux/kernel.h
+17
-0
include/linux/string.h
include/linux/string.h
+7
-0
lib/Kconfig
lib/Kconfig
+3
-0
lib/vsprintf.c
lib/vsprintf.c
+779
-227
No files found.
include/linux/kernel.h
View file @
546e5354
...
...
@@ -242,6 +242,19 @@ extern struct ratelimit_state printk_ratelimit_state;
extern
int
printk_ratelimit
(
void
);
extern
bool
printk_timed_ratelimit
(
unsigned
long
*
caller_jiffies
,
unsigned
int
interval_msec
);
/*
* Print a one-time message (analogous to WARN_ONCE() et al):
*/
#define printk_once(x...) ({ \
static int __print_once = 1; \
\
if (__print_once) { \
__print_once = 0; \
printk(x); \
} \
})
#else
static
inline
int
vprintk
(
const
char
*
s
,
va_list
args
)
__attribute__
((
format
(
printf
,
1
,
0
)));
...
...
@@ -253,6 +266,10 @@ static inline int printk_ratelimit(void) { return 0; }
static
inline
bool
printk_timed_ratelimit
(
unsigned
long
*
caller_jiffies
,
\
unsigned
int
interval_msec
)
\
{
return
false
;
}
/* No effect, but we still get type checking even in the !PRINTK case: */
#define printk_once(x...) printk(x)
#endif
extern
int
printk_needs_cpu
(
int
cpu
);
...
...
include/linux/string.h
View file @
546e5354
...
...
@@ -10,6 +10,7 @@
#include <linux/compiler.h>
/* for inline */
#include <linux/types.h>
/* for size_t */
#include <linux/stddef.h>
/* for NULL */
#include <stdarg.h>
extern
char
*
strndup_user
(
const
char
__user
*
,
long
);
...
...
@@ -111,6 +112,12 @@ extern void argv_free(char **argv);
extern
bool
sysfs_streq
(
const
char
*
s1
,
const
char
*
s2
);
#ifdef CONFIG_BINARY_PRINTF
int
vbin_printf
(
u32
*
bin_buf
,
size_t
size
,
const
char
*
fmt
,
va_list
args
);
int
bstr_printf
(
char
*
buf
,
size_t
size
,
const
char
*
fmt
,
const
u32
*
bin_buf
);
int
bprintf
(
u32
*
bin_buf
,
size_t
size
,
const
char
*
fmt
,
...)
__printf
(
3
,
4
);
#endif
extern
ssize_t
memory_read_from_buffer
(
void
*
to
,
size_t
count
,
loff_t
*
ppos
,
const
void
*
from
,
size_t
available
);
...
...
lib/Kconfig
View file @
546e5354
...
...
@@ -2,6 +2,9 @@
# Library configuration
#
config BINARY_PRINTF
def_bool n
menu "Library routines"
config BITREVERSE
...
...
lib/vsprintf.c
View file @
546e5354
...
...
@@ -396,7 +396,38 @@ static noinline char* put_dec(char *buf, unsigned long long num)
#define SMALL 32
/* Must be 32 == 0x20 */
#define SPECIAL 64
/* 0x */
static
char
*
number
(
char
*
buf
,
char
*
end
,
unsigned
long
long
num
,
int
base
,
int
size
,
int
precision
,
int
type
)
enum
format_type
{
FORMAT_TYPE_NONE
,
/* Just a string part */
FORMAT_TYPE_WITDH
,
FORMAT_TYPE_PRECISION
,
FORMAT_TYPE_CHAR
,
FORMAT_TYPE_STR
,
FORMAT_TYPE_PTR
,
FORMAT_TYPE_PERCENT_CHAR
,
FORMAT_TYPE_INVALID
,
FORMAT_TYPE_LONG_LONG
,
FORMAT_TYPE_ULONG
,
FORMAT_TYPE_LONG
,
FORMAT_TYPE_USHORT
,
FORMAT_TYPE_SHORT
,
FORMAT_TYPE_UINT
,
FORMAT_TYPE_INT
,
FORMAT_TYPE_NRCHARS
,
FORMAT_TYPE_SIZE_T
,
FORMAT_TYPE_PTRDIFF
};
struct
printf_spec
{
enum
format_type
type
;
int
flags
;
/* flags to number() */
int
field_width
;
/* width of output field */
int
base
;
int
precision
;
/* # of digits/chars */
int
qualifier
;
};
static
char
*
number
(
char
*
buf
,
char
*
end
,
unsigned
long
long
num
,
struct
printf_spec
spec
)
{
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */
static
const
char
digits
[
16
]
=
"0123456789ABCDEF"
;
/* "GHIJKLMNOPQRSTUVWXYZ"; */
...
...
@@ -404,32 +435,32 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
char
tmp
[
66
];
char
sign
;
char
locase
;
int
need_pfx
=
((
type
&
SPECIAL
)
&&
base
!=
10
);
int
need_pfx
=
((
spec
.
flags
&
SPECIAL
)
&&
spec
.
base
!=
10
);
int
i
;
/* locase = 0 or 0x20. ORing digits or letters with 'locase'
* produces same digits or (maybe lowercased) letters */
locase
=
(
type
&
SMALL
);
if
(
type
&
LEFT
)
type
&=
~
ZEROPAD
;
locase
=
(
spec
.
flags
&
SMALL
);
if
(
spec
.
flags
&
LEFT
)
spec
.
flags
&=
~
ZEROPAD
;
sign
=
0
;
if
(
type
&
SIGN
)
{
if
(
spec
.
flags
&
SIGN
)
{
if
((
signed
long
long
)
num
<
0
)
{
sign
=
'-'
;
num
=
-
(
signed
long
long
)
num
;
s
ize
--
;
}
else
if
(
type
&
PLUS
)
{
s
pec
.
field_width
--
;
}
else
if
(
spec
.
flags
&
PLUS
)
{
sign
=
'+'
;
s
ize
--
;
}
else
if
(
type
&
SPACE
)
{
s
pec
.
field_width
--
;
}
else
if
(
spec
.
flags
&
SPACE
)
{
sign
=
' '
;
s
ize
--
;
s
pec
.
field_width
--
;
}
}
if
(
need_pfx
)
{
s
ize
--
;
if
(
base
==
16
)
s
ize
--
;
s
pec
.
field_width
--
;
if
(
spec
.
base
==
16
)
s
pec
.
field_width
--
;
}
/* generate full string in tmp[], in reverse order */
...
...
@@ -441,10 +472,10 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
tmp[i++] = (digits[do_div(num,base)] | locase);
} while (num != 0);
*/
else
if
(
base
!=
10
)
{
/* 8 or 16 */
int
mask
=
base
-
1
;
else
if
(
spec
.
base
!=
10
)
{
/* 8 or 16 */
int
mask
=
spec
.
base
-
1
;
int
shift
=
3
;
if
(
base
==
16
)
shift
=
4
;
if
(
spec
.
base
==
16
)
shift
=
4
;
do
{
tmp
[
i
++
]
=
(
digits
[((
unsigned
char
)
num
)
&
mask
]
|
locase
);
num
>>=
shift
;
...
...
@@ -454,12 +485,12 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
}
/* printing 100 using %2d gives "100", not "00" */
if
(
i
>
precision
)
precision
=
i
;
if
(
i
>
spec
.
precision
)
spec
.
precision
=
i
;
/* leading space padding */
s
ize
-=
precision
;
if
(
!
(
type
&
(
ZEROPAD
+
LEFT
)))
{
while
(
--
s
ize
>=
0
)
{
s
pec
.
field_width
-=
spec
.
precision
;
if
(
!
(
spec
.
flags
&
(
ZEROPAD
+
LEFT
)))
{
while
(
--
s
pec
.
field_width
>=
0
)
{
if
(
buf
<
end
)
*
buf
=
' '
;
++
buf
;
...
...
@@ -476,23 +507,23 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
if
(
buf
<
end
)
*
buf
=
'0'
;
++
buf
;
if
(
base
==
16
)
{
if
(
spec
.
base
==
16
)
{
if
(
buf
<
end
)
*
buf
=
(
'X'
|
locase
);
++
buf
;
}
}
/* zero or space padding */
if
(
!
(
type
&
LEFT
))
{
char
c
=
(
type
&
ZEROPAD
)
?
'0'
:
' '
;
while
(
--
s
ize
>=
0
)
{
if
(
!
(
spec
.
flags
&
LEFT
))
{
char
c
=
(
spec
.
flags
&
ZEROPAD
)
?
'0'
:
' '
;
while
(
--
s
pec
.
field_width
>=
0
)
{
if
(
buf
<
end
)
*
buf
=
c
;
++
buf
;
}
}
/* hmm even more zero padding? */
while
(
i
<=
--
precision
)
{
while
(
i
<=
--
spec
.
precision
)
{
if
(
buf
<
end
)
*
buf
=
'0'
;
++
buf
;
...
...
@@ -504,7 +535,7 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
++
buf
;
}
/* trailing space padding */
while
(
--
s
ize
>=
0
)
{
while
(
--
s
pec
.
field_width
>=
0
)
{
if
(
buf
<
end
)
*
buf
=
' '
;
++
buf
;
...
...
@@ -512,17 +543,17 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
return
buf
;
}
static
char
*
string
(
char
*
buf
,
char
*
end
,
char
*
s
,
int
field_width
,
int
precision
,
int
flags
)
static
char
*
string
(
char
*
buf
,
char
*
end
,
char
*
s
,
struct
printf_spec
spec
)
{
int
len
,
i
;
if
((
unsigned
long
)
s
<
PAGE_SIZE
)
s
=
"<NULL>"
;
len
=
strnlen
(
s
,
precision
);
len
=
strnlen
(
s
,
spec
.
precision
);
if
(
!
(
flags
&
LEFT
))
{
while
(
len
<
field_width
--
)
{
if
(
!
(
spec
.
flags
&
LEFT
))
{
while
(
len
<
spec
.
field_width
--
)
{
if
(
buf
<
end
)
*
buf
=
' '
;
++
buf
;
...
...
@@ -533,7 +564,7 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio
*
buf
=
*
s
;
++
buf
;
++
s
;
}
while
(
len
<
field_width
--
)
{
while
(
len
<
spec
.
field_width
--
)
{
if
(
buf
<
end
)
*
buf
=
' '
;
++
buf
;
...
...
@@ -541,21 +572,24 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio
return
buf
;
}
static
char
*
symbol_string
(
char
*
buf
,
char
*
end
,
void
*
ptr
,
int
field_width
,
int
precision
,
int
flags
)
static
char
*
symbol_string
(
char
*
buf
,
char
*
end
,
void
*
ptr
,
struct
printf_spec
spec
)
{
unsigned
long
value
=
(
unsigned
long
)
ptr
;
#ifdef CONFIG_KALLSYMS
char
sym
[
KSYM_SYMBOL_LEN
];
sprint_symbol
(
sym
,
value
);
return
string
(
buf
,
end
,
sym
,
field_width
,
precision
,
flags
);
return
string
(
buf
,
end
,
sym
,
spec
);
#else
field_width
=
2
*
sizeof
(
void
*
);
flags
|=
SPECIAL
|
SMALL
|
ZEROPAD
;
return
number
(
buf
,
end
,
value
,
16
,
field_width
,
precision
,
flags
);
spec
.
field_width
=
2
*
sizeof
(
void
*
);
spec
.
flags
|=
SPECIAL
|
SMALL
|
ZEROPAD
;
spec
.
base
=
16
;
return
number
(
buf
,
end
,
value
,
spec
);
#endif
}
static
char
*
resource_string
(
char
*
buf
,
char
*
end
,
struct
resource
*
res
,
int
field_width
,
int
precision
,
int
flags
)
static
char
*
resource_string
(
char
*
buf
,
char
*
end
,
struct
resource
*
res
,
struct
printf_spec
spec
)
{
#ifndef IO_RSRC_PRINTK_SIZE
#define IO_RSRC_PRINTK_SIZE 4
...
...
@@ -564,7 +598,11 @@ static char *resource_string(char *buf, char *end, struct resource *res, int fie
#ifndef MEM_RSRC_PRINTK_SIZE
#define MEM_RSRC_PRINTK_SIZE 8
#endif
struct
printf_spec
num_spec
=
{
.
base
=
16
,
.
precision
=
-
1
,
.
flags
=
SPECIAL
|
SMALL
|
ZEROPAD
,
};
/* room for the actual numbers, the two "0x", -, [, ] and the final zero */
char
sym
[
4
*
sizeof
(
resource_size_t
)
+
8
];
char
*
p
=
sym
,
*
pend
=
sym
+
sizeof
(
sym
);
...
...
@@ -576,17 +614,18 @@ static char *resource_string(char *buf, char *end, struct resource *res, int fie
size
=
MEM_RSRC_PRINTK_SIZE
;
*
p
++
=
'['
;
p
=
number
(
p
,
pend
,
res
->
start
,
16
,
size
,
-
1
,
SPECIAL
|
SMALL
|
ZEROPAD
);
num_spec
.
field_width
=
size
;
p
=
number
(
p
,
pend
,
res
->
start
,
num_spec
);
*
p
++
=
'-'
;
p
=
number
(
p
,
pend
,
res
->
end
,
16
,
size
,
-
1
,
SPECIAL
|
SMALL
|
ZEROPAD
);
p
=
number
(
p
,
pend
,
res
->
end
,
num_spec
);
*
p
++
=
']'
;
*
p
=
0
;
return
string
(
buf
,
end
,
sym
,
field_width
,
precision
,
flags
);
return
string
(
buf
,
end
,
sym
,
spec
);
}
static
char
*
mac_address_string
(
char
*
buf
,
char
*
end
,
u8
*
addr
,
int
field_width
,
int
precision
,
int
flags
)
static
char
*
mac_address_string
(
char
*
buf
,
char
*
end
,
u8
*
addr
,
struct
printf_spec
spec
)
{
char
mac_addr
[
6
*
3
];
/* (6 * 2 hex digits), 5 colons and trailing zero */
char
*
p
=
mac_addr
;
...
...
@@ -594,16 +633,17 @@ static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
for
(
i
=
0
;
i
<
6
;
i
++
)
{
p
=
pack_hex_byte
(
p
,
addr
[
i
]);
if
(
!
(
flags
&
SPECIAL
)
&&
i
!=
5
)
if
(
!
(
spec
.
flags
&
SPECIAL
)
&&
i
!=
5
)
*
p
++
=
':'
;
}
*
p
=
'\0'
;
spec
.
flags
&=
~
SPECIAL
;
return
string
(
buf
,
end
,
mac_addr
,
field_width
,
precision
,
flags
&
~
SPECIAL
);
return
string
(
buf
,
end
,
mac_addr
,
spec
);
}
static
char
*
ip6_addr_string
(
char
*
buf
,
char
*
end
,
u8
*
addr
,
int
field_width
,
int
precision
,
int
flags
)
static
char
*
ip6_addr_string
(
char
*
buf
,
char
*
end
,
u8
*
addr
,
struct
printf_spec
spec
)
{
char
ip6_addr
[
8
*
5
];
/* (8 * 4 hex digits), 7 colons and trailing zero */
char
*
p
=
ip6_addr
;
...
...
@@ -612,16 +652,17 @@ static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
for
(
i
=
0
;
i
<
8
;
i
++
)
{
p
=
pack_hex_byte
(
p
,
addr
[
2
*
i
]);
p
=
pack_hex_byte
(
p
,
addr
[
2
*
i
+
1
]);
if
(
!
(
flags
&
SPECIAL
)
&&
i
!=
7
)
if
(
!
(
spec
.
flags
&
SPECIAL
)
&&
i
!=
7
)
*
p
++
=
':'
;
}
*
p
=
'\0'
;
spec
.
flags
&=
~
SPECIAL
;
return
string
(
buf
,
end
,
ip6_addr
,
field_width
,
precision
,
flags
&
~
SPECIAL
);
return
string
(
buf
,
end
,
ip6_addr
,
spec
);
}
static
char
*
ip4_addr_string
(
char
*
buf
,
char
*
end
,
u8
*
addr
,
int
field_width
,
int
precision
,
int
flags
)
static
char
*
ip4_addr_string
(
char
*
buf
,
char
*
end
,
u8
*
addr
,
struct
printf_spec
spec
)
{
char
ip4_addr
[
4
*
4
];
/* (4 * 3 decimal digits), 3 dots and trailing zero */
char
temp
[
3
];
/* hold each IP quad in reverse order */
...
...
@@ -637,8 +678,9 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
*
p
++
=
'.'
;
}
*
p
=
'\0'
;
spec
.
flags
&=
~
SPECIAL
;
return
string
(
buf
,
end
,
ip4_addr
,
field_width
,
precision
,
flags
&
~
SPECIAL
);
return
string
(
buf
,
end
,
ip4_addr
,
spec
);
}
/*
...
...
@@ -663,41 +705,234 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
* function pointers are really function descriptors, which contain a
* pointer to the real address.
*/
static
char
*
pointer
(
const
char
*
fmt
,
char
*
buf
,
char
*
end
,
void
*
ptr
,
int
field_width
,
int
precision
,
int
flags
)
static
char
*
pointer
(
const
char
*
fmt
,
char
*
buf
,
char
*
end
,
void
*
ptr
,
struct
printf_spec
spec
)
{
if
(
!
ptr
)
return
string
(
buf
,
end
,
"(null)"
,
field_width
,
precision
,
flags
);
return
string
(
buf
,
end
,
"(null)"
,
spec
);
switch
(
*
fmt
)
{
case
'F'
:
ptr
=
dereference_function_descriptor
(
ptr
);
/* Fallthrough */
case
'S'
:
return
symbol_string
(
buf
,
end
,
ptr
,
field_width
,
precision
,
flags
);
return
symbol_string
(
buf
,
end
,
ptr
,
spec
);
case
'R'
:
return
resource_string
(
buf
,
end
,
ptr
,
field_width
,
precision
,
flags
);
return
resource_string
(
buf
,
end
,
ptr
,
spec
);
case
'm'
:
flags
|=
SPECIAL
;
spec
.
flags
|=
SPECIAL
;
/* Fallthrough */
case
'M'
:
return
mac_address_string
(
buf
,
end
,
ptr
,
field_width
,
precision
,
flags
);
return
mac_address_string
(
buf
,
end
,
ptr
,
spec
);
case
'i'
:
flags
|=
SPECIAL
;
spec
.
flags
|=
SPECIAL
;
/* Fallthrough */
case
'I'
:
if
(
fmt
[
1
]
==
'6'
)
return
ip6_addr_string
(
buf
,
end
,
ptr
,
field_width
,
precision
,
flags
);
return
ip6_addr_string
(
buf
,
end
,
ptr
,
spec
);
if
(
fmt
[
1
]
==
'4'
)
return
ip4_addr_string
(
buf
,
end
,
ptr
,
field_width
,
precision
,
flags
);
flags
&=
~
SPECIAL
;
return
ip4_addr_string
(
buf
,
end
,
ptr
,
spec
);
spec
.
flags
&=
~
SPECIAL
;
break
;
}
spec
.
flags
|=
SMALL
;
if
(
spec
.
field_width
==
-
1
)
{
spec
.
field_width
=
2
*
sizeof
(
void
*
);
spec
.
flags
|=
ZEROPAD
;
}
spec
.
base
=
16
;
return
number
(
buf
,
end
,
(
unsigned
long
)
ptr
,
spec
);
}
/*
* Helper function to decode printf style format.
* Each call decode a token from the format and return the
* number of characters read (or likely the delta where it wants
* to go on the next call).
* The decoded token is returned through the parameters
*
* 'h', 'l', or 'L' for integer fields
* 'z' support added 23/7/1999 S.H.
* 'z' changed to 'Z' --davidm 1/25/99
* 't' added for ptrdiff_t
*
* @fmt: the format string
* @type of the token returned
* @flags: various flags such as +, -, # tokens..
* @field_width: overwritten width
* @base: base of the number (octal, hex, ...)
* @precision: precision of a number
* @qualifier: qualifier of a number (long, size_t, ...)
*/
static
int
format_decode
(
const
char
*
fmt
,
struct
printf_spec
*
spec
)
{
const
char
*
start
=
fmt
;
bool
sign
=
false
;
/* we finished early by reading the field width */
if
(
spec
->
type
==
FORMAT_TYPE_WITDH
)
{
if
(
spec
->
field_width
<
0
)
{
spec
->
field_width
=
-
spec
->
field_width
;
spec
->
flags
|=
LEFT
;
}
spec
->
type
=
FORMAT_TYPE_NONE
;
goto
precision
;
}
/* we finished early by reading the precision */
if
(
spec
->
type
==
FORMAT_TYPE_PRECISION
)
{
if
(
spec
->
precision
<
0
)
spec
->
precision
=
0
;
spec
->
type
=
FORMAT_TYPE_NONE
;
goto
qualifier
;
}
/* By default */
spec
->
type
=
FORMAT_TYPE_NONE
;
for
(;
*
fmt
;
++
fmt
)
{
if
(
*
fmt
==
'%'
)
break
;
}
/* Return the current non-format string */
if
(
fmt
!=
start
||
!*
fmt
)
return
fmt
-
start
;
/* Process flags */
spec
->
flags
=
0
;
while
(
1
)
{
/* this also skips first '%' */
bool
found
=
true
;
++
fmt
;
switch
(
*
fmt
)
{
case
'-'
:
spec
->
flags
|=
LEFT
;
break
;
case
'+'
:
spec
->
flags
|=
PLUS
;
break
;
case
' '
:
spec
->
flags
|=
SPACE
;
break
;
case
'#'
:
spec
->
flags
|=
SPECIAL
;
break
;
case
'0'
:
spec
->
flags
|=
ZEROPAD
;
break
;
default:
found
=
false
;
}
if
(
!
found
)
break
;
}
/* get field width */
spec
->
field_width
=
-
1
;
if
(
isdigit
(
*
fmt
))
spec
->
field_width
=
skip_atoi
(
&
fmt
);
else
if
(
*
fmt
==
'*'
)
{
/* it's the next argument */
spec
->
type
=
FORMAT_TYPE_WITDH
;
return
++
fmt
-
start
;
}
precision:
/* get the precision */
spec
->
precision
=
-
1
;
if
(
*
fmt
==
'.'
)
{
++
fmt
;
if
(
isdigit
(
*
fmt
))
{
spec
->
precision
=
skip_atoi
(
&
fmt
);
if
(
spec
->
precision
<
0
)
spec
->
precision
=
0
;
}
else
if
(
*
fmt
==
'*'
)
{
/* it's the next argument */
spec
->
type
=
FORMAT_TYPE_WITDH
;
return
++
fmt
-
start
;
}
}
qualifier:
/* get the conversion qualifier */
spec
->
qualifier
=
-
1
;
if
(
*
fmt
==
'h'
||
*
fmt
==
'l'
||
*
fmt
==
'L'
||
*
fmt
==
'Z'
||
*
fmt
==
'z'
||
*
fmt
==
't'
)
{
spec
->
qualifier
=
*
fmt
;
++
fmt
;
if
(
spec
->
qualifier
==
'l'
&&
*
fmt
==
'l'
)
{
spec
->
qualifier
=
'L'
;
++
fmt
;
}
}
/* default base */
spec
->
base
=
10
;
switch
(
*
fmt
)
{
case
'c'
:
spec
->
type
=
FORMAT_TYPE_CHAR
;
return
++
fmt
-
start
;
case
's'
:
spec
->
type
=
FORMAT_TYPE_STR
;
return
++
fmt
-
start
;
case
'p'
:
spec
->
type
=
FORMAT_TYPE_PTR
;
return
fmt
-
start
;
/* skip alnum */
case
'n'
:
spec
->
type
=
FORMAT_TYPE_NRCHARS
;
return
++
fmt
-
start
;
case
'%'
:
spec
->
type
=
FORMAT_TYPE_PERCENT_CHAR
;
return
++
fmt
-
start
;
/* integer number formats - set up the flags and "break" */
case
'o'
:
spec
->
base
=
8
;
break
;
case
'x'
:
spec
->
flags
|=
SMALL
;
case
'X'
:
spec
->
base
=
16
;
break
;
case
'd'
:
case
'i'
:
sign
=
true
;
case
'u'
:
break
;
default:
spec
->
type
=
FORMAT_TYPE_INVALID
;
return
fmt
-
start
;
}
flags
|=
SMALL
;
if
(
field_width
==
-
1
)
{
field_width
=
2
*
sizeof
(
void
*
);
flags
|=
ZEROPAD
;
if
(
spec
->
qualifier
==
'L'
)
spec
->
type
=
FORMAT_TYPE_LONG_LONG
;
else
if
(
spec
->
qualifier
==
'l'
)
{
if
(
sign
)
spec
->
type
=
FORMAT_TYPE_LONG
;
else
spec
->
type
=
FORMAT_TYPE_ULONG
;
}
else
if
(
spec
->
qualifier
==
'Z'
||
spec
->
qualifier
==
'z'
)
{
spec
->
type
=
FORMAT_TYPE_SIZE_T
;
}
else
if
(
spec
->
qualifier
==
't'
)
{
spec
->
type
=
FORMAT_TYPE_PTRDIFF
;
}
else
if
(
spec
->
qualifier
==
'h'
)
{
if
(
sign
)
spec
->
type
=
FORMAT_TYPE_SHORT
;
else
spec
->
type
=
FORMAT_TYPE_USHORT
;
}
else
{
if
(
sign
)
spec
->
type
=
FORMAT_TYPE_INT
;
else
spec
->
type
=
FORMAT_TYPE_UINT
;
}
return
number
(
buf
,
end
,
(
unsigned
long
)
ptr
,
16
,
field_width
,
precision
,
flags
);
return
++
fmt
-
start
;
}
/**
...
...
@@ -726,18 +961,9 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field
int
vsnprintf
(
char
*
buf
,
size_t
size
,
const
char
*
fmt
,
va_list
args
)
{
unsigned
long
long
num
;
int
base
;
char
*
str
,
*
end
,
c
;
int
flags
;
/* flags to number() */
int
field_width
;
/* width of output field */
int
precision
;
/* min. # of digits for integers; max
number of chars for from string */
int
qualifier
;
/* 'h', 'l', or 'L' for integer fields */
/* 'z' support added 23/7/1999 S.H. */
/* 'z' changed to 'Z' --davidm 1/25/99 */
/* 't' added for ptrdiff_t */
int
read
;
struct
printf_spec
spec
=
{
0
};
/* Reject out-of-range values early. Large positive sizes are
used for unknown buffer sizes. */
...
...
@@ -758,142 +984,71 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
size
=
end
-
buf
;
}
for
(;
*
fmt
;
++
fmt
)
{
if
(
*
fmt
!=
'%'
)
{
if
(
str
<
end
)
*
str
=
*
fmt
;
++
str
;
continue
;
}
while
(
*
fmt
)
{
const
char
*
old_fmt
=
fmt
;
/* process flags */
flags
=
0
;
repeat:
++
fmt
;
/* this also skips first '%' */
switch
(
*
fmt
)
{
case
'-'
:
flags
|=
LEFT
;
goto
repeat
;
case
'+'
:
flags
|=
PLUS
;
goto
repeat
;
case
' '
:
flags
|=
SPACE
;
goto
repeat
;
case
'#'
:
flags
|=
SPECIAL
;
goto
repeat
;
case
'0'
:
flags
|=
ZEROPAD
;
goto
repeat
;
}
read
=
format_decode
(
fmt
,
&
spec
);
/* get field width */
field_width
=
-
1
;
if
(
isdigit
(
*
fmt
))
field_width
=
skip_atoi
(
&
fmt
);
else
if
(
*
fmt
==
'*'
)
{
++
fmt
;
/* it's the next argument */
field_width
=
va_arg
(
args
,
int
);
if
(
field_width
<
0
)
{
field_width
=
-
field_width
;
flags
|=
LEFT
;
}
}
fmt
+=
read
;
/* get the precision */
precision
=
-
1
;
if
(
*
fmt
==
'.'
)
{
++
fmt
;
if
(
isdigit
(
*
fmt
))
precision
=
skip_atoi
(
&
fmt
);
else
if
(
*
fmt
==
'*'
)
{
++
fmt
;
/* it's the next argument */
precision
=
va_arg
(
args
,
int
);
switch
(
spec
.
type
)
{
case
FORMAT_TYPE_NONE
:
{
int
copy
=
read
;
if
(
str
<
end
)
{
if
(
copy
>
end
-
str
)
copy
=
end
-
str
;
memcpy
(
str
,
old_fmt
,
copy
);
}
if
(
precision
<
0
)
precision
=
0
;
str
+=
read
;
break
;
}
/* get the conversion qualifier */
qualifier
=
-
1
;
if
(
*
fmt
==
'h'
||
*
fmt
==
'l'
||
*
fmt
==
'L'
||
*
fmt
==
'Z'
||
*
fmt
==
'z'
||
*
fmt
==
't'
)
{
qualifier
=
*
fmt
;
++
fmt
;
if
(
qualifier
==
'l'
&&
*
fmt
==
'l'
)
{
qualifier
=
'L'
;
++
fmt
;
}
}
case
FORMAT_TYPE_WITDH
:
spec
.
field_width
=
va_arg
(
args
,
int
);
break
;
/* default base */
base
=
10
;
case
FORMAT_TYPE_PRECISION
:
spec
.
precision
=
va_arg
(
args
,
int
);
break
;
switch
(
*
fmt
)
{
case
'c'
:
if
(
!
(
flags
&
LEFT
))
{
while
(
--
field_width
>
0
)
{
case
FORMAT_TYPE_CHAR
:
if
(
!
(
spec
.
flags
&
LEFT
))
{
while
(
--
spec
.
field_width
>
0
)
{
if
(
str
<
end
)
*
str
=
' '
;
++
str
;
}
}
c
=
(
unsigned
char
)
va_arg
(
args
,
int
);
if
(
str
<
end
)
*
str
=
c
;
++
str
;
while
(
--
field_width
>
0
)
{
while
(
--
spec
.
field_width
>
0
)
{
if
(
str
<
end
)
*
str
=
' '
;
++
str
;
}
continue
;
break
;
case
's'
:
str
=
string
(
str
,
end
,
va_arg
(
args
,
char
*
),
field_width
,
precision
,
flags
);
continue
;
case
FORMAT_TYPE_STR
:
str
=
string
(
str
,
end
,
va_arg
(
args
,
char
*
),
spec
);
break
;
case
'p'
:
str
=
pointer
(
fmt
+
1
,
str
,
end
,
va_arg
(
args
,
void
*
),
field_width
,
precision
,
flags
);
/* Skip all alphanumeric pointer suffixes */
while
(
isalnum
(
fmt
[
1
]))
case
FORMAT_TYPE_PTR
:
str
=
pointer
(
fmt
+
1
,
str
,
end
,
va_arg
(
args
,
void
*
),
spec
);
while
(
isalnum
(
*
fmt
))
fmt
++
;
continue
;
case
'n'
:
/* FIXME:
* What does C99 say about the overflow case here? */
if
(
qualifier
==
'l'
)
{
long
*
ip
=
va_arg
(
args
,
long
*
);
*
ip
=
(
str
-
buf
);
}
else
if
(
qualifier
==
'Z'
||
qualifier
==
'z'
)
{
size_t
*
ip
=
va_arg
(
args
,
size_t
*
);
*
ip
=
(
str
-
buf
);
}
else
{
int
*
ip
=
va_arg
(
args
,
int
*
);
*
ip
=
(
str
-
buf
);
}
continue
;
break
;
case
'%'
:
case
FORMAT_TYPE_PERCENT_CHAR
:
if
(
str
<
end
)
*
str
=
'%'
;
++
str
;
continue
;
/* integer number formats - set up the flags and "break" */
case
'o'
:
base
=
8
;
break
;
case
'x'
:
flags
|=
SMALL
;
case
'X'
:
base
=
16
;
break
;
case
'd'
:
case
'i'
:
flags
|=
SIGN
;
case
'u'
:
break
;
default:
case
FORMAT_TYPE_INVALID
:
if
(
str
<
end
)
*
str
=
'%'
;
++
str
;
...
...
@@ -904,38 +1059,69 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
}
else
{
--
fmt
;
}
continue
;
break
;
case
FORMAT_TYPE_NRCHARS
:
{
int
qualifier
=
spec
.
qualifier
;
if
(
qualifier
==
'l'
)
{
long
*
ip
=
va_arg
(
args
,
long
*
);
*
ip
=
(
str
-
buf
);
}
else
if
(
qualifier
==
'Z'
||
qualifier
==
'z'
)
{
size_t
*
ip
=
va_arg
(
args
,
size_t
*
);
*
ip
=
(
str
-
buf
);
}
else
{
int
*
ip
=
va_arg
(
args
,
int
*
);
*
ip
=
(
str
-
buf
);
}
break
;
}
if
(
qualifier
==
'L'
)
default:
switch
(
spec
.
type
)
{
case
FORMAT_TYPE_LONG_LONG
:
num
=
va_arg
(
args
,
long
long
);
else
if
(
qualifier
==
'l'
)
{
break
;
case
FORMAT_TYPE_ULONG
:
num
=
va_arg
(
args
,
unsigned
long
);
if
(
flags
&
SIGN
)
num
=
(
signed
long
)
num
;
}
else
if
(
qualifier
==
'Z'
||
qualifier
==
'z'
)
{
break
;
case
FORMAT_TYPE_LONG
:
num
=
va_arg
(
args
,
long
);
break
;
case
FORMAT_TYPE_SIZE_T
:
num
=
va_arg
(
args
,
size_t
);
}
else
if
(
qualifier
==
't'
)
{
break
;
case
FORMAT_TYPE_PTRDIFF
:
num
=
va_arg
(
args
,
ptrdiff_t
);
}
else
if
(
qualifier
==
'h'
)
{
break
;
case
FORMAT_TYPE_USHORT
:
num
=
(
unsigned
short
)
va_arg
(
args
,
int
);
if
(
flags
&
SIGN
)
num
=
(
signed
short
)
num
;
}
else
{
break
;
case
FORMAT_TYPE_SHORT
:
num
=
(
short
)
va_arg
(
args
,
int
);
break
;
case
FORMAT_TYPE_UINT
:
num
=
va_arg
(
args
,
unsigned
int
);
break
;
default:
num
=
va_arg
(
args
,
unsigned
int
);
if
(
flags
&
SIGN
)
num
=
(
signed
int
)
num
;
}
str
=
number
(
str
,
end
,
num
,
base
,
field_width
,
precision
,
flags
);
str
=
number
(
str
,
end
,
num
,
spec
);
}
}
if
(
size
>
0
)
{
if
(
str
<
end
)
*
str
=
'\0'
;
else
end
[
-
1
]
=
'\0'
;
}
/* the trailing null byte doesn't count towards the total */
return
str
-
buf
;
}
EXPORT_SYMBOL
(
vsnprintf
);
...
...
@@ -1058,6 +1244,372 @@ int sprintf(char * buf, const char *fmt, ...)
}
EXPORT_SYMBOL
(
sprintf
);
#ifdef CONFIG_BINARY_PRINTF
/*
* bprintf service:
* vbin_printf() - VA arguments to binary data
* bstr_printf() - Binary data to text string
*/
/**
* vbin_printf - Parse a format string and place args' binary value in a buffer
* @bin_buf: The buffer to place args' binary value
* @size: The size of the buffer(by words(32bits), not characters)
* @fmt: The format string to use
* @args: Arguments for the format string
*
* The format follows C99 vsnprintf, except %n is ignored, and its argument
* is skiped.
*
* The return value is the number of words(32bits) which would be generated for
* the given input.
*
* NOTE:
* If the return value is greater than @size, the resulting bin_buf is NOT
* valid for bstr_printf().
*/
int
vbin_printf
(
u32
*
bin_buf
,
size_t
size
,
const
char
*
fmt
,
va_list
args
)
{
struct
printf_spec
spec
=
{
0
};
char
*
str
,
*
end
;
int
read
;
str
=
(
char
*
)
bin_buf
;
end
=
(
char
*
)(
bin_buf
+
size
);
#define save_arg(type) \
do { \
if (sizeof(type) == 8) { \
unsigned long long value; \
str = PTR_ALIGN(str, sizeof(u32)); \
value = va_arg(args, unsigned long long); \
if (str + sizeof(type) <= end) { \
*(u32 *)str = *(u32 *)&value; \
*(u32 *)(str + 4) = *((u32 *)&value + 1); \
} \
} else { \
unsigned long value; \
str = PTR_ALIGN(str, sizeof(type)); \
value = va_arg(args, int); \
if (str + sizeof(type) <= end) \
*(typeof(type) *)str = (type)value; \
} \
str += sizeof(type); \
} while (0)
while
(
*
fmt
)
{
read
=
format_decode
(
fmt
,
&
spec
);
fmt
+=
read
;
switch
(
spec
.
type
)
{
case
FORMAT_TYPE_NONE
:
break
;
case
FORMAT_TYPE_WITDH
:
case
FORMAT_TYPE_PRECISION
:
save_arg
(
int
);
break
;
case
FORMAT_TYPE_CHAR
:
save_arg
(
char
);
break
;
case
FORMAT_TYPE_STR
:
{
const
char
*
save_str
=
va_arg
(
args
,
char
*
);
size_t
len
;
if
((
unsigned
long
)
save_str
>
(
unsigned
long
)
-
PAGE_SIZE
||
(
unsigned
long
)
save_str
<
PAGE_SIZE
)
save_str
=
"<NULL>"
;
len
=
strlen
(
save_str
);
if
(
str
+
len
+
1
<
end
)
memcpy
(
str
,
save_str
,
len
+
1
);
str
+=
len
+
1
;
break
;
}
case
FORMAT_TYPE_PTR
:
save_arg
(
void
*
);
/* skip all alphanumeric pointer suffixes */
while
(
isalnum
(
*
fmt
))
fmt
++
;
break
;
case
FORMAT_TYPE_PERCENT_CHAR
:
break
;
case
FORMAT_TYPE_INVALID
:
if
(
!*
fmt
)
--
fmt
;
break
;
case
FORMAT_TYPE_NRCHARS
:
{
/* skip %n 's argument */
int
qualifier
=
spec
.
qualifier
;
void
*
skip_arg
;
if
(
qualifier
==
'l'
)
skip_arg
=
va_arg
(
args
,
long
*
);
else
if
(
qualifier
==
'Z'
||
qualifier
==
'z'
)
skip_arg
=
va_arg
(
args
,
size_t
*
);
else
skip_arg
=
va_arg
(
args
,
int
*
);
break
;
}
default:
switch
(
spec
.
type
)
{
case
FORMAT_TYPE_LONG_LONG
:
save_arg
(
long
long
);
break
;
case
FORMAT_TYPE_ULONG
:
case
FORMAT_TYPE_LONG
:
save_arg
(
unsigned
long
);
break
;
case
FORMAT_TYPE_SIZE_T
:
save_arg
(
size_t
);
break
;
case
FORMAT_TYPE_PTRDIFF
:
save_arg
(
ptrdiff_t
);
break
;
case
FORMAT_TYPE_USHORT
:
case
FORMAT_TYPE_SHORT
:
save_arg
(
short
);
break
;
default:
save_arg
(
int
);
}
}
}
return
(
u32
*
)(
PTR_ALIGN
(
str
,
sizeof
(
u32
)))
-
bin_buf
;
#undef save_arg
}
EXPORT_SYMBOL_GPL
(
vbin_printf
);
/**
* bstr_printf - Format a string from binary arguments and place it in a buffer
* @buf: The buffer to place the result into
* @size: The size of the buffer, including the trailing null space
* @fmt: The format string to use
* @bin_buf: Binary arguments for the format string
*
* This function like C99 vsnprintf, but the difference is that vsnprintf gets
* arguments from stack, and bstr_printf gets arguments from @bin_buf which is
* a binary buffer that generated by vbin_printf.
*
* The format follows C99 vsnprintf, but has some extensions:
* %pS output the name of a text symbol
* %pF output the name of a function pointer
* %pR output the address range in a struct resource
* %n is ignored
*
* The return value is the number of characters which would
* be generated for the given input, excluding the trailing
* '\0', as per ISO C99. If you want to have the exact
* number of characters written into @buf as return value
* (not including the trailing '\0'), use vscnprintf(). If the
* return is greater than or equal to @size, the resulting
* string is truncated.
*/
int
bstr_printf
(
char
*
buf
,
size_t
size
,
const
char
*
fmt
,
const
u32
*
bin_buf
)
{
unsigned
long
long
num
;
char
*
str
,
*
end
,
c
;
const
char
*
args
=
(
const
char
*
)
bin_buf
;
struct
printf_spec
spec
=
{
0
};
if
(
unlikely
((
int
)
size
<
0
))
{
/* There can be only one.. */
static
char
warn
=
1
;
WARN_ON
(
warn
);
warn
=
0
;
return
0
;
}
str
=
buf
;
end
=
buf
+
size
;
#define get_arg(type) \
({ \
typeof(type) value; \
if (sizeof(type) == 8) { \
args = PTR_ALIGN(args, sizeof(u32)); \
*(u32 *)&value = *(u32 *)args; \
*((u32 *)&value + 1) = *(u32 *)(args + 4); \
} else { \
args = PTR_ALIGN(args, sizeof(type)); \
value = *(typeof(type) *)args; \
} \
args += sizeof(type); \
value; \
})
/* Make sure end is always >= buf */
if
(
end
<
buf
)
{
end
=
((
void
*
)
-
1
);
size
=
end
-
buf
;
}
while
(
*
fmt
)
{
int
read
;
const
char
*
old_fmt
=
fmt
;
read
=
format_decode
(
fmt
,
&
spec
);
fmt
+=
read
;
switch
(
spec
.
type
)
{
case
FORMAT_TYPE_NONE
:
{
int
copy
=
read
;
if
(
str
<
end
)
{
if
(
copy
>
end
-
str
)
copy
=
end
-
str
;
memcpy
(
str
,
old_fmt
,
copy
);
}
str
+=
read
;
break
;
}
case
FORMAT_TYPE_WITDH
:
spec
.
field_width
=
get_arg
(
int
);
break
;
case
FORMAT_TYPE_PRECISION
:
spec
.
precision
=
get_arg
(
int
);
break
;
case
FORMAT_TYPE_CHAR
:
if
(
!
(
spec
.
flags
&
LEFT
))
{
while
(
--
spec
.
field_width
>
0
)
{
if
(
str
<
end
)
*
str
=
' '
;
++
str
;
}
}
c
=
(
unsigned
char
)
get_arg
(
char
);
if
(
str
<
end
)
*
str
=
c
;
++
str
;
while
(
--
spec
.
field_width
>
0
)
{
if
(
str
<
end
)
*
str
=
' '
;
++
str
;
}
break
;
case
FORMAT_TYPE_STR
:
{
const
char
*
str_arg
=
args
;
size_t
len
=
strlen
(
str_arg
);
args
+=
len
+
1
;
str
=
string
(
str
,
end
,
(
char
*
)
str_arg
,
spec
);
break
;
}
case
FORMAT_TYPE_PTR
:
str
=
pointer
(
fmt
+
1
,
str
,
end
,
get_arg
(
void
*
),
spec
);
while
(
isalnum
(
*
fmt
))
fmt
++
;
break
;
case
FORMAT_TYPE_PERCENT_CHAR
:
if
(
str
<
end
)
*
str
=
'%'
;
++
str
;
break
;
case
FORMAT_TYPE_INVALID
:
if
(
str
<
end
)
*
str
=
'%'
;
++
str
;
if
(
*
fmt
)
{
if
(
str
<
end
)
*
str
=
*
fmt
;
++
str
;
}
else
{
--
fmt
;
}
break
;
case
FORMAT_TYPE_NRCHARS
:
/* skip */
break
;
default:
switch
(
spec
.
type
)
{
case
FORMAT_TYPE_LONG_LONG
:
num
=
get_arg
(
long
long
);
break
;
case
FORMAT_TYPE_ULONG
:
num
=
get_arg
(
unsigned
long
);
break
;
case
FORMAT_TYPE_LONG
:
num
=
get_arg
(
unsigned
long
);
break
;
case
FORMAT_TYPE_SIZE_T
:
num
=
get_arg
(
size_t
);
break
;
case
FORMAT_TYPE_PTRDIFF
:
num
=
get_arg
(
ptrdiff_t
);
break
;
case
FORMAT_TYPE_USHORT
:
num
=
get_arg
(
unsigned
short
);
break
;
case
FORMAT_TYPE_SHORT
:
num
=
get_arg
(
short
);
break
;
case
FORMAT_TYPE_UINT
:
num
=
get_arg
(
unsigned
int
);
break
;
default:
num
=
get_arg
(
int
);
}
str
=
number
(
str
,
end
,
num
,
spec
);
}
}
if
(
size
>
0
)
{
if
(
str
<
end
)
*
str
=
'\0'
;
else
end
[
-
1
]
=
'\0'
;
}
#undef get_arg
/* the trailing null byte doesn't count towards the total */
return
str
-
buf
;
}
EXPORT_SYMBOL_GPL
(
bstr_printf
);
/**
* bprintf - Parse a format string and place args' binary value in a buffer
* @bin_buf: The buffer to place args' binary value
* @size: The size of the buffer(by words(32bits), not characters)
* @fmt: The format string to use
* @...: Arguments for the format string
*
* The function returns the number of words(u32) written
* into @bin_buf.
*/
int
bprintf
(
u32
*
bin_buf
,
size_t
size
,
const
char
*
fmt
,
...)
{
va_list
args
;
int
ret
;
va_start
(
args
,
fmt
);
ret
=
vbin_printf
(
bin_buf
,
size
,
fmt
,
args
);
va_end
(
args
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
bprintf
);
#endif
/* CONFIG_BINARY_PRINTF */
/**
* vsscanf - Unformat a buffer into a list of arguments
* @buf: input buffer
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment