1 // Debugging support -*- C++ -*-
2 
3 // Copyright (C) 2013-2014 Free Software Foundation, Inc.
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>
27 #include <bits/functexcept.h>
28 #include <bits/locale_facets.h>
29 
30 namespace std {
31 _GLIBCXX_BEGIN_NAMESPACE_VERSION
32   template<typename _CharT, typename _ValueT>
33   int
34   __int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit,
35                 ios_base::fmtflags __flags, bool __dec);
36 _GLIBCXX_END_NAMESPACE_VERSION
37 }
38 
39 namespace __gnu_cxx {
40 
41   // Private helper to throw logic error if snprintf_lite runs out
42   // of space (which is not expected to ever happen).
43   // NUL-terminates __buf.
44   void
45   __throw_insufficient_space(const char *__buf, const char *__bufend)
46     __attribute__((__noreturn__));
47 
48   void
__throw_insufficient_space(const char * __buf,const char * __bufend)49   __throw_insufficient_space(const char *__buf, const char *__bufend)
50   {
51     // Include space for trailing NUL.
52     const size_t __len = __bufend - __buf + 1;
53 
54     const char __err[] = "not enough space for format expansion "
55       "(Please submit full bug report at http://gcc.gnu.org/bugs.html):\n    ";
56     const size_t __errlen = sizeof(__err) - 1;
57 
58     char *const __e
59       = static_cast<char*>(__builtin_alloca(__errlen + __len));
60 
61     __builtin_memcpy(__e, __err, __errlen);
62     __builtin_memcpy(__e + __errlen, __buf, __len - 1);
63     __e[__errlen + __len - 1] = '\0';
64     std::__throw_logic_error(__e);
65   }
66 
67 
68   // Private routine to append decimal representation of VAL to the given
69   // BUFFER, but not more than BUFSIZE characters.
70   // Does not NUL-terminate the output buffer.
71   // Returns number of characters appended, or -1 if BUFSIZE is too small.
__concat_size_t(char * __buf,size_t __bufsize,size_t __val)72   int __concat_size_t(char *__buf, size_t __bufsize, size_t __val)
73   {
74     // __int_to_char is explicitly instantiated and available only for
75     // some, but not all, types. See locale-inst.cc.
76 #ifdef _GLIBCXX_USE_LONG_LONG
77     unsigned long long __val2 = __val;
78 #else
79     unsigned long __val2 = __val;
80 #endif
81     // Long enough for decimal representation.
82     int __ilen = 3 * sizeof(__val2);
83     char *__cs = static_cast<char*>(__builtin_alloca(__ilen));
84     size_t __len = std::__int_to_char(__cs + __ilen, __val2,
85 				      std::__num_base::_S_atoms_out,
86 				      std::ios_base::dec, true);
87     if (__bufsize < __len)
88       return -1;
89 
90     __builtin_memcpy(__buf, __cs + __ilen - __len, __len);
91     return __len;
92   }
93 
94 
95   // Private routine to print into __buf arguments according to format,
96   // not to exceed __bufsize.
97   // Only '%%', '%s' and '%zu' format specifiers are understood.
98   // Returns number of characters printed (excluding terminating NUL).
99   // Always NUL-terminates __buf.
100   // Throws logic_error on insufficient space.
__snprintf_lite(char * __buf,size_t __bufsize,const char * __fmt,va_list __ap)101   int __snprintf_lite(char *__buf, size_t __bufsize, const char *__fmt,
102 		      va_list __ap)
103   {
104     char *__d = __buf;
105     const char *__s = __fmt;
106     const char *const __limit = __d + __bufsize - 1;  // Leave space for NUL.
107 
108     while (__s[0] != '\0' && __d < __limit)
109       {
110 	if (__s[0] == '%')
111 	  switch (__s[1])
112 	    {
113 	    default:  // Stray '%'. Just print it.
114 	      break;
115 	    case '%':  // '%%'
116 	      __s += 1;
117 	      break;
118 	    case 's':  // '%s'.
119 	      {
120 		const char *__v = va_arg(__ap, const char *);
121 
122 		while (__v[0] != '\0' && __d < __limit)
123 		  *__d++ = *__v++;
124 
125 		if (__v[0] != '\0')
126 		  // Not enough space for __fmt expansion.
127 		  __throw_insufficient_space(__buf, __d);
128 
129 		__s += 2;  // Step over %s.
130 		continue;
131 	      }
132 	      break;
133 	    case 'z':
134 	      if (__s[2] == 'u')  // '%zu' -- expand next size_t arg.
135 		{
136 		  const int __len = __concat_size_t(__d, __limit - __d,
137 						    va_arg(__ap, size_t));
138 		  if (__len > 0)
139 		    __d += __len;
140 		  else
141 		    // Not enough space for __fmt expansion.
142 		    __throw_insufficient_space(__buf, __d);
143 
144 		  __s += 3;  // Step over %zu
145 		  continue;
146 		}
147 	      // Stray '%zX'. Just print it.
148 	      break;
149 	    }
150 	*__d++ = *__s++;
151       }
152 
153     if (__s[0] != '\0')
154       // Not enough space for __fmt expansion.
155       __throw_insufficient_space(__buf, __d);
156 
157     *__d = '\0';
158     return __d - __buf;
159   }
160 
161 }  // __gnu_cxx
162