1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | /*** |
6 | *xtoa.c - convert integers/longs to ASCII string |
7 | * |
8 | |
9 | * |
10 | *Purpose: |
11 | * The module has code to convert integers/longs to ASCII strings. See |
12 | * |
13 | *******************************************************************************/ |
14 | |
15 | #ifdef _UNICODE |
16 | #define xtox_s xtow_s |
17 | #define _itox_s _itow_s |
18 | #define _ltox_s _ltow_s |
19 | #define _ultox_s _ultow_s |
20 | #define x64tox_s x64tow_s |
21 | #define _i64tox_s _i64tow_s |
22 | #define _ui64tox_s _ui64tow_s |
23 | #define xtox xtow |
24 | #define _ltox _ltow |
25 | #define _ultox _ultow |
26 | #define x64tox x64tow |
27 | #else /* _UNICODE */ |
28 | #define xtox_s xtoa_s |
29 | #define _itox_s _itoa_s |
30 | #define _ltox_s _ltoa_s |
31 | #define _ultox_s _ultoa_s |
32 | #define x64tox_s x64toa_s |
33 | #define _i64tox_s _i64toa_s |
34 | #define _ui64tox_s _ui64toa_s |
35 | #define xtox xtoa |
36 | #define _ltox _ltoa |
37 | #define _ultox _ultoa |
38 | #define x64tox x64toa |
39 | #endif /* _UNICODE */ |
40 | |
41 | /*** |
42 | *char *_itoa_s, *_ltoa_s, *_ultoa_s(val, buf, sizeInTChars, radix) - convert binary int to ASCII |
43 | * string |
44 | * |
45 | *Purpose: |
46 | * Converts an int to a character string. |
47 | * |
48 | *Entry: |
49 | * val - number to be converted (int, long or unsigned long) |
50 | * char *buf - ptr to buffer to place result |
51 | * size_t sizeInTChars - size of the destination buffer |
52 | * int radix - base to convert into |
53 | * |
54 | *Exit: |
55 | * Fills in space pointed to by buf with string result. |
56 | * Returns the errno_t: err != 0 means that something went wrong, and |
57 | * an empty string (buf[0] = 0) is returned. |
58 | * |
59 | *Exceptions: |
60 | * Input parameters and buffer length are validated. |
61 | * Refer to the validation section of the function. |
62 | * |
63 | *******************************************************************************/ |
64 | |
65 | /* helper routine that does the main job. */ |
66 | #ifdef _SECURE_ITOA |
67 | static errno_t __stdcall xtox_s |
68 | ( |
69 | unsigned long val, |
70 | TCHAR *buf, |
71 | size_t sizeInTChars, |
72 | unsigned radix, |
73 | int is_neg |
74 | ) |
75 | #else /* _SECURE_ITOA */ |
76 | static void __stdcall xtox |
77 | ( |
78 | unsigned long val, |
79 | TCHAR *buf, |
80 | unsigned radix, |
81 | int is_neg |
82 | ) |
83 | #endif /* _SECURE_ITOA */ |
84 | { |
85 | TCHAR *p; /* pointer to traverse string */ |
86 | TCHAR *firstdig; /* pointer to first digit */ |
87 | TCHAR temp; /* temp char */ |
88 | unsigned digval; /* value of digit */ |
89 | #ifdef _SECURE_ITOA |
90 | size_t length; /* current length of the string */ |
91 | |
92 | /* validation section */ |
93 | _VALIDATE_RETURN_ERRCODE(buf != NULL, EINVAL); |
94 | _VALIDATE_RETURN_ERRCODE(sizeInTChars > 0, EINVAL); |
95 | _RESET_STRING(buf, sizeInTChars); |
96 | _VALIDATE_RETURN_ERRCODE(sizeInTChars > (size_t)(is_neg ? 2 : 1), ERANGE); |
97 | _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL); |
98 | length = 0; |
99 | |
100 | #endif /* _SECURE_ITOA */ |
101 | p = buf; |
102 | |
103 | if (is_neg) { |
104 | /* negative, so output '-' and negate */ |
105 | *p++ = _T('-'); |
106 | #ifdef _SECURE_ITOA |
107 | length++; |
108 | #endif /* _SECURE_ITOA */ |
109 | val = (unsigned long)(-(long)val); |
110 | } |
111 | |
112 | firstdig = p; /* save pointer to first digit */ |
113 | |
114 | do { |
115 | digval = (unsigned) (val % radix); |
116 | val /= radix; /* get next digit */ |
117 | |
118 | /* convert to ascii and store */ |
119 | if (digval > 9) |
120 | *p++ = (TCHAR) (digval - 10 + _T('a')); /* a letter */ |
121 | else |
122 | *p++ = (TCHAR) (digval + _T('0')); /* a digit */ |
123 | #ifndef _SECURE_ITOA |
124 | } while (val > 0); |
125 | #else /* _SECURE_ITOA */ |
126 | length++; |
127 | } while (val > 0 && length < sizeInTChars); |
128 | |
129 | /* Check for buffer overrun */ |
130 | if (length >= sizeInTChars) |
131 | { |
132 | buf[0] = '\0'; |
133 | _VALIDATE_RETURN_ERRCODE(length < sizeInTChars, ERANGE); |
134 | } |
135 | #endif /* _SECURE_ITOA */ |
136 | /* We now have the digit of the number in the buffer, but in reverse |
137 | order. Thus we reverse them now. */ |
138 | |
139 | *p-- = _T('\0'); /* terminate string; p points to last digit */ |
140 | |
141 | do { |
142 | temp = *p; |
143 | *p = *firstdig; |
144 | *firstdig = temp; /* swap *p and *firstdig */ |
145 | --p; |
146 | ++firstdig; /* advance to next two digits */ |
147 | } while (firstdig < p); /* repeat until halfway */ |
148 | #ifdef _SECURE_ITOA |
149 | return 0; |
150 | #endif /* _SECURE_ITOA */ |
151 | } |
152 | |
153 | /* Actual functions just call conversion helper with neg flag set correctly, |
154 | and return pointer to buffer. */ |
155 | |
156 | #ifdef _SECURE_ITOA |
157 | errno_t __cdecl _itox_s ( |
158 | int val, |
159 | TCHAR *buf, |
160 | size_t sizeInTChars, |
161 | int radix |
162 | ) |
163 | { |
164 | errno_t e = 0; |
165 | |
166 | if (radix == 10 && val < 0) |
167 | e = xtox_s((unsigned long)val, buf, sizeInTChars, radix, 1); |
168 | else |
169 | e = xtox_s((unsigned long)(unsigned int)val, buf, sizeInTChars, radix, 0); |
170 | |
171 | return e; |
172 | } |
173 | |
174 | errno_t __cdecl _ltox_s ( |
175 | long val, |
176 | TCHAR *buf, |
177 | size_t sizeInTChars, |
178 | int radix |
179 | ) |
180 | { |
181 | return xtox_s((unsigned long)val, buf, sizeInTChars, radix, (radix == 10 && val < 0)); |
182 | } |
183 | |
184 | errno_t __cdecl _ultox_s ( |
185 | unsigned long val, |
186 | TCHAR *buf, |
187 | size_t sizeInTChars, |
188 | int radix |
189 | ) |
190 | { |
191 | return xtox_s(val, buf, sizeInTChars, radix, 0); |
192 | } |
193 | |
194 | #else /* _SECURE_ITOA */ |
195 | |
196 | /*** |
197 | *char *_itoa, *_ltoa, *_ultoa(val, buf, radix) - convert binary int to ASCII |
198 | * string |
199 | * |
200 | *Purpose: |
201 | * Converts an int to a character string. |
202 | * |
203 | *Entry: |
204 | * val - number to be converted (int, long or unsigned long) |
205 | * int radix - base to convert into |
206 | * char *buf - ptr to buffer to place result |
207 | * |
208 | *Exit: |
209 | * fills in space pointed to by buf with string result |
210 | * returns a pointer to this buffer |
211 | * |
212 | *Exceptions: |
213 | * Input parameters are validated. The buffer is assumed to be big enough to |
214 | * contain the string. Refer to the validation section of the function. |
215 | * |
216 | *******************************************************************************/ |
217 | |
218 | /* Actual functions just call conversion helper with neg flag set correctly, |
219 | and return pointer to buffer. */ |
220 | |
221 | TCHAR * __cdecl _ltox ( |
222 | long val, |
223 | TCHAR *buf, |
224 | int radix |
225 | ) |
226 | { |
227 | xtox((unsigned long)val, buf, radix, (radix == 10 && val < 0)); |
228 | return buf; |
229 | } |
230 | |
231 | TCHAR * __cdecl _ultox ( |
232 | unsigned long val, |
233 | TCHAR *buf, |
234 | int radix |
235 | ) |
236 | { |
237 | xtox(val, buf, radix, 0); |
238 | return buf; |
239 | } |
240 | |
241 | #endif /* _SECURE_ITOA */ |
242 | |
243 | #ifndef _NO_INT64 |
244 | |
245 | /*** |
246 | *char *_i64toa_s(val, buf, sizeInTChars, radix) - convert binary int to ASCII |
247 | * string |
248 | * |
249 | *Purpose: |
250 | * Converts an int64 to a character string. |
251 | * |
252 | *Entry: |
253 | * val - number to be converted |
254 | * char *buf - ptr to buffer to place result |
255 | * size_t sizeInTChars - size of the destination buffer |
256 | * int radix - base to convert into |
257 | * |
258 | *Exit: |
259 | * Fills in space pointed to by buf with string result. |
260 | * Returns the errno_t: err != 0 means that something went wrong, and |
261 | * an empty string (buf[0] = 0) is returned. |
262 | * |
263 | *Exceptions: |
264 | * Input parameters and buffer length are validated. |
265 | * Refer to the validation section of the function. |
266 | * |
267 | *******************************************************************************/ |
268 | |
269 | #ifdef _SECURE_ITOA |
270 | static errno_t __fastcall x64tox_s |
271 | (/* stdcall is faster and smaller... Might as well use it for the helper. */ |
272 | unsigned __int64 val, |
273 | TCHAR *buf, |
274 | size_t sizeInTChars, |
275 | unsigned radix, |
276 | int is_neg |
277 | ) |
278 | #else /* _SECURE_ITOA */ |
279 | static void __fastcall x64tox |
280 | (/* stdcall is faster and smaller... Might as well use it for the helper. */ |
281 | unsigned __int64 val, |
282 | TCHAR *buf, |
283 | unsigned radix, |
284 | int is_neg |
285 | ) |
286 | #endif /* _SECURE_ITOA */ |
287 | { |
288 | TCHAR *p; /* pointer to traverse string */ |
289 | TCHAR *firstdig; /* pointer to first digit */ |
290 | TCHAR temp; /* temp char */ |
291 | unsigned digval; /* value of digit */ |
292 | #ifdef _SECURE_ITOA |
293 | size_t length; /* current length of the string */ |
294 | |
295 | /* validation section */ |
296 | _VALIDATE_RETURN_ERRCODE(buf != NULL, EINVAL); |
297 | _VALIDATE_RETURN_ERRCODE(sizeInTChars > 0, EINVAL); |
298 | _RESET_STRING(buf, sizeInTChars); |
299 | _VALIDATE_RETURN_ERRCODE(sizeInTChars > (size_t)(is_neg ? 2 : 1), ERANGE); |
300 | _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL); |
301 | length = 0; |
302 | #endif /* _SECURE_ITOA */ |
303 | p = buf; |
304 | |
305 | if ( is_neg ) |
306 | { |
307 | *p++ = _T('-'); /* negative, so output '-' and negate */ |
308 | #ifdef _SECURE_ITOA |
309 | length++; |
310 | #endif /* _SECURE_ITOA */ |
311 | val = (unsigned __int64)(-(__int64)val); |
312 | } |
313 | |
314 | firstdig = p; /* save pointer to first digit */ |
315 | |
316 | do { |
317 | digval = (unsigned) (val % radix); |
318 | val /= radix; /* get next digit */ |
319 | |
320 | /* convert to ascii and store */ |
321 | if (digval > 9) |
322 | *p++ = (TCHAR) (digval - 10 + _T('a')); /* a letter */ |
323 | else |
324 | *p++ = (TCHAR) (digval + _T('0')); /* a digit */ |
325 | |
326 | #ifndef _SECURE_ITOA |
327 | } while (val > 0); |
328 | #else /* _SECURE_ITOA */ |
329 | length++; |
330 | } while (val > 0 && length < sizeInTChars); |
331 | |
332 | /* Check for buffer overrun */ |
333 | if (length >= sizeInTChars) |
334 | { |
335 | buf[0] = '\0'; |
336 | _VALIDATE_RETURN_ERRCODE(length < sizeInTChars, ERANGE); |
337 | } |
338 | #endif /* _SECURE_ITOA */ |
339 | /* We now have the digit of the number in the buffer, but in reverse |
340 | order. Thus we reverse them now. */ |
341 | |
342 | *p-- = _T('\0'); /* terminate string; p points to last digit */ |
343 | |
344 | do { |
345 | temp = *p; |
346 | *p = *firstdig; |
347 | *firstdig = temp; /* swap *p and *firstdig */ |
348 | --p; |
349 | ++firstdig; /* advance to next two digits */ |
350 | } while (firstdig < p); /* repeat until halfway */ |
351 | |
352 | #ifdef _SECURE_ITOA |
353 | return 0; |
354 | #endif /* _SECURE_ITOA */ |
355 | } |
356 | |
357 | #ifdef _SECURE_ITOA |
358 | |
359 | /* Actual functions just call conversion helper with neg flag set correctly, |
360 | and return pointer to buffer. */ |
361 | |
362 | errno_t __cdecl _i64tox_s ( |
363 | long long val, |
364 | TCHAR *buf, |
365 | size_t sizeInTChars, |
366 | int radix |
367 | ) |
368 | { |
369 | return x64tox_s((unsigned __int64)val, buf, sizeInTChars, radix, (radix == 10 && val < 0)); |
370 | } |
371 | |
372 | errno_t __cdecl _ui64tox_s ( |
373 | unsigned long long val, |
374 | TCHAR *buf, |
375 | size_t sizeInTChars, |
376 | int radix |
377 | ) |
378 | { |
379 | return x64tox_s(val, buf, sizeInTChars, radix, 0); |
380 | } |
381 | |
382 | #else /* _SECURE_ITOA */ |
383 | |
384 | /*** |
385 | *char *_i64toa(val, buf, radix) - convert binary int to ASCII |
386 | * string |
387 | * |
388 | *Purpose: |
389 | * Converts an int64 to a character string. |
390 | * |
391 | *Entry: |
392 | * val - number to be converted |
393 | * int radix - base to convert into |
394 | * char *buf - ptr to buffer to place result |
395 | * |
396 | *Exit: |
397 | * fills in space pointed to by buf with string result |
398 | * returns a pointer to this buffer |
399 | * |
400 | *Exceptions: |
401 | * Input parameters are validated. The buffer is assumed to be big enough to |
402 | * contain the string. Refer to the validation section of the function. |
403 | * |
404 | *******************************************************************************/ |
405 | |
406 | /* Actual functions just call conversion helper with neg flag set correctly, |
407 | and return pointer to buffer. */ |
408 | |
409 | TCHAR * __cdecl _ui64tox ( |
410 | unsigned __int64 val, |
411 | TCHAR *buf, |
412 | int radix |
413 | ) |
414 | { |
415 | x64tox(val, buf, radix, 0); |
416 | return buf; |
417 | } |
418 | |
419 | #endif /* _SECURE_ITOA */ |
420 | |
421 | #endif /* _NO_INT64 */ |
422 | |