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
>
12
BSLS_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
/** @} */
bsls_ident.h
BSLS_IDENT
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition
bsls_ident.h:238
doxygen_input
bde
groups
bsl
bsla
bsla_nullterminated.h
Generated by
1.9.8