aboutsummaryrefslogtreecommitdiffstats
path: root/lib/vsprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r--lib/vsprintf.c235
1 files changed, 131 insertions, 104 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index c399bc1093cb..cceecb6a963d 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -32,40 +32,48 @@
32/* Works only for digits and letters, but small and fast */ 32/* Works only for digits and letters, but small and fast */
33#define TOLOWER(x) ((x) | 0x20) 33#define TOLOWER(x) ((x) | 0x20)
34 34
35static unsigned int simple_guess_base(const char *cp)
36{
37 if (cp[0] == '0') {
38 if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
39 return 16;
40 else
41 return 8;
42 } else {
43 return 10;
44 }
45}
46
35/** 47/**
36 * simple_strtoul - convert a string to an unsigned long 48 * simple_strtoul - convert a string to an unsigned long
37 * @cp: The start of the string 49 * @cp: The start of the string
38 * @endp: A pointer to the end of the parsed string will be placed here 50 * @endp: A pointer to the end of the parsed string will be placed here
39 * @base: The number base to use 51 * @base: The number base to use
40 */ 52 */
41unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) 53unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
42{ 54{
43 unsigned long result = 0,value; 55 unsigned long result = 0;
44 56
45 if (!base) { 57 if (!base)
46 base = 10; 58 base = simple_guess_base(cp);
47 if (*cp == '0') { 59
48 base = 8; 60 if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
49 cp++; 61 cp += 2;
50 if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) { 62
51 cp++; 63 while (isxdigit(*cp)) {
52 base = 16; 64 unsigned int value;
53 } 65
54 } 66 value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
55 } else if (base == 16) { 67 if (value >= base)
56 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x') 68 break;
57 cp += 2; 69 result = result * base + value;
58 }
59 while (isxdigit(*cp) &&
60 (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
61 result = result*base + value;
62 cp++; 70 cp++;
63 } 71 }
72
64 if (endp) 73 if (endp)
65 *endp = (char *)cp; 74 *endp = (char *)cp;
66 return result; 75 return result;
67} 76}
68
69EXPORT_SYMBOL(simple_strtoul); 77EXPORT_SYMBOL(simple_strtoul);
70 78
71/** 79/**
@@ -74,13 +82,12 @@ EXPORT_SYMBOL(simple_strtoul);
74 * @endp: A pointer to the end of the parsed string will be placed here 82 * @endp: A pointer to the end of the parsed string will be placed here
75 * @base: The number base to use 83 * @base: The number base to use
76 */ 84 */
77long simple_strtol(const char *cp,char **endp,unsigned int base) 85long simple_strtol(const char *cp, char **endp, unsigned int base)
78{ 86{
79 if(*cp=='-') 87 if(*cp == '-')
80 return -simple_strtoul(cp+1,endp,base); 88 return -simple_strtoul(cp + 1, endp, base);
81 return simple_strtoul(cp,endp,base); 89 return simple_strtoul(cp, endp, base);
82} 90}
83
84EXPORT_SYMBOL(simple_strtol); 91EXPORT_SYMBOL(simple_strtol);
85 92
86/** 93/**
@@ -89,34 +96,30 @@ EXPORT_SYMBOL(simple_strtol);
89 * @endp: A pointer to the end of the parsed string will be placed here 96 * @endp: A pointer to the end of the parsed string will be placed here
90 * @base: The number base to use 97 * @base: The number base to use
91 */ 98 */
92unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) 99unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
93{ 100{
94 unsigned long long result = 0,value; 101 unsigned long long result = 0;
95 102
96 if (!base) { 103 if (!base)
97 base = 10; 104 base = simple_guess_base(cp);
98 if (*cp == '0') { 105
99 base = 8; 106 if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
100 cp++; 107 cp += 2;
101 if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) { 108
102 cp++; 109 while (isxdigit(*cp)) {
103 base = 16; 110 unsigned int value;
104 } 111
105 } 112 value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
106 } else if (base == 16) { 113 if (value >= base)
107 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x') 114 break;
108 cp += 2; 115 result = result * base + value;
109 }
110 while (isxdigit(*cp)
111 && (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
112 result = result*base + value;
113 cp++; 116 cp++;
114 } 117 }
118
115 if (endp) 119 if (endp)
116 *endp = (char *)cp; 120 *endp = (char *)cp;
117 return result; 121 return result;
118} 122}
119
120EXPORT_SYMBOL(simple_strtoull); 123EXPORT_SYMBOL(simple_strtoull);
121 124
122/** 125/**
@@ -125,14 +128,13 @@ EXPORT_SYMBOL(simple_strtoull);
125 * @endp: A pointer to the end of the parsed string will be placed here 128 * @endp: A pointer to the end of the parsed string will be placed here
126 * @base: The number base to use 129 * @base: The number base to use
127 */ 130 */
128long long simple_strtoll(const char *cp,char **endp,unsigned int base) 131long long simple_strtoll(const char *cp, char **endp, unsigned int base)
129{ 132{
130 if(*cp=='-') 133 if(*cp=='-')
131 return -simple_strtoull(cp+1,endp,base); 134 return -simple_strtoull(cp + 1, endp, base);
132 return simple_strtoull(cp,endp,base); 135 return simple_strtoull(cp, endp, base);
133} 136}
134 137
135
136/** 138/**
137 * strict_strtoul - convert a string to an unsigned long strictly 139 * strict_strtoul - convert a string to an unsigned long strictly
138 * @cp: The string to be converted 140 * @cp: The string to be converted
@@ -155,7 +157,27 @@ long long simple_strtoll(const char *cp,char **endp,unsigned int base)
155 * simple_strtoul just ignores the successive invalid characters and 157 * simple_strtoul just ignores the successive invalid characters and
156 * return the converted value of prefix part of the string. 158 * return the converted value of prefix part of the string.
157 */ 159 */
158int strict_strtoul(const char *cp, unsigned int base, unsigned long *res); 160int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
161{
162 char *tail;
163 unsigned long val;
164 size_t len;
165
166 *res = 0;
167 len = strlen(cp);
168 if (len == 0)
169 return -EINVAL;
170
171 val = simple_strtoul(cp, &tail, base);
172 if ((*tail == '\0') ||
173 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
174 *res = val;
175 return 0;
176 }
177
178 return -EINVAL;
179}
180EXPORT_SYMBOL(strict_strtoul);
159 181
160/** 182/**
161 * strict_strtol - convert a string to a long strictly 183 * strict_strtol - convert a string to a long strictly
@@ -169,7 +191,20 @@ int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
169 * It returns 0 if conversion is successful and *res is set to the converted 191 * It returns 0 if conversion is successful and *res is set to the converted
170 * value, otherwise it returns -EINVAL and *res is set to 0. 192 * value, otherwise it returns -EINVAL and *res is set to 0.
171 */ 193 */
172int strict_strtol(const char *cp, unsigned int base, long *res); 194int strict_strtol(const char *cp, unsigned int base, long *res)
195{
196 int ret;
197 if (*cp == '-') {
198 ret = strict_strtoul(cp + 1, base, (unsigned long *)res);
199 if (!ret)
200 *res = -(*res);
201 } else {
202 ret = strict_strtoul(cp, base, (unsigned long *)res);
203 }
204
205 return ret;
206}
207EXPORT_SYMBOL(strict_strtol);
173 208
174/** 209/**
175 * strict_strtoull - convert a string to an unsigned long long strictly 210 * strict_strtoull - convert a string to an unsigned long long strictly
@@ -193,7 +228,27 @@ int strict_strtol(const char *cp, unsigned int base, long *res);
193 * simple_strtoull just ignores the successive invalid characters and 228 * simple_strtoull just ignores the successive invalid characters and
194 * return the converted value of prefix part of the string. 229 * return the converted value of prefix part of the string.
195 */ 230 */
196int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res); 231int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res)
232{
233 char *tail;
234 unsigned long long val;
235 size_t len;
236
237 *res = 0;
238 len = strlen(cp);
239 if (len == 0)
240 return -EINVAL;
241
242 val = simple_strtoull(cp, &tail, base);
243 if ((*tail == '\0') ||
244 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
245 *res = val;
246 return 0;
247 }
248
249 return -EINVAL;
250}
251EXPORT_SYMBOL(strict_strtoull);
197 252
198/** 253/**
199 * strict_strtoll - convert a string to a long long strictly 254 * strict_strtoll - convert a string to a long long strictly
@@ -207,53 +262,20 @@ int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res);
207 * It returns 0 if conversion is successful and *res is set to the converted 262 * It returns 0 if conversion is successful and *res is set to the converted
208 * value, otherwise it returns -EINVAL and *res is set to 0. 263 * value, otherwise it returns -EINVAL and *res is set to 0.
209 */ 264 */
210int strict_strtoll(const char *cp, unsigned int base, long long *res); 265int strict_strtoll(const char *cp, unsigned int base, long long *res)
211 266{
212#define define_strict_strtoux(type, valtype) \ 267 int ret;
213int strict_strtou##type(const char *cp, unsigned int base, valtype *res)\ 268 if (*cp == '-') {
214{ \ 269 ret = strict_strtoull(cp + 1, base, (unsigned long long *)res);
215 char *tail; \ 270 if (!ret)
216 valtype val; \ 271 *res = -(*res);
217 size_t len; \ 272 } else {
218 \ 273 ret = strict_strtoull(cp, base, (unsigned long long *)res);
219 *res = 0; \ 274 }
220 len = strlen(cp); \
221 if (len == 0) \
222 return -EINVAL; \
223 \
224 val = simple_strtou##type(cp, &tail, base); \
225 if ((*tail == '\0') || \
226 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {\
227 *res = val; \
228 return 0; \
229 } \
230 \
231 return -EINVAL; \
232} \
233
234#define define_strict_strtox(type, valtype) \
235int strict_strto##type(const char *cp, unsigned int base, valtype *res) \
236{ \
237 int ret; \
238 if (*cp == '-') { \
239 ret = strict_strtou##type(cp+1, base, res); \
240 if (!ret) \
241 *res = -(*res); \
242 } else \
243 ret = strict_strtou##type(cp, base, res); \
244 \
245 return ret; \
246} \
247
248define_strict_strtoux(l, unsigned long)
249define_strict_strtox(l, long)
250define_strict_strtoux(ll, unsigned long long)
251define_strict_strtox(ll, long long)
252 275
253EXPORT_SYMBOL(strict_strtoul); 276 return ret;
254EXPORT_SYMBOL(strict_strtol); 277}
255EXPORT_SYMBOL(strict_strtoll); 278EXPORT_SYMBOL(strict_strtoll);
256EXPORT_SYMBOL(strict_strtoull);
257 279
258static int skip_atoi(const char **s) 280static int skip_atoi(const char **s)
259{ 281{
@@ -565,6 +587,10 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field
565 * @fmt: The format string to use 587 * @fmt: The format string to use
566 * @args: Arguments for the format string 588 * @args: Arguments for the format string
567 * 589 *
590 * This function follows C99 vsnprintf, but has some extensions:
591 * %pS output the name of a text symbol
592 * %pF output the name of a function pointer
593 *
568 * The return value is the number of characters which would 594 * The return value is the number of characters which would
569 * be generated for the given input, excluding the trailing 595 * be generated for the given input, excluding the trailing
570 * '\0', as per ISO C99. If you want to have the exact 596 * '\0', as per ISO C99. If you want to have the exact
@@ -790,7 +816,6 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
790 /* the trailing null byte doesn't count towards the total */ 816 /* the trailing null byte doesn't count towards the total */
791 return str-buf; 817 return str-buf;
792} 818}
793
794EXPORT_SYMBOL(vsnprintf); 819EXPORT_SYMBOL(vsnprintf);
795 820
796/** 821/**
@@ -806,6 +831,8 @@ EXPORT_SYMBOL(vsnprintf);
806 * 831 *
807 * Call this function if you are already dealing with a va_list. 832 * Call this function if you are already dealing with a va_list.
808 * You probably want scnprintf() instead. 833 * You probably want scnprintf() instead.
834 *
835 * See the vsnprintf() documentation for format string extensions over C99.
809 */ 836 */
810int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) 837int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
811{ 838{
@@ -814,7 +841,6 @@ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
814 i=vsnprintf(buf,size,fmt,args); 841 i=vsnprintf(buf,size,fmt,args);
815 return (i >= size) ? (size - 1) : i; 842 return (i >= size) ? (size - 1) : i;
816} 843}
817
818EXPORT_SYMBOL(vscnprintf); 844EXPORT_SYMBOL(vscnprintf);
819 845
820/** 846/**
@@ -828,6 +854,8 @@ EXPORT_SYMBOL(vscnprintf);
828 * generated for the given input, excluding the trailing null, 854 * generated for the given input, excluding the trailing null,
829 * as per ISO C99. If the return is greater than or equal to 855 * as per ISO C99. If the return is greater than or equal to
830 * @size, the resulting string is truncated. 856 * @size, the resulting string is truncated.
857 *
858 * See the vsnprintf() documentation for format string extensions over C99.
831 */ 859 */
832int snprintf(char * buf, size_t size, const char *fmt, ...) 860int snprintf(char * buf, size_t size, const char *fmt, ...)
833{ 861{
@@ -839,7 +867,6 @@ int snprintf(char * buf, size_t size, const char *fmt, ...)
839 va_end(args); 867 va_end(args);
840 return i; 868 return i;
841} 869}
842
843EXPORT_SYMBOL(snprintf); 870EXPORT_SYMBOL(snprintf);
844 871
845/** 872/**
@@ -877,12 +904,13 @@ EXPORT_SYMBOL(scnprintf);
877 * 904 *
878 * Call this function if you are already dealing with a va_list. 905 * Call this function if you are already dealing with a va_list.
879 * You probably want sprintf() instead. 906 * You probably want sprintf() instead.
907 *
908 * See the vsnprintf() documentation for format string extensions over C99.
880 */ 909 */
881int vsprintf(char *buf, const char *fmt, va_list args) 910int vsprintf(char *buf, const char *fmt, va_list args)
882{ 911{
883 return vsnprintf(buf, INT_MAX, fmt, args); 912 return vsnprintf(buf, INT_MAX, fmt, args);
884} 913}
885
886EXPORT_SYMBOL(vsprintf); 914EXPORT_SYMBOL(vsprintf);
887 915
888/** 916/**
@@ -894,6 +922,8 @@ EXPORT_SYMBOL(vsprintf);
894 * The function returns the number of characters written 922 * The function returns the number of characters written
895 * into @buf. Use snprintf() or scnprintf() in order to avoid 923 * into @buf. Use snprintf() or scnprintf() in order to avoid
896 * buffer overflows. 924 * buffer overflows.
925 *
926 * See the vsnprintf() documentation for format string extensions over C99.
897 */ 927 */
898int sprintf(char * buf, const char *fmt, ...) 928int sprintf(char * buf, const char *fmt, ...)
899{ 929{
@@ -905,7 +935,6 @@ int sprintf(char * buf, const char *fmt, ...)
905 va_end(args); 935 va_end(args);
906 return i; 936 return i;
907} 937}
908
909EXPORT_SYMBOL(sprintf); 938EXPORT_SYMBOL(sprintf);
910 939
911/** 940/**
@@ -1134,7 +1163,6 @@ int vsscanf(const char * buf, const char * fmt, va_list args)
1134 1163
1135 return num; 1164 return num;
1136} 1165}
1137
1138EXPORT_SYMBOL(vsscanf); 1166EXPORT_SYMBOL(vsscanf);
1139 1167
1140/** 1168/**
@@ -1153,5 +1181,4 @@ int sscanf(const char * buf, const char * fmt, ...)
1153 va_end(args); 1181 va_end(args);
1154 return i; 1182 return i;
1155} 1183}
1156
1157EXPORT_SYMBOL(sscanf); 1184EXPORT_SYMBOL(sscanf);