BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsla_scanf.h
Go to the documentation of this file.
1/// @file bsla_scanf.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsla_scanf.h -*-C++-*-
8#ifndef INCLUDED_BSLA_SCANF
9#define INCLUDED_BSLA_SCANF
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsla_scanf bsla_scanf
15/// @brief Provide a macro for checking `scanf`-style format strings.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsla
19/// @{
20/// @addtogroup bsla_scanf
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsla_scanf-purpose"> Purpose</a>
25/// * <a href="#bsla_scanf-macros"> Macros </a>
26/// * <a href="#bsla_scanf-description"> Description </a>
27/// * <a href="#bsla_scanf-macro-reference"> Macro Reference </a>
28/// * <a href="#bsla_scanf-usage"> Usage </a>
29/// * <a href="#bsla_scanf-example-1-populate-a-sequence-of-ints-and-floats-with-random-numbers"> Example 1: Populate a Sequence of ints and floats with Random Numbers </a>
30///
31/// # Purpose {#bsla_scanf-purpose}
32/// Provide a macro for checking `scanf`-style format strings.
33///
34/// # Macros {#bsla_scanf-macros}
35///
36/// - BSLA_SCANF(FMTIDX, STARTIDX): validate `scanf` format and arguments
37/// - BSLA_SCANF_IS_ACTIVE: defined if `BSLA_SCANF` is active
38///
39/// @see bsla_annotations
40///
41/// # Description {#bsla_scanf-description}
42/// This component provides a preprocessor macro that indicates
43/// that one of the arguments to a function is a `scanf`-style format string,
44/// and that the arguments starting at a certain index are to be checked for
45/// compatibility with that format string.
46///
47/// ## Macro Reference {#bsla_scanf-macro-reference}
48///
49///
50/// `BSLA_SCANF(FMTIDX, STARTIDX)`:
51/// This annotation instructs the compiler to perform additional checks on
52/// so-annotated functions that take `scanf`-style arguments, which should
53/// be type-checked against a format string.
54///
55/// - The `FMTIDX` parameter is the one-based index to the `const` format
56/// string. The `STARTIDX` parameter is the one-based index to the first
57/// variable argument to type-check against that format string. For
58/// example:
59/// @code
60/// extern int my_scanf(void *obj, const char *format, ...) BSLA_SCANF(2, 3);
61/// @endcode
62///
63/// `BSLA_SCANF_IS_ACTIVE`:
64/// The macro `BSLA_SCANF_IS_ACTIVE` is defined if `BSLA_SCANF` expands to
65/// something with the desired effect; otherwise `BSLA_SCANF_IS_ACTIVE` is
66/// not defined and `BSLA_SCANF` expands to nothing.
67///
68/// ## Usage {#bsla_scanf-usage}
69///
70///
71/// This section illustrates intended use of this component.
72///
73/// ### Example 1: Populate a Sequence of ints and floats with Random Numbers {#bsla_scanf-example-1-populate-a-sequence-of-ints-and-floats-with-random-numbers}
74///
75///
76/// Suppose we want to have a function that will populate a list of `int`s and
77/// `float`s with random numbers in the range `[ 0 .. 100 )`.
78///
79/// First, we define our function:
80/// @code
81/// int populateValues(const char *format, ...) BSLA_SCANF(1, 2);
82/// // Use 'rand' to populate 'int's and 'float's, passed by pointer after
83/// // the specified 'format', which will specify the types of the
84/// // variables passed. Return the number of variables populated, or -1
85/// // if the format string is invalid.
86///
87/// int populateValues(const char *format, ...)
88/// {
89/// int ret = 0;
90///
91/// va_list ap;
92/// va_start(ap, format);
93///
94/// for (const char *pc = format; *pc; ++pc) {
95/// if ('%' != *pc) {
96/// continue;
97/// }
98/// const char c = *++pc;
99/// if ('%' == c) {
100/// continue;
101/// }
102/// else if ('d' == c) {
103/// * va_arg(ap, int *) = static_cast<unsigned>(rand()) % 100;
104/// }
105/// else if ('f' == c || 'e' == c || 'g' == c) {
106/// const int characteristic = static_cast<unsigned>(rand()) % 100;
107/// const int mantissa = static_cast<unsigned>(rand()) % 1000;
108///
109/// * va_arg(ap, float *) = static_cast<float>(characteristic +
110/// mantissa / 1000.0);
111/// }
112/// else {
113/// // Unrecognized character. Return a negative value.
114///
115/// ret = -1;
116/// break;
117/// }
118///
119/// ++ret;
120/// }
121///
122/// va_end(ap);
123///
124/// return ret;
125/// }
126/// @endcode
127/// Then, in `main`, we call `populateValues` properly:
128/// @code
129/// float ff[3] = { 0, 0, 0 };
130/// int ii[3] = { 0, 0, 0 };
131///
132/// int numVars = populateValues("%d %g %g %d %d %g",
133/// &ii[0], &ff[0], &ff[1], &ii[1], &ii[2], &ff[2]);
134/// assert(6 == numVars);
135/// for (int jj = 0; jj < 3; ++jj) {
136/// assert(0 <= ii[jj]);
137/// assert(0 <= ff[jj]);
138/// assert( ii[jj] < 100);
139/// assert( ff[jj] < 100);
140/// }
141/// printf("%d %g %g %d %d %g\n",
142/// ii[0], ff[0], ff[1], ii[1], ii[2], ff[2]);
143/// @endcode
144/// Next, we observe that there are no compiler warnings and a reasonable set of
145/// random numbers are output:
146/// @code
147/// 83 86.777 15.793 35 86 92.649
148/// @endcode
149/// Now, we make a call where the arguments don't match the format string:
150/// @code
151/// numVars = populateValues("%d %g", &ff[0], &ii[0]);
152/// @endcode
153/// Finally, we observe the following compiler warnings with clang:
154/// @code
155/// .../bsla_scanf.t.cpp:351:43: warning: format specifies type 'int *' but the
156/// argument has type 'float *' [-Wformat]
157/// numVars = populateValues("%d %g", &ff[0], &ii[0]);
158/// ~~ ^~~~~~
159/// %f
160/// .../bsla_scanf.t.cpp:351:51: warning: format specifies type 'float *' but
161/// the argument has type 'int *' [-Wformat]
162/// numVars = populateValues("%d %g", &ff[0], &ii[0]);
163/// ~~ ^~~~~~
164/// %d
165/// @endcode
166/// @}
167/** @} */
168/** @} */
169
170/** @addtogroup bsl
171 * @{
172 */
173/** @addtogroup bsla
174 * @{
175 */
176/** @addtogroup bsla_scanf
177 * @{
178 */
179
180#include <bsls_compilerfeatures.h>
181#include <bsls_platform.h>
182
183 // =============================
184 // Checks for Pre-Defined macros
185 // =============================
186
187#if defined(BSLA_SCANF)
188#error BSLA_SCANF is already defined!
189#endif
190
191#if defined(BSLA_SCANF_IS_ACTIVE)
192#error BSLA_SCANF_IS_ACTIVE is already defined!
193#endif
194
195 // =========================
196 // Set macros as appropriate
197 // =========================
198
199#if defined(BSLS_PLATFORM_CMP_GNU) || \
200 defined(BSLS_PLATFORM_CMP_CLANG) || \
201 defined(BSLS_PLATFORM_CMP_HP)
202 #define BSLA_SCANF(FMTIDX, STARTIDX) \
203 __attribute__((format(scanf, FMTIDX, STARTIDX)))
204
205 #define BSLA_SCANF_IS_ACTIVE 1
206#else
207 #define BSLA_SCANF(FMTIDX, STARTIDX)
208#endif
209
210#endif
211
212// ----------------------------------------------------------------------------
213// Copyright 2019 Bloomberg Finance L.P.
214//
215// Licensed under the Apache License, Version 2.0 (the "License");
216// you may not use this file except in compliance with the License.
217// You may obtain a copy of the License at
218//
219// http://www.apache.org/licenses/LICENSE-2.0
220//
221// Unless required by applicable law or agreed to in writing, software
222// distributed under the License is distributed on an "AS IS" BASIS,
223// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
224// See the License for the specific language governing permissions and
225// limitations under the License.
226// ----------------------------- END-OF-FILE ----------------------------------
227
228/** @} */
229/** @} */
230/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195