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