]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/stdio/xprintf_int.c
bsdinstall: remove VTOC8 partition scheme option
[FreeBSD/FreeBSD.git] / lib / libc / stdio / xprintf_int.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2005 Poul-Henning Kamp
5  * Copyright (c) 1990, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Chris Torek.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $FreeBSD$
36  */
37
38 #include <namespace.h>
39 #include <err.h>
40 #include <sys/types.h>
41 #include <stddef.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <limits.h>
45 #include <locale.h>
46 #include <stdint.h>
47 #include <assert.h>
48 #include <namespace.h>
49 #include <string.h>
50 #include <wchar.h>
51 #include <un-namespace.h>
52
53 #include "printf.h"
54
55 /* private stuff -----------------------------------------------------*/
56
57 union arg {
58         int                     intarg;
59         u_int                   uintarg;
60         long                    longarg;
61         u_long                  ulongarg;
62         intmax_t                intmaxarg;
63         uintmax_t               uintmaxarg;
64 };
65
66 /*
67  * Macros for converting digits to letters and vice versa
68  */
69 #define to_char(n)      ((n) + '0')
70
71 /* various globals ---------------------------------------------------*/
72
73 /*
74  * The size of the buffer we use for integer conversions.
75  * Technically, we would need the most space for base 10
76  * conversions with thousands' grouping characters between
77  * each pair of digits: 60 digits for 128 bit intmax_t.
78  * Use a bit more for better alignment of stuff.
79  */
80 #define BUF     64
81
82 /* misc --------------------------------------------------------------*/
83
84 /*
85  * Convert an unsigned long to ASCII for printf purposes, returning
86  * a pointer to the first character of the string representation.
87  * Octal numbers can be forced to have a leading zero; hex numbers
88  * use the given digits.
89  */
90 static char *
91 __ultoa(u_long val, char *endp, int base, const char *xdigs,
92         int needgrp, char thousep, const char *grp)
93 {
94         char *cp = endp;
95         long sval;
96         int ndig;
97
98         /*
99          * Handle the three cases separately, in the hope of getting
100          * better/faster code.
101          */
102         switch (base) {
103         case 10:
104                 if (val < 10) { /* many numbers are 1 digit */
105                         *--cp = to_char(val);
106                         return (cp);
107                 }
108                 ndig = 0;
109                 /*
110                  * On many machines, unsigned arithmetic is harder than
111                  * signed arithmetic, so we do at most one unsigned mod and
112                  * divide; this is sufficient to reduce the range of
113                  * the incoming value to where signed arithmetic works.
114                  */
115                 if (val > LONG_MAX) {
116                         *--cp = to_char(val % 10);
117                         ndig++;
118                         sval = val / 10;
119                 } else
120                         sval = val;
121                 do {
122                         *--cp = to_char(sval % 10);
123                         ndig++;
124                         /*
125                          * If (*grp == CHAR_MAX) then no more grouping
126                          * should be performed.
127                          */
128                         if (needgrp && ndig == *grp && *grp != CHAR_MAX
129                                         && sval > 9) {
130                                 *--cp = thousep;
131                                 ndig = 0;
132                                 /*
133                                  * If (*(grp+1) == '\0') then we have to
134                                  * use *grp character (last grouping rule)
135                                  * for all next cases
136                                  */
137                                 if (*(grp+1) != '\0')
138                                         grp++;
139                         }
140                         sval /= 10;
141                 } while (sval != 0);
142                 break;
143
144         case 8:
145                 do {
146                         *--cp = to_char(val & 7);
147                         val >>= 3;
148                 } while (val);
149                 break;
150
151         case 16:
152                 do {
153                         *--cp = xdigs[val & 15];
154                         val >>= 4;
155                 } while (val);
156                 break;
157
158         default:                        /* oops */
159                 assert(base == 16);
160         }
161         return (cp);
162 }
163
164
165 /* Identical to __ultoa, but for intmax_t. */
166 static char *
167 __ujtoa(uintmax_t val, char *endp, int base, const char *xdigs, 
168         int needgrp, char thousep, const char *grp)
169 {
170         char *cp = endp;
171         intmax_t sval;
172         int ndig;
173
174         switch (base) {
175         case 10:
176                 if (val < 10) {
177                         *--cp = to_char(val % 10);
178                         return (cp);
179                 }
180                 ndig = 0;
181                 if (val > INTMAX_MAX) {
182                         *--cp = to_char(val % 10);
183                         ndig++;
184                         sval = val / 10;
185                 } else
186                         sval = val;
187                 do {
188                         *--cp = to_char(sval % 10);
189                         ndig++;
190                         /*
191                          * If (*grp == CHAR_MAX) then no more grouping
192                          * should be performed.
193                          */
194                         if (needgrp && *grp != CHAR_MAX && ndig == *grp
195                                         && sval > 9) {
196                                 *--cp = thousep;
197                                 ndig = 0;
198                                 /*
199                                  * If (*(grp+1) == '\0') then we have to
200                                  * use *grp character (last grouping rule)
201                                  * for all next cases
202                                  */
203                                 if (*(grp+1) != '\0')
204                                         grp++;
205                         }
206                         sval /= 10;
207                 } while (sval != 0);
208                 break;
209
210         case 8:
211                 do {
212                         *--cp = to_char(val & 7);
213                         val >>= 3;
214                 } while (val);
215                 break;
216
217         case 16:
218                 do {
219                         *--cp = xdigs[val & 15];
220                         val >>= 4;
221                 } while (val);
222                 break;
223
224         default:
225                 abort();
226         }
227         return (cp);
228 }
229
230
231 /* 'd' ---------------------------------------------------------------*/
232
233 int
234 __printf_arginfo_int(const struct printf_info *pi, size_t n, int *argt)
235 {
236         assert (n > 0);
237         argt[0] = PA_INT;
238         if (pi->is_ptrdiff)
239                 argt[0] |= PA_FLAG_PTRDIFF;
240         else if (pi->is_size)
241                 argt[0] |= PA_FLAG_SIZE;
242         else if (pi->is_long)
243                 argt[0] |= PA_FLAG_LONG;
244         else if (pi->is_intmax)
245                 argt[0] |= PA_FLAG_INTMAX;
246         else if (pi->is_quad)
247                 argt[0] |= PA_FLAG_QUAD;
248         else if (pi->is_long_double)
249                 argt[0] |= PA_FLAG_LONG_LONG;
250         else if (pi->is_short)
251                 argt[0] |= PA_FLAG_SHORT;
252         else if (pi->is_char)
253                 argt[0] = PA_CHAR;
254         return (1);
255 }
256
257 int
258 __printf_render_int(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
259 {
260         const union arg *argp;
261         char buf[BUF];
262         char *p, *pe;
263         char ns;
264         int l, ngrp, rdx, sign, zext;
265         const char *nalt, *digit;
266         char thousands_sep;     /* locale specific thousands separator */
267         const char *grouping;   /* locale specific numeric grouping rules */
268         uintmax_t uu;
269         int ret;
270
271         ret = 0;
272         nalt = NULL;
273         digit = __lowercase_hex;
274         ns = '\0';
275         pe = buf + sizeof buf - 1;
276
277         if (pi->group) {
278                 thousands_sep = *(localeconv()->thousands_sep);
279                 grouping = localeconv()->grouping;
280                 ngrp = 1;
281         } else {
282                 thousands_sep = 0;
283                 grouping = NULL;
284                 ngrp = 0;
285         }
286
287         switch(pi->spec) {
288         case 'd':
289         case 'i':
290                 rdx = 10;
291                 sign = 1;
292                 break;
293         case 'X':
294                 digit = __uppercase_hex;
295                 /*FALLTHOUGH*/
296         case 'x':
297                 rdx = 16;
298                 sign = 0;
299                 break;
300         case 'u':
301         case 'U':
302                 rdx = 10;
303                 sign = 0;
304                 break;
305         case 'o':
306         case 'O':
307                 rdx = 8;
308                 sign = 0;
309                 break;
310         default:
311                 fprintf(stderr, "pi->spec = '%c'\n", pi->spec);
312                 assert(1 == 0);
313         }
314         argp = arg[0];
315
316         if (sign)
317                 ns = pi->showsign;
318
319         if (pi->is_long_double || pi->is_quad || pi->is_intmax ||
320             pi->is_size || pi->is_ptrdiff) {
321                 if (sign && argp->intmaxarg < 0) {
322                         uu = -argp->intmaxarg;
323                         ns = '-';
324                 } else
325                         uu = argp->uintmaxarg;
326         } else if (pi->is_long) {
327                 if (sign && argp->longarg < 0) {
328                         uu = (u_long)-argp->longarg;
329                         ns = '-';
330                 } else 
331                         uu = argp->ulongarg;
332         } else if (pi->is_short) {
333                 if (sign && (short)argp->intarg < 0) {
334                         uu = -(short)argp->intarg;
335                         ns = '-';
336                 } else 
337                         uu = (unsigned short)argp->uintarg;
338         } else if (pi->is_char) {
339                 if (sign && (signed char)argp->intarg < 0) {
340                         uu = -(signed char)argp->intarg;
341                         ns = '-';
342                 } else 
343                         uu = (unsigned char)argp->uintarg;
344         } else {
345                 if (sign && argp->intarg < 0) {
346                         uu = (unsigned)-argp->intarg;
347                         ns = '-';
348                 } else
349                         uu = argp->uintarg;
350         }
351         if (uu <= ULONG_MAX)
352                 p = __ultoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
353         else
354                 p = __ujtoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
355
356         l = 0;
357         if (uu == 0) {
358                 /*-
359                  * ``The result of converting a zero value with an
360                  * explicit precision of zero is no characters.''
361                  *      -- ANSI X3J11
362                  *
363                  * ``The C Standard is clear enough as is.  The call
364                  * printf("%#.0o", 0) should print 0.''
365                  *      -- Defect Report #151
366                  */
367                         ;
368                 if (pi->prec == 0 && !(pi->alt && rdx == 8))
369                         p = pe;
370         } else if (pi->alt) {
371                 if (rdx == 8) 
372                         *--p = '0';
373                 if (rdx == 16) {
374                         if (pi->spec == 'x')
375                                 nalt = "0x";
376                         else
377                                 nalt = "0X";
378                         l += 2;
379                 }
380         }
381         l += pe - p;
382         if (ns)
383                 l++;
384
385         /*-
386          * ``... diouXx conversions ... if a precision is
387          * specified, the 0 flag will be ignored.''
388          *      -- ANSI X3J11
389          */
390         if (pi->prec > (pe - p))
391                 zext = pi->prec - (pe - p);
392         else if (pi->prec != -1)
393                 zext = 0;
394         else if (pi->pad == '0' && pi->width > l && !pi->left)
395                 zext = pi->width - l;
396         else
397                 zext = 0;
398
399         l += zext;
400
401         while (zext > 0 && p > buf) {
402                 *--p = '0';
403                 zext--;
404         }
405
406         if (l < BUF) {
407                 if (ns) {
408                         *--p = ns;
409                 } else if (nalt != NULL) {
410                         *--p = nalt[1];
411                         *--p = nalt[0];
412                 }
413                 if (pi->width > (pe - p) && !pi->left) {
414                         l = pi->width - (pe - p);
415                         while (l > 0 && p > buf) {
416                                 *--p = ' ';
417                                 l--;
418                         }
419                         if (l)
420                                 ret += __printf_pad(io, l, 0);
421                 }
422         } else {
423                 if (!pi->left && pi->width > l)
424                         ret += __printf_pad(io, pi->width - l, 0);
425                 if (ns != '\0')
426                         ret += __printf_puts(io, &ns, 1);
427                 else if (nalt != NULL)
428                         ret += __printf_puts(io, nalt, 2);
429                 if (zext > 0)
430                         ret += __printf_pad(io, zext, 1);
431         }
432         
433         ret += __printf_puts(io, p, pe - p);
434         if (pi->width > ret && pi->left) 
435                 ret += __printf_pad(io, pi->width - ret, 0);
436         __printf_flush(io);
437         return (ret);
438 }
439
440 /* 'p' ---------------------------------------------------------------*/
441
442 int
443 __printf_arginfo_ptr(const struct printf_info *pi __unused, size_t n, int *argt)
444 {
445
446         assert (n > 0);
447         argt[0] = PA_POINTER;
448         return (1);
449 }
450
451 int
452 __printf_render_ptr(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
453 {
454         struct printf_info p2;
455         uintmax_t u;
456         const void *p;
457
458         /*-
459          * ``The argument shall be a pointer to void.  The
460          * value of the pointer is converted to a sequence
461          * of printable characters, in an implementation-
462          * defined manner.''
463          *      -- ANSI X3J11
464          */
465         u = (uintmax_t)(uintptr_t) *((void **)arg[0]);
466         p2 = *pi;
467
468         p2.spec = 'x';
469         p2.alt = 1;
470         p2.is_long_double = 1;
471         p = &u;
472         return (__printf_render_int(io, &p2, &p));
473 }