RTEMS
iovprintf.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1986, 1988, 1991, 1993
5  * The Regents of the University of California. All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  * notice, this list of conditions and the following disclaimer in the
19  * documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  * may be used to endorse or promote products derived from this software
22  * without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
37  */
38 
39 #include <rtems/score/io.h>
40 
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD: head/sys/kern/subr_prf.c 336417 2018-07-17 14:56:54Z markj $");
43 
44 #include <sys/param.h>
45 #include <string.h>
46 
47 /* Max number conversion buffer length: a intmax_t in base 8, plus NUL byte. */
48 #define MAXNBUF (howmany(sizeof(intmax_t) * NBBY, 3) + 1)
49 
50 static inline int imax(int a, int b) { return (a > b ? a : b); }
51 
52 static char const hex2ascii_data[2][16] = {
53  { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
54  'a', 'b', 'c', 'd', 'e', 'f' },
55  { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
56  'A', 'B', 'C', 'D', 'E', 'F' }
57 };
58 
59 static inline char
60 hex2ascii(int hex)
61 {
62 
63  return (hex2ascii_data[0][hex]);
64 }
65 
66 /*
67  * Put a NUL-terminated ASCII number (base <= 16) in a buffer in reverse
68  * order; return an optional length and a pointer to the last character
69  * written in the buffer (i.e., the first character of the string).
70  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
71  */
72 static char *
73 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
74 {
75  char *p;
76 
77  p = nbuf;
78  *p = '\0';
79  do {
80  *++p = hex2ascii_data[upper][num % base];
81  } while (num /= base);
82  if (lenp)
83  *lenp = p - nbuf;
84  return (p);
85 }
86 
87 int
88 _IO_Vprintf(IO_Put_char put_char, void *arg, char const *fmt, va_list ap)
89 {
90 #define PCHAR(c) {int cc=(c); (*put_char)(cc, arg); retval++; }
91  char nbuf[MAXNBUF];
92  const char *p, *percent, *q;
93  u_char *up;
94  int ch, n;
95  uintmax_t num;
96  int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
97  int cflag, hflag, jflag;
98  RTEMS_STATIC_ASSERT(sizeof(intmax_t) == sizeof(long long), _IO_Vprintf_j);
99 #if __SIZEOF_PTRDIFF_T__ == __SIZEOF_LONG__
100 #define tflag lflag
101 #else
102  int tflag;
103 #endif
104 #if __SIZEOF_SIZE_T__ == __SIZEOF_LONG__
105 #define zflag lflag
106 #else
107  int zflag;
108 #endif
109  int dwidth, upper;
110  char padc;
111  int stop = 0, retval = 0;
112 
113  num = 0;
114 
115  if (fmt == NULL)
116  fmt = "(fmt null)\n";
117 
118  for (;;) {
119  padc = ' ';
120  width = 0;
121  while ((ch = (u_char)*fmt++) != '%' || stop) {
122  if (ch == '\0')
123  return (retval);
124  PCHAR(ch);
125  }
126  percent = fmt - 1;
127  lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
128  sign = 0; dot = 0; dwidth = 0; upper = 0;
129  cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
130 reswitch: switch (ch = (u_char)*fmt++) {
131  case '.':
132  dot = 1;
133  goto reswitch;
134  case '#':
135  sharpflag = 1;
136  goto reswitch;
137  case '+':
138  sign = 1;
139  goto reswitch;
140  case '-':
141  ladjust = 1;
142  goto reswitch;
143  case '%':
144  PCHAR(ch);
145  break;
146  case '*':
147  if (!dot) {
148  width = va_arg(ap, int);
149  if (width < 0) {
150  ladjust = !ladjust;
151  width = -width;
152  }
153  } else {
154  dwidth = va_arg(ap, int);
155  }
156  goto reswitch;
157  case '0':
158  if (!dot) {
159  padc = '0';
160  goto reswitch;
161  }
162  /* FALLTHROUGH */
163  case '1': case '2': case '3': case '4':
164  case '5': case '6': case '7': case '8': case '9':
165  for (n = 0;; ++fmt) {
166  n = n * 10 + ch - '0';
167  ch = *fmt;
168  if (ch < '0' || ch > '9')
169  break;
170  }
171  if (dot)
172  dwidth = n;
173  else
174  width = n;
175  goto reswitch;
176  case 'c':
177  width -= 1;
178 
179  if (!ladjust && width > 0)
180  while (width--)
181  PCHAR(padc);
182  PCHAR(va_arg(ap, int));
183  if (ladjust && width > 0)
184  while (width--)
185  PCHAR(padc);
186  break;
187  case 'D':
188  up = va_arg(ap, u_char *);
189  p = va_arg(ap, char *);
190  if (!width)
191  width = 16;
192  while(width--) {
193  PCHAR(hex2ascii(*up >> 4));
194  PCHAR(hex2ascii(*up & 0x0f));
195  up++;
196  if (width)
197  for (q=p;*q;q++)
198  PCHAR(*q);
199  }
200  break;
201  case 'd':
202  case 'i':
203  base = 10;
204  sign = 1;
205  goto handle_sign;
206  case 'h':
207  if (hflag) {
208  hflag = 0;
209  cflag = 1;
210  } else
211  hflag = 1;
212  goto reswitch;
213  case 'j':
214  jflag = 1;
215  goto reswitch;
216  case 'l':
217  if (lflag) {
218  jflag = 1;
219  } else
220  lflag = 1;
221  goto reswitch;
222  case 'o':
223  base = 8;
224  goto handle_nosign;
225  case 'p':
226  base = 16;
227  sharpflag = (width == 0);
228  sign = 0;
229  num = (uintptr_t)va_arg(ap, void *);
230  goto number;
231  case 's':
232  p = va_arg(ap, char *);
233  if (p == NULL)
234  p = "(null)";
235  if (!dot)
236  n = strlen (p);
237  else
238  for (n = 0; n < dwidth && p[n]; n++)
239  continue;
240 
241  width -= n;
242 
243  if (!ladjust && width > 0)
244  while (width--)
245  PCHAR(padc);
246  while (n--)
247  PCHAR(*p++);
248  if (ladjust && width > 0)
249  while (width--)
250  PCHAR(padc);
251  break;
252  case 't':
253  tflag = 1;
254  goto reswitch;
255  case 'u':
256  base = 10;
257  goto handle_nosign;
258  case 'X':
259  upper = 1;
260  case 'x':
261  base = 16;
262  goto handle_nosign;
263  case 'y':
264  base = 16;
265  sign = 1;
266  goto handle_sign;
267  case 'z':
268  zflag = 1;
269  goto reswitch;
270 handle_nosign:
271  sign = 0;
272  if (jflag)
273  num = va_arg(ap, uintmax_t);
274 #if __SIZEOF_PTRDIFF_T__ != __SIZEOF_LONG__
275  else if (tflag)
276  num = va_arg(ap, ptrdiff_t);
277 #endif
278  else if (lflag)
279  num = va_arg(ap, u_long);
280 #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG__
281  else if (zflag)
282  num = va_arg(ap, size_t);
283 #endif
284  else if (hflag)
285  num = (u_short)va_arg(ap, int);
286  else if (cflag)
287  num = (u_char)va_arg(ap, int);
288  else
289  num = va_arg(ap, u_int);
290  goto number;
291 handle_sign:
292  if (jflag)
293  num = va_arg(ap, intmax_t);
294 #if __SIZEOF_PTRDIFF_T__ == __SIZEOF_LONG__
295  else if (tflag)
296  num = va_arg(ap, ptrdiff_t);
297 #endif
298  else if (lflag)
299  num = va_arg(ap, long);
300 #if __SIZEOF_SIZE_T__ == __SIZEOF_LONG__
301  else if (zflag)
302  num = va_arg(ap, ssize_t);
303 #endif
304  else if (hflag)
305  num = (short)va_arg(ap, int);
306  else if (cflag)
307  num = (char)va_arg(ap, int);
308  else
309  num = va_arg(ap, int);
310 number:
311  if (sign && (intmax_t)num < 0) {
312  neg = 1;
313  num = -(intmax_t)num;
314  }
315  p = ksprintn(nbuf, num, base, &n, upper);
316  tmp = 0;
317  if (sharpflag && num != 0) {
318  if (base == 8)
319  tmp++;
320  else if (base == 16)
321  tmp += 2;
322  }
323  if (neg)
324  tmp++;
325 
326  if (!ladjust && padc == '0')
327  dwidth = width - tmp;
328  width -= tmp + imax(dwidth, n);
329  dwidth -= n;
330  if (!ladjust)
331  while (width-- > 0)
332  PCHAR(' ');
333  if (neg)
334  PCHAR('-');
335  if (sharpflag && num != 0) {
336  if (base == 8) {
337  PCHAR('0');
338  } else if (base == 16) {
339  PCHAR('0');
340  PCHAR('x');
341  }
342  }
343  while (dwidth-- > 0)
344  PCHAR('0');
345 
346  while (*p)
347  PCHAR(*p--);
348 
349  if (ladjust)
350  while (width-- > 0)
351  PCHAR(' ');
352 
353  break;
354  default:
355  while (percent < fmt)
356  PCHAR(*percent++);
357  /*
358  * Since we ignore a formatting argument it is no
359  * longer safe to obey the remaining formatting
360  * arguments as the arguments will no longer match
361  * the format specs.
362  */
363  stop = 1;
364  break;
365  }
366  }
367 #undef PCHAR
368 }
#define RTEMS_STATIC_ASSERT(_cond, _msg)
Asserts at compile time that the specified condition is satisfied.
Definition: basedefs.h:838