BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsla_nullterminated.h
Go to the documentation of this file.
1/// @file bsla_nullterminated.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsla_nullterminated.h -*-C++-*-
8#ifndef INCLUDED_BSLA_NULLTERMINATED
9#define INCLUDED_BSLA_NULLTERMINATED
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsla_nullterminated bsla_nullterminated
15/// @brief Provide macros for use with `NULL`-terminated variadic functions.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsla
19/// @{
20/// @addtogroup bsla_nullterminated
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsla_nullterminated-purpose"> Purpose</a>
25/// * <a href="#bsla_nullterminated-macros"> Macros </a>
26/// * <a href="#bsla_nullterminated-description"> Description </a>
27/// * <a href="#bsla_nullterminated-macro-reference"> Macro Reference </a>
28/// * <a href="#bsla_nullterminated-usage"> Usage </a>
29/// * <a href="#bsla_nullterminated-example-1-catstrings-function"> Example 1: catStrings Function </a>
30/// * <a href="#bsla_nullterminated-example-2-catverdict-function"> Example 2: catVerdict Function </a>
31///
32/// # Purpose {#bsla_nullterminated-purpose}
33/// Provide macros for use with `NULL`-terminated variadic functions.
34///
35/// # Macros {#bsla_nullterminated-macros}
36///
37/// - BSLA_NULLTERMINATED: warn if last argument is not `NULL`
38/// - BSLA_NULLTERMINATEDAT(ARG_IDX): warn if argument at `ARG_IDX` is not `NULL`
39/// - BSLA_NULLTERMINATED_IS_ACTIVE: defined if `BSLA_NULLTERMINATED` is active
40/// - BSLA_NULLTERMINATEDAT_IS_ACTIVE: defined if `BSLA_NULLTERMINATEDAT` active
41///
42/// @see bsla_annotations
43///
44/// # Description {#bsla_nullterminated-description}
45/// This component provides preprocessor macros to indicate that a
46/// variadic function's arguments are terminated by `NULL`, or, in the case of
47/// `BSLA_NULLTERMINATEDAT`, by `NULL` at a certain index. Note that the
48/// terminating `NULL` must actually be `NULL` or, with C++11, `nullptr`;
49/// passing 0 in its place will result in a warning.
50///
51/// ## Macro Reference {#bsla_nullterminated-macro-reference}
52///
53///
54/// `BSLA_NULLTERMINATED`:
55/// This annotation on a variadic macro indicates that a warning should be
56/// issued unless the last argument to the function is explicitly `NULL`.
57///
58/// `BSLA_NULLTERMINATEDAT(ARG_IDX)`:
59/// This annotation on a variadic function indicates that a warning should
60/// be issued unless the argument at `ARG_IDX` is `NULL`, where `ARG_IDX`
61/// is the number of arguments from the last, the last argument having
62/// `ARG_IDX == 0`. Thus, `BSLA_NULLTERMINATED` is equivalent to
63/// `BSLA_NULLTERMINATEDAT(0)`.
64///
65/// `BSLA_NULLTERMINATED_IS_ACTIVE`:
66/// The macro `BSLA_NULLTERMINATED_IS_ACTIVE` is defined if
67/// `BSLA_NULLTERMINATED` expands to something with the desired effect;
68/// otherwise `BSLA_NULLTERMINATED_IS_ACTIVE` is not defined and
69/// `BSLA_NULLTERMINATED` expands to nothing.
70///
71/// `BSLA_NULLTERMINATEDAT_IS_ACTIVE`:
72/// The macro `BSLA_NULLTERMINATEDAT_IS_ACTIVE` is defined if
73/// `BSLA_NULLTERMINATEDAT` expands to something with the desired effect;
74/// otherwise `BSLA_NULLTERMINATEDAT_IS_ACTIVE` is not defined and
75/// `BSLA_NULLTERMINATEDAT` expands to nothing.
76///
77/// ## Usage {#bsla_nullterminated-usage}
78///
79///
80/// This section illustrates intended use of this component.
81///
82/// ### Example 1: catStrings Function {#bsla_nullterminated-example-1-catstrings-function}
83///
84///
85/// Suppose we want to have a function that, passed a variable length argument
86/// list of `const char *` strings terminated by `NULL`, concatenates the
87/// strings, separated by spaces, into a buffer.
88///
89/// First, we declare and define the function, annotated with
90/// `BSLA_NULL_TERMINATED`:
91/// @code
92/// void catStrings(char *outputBuffer, ...) BSLA_NULLTERMINATED;
93/// void catStrings(char *outputBuffer, ...)
94/// // The specified 'outputBuffer' is a buffer where the output of this
95/// // function is placed. The specified '...' is a 'NULL'-terminated list
96/// // of 'const char *' strings, which are to be copied into
97/// // 'outputBuffer', concatenated together and separated by spaces. The
98/// // behavior is undefined unless the '...' is a 'NULL'-terminated list
99/// // of 'const char *' arguments.
100/// {
101/// *outputBuffer = 0;
102///
103/// va_list ap;
104/// va_start(ap, outputBuffer);
105/// const char *next;
106/// for (bool first = 1; (next = va_arg(ap, const char *)); first = 0) {
107/// ::strcat(outputBuffer, first ? "" : " ");
108/// ::strcat(outputBuffer, next);
109/// }
110/// va_end(ap);
111/// }
112/// @endcode
113/// Then, in `main`, we call `catStrings` correctly:
114/// @code
115/// char buf[1000];
116/// catStrings(buf, "Now", "you", "see", "it.", NULL);
117/// printf("%s\n", buf);
118/// @endcode
119/// which compiles without a warning and produces the output:
120/// @code
121/// Now you see it.
122/// @endcode
123/// Now, we call `catStrings" again and forget to add the terminating `NULL':
124/// @code
125/// catStrings(buf, "Now", "you", "don't.");
126/// printf("%s\n", buf);
127/// @endcode
128/// Finally, we get the compiler warning:
129/// @code
130/// .../bsla_nullterminated.t.cpp:412:47: warning: missing sentinel in function
131/// call [-Wsentinel]
132/// catStrings(buf, "Now", "you", "don't.");
133/// ^
134/// , nullptr
135/// .../bsla_nullterminated.t.cpp:137:10: note: function has been explicitly
136/// marked sentinel here
137/// void catStrings(char *outputBuffer, ...)
138/// ^
139/// @endcode
140///
141/// ### Example 2: catVerdict Function {#bsla_nullterminated-example-2-catverdict-function}
142///
143///
144/// Suppose we want to have a function that, passed a variable length argument
145/// list of `const char *` strings terminated by `NULL`, concatenates the
146/// strings, separated by spaces, into a buffer, and then there's an additional
147/// integer argument, interpreted as a boolean, that determines what is to be
148/// appended to the end of the buffer.
149///
150/// First, we declare and define the function, annotated with
151/// `BSLA_NULL_TERMINATEDAT(1)`:
152/// @code
153/// void catVerdict(char *outputBuffer, ...) BSLA_NULLTERMINATEDAT(1);
154/// void catVerdict(char *outputBuffer, ...)
155/// // The specified 'outputBuffer' is a buffer where output is to be
156/// // placed. All but the last 2 of the specified '...' arguments are
157/// // 'const char *' strings to be concatenated together into
158/// // 'outputBuffer', separated by spaces. The second-to-last argument is
159/// // to be 'NULL', and the last argument is an 'int' interpreted as a
160/// // boolean to determine whether the buffer is to end with a verdict of
161/// // "guilty" or "not guilty". The behavior is undefined unless the
162/// // types of all the arguments are correct and the second to last
163/// // argument is 'NULL'.
164/// {
165/// *outputBuffer = 0;
166///
167/// va_list ap;
168/// va_start(ap, outputBuffer);
169/// const char *next;
170/// for (bool first = 1; (next = va_arg(ap, const char *)); first = 0) {
171/// ::strcat(outputBuffer, first ? "" : " ");
172/// ::strcat(outputBuffer, next);
173/// }
174///
175/// const bool guilty = va_arg(ap, int);
176/// ::strcat(outputBuffer, guilty ? ": guilty" : ": not guilty");
177/// va_end(ap);
178/// }
179/// @endcode
180/// Then, in `main`, we call `catVerdict` correctly:
181/// @code
182/// char buf[1000];
183/// catVerdict(buf, "We find the", "defendant,", "Bugs Bunny", NULL, 0);
184/// printf("%s\n", buf);
185/// @endcode
186/// which compiles without a warning and produces the output:
187/// @code
188/// We find the defendant, Bugs Bunny: not guilty
189/// @endcode
190/// Next, we call `catVerdict` with no `NULL` passed, and get a warning (and
191/// probably a core dump if we ran it):
192/// @code
193/// catVerdict(buf, "We find the", "defendant,", "Wile E. Coyote", 1);
194/// printf("%s\n", buf);
195/// @endcode
196/// And we get the following compiler warning:
197/// @code
198/// .../bsla_nullterminated.t.cpp:447:70: warning: missing sentinel in function
199/// call [-Wsentinel]
200/// catVerdict(buf, "We find the", "defendant,", "Wile E. Coyote", 1);
201/// ^
202/// , nullptr
203/// .../bsla_nullterminated.t.cpp:171:10: note: function has been explicitly
204/// marked sentinel here
205/// void catVerdict(char *outputBuffer, ...)
206/// ^
207/// @endcode
208/// Now, we call `catVerdict` and forget to put the integer that indicates guilt
209/// or innocence after the `NULL`. This means that `NULL` is happening at index
210/// 0, not index 1, which violates the requirement imposed by the annotation:
211/// @code
212/// catVerdict(buf, "We find the", "defendant,", "Road Runner", NULL);
213/// printf("%s\n", buf);
214/// @endcode
215/// Finally, we get the compiler warning:
216/// @code
217/// .../bsla_nullterminated.t.cpp:471:67: warning: missing sentinel in function
218/// call [-Wsentinel]
219/// catVerdict(buf, "We find the", "defendant,", "Road Runner", NULL);
220/// ^
221/// , nullptr
222/// .../bsla_nullterminated.t.cpp:171:10: note: function has been explicitly
223/// marked sentinel here
224/// void catVerdict(char *outputBuffer, ...)
225/// ^
226/// @endcode
227/// @}
228/** @} */
229/** @} */
230
231/** @addtogroup bsl
232 * @{
233 */
234/** @addtogroup bsla
235 * @{
236 */
237/** @addtogroup bsla_nullterminated
238 * @{
239 */
240
241#include <bsls_platform.h>
242
243 // =============================
244 // Checks for Pre-Defined macros
245 // =============================
246
247#if defined(BSLA_NULLTERMINATED)
248#error BSLA_NULLTERMINATED is already defined!
249#endif
250
251#if defined(BSLA_NULLTERMINATED_IS_ACTIVE)
252#error BSLA_NULLTERMINATED_IS_ACTIVE is already defined!
253#endif
254
255#if defined(BSLA_NULLTERMINATEDAT)
256#error BSLA_NULLTERMINATEDAT is already defined!
257#endif
258
259#if defined(BSLA_NULLTERMINATEDAT_IS_ACTIVE)
260#error BSLA_NULLTERMINATEDAT_IS_ACTIVE is already defined!
261#endif
262 // =========================
263 // Set macros as appropriate
264 // =========================
265
266#if (defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG)) && \
267 !defined(BSLS_PLATFORM_OS_SOLARIS)
268 #define BSLA_NULLTERMINATED __attribute__((__sentinel__))
269 #define BSLA_NULLTERMINATEDAT(ARG_IDX) \
270 __attribute__((__sentinel__(ARG_IDX)))
271
272 #define BSLA_NULLTERMINATED_IS_ACTIVE 1
273 #define BSLA_NULLTERMINATEDAT_IS_ACTIVE 1
274#else
275 #define BSLA_NULLTERMINATED
276 #define BSLA_NULLTERMINATEDAT(ARG_IDX)
277#endif
278
279#endif
280
281// ----------------------------------------------------------------------------
282// Copyright 2019 Bloomberg Finance L.P.
283//
284// Licensed under the Apache License, Version 2.0 (the "License");
285// you may not use this file except in compliance with the License.
286// You may obtain a copy of the License at
287//
288// http://www.apache.org/licenses/LICENSE-2.0
289//
290// Unless required by applicable law or agreed to in writing, software
291// distributed under the License is distributed on an "AS IS" BASIS,
292// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
293// See the License for the specific language governing permissions and
294// limitations under the License.
295// ----------------------------- END-OF-FILE ----------------------------------
296
297/** @} */
298/** @} */
299/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195