]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/src/c++11/snprintf_lite.cc
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / src / c++11 / snprintf_lite.cc
CommitLineData
9779c871
PP
1// Debugging support -*- C++ -*-
2
83ffe9cd 3// Copyright (C) 2013-2023 Free Software Foundation, Inc.
9779c871
PP
4//
5// This file is part of GCC.
6//
7// GCC is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 3, or (at your option)
10// any later version.
11//
12// GCC is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// Under Section 7 of GPL version 3, you are granted additional
18// permissions described in the GCC Runtime Library Exception, version
19// 3.1, as published by the Free Software Foundation.
20
21// You should have received a copy of the GNU General Public License and
22// a copy of the GCC Runtime Library Exception along with this program;
23// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24// <http://www.gnu.org/licenses/>.
25
26#include <stdarg.h>
44967af8 27#include <stddef.h>
9779c871 28#include <bits/functexcept.h>
9779c871
PP
29
30namespace __gnu_cxx {
31
32 // Private helper to throw logic error if snprintf_lite runs out
33 // of space (which is not expected to ever happen).
34 // NUL-terminates __buf.
35 void
36 __throw_insufficient_space(const char *__buf, const char *__bufend)
37 __attribute__((__noreturn__));
38
39 void
40 __throw_insufficient_space(const char *__buf, const char *__bufend)
41 {
42 // Include space for trailing NUL.
43 const size_t __len = __bufend - __buf + 1;
44
45 const char __err[] = "not enough space for format expansion "
a8fc7e07 46 "(Please submit full bug report at https://gcc.gnu.org/bugs/):\n ";
9779c871
PP
47 const size_t __errlen = sizeof(__err) - 1;
48
49 char *const __e
50 = static_cast<char*>(__builtin_alloca(__errlen + __len));
51
52 __builtin_memcpy(__e, __err, __errlen);
53 __builtin_memcpy(__e + __errlen, __buf, __len - 1);
54 __e[__errlen + __len - 1] = '\0';
55 std::__throw_logic_error(__e);
56 }
57
58
59 // Private routine to append decimal representation of VAL to the given
60 // BUFFER, but not more than BUFSIZE characters.
61 // Does not NUL-terminate the output buffer.
62 // Returns number of characters appended, or -1 if BUFSIZE is too small.
63 int __concat_size_t(char *__buf, size_t __bufsize, size_t __val)
64 {
65 // Long enough for decimal representation.
b333e8eb 66 int __ilen = 3 * sizeof(__val);
9779c871 67 char *__cs = static_cast<char*>(__builtin_alloca(__ilen));
b333e8eb
JW
68 char* __out = __cs + __ilen;
69 do
70 {
71 *--__out = "0123456789"[__val % 10];
72 __val /= 10;
73 }
74 while (__val != 0);
728e81e3 75 size_t __len = __cs + __ilen - __out;
9779c871
PP
76 if (__bufsize < __len)
77 return -1;
78
79 __builtin_memcpy(__buf, __cs + __ilen - __len, __len);
80 return __len;
81 }
82
83
84 // Private routine to print into __buf arguments according to format,
85 // not to exceed __bufsize.
86 // Only '%%', '%s' and '%zu' format specifiers are understood.
87 // Returns number of characters printed (excluding terminating NUL).
88 // Always NUL-terminates __buf.
89 // Throws logic_error on insufficient space.
90 int __snprintf_lite(char *__buf, size_t __bufsize, const char *__fmt,
91 va_list __ap)
92 {
93 char *__d = __buf;
94 const char *__s = __fmt;
95 const char *const __limit = __d + __bufsize - 1; // Leave space for NUL.
96
97 while (__s[0] != '\0' && __d < __limit)
98 {
99 if (__s[0] == '%')
100 switch (__s[1])
101 {
102 default: // Stray '%'. Just print it.
103 break;
104 case '%': // '%%'
105 __s += 1;
106 break;
107 case 's': // '%s'.
108 {
109 const char *__v = va_arg(__ap, const char *);
110
111 while (__v[0] != '\0' && __d < __limit)
112 *__d++ = *__v++;
113
114 if (__v[0] != '\0')
115 // Not enough space for __fmt expansion.
116 __throw_insufficient_space(__buf, __d);
117
118 __s += 2; // Step over %s.
119 continue;
120 }
121 break;
122 case 'z':
123 if (__s[2] == 'u') // '%zu' -- expand next size_t arg.
124 {
125 const int __len = __concat_size_t(__d, __limit - __d,
126 va_arg(__ap, size_t));
127 if (__len > 0)
128 __d += __len;
129 else
130 // Not enough space for __fmt expansion.
131 __throw_insufficient_space(__buf, __d);
132
133 __s += 3; // Step over %zu
134 continue;
135 }
136 // Stray '%zX'. Just print it.
137 break;
138 }
139 *__d++ = *__s++;
140 }
141
142 if (__s[0] != '\0')
143 // Not enough space for __fmt expansion.
144 __throw_insufficient_space(__buf, __d);
145
146 *__d = '\0';
147 return __d - __buf;
148 }
149
150} // __gnu_cxx