Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
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
Hide 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,184 +984,144 @@ 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
)
{
if
(
str
<
end
)
*
str
=
' '
;
++
str
;
}
}
c
=
(
unsigned
char
)
va_arg
(
args
,
int
);
if
(
str
<
end
)
*
str
=
c
;
++
str
;
while
(
--
field_width
>
0
)
{
case
FORMAT_TYPE_CHAR
:
if
(
!
(
spec
.
flags
&
LEFT
))
{
while
(
--
spec
.
field_width
>
0
)
{
if
(
str
<
end
)
*
str
=
' '
;
++
str
;
}
continue
;
case
's'
:
str
=
string
(
str
,
end
,
va_arg
(
args
,
char
*
),
field_width
,
precision
,
flags
);
continue
;
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
]))
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
;
case
'%'
:
}
}
c
=
(
unsigned
char
)
va_arg
(
args
,
int
);
if
(
str
<
end
)
*
str
=
c
;
++
str
;
while
(
--
spec
.
field_width
>
0
)
{
if
(
str
<
end
)
*
str
=
'
%
'
;
*
str
=
'
'
;
++
str
;
continue
;
}
break
;
/* integer number formats - set up the flags and "break" */
case
'o'
:
base
=
8
;
break
;
case
FORMAT_TYPE_STR
:
str
=
string
(
str
,
end
,
va_arg
(
args
,
char
*
),
spec
);
break
;
case
'x'
:
flags
|=
SMALL
;
case
'X'
:
base
=
16
;
break
;
case
FORMAT_TYPE_PTR
:
str
=
pointer
(
fmt
+
1
,
str
,
end
,
va_arg
(
args
,
void
*
),
spec
);
while
(
isalnum
(
*
fmt
))
fmt
++
;
break
;
case
'd'
:
case
'i'
:
flags
|=
SIGN
;
case
'u'
:
break
;
case
FORMAT_TYPE_PERCENT_CHAR
:
if
(
str
<
end
)
*
str
=
'%'
;
++
str
;
break
;
default:
case
FORMAT_TYPE_INVALID
:
if
(
str
<
end
)
*
str
=
'%'
;
++
str
;
if
(
*
fmt
)
{
if
(
str
<
end
)
*
str
=
'%'
;
*
str
=
*
fmt
;
++
str
;
if
(
*
fmt
)
{
if
(
str
<
end
)
*
str
=
*
fmt
;
++
str
;
}
else
{
--
fmt
;
}
continue
;
}
else
{
--
fmt
;
}
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'
)
num
=
va_arg
(
args
,
long
long
);
else
if
(
qualifier
==
'l'
)
{
num
=
va_arg
(
args
,
unsigned
long
);
if
(
flags
&
SIGN
)
num
=
(
signed
long
)
num
;
}
else
if
(
qualifier
==
'Z'
||
qualifier
==
'z'
)
{
num
=
va_arg
(
args
,
size_t
);
}
else
if
(
qualifier
==
't'
)
{
num
=
va_arg
(
args
,
ptrdiff_t
);
}
else
if
(
qualifier
==
'h'
)
{
num
=
(
unsigned
short
)
va_arg
(
args
,
int
);
if
(
flags
&
SIGN
)
num
=
(
signed
short
)
num
;
}
else
{
num
=
va_arg
(
args
,
unsigned
int
);
if
(
flags
&
SIGN
)
num
=
(
signed
int
)
num
;
default:
switch
(
spec
.
type
)
{
case
FORMAT_TYPE_LONG_LONG
:
num
=
va_arg
(
args
,
long
long
);
break
;
case
FORMAT_TYPE_ULONG
:
num
=
va_arg
(
args
,
unsigned
long
);
break
;
case
FORMAT_TYPE_LONG
:
num
=
va_arg
(
args
,
long
);
break
;
case
FORMAT_TYPE_SIZE_T
:
num
=
va_arg
(
args
,
size_t
);
break
;
case
FORMAT_TYPE_PTRDIFF
:
num
=
va_arg
(
args
,
ptrdiff_t
);
break
;
case
FORMAT_TYPE_USHORT
:
num
=
(
unsigned
short
)
va_arg
(
args
,
int
);
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
);
}
str
=
number
(
str
,
end
,
num
,
spec
);
}
str
=
number
(
str
,
end
,
num
,
base
,
field_width
,
precision
,
flags
);
}
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