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
67static 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 */
76static 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
157errno_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
174errno_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
184errno_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
221TCHAR * __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
231TCHAR * __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
270static 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 */
279static 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
362errno_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
372errno_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
409TCHAR * __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