Coverage Report

Created: 2025-07-14 06:48

/src/frr/lib/printf/printfcommon.h
Line
Count
Source (jump to first uncovered line)
1
/*-
2
 * SPDX-License-Identifier: BSD-3-Clause
3
 *
4
 * Copyright (c) 1990, 1993
5
 *  The Regents of the University of California.  All rights reserved.
6
 *
7
 * This code is derived from software contributed to Berkeley by
8
 * Chris Torek.
9
 *
10
 * Copyright (c) 2011 The FreeBSD Foundation
11
 * All rights reserved.
12
 * Portions of this software were developed by David Chisnall
13
 * under sponsorship from the FreeBSD Foundation.
14
 *
15
 * Redistribution and use in source and binary forms, with or without
16
 * modification, are permitted provided that the following conditions
17
 * are met:
18
 * 1. Redistributions of source code must retain the above copyright
19
 *    notice, this list of conditions and the following disclaimer.
20
 * 2. Redistributions in binary form must reproduce the above copyright
21
 *    notice, this list of conditions and the following disclaimer in the
22
 *    documentation and/or other materials provided with the distribution.
23
 * 3. Neither the name of the University nor the names of its contributors
24
 *    may be used to endorse or promote products derived from this software
25
 *    without specific prior written permission.
26
 *
27
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37
 * SUCH DAMAGE.
38
 *
39
 * $FreeBSD$
40
 */
41
42
/*
43
 * This file defines common routines used by both printf and wprintf.
44
 * You must define CHAR to either char or wchar_t prior to including this.
45
 */
46
47
48
static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *);
49
static CHAR *__ultoa(u_long, CHAR *, int, int, const char *);
50
51
#define NIOV 8
52
struct io_state {
53
  struct fbuf *cb;
54
  size_t avail;
55
};
56
57
static inline void
58
io_init(struct io_state *iop, struct fbuf *cb)
59
498k
{
60
498k
  iop->cb = cb;
61
498k
  iop->avail = cb ? cb->len - (cb->pos - cb->buf) : 0;
62
498k
}
63
64
/*
65
 * WARNING: The buffer passed to io_print() is not copied immediately; it must
66
 * remain valid until io_flush() is called.
67
 */
68
static inline int
69
io_print(struct io_state *iop, const CHAR * __restrict ptr, size_t len)
70
448k
{
71
448k
  size_t copylen = len;
72
73
448k
  if (!iop->cb)
74
0
    return 0;
75
448k
  if (iop->avail < copylen)
76
5
    copylen = iop->avail;
77
78
448k
  memcpy(iop->cb->pos, ptr, copylen);
79
448k
  iop->avail -= copylen;
80
448k
  iop->cb->pos += copylen;
81
448k
  return 0;
82
448k
}
83
84
/*
85
 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
86
 * fields occur frequently, increase PADSIZE and make the initialisers
87
 * below longer.
88
 */
89
52
#define PADSIZE 16    /* pad chunk size */
90
static const CHAR blanks[PADSIZE] =
91
{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
92
static const CHAR zeroes[PADSIZE] =
93
{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
94
95
/*
96
 * Pad with blanks or zeroes. 'with' should point to either the blanks array
97
 * or the zeroes array.
98
 */
99
static inline int
100
io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with)
101
63.5k
{
102
63.5k
  int n;
103
104
63.6k
  while (howmany > 0) {
105
52
    n = (howmany >= PADSIZE) ? PADSIZE : howmany;
106
52
    if (io_print(iop, with, n))
107
0
      return (-1);
108
52
    howmany -= n;
109
52
  }
110
63.5k
  return (0);
111
63.5k
}
112
113
/*
114
 * Print exactly len characters of the string spanning p to ep, truncating
115
 * or padding with 'with' as necessary.
116
 */
117
static inline int
118
io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
119
         int len, const CHAR * __restrict with)
120
0
{
121
0
  int p_len;
122
0
123
0
  p_len = ep - p;
124
0
  if (p_len > len)
125
0
    p_len = len;
126
0
  if (p_len > 0) {
127
0
    if (io_print(iop, p, p_len))
128
0
      return (-1);
129
0
  } else {
130
0
    p_len = 0;
131
0
  }
132
0
  return (io_pad(iop, len - p_len, with));
133
0
}
134
135
/*
136
 * Convert an unsigned long to ASCII for printf purposes, returning
137
 * a pointer to the first character of the string representation.
138
 * Octal numbers can be forced to have a leading zero; hex numbers
139
 * use the given digits.
140
 */
141
static CHAR *
142
__ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs)
143
175
{
144
175
  CHAR *cp = endp;
145
175
  long sval;
146
147
  /*
148
   * Handle the three cases separately, in the hope of getting
149
   * better/faster code.
150
   */
151
175
  switch (base) {
152
175
  case 10:
153
175
    if (val < 10) { /* many numbers are 1 digit */
154
77
      *--cp = to_char(val);
155
77
      return (cp);
156
77
    }
157
    /*
158
     * On many machines, unsigned arithmetic is harder than
159
     * signed arithmetic, so we do at most one unsigned mod and
160
     * divide; this is sufficient to reduce the range of
161
     * the incoming value to where signed arithmetic works.
162
     */
163
98
    if (val > LONG_MAX) {
164
0
      *--cp = to_char(val % 10);
165
0
      sval = val / 10;
166
0
    } else
167
98
      sval = val;
168
483
    do {
169
483
      *--cp = to_char(sval % 10);
170
483
      sval /= 10;
171
483
    } while (sval != 0);
172
98
    break;
173
174
0
  case 8:
175
0
    do {
176
0
      *--cp = to_char(val & 7);
177
0
      val >>= 3;
178
0
    } while (val);
179
0
    if (octzero && *cp != '0')
180
0
      *--cp = '0';
181
0
    break;
182
183
0
  case 16:
184
0
    do {
185
0
      *--cp = xdigs[val & 15];
186
0
      val >>= 4;
187
0
    } while (val);
188
0
    break;
189
190
0
  default:      /* oops */
191
0
    abort();
192
175
  }
193
98
  return (cp);
194
175
}
195
196
/* Identical to __ultoa, but for intmax_t. */
197
static CHAR *
198
__ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs)
199
3
{
200
3
  CHAR *cp = endp;
201
3
  intmax_t sval;
202
203
  /* quick test for small values; __ultoa is typically much faster */
204
  /* (perhaps instead we should run until small, then call __ultoa?) */
205
3
  if (val <= ULONG_MAX)
206
3
    return (__ultoa((u_long)val, endp, base, octzero, xdigs));
207
0
  switch (base) {
208
0
  case 10:
209
0
    if (val < 10) {
210
0
      *--cp = to_char(val % 10);
211
0
      return (cp);
212
0
    }
213
0
    if (val > INTMAX_MAX) {
214
0
      *--cp = to_char(val % 10);
215
0
      sval = val / 10;
216
0
    } else
217
0
      sval = val;
218
0
    do {
219
0
      *--cp = to_char(sval % 10);
220
0
      sval /= 10;
221
0
    } while (sval != 0);
222
0
    break;
223
224
0
  case 8:
225
0
    do {
226
0
      *--cp = to_char(val & 7);
227
0
      val >>= 3;
228
0
    } while (val);
229
0
    if (octzero && *cp != '0')
230
0
      *--cp = '0';
231
0
    break;
232
233
0
  case 16:
234
0
    do {
235
0
      *--cp = xdigs[val & 15];
236
0
      val >>= 4;
237
0
    } while (val);
238
0
    break;
239
240
0
  default:
241
0
    abort();
242
0
  }
243
0
  return (cp);
244
0
}