]>
sourceware.org Git - systemtap.git/blob - runtime/vsprintf.c
3 * Copyright (C) 2006 Red Hat Inc.
4 * Based on code from the Linux kernel
5 * Copyright (C) 1991, 1992 Linus Torvalds
7 * This file is part of systemtap, and is free software. You can
8 * redistribute it and/or modify it under the terms of the GNU General
9 * Public License (GPL); either version 2, or (at your option) any
15 enum endian
{STP_NATIVE
=0, STP_LITTLE
, STP_BIG
};
16 static enum endian _stp_endian
= STP_NATIVE
;
18 static int skip_atoi(const char **s
)
22 i
= i
*10 + *((*s
)++) - '0';
26 enum print_flag
{STP_ZEROPAD
=1, STP_SIGN
=2, STP_PLUS
=4, STP_SPACE
=8, STP_LEFT
=16, STP_SPECIAL
=32, STP_LARGE
=64};
28 static char * number(char * buf
, char * end
, uint64_t num
, int base
, int size
, int precision
, enum print_flag type
)
32 static const char small_digits
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
33 static const char large_digits
[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
36 digits
= (type
& STP_LARGE
) ? large_digits
: small_digits
;
39 if (base
< 2 || base
> 36)
41 c
= (type
& STP_ZEROPAD
) ? '0' : ' ';
43 if (type
& STP_SIGN
) {
44 if ((int64_t) num
< 0) {
46 num
= - (int64_t) num
;
48 } else if (type
& STP_PLUS
) {
51 } else if (type
& STP_SPACE
) {
56 if (type
& STP_SPECIAL
) {
66 tmp
[i
++] = digits
[do_div(num
,base
)];
70 if (!(type
&(STP_ZEROPAD
+STP_LEFT
))) {
82 if (type
& STP_SPECIAL
) {
87 } else if (base
==16) {
96 if (!(type
& STP_LEFT
)) {
103 while (i
< precision
--) {
121 int _stp_vsnprintf(char *buf
, size_t size
, const char *fmt
, va_list args
)
128 enum print_flag flags
; /* flags to number() */
129 int field_width
; /* width of output field */
130 int precision
; /* min. # of digits for integers; max
131 number of chars for from string */
132 int qualifier
; /* 'h', 'l', or 'L' for integer fields */
133 char *write_len_ptr
= NULL
;
134 int write_len_width
= 0;
136 /* Reject out-of-range values early */
137 if (unlikely((int) size
< 0))
141 end
= buf
+ size
- 1;
143 for (; *fmt
; ++fmt
) {
154 ++fmt
; /* this also skips first '%' */
156 case '-': flags
|= STP_LEFT
; goto repeat
;
157 case '+': flags
|= STP_PLUS
; goto repeat
;
158 case ' ': flags
|= STP_SPACE
; goto repeat
;
159 case '#': flags
|= STP_SPECIAL
; goto repeat
;
160 case '0': flags
|= STP_ZEROPAD
; goto repeat
;
163 /* get field width */
166 field_width
= skip_atoi(&fmt
);
167 else if (*fmt
== '*') {
169 /* it's the next argument */
170 field_width
= va_arg(args
, int);
171 if (field_width
< 0) {
172 field_width
= -field_width
;
177 /* get the precision */
182 precision
= skip_atoi(&fmt
);
183 else if (*fmt
== '*') {
185 /* it's the next argument */
186 precision
= va_arg(args
, int);
192 /* get the conversion qualifier */
194 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L') {
197 if (qualifier
== 'l' && *fmt
== 'l') {
208 num
= va_arg(args
, int64_t);
209 switch(field_width
) {
212 *(int8_t *)str
= (int8_t)num
;
216 if (_stp_endian
!= STP_NATIVE
) {
217 if (_stp_endian
== STP_BIG
)
218 num
= cpu_to_be16(num
);
220 num
= cpu_to_le16(num
);
223 *(int16_t *)str
= (int16_t)num
;
227 if (_stp_endian
!= STP_NATIVE
) {
228 if (_stp_endian
== STP_BIG
)
229 num
= cpu_to_be64(num
);
231 num
= cpu_to_le64(num
);
235 *(int64_t *)str
= num
;
239 default: // "%4b" by default
240 if (_stp_endian
!= STP_NATIVE
) {
241 if (_stp_endian
== STP_BIG
)
242 num
= cpu_to_be32(num
);
244 num
= cpu_to_le32(num
);
248 *(int32_t *)str
= num
;
255 s
= va_arg(args
, char *);
256 if ((unsigned long)s
< PAGE_SIZE
)
259 len
= strnlen(s
, precision
);
261 if (!(flags
& STP_LEFT
)) {
262 while (len
< field_width
--) {
268 for (i
= 0; i
< len
; ++i
) {
273 while (len
< field_width
--) {
278 if(flags
& STP_ZEROPAD
) {
298 len
= 2*sizeof(void *) + 2;
299 flags
|= STP_ZEROPAD
;
301 if (field_width
== -1)
304 if (!(flags
& STP_LEFT
)) {
305 while (len
< field_width
) {
321 str
= number(str
, end
,
322 (unsigned long) va_arg(args
, int64_t),
323 16, field_width
, field_width
, flags
);
329 if (field_width
== 1)
331 else if (field_width
== 4)
333 str
+= write_len_width
;
342 /* integer number formats - set up the flags and "break" */
348 if (!(flags
& STP_LEFT
)) {
349 while (--field_width
> 0) {
355 c
= (unsigned char) va_arg(args
, int);
359 while (--field_width
> 0) {
380 if (qualifier
== 'L')
381 num
= va_arg(args
, int64_t);
382 else if (qualifier
== 'l') {
383 num
= va_arg(args
, unsigned long);
384 if (flags
& STP_SIGN
)
385 num
= (signed long) num
;
386 } else if (qualifier
== 'h') {
387 num
= (unsigned short) va_arg(args
, int);
388 if (flags
& STP_SIGN
)
389 num
= (signed short) num
;
391 num
= va_arg(args
, unsigned int);
392 if (flags
& STP_SIGN
)
393 num
= (signed int) num
;
395 str
= number(str
, end
, num
, base
,
396 field_width
, precision
, flags
);
401 if (likely(str
<= end
))
402 written
= str
- write_len_ptr
- write_len_width
;
404 written
= end
- write_len_ptr
- write_len_width
;
406 if (likely(write_len_ptr
+ write_len_width
< end
)) {
407 switch (write_len_width
) {
409 *(uint8_t *)write_len_ptr
= (uint8_t)written
;
412 *(uint16_t *)write_len_ptr
= (uint16_t)written
;
416 *(uint32_t *)write_len_ptr
= (uint32_t)written
;
422 if (likely(str
<= end
))
425 /* don't write out a null byte if the buf size is zero */
430 #endif /* _VSPRINTF_C_ */
This page took 0.071225 seconds and 5 git commands to generate.