BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsls_bslsourcenameparserutil.h
Go to the documentation of this file.
1/// @file bsls_bslsourcenameparserutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_bslsourcenameparserutil.h -*-C++-*-
8#ifndef INCLUDED_BSLS_BSLSOURCENAMEPARSERUTIL
9#define INCLUDED_BSLS_BSLSOURCENAMEPARSERUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_bslsourcenameparserutil bsls_bslsourcenameparserutil
15/// @brief Provide low-level functions for parsing source file names.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_bslsourcenameparserutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_bslsourcenameparserutil-purpose"> Purpose</a>
25/// * <a href="#bsls_bslsourcenameparserutil-classes"> Classes </a>
26/// * <a href="#bsls_bslsourcenameparserutil-description"> Description </a>
27/// * <a href="#bsls_bslsourcenameparserutil-bde-style-source-file-names"> BDE-Style Source File Names </a>
28/// * <a href="#bsls_bslsourcenameparserutil-public-component-names"> Public Component Names </a>
29/// * <a href="#bsls_bslsourcenameparserutil-subordinate-or-package-internal-component-names"> Subordinate or Package-Internal Component Names </a>
30/// * <a href="#bsls_bslsourcenameparserutil-test-driver-source-file-names"> Test Driver Source File Names </a>
31/// * <a href="#bsls_bslsourcenameparserutil-other-source-file-names"> Other Source File Names </a>
32/// * <a href="#bsls_bslsourcenameparserutil-usage"> Usage </a>
33/// * <a href="#bsls_bslsourcenameparserutil-example-1-determining-component-name-from-source-file-name"> Example 1: Determining Component Name from Source File Name </a>
34/// * <a href="#bsls_bslsourcenameparserutil-example-2-determining-the-type-of-a-source-file"> Example 2: Determining the Type of a Source File </a>
35/// * <a href="#bsls_bslsourcenameparserutil-example-3-reporting-parsing-errors"> Example 3: Reporting Parsing Errors </a>
36///
37/// # Purpose {#bsls_bslsourcenameparserutil-purpose}
38/// Provide low-level functions for parsing source file names.
39///
40/// # Classes {#bsls_bslsourcenameparserutil-classes}
41///
42/// - bsls::BslSourceNameParserUtil: utility namespace to parse source file names
43///
44/// @see
45///
46/// # Description {#bsls_bslsourcenameparserutil-description}
47/// This component provides a namespace
48/// `bsls::BslSourceNameParserUtil` for methods to parse source code file names
49/// (as may be reported by the `__FILE__` macro, or a listing), including
50/// BDE-style (Lakos-style) component and test driver source file names. This
51/// component is not using any C++ library or `bsl` dependencies. In other
52/// words, it uses only some functionality of the C standard library, and C++
53/// core language features. This is a necessary limitation because parsing file
54/// names may be used form the lowest levels of `bsl` code, especially in test
55/// drivers.
56///
57/// ## BDE-Style Source File Names {#bsls_bslsourcenameparserutil-bde-style-source-file-names}
58///
59///
60/// The majority of source files in a BDE-style code base are component header
61/// and implementation, and their test driver source files. There are other,
62/// special, source files names that we describe only briefly. In this section
63/// we introduce the basic construct of the component source file names as well
64/// as the component test driver file names as implemented by this utility. We
65/// do not provide complete coverage of all possible BDE-style source file
66/// naming conventions, for that see John Lakos: Large Scale C++ Volume 1.
67///
68/// ### Public Component Names {#bsls_bslsourcenameparserutil-public-component-names}
69///
70///
71/// A component consists of two source files sharing the same file name with
72/// different extensions: `.h` for the header file and `.cpp` for the
73/// implementation file. The component file name itself consists of the package
74/// name the component belongs to (such as `bsls`), followed by an underscore
75/// (`_`), followed by the name of the component (such as `atomicoperations`),
76/// all lowercase letters, e.g., `bsls_atomicoperations.h`,
77/// `bsls_atomicoperations.cpp`.
78///
79/// ### Subordinate or Package-Internal Component Names {#bsls_bslsourcenameparserutil-subordinate-or-package-internal-component-names}
80///
81///
82/// Subordinate components are considered package-internal and, similarly to
83/// component-private type names, formed by adding further underscore-delimited
84/// "sections" to the file name (before the extension), such as:
85/// `bsls_atomicoperations_default.h`, `bsls_atomicoperations_x64_all_gcc.h`,
86/// `bsls_assert_macroreset.h`, or `bsls_byteorderutil_impl.h`.
87///
88/// There are two kinds of special subordinate components that are considered
89/// part of the main component, and they are in separate files only for
90/// non-structural (technical) reasons. One such kind is the so-called
91/// subordinate test component, that will be introduced in the section below.
92/// The other is generated so-called `_cpp03` components for (mainly) emulating
93/// variadic templates in C++03. Such generated subordinate components get
94/// `_cpp03` appended to their file name, right before the first dot `.` of the
95/// extension(s).
96///
97/// ### Test Driver Source File Names {#bsls_bslsourcenameparserutil-test-driver-source-file-names}
98///
99///
100/// Test driver source file names are normally very simple: the same base name
101/// as the component, followed by `.t.cpp`. However some components that
102/// provide class and functions templates with many template parameters require
103/// more than one test driver so the test driver files can compile, and compile
104/// in a reasonable amount of time. (Most often old, C++03 compilers run out of
105/// resources or internal limits, but in case of optimized code even new
106/// compilers may try to use too much memory.)
107///
108/// In the past, special private components were created when a test driver was
109/// too large to compile. Those components are called "subordinate test
110/// (driver) components", and their names were created by having the last
111/// underscore-delimited "segment" of the name to start with `_test`.
112/// Optionally, after `_test` there could be a decimal number between 0-9, or
113/// 00-99. (Due to legacy code that used text, we also allow alpha characters,
114/// like `_testconstructors`.) So for an imaginary
115/// `bslstl_unordinarymultikeymultimap.h` and `.cpp` we may have the expected
116/// `bslstl_unordinarymultikeymultimap.t.cpp`, but also
117/// `bslstl_unordinarymultikeymultimap_test1.t.cpp`/`.h`/`.cpp`, and so on.
118///
119/// Newer complex components (and components that have been modernized) will not
120/// have subordinate test drivers, but so-called test driver parts. Test driver
121/// part source file names are created by inserting a dot and a decimal number
122/// (between 0-9 or 00-99), right before the `.t.cpp`. Our example from the
123/// previous paragraph would then have several test driver source files:
124/// `bslstl_unordinarymultikeymultimap.0.t.cpp`,
125/// `bslstl_unordinarymultikeymultimap.1.t.cpp`, and so on, but only one
126/// component `bslstl_unordinarymultikeymultimap.h` and `.cpp`.
127///
128/// Because the components that need many files for their test driver often use
129/// variadic templates (that need to be emulated in C++03) we often also have:
130/// `bslstl_unordinarymultikeymultimap_test1_cpp03.t.cpp`/`.h`/`.cpp`, etc., or
131/// `bslstl_unordinarymultikeymultimap_cpp03.0.t.cpp` files as well.
132///
133/// For the subordinate test components (including the ones that end with
134/// `_cpp03`) we consider the main component name
135/// @ref bslstl_unordinarymultikeymultimap to be the component name part, because
136/// the other components exists only due to compiler technical limitations.
137///
138/// ### Other Source File Names {#bsls_bslsourcenameparserutil-other-source-file-names}
139///
140///
141/// Special source files that are not components or component test drivers have
142/// either a special one letter prefix, a one letter "designator extension", or
143/// a first segment that is too long to be a package name (more than 6
144/// characters). The current parsing logic in this utility does not directly
145/// recognize such source file names. The parsing logic makes sure that such
146/// names will not be successfully parsed in a way that the reported component
147/// name could match a real component.
148///
149/// ## Usage {#bsls_bslsourcenameparserutil-usage}
150///
151///
152/// This section illustrates intended use of this component.
153///
154/// ### Example 1: Determining Component Name from Source File Name {#bsls_bslsourcenameparserutil-example-1-determining-component-name-from-source-file-name}
155///
156///
157/// Suppose we need to determine the component name from one of its source file
158/// names. To ease understanding we use string literals for source file names.
159///
160/// First, we declare the result variables that the parser will fill:
161/// @code
162/// const char *componentStart = 0;
163/// size_t componentLength = 0;
164/// @endcode
165/// Next, we call the parser, saving its return value:
166/// @code
167/// int returnCode = bsls::BslSourceNameParserUtil::getComponentName(
168/// &componentStart,
169/// &componentLength,
170/// "groups/abc/abcx/abcx_name_cpp03.h");
171/// @endcode
172/// Now, we verify that the parsing was successful:
173/// @code
174/// assert(0 == returnCode);
175/// @endcode
176/// Finally, we verify that the expected component name is found:
177/// @code
178/// assert(9 == componentLength &&
179/// 0 == memcmp("abcx_name", componentStart, 9));
180/// @endcode
181/// Notice how the "_cpp03" suffix of the generated file has been removed.
182///
183/// ### Example 2: Determining the Type of a Source File {#bsls_bslsourcenameparserutil-example-2-determining-the-type-of-a-source-file}
184///
185///
186/// Suppose we need to determine, in addition to the component name, what kind
187/// source file name do we have. To ease understanding we use string literals
188/// for source file names.
189///
190/// First, we declare the result variables that the parser will fill:
191/// @code
192/// const char *componentStart = 0;
193/// size_t componentLength = 0;
194/// unsigned sourceType = ~0u;
195/// @endcode
196/// Next, we call the parser with the first name, passing the address of the
197/// optional output variable after the source file name:
198/// @code
199/// int returnCode = bsls::BslSourceNameParserUtil::getComponentName(
200/// &componentStart,
201/// &componentLength,
202/// "groups/abc/abcx/abcx_name_cpp03.h",
203/// &sourceType);
204/// @endcode
205/// Then, we verify that the parsing was successful, and the expected component
206/// name is found:
207/// @code
208/// assert(0 == returnCode);
209/// assert(9 == componentLength &&
210/// 0 == memcmp("abcx_name", componentStart, 9));
211/// @endcode
212/// Next, we verify the determined source file type by examining the "kind",
213/// stored in the bits masked by `bsls::BslSourceNameParserUtil::k_MASK_KIND`,
214/// and the flags stored in other bits:
215/// @code
216/// typedef bsls::BslSourceNameParserUtil Util; // For brevity
217///
218/// assert(Util::k_HEADER == (sourceType & Util::k_MASK_KIND));
219///
220/// assert(0 == (sourceType & Util::k_IS_MULTIFILE_TEST ));
221/// assert(0 == (sourceType & Util::k_IS_SUBORDINATE_TEST));
222/// assert(0 != (sourceType & Util::k_IS_CPP03_GENERATED ));
223/// @endcode
224/// Then, we can verify a subordinate test component implementation file name.
225/// These names, and also headers for subordinate test components are special as
226/// they are not supposed to contain executable code. They are just another
227/// test driver for their main component.
228/// @code
229/// returnCode = bsls::BslSourceNameParserUtil::getComponentName(
230/// &componentStart,
231/// &componentLength,
232/// "groups/abc/abcx/abcx_name_test12.cpp",
233/// &sourceType);
234///
235/// assert(0 == returnCode);
236/// assert(9 == componentLength &&
237/// 0 == memcmp("abcx_name", componentStart, 9));
238/// @endcode
239/// Note that the main component name is reported.
240/// @code
241/// assert(Util::k_IMPL == (sourceType & Util::k_MASK_KIND));
242///
243/// assert(0 == (sourceType & Util::k_IS_MULTIFILE_TEST ));
244/// assert(0 != (sourceType & Util::k_IS_SUBORDINATE_TEST));
245/// assert(0 == (sourceType & Util::k_IS_CPP03_GENERATED ));
246/// @endcode
247/// Now, we verify a traditional test driver file name of a subordinate test
248/// component:
249/// @code
250/// returnCode = bsls::BslSourceNameParserUtil::getComponentName(
251/// &componentStart,
252/// &componentLength,
253/// "groups/abc/abcx/abcx_name_test12.t.cpp",
254/// &sourceType);
255///
256/// assert(0 == returnCode);
257/// assert(9 == componentLength &&
258/// 0 == memcmp("abcx_name", componentStart, 9));
259///
260/// assert(Util::k_TTEST == (sourceType & Util::k_MASK_KIND));
261///
262/// assert(0 == (sourceType & Util::k_IS_MULTIFILE_TEST ));
263/// assert(0 != (sourceType & Util::k_IS_SUBORDINATE_TEST));
264/// assert(0 == (sourceType & Util::k_IS_CPP03_GENERATED ));
265/// @endcode
266/// Finally, we verify a multi-file test driver source:
267/// @code
268/// returnCode = bsls::BslSourceNameParserUtil::getComponentName(
269/// &componentStart,
270/// &componentLength,
271/// "wxya_other_cpp03.0.g.cpp",
272/// &sourceType);
273///
274/// assert(0 == returnCode);
275/// assert(10 == componentLength &&
276/// 0 == memcmp("wxya_other", componentStart, 10));
277///
278/// assert(Util::k_GTEST == (sourceType & Util::k_MASK_KIND));
279///
280/// assert(0 != (sourceType & Util::k_IS_MULTIFILE_TEST ));
281/// assert(0 == (sourceType & Util::k_IS_SUBORDINATE_TEST));
282/// assert(0 != (sourceType & Util::k_IS_CPP03_GENERATED ));
283/// @endcode
284///
285/// ### Example 3: Reporting Parsing Errors {#bsls_bslsourcenameparserutil-example-3-reporting-parsing-errors}
286///
287///
288/// Suppose we need to parse source file names from an external source, and
289/// therefore we may need to report the reason for parsing failures for human
290/// readers (of log files). To ease understanding we use string literals for
291/// source file names.
292///
293/// First, we declare the result variables that the parser will fill:
294/// @code
295/// const char *componentStart = 0;
296/// size_t componentLength = 0;
297/// @endcode
298/// Next, we can call the parser with a too short file name and save the return
299/// value:
300/// @code
301/// int returnCode = bsls::BslSourceNameParserUtil::getComponentName(
302/// &componentStart,
303/// &componentLength,
304/// "a.h");
305/// @endcode
306/// Then, we verify that the parsing has failed:
307/// @code
308/// assert(0 != returnCode);
309/// @endcode
310/// Next, we output a brief error message to the user if requested:
311/// @code
312/// if (verbose) {
313/// printf("Error parsing source file name \"%s\": %s\n",
314/// "a.h",
315/// bsls::BslSourceNameParserUtil::errorMessage(returnCode));
316/// // Output will indicate the file name was too short (to be a BDE name)
317/// }
318/// @endcode
319/// Now, we demonstrate another failing-to-parse source name and its error
320/// message:
321/// @code
322/// returnCode = bsls::BslSourceNameParserUtil::getComponentName(
323/// &componentStart,
324/// &componentLength,
325/// "abcxyz_name.hpp");
326/// assert(0 != returnCode);
327/// if (verbose) {
328/// printf("Error parsing source file name \"%s\": %s\n",
329/// "abcxyz_name.hpp",
330/// bsls::BslSourceNameParserUtil::errorMessage(returnCode));
331/// // Output will indicate an unsupported extension
332/// }
333/// @endcode
334/// Finally, we demonstrate the "missing test driver tag" error:
335/// @code
336/// returnCode = bsls::BslSourceNameParserUtil::getComponentName(
337/// &componentStart,
338/// &componentLength,
339/// "abcx_name..t.cpp");
340/// assert(0 != returnCode);
341/// if (verbose) {
342/// printf("Error parsing source file name \"%s\": %s\n",
343/// "abcx_name..t.cpp",
344/// bsls::BslSourceNameParserUtil::errorMessage(returnCode));
345/// // Output will indicate two dots next to each other in the file name
346/// }
347/// @endcode
348/// @}
349/** @} */
350/** @} */
351
352/** @addtogroup bsl
353 * @{
354 */
355/** @addtogroup bsls
356 * @{
357 */
358/** @addtogroup bsls_bslsourcenameparserutil
359 * @{
360 */
361
362#include <stddef.h> // 'size_t'
363
364
365namespace bsls {
366
367 //===============================
368 // struct BslSourceNameParserUtil
369 //===============================
370
371/// This `struct` provides a namespace for `static` utility functions that
372/// parse source file names (as may be reported by the `__FILE__` macro),
373/// including Lakos-style component source and test driver names.
375
376 // PUBLIC TYPES
378 // Bit masks and constants that describe the meaning of the 'type_p'
379 // parameter of 'getComponentName' below. Only some bits of the lowest
380 // significant word are used at the moment:
381 //..
382 // 7 6 5 4 3 2 10
383 // |r|r|3|S|M|X|KK|
384 //
385 // K - two bits describing the extension (kind)
386 //
387 // X - a bit that is set only the file is a test driver "template"
388 // source file with the extension ".xt.cpp". These files are valid
389 // C++ code, but they are not compiled directly, as they are too
390 // large/slow to compile (on certain platforms/compilers). Their
391 // content is selectively copied into temporary '.NN.t.xpp' files
392 // that are actually compiled into executables. The temporary
393 // '.NN.t.xpp' files use '#line N "filename"' directives to refer
394 // back to the ".xt.cpp" template so the actual build and run time
395 // (ASSERT) messages will point to the actual source that is
396 // visible to the programmer (in the source control system). (The
397 // generated '.NN.t.xpp' files exist during the build only.)
398 //
399 // M - a bit that is set only the file is a test driver source file,
400 // and it is a multi-file test driver that has a "segment" of
401 // (normally) decimal digits, e.g., "abcx_name.14.t.cpp".
402 //
403 // S - a bit that is set if the file belongs to a subordinate test
404 // driver, a file that has "_test", followed by non-underscore
405 // characters (except if it is also a generated simulation file for
406 // C++03, see below)
407 //
408 // 3 - a bit that is set if the file name is a generated simulation
409 // file for C++03 (simulates some C++11 features such as variadic
410 // templates up to a certain number of parameters etc)
411 //
412 // r - all other bits are reserved for future use
413 //..
414 // For example "abcx_name_testq_cpp03.g.cpp" will be
415
418
419 k_HEADER = 0x0, // .h
420 k_IMPL = 0x1, // .cpp
421 k_TTEST = 0x2, // .t.cpp -- traditional test driver
422 k_GTEST = 0x3, // .g.cpp -- Google test test driver
423
424 k_IS_TEST_XTEMPLATE = 0x4, // ".xt.cpp" file
425
426 k_IS_MULTIFILE_TEST = 0x8, // "[^a-z0-9]+.(t.cpp|g.cpp)"
427
428 k_IS_SUBORDINATE_TEST = 0x10, // "_test[^a-z0-9]*.(h|cpp|t.cpp|g.cpp)"
429
430 k_IS_CPP03_GENERATED = 0x20 // "_cpp03" at the very end, before exts
431 };
432
433 // CLASS METHODS
434
435 // Parsing
436
437 /// Parse the specified Lakos-style `sourceName` source file name with
438 /// optional path portion to find the component name part. Return zero
439 /// on success and a non-zero value if parsing failed. In case of
440 /// success, fill the specified `componentNamePtr` with a pointer to the
441 /// first character, and the specified `componentNameLength` with the
442 /// number of character of the component name found. Optionally specify
443 /// `type_p`. When `type_p` is not 0 set the bits of the pointed
444 /// `unsigned`, according to `SourceTypes`, that describe the type of
445 /// the source file that was parsed.
446 ///
447 /// This function does not validate its input, it assumes that it is a
448 /// valid Lakos-style component source or test driver file name, or one
449 /// of the special names defined by John Lakos: Large Scale C++ Design
450 /// (application, adapter, etc). If `SourceName` is not as such, the
451 /// function may return a non-zero error value, or it may report success
452 /// with its output is unspecified.
453 ///
454 /// Subordinate test component sources are special, as they should not
455 /// contain code, only their test drivers. The component name reported
456 /// for subordinate test drivers is the main component name.
457 ///
458 /// Use the `errorMessage` function (in this utility) to get a static,
459 /// brief English textual description of a negative return value.
460 static int getComponentName(const char **componentNamePtr,
461 size_t *componentNameLength,
462 const char *sourceName,
463 unsigned *type_p = 0);
464
465 // Miscellaneous
466
467 /// Return a static, brief English error message that describes the
468 /// specified negative parsing `errorCode`. The behavior is undefined
469 /// unless `errorCode < 0` and was returned by one of the parsing
470 /// methods (of this utility) that states in its contract to use this
471 /// method to get the description of an error code.
472 static const char *errorMessage(int errorCode);
473};
474
475} // close package namespace
476
477
478#endif
479
480// ----------------------------------------------------------------------------
481// Copyright 2022 Bloomberg Finance L.P.
482//
483// Licensed under the Apache License, Version 2.0 (the "License");
484// you may not use this file except in compliance with the License.
485// You may obtain a copy of the License at
486//
487// http://www.apache.org/licenses/LICENSE-2.0
488//
489// Unless required by applicable law or agreed to in writing, software
490// distributed under the License is distributed on an "AS IS" BASIS,
491// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
492// See the License for the specific language governing permissions and
493// limitations under the License.
494// ----------------------------- END-OF-FILE ----------------------------------
495
496/** @} */
497/** @} */
498/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlt_iso8601util.h:691
Definition bsls_bslsourcenameparserutil.h:374
static int getComponentName(const char **componentNamePtr, size_t *componentNameLength, const char *sourceName, unsigned *type_p=0)
SourceTypes
Definition bsls_bslsourcenameparserutil.h:377
@ k_MASK_TEST
Definition bsls_bslsourcenameparserutil.h:417
@ k_HEADER
Definition bsls_bslsourcenameparserutil.h:419
@ k_MASK_KIND
Definition bsls_bslsourcenameparserutil.h:416
@ k_GTEST
Definition bsls_bslsourcenameparserutil.h:422
@ k_IMPL
Definition bsls_bslsourcenameparserutil.h:420
@ k_IS_SUBORDINATE_TEST
Definition bsls_bslsourcenameparserutil.h:428
@ k_TTEST
Definition bsls_bslsourcenameparserutil.h:421
@ k_IS_TEST_XTEMPLATE
Definition bsls_bslsourcenameparserutil.h:424
@ k_IS_MULTIFILE_TEST
Definition bsls_bslsourcenameparserutil.h:426
@ k_IS_CPP03_GENERATED
Definition bsls_bslsourcenameparserutil.h:430
static const char * errorMessage(int errorCode)