Skip to content

Commit e87dd41

Browse files
Hash API (redux) (#45)
* chore(misc): language discrimination; CI branch(es) * chore(misc): ensuring `\file` designators are correct * chore(mist): removed unused `CSTRING_VECTOR_ASSERT()` * chore(misc): tidying * fix(cstring): discriminate cstring_hash_t and use it for hashing Gate <stdint.h> on C99, on C++ with that header or C++11, and on MSVC 7.1 or later, and typedef cstring_hash_t to uint64_t when it is included; use cstring_hash_t for the djb2 and FNV-1a API and for the hash unit tests. * chore(performance tests): prefer `uint64_t` to `std::uint64_t` * test(cstring): exercise the hashing API from a C unit test Move the eight C hashing functions into **test.unit.hash** (`entry.c`) so the suite builds when `NO_CSTRING_CPP_API` is on. Keep the C++ shim checks in **test.unit.hash.cxx**, which stays behind that option. * test(cstring): lock high-byte and embedded-NUL hash results Cover octet 0xFF and an interior NUL in test.unit.hash. Exact narrow vectors stay off the wide build so a later wchar_t fix is not frozen. * feat(cstring): publish the djb2 and FNV-1a basis macros Add CSTRING_HASH_DJB2_SEED, CSTRING_HASH_FNV1A_OFFSET, and CSTRING_HASH_FNV1A_PRIME beside cstring_hash_t, and use them as the only copies of those constants in the hash implementation. Cite Yigit's djb2 page and the Fowler, Noll, and Vo notes and RFC 9923, and lock each macro to its historic literal in the C unit test. * fix * refactor(cstring): rename the case-folded hash suffix to _case Rename the case-folded hash functions from the `_ci` suffix to `_case` (`cstring_hash_djb2_case`, `cstring_hash_djb2_len_case`, and the FNV-1a twins), including the C++ shims and the unit tests. * refactor(cstring): rename the counted hash suffix from _len to _buf Rename the pointer-and-length hash functions from `_len` to `_buf` (`cstring_hash_djb2_buf`, `cstring_hash_djb2_buf_case`, and the FNV-1a twins), including the C++ shims and the unit tests. * refactor(cstring): .DEF file renames of hash functions * feat(cstring): add always-available multibyte and wide hash API Move the hash declarations into hash.h and the stdint.h discrimination into common.h. cstring.h includes both. Add mbs, wcs, mbuf, and wbuf entry points, including the case forms, for djb2 and FNV-1a. Each code unit contributes its low 8 bits, so ASCII text has one hash in both encodings. C++ shims overload on char const*, wchar_t const*, and both buffer forms. * docs(cstring): document hash groups, contract, and consumers - Document the hash contract, the djb2 and FNV-1a steps, and the published vectors in hash.h, README.md, and doc/mainpage.md; - Define group__cstring_api__hashing__djb2 and group__cstring_api__hashing__fnv1a, and keep the published references on those groups; - Place the C++ hash shims in namespace cstring, and import them in test.unit.hash.cxx; - Name the projects that call or link cstring, including the sistools programs; - Parenthesise the hash basis macros and note the FNV-1a prime in decimal; - Record the header-split and auto-buffer provenance items in TODO.md; - Spell NUL in the hash and status-code comments;
1 parent dfc33d7 commit e87dd41

15 files changed

Lines changed: 1625 additions & 430 deletions

File tree

‎CHANGES.md‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33

44
## 4.1.0 - 5th October 2026
55

6-
* Added 64-bit `djb2` hash functions: `cstring_hash_djb2()`, `cstring_hash_djb2_ci()`, `cstring_hash_djb2_len()`, and `cstring_hash_djb2_len_ci()`;
7-
* Added 64-bit `FNV-1a` hash functions: `cstring_hash_fnv1a()`, `cstring_hash_fnv1a_ci()`, `cstring_hash_fnv1a_len()`, and `cstring_hash_fnv1a_len_ci()`;
6+
* Added 64-bit `djb2` hash functions: `cstring_hash_djb2()`, `cstring_hash_djb2_case()`, `cstring_hash_djb2_buf()`, and `cstring_hash_djb2_buf_case()`;
7+
* Added 64-bit `FNV-1a` hash functions: `cstring_hash_fnv1a()`, `cstring_hash_fnv1a_case()`, `cstring_hash_fnv1a_buf()`, and `cstring_hash_fnv1a_buf_case()`;
8+
* Added multibyte and wide hash entry points `cstring_hash_djb2_mbs()`, `cstring_hash_djb2_wcs()`, `cstring_hash_djb2_mbuf()`, `cstring_hash_djb2_wbuf()`, and the `_case` forms, and the same set for `cstring_hash_fnv1a()`;
89
* Added `cstring_hash_t` typedef (`uint64_t`);
9-
* Added C++ hash access shims for `cstring_t` (reference and pointer) and buffer/slice forms;
10+
* Added **common.h** for shared `<stdint.h>` discrimination, and **hash.h** for the hash API, included from **cstring.h**;
11+
* Added C++ hash access shims `hash_djb2()`, `hash_djb2_case()`, `hash_fnv1a()`, and `hash_fnv1a_case()` for `cstring_t` (reference and pointer), `char const*`, `wchar_t const*`, and both buffer forms;
1012
* Added unit test **test.unit.hash** (C hashing API, built with and without the C++ API) and **test.unit.hash.cxx** (C++ hash shims);
1113
* Published `CSTRING_HASH_DJB2_SEED`, `CSTRING_HASH_FNV1A_OFFSET`, and `CSTRING_HASH_FNV1A_PRIME` as the djb2 and FNV-1a basis constants;
1214
* Documented `CSTRING_HASH_DJB2_SEED`, `CSTRING_HASH_FNV1A_OFFSET`, and `CSTRING_HASH_FNV1A_PRIME` with references to the published djb2 and FNV-1a algorithms;
15+
* Documented the hash contract (forms, low octet, case fold, published vectors) and grouped the algorithms as `group__cstring_api__hashing__djb2` and `group__cstring_api__hashing__fnv1a`;
1316

1417

1518
## 4.0.19 - 4th October 2026

‎FAQ.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ See [INSTALL.md](./INSTALL.md) for details of how to install **cstring**.
4646

4747
## Q3: "How do I use cstring?"
4848

49-
Include **cstring/cstring.h** (and **cstring/cstring.vector.h** where needed)
49+
Include **cstring/cstring.h** (which includes **cstring/hash.h**; and
50+
**cstring/cstring.vector.h** where needed)
5051
and link against **libcstring** (the **CMake** target is `cstring::core`).
5152
Create and destroy instances with `cstring_create()` / `cstring_destroy()`,
5253
and mutate with `cstring_assign()`, `cstring_append()`, and related APIs.

‎INSTALL.md‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
**cstring** is a classic-form C library, insofar as it has implementation
44
files in its **src** directory and header files in its **include/cstring**
55
directory. Thus, once "installed", one must simply include
6-
**cstring/cstring.h** (and, where needed, **cstring/cstring.vector.h**), and
7-
compile-in or link-in the implementation.
6+
**cstring/cstring.h** (which includes **cstring/hash.h**) and, where needed,
7+
**cstring/cstring.vector.h**, and compile-in or link-in the implementation.
88

99
The **C** API has no non-standard dependencies. Building the project's tests
1010
additionally requires **STLSoft** and **xTests** (and optionally recognises
@@ -164,10 +164,11 @@ The primary choice for installation is by use of **CMake**.
164164
In that case:
165165

166166
* add **cstring**'s **include** directory to your project's include path;
167-
* compile **src/cstring.core.c** and **src/cstring.vector.c** into your build
168-
(or link a previously built **libcstring**); and
167+
* compile **src/cstring.core.c**, **src/cstring.hash.c**, and
168+
**src/cstring.vector.c** into your build (or link a previously built
169+
**libcstring**); and
169170
* `#include <cstring/cstring.h>` (and **cstring/cstring.vector.h** where
170-
needed).
171+
needed). **cstring.h** includes **cstring/hash.h**.
171172

172173

173174
<!-- ########################### end of file ########################### -->

‎README.md‎

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Small standalone C library that provides extensible C-style strings and extensib
2727
- [Modification functions](#modification-functions)
2828
- [File functions](#file-functions)
2929
- [Hashing functions](#hashing-functions)
30+
- [djb2](#djb2)
31+
- [FNV-1a](#fnv-1a)
3032
- [Vector API](#vector-api)
3133
- [C++ Integration](#c-integration)
3234
- [Examples](#examples)
@@ -215,16 +217,48 @@ Defined in **cstring/cstring.h**:
215217
216218
#### Hashing functions
217219
218-
Both 64-bit **djb2** (initial seed `5381`, `CSTRING_HASH_DJB2_SEED`) and **FNV-1a** (offset basis `0xcbf29ce484222325ULL`, `CSTRING_HASH_FNV1A_OFFSET`; prime `0x100000001b3ULL`, `CSTRING_HASH_FNV1A_PRIME`) hash functions are provided, returning `cstring_hash_t` (`uint64_t`). Buffer/slice variants (`_len`) allow hashing character sequences without constructing a `cstring_t` instance. Case-insensitive variants (`_ci`) fold characters to lower case, facilitating case-folded lookups and comparisons. All functions safely tolerate `NULL` pointers and zero lengths. An empty or `NULL` input hashes to `CSTRING_HASH_DJB2_SEED` or `CSTRING_HASH_FNV1A_OFFSET`:
220+
Declared in **cstring/hash.h**, which **cstring.h** includes. Both algorithms return `cstring_hash_t` (`uint64_t`). Multibyte and wide entry points exist in every build, whatever ambient `cstring_char_t` is. Each code unit contributes its low 8 bits, so ASCII text has one hash in both encodings. A wide code unit of value `0x161` hashes as the octet `0x61` (`'a'`). A `NULL` pointer, or a zero length, yields that algorithm's empty-input value and does not read the pointer.
219221
220-
* `cstring_hash_djb2()` — calculates a 64-bit djb2 hash of a `cstring_t` instance;
221-
* `cstring_hash_djb2_ci()` — calculates a case-insensitive 64-bit djb2 hash of a `cstring_t` instance;
222-
* `cstring_hash_djb2_len()` — calculates a 64-bit djb2 hash of a character buffer or slice;
223-
* `cstring_hash_djb2_len_ci()` — calculates a case-insensitive 64-bit djb2 hash of a character buffer or slice;
224-
* `cstring_hash_fnv1a()` — calculates a 64-bit FNV-1a hash of a `cstring_t` instance;
225-
* `cstring_hash_fnv1a_ci()` — calculates a case-insensitive 64-bit FNV-1a hash of a `cstring_t` instance;
226-
* `cstring_hash_fnv1a_len()` — calculates a 64-bit FNV-1a hash of a character buffer or slice;
227-
* `cstring_hash_fnv1a_len_ci()` — calculates a case-insensitive 64-bit FNV-1a hash of a character buffer or slice;
222+
| Suffix | Input | What is hashed |
223+
| ------ | ----- | -------------- |
224+
| (none) | `cstring_t const*` | `ptr` for `len` code units, including embedded NULs |
225+
| `_mbs` | `char const*` | stops at the first NUL |
226+
| `_wcs` | `wchar_t const*` | stops at the first NUL |
227+
| `_buf` | `cstring_char_t const*`, `size_t` | ambient buffer; calls `_mbuf` or `_wbuf` |
228+
| `_mbuf` | `char const*`, `size_t` | exactly `cch` code units, including embedded NULs |
229+
| `_wbuf` | `wchar_t const*`, `size_t` | exactly `cch` code units, including embedded NULs |
230+
231+
`_case` is the last suffix of each name (`cstring_hash_djb2_mbs_case()`, `cstring_hash_fnv1a_wbuf_case()`, and so on). Case folding uses `tolower` or `towlower`, which follow the process locale, and then the low 8 bits.
232+
233+
Names follow `cstring_hash_<algorithm><suffix>`, for example `cstring_hash_djb2()`, `cstring_hash_djb2_mbuf()`, and `cstring_hash_fnv1a_wbuf_case()`.
234+
235+
236+
##### djb2
237+
238+
The hash starts at `CSTRING_HASH_DJB2_SEED` (`5381`). For each octet `b` the step is `hash = ((hash << 5) + hash) + b`, which is `hash * 33 + b`. Daniel J. Bernstein's djb2, as published by Ozan Yigit.
239+
240+
| Input | Hash |
241+
| ----- | ---- |
242+
| empty, or `NULL` | `5381` |
243+
| `"a"` | `177670` |
244+
| `"foobar"` | `6953516687550` |
245+
| `{ 'a', 0, 'b' }` length 3 | `193482728` |
246+
| octet `0xFF` | `177828` |
247+
248+
The length-3 buffer differs from `"ab"`, because the embedded NUL is hashed.
249+
250+
251+
##### FNV-1a
252+
253+
The hash starts at `CSTRING_HASH_FNV1A_OFFSET` (`0xcbf29ce484222325`). For each octet `b` the step is `hash ^= b` and then `hash *= CSTRING_HASH_FNV1A_PRIME` (`0x100000001b3`). Fowler, Noll, and Vo FNV-1a, 64-bit.
254+
255+
| Input | Hash |
256+
| ----- | ---- |
257+
| empty, or `NULL` | `0xcbf29ce484222325` |
258+
| `"a"` | `0xaf63dc4c8601ec8c` |
259+
| `"foobar"` | `0x85944171f73967e8` |
260+
| `{ 'a', 0, 'b' }` length 3 | `0xe5d29919042666b2` |
261+
| octet `0xFF` | `0xaf64724c8602eb6e` |
228262
229263
230264
### Vector API
@@ -244,7 +278,7 @@ Defined in **cstring/cstring.vector.h**:
244278
245279
When included in C++ compilation units, **cstring/cstring.h** provides inline access shims:
246280
* **String access shims** — `c_str_data()`, `c_str_len()`, and `c_str_ptr()`, allowing `cstring_t` instances to be used directly with **STLSoft** and generic C++ templates;
247-
* **Hash access shims** — `hash_djb2()`, `hash_djb2_ci()`, `hash_fnv1a()`, and `hash_fnv1a_ci()`, overloaded for `struct cstring_t const&`, `struct cstring_t const*`, and slice / buffer forms `(cstring_char_t const* s, size_t cch)`;
281+
* **Hash access shims** — `cstring::hash_djb2()`, `cstring::hash_djb2_case()`, `cstring::hash_fnv1a()`, and `cstring::hash_fnv1a_case()`, overloaded for `struct cstring_t const&`, `struct cstring_t const*`, `char const*`, `wchar_t const*`, and the buffer forms `(char const* s, size_t cch)` and `(wchar_t const* s, size_t cch)`. A `NULL` argument must be cast, because `char const*` and `wchar_t const*` are both viable;
248282
249283
250284
## Examples
@@ -299,11 +333,15 @@ When supplying `'--no-shwild'` — sets `NO_SHWILD=ON` — **shwild** is not rec
299333
300334
### Related projects
301335
302-
Projects in which **cstring** is used include:
336+
Projects that call the **cstring** API, or that require the **CMake** package `cstring`:
303337
304-
* [**errni**](https://github.com/sistools/errni)
305-
* [**rstrip**](https://github.com/sistools/rstrip)
306-
* [**shwild.fnmatch**](https://github.com/synesissoftware/shwild.fnmatch)
338+
| Project | Use |
339+
| ------- | --- |
340+
| [**errni**](https://github.com/sistools/errni) | Builds each result line and writes it with `cstring_writeline()` |
341+
| [**lnunique**](https://github.com/sistools/lnunique) | Requires `cstring` 4.0 and links `cstring::core` for line strings |
342+
| [**rstrip**](https://github.com/sistools/rstrip) | Accumulates each output line and writes it with `cstring_write()` |
343+
| [**shwild.fnmatch**](https://github.com/synesissoftware/shwild.fnmatch) | Holds patterns and subject strings as `cstring_t` |
344+
| [**STLSoft**](https://github.com/synesissoftware/STLSoft) | Optional; the C unit test `output_debug_line.C` uses `cstring_t` when the package is found |
307345
308346
309347
### License

‎TODO.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,18 @@
5858
* [ ] `--no-cpp`;
5959
* [ ] `--no-p99`;
6060
* [ ] `--no-shwild`;
61+
* [ ] API headers reconciled:
62+
* [ ] String API in cstring/string.h;
63+
* [ ] Hash API in cstring/hash.h;
64+
* [ ] Vector API in cstring/vector.h;
65+
* [ ] Umbrella / All API in cstring/cstring.h;
6166
* [-] ~~~Makefiles (legacy build trees removed; CMake-only)~~~ - ❌;
6267
* [ ] Packages:
6368
* [ ] vcpkg;
6469
* [ ] HomeBrew;
6570
* [ ] . . .
6671
* [ ] Website;
72+
* [ ] Project README.md and website need to mention clearly the provenance of the "auto-buffer" concept;
6773
* [ ] . . .
6874
6975

‎doc/mainpage.md‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ string instances and extensible arrays of such, for Unix and Windows.
99
| Module | Header | Summary |
1010
| ------ | ------ | ------- |
1111
| @ref group__cstring_api | `<cstring/cstring.h>` | Core `cstring_t` API (create, mutate, stream I/O, status codes) |
12+
| @ref group__cstring_api__hashing | `<cstring/hash.h>` | djb2 and FNV-1a hashes of `cstring_t`, C strings, and buffers |
13+
| @ref group__cstring_api__hashing__djb2 | `<cstring/hash.h>` | djb2 (seed `5381`); instance, C string, and buffer forms |
14+
| @ref group__cstring_api__hashing__fnv1a | `<cstring/hash.h>` | FNV-1a 64-bit; the same forms as djb2 |
1215
| @ref group__cstring_api__flags | `<cstring/cstring.h>` | Memory-arena and capacity control flags |
1316
| Vector API | `<cstring/cstring.vector.h>` | `cstring_vector_t` sequences of `cstring_t` |
1417

@@ -49,7 +52,15 @@ for build and install instructions.
4952
5053
## Related projects
5154
52-
* [shwild.fnmatch](https://github.com/synesissoftware/shwild.fnmatch)
55+
Projects that call the **cstring** API, or that require the **CMake** package `cstring`:
56+
57+
| Project | Use |
58+
| ------- | --- |
59+
| [errni](https://github.com/sistools/errni) | Builds each result line and writes it with `cstring_writeline()` |
60+
| [lnunique](https://github.com/sistools/lnunique) | Requires `cstring` 4.0 and links `cstring::core` for line strings |
61+
| [rstrip](https://github.com/sistools/rstrip) | Accumulates each output line and writes it with `cstring_write()` |
62+
| [shwild.fnmatch](https://github.com/synesissoftware/shwild.fnmatch) | Holds patterns and subject strings as `cstring_t` |
63+
| [STLSoft](https://github.com/synesissoftware/STLSoft) | Optional; the C unit test `output_debug_line.C` uses `cstring_t` when the package is found |
5364
5465
5566
<!-- ########################### end of file ########################### -->

‎include/cstring/common.h‎

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/* /////////////////////////////////////////////////////////////////////////
2+
* File: cstring/common.h
3+
*
4+
* Purpose: Common definitions for the cstring headers.
5+
*
6+
* Created: 5th October 2026
7+
* Updated: 6th October 2026
8+
*
9+
* Home: http://synesis.com.au/software/
10+
*
11+
* Copyright (c) 2026, Matthew Wilson and Synesis Information Systems
12+
* All rights reserved.
13+
*
14+
* Redistribution and use in source and binary forms, with or without
15+
* modification, are permitted provided that the following conditions are
16+
* met:
17+
*
18+
* - Redistributions of source code must retain the above copyright notice,
19+
* this list of conditions and the following disclaimer.
20+
* - Redistributions in binary form must reproduce the above copyright
21+
* notice, this list of conditions and the following disclaimer in the
22+
* documentation and/or other materials provided with the distribution.
23+
* - Neither the names of Matthew Wilson and Synesis Information Systems nor
24+
* the names of any contributors may be used to endorse or promote
25+
* products derived from this software without specific prior written
26+
* permission.
27+
*
28+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
29+
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
30+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
32+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
35+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
36+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39+
*
40+
* ////////////////////////////////////////////////////////////////////// */
41+
42+
43+
/** \file cstring/common.h Common definitions for the cstring headers
44+
*/
45+
46+
#ifndef CSTRING_INCL_CSTRING_H_COMMON
47+
#define CSTRING_INCL_CSTRING_H_COMMON
48+
49+
50+
/* /////////////////////////////////////////////////////////////////////////
51+
* version
52+
*/
53+
54+
#ifndef CSTRING_DOCUMENTATION_SKIP_SECTION
55+
# define CSTRING_VER_CSTRING_H_COMMON_MAJOR 1
56+
# define CSTRING_VER_CSTRING_H_COMMON_MINOR 0
57+
# define CSTRING_VER_CSTRING_H_COMMON_REVISION 1
58+
# define CSTRING_VER_CSTRING_H_COMMON_EDIT 1
59+
#endif /* !CSTRING_DOCUMENTATION_SKIP_SECTION */
60+
61+
62+
/* /////////////////////////////////////////////////////////////////////////
63+
* includes
64+
*/
65+
66+
#include <stddef.h>
67+
68+
69+
/* /////////////////////////////////////////////////////////////////////////
70+
* compatibility
71+
*/
72+
73+
/* Shared detection of <stdint.h>, used by cstring/hash.h when selecting the
74+
* type of cstring_hash_t.
75+
*/
76+
77+
#if 0
78+
#elif defined(__STDC_VERSION__) &&\
79+
__STDC_VERSION__ >= 199901L
80+
81+
# define CSTRING_HAS_h_stdint_
82+
#elif defined(__cplusplus) &&\
83+
defined(__has_include) &&\
84+
__has_include(<stdint.h>)
85+
86+
# define CSTRING_HAS_h_stdint_
87+
#elif defined(__cplusplus) &&\
88+
__cplusplus >= 201103L
89+
90+
# define CSTRING_HAS_h_stdint_
91+
#elif 0 ||\
92+
( defined(_MSC_VER) &&\
93+
_MSC_VER >= 1310) ||\
94+
0
95+
96+
# define CSTRING_HAS_h_stdint_
97+
#else
98+
99+
#endif
100+
101+
102+
/* /////////////////////////////////////////////////////////////////////////
103+
* includes
104+
*/
105+
106+
#ifdef CSTRING_HAS_h_stdint_
107+
# include <stdint.h>
108+
#endif /* CSTRING_HAS_h_stdint_ */
109+
110+
111+
/* /////////////////////////////////////////////////////////////////////////
112+
* inclusion control
113+
*/
114+
115+
#ifdef STLSOFT_PPF_pragma_once_SUPPORT
116+
# pragma once
117+
#endif /* STLSOFT_PPF_pragma_once_SUPPORT */
118+
119+
#endif /* CSTRING_INCL_CSTRING_H_COMMON */
120+
121+
/* ///////////////////////////// end of file //////////////////////////// */
122+

0 commit comments

Comments
 (0)