Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:11

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSDeviceIO
0005  *
0006  * @brief This source file contains the implementation of
0007  *   _IO_Vprintf().
0008  */
0009 
0010 /*-
0011  * SPDX-License-Identifier: BSD-3-Clause
0012  *
0013  * Copyright (c) 1986, 1988, 1991, 1993
0014  *  The Regents of the University of California.  All rights reserved.
0015  * (c) UNIX System Laboratories, Inc.
0016  * All or some portions of this file are derived from material licensed
0017  * to the University of California by American Telephone and Telegraph
0018  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
0019  * the permission of UNIX System Laboratories, Inc.
0020  *
0021  * Redistribution and use in source and binary forms, with or without
0022  * modification, are permitted provided that the following conditions
0023  * are met:
0024  * 1. Redistributions of source code must retain the above copyright
0025  *    notice, this list of conditions and the following disclaimer.
0026  * 2. Redistributions in binary form must reproduce the above copyright
0027  *    notice, this list of conditions and the following disclaimer in the
0028  *    documentation and/or other materials provided with the distribution.
0029  * 3. Neither the name of the University nor the names of its contributors
0030  *    may be used to endorse or promote products derived from this software
0031  *    without specific prior written permission.
0032  *
0033  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
0034  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0035  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0036  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
0037  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0038  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0039  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0040  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0041  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0042  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0043  * SUCH DAMAGE.
0044  */
0045 
0046 #include <rtems/dev/io.h>
0047 
0048 #include <sys/cdefs.h>
0049 #include <sys/param.h>
0050 #include <string.h>
0051 
0052 /* Max number conversion buffer length: a intmax_t in base 8, plus NUL byte. */
0053 #define MAXNBUF (howmany(sizeof(intmax_t) * NBBY, 3) + 1)
0054 
0055 static inline int imax(int a, int b) { return (a > b ? a : b); }
0056 
0057 static char const hex2ascii_data[2][16] = {
0058     { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
0059       'a', 'b', 'c', 'd', 'e', 'f' },
0060     { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
0061       'A', 'B', 'C', 'D', 'E', 'F' }
0062 };
0063 
0064 static inline char
0065 hex2ascii(int hex)
0066 {
0067 
0068     return (hex2ascii_data[0][hex]);
0069 }
0070 
0071 /*
0072  * Put a NUL-terminated ASCII number (base <= 16) in a buffer in reverse
0073  * order; return an optional length and a pointer to the last character
0074  * written in the buffer (i.e., the first character of the string).
0075  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
0076  */
0077 static inline char *
0078 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
0079 {
0080     char *p;
0081 
0082     p = nbuf;
0083     *p = '\0';
0084     do {
0085         *++p = hex2ascii_data[upper][num % base];
0086     } while (num /= base);
0087     *lenp = p - nbuf;
0088     return (p);
0089 }
0090 
0091 int
0092 _IO_Vprintf(IO_Put_char put_char, void *arg, char const *fmt, va_list ap)
0093 {
0094 #define PCHAR(c) {int cc=(c); (*put_char)(cc, arg); retval++; }
0095     char nbuf[MAXNBUF];
0096     const char *p, *percent, *q;
0097     u_char *up;
0098     int ch, n, sign;
0099     uintmax_t num;
0100     int base, lflag, tmp, width, ladjust, sharpflag, dot;
0101     int cflag, hflag, jflag;
0102     RTEMS_STATIC_ASSERT(sizeof(intmax_t) == sizeof(long long), _IO_Vprintf_j);
0103 #if __SIZEOF_PTRDIFF_T__ == __SIZEOF_LONG__
0104 #define tflag lflag
0105 #else
0106     int tflag;
0107 #endif
0108 #if __SIZEOF_SIZE_T__ == __SIZEOF_LONG__
0109 #define zflag lflag
0110 #else
0111     int zflag;
0112 #endif
0113     int dwidth, upper;
0114     char padc;
0115     int stop = 0, retval = 0;
0116 
0117     num = 0;
0118 
0119     if (fmt == NULL)
0120         fmt = "(fmt null)\n";
0121 
0122     for (;;) {
0123         padc = ' ';
0124         width = 0;
0125         while ((ch = (u_char)*fmt++) != '%' || stop) {
0126             if (ch == '\0')
0127                 return (retval);
0128             PCHAR(ch);
0129         }
0130         percent = fmt - 1;
0131         lflag = 0; ladjust = 0; sharpflag = 0;
0132         sign = 0; dot = 0; dwidth = 0; upper = 0;
0133         cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
0134 reswitch:   switch (ch = (u_char)*fmt++) {
0135         case '.':
0136             dot = 1;
0137             goto reswitch;
0138         case '#':
0139             sharpflag = 1;
0140             goto reswitch;
0141         case '+':
0142             sign = '+';
0143             goto reswitch;
0144         case '-':
0145             ladjust = 1;
0146             goto reswitch;
0147         case '%':
0148             PCHAR(ch);
0149             break;
0150         case '*':
0151             if (!dot) {
0152                 width = va_arg(ap, int);
0153                 if (width < 0) {
0154                     ladjust = !ladjust;
0155                     width = -width;
0156                 }
0157             } else {
0158                 dwidth = va_arg(ap, int);
0159             }
0160             goto reswitch;
0161         case '0':
0162             if (!dot) {
0163                 padc = '0';
0164                 goto reswitch;
0165             }
0166             /* FALLTHROUGH */
0167         case '1': case '2': case '3': case '4':
0168         case '5': case '6': case '7': case '8': case '9':
0169                 for (n = 0;; ++fmt) {
0170                     n = n * 10 + ch - '0';
0171                     ch = *fmt;
0172                     if (ch < '0' || ch > '9')
0173                         break;
0174                 }
0175             if (dot)
0176                 dwidth = n;
0177             else
0178                 width = n;
0179             goto reswitch;
0180         case 'c':
0181             width -= 1;
0182 
0183             if (!ladjust && width > 0)
0184                 while (width--)
0185                     PCHAR(padc);
0186             PCHAR(va_arg(ap, int));
0187             if (ladjust && width > 0)
0188                 while (width--)
0189                     PCHAR(padc);
0190             break;
0191         case 'D':
0192             up = va_arg(ap, u_char *);
0193             p = va_arg(ap, char *);
0194             if (!width)
0195                 width = 16;
0196             while(width--) {
0197                 PCHAR(hex2ascii(*up >> 4));
0198                 PCHAR(hex2ascii(*up & 0x0f));
0199                 up++;
0200                 if (width)
0201                     for (q=p;*q;q++)
0202                         PCHAR(*q);
0203             }
0204             break;
0205         case 'd':
0206         case 'i':
0207             base = 10;
0208             goto handle_sign;
0209         case 'h':
0210             if (hflag) {
0211                 hflag = 0;
0212                 cflag = 1;
0213             } else
0214                 hflag = 1;
0215             goto reswitch;
0216         case 'j':
0217             jflag = 1;
0218             goto reswitch;
0219         case 'l':
0220             if (lflag) {
0221                 jflag = 1;
0222             } else
0223                 lflag = 1;
0224             goto reswitch;
0225         case 'o':
0226             base = 8;
0227             goto handle_nosign;
0228         case 'p':
0229             base = 16;
0230             sharpflag = (width == 0);
0231             sign = 0;
0232             num = (uintptr_t)va_arg(ap, void *);
0233             goto number;
0234         case 's':
0235             p = va_arg(ap, char *);
0236             if (p == NULL)
0237                 p = "(null)";
0238             if (!dot)
0239                 n = strlen (p);
0240             else
0241                 for (n = 0; n < dwidth && p[n]; n++)
0242                     continue;
0243 
0244             width -= n;
0245 
0246             if (!ladjust && width > 0)
0247                 while (width--)
0248                     PCHAR(padc);
0249             while (n--)
0250                 PCHAR(*p++);
0251             if (ladjust && width > 0)
0252                 while (width--)
0253                     PCHAR(padc);
0254             break;
0255         case 't':
0256             tflag = 1;
0257             goto reswitch;
0258         case 'u':
0259             base = 10;
0260             goto handle_nosign;
0261         case 'X':
0262             upper = 1;
0263             /* FALLTHROUGH */
0264         case 'x':
0265             base = 16;
0266             goto handle_nosign;
0267         case 'y':
0268             base = 16;
0269             goto handle_sign;
0270         case 'z':
0271             zflag = 1;
0272             goto reswitch;
0273 handle_nosign:
0274             if (jflag)
0275                 num = va_arg(ap, uintmax_t);
0276 #if __SIZEOF_PTRDIFF_T__ != __SIZEOF_LONG__
0277             else if (tflag)
0278                 num = va_arg(ap, ptrdiff_t);
0279 #endif
0280             else if (lflag)
0281                 num = va_arg(ap, u_long);
0282 #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG__
0283             else if (zflag)
0284                 num = va_arg(ap, size_t);
0285 #endif
0286             else if (hflag)
0287                 num = (u_short)va_arg(ap, int);
0288             else if (cflag)
0289                 num = (u_char)va_arg(ap, int);
0290             else
0291                 num = va_arg(ap, u_int);
0292             goto number;
0293 handle_sign:
0294             if (jflag)
0295                 num = va_arg(ap, intmax_t);
0296 #if __SIZEOF_PTRDIFF_T__ != __SIZEOF_LONG__
0297             else if (tflag)
0298                 num = va_arg(ap, ptrdiff_t);
0299 #endif
0300             else if (lflag)
0301                 num = va_arg(ap, long);
0302 #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG__
0303             else if (zflag)
0304                 num = va_arg(ap, ssize_t);
0305 #endif
0306             else if (hflag)
0307                 num = (short)va_arg(ap, int);
0308             else if (cflag)
0309                 num = (signed char)va_arg(ap, int);
0310             else
0311                 num = va_arg(ap, int);
0312             if ((intmax_t)num < 0) {
0313                 sign = '-';
0314                 num = -(intmax_t)num;
0315             }
0316 number:
0317             p = ksprintn(nbuf, num, base, &n, upper);
0318             tmp = 0;
0319             if (sharpflag && num != 0) {
0320                 if (base == 8)
0321                     tmp++;
0322                 else if (base == 16)
0323                     tmp += 2;
0324             }
0325             if (sign)
0326                 tmp++;
0327 
0328             if (!ladjust && padc == '0')
0329                 dwidth = width - tmp;
0330             width -= tmp + imax(dwidth, n);
0331             dwidth -= n;
0332             if (!ladjust)
0333                 while (width-- > 0)
0334                     PCHAR(' ');
0335             if (sign)
0336                 PCHAR(sign);
0337             if (sharpflag && num != 0) {
0338                 if (base == 8) {
0339                     PCHAR('0');
0340                 } else if (base == 16) {
0341                     PCHAR('0');
0342                     PCHAR('x');
0343                 }
0344             }
0345             while (dwidth-- > 0)
0346                 PCHAR('0');
0347 
0348             while (*p)
0349                 PCHAR(*p--);
0350 
0351             if (ladjust)
0352                 while (width-- > 0)
0353                     PCHAR(' ');
0354 
0355             break;
0356         default:
0357             while (percent < fmt)
0358                 PCHAR(*percent++);
0359             /*
0360              * Since we ignore a formatting argument it is no
0361              * longer safe to obey the remaining formatting
0362              * arguments as the arguments will no longer match
0363              * the format specs.
0364              */
0365             stop = 1;
0366             break;
0367         }
0368     }
0369 #undef PCHAR
0370 }