[444] | 1 | /* |
---|
| 2 | * Copyright (c) 2012-2014 ARM Ltd |
---|
| 3 | * All rights reserved. |
---|
| 4 | * |
---|
| 5 | * Redistribution and use in source and binary forms, with or without |
---|
| 6 | * modification, are permitted provided that the following conditions |
---|
| 7 | * are met: |
---|
| 8 | * 1. Redistributions of source code must retain the above copyright |
---|
| 9 | * notice, this list of conditions and the following disclaimer. |
---|
| 10 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
| 11 | * notice, this list of conditions and the following disclaimer in the |
---|
| 12 | * documentation and/or other materials provided with the distribution. |
---|
| 13 | * 3. The name of the company may not be used to endorse or promote |
---|
| 14 | * products derived from this software without specific prior written |
---|
| 15 | * permission. |
---|
| 16 | * |
---|
| 17 | * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED |
---|
| 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
---|
| 19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
| 20 | * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
---|
| 21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
---|
| 22 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
---|
| 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
---|
| 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
---|
| 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
---|
| 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
| 27 | */ |
---|
| 28 | |
---|
| 29 | #include <newlib.h> |
---|
| 30 | |
---|
| 31 | #include <_ansi.h> |
---|
| 32 | #include <reent.h> |
---|
| 33 | #include <stdio.h> |
---|
| 34 | #include <stdlib.h> |
---|
| 35 | #include <string.h> |
---|
| 36 | #include <limits.h> |
---|
| 37 | #include <stdint.h> |
---|
| 38 | #include <wchar.h> |
---|
| 39 | #include <sys/lock.h> |
---|
| 40 | #include <stdarg.h> |
---|
| 41 | #include "local.h" |
---|
| 42 | #include "../stdlib/local.h" |
---|
| 43 | #include "fvwrite.h" |
---|
| 44 | #include "vfieeefp.h" |
---|
| 45 | #include "nano-vfprintf_local.h" |
---|
| 46 | |
---|
| 47 | /* Decode and print non-floating point data. */ |
---|
| 48 | int |
---|
| 49 | _printf_common (struct _reent *data, |
---|
| 50 | struct _prt_data_t *pdata, |
---|
| 51 | int *realsz, |
---|
| 52 | FILE *fp, |
---|
| 53 | int (*pfunc)(struct _reent *, FILE *, |
---|
| 54 | const char *, size_t len)) |
---|
| 55 | { |
---|
| 56 | int n; |
---|
| 57 | /* |
---|
| 58 | * All reasonable formats wind up here. At this point, `cp' |
---|
| 59 | * points to a string which (if not flags&LADJUST) should be |
---|
| 60 | * padded out to `width' places. If flags&ZEROPAD, it should |
---|
| 61 | * first be prefixed by any sign or other prefix; otherwise, |
---|
| 62 | * it should be blank padded before the prefix is emitted. |
---|
| 63 | * After any left-hand padding and prefixing, emit zeroes |
---|
| 64 | * required by a decimal [diouxX] precision, then print the |
---|
| 65 | * string proper, then emit zeroes required by any leftover |
---|
| 66 | * floating precision; finally, if LADJUST, pad with blanks. |
---|
| 67 | * If flags&FPT, ch must be in [aAeEfg]. |
---|
| 68 | * |
---|
| 69 | * Compute actual size, so we know how much to pad. |
---|
| 70 | * size excludes decimal prec; realsz includes it. |
---|
| 71 | */ |
---|
| 72 | *realsz = pdata->dprec > pdata->size ? pdata->dprec : pdata->size; |
---|
| 73 | if (pdata->l_buf[0]) |
---|
| 74 | (*realsz)++; |
---|
| 75 | |
---|
| 76 | if (pdata->flags & HEXPREFIX) |
---|
| 77 | *realsz += 2; |
---|
| 78 | |
---|
| 79 | /* Right-adjusting blank padding. */ |
---|
| 80 | if ((pdata->flags & (LADJUST|ZEROPAD)) == 0) |
---|
| 81 | PAD (pdata->width - *realsz, pdata->blank); |
---|
| 82 | |
---|
| 83 | /* Prefix. */ |
---|
| 84 | n = 0; |
---|
| 85 | if (pdata->l_buf[0]) |
---|
| 86 | n++; |
---|
| 87 | |
---|
| 88 | if (pdata->flags & HEXPREFIX) |
---|
| 89 | { |
---|
| 90 | pdata->l_buf[n++] = '0'; |
---|
| 91 | pdata->l_buf[n++] = pdata->l_buf[2]; |
---|
| 92 | } |
---|
| 93 | |
---|
| 94 | PRINT (pdata->l_buf, n); |
---|
| 95 | n = pdata->width - *realsz; |
---|
| 96 | if ((pdata->flags & (LADJUST|ZEROPAD)) != ZEROPAD || n < 0) |
---|
| 97 | n = 0; |
---|
| 98 | |
---|
| 99 | if (pdata->dprec > pdata->size) |
---|
| 100 | n += pdata->dprec - pdata->size; |
---|
| 101 | |
---|
| 102 | PAD (n, pdata->zero); |
---|
| 103 | return 0; |
---|
| 104 | error: |
---|
| 105 | return -1; |
---|
| 106 | } |
---|
| 107 | int |
---|
| 108 | _printf_i (struct _reent *data, struct _prt_data_t *pdata, FILE *fp, |
---|
| 109 | int (*pfunc)(struct _reent *, FILE *, const char *, size_t len), |
---|
| 110 | va_list *ap) |
---|
| 111 | { |
---|
| 112 | /* Field size expanded by dprec. */ |
---|
| 113 | int realsz; |
---|
| 114 | u_quad_t _uquad; |
---|
| 115 | int base; |
---|
| 116 | int n; |
---|
| 117 | char *cp = pdata->buf + BUF; |
---|
| 118 | char *xdigs = "0123456789ABCDEF"; |
---|
| 119 | |
---|
| 120 | /* Decoding the conversion specifier. */ |
---|
| 121 | switch (pdata->code) |
---|
| 122 | { |
---|
| 123 | case 'c': |
---|
| 124 | *--cp = GET_ARG (N, *ap, int); |
---|
| 125 | pdata->size = 1; |
---|
| 126 | goto non_number_nosign; |
---|
| 127 | case 'd': |
---|
| 128 | case 'i': |
---|
| 129 | _uquad = SARG (pdata->flags); |
---|
| 130 | if ((long) _uquad < 0) |
---|
| 131 | { |
---|
| 132 | _uquad = -_uquad; |
---|
| 133 | pdata->l_buf[0] = '-'; |
---|
| 134 | } |
---|
| 135 | base = 10; |
---|
| 136 | goto number; |
---|
| 137 | case 'u': |
---|
| 138 | case 'o': |
---|
| 139 | _uquad = UARG (pdata->flags); |
---|
| 140 | base = (pdata->code == 'o') ? 8 : 10; |
---|
| 141 | goto nosign; |
---|
| 142 | case 'X': |
---|
| 143 | pdata->l_buf[2] = 'X'; |
---|
| 144 | goto hex; |
---|
| 145 | case 'p': |
---|
| 146 | /* |
---|
| 147 | * ``The argument shall be a pointer to void. The |
---|
| 148 | * value of the pointer is converted to a sequence |
---|
| 149 | * of printable characters, in an implementation- |
---|
| 150 | * defined manner.'' |
---|
| 151 | * -- ANSI X3J11 |
---|
| 152 | */ |
---|
| 153 | pdata->flags |= HEXPREFIX; |
---|
| 154 | if (sizeof (void*) > sizeof (int)) |
---|
| 155 | pdata->flags |= LONGINT; |
---|
| 156 | /* NOSTRICT. */ |
---|
| 157 | case 'x': |
---|
| 158 | pdata->l_buf[2] = 'x'; |
---|
| 159 | xdigs = "0123456789abcdef"; |
---|
| 160 | hex: |
---|
| 161 | _uquad = UARG (pdata->flags); |
---|
| 162 | base = 16; |
---|
| 163 | if (pdata->flags & ALT) |
---|
| 164 | pdata->flags |= HEXPREFIX; |
---|
| 165 | |
---|
| 166 | /* Leading 0x/X only if non-zero. */ |
---|
| 167 | if (_uquad == 0) |
---|
| 168 | pdata->flags &= ~HEXPREFIX; |
---|
| 169 | |
---|
| 170 | /* Unsigned conversions. */ |
---|
| 171 | nosign: |
---|
| 172 | pdata->l_buf[0] = '\0'; |
---|
| 173 | /* |
---|
| 174 | * ``... diouXx conversions ... if a precision is |
---|
| 175 | * specified, the 0 flag will be ignored.'' |
---|
| 176 | * -- ANSI X3J11 |
---|
| 177 | */ |
---|
| 178 | number: |
---|
| 179 | if ((pdata->dprec = pdata->prec) >= 0) |
---|
| 180 | pdata->flags &= ~ZEROPAD; |
---|
| 181 | |
---|
| 182 | /* |
---|
| 183 | * ``The result of converting a zero value with an |
---|
| 184 | * explicit precision of zero is no characters.'' |
---|
| 185 | * -- ANSI X3J11 |
---|
| 186 | */ |
---|
| 187 | if (_uquad != 0 || pdata->prec != 0) |
---|
| 188 | { |
---|
| 189 | do |
---|
| 190 | { |
---|
| 191 | *--cp = xdigs[_uquad % base]; |
---|
| 192 | _uquad /= base; |
---|
| 193 | } |
---|
| 194 | while (_uquad); |
---|
| 195 | } |
---|
| 196 | /* For 'o' conversion, '#' increases the precision to force the first |
---|
| 197 | digit of the result to be zero. */ |
---|
| 198 | if (base == 8 && (pdata->flags & ALT) && pdata->prec <= pdata->size) |
---|
| 199 | *--cp = '0'; |
---|
| 200 | |
---|
| 201 | pdata->size = pdata->buf + BUF - cp; |
---|
| 202 | break; |
---|
| 203 | case 'n': |
---|
| 204 | if (pdata->flags & LONGINT) |
---|
| 205 | *GET_ARG (N, *ap, long_ptr_t) = pdata->ret; |
---|
| 206 | else if (pdata->flags & SHORTINT) |
---|
| 207 | *GET_ARG (N, *ap, short_ptr_t) = pdata->ret; |
---|
| 208 | else |
---|
| 209 | *GET_ARG (N, *ap, int_ptr_t) = pdata->ret; |
---|
| 210 | case '\0': |
---|
| 211 | pdata->size = 0; |
---|
| 212 | break; |
---|
| 213 | case 's': |
---|
| 214 | cp = GET_ARG (N, *ap, char_ptr_t); |
---|
| 215 | /* Precision gives the maximum number of chars to be written from a |
---|
| 216 | string, and take prec == -1 into consideration. |
---|
| 217 | Use normal Newlib approach here to support case where cp is not |
---|
| 218 | nul-terminated. */ |
---|
| 219 | char *p = memchr (cp, 0, pdata->prec); |
---|
| 220 | |
---|
| 221 | if (p != NULL) |
---|
| 222 | pdata->prec = p - cp; |
---|
| 223 | |
---|
| 224 | pdata->size = pdata->prec; |
---|
| 225 | goto non_number_nosign; |
---|
| 226 | default: |
---|
| 227 | /* "%?" prints ?, unless ? is NUL. */ |
---|
| 228 | /* Pretend it was %c with argument ch. */ |
---|
| 229 | *--cp = pdata->code; |
---|
| 230 | pdata->size = 1; |
---|
| 231 | non_number_nosign: |
---|
| 232 | pdata->l_buf[0] = '\0'; |
---|
| 233 | break; |
---|
| 234 | } |
---|
| 235 | |
---|
| 236 | /* Output. */ |
---|
| 237 | n = _printf_common (data, pdata, &realsz, fp, pfunc); |
---|
| 238 | if (n == -1) |
---|
| 239 | goto error; |
---|
| 240 | |
---|
| 241 | PRINT (cp, pdata->size); |
---|
| 242 | /* Left-adjusting padding (always blank). */ |
---|
| 243 | if (pdata->flags & LADJUST) |
---|
| 244 | PAD (pdata->width - realsz, pdata->blank); |
---|
| 245 | |
---|
| 246 | return (pdata->width > realsz ? pdata->width : realsz); |
---|
| 247 | error: |
---|
| 248 | return -1; |
---|
| 249 | } |
---|
| 250 | |
---|